<!DOCTYPE HTML>
<HTML LANG="ja">
<HEAD>
<META CHARSET="Shift_JIS">
<TITLE>特殊効果ビデオ</TITLE>
</HEAD>
<BODY onLoad="init()" STYLE="background-color:#CCFFFF">
<DIV STYLE="text-align:center">
<BR>
<B>特殊効果ビデオ</B>
<BR><BR>
<FORM>
<SELECT ID="sel" DISABLED onChange="sel_chg(this.selectedIndex)">
<OPTION SELECTED>ソラリゼーション
<OPTION>レリーフ
<OPTION>ラプラシアン 1
<OPTION>ラプラシアン 2
<OPTION>ポスタリゼーション 1
<OPTION>ポスタリゼーション 2
<OPTION>ポスタリゼーション 3
<OPTION>ガラス
<OPTION>スケッチ
<OPTION>ディザ 1
<OPTION>ディザ 2
<OPTION>ディザ 3
<OPTION>網点
<OPTION>波紋
<OPTION>回転
</SELECT>
</FORM>
<BR>
<CANVAS ID="view" WIDTH=1 HEIGHT=1></CANVAS>
</DIV>
<SCRIPT TYPE="text/javascript">
<!--
function init() {
if(navigator.mozGetUserMedia == undefined) {
if(navigator.webkitGetUserMedia == undefined)
navigator.getUserMedia({video:true, audio:false}, success, error);
else
navigator.webkitGetUserMedia({video:true, audio:false}, success, error);
}
else {
navigator.mozGetUserMedia({video:true, audio:false}, success, error);
}
}
function success(stream) {
elem_video = document.createElement("VIDEO");
elem_video.autoplay = true;
elem_video.addEventListener("canplay", wait, false);
if(elem_video.mozSrcObject === undefined) {
if(elem_video.srcObject === undefined)
elem_video.src = (window.URL == undefined || window.URL.createObjectURL == undefined)
? stream : window.URL.createObjectURL(stream);
else
elem_video.srcObject = stream;
}
else {
elem_video.mozSrcObject = stream;
}
elem_video.play();
}
function error(err) {
alert("カメラが使用できません");
}
function wait() {
if(elem_video.videoWidth) {
video_width_h = (video_width = elem_video.videoWidth) >> 1;
video_height_h = (video_height = elem_video.videoHeight) >> 1;
with(elem_view = document.getElementById("view")) {
width = video_width;
height = video_height;
style.width = String(video_width) + "px";
style.height = String(video_height) + "px";
ctx_view = getContext("2d");
}
with(work_imgdat = ctx_view.getImageData(0, 0, video_width, video_height)) {
dev_width_h = (dev_width = width) >> 1;
dev_height_h = (dev_height = height) >> 1;
}
data_len = (dev_size = dev_width * dev_height) << 2;
// ガラス,波紋 用
glass_rnd = new Uint32Array(dev_size);
ripple_pha = new Uint8Array(dev_size);
ripple_att = new Float32Array(dev_size);
var i = 0;
for(var y = 0; y < dev_height; y++) {
var dist_y = y - dev_height_h;
dist_y *= dist_y;
for(var x = 0; x < dev_width; x++) {
var rnd_x = x + (Math.floor(Math.random() * 41) - 20);
if(rnd_x < 0)
rnd_x = 0;
else if(rnd_x >= dev_width)
rnd_x = dev_width - 1;
var rnd_y = y + (Math.floor(Math.random() * 41) - 20);
if(rnd_y < 0)
rnd_y = 0;
else if(rnd_y >= dev_height)
rnd_y = dev_height - 1;
glass_rnd[i] = (rnd_y * (dev_width + 6) + rnd_x) << 2;
var dist = x - dev_width_h;
dist = Math.sqrt(dist * dist + dist_y);
ripple_pha[i] = Math.round(dist * 8) & 0xff;
ripple_att[i] = (dist < 32) ? dist : dist * Math.sqrt(dist / 32);
i++;
}
}
// 回転 用
ctx_view.beginPath();
ctx_view.arc(video_width_h, video_height_h,
((video_width < video_height) ? video_width_h : video_height_h) - 10, 0, PI2, false);
ctx_view.closePath();
work_data = new Uint8Array(work_imgdat.data.buffer, 0, data_len);
work_data32 = new Uint32Array(work_imgdat.data.buffer, 0, dev_size);
work1 = new Uint8Array(work_imgdat.data.buffer, 0, dev_size);
work2 = new Uint8Array(work_imgdat.data.buffer, dev_size, dev_size);
work3 = new Uint8Array(work_imgdat.data.buffer, dev_size << 1, dev_size);
var size = dev_width_h * dev_height_h;
work1d = new Int16Array(work_imgdat.data.buffer, 0, size);
work2d = new Int16Array(work_imgdat.data.buffer, size << 1, size);
work3d = new Int16Array(work_imgdat.data.buffer, size << 2, size);
with(elem_work = document.createElement("CANVAS")) {
width = video_width + 6;
height = video_height + 6;
ctx_work = getContext("2d");
}
document.getElementById("sel").disabled = false;
frame();
return;
}
setTimeout(wait, 50);
}
function sel_chg(index) {
proc = proc_tbl[index];
interval = (proc == rotate/* 回転 */) ? 50 : 200;
if(proc == glass) { // ガラス
// αを非透過に初期化する
for(var i = 3; i < data_len; i += 4)
work_data[i] = 255;
}
}
function frame() {
setTimeout(frame, interval);
if(proc == glass) { // ガラス
glass();
}
else {
ctx_view.drawImage(elem_video, 0, 0);
if(proc == rotate) { // 回転
rotate();
}
else {
var imgdat = ctx_view.getImageData(0, 0, video_width, video_height);
if(proc == ripple) { // 波紋
ripple(imgdat);
}
else {
// クランプされないように(高速化のため),ただの配列にする
proc(new Uint8Array(imgdat.data.buffer));
ctx_view.putImageData(imgdat, 0, 0);
}
}
}
}
// ソラリゼーション
function solar(data) {
for(var i_data = 0; i_data < data_len; i_data += 4)
data[i_data] = data[i_data + 1] = data[i_data + 2]
= solar_map[(360 * data[i_data] + 707 * data[i_data + 1] + 137 * data[i_data + 2]) >> 8];
}
// レリーフ
function relief(data) {
var i_data = 0;
var off = (dev_width << 3) + 8;
for(var y = dev_height - 2; y; y--) {
for(var x = dev_width - 2; x; x--) {
var i_data2 = i_data + off;
var val = (((306 * data[i_data] + 601 * data[i_data + 1] + 117 * data[i_data + 2])
+ 0x3fc00
- (306 * data[i_data2] + 601 * data[i_data2 + 1] + 117 * data[i_data2 + 2])) >> 10)
- 128;
data[i_data] = data[i_data + 1] = data[i_data + 2] = (val > 255) ? 255 : ((val < 0) ? 0 : val);
i_data += 4;
}
data[i_data] = data[i_data + 1] = data[i_data + 2]
= data[i_data + 4] = data[i_data + 5] = data[i_data + 6] = 128;
i_data += 8;
}
for(; i_data < data_len; i_data += 4)
data[i_data] = data[i_data + 1] = data[i_data + 2] = 128;
}
// ラプラシアン 1
function laplacian_1(data) {
var stride = dev_width << 2;
var i_data = stride + 4;
var i_work = 0;
for(var y = dev_height - 2; y; y--) {
for(var x = dev_width - 2; x; x--) {
var i_data2 = i_data - stride;
var i_data3 = i_data + stride;
var val = ((data[i_data] << 3)
- data[i_data2 - 4] - data[i_data2] - data[i_data2 + 4]
- data[i_data - 4] - data[i_data + 4]
- data[i_data3 - 4] - data[i_data3] - data[i_data3 + 4])
+ ((data[i_data + 1] << 3)
- data[i_data2 - 3] - data[i_data2 + 1] - data[i_data2 + 5]
- data[i_data - 3] - data[i_data + 5]
- data[i_data3 - 3] - data[i_data3 + 1] - data[i_data3 + 5])
+ ((data[i_data + 2] << 3)
- data[i_data2 - 2] - data[i_data2 + 2] - data[i_data2 + 6]
- data[i_data - 2] - data[i_data + 6]
- data[i_data3 - 2] - data[i_data3 + 2] - data[i_data3 + 6]);
work1[i_work++] = (val > 255) ? 0 : ((val < 0) ? 255 : 255 - val)
i_data += 4;
}
i_data += 8;
}
var off = (dev_height - 1) * stride;
for(i_data = 0; i_data < stride; i_data += 4) {
var i_data2 = i_data + off;
data[i_data] = data[i_data + 1] = data[i_data + 2]
= data[i_data2] = data[i_data2 + 1] = data[i_data2 + 2] = 255;
}
i_work = 0;
for(var y = dev_height - 2; y; y--) {
data[i_data] = data[i_data + 1] = data[i_data + 2] = 255;
i_data += 4;
for(var x = dev_width - 2; x; x--) {
data[i_data] = data[i_data + 1] = data[i_data + 2] = work1[i_work++];
i_data += 4;
}
data[i_data] = data[i_data + 1] = data[i_data + 2] = 255;
i_data += 4;
}
}
// ラプラシアン 2
function laplacian_2(data) {
var stride = dev_width << 2;
var i_data = stride + 4;
var i_work = 0;
for(var y = dev_height - 2; y; y--) {
for(var x = dev_width - 2; x; x--) {
var i_data2 = i_data - stride;
var i_data3 = i_data + stride;
var r = (data[i_data] << 3)
- data[i_data2 - 4] - data[i_data2] - data[i_data2 + 4]
- data[i_data - 4] - data[i_data + 4]
- data[i_data3 - 4] - data[i_data3] - data[i_data3 + 4];
var g = (data[i_data + 1] << 3)
- data[i_data2 - 3] - data[i_data2 + 1] - data[i_data2 + 5]
- data[i_data - 3] - data[i_data + 5]
- data[i_data3 - 3] - data[i_data3 + 1] - data[i_data3 + 5];
var b = (data[i_data + 2] << 3)
- data[i_data2 - 2] - data[i_data2 + 2] - data[i_data2 + 6]
- data[i_data - 2] - data[i_data + 6]
- data[i_data3 - 2] - data[i_data3 + 2] - data[i_data3 + 6];
work1[i_work++] = (r > 50 || g > 50 || b > 50) ? 0 : 255;
i_data += 4;
}
i_data += 8;
}
var off = (dev_height - 1) * stride;
for(i_data = 0; i_data < stride; i_data += 4) {
var i_data2 = i_data + off;
data[i_data] = data[i_data + 1] = data[i_data + 2]
= data[i_data2] = data[i_data2 + 1] = data[i_data2 + 2] = 255;
}
i_work = 0;
for(var y = dev_height - 2; y; y--) {
data[i_data] = data[i_data + 1] = data[i_data + 2] = 255;
i_data += 4;
for(var x = dev_width - 2; x; x--) {
data[i_data] = data[i_data + 1] = data[i_data + 2] = work1[i_work++];
i_data += 4;
}
data[i_data] = data[i_data + 1] = data[i_data + 2] = 255;
i_data += 4;
}
}
// ポスタリゼーション 1
function poster_1(data) {
for(var i_data = 0; i_data < data_len; i_data += 4) {
var val;
val = data[i_data] & 0xc0;
data[i_data] = val | (val >> 2) | (val >> 4) | (val >> 6);
val = data[i_data + 1] & 0xc0;
data[i_data + 1] = val | (val >> 2) | (val >> 4) | (val >> 6);
val = data[i_data + 2] & 0xc0;
data[i_data + 2] = val | (val >> 2) | (val >> 4) | (val >> 6);
}
}
// ポスタリゼーション 2
function poster_2(data) {
for(var i_data = 0; i_data < data_len; i_data += 4) {
data[i_data] = (data[i_data] & 0x80) ? 0xd0 : 0x30;
data[i_data + 1] = (data[i_data + 1] & 0x80) ? 0xd0 : 0x30;
data[i_data + 2] = (data[i_data + 2] & 0x80) ? 0xd0 : 0x30;
}
}
// ポスタリゼーション 3
function poster_3(data) {
// 16色に減色
var i_data;
var i;
poster_leaves = 0;
for(i = 0; i < 4680; i++)
poster_pixels[i] = 0x80000000;
poster_internal_cnt[0] = poster_internal_cnt[1] = poster_internal_cnt[2] = 0;
for(i_data = 0; i_data < data_len; i_data += 4) {
poster_add_color(data[i_data], data[i_data + 1], data[i_data + 2], 0, 0);
while(poster_leaves > 16) { // 葉の数が 16 より多い
// 葉を減らす
var level;
for(level = 2; ; level--) {
if(poster_internal_cnt[level])
break;
}
var i_store = poster_internal[level * 17 + --poster_internal_cnt[level]];
var index = (i_store - poster_off[level]) << 3;
level++;
var pixels = 0;
var r_sum = 0;
var g_sum = 0;
var b_sum = 0;
for(i = 0; i < 8; i++) {
var i_store_child = poster_off[level] + (index | i);
if(!(poster_pixels[i_store_child] & 0x80000000)) { // ノードあり
pixels += poster_pixels[i_store_child];
r_sum += poster_r_sum[i_store_child];
g_sum += poster_g_sum[i_store_child];
b_sum += poster_b_sum[i_store_child];
poster_leaves--;
}
}
poster_leaves++;
poster_pixels[i_store] = pixels;
poster_r_sum[i_store] = r_sum;
poster_g_sum[i_store] = g_sum;
poster_b_sum[i_store] = b_sum;
}
}
poster_i_color = 0;
poster_get_colors(-1, 0);
for(i_data = 0; i_data < data_len; i_data += 4) {
var r = data[i_data];
var g = data[i_data + 1];
var b = data[i_data + 2];
var min = 0x7fffffff;
var i_min;
for(i = 0; i < poster_leaves; i++) {
var dr = r - poster_r[i];
var dg = g - poster_g[i];
var db = b - poster_b[i];
var d2 = dr * dr + dg * dg + db * db;
if(d2 < min) {
min = d2;
i_min = i;
}
}
data[i_data] = poster_r[i_min];
data[i_data + 1] = poster_g[i_min];
data[i_data + 2] = poster_b[i_min];
}
}
function poster_add_color(r, g, b, level, index) {
index = (index << 3) | ((r >> (5 - level)) & 0x4)
| ((g >> (6 - level)) & 0x2)
| ((b >> (7 - level)) & 0x1);
var i_store = poster_off[level] + index;
if(poster_pixels[i_store] & 0x80000000) { // ノードなし
// ノード追加
poster_pixels[i_store] = 0;
if(level == 3) { // 葉
poster_r_sum[i_store] = 0;
poster_g_sum[i_store] = 0;
poster_b_sum[i_store] = 0;
poster_leaves++;
}
else {
poster_internal[level * 17 + poster_internal_cnt[level]++] = i_store;
}
}
if(poster_pixels[i_store] || level == 3) { // 葉
poster_pixels[i_store]++;
poster_r_sum[i_store] += r;
poster_g_sum[i_store] += g;
poster_b_sum[i_store] += b;
}
else {
poster_add_color(r, g, b, level + 1, index);
}
}
function poster_get_colors(level, index) {
var i_store;
var pixels = (level < 0) ? 0 : poster_pixels[i_store = poster_off[level] + index];
if(pixels) { // 葉
poster_r[poster_i_color] = Math.floor(poster_r_sum[i_store] / pixels);
poster_g[poster_i_color] = Math.floor(poster_g_sum[i_store] / pixels);
poster_b[poster_i_color] = Math.floor(poster_b_sum[i_store] / pixels);
poster_i_color++;
}
else {
index <<= 3;
level++;
for(var i = 0; i < 8; i++) {
if(!(poster_pixels[poster_off[level] + (index | i)] & 0x80000000)) { // ノードあり
poster_get_colors(level, index | i);
if(poster_i_color == poster_leaves)
break;
}
}
}
}
// ガラス
function glass() {
ctx_work.drawImage(elem_video, 3, 3);
ctx_work.drawImage(elem_work, 3, 3, 1, video_height, 0, 3, 3, video_height);
ctx_work.drawImage(elem_work, 2 + video_width, 3, 1, video_height, 3 + video_width, 3, 3, video_height);
ctx_work.drawImage(elem_work, 0, 3, video_width + 6, 1, 0, 0, video_width + 6, 3);
ctx_work.drawImage(elem_work, 0, 2 + video_height, video_width + 6, 1, 0, 3 + video_height, video_width + 6, 3);
var data = ctx_work.getImageData(0, 0, video_width + 6, video_height + 6).data;
var y_l6 = (dev_width + 6) * 24;
var off = dev_width << 2;
for(var i_rnd = dev_size; i_rnd; ) {
var i_data;
var sum_r, sum_g, sum_b;
sum_r = sum_g = sum_b = 0;
i_data = glass_rnd[--i_rnd];
var i_kernel = 0;
for(var y_end = i_data + y_l6; ; ) {
for(var x_end = i_data + 24; ; ) {
var k = blur_kernel[i_kernel++];
sum_r += data[i_data] * k;
sum_g += data[i_data + 1] * k;
sum_b += data[i_data + 2] * k;
if(i_data == x_end)
break;
i_data += 4;
}
if(i_data > y_end)
break;
i_data += off;
}
i_data = i_rnd << 2;
work_data[i_data] = sum_r >> 12;
work_data[i_data + 1] = sum_g >> 12;
work_data[i_data + 2] = sum_b >> 12;
}
ctx_view.putImageData(work_imgdat, 0, 0);
}
// スケッチ
function sketch(data) {
var i_data;
for(i_data = 0; i_data < data_len; i_data += 4)
data[i_data] = (306 * data[i_data] + 601 * data[i_data + 1] + 117 * data[i_data + 2]) >> 10;
var off1 = (dev_width + 1) * 12;
var off2 = (dev_width - 6) << 2;
i_data = 0;
for(var y = 0; y < dev_height; y++) {
for(var x = 0; x < dev_width; x++) {
var sum = 0;
var i_data2 = i_data - off1;
var i_kernel = 0;
for(var dy = -3; ; ) {
var y_ob = (y + dy < 0 || y + dy >= dev_height);
for(var dx = -3; ; ) {
sum += data[(y_ob || x + dx < 0 || x + dx >= dev_width) ? i_data : i_data2] * blur_kernel[i_kernel++];
if(dx == 3)
break;
dx++;
i_data2 += 4;
}
if(dy == 3)
break;
dy++;
i_data2 += off2;
}
data[i_data + 1] = sum >> 12;
i_data += 4;
}
}
for(i_data = 0; i_data < data_len; i_data += 4) {
var val = (data[i_data + 1]) ? Math.floor(data[i_data] * 510 / data[i_data + 1]) - 255 : 255;
data[i_data] = data[i_data + 1] = data[i_data + 2] = (val > 255) ? 255 : ((val < 0) ? 0 : val);
}
}
// ディザ 1
function dither_1(data) {
var i_data = 0;
var i, i_end;
for(i = 0, i_end = dev_width << 1; i < i_end; i++) {
work1d[i] = data[i_data]
work2d[i] = data[i_data + 1]
work3d[i] = data[i_data + 2]
i_data += 4;
}
i_data = 0;
var i_work1 = 0;
var i_work2 = dev_width;
for(var y = dev_height; ; ) {
for(var x = dev_width; x; x--) {
// R
var r = work1d[i_work1];
data[i_data] = (r >= 128) ? (r -= 255, 255) : 0;
// G
var g = work2d[i_work1];
data[i_data + 1] = (g >= 128) ? (g -= 255, 255) : 0;
// B
var b = work3d[i_work1];
data[i_data + 2] = (b >= 128) ? (b -= 255, 255) : 0;
if(x > 1) {
work1d[i_work1 + 1] += (r * 7) >> 4;
work2d[i_work1 + 1] += (g * 7) >> 4;
work3d[i_work1 + 1] += (b * 7) >> 4;
}
if(y > 1) {
if(x < dev_width) {
work1d[i_work2 - 1] += (r * 3) >> 4;
work2d[i_work2 - 1] += (g * 3) >> 4;
work3d[i_work2 - 1] += (b * 3) >> 4;
}
work1d[i_work2] += (r * 5) >> 4;
work2d[i_work2] += (g * 5) >> 4;
work3d[i_work2] += (b * 5) >> 4;
if(x > 1) {
work1d[i_work2 + 1] += r >> 4;
work2d[i_work2 + 1] += g >> 4;
work3d[i_work2 + 1] += b >> 4;
}
}
i_data += 4;
i_work1++;
i_work2++;
}
if(y == 1)
break;
if(i_work1 == dev_width)
i_work2 = 0;
else
i_work1 = 0;
var i_data2 = i_data + (dev_width << 2);
for(i = i_work2, i_end = i_work2 + dev_width; i < i_end; i++) {
work1d[i] = data[i_data2]
work2d[i] = data[i_data2 + 1]
work3d[i] = data[i_data2 + 2]
i_data2 += 4;
}
y--;
}
}
// ディザ 2
function dither_2(data) {
var stride = dev_width << 2;
var i_data = 0;
var i_work = 0;
var x, y;
for(y = dev_height_h; y; y--) {
for(x = dev_width_h; x; x--) {
var i_data2 = i_data + stride;
work1d[i_work] = (data[i_data] + data[i_data + 4] + data[i_data2] + data[i_data2 + 4]) >> 2;
work2d[i_work] = (data[i_data + 1] + data[i_data + 5] + data[i_data2 + 1] + data[i_data2 + 5]) >> 2;
work3d[i_work] = (data[i_data + 2] + data[i_data + 6] + data[i_data2 + 2] + data[i_data2 + 6]) >> 2;
i_data += 8;
i_work++;
}
if(dev_width & 0x1) {
data[i_data] = data[i_data + 1] = data[i_data + 2]
= data[i_data + stride] = data[i_data + stride + 1] = data[i_data + stride + 2] = 0;
i_data += 4;
}
i_data += stride;
}
if(dev_height & 0x1) {
for(x = dev_width; x; x--) {
data[i_data] = data[i_data + 1] = data[i_data + 2] = 0;
i_data += 4;
}
}
i_data = 0;
i_work = 0;
for(y = dev_height_h; y; y--) {
for(x = dev_width_h; x; x--) {
var i_data2 = i_data + stride;
// R
var r = work1d[i_work];
data[i_data] = data[i_data + 4] = data[i_data2] = data[i_data2 + 4]
= (r >= 128) ? (r -= 255, 255) : 0;
// G
var g = work2d[i_work];
data[i_data + 1] = data[i_data + 5] = data[i_data2 + 1] = data[i_data2 + 5]
= (g >= 128) ? (g -= 255, 255) : 0;
// B
var b = work3d[i_work];
data[i_data + 2] = data[i_data + 6] = data[i_data2 + 2] = data[i_data2 + 6]
= (b >= 128) ? (b -= 255, 255) : 0;
if(x > 1) {
work1d[i_work + 1] += (r * 7) >> 4;
work2d[i_work + 1] += (g * 7) >> 4;
work3d[i_work + 1] += (b * 7) >> 4;
}
if(y > 1) {
var i_work2 = i_work + dev_width_h;
if(x < dev_width_h) {
work1d[i_work2 - 1] += (r * 3) >> 4;
work2d[i_work2 - 1] += (g * 3) >> 4;
work3d[i_work2 - 1] += (b * 3) >> 4;
}
work1d[i_work2] += (r * 5) >> 4;
work2d[i_work2] += (g * 5) >> 4;
work3d[i_work2] += (b * 5) >> 4;
if(x > 1) {
work1d[i_work2 + 1] += r >> 4;
work2d[i_work2 + 1] += g >> 4;
work3d[i_work2 + 1] += b >> 4;
}
}
i_data += 8;
i_work++;
}
if(dev_width & 0x1)
i_data += 4;
i_data += stride;
}
}
// ディザ 3
function dither_3(data) {
var i_data = 0;
for(var y = 0; y < dev_height; y++) {
var y2 = (y & 0x3) << 2;
for(var x = 0; x < dev_width; x++) {
var thresh = dither_thresh[y2 | (x & 0x3)];
data[i_data] = (data[i_data] >= thresh) ? 255 : 0;
data[i_data + 1] = (data[i_data + 1] >= thresh) ? 255 : 0;
data[i_data + 2] = (data[i_data + 2] >= thresh) ? 255 : 0;
i_data += 4;
}
}
}
// 網点
function halftone(data) {
var x_adj;
var y_rem;
var i;
// 3 ピクセル単位の余りの部分をクリア
var data32 = new Uint32Array(data.buffer);
switch(x_adj = dev_width % 3) {
case 1:
for(i = dev_size - 1; i > 0; i -= dev_width)
data32[i] = 0xffffffff;
break;
case 2:
for(i = dev_size - 1; i > 0; i -= dev_width)
data32[i - 1] = data32[i] = 0xffffffff;
break;
}
x_adj <<= 2;
if(y_rem = dev_height % 3) {
for(i = dev_width * (dev_height - y_rem); i < dev_size; i++)
data32[i] = 0xffffffff;
}
var stride = dev_width << 2;
var wt = Math.floor(dev_width / 3);
var ht = Math.floor(dev_height / 3);
var i_data1 = data_len - (y_rem + 2) * stride - x_adj;
for(var y = ht; y; y--) {
for(var x = wt; x; x--) {
i_data1 -= 12;
var i_data2, i_data3;
i_data3 = (i_data2 = i_data1 + stride) + stride;
var g_b2, g_b3, b_b2, b_b3;
// R(C)
i = Math.floor((data[i_data1] + data[i_data1 + 4] + data[i_data1 + 8]
+ data[i_data2] + data[i_data2 + 4] + data[i_data2 + 8]
+ data[i_data3] + data[i_data3 + 4] + data[i_data3 + 8]) / 9) >> 4;
data[i_data2 + 4] = halftone_b1[i];
data[i_data1 + 4] = data[i_data2] = data[i_data2 + 8] = data[i_data3 + 4] = halftone_b2[i];
data[i_data1] = data[i_data1 + 8] = data[i_data3] = data[i_data3 + 8] = halftone_b3[i];
// G(M)
// 1 ピクセル右にずらす
i = Math.floor((data[i_data1 + 1] + data[i_data1 + 5] + data[i_data1 + 9]
+ data[i_data2 + 1] + data[i_data2 + 5] + data[i_data2 + 9]
+ data[i_data3 + 1] + data[i_data3 + 5] + data[i_data3 + 9]) / 9) >> 4;
data[i_data2 + 9] = halftone_b1[i];
data[i_data1 + 9] = data[i_data2 + 5] = data[i_data3 + 9] = g_b2 = halftone_b2[i];
data[i_data1 + 5] = data[i_data3 + 5] = g_b3 = halftone_b3[i];
// B(Y)
// 1 ピクセル下にずらす
i = Math.floor((data[i_data1 + 2] + data[i_data1 + 6] + data[i_data1 + 10]
+ data[i_data2 + 2] + data[i_data2 + 6] + data[i_data2 + 10]
+ data[i_data3 + 2] + data[i_data3 + 6] + data[i_data3 + 10]) / 9) >> 4;
data[i_data3 + 6] = halftone_b1[i];
data[i_data2 + 6] = data[i_data3 + 2] = data[i_data3 + 10] = b_b2 = halftone_b2[i];
data[i_data2 + 2] = data[i_data2 + 10] = b_b3 = halftone_b3[i];
if(x < wt || x_adj) {
// G(M)
data[i_data2 + 13] = g_b2;
data[i_data1 + 13] = data[i_data3 + 13] = g_b3;
}
if(y < ht || y_rem) {
// B(Y)
i = i_data3 + stride;
data[i + 6] = b_b2;
data[i + 2] = data[i + 10] = b_b3;
}
}
i_data1 -= x_adj + (stride << 1);
}
for(i = data_len - y_rem * stride + 1; ; ) {
if((i -= stride) < 0)
break;
data[i] = 255;
}
for(i = stride - x_adj + 2; ; ) {
if((i -= 4) < 0)
break;
data[i] = 255;
}
}
// 波紋
function ripple(imgdat) {
var data = new Uint32Array(imgdat.data.buffer);
var x_end = (dev_width & 0x1) ? dev_width_h + 1 : dev_width_h;
var y_end = (dev_height & 0x1) ? dev_height_h + 1 : dev_height_h;
var i = 0;
for(var y = - dev_height_h; y < y_end; y++) {
for(var x = - dev_width_h; x < x_end; x++) {
if(x | y) {
var disp = ripple_sin[(ripple_pha[i] + ripple_time) & 0xff] / ripple_att[i];
var x2 = x + Math.round(x * disp);
var y2 = y + Math.round(y * disp);
if(x >= 0) {
if (x2 < 0)
x2 = 0;
else if(x2 >= x_end)
x2 = x_end - 1;
}
else {
if (x2 >= 0)
x2 = -1;
else if(x2 < - dev_width_h)
x2 = - dev_width_h;
}
if(y >= 0) {
if (y2 < 0)
y2 = 0;
else if(y2 >= y_end)
y2 = y_end - 1;
}
else {
if (y2 >= 0)
y2 = -1;
else if(y2 < - dev_height_h)
y2 = - dev_height_h;
}
work_data32[i] = data[(y2 + dev_height_h) * dev_width + (x2 + dev_width_h)];
}
else {
work_data32[i] = data[i];
}
i++;
}
}
ctx_view.putImageData(work_imgdat, 0, 0);
ripple_time = (ripple_time - 40) & 0xff;
}
// 回転
function rotate() {
ctx_work.drawImage(elem_view, 0, 0);
ctx_view.save();
ctx_view.clip();
ctx_view.translate(video_width_h, video_height_h);
ctx_view.rotate(rotate_angle);
ctx_view.translate(- video_width_h, - video_height_h);
ctx_view.drawImage(elem_work, 0, 0, video_width, video_height);
ctx_view.restore();
if((rotate_angle += 0.05) >= PI2)
rotate_angle -= PI2;
}
proc_tbl = [solar, relief, laplacian_1, laplacian_2, poster_1, poster_2, poster_3, glass, sketch,
dither_1, dither_2, dither_3, halftone, ripple, rotate];
proc = solar;
interval = 200;
// ソラリゼーション用変換マップ
solar_map = new Uint8Array(1200);
for(i = 0; i < 200; i++)
solar_map[i + 1000] = (solar_map[i] = Math.floor(i * 128 / 200)) + 128;
for(; i < 600; i++) {
var sin = Math.sin((i - 200) * Math.PI / 400) * 256 / Math.PI;
solar_map[i] = Math.floor(128 + sin);
solar_map[i + 400] = Math.floor(128 - sin);
}
// ポスタリゼーション用減色処理ワーク
// 8 + 8*8 + 8*8*8 + 8*8*8*8 = 4680
poster_pixels = new Uint32Array(4680);
poster_r_sum = new Uint32Array(4680);
poster_g_sum = new Uint32Array(4680);
poster_b_sum = new Uint32Array(4680);
poster_off = new Uint16Array([0, 8, 72, 584]);
poster_internal = new Uint16Array(51);
poster_internal_cnt = new Uint8Array(3);
poster_r = new Uint8Array(16);
poster_g = new Uint8Array(16);
poster_b = new Uint8Array(16);
// ぼかしフィルター
blur_kernel = new Uint16Array([ 21, 38, 55, 63, 55, 38, 21,
38, 71, 102, 116, 102, 71, 38,
55, 102, 148, 167, 148, 102, 55,
63, 116, 167, 192, 167, 116, 63,
55, 102, 148, 167, 148, 102, 55,
38, 71, 102, 116, 102, 71, 38,
21, 38, 55, 63, 55, 38, 21]);
// ディザ用しきい値
dither_thresh = new Uint8Array([ 15, 136, 45, 166,
196, 75, 226, 105,
60, 181, 30, 151,
241, 120, 211, 90]);
// 網点用明度
halftone_b1 = new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 29, 135, 255]);
halftone_b2 = new Uint8Array([ 7, 20, 34, 48, 63, 79, 96, 113, 132, 152, 175, 200, 228, 251, 255, 255]);
halftone_b3 = new Uint8Array([116, 133, 149, 165, 180, 194, 208, 220, 231, 241, 249, 254, 255, 255, 255, 255]);
// 波紋用 sin テーブル
ripple_sin = new Float32Array(256);
for(i = 0; i < 256; i++)
ripple_sin[i] = Math.sin(i * Math.PI / 128) * 40;
ripple_time = 0;
rotate_angle = 0;
PI2 = 2 * Math.PI;
// ページを再ロードしたときのため
document.forms[0].reset();
document.getElementById("sel").disabled = true;
//-->
</SCRIPT>
</BODY>
</HTML>
|