Microsoft Edge Kiosk Mode /w Session Storage

What’s kiosk mode?

If you go to fast food market, you may use vendor machine/self-assist machine to complete your shopping tasks. The applications in the modern operating systems we called kiosk. [1]

Kiosk mode in MS edge

The tutorials posted by Microsoft were for in private mode, which cannot retain users’ session data (e.g. IndexDB, Local Storage)[2].

There is a convenient command you can use for keeping user session data. [3]

start msedge --kiosk  --app=<your_website>

If you want to keep the session data in a specific folder, you can add --user-data-dir parameter. But, it will automatically open the browser in full screen mode. [4].

start msedge --kiosk --app=<your_website> --user-data-dir=<your_session_folder_path>


  1. “Chrome Kiosk Mode”, URL:
  2. Microsoft, “Configure Microsoft Kiosk Mode”, URL:
  3. “認識 Google Chrome 與 Microsoft Edge 的 Kiosk 模式”, URL:
  4. Microsoft, “Create Microsoft Edge user data directory variables”. URL:
Posted in Web Design | Tagged , | Leave a comment

A c# implementation of Websocket: Websocket-sharp

If you are finding a websocket library which completely implement Websocket protocol RFC 6455)[1].

I would like to introduce WebsocketSharp. [2]

Performance tips

Although there is no size implementation for websocket, the limitations of websocket implementations are different. The original websocketsharp’s text buffer(initial frame size) is 1016 characters. If you want to increase the suze, please download the source codes and modify FragmentLength in Websocket.cs. [3][4]


  1. IETF, “RFC 6455:Websocket protocol”, URL:
  2. Websocket-Sharp, URL:
  3. “How to disable force Frame continuations in websocket sharp?” URL:
  4. “Websocketsharp.cs”, URL:
Posted in C#, Web Design | Tagged | Leave a comment

Image rendering and scaling algorithms in browsers

Image rendering control

We can control the image rendering algorithms by setting image-rendering property in CSS. [1]

What resize or image generation algorithms are in browser?

If you’re interested in how chromium based browsers generate the images per size or quality parameters, you can refer to the source codes used in the project. [2]


  1. Image rendering, URL:
  2. Skia image generation, URL:
Posted in image processing, Web Design, 未分類 | Tagged | Leave a comment

Blog has been migrated!

The original blog has been migrated to WordPress!


Posted in 未分類 | Leave a comment

Logistics regression in Chinese

Here are recommended posts in Chinese for understanding logistics regressions. The readers can read them step by step. 

2. 你可能不知道的邏輯回歸(Logistics Regression), URL:
Posted in Data Mining, Machine Learning | Leave a comment


在2006年左右,我還在唸嘉義大學數學系時,跟同學分工合作,用PHP 5+Dreamweaver 寫學校處室網站,那時候學校IT不給MySQL/Sql Server,我自己還默默用很簡單的檔案系統處理函數,定義好資料結構,一行一行把「最新消息」等訊息,存在單一檔案作為offline database使用(那時候學藝不精,不知道有Sqlite可以用)。就這樣把學校處室的消息發布功能做了出來,還具備CRUD功能。 

在那個大學年代,身兼學校的BBS系統站長,在那邊辛苦學習FreeBSD , Linux⋯當起MIS,三不五時就是去修伺服器,怎麼用fsck修硬碟, Make tools, build kernel 還自己去學怎麼剪RJ 45網路線,讓Server可以正常運作(可見那時候多窮,還要自己剪網路線)。
碩士班時期,實驗室還沒有積累一些關於data mining智慧資產,自己寫了一些演算法,像是PrefixSpan sequential pattern mining. 為了求效能,還全部用C++搭配STL寫。自己排crontab job,搭配bash script來產生自己要的實驗記錄。
當了三年的兼任助理,幫忙編hadoop教材…。為了自己的生計,還幫學校處室架設Wordpress,改別人的theme,甚至去看wordpress template怎麼寫,修掉別人模板的bug。也稍微懂得怎麼調整Apache的參數讓系統效能能夠跟得上來。
去當了幾家公司的兼任工程師,都是以C# + ASP.Net/MVC 作為主要工作技能。
為了打軟體競賽,還去用MongoDB,寫寫jQuery and Bootstrap。
為了做某公司的軟體專案,自己去玩Zebra ZPL印表機語言, WCF跟實作軟體序號與數位簽章演算法。
為了幫德國實驗室的同事做Big Data Benchmark,學怎麼用HBase & MapReduce API來做一些ETL工作(後來這也成為我的論文參考文獻之一)。
那時候政府還很流行Open Data,就去學架設CKAN,以及去研究HTTP協議,寫一些CKAN的prototype plugin。
Posted in 未分類 | 2 Comments

Raspberry Pi Camera + OpenCV

If you are interested in how to use Raspberry Pi Camera + OpenCV to capture images, here is a great post in Chinese. 

However, the post had something wrong. If you want to install OpenCV packages of Python 3, please use the command “apt-get install python3-opencv”. 
Posted in Python, Raspberry Pi | Leave a comment

FFMPEG: Decode and then encode frames to JPEG images

I’ve used FFMPEG library for a while. Actually, the FFMPEG library’s decoding process flow can be described as the following picture. If you want to read the videos and then save to jpeg file, you can take a look on my programming code (tested on FFMPEG ver. 4 library).

// VideoProcessing.cpp 
#pragma once
using namespace std;
#include <iostream>
extern "C"
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swscale.lib")

void SaveToJPEG(AVFrame* pFrame, const char * folderName, int index)


