@vibrant/quantizer-mmcq
Advanced tools
Comparing version 4.0.0-alpha.3 to 4.0.0-alpha.4
@@ -0,6 +1,5 @@ | ||
import { Swatch } from '@vibrant/color'; | ||
import { Pixels } from '@vibrant/image'; | ||
import { QuantizerOptions } from '@vibrant/quantizer'; | ||
import { Pixels } from '@vibrant/image'; | ||
import { Swatch } from '@vibrant/color'; | ||
declare const MMCQ: (pixels: Pixels, opts: QuantizerOptions) => Array<Swatch>; | ||
export default MMCQ; | ||
export declare const MMCQ: (pixels: Pixels, opts: QuantizerOptions) => Array<Swatch>; |
import { Swatch } from "@vibrant/color"; | ||
import VBox from "./vbox.js"; | ||
import PQueue from "./pqueue.js"; | ||
import { VBox } from "./vbox.js"; | ||
import { PQueue } from "./pqueue.js"; | ||
const fractByPopulations = 0.75; | ||
@@ -11,2 +11,3 @@ function _splitBoxes(pq, target) { | ||
const [vbox1, vbox2] = vbox.split(); | ||
if (!vbox1) break; | ||
pq.push(vbox1); | ||
@@ -50,4 +51,4 @@ if (vbox2 && vbox2.count() > 0) pq.push(vbox2); | ||
export { | ||
MMCQ as default | ||
MMCQ | ||
}; | ||
//# sourceMappingURL=index.js.map |
interface PQueueComparator<T> { | ||
(a: T, b: T): number; | ||
} | ||
export default class PQueue<T> { | ||
export declare class PQueue<T> { | ||
contents: T[]; | ||
@@ -12,3 +12,3 @@ private _sorted; | ||
peek(index?: number): T; | ||
pop(): T; | ||
pop(): T | undefined; | ||
size(): number; | ||
@@ -15,0 +15,0 @@ map<U>(mapper: (item: T, index: number) => any): U[]; |
@@ -35,4 +35,4 @@ class PQueue { | ||
export { | ||
PQueue as default | ||
PQueue | ||
}; | ||
//# sourceMappingURL=pqueue.js.map |
@@ -0,3 +1,3 @@ | ||
import { Histogram, Pixels } from '@vibrant/image'; | ||
import { Vec3 } from '@vibrant/color'; | ||
import { Pixels, Histogram } from '@vibrant/image'; | ||
@@ -13,3 +13,3 @@ interface Dimension { | ||
} | ||
export default class VBox { | ||
export declare class VBox { | ||
histogram: Histogram; | ||
@@ -16,0 +16,0 @@ static build(pixels: Pixels): VBox; |
@@ -8,2 +8,3 @@ import { Histogram } from "@vibrant/image"; | ||
this._volume = -1; | ||
this._avg = null; | ||
this._count = -1; | ||
@@ -37,2 +38,5 @@ this.dimension = { r1, r2, g1, g2, b1, b2 }; | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) { | ||
continue; | ||
} | ||
c += hist[index]; | ||
@@ -66,2 +70,3 @@ } | ||
const h = hist[index]; | ||
if (!h) continue; | ||
ntot += h; | ||
@@ -117,2 +122,3 @@ rsum += h * (r + 0.5) * mult; | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]; | ||
@@ -132,2 +138,3 @@ } | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]; | ||
@@ -147,2 +154,3 @@ } | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]; | ||
@@ -159,2 +167,3 @@ } | ||
const d = accSum[i]; | ||
if (!d) continue; | ||
if (splitPoint < 0 && d > total / 2) splitPoint = i; | ||
@@ -191,4 +200,4 @@ reverseSum[i] = total - d; | ||
export { | ||
VBox as default | ||
VBox | ||
}; | ||
//# sourceMappingURL=vbox.js.map |
103
package.json
{ | ||
"name": "@vibrant/quantizer-mmcq", | ||
"version": "4.0.0-alpha.3", | ||
"description": "MMCQ quantzier for vibrant", | ||
"scripts": { | ||
"build": "vite build" | ||
}, | ||
"type": "module", | ||
"types": "dist/esm/index.d.ts", | ||
"main": "dist/cjs/index.cjs", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
".": { | ||
"import": { | ||
"types": "./dist/esm/index.d.ts", | ||
"default": "./dist/esm/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/cjs/index.d.cts", | ||
"default": "./dist/cjs/index.cjs" | ||
} | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"sideEffects": false, | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"author": { | ||
"name": "akfish", | ||
"email": "akfish@gmail.com" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/akfish/node-vibrant/issues" | ||
}, | ||
"homepage": "https://github.com/akfish/node-vibrant", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@vibrant/color": "^4.0.0-alpha.3", | ||
"@vibrant/image": "^4.0.0-alpha.3", | ||
"@vibrant/quantizer": "^4.0.0-alpha.3" | ||
}, | ||
"devDependencies": { | ||
"@tanstack/config": "^0.14.2", | ||
"typescript": "^4.5.2", | ||
"vite": "^6.0.3" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "2cdb48edcf5398024bd18a6ed07f2ec50a20030b" | ||
"name": "@vibrant/quantizer-mmcq", | ||
"version": "4.0.0-alpha.4", | ||
"description": "MMCQ quantzier for vibrant", | ||
"scripts": { | ||
"build": "vite build", | ||
"test:eslint": "eslint ./src" | ||
}, | ||
"type": "module", | ||
"types": "dist/esm/index.d.ts", | ||
"main": "dist/cjs/index.cjs", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
".": { | ||
"import": { | ||
"types": "./dist/esm/index.d.ts", | ||
"default": "./dist/esm/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/cjs/index.d.cts", | ||
"default": "./dist/cjs/index.cjs" | ||
} | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"sideEffects": false, | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"author": { | ||
"name": "akfish", | ||
"email": "akfish@gmail.com" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/akfish/node-vibrant/issues" | ||
}, | ||
"homepage": "https://github.com/akfish/node-vibrant", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@vibrant/color": "^4.0.0-alpha.4", | ||
"@vibrant/image": "^4.0.0-alpha.4", | ||
"@vibrant/quantizer": "^4.0.0-alpha.4" | ||
}, | ||
"devDependencies": { | ||
"@tanstack/config": "^0.14.2", | ||
"typescript": "^4.5.2", | ||
"vite": "^6.0.3" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "87c300667e339a8bc4f463d058c0e960f8d18ba9" | ||
} |
# @vibrant/quantizer-mmcq | ||
MMCQ quantzier for vibrant | ||
101
src/index.ts
@@ -1,6 +0,7 @@ | ||
import { Quantizer, QuantizerOptions } from "@vibrant/quantizer"; | ||
import { Pixels } from "@vibrant/image"; | ||
import { Quantizer } from "@vibrant/quantizer"; | ||
import { Filter, Swatch } from "@vibrant/color"; | ||
import VBox from "./vbox"; | ||
import PQueue from "./pqueue"; | ||
import { VBox } from "./vbox"; | ||
import { PQueue } from "./pqueue"; | ||
import type { Pixels } from "@vibrant/image"; | ||
import type { QuantizerOptions } from "@vibrant/quantizer"; | ||
@@ -10,62 +11,62 @@ const fractByPopulations = 0.75; | ||
function _splitBoxes(pq: PQueue<VBox>, target: number): void { | ||
let lastSize = pq.size(); | ||
while (pq.size() < target) { | ||
const vbox = pq.pop(); | ||
let lastSize = pq.size(); | ||
while (pq.size() < target) { | ||
const vbox = pq.pop(); | ||
if (vbox && vbox.count() > 0) { | ||
const [vbox1, vbox2] = vbox.split(); | ||
if (vbox && vbox.count() > 0) { | ||
const [vbox1, vbox2] = vbox.split(); | ||
pq.push(vbox1); | ||
if (vbox2 && vbox2.count() > 0) pq.push(vbox2); | ||
if (!vbox1) break; | ||
// No more new boxes, converged | ||
if (pq.size() === lastSize) { | ||
break; | ||
} else { | ||
lastSize = pq.size(); | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
pq.push(vbox1); | ||
if (vbox2 && vbox2.count() > 0) pq.push(vbox2); | ||
// No more new boxes, converged | ||
if (pq.size() === lastSize) { | ||
break; | ||
} else { | ||
lastSize = pq.size(); | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
const MMCQ = (pixels: Pixels, opts: QuantizerOptions): Array<Swatch> => { | ||
if (pixels.length === 0 || opts.colorCount < 2 || opts.colorCount > 256) { | ||
throw new Error("Wrong MMCQ parameters"); | ||
} | ||
export const MMCQ = (pixels: Pixels, opts: QuantizerOptions): Array<Swatch> => { | ||
if (pixels.length === 0 || opts.colorCount < 2 || opts.colorCount > 256) { | ||
throw new Error("Wrong MMCQ parameters"); | ||
} | ||
const vbox = VBox.build(pixels); | ||
const colorCount = vbox.histogram.colorCount; | ||
const pq = new PQueue<VBox>((a, b) => a.count() - b.count()); | ||
const vbox = VBox.build(pixels); | ||
const colorCount = vbox.histogram.colorCount; | ||
const pq = new PQueue<VBox>((a, b) => a.count() - b.count()); | ||
pq.push(vbox); | ||
pq.push(vbox); | ||
// first set of colors, sorted by population | ||
_splitBoxes(pq, fractByPopulations * opts.colorCount); | ||
// first set of colors, sorted by population | ||
_splitBoxes(pq, fractByPopulations * opts.colorCount); | ||
// Re-order | ||
const pq2 = new PQueue<VBox>( | ||
(a, b) => a.count() * a.volume() - b.count() * b.volume() | ||
); | ||
pq2.contents = pq.contents; | ||
// Re-order | ||
const pq2 = new PQueue<VBox>( | ||
(a, b) => a.count() * a.volume() - b.count() * b.volume(), | ||
); | ||
pq2.contents = pq.contents; | ||
// next set - generate the median cuts using the (npix * vol) sorting. | ||
_splitBoxes(pq2, opts.colorCount - pq2.size()); | ||
// next set - generate the median cuts using the (npix * vol) sorting. | ||
_splitBoxes(pq2, opts.colorCount - pq2.size()); | ||
// calculate the actual colors | ||
return generateSwatches(pq2); | ||
// calculate the actual colors | ||
return generateSwatches(pq2); | ||
}; | ||
function generateSwatches(pq: PQueue<VBox>) { | ||
const swatches: Swatch[] = []; | ||
while (pq.size()) { | ||
const v = pq.pop()!; | ||
const color = v.avg(); | ||
const [r, g, b] = color; | ||
swatches.push(new Swatch(color, v.count())); | ||
} | ||
return swatches; | ||
const swatches: Swatch[] = []; | ||
while (pq.size()) { | ||
const v = pq.pop()!; | ||
const color = v.avg(); | ||
const [r, g, b] = color; | ||
swatches.push(new Swatch(color, v.count())); | ||
} | ||
return swatches; | ||
} | ||
export default MMCQ; |
interface PQueueComparator<T> { | ||
(a: T, b: T): number; | ||
(a: T, b: T): number; | ||
} | ||
export default class PQueue<T> { | ||
contents: T[]; | ||
private _sorted: boolean; | ||
private _comparator: PQueueComparator<T>; | ||
private _sort(): void { | ||
if (!this._sorted) { | ||
this.contents.sort(this._comparator); | ||
this._sorted = true; | ||
} | ||
} | ||
export class PQueue<T> { | ||
contents: T[]; | ||
private _sorted: boolean; | ||
private _comparator: PQueueComparator<T>; | ||
private _sort(): void { | ||
if (!this._sorted) { | ||
this.contents.sort(this._comparator); | ||
this._sorted = true; | ||
} | ||
} | ||
constructor(comparator: PQueueComparator<T>) { | ||
this._comparator = comparator; | ||
this.contents = []; | ||
this._sorted = false; | ||
} | ||
constructor(comparator: PQueueComparator<T>) { | ||
this._comparator = comparator; | ||
this.contents = []; | ||
this._sorted = false; | ||
} | ||
push(item: T): void { | ||
this.contents.push(item); | ||
this._sorted = false; | ||
} | ||
push(item: T): void { | ||
this.contents.push(item); | ||
this._sorted = false; | ||
} | ||
peek(index?: number): T { | ||
this._sort(); | ||
index = typeof index === "number" ? index : this.contents.length - 1; | ||
return this.contents[index]; | ||
} | ||
peek(index?: number): T { | ||
this._sort(); | ||
index = typeof index === "number" ? index : this.contents.length - 1; | ||
return this.contents[index]!; | ||
} | ||
pop() { | ||
this._sort(); | ||
return this.contents.pop(); | ||
} | ||
pop() { | ||
this._sort(); | ||
return this.contents.pop(); | ||
} | ||
size(): number { | ||
return this.contents.length; | ||
} | ||
size(): number { | ||
return this.contents.length; | ||
} | ||
map<U>(mapper: (item: T, index: number) => any): U[] { | ||
this._sort(); | ||
return this.contents.map(mapper); | ||
} | ||
map<U>(mapper: (item: T, index: number) => any): U[] { | ||
this._sort(); | ||
return this.contents.map(mapper); | ||
} | ||
} |
408
src/vbox.ts
@@ -1,11 +0,14 @@ | ||
import { Vec3, Filter } from "@vibrant/color"; | ||
import { Pixels, Histogram } from "@vibrant/image"; | ||
import { Filter } from "@vibrant/color"; | ||
import { Histogram } from "@vibrant/image"; | ||
import type { Vec3 } from "@vibrant/color"; | ||
import type { Pixels } from "@vibrant/image"; | ||
interface Dimension { | ||
r1: number; | ||
r2: number; | ||
g1: number; | ||
g2: number; | ||
b1: number; | ||
b2: number; | ||
[d: string]: number; | ||
r1: number; | ||
r2: number; | ||
g1: number; | ||
g2: number; | ||
b1: number; | ||
b2: number; | ||
[d: string]: number; | ||
} | ||
@@ -16,215 +19,224 @@ | ||
export default class VBox { | ||
static build(pixels: Pixels): VBox { | ||
const h = new Histogram(pixels, { sigBits: SIGBITS }); | ||
const { rmin, rmax, gmin, gmax, bmin, bmax } = h; | ||
return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, h); | ||
} | ||
export class VBox { | ||
static build(pixels: Pixels): VBox { | ||
const h = new Histogram(pixels, { sigBits: SIGBITS }); | ||
const { rmin, rmax, gmin, gmax, bmin, bmax } = h; | ||
return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, h); | ||
} | ||
dimension: Dimension; | ||
dimension: Dimension; | ||
private _volume = -1; | ||
private _avg: Vec3 | null; | ||
private _count = -1; | ||
private _volume = -1; | ||
private _avg: Vec3 | null = null; | ||
private _count = -1; | ||
constructor( | ||
r1: number, | ||
r2: number, | ||
g1: number, | ||
g2: number, | ||
b1: number, | ||
b2: number, | ||
public histogram: Histogram | ||
) { | ||
// NOTE: dimension will be mutated by split operation. | ||
// It must be specified explicitly, not from histogram | ||
this.dimension = { r1, r2, g1, g2, b1, b2 }; | ||
} | ||
constructor( | ||
r1: number, | ||
r2: number, | ||
g1: number, | ||
g2: number, | ||
b1: number, | ||
b2: number, | ||
public histogram: Histogram, | ||
) { | ||
// NOTE: dimension will be mutated by split operation. | ||
// It must be specified explicitly, not from histogram | ||
this.dimension = { r1, r2, g1, g2, b1, b2 }; | ||
} | ||
invalidate(): void { | ||
this._volume = this._count = -1; | ||
this._avg = null; | ||
} | ||
invalidate(): void { | ||
this._volume = this._count = -1; | ||
this._avg = null; | ||
} | ||
volume(): number { | ||
if (this._volume < 0) { | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
this._volume = (r2 - r1 + 1) * (g2 - g1 + 1) * (b2 - b1 + 1); | ||
} | ||
return this._volume; | ||
} | ||
volume(): number { | ||
if (this._volume < 0) { | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
this._volume = (r2 - r1 + 1) * (g2 - g1 + 1) * (b2 - b1 + 1); | ||
} | ||
return this._volume; | ||
} | ||
count(): number { | ||
if (this._count < 0) { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
let c = 0; | ||
count(): number { | ||
if (this._count < 0) { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
let c = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
c += hist[index]; | ||
} | ||
} | ||
} | ||
this._count = c; | ||
} | ||
return this._count; | ||
} | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) { | ||
continue; | ||
} | ||
c += hist[index]!; | ||
} | ||
} | ||
} | ||
this._count = c; | ||
} | ||
return this._count; | ||
} | ||
clone(): VBox { | ||
const { histogram } = this; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
return new VBox(r1, r2, g1, g2, b1, b2, histogram); | ||
} | ||
clone(): VBox { | ||
const { histogram } = this; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
return new VBox(r1, r2, g1, g2, b1, b2, histogram); | ||
} | ||
avg(): Vec3 { | ||
if (!this._avg) { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
let ntot = 0; | ||
const mult = 1 << (8 - SIGBITS); | ||
let rsum: number; | ||
let gsum: number; | ||
let bsum: number; | ||
rsum = gsum = bsum = 0; | ||
avg(): Vec3 { | ||
if (!this._avg) { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
let ntot = 0; | ||
const mult = 1 << (8 - SIGBITS); | ||
let rsum: number; | ||
let gsum: number; | ||
let bsum: number; | ||
rsum = gsum = bsum = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
const h = hist[index]; | ||
ntot += h; | ||
rsum += h * (r + 0.5) * mult; | ||
gsum += h * (g + 0.5) * mult; | ||
bsum += h * (b + 0.5) * mult; | ||
} | ||
} | ||
} | ||
if (ntot) { | ||
this._avg = [~~(rsum / ntot), ~~(gsum / ntot), ~~(bsum / ntot)]; | ||
} else { | ||
this._avg = [ | ||
~~((mult * (r1 + r2 + 1)) / 2), | ||
~~((mult * (g1 + g2 + 1)) / 2), | ||
~~((mult * (b1 + b2 + 1)) / 2), | ||
]; | ||
} | ||
} | ||
return this._avg; | ||
} | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
const h = hist[index]; | ||
if (!h) continue; | ||
ntot += h; | ||
rsum += h * (r + 0.5) * mult; | ||
gsum += h * (g + 0.5) * mult; | ||
bsum += h * (b + 0.5) * mult; | ||
} | ||
} | ||
} | ||
if (ntot) { | ||
this._avg = [~~(rsum / ntot), ~~(gsum / ntot), ~~(bsum / ntot)]; | ||
} else { | ||
this._avg = [ | ||
~~((mult * (r1 + r2 + 1)) / 2), | ||
~~((mult * (g1 + g2 + 1)) / 2), | ||
~~((mult * (b1 + b2 + 1)) / 2), | ||
]; | ||
} | ||
} | ||
return this._avg; | ||
} | ||
contains(rgb: Vec3): boolean { | ||
let [r, g, b] = rgb; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
r >>= RSHIFT; | ||
g >>= RSHIFT; | ||
b >>= RSHIFT; | ||
contains(rgb: Vec3): boolean { | ||
let [r, g, b] = rgb; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
r >>= RSHIFT; | ||
g >>= RSHIFT; | ||
b >>= RSHIFT; | ||
return r >= r1 && r <= r2 && g >= g1 && g <= g2 && b >= b1 && b <= b2; | ||
} | ||
return r >= r1 && r <= r2 && g >= g1 && g <= g2 && b >= b1 && b <= b2; | ||
} | ||
split(): VBox[] { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
const count = this.count(); | ||
if (!count) return []; | ||
if (count === 1) return [this.clone()]; | ||
const rw = r2 - r1 + 1; | ||
const gw = g2 - g1 + 1; | ||
const bw = b2 - b1 + 1; | ||
split(): VBox[] { | ||
const { hist, getColorIndex } = this.histogram; | ||
const { r1, r2, g1, g2, b1, b2 } = this.dimension; | ||
const count = this.count(); | ||
if (!count) return []; | ||
if (count === 1) return [this.clone()]; | ||
const rw = r2 - r1 + 1; | ||
const gw = g2 - g1 + 1; | ||
const bw = b2 - b1 + 1; | ||
const maxw = Math.max(rw, gw, bw); | ||
let accSum: Uint32Array | null = null; | ||
let sum: number; | ||
let total: number; | ||
sum = total = 0; | ||
const maxw = Math.max(rw, gw, bw); | ||
let accSum: Uint32Array | null = null; | ||
let sum: number; | ||
let total: number; | ||
sum = total = 0; | ||
let maxd: "r" | "g" | "b" | null = null; | ||
let maxd: "r" | "g" | "b" | null = null; | ||
if (maxw === rw) { | ||
maxd = "r"; | ||
accSum = new Uint32Array(r2 + 1); | ||
for (let r = r1; r <= r2; r++) { | ||
sum = 0; | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
sum += hist[index]; | ||
} | ||
} | ||
total += sum; | ||
accSum[r] = total; | ||
} | ||
} else if (maxw === gw) { | ||
maxd = "g"; | ||
accSum = new Uint32Array(g2 + 1); | ||
for (let g = g1; g <= g2; g++) { | ||
sum = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
sum += hist[index]; | ||
} | ||
} | ||
total += sum; | ||
accSum[g] = total; | ||
} | ||
} else { | ||
maxd = "b"; | ||
accSum = new Uint32Array(b2 + 1); | ||
for (let b = b1; b <= b2; b++) { | ||
sum = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
const index = getColorIndex(r, g, b); | ||
sum += hist[index]; | ||
} | ||
} | ||
total += sum; | ||
accSum[b] = total; | ||
} | ||
} | ||
if (maxw === rw) { | ||
maxd = "r"; | ||
accSum = new Uint32Array(r2 + 1); | ||
for (let r = r1; r <= r2; r++) { | ||
sum = 0; | ||
for (let g = g1; g <= g2; g++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]!; | ||
} | ||
} | ||
total += sum; | ||
accSum[r] = total; | ||
} | ||
} else if (maxw === gw) { | ||
maxd = "g"; | ||
accSum = new Uint32Array(g2 + 1); | ||
for (let g = g1; g <= g2; g++) { | ||
sum = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let b = b1; b <= b2; b++) { | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]!; | ||
} | ||
} | ||
total += sum; | ||
accSum[g] = total; | ||
} | ||
} else { | ||
maxd = "b"; | ||
accSum = new Uint32Array(b2 + 1); | ||
for (let b = b1; b <= b2; b++) { | ||
sum = 0; | ||
for (let r = r1; r <= r2; r++) { | ||
for (let g = g1; g <= g2; g++) { | ||
const index = getColorIndex(r, g, b); | ||
if (!hist[index]) continue; | ||
sum += hist[index]!; | ||
} | ||
} | ||
total += sum; | ||
accSum[b] = total; | ||
} | ||
} | ||
let splitPoint = -1; | ||
const reverseSum = new Uint32Array(accSum.length); | ||
for (let i = 0; i < accSum.length; i++) { | ||
const d = accSum[i]; | ||
if (splitPoint < 0 && d > total / 2) splitPoint = i; | ||
reverseSum[i] = total - d; | ||
} | ||
let splitPoint = -1; | ||
const reverseSum = new Uint32Array(accSum.length); | ||
for (let i = 0; i < accSum.length; i++) { | ||
const d = accSum[i]; | ||
if (!d) continue; | ||
if (splitPoint < 0 && d > total / 2) splitPoint = i; | ||
reverseSum[i] = total - d; | ||
} | ||
const vbox = this; | ||
const vbox = this; | ||
function doCut(d: string): VBox[] { | ||
const dim1 = d + "1"; | ||
const dim2 = d + "2"; | ||
const d1 = vbox.dimension[dim1]; | ||
let d2 = vbox.dimension[dim2]; | ||
const vbox1 = vbox.clone(); | ||
const vbox2 = vbox.clone(); | ||
const left = splitPoint - d1; | ||
const right = d2 - splitPoint; | ||
if (left <= right) { | ||
d2 = Math.min(d2 - 1, ~~(splitPoint + right / 2)); | ||
d2 = Math.max(0, d2); | ||
} else { | ||
d2 = Math.max(d1, ~~(splitPoint - 1 - left / 2)); | ||
d2 = Math.min(vbox.dimension[dim2], d2); | ||
} | ||
function doCut(d: string): VBox[] { | ||
const dim1 = d + "1"; | ||
const dim2 = d + "2"; | ||
const d1 = vbox.dimension[dim1]!; | ||
let d2 = vbox.dimension[dim2]!; | ||
const vbox1 = vbox.clone(); | ||
const vbox2 = vbox.clone(); | ||
const left = splitPoint - d1; | ||
const right = d2 - splitPoint; | ||
while (!accSum![d2]) d2++; | ||
if (left <= right) { | ||
d2 = Math.min(d2 - 1, ~~(splitPoint + right / 2)); | ||
d2 = Math.max(0, d2); | ||
} else { | ||
d2 = Math.max(d1, ~~(splitPoint - 1 - left / 2)); | ||
d2 = Math.min(vbox.dimension[dim2]!, d2); | ||
} | ||
let c2 = reverseSum[d2]; | ||
while (!c2 && accSum![d2 - 1]) c2 = reverseSum[--d2]; | ||
while (!accSum![d2]) d2++; | ||
vbox1.dimension[dim2] = d2; | ||
vbox2.dimension[dim1] = d2 + 1; | ||
let c2 = reverseSum[d2]; | ||
while (!c2 && accSum![d2 - 1]) c2 = reverseSum[--d2]; | ||
return [vbox1, vbox2]; | ||
} | ||
vbox1.dimension[dim2] = d2; | ||
vbox2.dimension[dim1] = d2 + 1; | ||
return doCut(maxd); | ||
} | ||
return [vbox1, vbox2]; | ||
} | ||
return doCut(maxd); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
60311
925
4