diff --git a/src/binarizer/index.ts b/src/binarizer/index.ts index 9f230653..7744b229 100644 --- a/src/binarizer/index.ts +++ b/src/binarizer/index.ts @@ -1,4 +1,5 @@ import {BitMatrix} from "../BitMatrix"; +import {GreyscaleWeights} from "../index"; const REGION_SIZE = 8; const MIN_DYNAMIC_RANGE = 24; @@ -23,18 +24,35 @@ class Matrix { } } -export function binarize(data: Uint8ClampedArray, width: number, height: number, returnInverted: boolean) { +export function binarize(data: Uint8ClampedArray, width: number, height: number, returnInverted: boolean, + greyscaleWeights: GreyscaleWeights) { if (data.length !== width * height * 4) { throw new Error("Malformed data passed to binarizer."); } // Convert image to greyscale const greyscalePixels = new Matrix(width, height); - for (let x = 0; x < width; x++) { - for (let y = 0; y < height; y++) { - const r = data[((y * width + x) * 4) + 0]; - const g = data[((y * width + x) * 4) + 1]; - const b = data[((y * width + x) * 4) + 2]; - greyscalePixels.set(x, y, 0.2126 * r + 0.7152 * g + 0.0722 * b); + if (greyscaleWeights.useIntegerApproximation) { + for (let x = 0; x < width; x++) { + for (let y = 0; y < height; y++) { + const pixelPosition = (y * width + x) * 4; + const r = data[pixelPosition]; + const g = data[pixelPosition + 1]; + const b = data[pixelPosition + 2]; + greyscalePixels.set(x, y, + // tslint:disable-next-line no-bitwise + (greyscaleWeights.red * r + greyscaleWeights.green * g + greyscaleWeights.blue * b + 128) >> 8); + } + } + } else { + for (let x = 0; x < width; x++) { + for (let y = 0; y < height; y++) { + const pixelPosition = (y * width + x) * 4; + const r = data[pixelPosition]; + const g = data[pixelPosition + 1]; + const b = data[pixelPosition + 2]; + greyscalePixels.set(x, y, + greyscaleWeights.red * r + greyscaleWeights.green * g + greyscaleWeights.blue * b); + } } } const horizontalRegionCount = Math.ceil(width / REGION_SIZE); diff --git a/src/index.ts b/src/index.ts index 65116049..53b116da 100644 --- a/src/index.ts +++ b/src/index.ts @@ -56,10 +56,24 @@ function scan(matrix: BitMatrix): QRCode | null { export interface Options { inversionAttempts?: "dontInvert" | "onlyInvert" | "attemptBoth" | "invertFirst"; + greyScaleWeights?: GreyscaleWeights; +} + +export interface GreyscaleWeights { + red: number; + green: number; + blue: number; + useIntegerApproximation?: boolean; } const defaultOptions: Options = { inversionAttempts: "attemptBoth", + greyScaleWeights: { + red: 0.2126, + green: 0.7152, + blue: 0.0722, + useIntegerApproximation: false, + }, }; function jsQR(data: Uint8ClampedArray, width: number, height: number, providedOptions: Options = {}): QRCode | null { @@ -71,7 +85,7 @@ function jsQR(data: Uint8ClampedArray, width: number, height: number, providedOp const shouldInvert = options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst"; const tryInvertedFirst = options.inversionAttempts === "onlyInvert" || options.inversionAttempts === "invertFirst"; - const {binarized, inverted} = binarize(data, width, height, shouldInvert); + const {binarized, inverted} = binarize(data, width, height, shouldInvert, options.greyScaleWeights); let result = scan(tryInvertedFirst ? inverted : binarized); if (!result && (options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst")) { result = scan(tryInvertedFirst ? binarized : inverted);