的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
我们浏览数组的前四分之一(以丢失我们创建的空值),使用展平它[].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值从顶部的第四个数组重新映射回该数组,总得分为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])
)。