canvas-img 0.0.2 → 0.1.0

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
@@ -1,10 +1,6 @@
1
1
  # canvas-img
2
2
  Canvas draw image cross origin resource
3
3
 
4
- ## TODO
5
- 1. clear img
6
- 2. use Image
7
-
8
4
  ## Demo
9
5
  ```html
10
6
  <!DOCTYPE html>
package/package.json CHANGED
@@ -1,16 +1,21 @@
1
1
  {
2
2
  "name": "canvas-img",
3
- "version": "0.0.2",
4
- "main": "canvas-img.js",
3
+ "version": "0.1.0",
4
+ "description": "Cross-origin image drawing library for Canvas",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "unpkg": "dist/index.js",
9
+ "jsdelivr": "dist/index.js",
5
10
  "scripts": {
6
11
  "test": "echo \"Error: no test specified\" && exit 1"
7
12
  },
8
13
  "keywords": [
9
14
  "canvas",
10
15
  "drawImageCORS",
11
- "canvas-img"
16
+ "canvas-img",
17
+ "cross-origin"
12
18
  ],
13
19
  "author": "molang",
14
- "license": "MIT",
15
- "description": ""
20
+ "license": "MIT"
16
21
  }
@@ -0,0 +1,154 @@
1
+ // src/drawImageCORS.ts
2
+ // import { DrawParams } from './types';
3
+
4
+ /**
5
+ * Load image using hidden img element
6
+ */
7
+ function loadImage(src: string): Promise<HTMLImageElement> {
8
+ return new Promise((resolve, reject) => {
9
+ const img = new Image();
10
+ img.crossOrigin = 'anonymous';
11
+
12
+ const onLoad = () => {
13
+ img.removeEventListener('load', onLoad);
14
+ img.removeEventListener('error', onError);
15
+ resolve(img);
16
+ };
17
+
18
+ const onError = () => {
19
+ img.removeEventListener('load', onLoad);
20
+ img.removeEventListener('error', onError);
21
+
22
+ if (img.parentNode) {
23
+ img.parentNode.removeChild(img);
24
+ }
25
+ reject(new Error(`Failed to load image: ${src}`));
26
+ };
27
+
28
+ img.addEventListener('load', onLoad);
29
+ img.addEventListener('error', onError);
30
+
31
+ img.src = src;
32
+
33
+ // Handle cached images
34
+ if (img.complete) {
35
+ if (img.naturalWidth > 0) {
36
+ img.dispatchEvent(new Event('load'));
37
+ } else {
38
+ img.dispatchEvent(new Event('error'));
39
+ }
40
+ }
41
+ });
42
+ }
43
+
44
+ export type DrawParams =
45
+ | { type: 'simple'; src: string; x: number; y: number }
46
+ | { type: 'scaled'; src: string; x: number; y: number; width: number; height: number }
47
+ | { type: 'cropped'; src: string; sx: number; sy: number; sWidth: number; sHeight: number; dx: number; dy: number; dWidth: number; dHeight: number };
48
+
49
+ /**
50
+ * Parse function arguments
51
+ */
52
+ function parseArguments(args: any[]): DrawParams {
53
+ if (args.length === 3) {
54
+ return {
55
+ type: 'simple',
56
+ src: args[0],
57
+ x: args[1],
58
+ y: args[2],
59
+ };
60
+ } else if (args.length === 5) {
61
+ return {
62
+ type: 'scaled',
63
+ src: args[0],
64
+ x: args[1],
65
+ y: args[2],
66
+ width: args[3],
67
+ height: args[4],
68
+ };
69
+ } else if (args.length === 9) {
70
+ return {
71
+ type: 'cropped',
72
+ src: args[0],
73
+ sx: args[1],
74
+ sy: args[2],
75
+ sWidth: args[3],
76
+ sHeight: args[4],
77
+ dx: args[5],
78
+ dy: args[6],
79
+ dWidth: args[7],
80
+ dHeight: args[8],
81
+ };
82
+ } else {
83
+ throw new Error(
84
+ `Invalid number of arguments: expected 3, 5, or 9 arguments, but got ${args.length}`
85
+ );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Check if context is valid
91
+ */
92
+ function isCanvasValid(ctx: any): ctx is CanvasRenderingContext2D {
93
+ return ctx instanceof CanvasRenderingContext2D;
94
+ }
95
+
96
+ /**
97
+ * Core drawImageCORS function
98
+ */
99
+ function drawImageCORS(this: CanvasRenderingContext2D, ...args: any[]): Promise<HTMLImageElement> {
100
+ const ctx = this;
101
+
102
+ if (!isCanvasValid(ctx)) {
103
+ return Promise.reject(new Error('Invalid canvas context'));
104
+ }
105
+
106
+ let params
107
+ try {
108
+ params = parseArguments(args);
109
+ } catch (e) {
110
+ return Promise.reject(e);
111
+ }
112
+
113
+ const { src } = params;
114
+ if (!src || typeof src !== 'string') {
115
+ return Promise.reject(new Error('Invalid image address'));
116
+ }
117
+
118
+ return loadImage(src)
119
+ .then((img) => {
120
+ if (!isCanvasValid(ctx)) {
121
+ throw new Error('Canvas context is no longer valid');
122
+ }
123
+
124
+ switch (params.type) {
125
+ case 'simple':
126
+ ctx.drawImage(img, params.x, params.y);
127
+ break;
128
+ case 'scaled':
129
+ ctx.drawImage(img, params.x, params.y, params.width, params.height);
130
+ break;
131
+ case 'cropped':
132
+ ctx.drawImage(
133
+ img,
134
+ params.sx,
135
+ params.sy,
136
+ params.sWidth,
137
+ params.sHeight,
138
+ params.dx,
139
+ params.dy,
140
+ params.dWidth,
141
+ params.dHeight
142
+ );
143
+ break;
144
+ }
145
+
146
+ return img;
147
+ })
148
+ .catch((error) => {
149
+ console.error('drawImageCORS failed:', error.message);
150
+ throw error;
151
+ });
152
+ }
153
+
154
+ export default drawImageCORS;
package/src/index.ts ADDED
@@ -0,0 +1,43 @@
1
+ // src/index.ts
2
+ import drawImageCORS from './drawImageCORS';
3
+
4
+ // Extend CanvasRenderingContext2D prototype
5
+ if (typeof CanvasRenderingContext2D !== 'undefined') {
6
+ CanvasRenderingContext2D.prototype.drawImageCORS = drawImageCORS;
7
+ } else if (typeof HTMLCanvasElement !== 'undefined') {
8
+ (HTMLCanvasElement.prototype as any).drawImageCORS = drawImageCORS;
9
+ }
10
+
11
+ // Export types
12
+ // export * from './types';
13
+
14
+ // Declare global augmentation for TypeScript
15
+ declare global {
16
+ interface CanvasRenderingContext2D {
17
+ drawImageCORS(
18
+ src: string,
19
+ x: number,
20
+ y: number
21
+ ): Promise<HTMLImageElement>;
22
+
23
+ drawImageCORS(
24
+ src: string,
25
+ x: number,
26
+ y: number,
27
+ width: number,
28
+ height: number
29
+ ): Promise<HTMLImageElement>;
30
+
31
+ drawImageCORS(
32
+ src: string,
33
+ sx: number,
34
+ sy: number,
35
+ sWidth: number,
36
+ sHeight: number,
37
+ dx: number,
38
+ dy: number,
39
+ dWidth: number,
40
+ dHeight: number
41
+ ): Promise<HTMLImageElement>;
42
+ }
43
+ }
package/src/types.ts ADDED
@@ -0,0 +1,30 @@
1
+ // /**
2
+ // * Extended CanvasRenderingContext2D with drawImageCORS method
3
+ // */
4
+ // export interface CanvasRenderingContext2DWithCORS extends CanvasRenderingContext2D {
5
+ // drawImageCORS(
6
+ // src: string,
7
+ // x: number,
8
+ // y: number
9
+ // ): Promise<HTMLImageElement>;
10
+
11
+ // drawImageCORS(
12
+ // src: string,
13
+ // x: number,
14
+ // y: number,
15
+ // width: number,
16
+ // height: number
17
+ // ): Promise<HTMLImageElement>;
18
+
19
+ // drawImageCORS(
20
+ // src: string,
21
+ // sx: number,
22
+ // sy: number,
23
+ // sWidth: number,
24
+ // sHeight: number,
25
+ // dx: number,
26
+ // dy: number,
27
+ // dWidth: number,
28
+ // dHeight: number
29
+ // ): Promise<HTMLImageElement>;
30
+ // }
package/tsconfig.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Output
4
+ "target": "ES2015",
5
+ "module": "ESNext",
6
+ "lib": ["ES2015", "DOM"],
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+
11
+ // Type Checking
12
+ "strict": true,
13
+ "noUnusedLocals": true,
14
+ "noUnusedParameters": true,
15
+ "noImplicitReturns": true,
16
+ "noFallthroughCasesInSwitch": true,
17
+
18
+ // Interop
19
+ "esModuleInterop": true,
20
+ "allowSyntheticDefaultImports": true,
21
+ "resolveJsonModule": true,
22
+
23
+ // Advanced
24
+ "skipLibCheck": true,
25
+ "forceConsistentCasingInFileNames": true,
26
+ "removeComments": false,
27
+ "preserveConstEnums": true
28
+ },
29
+ "include": ["src/**/*"],
30
+ "exclude": ["node_modules", "dist", "demo"]
31
+ }
package/READMME.md DELETED
@@ -1,97 +0,0 @@
1
- # canvas-img
2
- Canvas draw image cross origin resource
3
-
4
- ## Demo
5
- ```html
6
- <!DOCTYPE html>
7
- <html>
8
- <head>
9
- <meta charset="UTF-8">
10
- <title>drawImageCORS demo</title>
11
- </head>
12
- <body>
13
- <canvas id="myCanvas" width="800" height="600"></canvas>
14
-
15
- <script src="canvas-img.js"></script>
16
-
17
- <script>
18
- const canvas = document.getElementById('myCanvas');
19
- const ctx = canvas.getContext('2d');
20
-
21
- // drawImageCORS (src, x, y)
22
- ctx.drawImageCORS('https://picsum.photos/400/300', 50, 50)
23
- .then(() => console.log('done'))
24
- .catch(err => console.error('error:', err));
25
-
26
- // drawImageCORS (src, x, y, width, height)
27
- ctx.drawImageCORS('https://picsum.photos/400/200', 500, 50, 200, 150)
28
- .then(() => console.log('done'));
29
-
30
- // drawImageCORS (src, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
31
- ctx.drawImageCORS(
32
- 'https://picsum.photos/400/400',
33
- 50, 50, 200, 150, // clip
34
- 50, 300, 200, 150
35
- );
36
-
37
- async function loadMultiple() {
38
- try {
39
- await ctx.drawImageCORS('https://picsum.photos/200/200', 0, 0);
40
- await ctx.drawImageCORS('https://picsum.photos/200/200', 200, 0);
41
- await ctx.drawImageCORS('https://picsum.photos/200/200', 400, 0);
42
- console.log('all done');
43
- } catch (error) {
44
- console.error('load error:', error);
45
- }
46
- }
47
-
48
- loadMultiple();
49
- </script>
50
- </body>
51
- </html><!DOCTYPE html>
52
- <html>
53
- <head>
54
- <meta charset="UTF-8">
55
- <title>drawImageCORS demo</title>
56
- </head>
57
- <body>
58
- <canvas id="myCanvas" width="800" height="600"></canvas>
59
-
60
- <script src="canvas-img.js"></script>
61
-
62
- <script>
63
- const canvas = document.getElementById('myCanvas');
64
- const ctx = canvas.getContext('2d');
65
-
66
- // drawImageCORS (src, x, y)
67
- ctx.drawImageCORS('https://picsum.photos/400/300', 50, 50)
68
- .then(() => console.log('done'))
69
- .catch(err => console.error('error:', err));
70
-
71
- // drawImageCORS (src, x, y, width, height)
72
- ctx.drawImageCORS('https://picsum.photos/400/200', 500, 50, 200, 150)
73
- .then(() => console.log('done'));
74
-
75
- // drawImageCORS (src, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
76
- ctx.drawImageCORS(
77
- 'https://picsum.photos/400/400',
78
- 50, 50, 200, 150, // clip
79
- 50, 300, 200, 150
80
- );
81
-
82
- async function loadMultiple() {
83
- try {
84
- await ctx.drawImageCORS('https://picsum.photos/200/200', 0, 0);
85
- await ctx.drawImageCORS('https://picsum.photos/200/200', 200, 0);
86
- await ctx.drawImageCORS('https://picsum.photos/200/200', 400, 0);
87
- console.log('all done');
88
- } catch (error) {
89
- console.error('load error:', error);
90
- }
91
- }
92
-
93
- loadMultiple();
94
- </script>
95
- </body>
96
- </html>
97
- ```
package/canvas-img.js DELETED
@@ -1,174 +0,0 @@
1
- /**
2
- * canvas.drawImageCORS - Cross-origin image drawing library
3
- * Loads images by dynamically creating hidden <img> elements, then draws them to canvas after loading completes
4
- *
5
- * Usage:
6
- * canvas.drawImageCORS(src, x, y)
7
- * canvas.drawImageCORS(src, x, y, width, height)
8
- * canvas.drawImageCORS(src, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
9
- *
10
- * Returns: Promise that resolves when the image is loaded and drawn
11
- */
12
-
13
- (function () {
14
- function loadImage(src) {
15
- return new Promise((resolve, reject) => {
16
- // const img = createHiddenImg(src);
17
- const img = new Image()
18
-
19
- const onLoad = function () {
20
- // console.log('loaded')
21
-
22
- img.removeEventListener("load", onLoad);
23
- img.removeEventListener("error", onError);
24
- resolve(img);
25
- };
26
-
27
- const onError = function () {
28
- img.removeEventListener("load", onLoad);
29
- img.removeEventListener("error", onError);
30
-
31
- if (img.parentNode) {
32
- img.parentNode.removeChild(img);
33
- }
34
- reject("Load image error " + src);
35
- };
36
-
37
-
38
-
39
- img.src = src;
40
-
41
- // If the image is already cached (browser cache), complete may be true
42
- if (img.complete) {
43
- // console.log('cached')
44
- // But onload may or may not have been triggered, handle it manually
45
- if (img.naturalWidth > 0) {
46
- // Manually trigger the load event
47
- const loadEvent = new Event("load");
48
- img.dispatchEvent(loadEvent);
49
- } else {
50
- // Manually trigger the error event
51
- const errorEvent = new Event("error");
52
- img.dispatchEvent(errorEvent);
53
- }
54
- resolve(img);
55
- }else{
56
- img.addEventListener("load", onLoad);
57
- img.addEventListener("error", onError);
58
- }
59
- });
60
- }
61
-
62
- function parseArguments(args) {
63
- if (args.length === 3) {
64
- // drawImageCORS(src, x, y)
65
- return {
66
- type: "simple",
67
- src: args[0],
68
- x: args[1],
69
- y: args[2],
70
- };
71
- } else if (args.length === 5) {
72
- // drawImageCORS(src, x, y, width, height)
73
- return {
74
- type: "scaled",
75
- src: args[0],
76
- x: args[1],
77
- y: args[2],
78
- width: args[3],
79
- height: args[4],
80
- };
81
- } else if (args.length === 9) {
82
- // drawImageCORS(src, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
83
- return {
84
- type: "cropped",
85
- src: args[0],
86
- sx: args[1],
87
- sy: args[2],
88
- sWidth: args[3],
89
- sHeight: args[4],
90
- dx: args[5],
91
- dy: args[6],
92
- dWidth: args[7],
93
- dHeight: args[8],
94
- };
95
- } else {
96
- throw new Error("Invalid number of arguments: expected 3, 5, or 9 arguments, but got ${args.length}");
97
- }
98
- }
99
-
100
- function isCanvasValid(ctx) {
101
- return ctx instanceof CanvasRenderingContext2D;
102
- }
103
-
104
- function drawImageCORS(...args) {
105
- const ctx = this;
106
-
107
- if (!isCanvasValid(ctx)) {
108
- return Promise.reject(new Error("Invalid canvas"));
109
- }
110
-
111
- let params;
112
- try {
113
- params = parseArguments(args);
114
- } catch (e) {
115
- return Promise.reject(e);
116
- }
117
-
118
- const src = params.src;
119
- if (!src || typeof src !== "string") {
120
- return Promise.reject(new Error("Invalid image address"));
121
- }
122
-
123
- return loadImage(src)
124
- .then((img) => {
125
- if (!isCanvasValid(ctx)) {
126
- throw new Error("Invalid canvas");
127
- }
128
-
129
- switch (params.type) {
130
- case "simple":
131
- ctx.drawImage(img, params.x, params.y);
132
- break;
133
- case "scaled":
134
- ctx.drawImage(img, params.x, params.y, params.width, params.height);
135
- break;
136
- case "cropped":
137
- ctx.drawImage(
138
- img,
139
- params.sx,
140
- params.sy,
141
- params.sWidth,
142
- params.sHeight,
143
- params.dx,
144
- params.dy,
145
- params.dWidth,
146
- params.dHeight,
147
- );
148
- break;
149
- }
150
-
151
- return img;
152
- })
153
- .catch((error) => {
154
- console.error("drawImageCORS faild:", error.message);
155
- throw error;
156
- });
157
- }
158
-
159
- if (typeof CanvasRenderingContext2D !== "undefined") {
160
- CanvasRenderingContext2D.prototype.drawImageCORS = drawImageCORS;
161
- } else {
162
- if (typeof HTMLCanvasElement !== "undefined") {
163
- HTMLCanvasElement.prototype.drawImageCORS = drawImageCORS;
164
- }
165
- }
166
-
167
- if (typeof module !== "undefined" && module.exports) {
168
- module.exports = {
169
- drawImageCORS,
170
- };
171
- } else if (typeof window !== "undefined") {
172
- window.drawImageCORS = drawImageCORS;
173
- }
174
- })();
File without changes