Skip to content

Commit 883c22f

Browse files
committed
refactor: replace CanvasToolkit instantiation with singleton access
1 parent c0c21ea commit 883c22f

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ import { CanvasToolkit, ImageProcessor, cv } from "ppu-ocv";
7777
const file = Bun.file("./assets/receipt.jpg");
7878
const image = await file.arrayBuffer();
7979

80-
const canvasToolkit = new CanvasToolkit();
80+
const canvasToolkit = CanvasToolkit.getInstance();
8181
const canvas = await ImageProcessor.prepareCanvas(image);
8282
await ImageProcessor.initRuntime();
8383

examples/perspective-correction-with-debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const DEBUG_FOLDER = "out";
88
const canvas = await ImageProcessor.prepareCanvas(image);
99
await ImageProcessor.initRuntime();
1010

11-
const canvasToolkit = new CanvasToolkit();
11+
const canvasToolkit = CanvasToolkit.getInstance();
1212
const processor = new ImageProcessor(canvas);
1313
canvasToolkit.clearOutput(DEBUG_FOLDER);
1414

src/canvas-toolkit.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,39 @@ import {
1010
} from "fs";
1111
import { join } from "path";
1212

13+
/**
14+
* Singleton class for canvas manipulation utilities
15+
*/
1316
export class CanvasToolkit {
17+
private static instance: CanvasToolkit | null = null;
1418
private step: number = 0;
1519

20+
/**
21+
* Private constructor to prevent direct instantiation
22+
*/
23+
private constructor() {}
24+
25+
/**
26+
* Get the singleton instance of CanvasToolkit
27+
* @returns The singleton instance
28+
* @example
29+
* const canvasToolkit = CanvasToolkit.getInstance();
30+
*/
31+
public static getInstance(): CanvasToolkit {
32+
if (!CanvasToolkit.instance) {
33+
CanvasToolkit.instance = new CanvasToolkit();
34+
}
35+
return CanvasToolkit.instance;
36+
}
37+
1638
/**
1739
* Crop a part of source canvas and return a new canvas of the cropped part
1840
* @param options
1941
* @param options.bbox Bounding box of the cropped part
2042
* @param options.canvas Source canvas
2143
* @returns A new canvas of the cropped part
2244
* @example
23-
* const croppedCanvas = canvasToolkit.crop({
45+
* const croppedCanvas = CanvasToolkit.getInstance().crop({
2446
* bbox: { x0: 10, y0: 10, x1: 100, y1: 100 },
2547
* canvas: sourceCanvas,
2648
* });
@@ -54,7 +76,7 @@ export class CanvasToolkit {
5476
* @param options.majorColorThreshold Major color threshold (default: 0.97)
5577
* @returns true if the canvas is dirty, false otherwise
5678
* @example
57-
* const isDirty = canvasToolkit.isDirty({
79+
* const isDirty = CanvasToolkit.getInstance().isDirty({
5880
* canvas: sourceCanvas,
5981
* threshold: 127.5,
6082
* majorColorThreshold: 0.97,
@@ -115,7 +137,7 @@ export class CanvasToolkit {
115137
* @param options.path Path to save the image file (default: "out")
116138
* @returns A promise that resolves when the image is saved
117139
* @example
118-
* await canvasToolkit.saveImage({
140+
* await CanvasToolkit.getInstance().saveImage({
119141
* canvas: sourceCanvas,
120142
* filename: "output.png",
121143
* });

tests/canvas-toolkit.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ test("crop returns correct sub-canvas", () => {
2727
ctx.fillStyle = "red";
2828
ctx.fillRect(2, 3, 4, 5);
2929

30-
const toolkit = new CanvasToolkit();
30+
const toolkit = CanvasToolkit.getInstance();
3131
const cropped = toolkit.crop({
3232
bbox: { x0: 2, y0: 3, x1: 6, y1: 8 },
3333
canvas,
@@ -51,7 +51,7 @@ test("isDirty returns false for uniform canvas and true for checkerboard", () =>
5151
ctx1.fillStyle = "white";
5252
ctx1.fillRect(0, 0, size, size);
5353

54-
const toolkit = new CanvasToolkit();
54+
const toolkit = CanvasToolkit.getInstance();
5555
expect(toolkit.isDirty({ canvas: canvas1 })).toBe(false);
5656

5757
const canvas2 = createCanvas(10, 10);
@@ -74,7 +74,7 @@ test("saveImage and clearOutput manage files correctly", async () => {
7474
ctx.fillStyle = "green";
7575
ctx.fillRect(0, 0, 4, 4);
7676

77-
const toolkit = new CanvasToolkit();
77+
const toolkit = CanvasToolkit.getInstance();
7878

7979
await toolkit.saveImage({
8080
canvas,
@@ -102,7 +102,7 @@ test("saveImage and clearOutput manage files correctly", async () => {
102102
test("drawLine draws a rectangle stroke on canvas", () => {
103103
const canvas = createCanvas(10, 10);
104104
const ctx = canvas.getContext("2d");
105-
const toolkit = new CanvasToolkit();
105+
const toolkit = CanvasToolkit.getInstance();
106106

107107
toolkit.drawLine({
108108
ctx,
@@ -133,7 +133,7 @@ test("drawContour draws given contour", () => {
133133
const canvas = createCanvas(6, 6);
134134

135135
const ctx = canvas.getContext("2d");
136-
const toolkit = new CanvasToolkit();
136+
const toolkit = CanvasToolkit.getInstance();
137137

138138
toolkit.drawContour({ ctx, contour, strokeStyle: "red", lineWidth: 1 });
139139

0 commit comments

Comments
 (0)