JavaScript (ES6), 301 328 312 bytes
(u,b)=>{i=new Image;i.src=u;e=document.createElement`canvas`;c=e.getContext`2d`;i.onload=_=>{w=e.width=i.width;h=e.height=i.height;c.drawImage(i,0,0);d=c.getImageData(0,0,w,h).data;for(o={},i=0;i<d.length;)++o[s=d.slice(i,i+=4)]?0:o[s]=1;b(o[(a=Object.keys(o).sort((a,b)=>o[b]-o[a]))[0]]==o[a[1]]?"Equal":a[0])}}
Feel free to golf further, this feels as long as Java to me personally.
This supports transparent images so alpha channel is included in output value.
The reason it's longer than before is because now that I've tested, it requires Image
to contain the attribute crossOrigin
, and the arguments to getImageData()
are not optional.
See Meta PCG for removal of CORS from byte count.
Usage
f("http://i.imgur.com/H5OmRVh.jpg", alert)
That will asynchronously alert
a color quadruplet or "Equal" after the image is loaded and counted.
The callback is not considered part of the program length because it is allowed as input by the OP in this special case.
How it works
It constructs an Image
, a Canvas
, and a CanvasRenderingContext2D
, then draws the image to the canvas after setting its width
and height
correctly. It then counts occurrences of each color by implicitly converting each quadruplet to a string and generating a hash of counters. After that, it sorts the hash keys by descending count before comparing the highest two occurrences and determining whether to return the first quadruplet string in the sorted array or the string "Equal"
.
If the demo below displays a SecurityError
, the domain of the image URL you chose does not support CORS.
Demo
f = (u, b) => {
let i = new Image;
i.crossOrigin = ''; // CORS added for demo
i.src = u;
let e = document.createElement `canvas`;
let c = e.getContext `2d`;
i.onload = _ => {
w = e.width = i.width;
h = e.height = i.height;
c.drawImage(i, 0, 0);
d = c.getImageData(0, 0, w, h).data;
for (o = {}, i = 0; i < d.length;)
++o[s = d.slice(i, i += 4)] ? 0 : o[s] = 1;
b(o[(a = Object.keys(o).sort((a, b) => o[b] - o[a]))[0]] == o[a[1]] ? "Equal" : a[0])
}
}
l = i => {
let p = i.nextElementSibling;
p.src = i.value;
f(`http://crossorigin.me/${i.value}`, c => p.nextElementSibling.value = c);
}
document.getElementById `i`.addEventListener('update', e => {
l(e.target)
})
Array.prototype.slice.call(document.querySelectorAll`.i`, 0, 3).forEach(l)
input {
display: block;
box-sizing: border-box;
width: 205px;
height: 18px;
}
input.o {
position: relative;
top: -36px;
}
img {
display: block;
position: relative;
box-sizing: border-box;
top: -18px;
left: 209px;
height: 40px;
}
<input class=i disabled value="https://i.sstatic.net/rqsAX.png">
<img>
<input class=o disabled>
<input class=i disabled value="https://i.sstatic.net/KECpJ.png">
<img>
<input class=o disabled>
<input class=i disabled value="https://i.sstatic.net/DRCWd.png">
<img>
<input class=o disabled>
<input class=i id=i placeholder="Try any image!">
<img>
<input class=o id=o disabled>