JavaScript(ES6)、383 377 354バイト
f=s=>{d=document,i=new Image,i.src=s,i.onload=$=>{c=d.createElement`canvas`,x=c.getContext`2d`,c.width=w=i.width,c.height=h=i.height,x.drawImage(i,0,0),D=x.getImageData(0,0,w,h),t=D.data,t.set([].concat(...[...t].map((v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)).sort((a,b)=>a.some((v,i)=>k=v-b[i])&&k)).slice(12*w*h)),x.putImageData(D,0,0),d.body.appendChild(c)}}
実行可能なデモ:
f=function(s) {l=[i=new Image].slice,i.crossOrigin="anonymous",i.src=s,i.onload=function($){d=document,c=d.createElement`canvas`,c.width=w=i.width,c.height=h=i.height,x=c.getContext`2d`,x.drawImage(i,0,0),D=x.getImageData(0,0,w,h),t=D.data,t.set([].concat.apply([],l.call(t).map((v,i)=>i%4?[0,0,0,0]:l.call(t,i,i+4)).sort((a,b)=>a.reduce((A,v,i)=>A||v-b[i],0))).slice(3*t.length)),x.putImageData(D,0,0),d.body.appendChild(c)}}
$("img").click(function() { f(this.src); })
canvas { padding-right: 4px; } img { cursor: pointer; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/The_Scream.jpg/114px-The_Scream.jpg"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Claude_Monet_La_Grenouill%C3%A9re.jpg/193px-Claude_Monet_La_Grenouill%C3%A9re.jpg"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Grant_Wood_-_American_Gothic_-_Google_Art_Project.jpg/120px-Grant_Wood_-_American_Gothic_-_Google_Art_Project.jpg"><br>
このコードの仕組みはgetImageData
、フォームの配列を取得するために使用することです
[R,G,B,A,
R,G,B,A,
R,G,B,A,
...]
そしてmap
それをフォームの配列に
[[R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
[R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
[R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
...]
そのため、R値はRGBAセットの配列にマップされ、B、G、およびAの値は最小値のゼロ配列になります。この配列を並べ替えると、すべての[0,0,0,0]
配列は下に並べ替えられ、実数値配列は通常上に並べ替えられます。
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],
[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],
[0,0,0,0],..., [R,G,B,A],[R,G,B,A],[R,G,B,A],...]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
extract & flatten these sorted pixels
(作成した空の値を失うために)配列の上位4分の1をスキムし、でフラット化し[].concat.apply
、再び最初の形式の配列になりますが、今回はソートされています。
空白とコメントで少しデゴルフ:
f=s=>{
// first, load image, then do everything else onload
i=new Image,
i.src = s,
i.onload=$=>{
// set up the canvas
d=document,
c=d.createElement`canvas`,
w=c.width=i.width,
h=c.height=i.height,
x=c.getContext`2d`,
// draw image to canvas and capture pixel data
x.drawImage(i,0,0),
D=x.getImageData(0,0,w,h),
t=D.data,
// set pixel data to...
t.set(
// the flattened array...
[].concat(...
// that is a mapping of the pixel data...
[...t].map(
// that clumps RGBA families into subarrays
// by replacing every fourth value with [R,G,B,A]
// and all other values to [0,0,0,0]...
(v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)
)
// and is then sorted...
.sort(
// by reducing each array to a positive, negative, or zero
// by comparing R,G,B,& A until the first nonzero difference
(a,b)=>a.some((v,i)=>k=v-b[i])&&k
)
)
// then eliminate the low-sorted empty [0,0,0,0] values we created,
// leaving only the top fourth, with real values
// (note that 3*4*w*h is the same as 3*t.length)
.slice(3*4*w*h)
),
// now that `t` is set, store `D` in canvas
x.putImageData(D,0,0),
// show canvas
d.body.appendChild(c)
}
}
ほとんどのブラウザは、膨大な数の引数をに渡すため、大きな画像に対してこのコードを実行できない場合があります[].concat
。ブラウザ環境がすべての引数に十分なメモリを許可しない場合、別の方法は、RGBA値を上位4番目の配列から再マッピングして配列に戻し、合計スコア361バイトにします。
f=s=>{d=document,i=new Image,i.src=s,i.onload=$=>{c=d.createElement`canvas`,x=c.getContext`2d`,c.width=w=i.width,c.height=h=i.height,x.drawImage(i,0,0),D=x.getImageData(0,0,w,h),t=D.data,t.set([...t].map((v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)).sort((a,b)=>a.some((v,i)=>k=v-b[i])&&k).map((v,i,A)=>A[3*w*h+(i>>2)][i%4])),x.putImageData(D,0,0),d.body.appendChild(c)}}
私たちは、単純に置き換える[].concat(...{stuff}).slice(12*w*h)
と{stuff}.map((v,i,A)=>A[3*w*h+(i>>2)][i%4])
。)