Skip to content

Commit 23b0afa

Browse files
authored
Merge pull request #132 from Pascal-Institute/develop
merge 1.0.12
2 parents 4786e41 + f86edda commit 23b0afa

20 files changed

Lines changed: 316 additions & 287 deletions

PRIVACYPOLICY.md

Lines changed: 0 additions & 63 deletions
This file was deleted.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#### The Image Processing & Analysis Tool based on Electron framework & sharp npm package
88

9-
<img width="1259" height="1007" alt="image" src="https://github.com/user-attachments/assets/c6dbe835-26d8-40ab-8fa4-a6a330e23baf" />
9+
<img width="1257" height="1011" alt="image" src="https://github.com/user-attachments/assets/03b939c2-9f7b-40e2-8b40-d4b9ae100f31" />
1010

1111
## 0. Application mission : Give wings to pixels
1212

@@ -66,7 +66,7 @@ npm run build
6666
### 4-1. Availiable file extension
6767

6868
```bash
69-
png svg jpg jpeg webp gif bmp ico tiff tif avif
69+
png svg jpg jpeg webp gif bmp ico tiff tif avif heif heic pix
7070
```
7171

7272
**Note:** Animated GIF files are now supported! When you load an animated GIF, playback controls appear automatically. See [GIF Animation Documentation](docs/GIF_ANIMATION.md) for details.

assets/pix.pix

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"width": 8,
3+
"height": 8,
4+
"channel": 1,
5+
"depth": 8,
6+
"compression": {
7+
"method": "none"
8+
},
9+
"hex_data": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
10+
"label": {
11+
"cat": [22, 44],
12+
"dog": [100, 103]
13+
}
14+
}

css/paint_panel.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#watermarkBtn:hover,
55
#colorpickerBtn:hover,
66
#colorpickerBox:hover,
7+
#padColorBox:hover,
78
#padBtn:hover,
89
#watermarkUploadBtn:hover {
910
cursor: pointer;
@@ -41,6 +42,7 @@
4142
right: 0px;
4243
}
4344

45+
#padColorBox,
4446
#colorpickerBox {
4547
margin-left: 5px;
4648
width: 36px;
@@ -49,6 +51,7 @@
4951
background-color: black;
5052
}
5153

54+
#padIndicator,
5255
#colorpickerIndicator {
5356
display: flex;
5457
align-items: center;
@@ -62,6 +65,7 @@
6265
object-fit: contain;
6366
}
6467

68+
#padColorValue,
6569
#padValue {
6670
width: 80px;
6771
margin-left: 5px;

imgkit/core/image_layer.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const { ImageLoader } = require("../processing/image_loader");
2222
const { ModeManager } = require("../features/image_mode");
2323
const { LayerHistory } = require("../features/layer_history");
2424
const { GifAnimation } = require("../features/gif_animation");
25+
const { Pix } = require("./pix");
2526