// Setup Output Path
char outFile[256] = { 0 };
sprintf_s(outFile, sizeof(outFile)/sizeof(outFile[0]), "%s\OutputImages-%d.jpg", folderName, index);

AVFormatContext* pFormatCtx = avformat_alloc_context();

// Setup the output format
pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);

// Initializext
if (avio_open(&pFormatCtx->pb, outFile, AVIO_FLAG_READ_WRITE) < 0) {

printf("Couldn't open output file.");



// Get a new Stream from the indicated format context
AVStream* pAVStream = avformat_new_stream(pFormatCtx, 0);

if (pAVStream == NULL) {



// Find encoder from the codec identifier.

AVCodec* pCodec = avcodec_find_encoder(pFormatCtx->oformat->video_codec);

if (!pCodec) {
printf("Codec not found.");
// Setup the codec context
AVCodecContext* codecCtx = avcodec_alloc_context3(pCodec);
codecCtx->codec_id = pFormatCtx->oformat->video_codec;
codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
codecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
codecCtx->width = pFrame->width;
codecCtx->height = pFrame->height;
codecCtx->time_base = AVRational{ 1,25 };

// Open the codec
if (avcodec_open2(codecCtx, pCodec, NULL) < 0) {

printf("Could not open codec.");


// assign the codec context to the stream parameters.
avcodec_parameters_from_context(pAVStream->codecpar, codecCtx);

//Write Header
avformat_write_header(pFormatCtx, NULL);

int y_size = (codecCtx->width) * (codecCtx->height);

// assign large enough space
AVPacket pkt;

av_new_packet(&pkt, y_size);

int got_picture = 0;

// Use avcodec_send_frame()/avcodec_receive_packet() instead
int ret = avcodec_send_frame(codecCtx, pFrame);

if (ret < 0) {

printf("Encode Error.n");


ret = avcodec_receive_packet(codecCtx, &pkt);

ret = av_write_frame(pFormatCtx, &pkt);



//Write Trailer

printf("Encode Successful.n");




int main(int argc, char * argv[])

if (argc < 2) {
cout << "You need to specify a media file." << endl;
cout << "Command line : VideoProcessing.exe [input_video_path] [output_folder]" << endl;
return -1;

AVFormatContext* pFormatContext = avformat_alloc_context();
if (!pFormatContext) {
cout << "ERROR could not allocate memory for Format Context" << endl;
return -1;

if (avformat_open_input(&pFormatContext, argv[1], NULL, NULL) != 0) {
cout << "ERROR could not open the file" << endl;
return -1;

if (avformat_find_stream_info(pFormatContext, NULL) < 0) {
cout << "ERROR could not get the stream info" << endl;
return -1;

// Initialize the codec, paramters for subsequent useage.
AVCodec* pCodec = NULL;
AVCodecParameters* pCodecParameters = NULL;
int videoStreamIndex = -1;

for (int i = 0; i < pFormatContext->nb_streams; i++)
AVCodecParameters* pLocalCodecParameters = NULL;
// Read the codec parameters corresponding to each stream.
pLocalCodecParameters = pFormatContext->streams[i]->codecpar;

AVCodec* pLocalCodec = NULL;
pLocalCodec = avcodec_find_decoder(pLocalCodecParameters->codec_id);

if (pLocalCodec == NULL)
cout << "[ERROR] Cannot find the codec" << endl;

if (pLocalCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO)
if (videoStreamIndex == -1)
videoStreamIndex = i;
pCodec = pLocalCodec;
pCodecParameters = pLocalCodecParameters;

AVCodecContext* pCodecContext = avcodec_alloc_context3(pCodec);
if (pCodecContext == NULL)
cout << "Fail to allocate the memoery to the Codec Context." << endl;
return -1;

if (avcodec_parameters_to_context(pCodecContext, pCodecParameters) < 0)
cout << "failed to copy codec params to codec context" << endl;
return -1;

if (avcodec_open2(pCodecContext, pCodec, NULL) < 0)
cout << "failed to open codec through avcodec_open2" << endl;
return -1;

AVFrame* pFrame = av_frame_alloc();
if (!pFrame)
cout << "failed to allocated memory for AVFrame" << endl;
return -1;

AVPacket* pPacket = av_packet_alloc();
if (!pPacket)
cout << "failed to allocated memory for AVPacket" << endl;
return -1;

int indexOfFrame = 0;
while (av_read_frame(pFormatContext, pPacket) >= 0)
// if it's the video stream
if (pPacket->stream_index == videoStreamIndex) {
int response = avcodec_send_packet(pCodecContext, pPacket);
if (response < 0)
response = avcodec_receive_frame(pCodecContext, pFrame);

if (response >= 0)
SaveToJPEG(pFrame, argv[2], indexOfFrame);
// Limit the number of output frame to be 5.
if (indexOfFrame == 5)



  1. FFMPEG libav decode note
  2. FFMPEG libav tutorial
  3. 用AVCodecParameters代替AVCodecContext
  4. 用FFmpeg保存JPEG图片

Posted in C, FFMPEG | Leave a comment

The introduction for JavaScript ES6’s classes

Do not understand the class features of JavaScript ES6?

You can take a look on this introduction in Chinese. 
Posted in JavaScript | Leave a comment

Speed up ActiveMQ performance by 25x

Sometimes we encounter the performance issue for persistent messaging using ActiveMQ. 
Here’s the best practice on Linux system to accelerate it.

Posted in ActiveMQ | Leave a comment