JavaScript (ES6), 383 377 354 octets
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)}}
Démo exécutable:
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>
Comment fonctionne ce code est d'utiliser getImageData
pour obtenir un tableau de la forme
[R,G,B,A,
R,G,B,A,
R,G,B,A,
...]
Et map
cela à un tableau de la forme
[[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],
...]
Ainsi, les valeurs R sont mappées sur les tableaux de l'ensemble RGBA et les valeurs B, G et A se transforment en tableaux de valeurs minimales nuls. Lorsque nous trions ce tableau, tous les [0,0,0,0]
tableaux sont classés en bas et les tableaux de valeurs réelles, normalement en haut:
[[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
Nous parcourons le quart supérieur du tableau (pour perdre les valeurs vides que nous avons créées), l'aplatissons avec [].concat.apply
et un tableau de la première forme, mais cette fois, il est trié.
Légèrement défiguré avec des espaces et des commentaires:
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)
}
}
Notez que la plupart des navigateurs peuvent ne pas exécuter ce code pour les images volumineuses, car il transmet un grand nombre d'arguments [].concat
. Lorsque l'environnement du navigateur n'autorise pas suffisamment de mémoire pour tous les arguments, une autre approche consiste à réaffecter les valeurs RGBA des quatrièmes premiers tableaux au tableau, pour un score total de 361 octets :
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)}}
Nous remplaçons simplement le [].concat(...{stuff}).slice(12*w*h)
avec {stuff}.map((v,i,A)=>A[3*w*h+(i>>2)][i%4])
.)