学習AIから画像を保護する「NoiseEncoder」
【更新履歴】
・2026/3/24 バージョン1.0公開。
(中略)
・2026/3/24 バージョン1.5公開。
【概要】
・自分で描いた画像を公開したいけど、
AIに学習されるのはイヤだ!
という場合があると思います。
・このツールでは、
加工したアニメpngなどを生成して、
クローリングや、スクレーピングから
あなたの画像を保護します。
・フレームごとの画像は、学習しにくいように
特殊な加工が施されています。
・ダウンロードされる方はこちら。↓
・ソースコードはこちら。↓
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Noise Encoder 1.5</title>
<style>
body { font-family: sans-serif; }
canvas { border:1px solid #ccc; margin:5px; }
#previewArea {
display:flex;
}
button { margin:3px; }
</style>
</head>
<body>
<h2>Noise Encoder 1.5</h2>
<input type="file" id="fileInput"><br><br>
フレーム数: <input type="number" id="frameCount" value="8"><br>
低周波: <input type="number" id="lowFreq" value="12"><br>
ノイズ: <input type="number" id="noise" value="4"><br>
位相: <input type="number" id="phase" step="0.01" value="0.15"><br>
FPS: <input type="number" id="fps" value="60"><br><br>
<button id="generateBtn">生成</button>
<button id="cancelBtn">キャンセル</button>
<button id="playBtn">再生</button>
<button id="stopBtn">停止</button>
<button id="exportPNG">PNG出力</button>
<button id="exportWEBM">WebM出力</button>
<hr>
<div id="previewArea">
<canvas id="original"></canvas>
<canvas id="preview"></canvas>
</div>
<hr>
<button id="prevBtn">前</button>
<button id="nextBtn">次</button>
<span id="frameIndex"></span><br>
<canvas id="frameView"></canvas>
<script>
// ===== 状態 =====
var frames = [];
var timer = null;
var idx = 0;
var w=0,h=0;
// ===== 乱数 =====
function Random(seed){this.s=seed;}
Random.prototype.next=function(){
this.s=(this.s*1664525+1013904223)>>>0;
return this.s/4294967296;
};
// ===== DCT =====
function C(u){return u==0?1/Math.sqrt(2):1;}
function dct(b){
var o=new Array(64);
for(var v=0;v<8;v++)
for(var u=0;u<8;u++){
var s=0;
for(var y=0;y<8;y++)
for(var x=0;x<8;x++){
s+=b[y*8+x]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);
}
o[v*8+u]=0.25*C(u)*C(v)*s;
}
return o;
}
function idct(b){
var o=new Array(64);
for(var y=0;y<8;y++)
for(var x=0;x<8;x++){
var s=0;
for(var v=0;v<8;v++)
for(var u=0;u<8;u++){
s+=C(u)*C(v)*b[v*8+u]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);
}
o[y*8+x]=0.25*s;
}
return o;
}
// ===== フレーム生成 =====
function generate(data,params){
var out=[];
for(var f=0;f<params.frameCount;f++){
var rand=new Random(f*999);
var frame=new Uint8ClampedArray(data.length);
for(var by=0;by<h;by+=8)
for(var bx=0;bx<w;bx+=8){
var r=[],g=[],b=[];
for(var y=0;y<8;y++)
for(var x=0;x<8;x++){
var px=bx+x,py=by+y;
if(px>=w||py>=h){r.push(0);g.push(0);b.push(0);continue;}
var i=(py*w+px)*4;
r.push(data[i]);g.push(data[i+1]);b.push(data[i+2]);
}
var dR=dct(r),dG=dct(g),dB=dct(b);
for(var i=params.lowFreq;i<64;i++){
var j=params.lowFreq+Math.floor(rand.next()*(64-params.lowFreq));
var t=dR[i];dR[i]=dR[j];dR[j]=t;
t=dG[i];dG[i]=dG[j];dG[j]=t;
t=dB[i];dB[i]=dB[j];dB[j]=t;
dR[i]+= (rand.next()-0.5)*params.noise;
dG[i]+= (rand.next()-0.5)*params.noise;
dB[i]+= (rand.next()-0.5)*params.noise;
}
var oR=idct(dR),oG=idct(dG),oB=idct(dB);
for(var y=0;y<8;y++)
for(var x=0;x<8;x++){
var px=bx+x,py=by+y;
if(px>=w||py>=h)continue;
var i=(py*w+px)*4;
var k=y*8+x;
frame[i]=oR[k];
frame[i+1]=oG[k];
frame[i+2]=oB[k];
frame[i+3]=255;
}
}
out.push(frame);
}
return out;
}
// ===== 表示 =====
function showFrame(i){
var c=document.getElementById("frameView");
var ctx=c.getContext("2d");
c.width=w;c.height=h;
var img=ctx.createImageData(w,h);
img.data.set(frames[i]);
ctx.putImageData(img,0,0);
frameIndex.innerText=(i+1)+"/"+frames.length;
}
// ===== 再生 =====
function play(fps){
var c=document.getElementById("preview");
var ctx=c.getContext("2d");
c.width=w;c.height=h;
clearInterval(timer);
idx=0;
timer=setInterval(function(){
var img=ctx.createImageData(w,h);
img.data.set(frames[idx]);
ctx.putImageData(img,0,0);
idx=(idx+1)%frames.length;
},1000/fps);
}
// ===== PNG出力 =====
function exportPNG(){
frames.forEach((f,i)=>{
var c=document.createElement("canvas");
c.width=w;c.height=h;
var ctx=c.getContext("2d");
var img=ctx.createImageData(w,h);
img.data.set(f);
ctx.putImageData(img,0,0);
var a=document.createElement("a");
a.href=c.toDataURL();
a.download="frame_"+i+".png";
a.click();
});
}
// ===== WebM出力 =====
function exportWEBM(){
var c=document.getElementById("preview");
var stream=c.captureStream();
var rec=new MediaRecorder(stream);
var chunks=[];
rec.ondataavailable=e=>chunks.push(e.data);
rec.onstop=e=>{
var blob=new Blob(chunks,{type:"video/webm"});
var a=document.createElement("a");
a.href=URL.createObjectURL(blob);
a.download="output.webm";
a.click();
};
rec.start();
var i=0;
var ctx=c.getContext("2d");
var interval=setInterval(()=>{
var img=ctx.createImageData(w,h);
img.data.set(frames[i]);
ctx.putImageData(img,0,0);
i++;
if(i>=frames.length){
clearInterval(interval);
rec.stop();
}
},1000/30);
}
// ===== UI =====
generateBtn.onclick=function(){
var file=fileInput.files[0];
var img=new Image();
img.onload=function(){
w=img.width;h=img.height;
var c=original;
var ctx=c.getContext("2d");
c.width=w;c.height=h;
ctx.drawImage(img,0,0);
var data=ctx.getImageData(0,0,w,h);
frames=generate(data.data,{
frameCount:+frameCount.value,
lowFreq:+lowFreq.value,
noise:+noise.value,
phase:+phase.value
});
showFrame(0);
play(+fps.value);
};
img.src=URL.createObjectURL(file);
};
prevBtn.onclick=function(){
idx=(idx-1+frames.length)%frames.length;
showFrame(idx);
};
nextBtn.onclick=function(){
idx=(idx+1)%frames.length;
showFrame(idx);
};
playBtn.onclick=function(){ play(+fps.value); };
stopBtn.onclick=function(){ clearInterval(timer); };
exportPNG.onclick=exportPNG;
exportWEBM.onclick=exportWEBM;
</script>
</body>
</html>

コメント