mjpic 1.0.20 → 1.0.21

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.
@@ -73,6 +73,82 @@ interface ImageState {
73
73
  reset: () => void;
74
74
  }
75
75
 
76
+ const sanitizeTransparentEdges = (canvas: HTMLCanvasElement) => {
77
+ const ctx = canvas.getContext('2d', { willReadFrequently: true } as any) as CanvasRenderingContext2D | null;
78
+ if (!ctx) return;
79
+
80
+ const { width, height } = canvas;
81
+ if (width <= 1 || height <= 1) return;
82
+
83
+ const imageData = ctx.getImageData(0, 0, width, height);
84
+ const { data } = imageData;
85
+
86
+ const isRowTransparent = (y: number) => {
87
+ for (let x = 0; x < width; x += 1) {
88
+ if (data[(y * width + x) * 4 + 3] !== 0) return false;
89
+ }
90
+ return true;
91
+ };
92
+
93
+ const isColumnTransparent = (x: number) => {
94
+ for (let y = 0; y < height; y += 1) {
95
+ if (data[(y * width + x) * 4 + 3] !== 0) return false;
96
+ }
97
+ return true;
98
+ };
99
+
100
+ const copyRow = (fromY: number, toY: number) => {
101
+ for (let x = 0; x < width; x += 1) {
102
+ const from = (fromY * width + x) * 4;
103
+ const to = (toY * width + x) * 4;
104
+ data[to] = data[from];
105
+ data[to + 1] = data[from + 1];
106
+ data[to + 2] = data[from + 2];
107
+ data[to + 3] = data[from + 3];
108
+ }
109
+ };
110
+
111
+ const copyColumn = (fromX: number, toX: number) => {
112
+ for (let y = 0; y < height; y += 1) {
113
+ const from = (y * width + fromX) * 4;
114
+ const to = (y * width + toX) * 4;
115
+ data[to] = data[from];
116
+ data[to + 1] = data[from + 1];
117
+ data[to + 2] = data[from + 2];
118
+ data[to + 3] = data[from + 3];
119
+ }
120
+ };
121
+
122
+ let top = 0;
123
+ while (top < height && isRowTransparent(top)) top += 1;
124
+
125
+ let bottom = height - 1;
126
+ while (bottom >= 0 && isRowTransparent(bottom)) bottom -= 1;
127
+
128
+ let left = 0;
129
+ while (left < width && isColumnTransparent(left)) left += 1;
130
+
131
+ let right = width - 1;
132
+ while (right >= 0 && isColumnTransparent(right)) right -= 1;
133
+
134
+ if (top >= height || bottom < 0 || left >= width || right < 0) return;
135
+
136
+ for (let y = 0; y < top; y += 1) {
137
+ copyRow(top, y);
138
+ }
139
+ for (let y = bottom + 1; y < height; y += 1) {
140
+ copyRow(bottom, y);
141
+ }
142
+ for (let x = 0; x < left; x += 1) {
143
+ copyColumn(left, x);
144
+ }
145
+ for (let x = right + 1; x < width; x += 1) {
146
+ copyColumn(right, x);
147
+ }
148
+
149
+ ctx.putImageData(imageData, 0, 0);
150
+ };
151
+
76
152
  const defaultConfig: ImageConfig = {
77
153
  rotation: 0,
78
154
  scale: 1,
@@ -225,6 +301,7 @@ export const useImageStore = create<ImageState>((set, get) => ({
225
301
  }
226
302
 
227
303
  ctx.drawImage(img, -drawWidth / 2, -drawHeight / 2, drawWidth, drawHeight);
304
+ sanitizeTransparentEdges(canvas);
228
305
 
229
306
  const croppedImage = canvas.toDataURL('image/png');
230
307