Web Workerを使用してプログレスバーをマルチスレッドで動かす[HTML5]
HTML5で追加された<progress>タグのプログレスバーを使用してみると、プログレスバーが思ったように動作しない経験はありませんか?
プログレスバーはマルチスレッドのWeb Workerを使用しないと正常に動作しません。という事でプログレスバーを動作させる方法をご紹介します。
プログレスバーを実行してみる
ボタンを押すとWeb Workerを使用してプログレスバーを動作させます。
※ページの読み込みが完了してから実行してください。
事前準備
お使いのブラウザがChromeの方は「Web Workerに画像データを値渡しではなく参照渡しする」の記事の事前準備を行ってください。
※事前準備を行わないとサンプルが動作しませんのでご了承ください。
サンプルコード
サンプルはWeb WorkerとHTMLの2つのファイルとなります。
Web Worker側 - effect.js
// ネガティブ
function EffectNegative(source){
var height = source.height;
var width = source.width;
var src = source.data;
var sRow,sCol
for (var y = 0; y < height; y++) {
sRow = (y * width*4);
for (var x = 0;x < width; x++) {
sCol = sRow + (x * 4);
src[sCol] = 255 - src[sCol];
src[sCol + 1] = 255 - src[sCol + 1];
src[sCol + 2] = 255 - src[sCol + 2];
src[sCol + 3] = 255; // Transparency
}
postMessage({'type':1,'max':(height-1),'pos':y});
}
}
////////////////////////////////////////////////////////////////////////////////
// Worker イベント
////////////////////////////////////////////////////////////////////////////////
onmessage = function (event) {
// 擬似的にImageDataオブジェクトを生成する
var source = {'data' : event.data.src_raw,
'width' : event.data.src_width,
'height': event.data.src_height};
// ネガティブ変換
EffectNegative(source);
// 変換後のデータを送信する[参照渡し]
postMessage({'type' : 2 ,
'width' : source.width,
'height' : source.height,
'raw' : source.data},[source.data.buffer]);
};
HTML側 - index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
// ワーカーの生成
var effect_worker = new Worker('effect.js');
// キャンバス
var src_canvas;
var src_ctx;
var dst_canvas;
var dst_ctx;
var dmy_canvas;
var dmy_ctx;
// イメージ
var image;
// プログレスバー
var pgs;
window.onload = function(){
src_canvas = document.getElementById("SrcCanvas");
src_ctx = src_canvas.getContext("2d");
dst_canvas = document.getElementById("DstCanvas");
dst_ctx = dst_canvas.getContext("2d");
dmy_canvas = document.getElementById("DmyCanvas");
dmy_ctx = dmy_canvas.getContext("2d");
image = document.getElementById("img_source");
}
function run(){
// 処理速度の違いがわかるようにサイズをリサイズする
if (window.navigator.msSaveBlob) {
// IE/Edge
dmy_canvas.width = 1000;
dmy_canvas.height = 1000;
}else{
dmy_canvas.width = 4000;
dmy_canvas.height = 4000;
}
dmy_ctx.drawImage(src_canvas,0,0,dmy_canvas.width,dmy_canvas.height);
var source = dmy_ctx.getImageData(0, 0, dmy_canvas.width, dmy_canvas.height);
// IEのプログレスバーは1度使用したら汚染されるので、
// 毎回、プログレスバーを生成する
document.getElementById("pg_parent").innerHTML = '<progress id="MyProgress" style="width:300px;"></progress>';
pgs = document.getElementById("MyProgress");
pgs.max = dmy_canvas.height-1;
pgs.value = 0;
effect_worker.postMessage({'src_width':source.width,'src_height':source.height,'src_raw': source.data},
[source.data.buffer]);
}
// workerからのメッセージ
effect_worker.onmessage = function (event) {
var type = event.data.type
// ---------------------
// プログレスバー
// ---------------------
if (type == 1){
pgs.max = event.data.max;
pgs.value = event.data.pos;
return;
// ---------------------
// 処理の完了
// ---------------------
}else if (type == 2){
dst_canvas.width = event.data.width;
dst_canvas.height = event.data.height;
var imagedata = dst_ctx.createImageData(event.data.width, event.data.height);
var src = event.data.raw;
var dst = imagedata.data;
for(var i = 0; i < src.length; i++){
dst[i] = src[i];
}
dst_ctx.putImageData(imagedata,0,0);
document.getElementById("msg_destination").innerHTML =
'[変換後] ' + dst_canvas.width + ' x ' + dst_canvas.height;
}
}
// ユーザーによりファイルが追加された
function onAddFile(event) {
var files;
var reader = new FileReader();
if(event.target.files){
files = event.target.files;
}else{
files = event.dataTransfer.files;
}
// ファイルが読み込まれた
reader.onload = function (event) {
// イメージが読み込まれた
image.onload = function (){
src_canvas.width = image.width;
src_canvas.height = image.height;
// キャンバスに画像を描画
src_ctx.drawImage(image,0,0);
document.getElementById("msg_source").innerHTML =
'[元の画像] ' + image.width + ' x ' + image.height;
};
// イメージが読み込めない
image.onerror = function (){
alert('このファイルは読み込めません。');
};
image.src = reader.result;
};
if (files[0]){
reader.readAsDataURL(files[0]);
}
document.getElementById("inputfile").value = '';
}
</script>
</head>
<body>
<h4>画像の読み込み</h4>
<p></p>
<input type="file" id="inputfile" accept="image/jpeg,image/png,image/gif" onchange="onAddFile(event);">
<p></p>
<button onclick="run();">実行</button>
<p></p>
<div id="pg_parent"></div>
<p></p>
<h3 id="msg_destination">[変換後]</h3>
<p></p>
<canvas id="DstCanvas"></canvas>
<p></p>
<h3 id="msg_source">[元の画像]</h3>
<p></p>
<img id="img_source" style="display:none;">
<canvas id="SrcCanvas"></canvas>
<canvas id="DmyCanvas" style="display:none;"></canvas>
<p></p>
</body>
</html>
Web Workerの流れ
メインスレッドではボタンを押した時にeffect_worker.postMessage()でWeb Workerにメッセージを送信します。受信はeffect_worker.onmessage = function (event) {}で行います。
Web WorkerからはpostMessage()でメインスレッドにメッセージを送信します。
その他
大半のコードは標準的なcanvas系の操作ですのでMDNで確認して下さい。
Web Worker側のEffectNegative()はRGBの色を反転させる画像処理ですので、興味が無い方は覚える必要はないです。
スポンサーリンク
関連記事
| 前の記事: | Web Workerに画像データを値渡しではなく参照渡しする[JavaScriptのマルチスレッドの高速化] |
| 次の記事: | PDF.jsでnullAdobe-Japan1-UCS2/ null90ms-RKSJ-Hのエラーが発生する[解決方法] |
公開日:2016年05月18日 最終更新日:2017年05月14日
記事NO:01964
プチモンテ ※この記事を書いた人
![]() | |
![]() | 💻 ITスキル・経験 サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。 画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ |
| 🎵 音楽制作 BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は抒情詩、抒情的な楽曲が多い。楽曲制作は🔰2023年12月中旬 ~ | |









