デモ
GUI上で各種画像処理(読み込み/保存、ピクセル編集、補間、ブレンド、各種フィルタ、減色処理 等)を試すことができます。
index.html
<!DOCTYPE html>
<html>
<head>
<title>InputDetect demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
<script type="module" src="./main.mjs" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="./libs/GuiBlocks.css">
<style type="text/css">
#scomponent {
display: block;
width: 100%;
background-color: #FFFFFF;
margin: 0px;
padding: 0em;
}
</style>
</head>
<body>
<div id="scomponent"></div>
</body>
</html>
import GuiBlocks from "./libs/GuiBlocks.min.js";
import PixelProcessing from "./libs/PixelProcessing.min.js";
/**
* 画像ファイルの読み込みと、画像データのCanvasやIMG要素への変換サンプル
* (PixelProcessingは直接使っていませんが、画像データ取得は他サンプルで利用)
* @param {GuiBlocks.Panel} panel
*/
const testFileLoad = function(panel) {
panel.clear();
// 描画領域(Canvas)作成
const canvas = new GuiBlocks.Canvas();
canvas.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas.setPixelSize(256, 256);
canvas.setSize(256, 256);
panel.put(canvas, GuiBlocks.PUT_TYPE.IN);
// ファイル読込ボタン
const loadbutton = new GuiBlocks.FileLoadButton("読み込み");
loadbutton.setFileAccept(GuiBlocks.FILE_ACCEPT.IMAGE);
canvas.put(loadbutton, GuiBlocks.PUT_TYPE.NEWLINE);
loadbutton.addListener(function(file) {
// ファイル読込 → Canvasに画像表示
canvas.putImage(
file[0],
true,
undefined,
function() {
console.log("ロード完了");
}
);
});
// Canvasの画像を IMGタグ表示(imagepanel へ)
const savebutton = new GuiBlocks.Button("IMG要素化");
loadbutton.put(savebutton, GuiBlocks.PUT_TYPE.RIGHT);
savebutton.addListener(function() {
imagepanel.putImage(
canvas,
function() {
console.log("描写完了");
}
);
});
// 画像を表示するパネル
const imagepanel = new GuiBlocks.ImagePanel();
savebutton.put(imagepanel, GuiBlocks.PUT_TYPE.NEWLINE);
};
/**
* PixelProcessingによるピクセルアクセス・書き込みのサンプル
* RGBA画像・グレースケール画像どちらも試せます
* @param {GuiBlocks.Panel} panel
*/
const testWritePixel = function(panel) {
panel.clear();
// 256x256のCanvasを黒で初期化
const canvas = new GuiBlocks.Canvas();
canvas.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas.setPixelSize(256, 256);
canvas.setSize(256, 256);
const size = canvas.getPixelSize();
canvas.getContext().fillStyle = "rgb(0, 0, 0)";
canvas.getContext().fillRect(0, 0, size.width, size.height);
panel.put(canvas, GuiBlocks.PUT_TYPE.IN);
// RGBA画像としてピクセル操作するボタン
const button1 = new GuiBlocks.Button("RGBA でピクセルに書き込み");
canvas.put(button1, GuiBlocks.PUT_TYPE.NEWLINE);
button1.addListener(function() {
// PixelProcessingのPixDataRGBAでCanvasから画像データを作成
const data = new PixelProcessing.DataRGBA(canvas.getImageData());
// 100ピクセルをランダムで白色を書き込む
let i = 0;
for(i = 0; i < 100; i++) {
const x = Math.floor(Math.random() * data.width);
const y = Math.floor(Math.random() * data.height);
// PixelProcessingのPixColorRGBAで色情報を作成
const color = new PixelProcessing.ColorRGBA([255, 255, 255, 255]);
// ピクセルの色を変更
data.setPixelInside(x, y, color);
}
// PixelProcessingで操作した画像をCanvasへ描画
canvas.putImageData(data.getImageData());
});
// グレースケール画像としてピクセル操作するボタン
const button2 = new GuiBlocks.Button("輝度値 でピクセルに書き込み");
button1.put(button2, GuiBlocks.PUT_TYPE.RIGHT);
button2.addListener(function() {
// PixelProcessingのPixDataYでCanvasから画像データを作成
const data = new PixelProcessing.DataY(canvas.getImageData());
let i = 0;
for(i = 0; i < 100; i++) {
const x = Math.floor(Math.random() * data.width);
const y = Math.floor(Math.random() * data.height);
// PixColorYで最大輝度(255)を書き込み
const color = new PixelProcessing.ColorY(255);
// ピクセルの色を変更
data.setPixelInside(x, y, color);
}
// PixelProcessingで操作した画像をCanvasへ描画
canvas.putImageData(data.getImageData());
});
};
/**
* PixelProcessingの画像補間(リサイズ/拡大・補間モード変更)のサンプル
* ラッピング/補間方法をGUIで切り替えられます
* @param {GuiBlocks.Panel} panel
*/
const testInterpolation = function(panel) {
panel.clear();
const srcWidth = 16;
const srcHeight = 16;
const dstWidth = 256;
const dstHeight = 256;
// 小さい画像を16x16サイズで生成(ランダム輝度)
const gene = new GuiBlocks.Button("画像作成");
const genefunc = function() {
// 現在のCanvas内容からPixelProcessing用の画像データを作成
const data = new PixelProcessing.DataY();
data.putImageData(inputcanvas.getImageData());
// 画像の全ピクセルをループ(forEachでx, y座標ごとに)
data.forEach(function(color, x, y) {
// 各ピクセルにランダムな輝度値をセット
// color.random() は 0〜255のランダム値を返すPixColorY
data.setPixelInside(x, y, color.random());
});
// 画像データをCanvasへ反映
inputcanvas.putImageData(data.getImageData());
};
gene.addListener(genefunc);
panel.put(gene, GuiBlocks.PUT_TYPE.IN);
// 入出力Canvas
const inputcanvas = new GuiBlocks.Canvas();
const outputcanvas = new GuiBlocks.Canvas();
inputcanvas.setPixelSize(srcWidth, srcHeight);
inputcanvas.setUnit(GuiBlocks.UNIT_TYPE.PX);
inputcanvas.setSize(srcWidth, srcHeight);
genefunc(); // 初回画像生成
gene.put(inputcanvas, GuiBlocks.PUT_TYPE.NEWLINE);
// ラッピング(画像外参照の挙動)の選択
const wrapmode = [
PixelProcessing.MODE_WRAP.REPEAT,
PixelProcessing.MODE_WRAP.CLAMP
];
// 補間モード(PixelProcessingの補間定数)
const filtermode = [
PixelProcessing.MODE_IP.NEAREST_NEIGHBOR,
PixelProcessing.MODE_IP.BILINEAR,
PixelProcessing.MODE_IP.COSINE,
PixelProcessing.MODE_IP.HERMITE4_3,
PixelProcessing.MODE_IP.HERMITE4_5,
PixelProcessing.MODE_IP.HERMITE16,
PixelProcessing.MODE_IP.BICUBIC,
PixelProcessing.MODE_IP.BICUBIC_SOFT,
PixelProcessing.MODE_IP.BICUBIC_NORMAL,
PixelProcessing.MODE_IP.BICUBIC_SHARP
];
const cb_selectertype = new GuiBlocks.ComboBox(wrapmode);
inputcanvas.put(cb_selectertype, GuiBlocks.PUT_TYPE.NEWLINE);
cb_selectertype.setWidth(16);
const cb_interpolationtype = new GuiBlocks.ComboBox(filtermode);
cb_selectertype.put(cb_interpolationtype, GuiBlocks.PUT_TYPE.NEWLINE);
cb_interpolationtype.setWidth(16);
// 拡大処理の実行
const button = new GuiBlocks.Button("拡大");
cb_interpolationtype.put(button, GuiBlocks.PUT_TYPE.NEWLINE);
button.addListener(function() {
// PixelProcessing.PixelDataYとして画像データを扱う
const srcdata = new PixelProcessing.DataY(inputcanvas.getImageData());
// ラッピング・補間方法をユーザ指定
srcdata.setWrapMode(cb_selectertype.getSelectedItem());
srcdata.setInterpolationMode(cb_interpolationtype.getSelectedItem());
const dstdata = new PixelProcessing.DataY(dstWidth, dstHeight);
// 結果をCanvasへ描画
dstdata.drawPixelData(srcdata, 0, 0, dstWidth, dstHeight);
outputcanvas.putImageData(dstdata.getImageData());
});
// 出力キャンバス初期化
outputcanvas.setUnit(GuiBlocks.UNIT_TYPE.PX);
outputcanvas.setPixelSize(dstWidth, dstHeight);
outputcanvas.setSize(dstWidth, dstHeight);
button.put(outputcanvas, GuiBlocks.PUT_TYPE.NEWLINE);
outputcanvas.getContext().fillStyle = "rgb(0, 0, 0)";
const size = outputcanvas.getPixelSize();
outputcanvas.getContext().fillRect(0, 0, size.width, size.height);
};
/**
* PixelProcessingの画像ブレンド(合成)機能のサンプル
* ブレンドモード/アルファ値を変更して画像合成が試せます
* @param {GuiBlocks.Panel} panel
*/
const testBlending = function(panel) {
panel.clear();
const canvasWidth = 128;
const canvasHeight = 128;
// 2つの画像(ベースと上書き)+合成結果用Canvas
const canvas_src1 = new GuiBlocks.Canvas();
const canvas_src2 = new GuiBlocks.Canvas();
const canvas_dst = new GuiBlocks.Canvas();
canvas_src1.setPixelSize(canvasWidth, canvasHeight);
canvas_src1.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas_src1.setSize(canvasWidth, canvasHeight);
canvas_src1.putImage("./resource/image_x.png");
canvas_src2.setPixelSize(canvasWidth, canvasHeight);
canvas_src2.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas_src2.setSize(canvasWidth, canvasHeight);
canvas_src2.putImage("./resource/image_y.png");
canvas_dst.setPixelSize(canvasWidth, canvasHeight);
canvas_dst.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas_dst.setSize(canvasWidth, canvasHeight);
// ブレンドモード選択・アルファ値選択
const label1 = new GuiBlocks.Label("ベース画像");
panel.put(label1, GuiBlocks.PUT_TYPE.IN);
label1.put(canvas_src1, GuiBlocks.PUT_TYPE.RIGHT);
const label2 = new GuiBlocks.Label("上書き画像");
canvas_src1.put(label2, GuiBlocks.PUT_TYPE.NEWLINE);
label2.put(canvas_src2, GuiBlocks.PUT_TYPE.RIGHT);
// ブレンドモードの選択
const brendtype = [
PixelProcessing.MODE_BLEND.NONE,
PixelProcessing.MODE_BLEND.ALPHA,
PixelProcessing.MODE_BLEND.ADD,
PixelProcessing.MODE_BLEND.SUB,
PixelProcessing.MODE_BLEND.REVSUB,
PixelProcessing.MODE_BLEND.MUL
];
const cb_brendtype = new GuiBlocks.ComboBox(brendtype);
cb_brendtype.setWidth(8);
canvas_src2.put(cb_brendtype, GuiBlocks.PUT_TYPE.NEWLINE);
const globalalpha = [
"1.0",
"0.8",
"0.5"
];
const cb_globalalpha = new GuiBlocks.ComboBox(globalalpha);
cb_globalalpha.setWidth(8);
cb_brendtype.put(cb_globalalpha, GuiBlocks.PUT_TYPE.RIGHT);
const button = new GuiBlocks.Button("blend");
cb_globalalpha.put(button, GuiBlocks.PUT_TYPE.RIGHT);
button.addListener(function() {
// PixelProcessingで画像データを取得
const src1 = new PixelProcessing.DataRGBA(canvas_src1.getImageData());
const src2 = new PixelProcessing.DataRGBA(canvas_src2.getImageData());
// ブレンドモードとグローバルアルファを設定
src1.setBlendType(cb_brendtype.getSelectedItem());
src1.globalAlpha = parseFloat(cb_globalalpha.getSelectedItem());
// drawPixDataで画像合成
src1.drawPixelData(src2, 0, 0);
// 合成結果をCanvasへ
canvas_dst.putImageData(src1.getImageData());
});
const label3 = new GuiBlocks.Label("結果画像");
button.put(label3, GuiBlocks.PUT_TYPE.NEWLINE);
label3.put(canvas_dst, GuiBlocks.PUT_TYPE.RIGHT);
};
/**
* PixelProcessingの各種フィルタ・減色・ノーマルマップ等の応用サンプル
* PixelProcessingのfilterXxx系メソッドで様々な画像処理が可能です
* @param {GuiBlocks.Panel} panel
*/
function testEtc(panel) {
panel.clear();
const canvasWidth = 320;
const canvasHeight = 240;
// 入出力用Canvas
const canvas_src = new GuiBlocks.Canvas();
const canvas_dst = new GuiBlocks.Canvas();
canvas_src.setPixelSize(canvasWidth, canvasHeight);
canvas_src.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas_src.setSize(canvasWidth, canvasHeight);
canvas_dst.setPixelSize(canvasWidth, canvasHeight);
canvas_dst.setUnit(GuiBlocks.UNIT_TYPE.PX);
canvas_dst.setSize(canvasWidth, canvasHeight);
// 画像選択
const label1 = new GuiBlocks.Label("使用画像");
panel.put(label1, GuiBlocks.PUT_TYPE.IN);
const picturetype = [
"./resource/image_parrots.jpg",
"./resource/image_mandrill.jpg",
"./resource/image_girl.jpg",
"./resource/image_lenna.jpg",
"./resource/image_test1.jpg",
"./resource/sampleimage.png",
"./resource/image_wg.png"
];
const cb_picturetype = new GuiBlocks.ComboBox(picturetype);
cb_picturetype.setWidth(32);
label1.put(cb_picturetype, GuiBlocks.PUT_TYPE.RIGHT);
cb_picturetype.addListener(function () {
canvas_src.putImage(cb_picturetype.getSelectedItem());
});
canvas_src.putImage(picturetype[0], true);
// 入力画像表示
const label2 = new GuiBlocks.Label("入力画像");
cb_picturetype.put(label2, GuiBlocks.PUT_TYPE.NEWLINE);
label2.put(canvas_src, GuiBlocks.PUT_TYPE.RIGHT);
// 処理の種類
const label3 = new GuiBlocks.Label("処理の種類");
canvas_src.put(label3, GuiBlocks.PUT_TYPE.NEWLINE);
const filtertype = [
"ソフト",
"シャープ",
"グレースケール",
"ノーマルマップ",
"ガウシアンフィルタ",
"バイラテラルフィルタ",
"レンズフィルタ",
"アンシャープ",
"単純減色",
"組織的ディザ法による減色",
"誤差拡散法による減色"
];
const cb_filtertype = new GuiBlocks.ComboBox(filtertype);
cb_filtertype.setWidth(32);
label3.put(cb_filtertype, GuiBlocks.PUT_TYPE.RIGHT);
// 実行ボタン(選択に応じて処理)
const button = new GuiBlocks.Button("実行");
cb_filtertype.put(button, GuiBlocks.PUT_TYPE.RIGHT);
button.addListener(function() {
const src = new PixelProcessing.DataRGBA(canvas_src.getImageData());
if(cb_filtertype.getSelectedItem() === filtertype[0]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterBlur(7); // ブラー(ぼかし)
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[1]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterSharp(0.5); // シャープ
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[2]) {
src.grayscale(); // グレースケール化
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[3]) {
src.grayscale();
const height = new PixelProcessing.DataY(src);
height.setWrapMode(PixelProcessing.MODE_WRAP.REPEAT);
height.filterGaussian(5);
canvas_dst.putImageData(height.getNormalMap().getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[4]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterGaussian(7); // ガウシアンぼかし
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[5]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterBilateral(5, 0.8); // バイラテラルフィルタ
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[6]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterSoftLens(5, 1.2); // ソフトレンズ風
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[7]) {
src.setWrapMode(PixelProcessing.MODE_WRAP.CLAMP);
src.filterUnSharp(7, 1); // アンシャープ
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[8]) {
src.filterQuantizationSimple(64); // 減色(単純)
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[9]) {
src.filterQuantizationOrdered(64); // 減色(ディザ)
canvas_dst.putImageData(src.getImageData());
}
else if(cb_filtertype.getSelectedItem() === filtertype[10]) {
src.filterQuantizationDiffusion(64); // 減色(誤差拡散)
canvas_dst.putImageData(src.getImageData());
}
});
// 結果画像表示
const label4 = new GuiBlocks.Label("結果画像");
button.put(label4, GuiBlocks.PUT_TYPE.NEWLINE);
label4.put(canvas_dst, GuiBlocks.PUT_TYPE.RIGHT);
}
/**
* サンプルデモのエントリポイント
* PixelProcessingの機能をGUIから色々試せます
*/
const main = function() {
console.log("PixelProcessing クラスのサンプル");
const mainpanel = new GuiBlocks.Panel();
mainpanel.putMe("scomponent", GuiBlocks.PUT_TYPE.IN);
const label = new GuiBlocks.Label("ImageProcessing のテストです");
mainpanel.put(label, GuiBlocks.PUT_TYPE.IN);
// 機能選択コンボボックス
const combobox_type = [
"画像ファイルの読み込み",
"データの読み書き",
"画像補間",
"ブレンド",
"そのほかいろいろ"
];
const combobox = new GuiBlocks.ComboBox(combobox_type);
combobox.setWidth(20);
label.put(combobox, GuiBlocks.PUT_TYPE.NEWLINE);
combobox.addListener(function () {
const item = combobox.getSelectedItem();
if(item === combobox_type[0]) {
testFileLoad(testpanel);
}
else if(item === combobox_type[1]) {
testWritePixel(testpanel);
}
else if(item === combobox_type[2]) {
testInterpolation(testpanel);
}
else if(item === combobox_type[3]) {
testBlending(testpanel);
}
else if(item === combobox_type[4]) {
testEtc(testpanel);
}
});
const testpanel = new GuiBlocks.Panel();
mainpanel.put(testpanel, GuiBlocks.PUT_TYPE.NEWLINE);
combobox.setSelectedItem(combobox_type[4]);
testEtc(testpanel);
};
main();