Skip to content

Commit 296d4b2

Browse files
so close
1 parent 296a776 commit 296d4b2

File tree

11 files changed

+227
-9
lines changed

11 files changed

+227
-9
lines changed

packages/core/src/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ export type JimpFormatArray<T> =
4949

5050
export type JimpFormatMime<T> = T extends Format<infer M> ? M : never;
5151

52-
export type JimpMethod<Args extends any[] = any[]> = (
53-
img: Jimp,
54-
...args: Args
55-
) => Jimp;
52+
export type JimpMethod<
53+
Args extends any[] = any[],
54+
J extends JimpClass = JimpClass,
55+
> = (img: J, ...args: Args) => J;
5656

5757
type JimpInstanceMethod<M, T> =
5858
T extends JimpMethod<infer Args>

packages/jimp/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"author": "Andrew Lisowski <[email protected]>",
3333
"license": "MIT",
3434
"dependencies": {
35+
"@jimp/plugin-blit": "workspace:*",
3536
"@jimp/plugin-crop": "workspace:*",
3637
"@jimp/js-png": "workspace:*",
3738
"@jimp/core": "workspace:*"

packages/jimp/src/index.test.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,33 @@ import { Jimp } from "./index.js";
99
// });
1010

1111
async function run() {
12-
const image = new Jimp();
1312
const imageBuffer = await fs.readFile(
1413
path.join(__dirname, "../../../../images/GIgFDCFbAAA0zlg.png"),
1514
);
1615

16+
const image = new Jimp();
1717
await image.fromBuffer(imageBuffer);
1818

19+
const image2 = new Jimp();
20+
await image2.fromBuffer(imageBuffer);
21+
22+
// works
23+
image.blit({
24+
src: image2,
25+
x: 100,
26+
y: 100,
27+
});
28+
29+
// works
1930
image.crop(100, 100, 150, 100);
2031

32+
// doesn't work
33+
image.crop(100, 100, 150, 100).blit({
34+
src: image2,
35+
x: 100,
36+
y: 100,
37+
});
38+
2139
const outputBuffer = await image.toBuffer("image/png");
2240
const outPath = path.join(__dirname, "./out.png");
2341

packages/jimp/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Jimp as JimpCustom } from "@jimp/core";
22

33
import crop from "@jimp/plugin-crop";
4+
import blit from "@jimp/plugin-blit";
45

56
import png from "@jimp/js-png";
67

7-
export const Jimp = JimpCustom.addFormat(png).plugin(crop);
8+
export const Jimp = JimpCustom.addFormat(png).plugin(blit).plugin(crop);

packages/utils/src/index.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function scan<I extends JimpClass>(
66
y: number,
77
w: number,
88
h: number,
9-
cb: (image: I, x: number, y: number, idx: number) => any,
9+
cb: (x: number, y: number, idx: number) => any,
1010
) {
1111
// round input
1212
x = Math.round(x);
@@ -17,7 +17,7 @@ export function scan<I extends JimpClass>(
1717
for (let _y = y; _y < y + h; _y++) {
1818
for (let _x = x; _x < x + w; _x++) {
1919
const idx = (image.bitmap.width * _y + _x) << 2;
20-
cb(image, _x, _y, idx);
20+
cb(_x, _y, idx);
2121
}
2222
}
2323

@@ -108,3 +108,13 @@ export function colorDiff(rgba1: RGBAColor, rgba2: RGBAColor) {
108108
maxVal
109109
);
110110
}
111+
112+
/**
113+
* Limits a number to between 0 or 255
114+
*/
115+
export function limit255(n: number) {
116+
n = Math.max(n, 0);
117+
n = Math.min(n, 255);
118+
119+
return n;
120+
}

plugins/plugin-blit/package.json

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@jimp/plugin-blit",
3+
"version": "1.0.0",
4+
"repository": "jimp-dev/jimp",
5+
"scripts": {
6+
"lint": "eslint .",
7+
"test": "vitest",
8+
"build": "tshy",
9+
"dev": "tshy --watch"
10+
},
11+
"author": "Andrew Lisowski <[email protected]>",
12+
"license": "MIT",
13+
"dependencies": {
14+
"@jimp/utils": "workspace:*",
15+
"@jimp/types": "workspace:*"
16+
},
17+
"devDependencies": {
18+
"@jimp/config-eslint": "workspace:*",
19+
"@jimp/config-typescript": "workspace:*",
20+
"eslint": "^8.57.0",
21+
"tshy": "^1.12.0",
22+
"typescript": "^5.4.2",
23+
"vitest": "^1.4.0"
24+
},
25+
"tshy": {
26+
"exports": {
27+
"./package.json": "./package.json",
28+
".": "./src/index.ts"
29+
}
30+
},
31+
"exports": {
32+
"./package.json": "./package.json",
33+
".": {
34+
"import": {
35+
"types": "./dist/esm/index.d.ts",
36+
"default": "./dist/esm/index.js"
37+
},
38+
"require": {
39+
"types": "./dist/commonjs/index.d.ts",
40+
"default": "./dist/commonjs/index.js"
41+
}
42+
}
43+
},
44+
"main": "./dist/commonjs/index.js",
45+
"types": "./dist/commonjs/index.d.ts",
46+
"type": "module"
47+
}

plugins/plugin-blit/src/index.test.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { expect, test } from "vitest";
2+
3+
test("adds 1 + 2 to equal 3", () => {
4+
expect(1 + 2).toBe(3);
5+
});

plugins/plugin-blit/src/index.ts

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { JimpClass } from "@jimp/types";
2+
import { limit255, scan } from "@jimp/utils";
3+
4+
/**
5+
* Blits a source image on to this image
6+
*/
7+
function blit<I extends JimpClass>(
8+
image: I,
9+
{
10+
src,
11+
x = 0,
12+
y = 0,
13+
srcX = 0,
14+
srcY = 0,
15+
srcW = src.bitmap.width,
16+
srcH = src.bitmap.height,
17+
}: {
18+
/** This image to blit on to the current image */
19+
src: I;
20+
/** the x position to blit the image */
21+
x: number;
22+
/** the y position to blit the image */
23+
y: number;
24+
/** the x position from which to crop the source image */
25+
srcX?: number;
26+
/** the y position from which to crop the source image */
27+
srcY?: number;
28+
/** the width to which to crop the source image */
29+
srcW?: number;
30+
/** the height to which to crop the source image */
31+
srcH?: number;
32+
},
33+
) {
34+
if (!("bitmap" in src)) {
35+
throw new Error("The source must be a Jimp image");
36+
}
37+
38+
if (typeof x !== "number" || typeof y !== "number") {
39+
throw new Error("x and y must be numbers");
40+
}
41+
42+
// round input
43+
x = Math.round(x);
44+
y = Math.round(y);
45+
46+
// round input
47+
srcX = Math.round(srcX);
48+
srcY = Math.round(srcY);
49+
srcW = Math.round(srcW);
50+
srcH = Math.round(srcH);
51+
52+
const maxWidth = image.bitmap.width;
53+
const maxHeight = image.bitmap.height;
54+
55+
scan(src, srcX, srcY, srcW, srcH, function (sx, sy, idx) {
56+
const xOffset = x + sx - srcX;
57+
const yOffset = y + sy - srcY;
58+
59+
if (
60+
xOffset >= 0 &&
61+
yOffset >= 0 &&
62+
maxWidth - xOffset > 0 &&
63+
maxHeight - yOffset > 0
64+
) {
65+
const dstIdx = image.getPixelIndex(xOffset, yOffset);
66+
const srcColor = {
67+
r: src.bitmap.data[idx] || 0,
68+
g: src.bitmap.data[idx + 1] || 0,
69+
b: src.bitmap.data[idx + 2] || 0,
70+
a: src.bitmap.data[idx + 3] || 0,
71+
};
72+
73+
const dst = {
74+
r: image.bitmap.data[dstIdx] || 0,
75+
g: image.bitmap.data[dstIdx + 1] || 0,
76+
b: image.bitmap.data[dstIdx + 2] || 0,
77+
a: image.bitmap.data[dstIdx + 3] || 0,
78+
};
79+
80+
image.bitmap.data[dstIdx] =
81+
((srcColor.a * (srcColor.r - dst.r) - dst.r + 255) >> 8) + dst.r;
82+
image.bitmap.data[dstIdx + 1] =
83+
((srcColor.a * (srcColor.g - dst.g) - dst.g + 255) >> 8) + dst.g;
84+
image.bitmap.data[dstIdx + 2] =
85+
((srcColor.a * (srcColor.b - dst.b) - dst.b + 255) >> 8) + dst.b;
86+
image.bitmap.data[dstIdx + 3] = limit255(dst.a + srcColor.a);
87+
}
88+
});
89+
90+
return image;
91+
}
92+
93+
export default function blitPlugin() {
94+
return {
95+
blit,
96+
};
97+
}

plugins/plugin-blit/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "@jimp/config-typescript/base.json",
3+
"compilerOptions": {
4+
"outDir": "dist"
5+
},
6+
"include": ["src"],
7+
"exclude": ["node_modules", "dist"]
8+
}

plugins/plugin-crop/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function crop<I extends JimpClass>(
3434
const bitmap = Buffer.allocUnsafe(w * h * 4);
3535
let offset = 0;
3636

37-
scan(image, x, y, w, h, function (i, x, y, idx) {
37+
scan(image, x, y, w, h, function (x, y, idx) {
3838
const data = image.bitmap.data.readUInt32BE(idx);
3939
bitmap.writeUInt32BE(data, offset);
4040
offset += 4;

pnpm-lock.yaml

+31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)