2627
const LAYER_EVENT_CHANNEL = "imgkit-layer-event";
2728
let nextLayerId = 1;
@@ -493,6 +494,13 @@ class ImageLayer {
493494
// If saving as SVG and we have SVG data, save the actual SVG
494495
if (this.extension === "svg" && this.svgData) {
495496
buffer = Buffer.from(this.svgData, "utf-8");
497+
} else if (this.extension === "pix") {
498+
// For PIX format, convert back to PIX buffer
499+
const pixData = await Pix.toPix(this.buffer, this.info);
500+
await Pix.save(pixData, savePath);
501+
this.filepath = savePath;
502+
ipcRenderer.send("showNotificationREQ", "imgkit-save");
503+
return;
496504
} else {
497505
// For other formats, extract from canvas
498506
const base64Data = this.image.src.replace(

imgkit/core/main_renderer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,9 @@ class ImgKitRenderer {
264264
if (!entry) continue;
265265

266266
const targetLayer =
267-
i === 0 ? this.getLayerById(targetLayerId) : this.createImageLayer(false);
267+
i === 0
268+
? this.getLayerById(targetLayerId)
269+
: this.createImageLayer(false);
268270
if (!targetLayer) continue;
269271

270272
let success = false;

imgkit/core/pix.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const jsonfile = require("jsonfile");
2+
const sharp = require("sharp");
3+
4+
class Pix {
5+
static open(path) {
6+
try {
7+
const data = jsonfile.readFileSync(path);
8+
return data;
9+
} catch (err) {
10+
console.error("Error reading pixData.json:", err);
11+
return null;
12+
}
13+
}
14+
15+
static save(pixData, path) {
16+
try {
17+
jsonfile.writeFileSync(path, pixData, { spaces: 2 });
18+
} catch (err) {
19+
console.error("Error writing pixData.json:", err);
20+
}
21+
}
22+
23+
static openFromBuffer(buffer) {
24+
try {
25+
const text = Buffer.isBuffer(buffer) ? buffer.toString("utf-8") : buffer;
26+
return JSON.parse(text);
27+
} catch (err) {
28+
console.error("Error parsing pix buffer:", err);
29+
return null;
30+
}
31+
}
32+
33+
static async toSharp(pixData) {
34+
const payload = pixData?.data ?? pixData;
35+
const { width, height, channel, depth, hex_data } = payload;
36+
if (!width || !height || !hex_data) return null;
37+
38+
const channels = channel ?? 4;
39+
const raw = Buffer.from(hex_data, "hex");
40+
const bytesPerPixel = Math.ceil(depth / 8) * channels;
41+
const expectedLength = width * height * bytesPerPixel;
42+
if (raw.length < expectedLength) raw.fill(0, raw.length, expectedLength);
43+
44+
return sharp(raw, {
45+
raw: { width, height, channels, depth: depth ?? 8 },
46+
})
47+
.png()
48+
.toBuffer({ resolveWithObject: true });
49+
}
50+
51+
static async toPix(buffer, info) {
52+
const { data, info: rawInfo } = await sharp(buffer)
53+
.raw()
54+
.toBuffer({ resolveWithObject: true });
55+
56+
return {
57+
width: info.width,
58+
height: info.height,
59+
channel: info.channels,
60+
depth: info.bitsPerSample || 8,
61+
compression: {
62+
method: "none",
63+
},
64+
hex_data: data.toString("hex"),
65+
label: {},
66+
joint: {},
67+
};
68+
}
69+
}
70+
71+
module.exports = {
72+
Pix,
73+
};

imgkit/features/image_layer_events.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,9 @@ class ImageLayerEvents {
4848
y
4949
);
5050

51-
const color_name = await ImageProcessor.getColorName(color);
52-
51+
navigator.clipboard.writeText(color);
5352
// Send color to main renderer
54-
ipcRenderer.send("colorpickerValueSEND", color, color_name);
53+
ipcRenderer.send("colorpickerValueSEND", color);
5554
}
5655
});
5756

@@ -101,6 +100,7 @@ class ImageLayerEvents {
101100
const color = colorDiv.title;
102101
if (color && color !== "empty") {
103102
navigator.clipboard.writeText(color).then(() => {
103+
ipcRenderer.send("colorpickerValueSEND", color);
104104
ipcRenderer.send("showNotificationREQ", "imgkit-color-copy");
105105
});
106106
}
@@ -224,16 +224,33 @@ class ImageLayerEvents {
224224
* Setup drag and drop handlers
225225
*/
226226
setupDragDrop() {
227-
// Prevent default browser behavior
228-
this.layer.canvas.addEventListener("dragover", (e) => e.preventDefault());
227+
// Prevent default browser behavior and add rotating border effect
228+
this.layer.canvas.addEventListener("dragover", (e) => {
229+
e.preventDefault();
230+
// Add rotating border animation class
231+
this.layer.panel.classList.add("drag-border-active");
232+
});
229233

230234
this.layer.canvas.addEventListener("dragenter", (e) => {
231235
e.preventDefault();
232236
this.sendLayerEvent("select");
237+
// Add rotating border animation class
238+
this.layer.panel.classList.add("drag-border-active");
239+
});
240+
241+
this.layer.canvas.addEventListener("dragleave", (e) => {
242+
// Only remove class if drag actually left the canvas (not moving to child element)
243+
// Also handle case where relatedTarget is null (e.g., drag left browser window)
244+
if (!e.relatedTarget || !this.layer.canvas.contains(e.relatedTarget)) {
245+
this.layer.panel.classList.remove("drag-border-active");
246+
}
233247
});
234248

235249
this.layer.canvas.addEventListener("drop", async (e) => {
236250
e.preventDefault();
251+
// Remove rotating border animation class
252+
this.layer.panel.classList.remove("drag-border-active");
253+
237254
const files = e.dataTransfer.files;
238255

239256
if (!files || files.length === 0) return;

imgkit/imgpanel.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,37 @@
103103
border-top: 3px solid #4caf50;
104104
}
105105

106+
/* Rotating dotted border animation during drag-over */
107+
@keyframes rotating-border {
108+
from {
109+
background-position: 0 0, 100% 100%, 0 100%, 100% 0;
110+
}
111+
to {
112+
background-position: 12px 0, calc(100% - 12px) 100%, 0 calc(100% - 12px),
113+
100% 12px;
114+
}
115+
}
116+
117+
.imgPanel.drag-border-active::before {
118+
content: "";
119+
position: absolute;
120+
top: 0;
121+
left: 0;
122+
right: 0;
123+
bottom: 0;
124+
border-radius: inherit;
125+
pointer-events: none;
126+
z-index: 10;
127+
background-image: linear-gradient(90deg, #666 50%, transparent 50%),
128+
linear-gradient(90deg, #666 50%, transparent 50%),
129+
linear-gradient(0deg, #666 50%, transparent 50%),
130+
linear-gradient(0deg, #666 50%, transparent 50%);
131+
background-size: 12px 3px, 12px 3px, 3px 12px, 3px 12px;
132+
background-position: 0 0, 100% 100%, 0 100%, 100% 0;
133+
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
134+
animation: rotating-border 0.5s linear infinite;
135+
}
136+
106137
.imgPanel:hover {
107138
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
108139
}

imgkit/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ <h2 class="coord-text">( - , - )</h2>
6363
<h2 class="info-text">0 x 0</h2>
6464
</div>
6565
<select class="extension-combo">
66+
<option value="pix">pix</option>
6667
<option value="png">png</option>
6768
<option value="svg">svg</option>
6869
<option value="jpg">jpg</option>
@@ -74,6 +75,8 @@ <h2 class="info-text">0 x 0</h2>
7475
<option value="tif">tif</option>
7576
<option value="tiff">tiff</option>
7677
<option value="avif">avif</option>
78+
<option value="heif">heif</option>
79+
<option value="heic">heic</option>
7780
</select>
7881
</div>
7982
</template>

0 commit comments

Comments
 (0)