From 5c96dc61b9bc608d764d5614f83e82f254264bf2 Mon Sep 17 00:00:00 2001 From: Brian Donovan <1938+eventualbuddha@users.noreply.github.com> Date: Mon, 7 Mar 2022 09:17:43 -0800 Subject: [PATCH] refactor(scan): use canvas `createImageData` I originally made my own version of it because we were using `sharp` to do some of the image processing. We're no longer doing that, so we don't need this anymore. In fact, the results of this function are not compatible with `canvas`, so it's better to just generate them using `canvas` directly. --- .../src/cli/commands/layout.ts | 2 +- .../src/utils/binarize.test.ts | 2 +- .../ballot-interpreter-vx/src/utils/canvas.ts | 33 ---------------- .../src/utils/crop.test.ts | 2 +- libs/ballot-interpreter-vx/src/utils/crop.ts | 2 +- .../src/utils/flip.test.ts | 2 +- .../src/utils/grayscale.test.ts | 38 ++++++------------- .../src/utils/jsfeat/diff.test.ts | 2 +- .../src/utils/jsfeat/mat_to_image_data.ts | 2 +- .../src/utils/outline.ts | 2 +- .../src/utils/template_map.test.ts | 2 +- libs/ballot-interpreter-vx/test/utils.ts | 2 +- 12 files changed, 22 insertions(+), 69 deletions(-) delete mode 100644 libs/ballot-interpreter-vx/src/utils/canvas.ts diff --git a/libs/ballot-interpreter-vx/src/cli/commands/layout.ts b/libs/ballot-interpreter-vx/src/cli/commands/layout.ts index f516366fa..c9a96123f 100644 --- a/libs/ballot-interpreter-vx/src/cli/commands/layout.ts +++ b/libs/ballot-interpreter-vx/src/cli/commands/layout.ts @@ -1,10 +1,10 @@ import { Point, Rect } from '@votingworks/types'; import { assert } from '@votingworks/utils'; import chalk from 'chalk'; +import { createImageData } from 'canvas'; import { GlobalOptions, OptionParseError } from '..'; import { findContests, ContestShape } from '../../hmpb/find_contests'; import { binarize, RGBA } from '../../utils/binarize'; -import { createImageData } from '../../utils/canvas'; import { vh } from '../../utils/flip'; import { getImageChannelCount } from '../../utils/image_format_utils'; import { loadImageData, writeImageData } from '../../utils/images'; diff --git a/libs/ballot-interpreter-vx/src/utils/binarize.test.ts b/libs/ballot-interpreter-vx/src/utils/binarize.test.ts index 445233610..e7595a838 100644 --- a/libs/ballot-interpreter-vx/src/utils/binarize.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/binarize.test.ts @@ -1,6 +1,6 @@ +import { createImageData } from 'canvas'; import { croppedQrCode } from '../../test/fixtures'; import { binarize, RGBA_BLACK, RGBA_WHITE } from './binarize'; -import { createImageData } from './canvas'; test('binarize grayscale', async () => { const imageData = createImageData(2, 2); diff --git a/libs/ballot-interpreter-vx/src/utils/canvas.ts b/libs/ballot-interpreter-vx/src/utils/canvas.ts deleted file mode 100644 index 3f4412e38..000000000 --- a/libs/ballot-interpreter-vx/src/utils/canvas.ts +++ /dev/null @@ -1,33 +0,0 @@ -const RGBA_CHANNEL_COUNT = 4; - -export function createImageData( - data: Uint8ClampedArray, - width: number, - height: number -): ImageData; -export function createImageData(width: number, height: number): ImageData; -export function createImageData(...args: unknown[]): ImageData { - let data: Uint8ClampedArray; - let width: number; - let height: number; - - if ( - args.length === 2 && - typeof args[0] === 'number' && - typeof args[1] === 'number' - ) { - [width, height] = args; - data = new Uint8ClampedArray(width * height * RGBA_CHANNEL_COUNT); - } else if ( - args.length === 3 && - args[0] instanceof Uint8ClampedArray && - typeof args[1] === 'number' && - typeof args[2] === 'number' - ) { - [data, width, height] = args; - } else { - throw new TypeError('unexpected arguments given to createImageData'); - } - - return { data, width, height }; -} diff --git a/libs/ballot-interpreter-vx/src/utils/crop.test.ts b/libs/ballot-interpreter-vx/src/utils/crop.test.ts index f000c55c3..4e3b34b2b 100644 --- a/libs/ballot-interpreter-vx/src/utils/crop.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/crop.test.ts @@ -1,6 +1,6 @@ import { Rect } from '@votingworks/types'; +import { createImageData } from 'canvas'; import { randomImage, randomInset } from '../../test/utils'; -import { createImageData } from './canvas'; import { crop } from './crop'; /** diff --git a/libs/ballot-interpreter-vx/src/utils/crop.ts b/libs/ballot-interpreter-vx/src/utils/crop.ts index 516ea75f2..4482c0080 100644 --- a/libs/ballot-interpreter-vx/src/utils/crop.ts +++ b/libs/ballot-interpreter-vx/src/utils/crop.ts @@ -1,5 +1,5 @@ import { Rect } from '@votingworks/types'; -import { createImageData } from './canvas'; +import { createImageData } from 'canvas'; /** * Returns a new image cropped to the specified bounds. diff --git a/libs/ballot-interpreter-vx/src/utils/flip.test.ts b/libs/ballot-interpreter-vx/src/utils/flip.test.ts index aa4fbcbae..90cea68f0 100644 --- a/libs/ballot-interpreter-vx/src/utils/flip.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/flip.test.ts @@ -1,4 +1,4 @@ -import { createImageData } from './canvas'; +import { createImageData } from 'canvas'; import { vh } from './flip'; test('vh does nothing to 1x1 image (in-place, rgba)', () => { diff --git a/libs/ballot-interpreter-vx/src/utils/grayscale.test.ts b/libs/ballot-interpreter-vx/src/utils/grayscale.test.ts index 5e1318733..95e149b35 100644 --- a/libs/ballot-interpreter-vx/src/utils/grayscale.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/grayscale.test.ts @@ -1,15 +1,11 @@ -import { createImageData } from './canvas'; +import { createImageData } from 'canvas'; import { fromGray, fromRgba } from './grayscale'; test('fromGray with grayscale image', () => { const imageData = createImageData(Uint8ClampedArray.of(127), 1, 1); fromGray(imageData); - expect(imageData).toEqual({ - data: Uint8ClampedArray.of(127), - width: 1, - height: 1, - }); + expect(imageData).toEqual(createImageData(Uint8ClampedArray.of(127), 1, 1)); }); test('fromGray with grayscale image copied', () => { @@ -32,11 +28,9 @@ test('fromRGBA with grayscale image', () => { ); fromRgba(imageData); - expect(imageData).toEqual({ - data: Uint8ClampedArray.of(127, 127, 127, 255), - width: 1, - height: 1, - }); + expect(imageData).toEqual( + createImageData(Uint8ClampedArray.of(127, 127, 127, 255), 1, 1) + ); }); test('fromRGBA with grayscale image copied', () => { @@ -55,11 +49,9 @@ test('fromRGBA with color image', () => { const imageData = createImageData(Uint8ClampedArray.of(255, 0, 0, 255), 1, 1); fromRgba(imageData); - expect(imageData).toEqual({ - data: Uint8ClampedArray.of(53, 53, 53, 255), - width: 1, - height: 1, - }); + expect(imageData).toEqual( + createImageData(Uint8ClampedArray.of(53, 53, 53, 255), 1, 1) + ); }); test('fromRGBA with color image copied RGBA image', () => { @@ -71,11 +63,9 @@ test('fromRGBA with color image copied RGBA image', () => { ); fromRgba(src, dst); - expect(dst).toEqual({ - data: Uint8ClampedArray.of(53, 53, 53, 255), - width: 1, - height: 1, - }); + expect(dst).toEqual( + createImageData(Uint8ClampedArray.of(53, 53, 53, 255), 1, 1) + ); }); test('fromRGBA with color image copied to single-channel image', () => { @@ -87,9 +77,5 @@ test('fromRGBA with color image copied to single-channel image', () => { ); fromRgba(src, dst); - expect(dst).toEqual({ - data: Uint8ClampedArray.of(53), - width: 1, - height: 1, - }); + expect(dst).toEqual(createImageData(Uint8ClampedArray.of(53), 1, 1)); }); diff --git a/libs/ballot-interpreter-vx/src/utils/jsfeat/diff.test.ts b/libs/ballot-interpreter-vx/src/utils/jsfeat/diff.test.ts index c3efadadf..743888660 100644 --- a/libs/ballot-interpreter-vx/src/utils/jsfeat/diff.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/jsfeat/diff.test.ts @@ -1,7 +1,7 @@ import { Rect } from '@votingworks/types'; +import { createImageData } from 'canvas'; import { croppedQrCode } from '../../../test/fixtures'; import { PIXEL_BLACK, PIXEL_WHITE } from '../binarize'; -import { createImageData } from '../canvas'; import { crop } from '../crop'; import { diff, countPixels, ratio } from './diff'; diff --git a/libs/ballot-interpreter-vx/src/utils/jsfeat/mat_to_image_data.ts b/libs/ballot-interpreter-vx/src/utils/jsfeat/mat_to_image_data.ts index d637443a4..c4a51e348 100644 --- a/libs/ballot-interpreter-vx/src/utils/jsfeat/mat_to_image_data.ts +++ b/libs/ballot-interpreter-vx/src/utils/jsfeat/mat_to_image_data.ts @@ -1,5 +1,5 @@ import * as jsfeat from 'jsfeat'; -import { createImageData } from '../canvas'; +import { createImageData } from 'canvas'; export function matToImageData(mat: jsfeat.matrix_t): ImageData { const imageData = createImageData(mat.cols, mat.rows); diff --git a/libs/ballot-interpreter-vx/src/utils/outline.ts b/libs/ballot-interpreter-vx/src/utils/outline.ts index 082d5a9ac..192fd53b4 100644 --- a/libs/ballot-interpreter-vx/src/utils/outline.ts +++ b/libs/ballot-interpreter-vx/src/utils/outline.ts @@ -1,5 +1,5 @@ +import { createImageData } from 'canvas'; import { PIXEL_BLACK } from './binarize'; -import { createImageData } from './canvas'; import { getImageChannelCount } from './image_format_utils'; /** diff --git a/libs/ballot-interpreter-vx/src/utils/template_map.test.ts b/libs/ballot-interpreter-vx/src/utils/template_map.test.ts index d1be465e1..2e44aad43 100644 --- a/libs/ballot-interpreter-vx/src/utils/template_map.test.ts +++ b/libs/ballot-interpreter-vx/src/utils/template_map.test.ts @@ -1,5 +1,5 @@ import { BallotType, BallotPageLayoutWithImage } from '@votingworks/types'; -import { createImageData } from './canvas'; +import { createImageData } from 'canvas'; import { templateMap, TemplateMapKey } from './template_map'; test('no locale info', () => { diff --git a/libs/ballot-interpreter-vx/test/utils.ts b/libs/ballot-interpreter-vx/test/utils.ts index dc094c32c..3366588ac 100644 --- a/libs/ballot-interpreter-vx/test/utils.ts +++ b/libs/ballot-interpreter-vx/test/utils.ts @@ -1,7 +1,7 @@ import { Rect } from '@votingworks/types'; import { assert } from '@votingworks/utils'; import { randomBytes } from 'crypto'; -import { createImageData } from '../src/utils/canvas'; +import { createImageData } from 'canvas'; export function randomImage({ width = 0,