Skip to content

Commit

Permalink
feat: BinaryQuantizer added
Browse files Browse the repository at this point in the history
  • Loading branch information
yegor-pelykh committed May 12, 2024
1 parent 3278068 commit 1513fc2
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/filter/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { QuantizeMethod } from './quantize-method';
import { SeparableKernel } from './separable-kernel';
import { ColorUtils } from '../color/color-utils';
import { SolarizeMode } from './solarize-mode';
import { BinaryQuantizer } from '../image/binary-quantizer';

interface ContrastCache {
lastContrast: number;
Expand Down Expand Up @@ -2211,8 +2212,10 @@ export abstract class Filter {
let quantizer: Quantizer | undefined = undefined;
if (method === QuantizeMethod.octree || numberOfColors < 4) {
quantizer = new OctreeQuantizer(opt.image, numberOfColors);
} else {
} else if (method === QuantizeMethod.neuralNet) {
quantizer = new NeuralQuantizer(opt.image, numberOfColors);
} else {
quantizer = new BinaryQuantizer();
}

return Filter.ditherImage({
Expand Down
1 change: 1 addition & 0 deletions src/filter/quantize-method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
export enum QuantizeMethod {
neuralNet,
octree,
binary,
}
9 changes: 7 additions & 2 deletions src/formats/gif-encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Quantizer } from '../image/quantizer';
import { Filter } from '../filter/filter';
import { LibError } from '../error/lib-error';
import { DitherKernel } from '../filter/dither-kernel';
import { BinaryQuantizer } from '../image/binary-quantizer';

export interface GifEncoderInitOptions {
delay?: number;
Expand Down Expand Up @@ -459,8 +460,10 @@ export class GifEncoder implements Encoder {
this._numColors,
this._samplingFactor
);
} else {
} else if (this._quantizerType === QuantizerType.octree) {
this._lastColorMap = new OctreeQuantizer(image, this._numColors);
} else if (this._quantizerType === QuantizerType.binary) {
this._lastColorMap = new BinaryQuantizer();
}

this._lastImage = Filter.ditherImage({
Expand Down Expand Up @@ -497,8 +500,10 @@ export class GifEncoder implements Encoder {
this._numColors,
this._samplingFactor
);
} else {
} else if (this._quantizerType === QuantizerType.octree) {
this._lastColorMap = new OctreeQuantizer(image, this._numColors);
} else {
this._lastColorMap = new BinaryQuantizer();
}

this._lastImage = Filter.ditherImage({
Expand Down
80 changes: 80 additions & 0 deletions src/image/binary-quantizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/** @format */

import { Color } from '../color/color';
import { ColorRgb8 } from '../color/color-rgb8';
import { ColorUtils } from '../color/color-utils';
import { MemoryImage } from './image';
import { Palette } from './palette';
import { PaletteUint8 } from './palette-uint8';
import { Pixel } from './pixel';
import { Quantizer } from './quantizer';

export class BinaryQuantizer implements Quantizer {
private readonly _palette: Palette;
public get palette(): Palette {
return this._palette;
}

private readonly _threshold: number;
public get threshold(): number {
return this._threshold;
}

constructor(threshold: number = 0.5) {
this._palette = new PaletteUint8(2, 3);
this._threshold = threshold;
this._palette.setRgb(1, 255, 255, 255);
}

public getColorIndex(c: Color): number {
return c.luminanceNormalized < this._threshold ? 0 : 1;
}

public getColorIndexRgb(r: number, g: number, b: number): number {
return ColorUtils.getLuminanceRgb(r, g, b) < this._threshold ? 0 : 1;
}

public getQuantizedColor(c: Color): Color {
return c.luminanceNormalized < this._threshold
? new ColorRgb8(
Math.trunc(this._palette.getRed(0)),
Math.trunc(this._palette.getGreen(0)),
Math.trunc(this._palette.getBlue(0))
)
: new ColorRgb8(
Math.trunc(this._palette.getRed(1)),
Math.trunc(this._palette.getGreen(1)),
Math.trunc(this._palette.getBlue(1))
);
}

/**
* Convert the **image** to a palette image.
*/
public getIndexImage(image: MemoryImage): MemoryImage {
const target = new MemoryImage({
width: image.width,
height: image.height,
numChannels: 1,
palette: this.palette,
});

target.frameIndex = image.frameIndex;
target.frameType = image.frameType;
target.frameDuration = image.frameDuration;

const imageIt = image[Symbol.iterator]();
const targetIt = target[Symbol.iterator]();
let imageItRes: IteratorResult<Pixel> | undefined = undefined;
let targetItRes: IteratorResult<Pixel> | undefined = undefined;
while (
(((imageItRes = imageIt.next()), (targetItRes = targetIt.next())),
!imageItRes.done && !targetItRes.done)
) {
const t = targetItRes.value;
t.setChannel(0, this.getColorIndex(imageItRes.value));
}

return target;
}
}
1 change: 1 addition & 0 deletions src/image/quantizer-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
export enum QuantizerType {
octree,
neural,
binary,
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ export { WebPDecoder } from './formats/webp-decoder';
export { WinEncoder } from './formats/win-encoder';

// Export types from 'image' directory
export { BinaryQuantizer } from './image/binary-quantizer';
export { FrameType } from './image/frame-type';
export { HeapNode } from './image/heap-node';
export { IccProfile } from './image/icc-profile';
Expand Down

0 comments on commit 1513fc2

Please sign in to comment.