Skip to content

Commit 463b4a2

Browse files
committed
feat: add arraybuffer-canvas conversion
1 parent 1cc6681 commit 463b4a2

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

jsr.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@snowfluke/ppu-ocv",
3-
"version": "1.2.3",
3+
"version": "1.4.0",
44
"license": "MIT",
55
"exports": "./src/index.ts",
66
"publish": {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ppu-ocv",
3-
"version": "1.3.0",
3+
"version": "1.4.0",
44
"description": "A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing.",
55
"keywords": [
66
"open-cv",
@@ -37,6 +37,7 @@
3737
"eslint": "latest",
3838
"eslint-plugin-jsdoc": "latest",
3939
"mitata": "latest",
40+
"prettier": "^3.6.2",
4041
"tsx": "latest",
4142
"typescript": "latest",
4243
"typescript-eslint": "latest",

src/image-processor.ts

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,60 @@ export class ImageProcessor {
5252
}
5353
}
5454

55+
/**
56+
* Convert array buffer to canvas
57+
*/
5558
static async prepareCanvas(file: ArrayBuffer): Promise<Canvas> {
56-
const img = await loadImage(file);
59+
if (file instanceof Canvas) return file;
5760

61+
const img = await loadImage(file);
5862
const canvas = createCanvas(img.width, img.height);
5963
const ctx = canvas.getContext("2d");
6064

6165
ctx.drawImage(img, 0, 0);
6266
return canvas;
6367
}
6468

69+
/**
70+
* Convert canvas to array buffer
71+
*/
72+
static async prepareBuffer(canvas: Canvas): Promise<ArrayBuffer> {
73+
if (canvas instanceof ArrayBuffer) return canvas;
74+
75+
if (typeof canvas.toBuffer === "function") {
76+
const buffer = canvas.toBuffer("image/png");
77+
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
78+
79+
new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
80+
return arrayBuffer;
81+
}
82+
83+
if (typeof canvas.toDataURL === "function") {
84+
const dataURL = canvas.toDataURL("image/png");
85+
const base64Data = dataURL.replace(/^data:image\/png;base64,/, "");
86+
87+
const buffer = Buffer.from(base64Data, "base64");
88+
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
89+
90+
new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
91+
return arrayBuffer;
92+
}
93+
94+
const ctx = canvas.getContext("2d");
95+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
96+
let canvasBuffer = new ArrayBuffer(imageData.data.byteLength);
97+
98+
new Uint8Array(canvasBuffer).set(
99+
new Uint8Array(
100+
imageData.data.buffer,
101+
imageData.data.byteOffset,
102+
imageData.data.byteLength,
103+
),
104+
);
105+
106+
return canvasBuffer;
107+
}
108+
65109
/**
66110
* Initialize OpenCV runtime, this is recommended to be called before any image processing
67111
*/
@@ -84,7 +128,7 @@ export class ImageProcessor {
84128
*/
85129
execute<Name extends NameWithRequiredOptions>(
86130
operationName: Name,
87-
options: OperationOptions<Name>
131+
options: OperationOptions<Name>,
88132
): this;
89133

90134
/**
@@ -94,7 +138,7 @@ export class ImageProcessor {
94138
*/
95139
execute<Name extends NameWithOptionalOptions>(
96140
operationName: Name,
97-
options?: Partial<OperationOptions<Name>>
141+
options?: Partial<OperationOptions<Name>>,
98142
): this;
99143

100144
/**
@@ -104,7 +148,7 @@ export class ImageProcessor {
104148
*/
105149
execute<Name extends OperationName>(
106150
operationName: Name,
107-
options?: OperationOptions<Name> | Partial<OperationOptions<Name>>
151+
options?: OperationOptions<Name> | Partial<OperationOptions<Name>>,
108152
): this {
109153
if (!registry.hasOperation(operationName)) {
110154
throw new Error(`Operation "${operationName}" not found`);
@@ -114,7 +158,7 @@ export class ImageProcessor {
114158
const result = executeOperation(
115159
operationName,
116160
this.img,
117-
options as Partial<OperationOptions<Name>> | undefined
161+
options as Partial<OperationOptions<Name>> | undefined,
118162
);
119163

120164
this.img = result.img;
@@ -196,7 +240,7 @@ export class ImageProcessor {
196240
*/
197241

198242
morphologicalGradient(
199-
options: Partial<MorphologicalGradientOptions> = {}
243+
options: Partial<MorphologicalGradientOptions> = {},
200244
): this {
201245
return this.execute("morphologicalGradient", options);
202246
}

0 commit comments

Comments
 (0)