ppu-ocv 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,7 +77,7 @@ import { CanvasToolkit, ImageProcessor, cv } from "ppu-ocv";
77
77
  const file = Bun.file("./assets/receipt.jpg");
78
78
  const image = await file.arrayBuffer();
79
79
 
80
- const canvasToolkit = new CanvasToolkit();
80
+ const canvasToolkit = CanvasToolkit.getInstance();
81
81
  const canvas = await ImageProcessor.prepareCanvas(image);
82
82
  await ImageProcessor.initRuntime();
83
83
 
@@ -1,7 +1,22 @@
1
1
  import type { BoundingBox, SKRSContext2D } from "./index";
2
2
  import { Canvas, cv } from "./index";
3
+ /**
4
+ * Singleton class for canvas manipulation utilities
5
+ */
3
6
  export declare class CanvasToolkit {
7
+ private static instance;
4
8
  private step;
9
+ /**
10
+ * Private constructor to prevent direct instantiation
11
+ */
12
+ private constructor();
13
+ /**
14
+ * Get the singleton instance of CanvasToolkit
15
+ * @returns The singleton instance
16
+ * @example
17
+ * const canvasToolkit = CanvasToolkit.getInstance();
18
+ */
19
+ static getInstance(): CanvasToolkit;
5
20
  /**
6
21
  * Crop a part of source canvas and return a new canvas of the cropped part
7
22
  * @param options
@@ -9,7 +24,7 @@ export declare class CanvasToolkit {
9
24
  * @param options.canvas Source canvas
10
25
  * @returns A new canvas of the cropped part
11
26
  * @example
12
- * const croppedCanvas = canvasToolkit.crop({
27
+ * const croppedCanvas = CanvasToolkit.getInstance().crop({
13
28
  * bbox: { x0: 10, y0: 10, x1: 100, y1: 100 },
14
29
  * canvas: sourceCanvas,
15
30
  * });
@@ -26,7 +41,7 @@ export declare class CanvasToolkit {
26
41
  * @param options.majorColorThreshold Major color threshold (default: 0.97)
27
42
  * @returns true if the canvas is dirty, false otherwise
28
43
  * @example
29
- * const isDirty = canvasToolkit.isDirty({
44
+ * const isDirty = CanvasToolkit.getInstance().isDirty({
30
45
  * canvas: sourceCanvas,
31
46
  * threshold: 127.5,
32
47
  * majorColorThreshold: 0.97,
@@ -46,7 +61,7 @@ export declare class CanvasToolkit {
46
61
  * @param options.path Path to save the image file (default: "out")
47
62
  * @returns A promise that resolves when the image is saved
48
63
  * @example
49
- * await canvasToolkit.saveImage({
64
+ * await CanvasToolkit.getInstance().saveImage({
50
65
  * canvas: sourceCanvas,
51
66
  * filename: "output.png",
52
67
  * });
package/canvas-toolkit.js CHANGED
@@ -1 +1 @@
1
- export class CanvasToolkit{step=0;crop(options){const{bbox,canvas}=options;let croppedCanvas=createCanvas(bbox.x1-bbox.x0,bbox.y1-bbox.y0);let croppedCtx=croppedCanvas.getContext("2d");croppedCtx.drawImage(canvas,bbox.x0,bbox.y0,bbox.x1-bbox.x0,bbox.y1-bbox.y0,0,0,croppedCanvas.width,croppedCanvas.height);return croppedCanvas}isDirty(options){const{canvas,threshold=127.5,majorColorThreshold=0.97}=options;let whiteCount=0;let blackCount=0;let borderlessCanvas=this.crop({bbox:{x0:canvas.width*0.1,y0:canvas.height*0.1,x1:canvas.width*0.9,y1:canvas.height*0.9},canvas});let ctx=borderlessCanvas.getContext("2d");let colorData=ctx.getImageData(0,0,borderlessCanvas.width,borderlessCanvas.height).data;for(let i=0;i<colorData.length;i+=4){let red=colorData[i];let green=colorData[i+1];let blue=colorData[i+2];if(red>=threshold&&green>=threshold&&blue>=threshold){whiteCount++}else{blackCount++}}let majorColorRatio=Math.max(whiteCount,blackCount)/(blackCount+whiteCount);return majorColorRatio<majorColorThreshold}saveImage(options){const{canvas,filename,path="out"}=options;let folderPath=join(process.cwd(),path);if(!existsSync(folderPath)){mkdirSync(folderPath,{recursive:true})}let filePath=join(folderPath,`${this.step++}. ${filename}.png`);let out=createWriteStream(filePath);let buffer=canvas.toBuffer("image/png");return new Promise((res,rej)=>{out.write(buffer,(err)=>{if(err){rej(err)}else{res()}})})}clearOutput(path="out"){let folderPath=join(process.cwd(),path);if(existsSync(folderPath)){let files=readdirSync(folderPath);for(let file of files){if(file===".gitignore")continue;let filePath=join(folderPath,file);unlinkSync(filePath)}}}drawLine(options){const{ctx,x,y,width,height,lineWidth=2,color="blue"}=options;ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.strokeRect(x,y,width,height);ctx.closePath()}drawContour(options){const{ctx,contour,strokeStyle="red",lineWidth=2}=options;let pts=contour.data32S;if(pts.length<4)return;ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth;ctx.beginPath();ctx.moveTo(pts[0],pts[1]);for(let i=2;i<pts.length;i+=2){ctx.lineTo(pts[i],pts[i+1])}ctx.closePath();ctx.stroke()}}import{createCanvas}from"./index";import{createWriteStream,existsSync,mkdirSync,readdirSync,unlinkSync}from"fs";import{join}from"path";
1
+ export class CanvasToolkit{static instance=null;step=0;constructor(){}static getInstance(){if(!CanvasToolkit.instance){CanvasToolkit.instance=new CanvasToolkit}return CanvasToolkit.instance}crop(options){const{bbox,canvas}=options;let croppedCanvas=createCanvas(bbox.x1-bbox.x0,bbox.y1-bbox.y0);let croppedCtx=croppedCanvas.getContext("2d");croppedCtx.drawImage(canvas,bbox.x0,bbox.y0,bbox.x1-bbox.x0,bbox.y1-bbox.y0,0,0,croppedCanvas.width,croppedCanvas.height);return croppedCanvas}isDirty(options){const{canvas,threshold=127.5,majorColorThreshold=0.97}=options;let whiteCount=0;let blackCount=0;let borderlessCanvas=this.crop({bbox:{x0:canvas.width*0.1,y0:canvas.height*0.1,x1:canvas.width*0.9,y1:canvas.height*0.9},canvas});let ctx=borderlessCanvas.getContext("2d");let colorData=ctx.getImageData(0,0,borderlessCanvas.width,borderlessCanvas.height).data;for(let i=0;i<colorData.length;i+=4){let red=colorData[i];let green=colorData[i+1];let blue=colorData[i+2];if(red>=threshold&&green>=threshold&&blue>=threshold){whiteCount++}else{blackCount++}}let majorColorRatio=Math.max(whiteCount,blackCount)/(blackCount+whiteCount);return majorColorRatio<majorColorThreshold}saveImage(options){const{canvas,filename,path="out"}=options;let folderPath=join(process.cwd(),path);if(!existsSync(folderPath)){mkdirSync(folderPath,{recursive:true})}let filePath=join(folderPath,`${this.step++}. ${filename}.png`);let out=createWriteStream(filePath);let buffer=canvas.toBuffer("image/png");return new Promise((res,rej)=>{out.write(buffer,(err)=>{if(err){rej(err)}else{res()}})})}clearOutput(path="out"){let folderPath=join(process.cwd(),path);if(existsSync(folderPath)){let files=readdirSync(folderPath);for(let file of files){if(file===".gitignore")continue;let filePath=join(folderPath,file);unlinkSync(filePath)}}}drawLine(options){const{ctx,x,y,width,height,lineWidth=2,color="blue"}=options;ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.strokeRect(x,y,width,height);ctx.closePath()}drawContour(options){const{ctx,contour,strokeStyle="red",lineWidth=2}=options;let pts=contour.data32S;if(pts.length<4)return;ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth;ctx.beginPath();ctx.moveTo(pts[0],pts[1]);for(let i=2;i<pts.length;i+=2){ctx.lineTo(pts[i],pts[i+1])}ctx.closePath();ctx.stroke()}}import{createCanvas}from"./index";import{createWriteStream,existsSync,mkdirSync,readdirSync,unlinkSync}from"fs";import{join}from"path";
@@ -21,15 +21,15 @@ export interface CalculateMeanLightnessOptions {
21
21
  * Lightness is normalized based on the image's own maximum lightness value before averaging.
22
22
  *
23
23
  * @param options - Configuration options.
24
- * @returns A promise resolving to the mean normalized lightness (0-1).
24
+ * @returns Mean normalized lightness (0-1).
25
25
  * @throws Error if OpenCV operations fail.
26
26
  */
27
- export declare function calculateMeanNormalizedLabLightness(options: CalculateMeanLightnessOptions): Promise<number>;
27
+ export declare function calculateMeanNormalizedLabLightness(options: CalculateMeanLightnessOptions): number;
28
28
  /**
29
29
  * Calculates the mean pixel value of the image after converting it to grayscale.
30
30
  *
31
31
  * @param canvas - The source canvas to be processed.
32
- * @returns A promise resolving to the mean grayscale value (typically 0-255).
32
+ * @returns Mean grayscale value (typically 0-255).
33
33
  * @throws Error if OpenCV operations fail.
34
34
  */
35
- export declare function calculateMeanGrayscaleValue(canvas: Canvas): Promise<number>;
35
+ export declare function calculateMeanGrayscaleValue(canvas: Canvas): number;
package/image-analysis.js CHANGED
@@ -1 +1 @@
1
- import{ImageProcessor,cv}from"./index";export async function calculateMeanNormalizedLabLightness(options){const{canvas,dimension}=options;let processor=null;let resized=null;let labImg=null;let channels=null;let L=null;let mask=null;let scalarMat=null;try{processor=new ImageProcessor(canvas);resized=processor.execute("resize",{width:dimension.width,height:dimension.height}).toMat();labImg=new cv.Mat;cv.cvtColor(resized,labImg,cv.COLOR_BGR2Lab);channels=new cv.MatVector;cv.split(labImg,channels);L=channels.get(0);mask=new cv.Mat;let maxLocResult=cv.minMaxLoc(L,mask);let maxPixelValue=maxLocResult.maxVal;if(maxPixelValue===0){return 0}scalarMat=new cv.Mat(L.rows,L.cols,L.type(),new cv.Scalar(maxPixelValue));cv.divide(L,scalarMat,L,1,-1);let meanL=cv.mean(L)[0];return meanL??0}finally{processor?.destroy();labImg?.delete();channels?.delete();L?.delete();mask?.delete();scalarMat?.delete()}}export async function calculateMeanGrayscaleValue(canvas){let processor=null;let grayscaleImg=null;try{processor=new ImageProcessor(canvas);grayscaleImg=processor.blur().grayscale().toMat();let mean=cv.mean(grayscaleImg)[0];return mean??0}finally{processor?.destroy()}}
1
+ import{ImageProcessor,cv}from"./index";export function calculateMeanNormalizedLabLightness(options){const{canvas,dimension}=options;let processor=null;let resized=null;let labImg=null;let channels=null;let L=null;let mask=null;let scalarMat=null;try{processor=new ImageProcessor(canvas);resized=processor.execute("resize",{width:dimension.width,height:dimension.height}).toMat();labImg=new cv.Mat;cv.cvtColor(resized,labImg,cv.COLOR_BGR2Lab);channels=new cv.MatVector;cv.split(labImg,channels);L=channels.get(0);mask=new cv.Mat;let maxLocResult=cv.minMaxLoc(L,mask);let maxPixelValue=maxLocResult.maxVal;if(maxPixelValue===0){return 0}scalarMat=new cv.Mat(L.rows,L.cols,L.type(),new cv.Scalar(maxPixelValue));cv.divide(L,scalarMat,L,1,-1);let meanL=cv.mean(L)[0];return meanL??0}finally{processor?.destroy();labImg?.delete();channels?.delete();L?.delete();mask?.delete();scalarMat?.delete()}}export function calculateMeanGrayscaleValue(canvas){let processor=null;let grayscaleImg=null;try{processor=new ImageProcessor(canvas);grayscaleImg=processor.blur().grayscale().toMat();let mean=cv.mean(grayscaleImg)[0];return mean??0}finally{processor?.destroy()}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ppu-ocv",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing.",
5
5
  "keywords": [
6
6
  "open-cv",