big-moving.ru/api/soft/picozu/quantize.js.1

386 lines
12 KiB
Groff
Executable File

/*!
* quantize.js Copyright 2008 Nick Rabinowitz.
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*/
/*!
* Block below copied from Protovis: http://mbostock.github.com/protovis/
* Copyright 2010 Stanford Visualization Group
* Licensed under the BSD License: http://www.opensource.org/licenses/bsd-license.php
*
* Basic Javascript port of the MMCQ (modified median cut quantization)
* algorithm from the Leptonica library (http://www.leptonica.com/).
* Returns a color map you can use to map original pixels to the reduced
* palette. Still a work in progress.
*/
if (!pv) {
var pv = {
map: function (e, t) {
var n = {};
return t ? e.map(function (e, r) {
n.index = r;
return t.call(n, e)
}) : e.slice()
},
naturalOrder: function (e, t) {
return e < t ? -1 : e > t ? 1 : 0
},
sum: function (e, t) {
var n = {};
return e.reduce(t ? function (e, r, i) {
n.index = i;
return e + t.call(n, r)
} : function (e, t) {
return e + t
}, 0)
},
max: function (e, t) {
return Math.max.apply(null, t ? pv.map(e, t) : e)
}
}
}
var MMCQ = function () {
function i(t, n, r) {
return (t << 2 * e) + (n << e) + r
}
function s(e) {
function r() {
t.sort(e);
n = true
}
var t = [],
n = false;
return {
push: function (e) {
t.push(e);
n = false
},
peek: function (e) {
if (!n) r();
if (e === undefined) e = t.length - 1;
return t[e]
},
pop: function () {
if (!n) r();
return t.pop()
},
size: function () {
return t.length
},
map: function (e) {
return t.map(e)
},
debug: function () {
if (!n) r();
return t
}
}
}
function o(e, t, n, r, i, s, o) {
var u = this;
u.r1 = e;
u.r2 = t;
u.g1 = n;
u.g2 = r;
u.b1 = i;
u.b2 = s;
u.histo = o
}
function u() {
this.vboxes = new s(function (e, t) {
return pv.naturalOrder(e.vbox.count() * e.vbox.volume(), t.vbox.count() * t.vbox.volume())
});
}
function a(n) {
var r = 1 << 3 * e,
s = new Array(r),
o, u, a, f;
n.forEach(function (e) {
u = e[0] >> t;
a = e[1] >> t;
f = e[2] >> t;
o = i(u, a, f);
s[o] = (s[o] || 0) + 1
});
return s
}
function f(e, n) {
var r = 1e6,
i = 0,
s = 1e6,
u = 0,
a = 1e6,
f = 0,
l, c, h;
e.forEach(function (e) {
l = e[0] >> t;
c = e[1] >> t;
h = e[2] >> t;
if (l < r) r = l;
else if (l > i) i = l;
if (c < s) s = c;
else if (c > u) u = c;
if (h < a) a = h;
else if (h > f) f = h
});
return new o(r, i, s, u, a, f, n)
}
function l(e, t) {
function v(e) {
var n = e + "1",
r = e + "2",
i, s, o, c, h, p = 0;
for (l = t[n]; l <= t[r]; l++) {
if (a[l] > u / 2) {
o = t.copy();
c = t.copy();
i = l - t[n];
s = t[r] - l;
if (i <= s) h = Math.min(t[r] - 1, ~~ (l + s / 2));
else h = Math.max(t[n], ~~ (l - 1 - i / 2));
while (!a[h]) h++;
p = f[h];
while (!p && a[h - 1]) p = f[--h];
o[r] = h;
c[n] = o[r] + 1;
return [o, c]
}
}
}
if (!t.count()) return;
var n = t.r2 - t.r1 + 1,
r = t.g2 - t.g1 + 1,
s = t.b2 - t.b1 + 1,
o = pv.max([n, r, s]);
if (t.count() == 1) {
return [t.copy()]
}
var u = 0,
a = [],
f = [],
l, c, h, p, d;
if (o == n) {
for (l = t.r1; l <= t.r2; l++) {
p = 0;
for (c = t.g1; c <= t.g2; c++) {
for (h = t.b1; h <= t.b2; h++) {
d = i(l, c, h);
p += e[d] || 0
}
}
u += p;
a[l] = u
}
} else if (o == r) {
for (l = t.g1; l <= t.g2; l++) {
p = 0;
for (c = t.r1; c <= t.r2; c++) {
for (h = t.b1; h <= t.b2; h++) {
d = i(c, l, h);
p += e[d] || 0
}
}
u += p;
a[l] = u
}
} else {
for (l = t.b1; l <= t.b2; l++) {
p = 0;
for (c = t.r1; c <= t.r2; c++) {
for (h = t.g1; h <= t.g2; h++) {
d = i(c, h, l);
p += e[d] || 0
}
}
u += p;
a[l] = u
}
}
a.forEach(function (e, t) {
f[t] = u - e
});
return o == n ? v("r") : o == r ? v("g") : v("b")
}
function c(t, i) {
function v(e, t) {
var r = 1,
i = 0,
s;
while (i < n) {
s = e.pop();
if (!s.count()) {
e.push(s);
i++;
continue
}
var u = l(o, s),
a = u[0],
f = u[1];
if (!a) {
return
}
e.push(a);
if (f) {
e.push(f);
r++
}
if (r >= t) return;
if (i++ > n) {
return
}
}
}
if (!t.length || i < 2 || i > 256) {
return false
}
var o = a(t),
c = 1 << 3 * e;
var h = 0;
o.forEach(function () {
h++
});
if (h <= i) {}
var p = f(t, o),
d = new s(function (e, t) {
return pv.naturalOrder(e.count(), t.count())
});
d.push(p);
v(d, r * i);
var m = new s(function (e, t) {
return pv.naturalOrder(e.count() * e.volume(), t.count() * t.volume())
});
while (d.size()) {
m.push(d.pop())
}
v(m, i - m.size());
var g = new u;
while (m.size()) {
g.push(m.pop())
}
return g
}
var e = 5,
t = 8 - e,
n = 1e3,
r = .75;
o.prototype = {
volume: function (e) {
var t = this;
if (!t._volume || e) {
t._volume = (t.r2 - t.r1 + 1) * (t.g2 - t.g1 + 1) * (t.b2 - t.b1 + 1)
}
return t._volume
},
count: function (e) {
var t = this,
n = t.histo;
if (!t._count_set || e) {
var r = 0,
s, o, u;
for (s = t.r1; s <= t.r2; s++) {
for (o = t.g1; o <= t.g2; o++) {
for (u = t.b1; u <= t.b2; u++) {
index = i(s, o, u);
r += n[index] || 0
}
}
}
t._count = r;
t._count_set = true
}
return t._count
},
copy: function () {
var e = this;
return new o(e.r1, e.r2, e.g1, e.g2, e.b1, e.b2, e.histo)
},
avg: function (t) {
var n = this,
r = n.histo;
if (!n._avg || t) {
var s = 0,
o = 1 << 8 - e,
u = 0,
a = 0,
f = 0,
l, c, h, p, d;
for (c = n.r1; c <= n.r2; c++) {
for (h = n.g1; h <= n.g2; h++) {
for (p = n.b1; p <= n.b2; p++) {
d = i(c, h, p);
l = r[d] || 0;
s += l;
u += l * (c + .5) * o;
a += l * (h + .5) * o;
f += l * (p + .5) * o
}
}
}
if (s) {
n._avg = [~~(u / s), ~~ (a / s), ~~ (f / s)]
} else {
n._avg = [~~(o * (n.r1 + n.r2 + 1) / 2), ~~ (o * (n.g1 + n.g2 + 1) / 2), ~~ (o * (n.b1 + n.b2 + 1) / 2)]
}
}
return n._avg
},
contains: function (e) {
var n = this,
r = e[0] >> t;
gval = e[1] >> t;
bval = e[2] >> t;
return r >= n.r1 && r <= n.r2 && gval >= n.g1 && r <= n.g2 && bval >= n.b1 && r <= n.b2
}
};
u.prototype = {
push: function (e) {
this.vboxes.push({
vbox: e,
color: e.avg()
})
},
palette: function () {
return this.vboxes.map(function (e) {
return e.color
})
},
size: function () {
return this.vboxes.size()
},
map: function (e) {
var t = this.vboxes;
for (var n = 0; n < t.size(); n++) {
if (t.peek(n).vbox.contains(e)) {
return t.peek(n).color
}
}
return this.nearest(e)
},
nearest: function (e) {
var t = this.vboxes,
n, r, i;
for (var s = 0; s < t.size(); s++) {
r = Math.sqrt(Math.pow(e[0] - t.peek(s).color[0], 2) + Math.pow(e[1] - t.peek(s).color[1], 2) + Math.pow(e[1] - t.peek(s).color[1], 2));
if (r < n || n === undefined) {
n = r;
i = t.peek(s).color
}
}
return i
},
forcebw: function () {
var e = this.vboxes;
e.sort(function (e, t) {
return pv.naturalOrder(pv.sum(e.color), pv.sum(t.color))
});
var t = e[0].color;
if (t[0] < 5 && t[1] < 5 && t[2] < 5) e[0].color = [0, 0, 0];
var n = e.length - 1,
r = e[n].color;
if (r[0] > 251 && r[1] > 251 && r[2] > 251) e[n].color = [255, 255, 255]
}
};
return {
quantize: c
}
}()