Skip to content

Commit 8cfa8ee

Browse files
committed
Merge remote-tracking branch 'origin/master' into dev
# Conflicts: # package.json
2 parents 045c4d2 + d61031e commit 8cfa8ee

14 files changed

Lines changed: 822 additions & 80 deletions

File tree

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Bug report
33
about: Create a report to help us improve
44
title: "[BUG]"
55
labels: bug
6-
assignees: matmen, evanwashere
76

87
---
98

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Feature request
33
about: Suggest an idea for this project
44
title: "[FR]"
55
labels: enhancement
6-
assignees: matmen
76

87
---
98

ImageScript.d.ts

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
export class Image {
2+
private __width__: number;
3+
private __height__: number;
4+
private __buffer__: ArrayBuffer;
5+
private __view__: DataView;
6+
private __u32__: Uint32Array;
7+
bitmap: Uint8ClampedArray;
8+
9+
constructor(width: number, height: number);
10+
11+
private toString(): string;
12+
13+
get width(): number;
14+
15+
get height(): number;
16+
17+
* [Symbol.iterator](): void;
18+
19+
* iterateWithColors(): Generator<[x: number, y: number, color: number], void, unknown>;
20+
21+
static rgbaToColor(r: number, g: number, b: number, a: number): number;
22+
23+
static rgbToColor(r: number, g: number, b: number): number;
24+
25+
static hslaToColor(h: number, s: number, l: number, a: number): number;
26+
27+
static hslToColor(h: number, s: number, l: number): number;
28+
29+
static rgbaToHSLA(r: number, g: number, b: number, a: number): number[];
30+
31+
static colorToRGBA(color: number): number[];
32+
33+
static colorToRGB(color: number): number[];
34+
35+
getPixelAt(x: number, y: number): number;
36+
37+
getRGBAAt(x: number, y: number): Uint8ClampedArray;
38+
39+
setPixelAt(x: number, y: number, pixelColor: number): Image;
40+
41+
private __set_pixel__(x: number, y: number, pixelColor: number): void;
42+
43+
private __check_boundaries__(x: number, y: number): void;
44+
45+
private static get __out_of_bounds__(): string;
46+
47+
fill(color: number | colorFunction): Image;
48+
49+
clone(): Image;
50+
51+
static get RESIZE_NEAREST_NEIGHBOR(): string;
52+
53+
static get RESIZE_AUTO(): number;
54+
55+
scale(factor: number, mode?: string): Image;
56+
57+
private __scale__(factor: number, mode?: string);
58+
59+
resize(width: number, height: number, mode?: string): Image;
60+
61+
contain(width: number, height: number, mode?: string): Image;
62+
63+
fit(width: number, height: number, mode?: string): Image;
64+
65+
cover(width: number, height: number, mode?: string): Image;
66+
67+
private __resize__(width: number, height: number, mode?: string): Image;
68+
69+
private __resize_nearest_neighbor__(width: number, height: number): Image;
70+
71+
crop(x: number, y: number, width: number, height: number): Image;
72+
73+
private __crop__(x: number, y: number, width: number, height: number): Image;
74+
75+
drawBox(x: number, y: number, width: number, height: number, color: number | colorFunction): Image;
76+
77+
private __fast_box__(x: number, y: number, width: number, height: number, color: number): Image;
78+
79+
drawCircle(x: number, y: number, radius: number, color: number | colorFunction): Image;
80+
81+
cropCircle(max?: boolean, feathering?: number): Image;
82+
83+
opacity(opacity: number, absolute?: boolean): Image;
84+
85+
red(saturation: number, absolute?: boolean): Image;
86+
87+
green(saturation: number, absolute?: boolean): Image;
88+
89+
blue(saturation: number, absolute?: boolean): Image;
90+
91+
private __set_channel_value__(value: number, absolute: boolean, offset: number): void;
92+
93+
lightness(value: number, absolute?: boolean): Image;
94+
95+
saturation(value: number, absolute?: boolean): Image;
96+
97+
composite(source: Image, x?: number, y?: number): Image;
98+
99+
invert(): Image;
100+
101+
invertValue(): Image;
102+
103+
invertSaturation(): Image;
104+
105+
invertHue(): Image;
106+
107+
hueShift(degrees: number): Image;
108+
109+
averageColor(): number;
110+
111+
dominantColor(ignoreBlack?: boolean, ignoreWhite?: boolean, bwThreshold?: number): number;
112+
113+
rotate(angle: number, resize?: boolean): Image;
114+
115+
private __apply__(image: Image | Frame): Image | Frame;
116+
117+
static gradient(colors: { [position: number]: number; }): ((position: number) => number);
118+
119+
roundCorners(radius?: number): Image;
120+
121+
private static __gradient__(startColor: number, endColor: number): number;
122+
123+
fisheye(radius?: number): Image;
124+
125+
async encode(compression?: number, metadata?: PNGMetadata): Promise<Uint8Array>;
126+
async encode(metadata?: PNGMetadata): Promise<Uint8Array>;
127+
128+
async encodeJPEG(quality?: number): Promise<Uint8Array>;
129+
130+
async encodeWEBP(quality?: null | number): Promise<Uint8Array>;
131+
132+
static async encode(data: Buffer | Uint8Array): Promise<Image>
133+
134+
static get SVG_MODE_SCALE(): number;
135+
136+
static get SVG_MODE_WIDTH(): number;
137+
138+
static get SVG_MODE_HEIGHT(): number;
139+
140+
static async renderSVG(svg: string, size?: number, mode?: number): Promise<Image>;
141+
142+
static async renderText(font: Uint8Array, scale: number, text: string, color?: number, layout?: TextLayout): Promise<Image>;
143+
};
144+
145+
export class Frame extends Image {
146+
static get DISPOSAL_KEEP(): string;
147+
148+
static get DISPOSAL_PREVIOUS(): string;
149+
150+
static get DISPOSAL_BACKGROUND(): string
151+
152+
private static __convert_disposal_mode__(mode: string | number): any;
153+
154+
constructor(width: number, height: number, duration?: number, xOffset?: number, yOffset?: number, disposalMode?: typeof Frame.DISPOSAL_KEEP | string);
155+
156+
toString(): string;
157+
158+
static from(image: Image, duration?: number, xOffset?: number, yOffset?: number, disposalMode?: typeof Frame.DISPOSAL_KEEP | string): Frame;
159+
160+
resize(width: number, height: number, mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string): Image;
161+
};
162+
163+
export class GIF extends Array {
164+
constructor(frames: Frame[], loopCount?: number);
165+
166+
get width(): number;
167+
168+
get height(): number;
169+
170+
toString(): string;
171+
172+
* [Symbol.iterator](): Generator<Frame, void, *>
173+
174+
slice(start: number, end: number): GIF;
175+
176+
get duration(): number;
177+
178+
async encode(quality?: number): Promise<Uint8Array>
179+
180+
static async decode(data: Buffer | Uint8Array, onlyExtractFirstFrame?: boolean): Promise<GIF>;
181+
182+
resize(width: number, height: number, mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string): void;
183+
}
184+
185+
export class TextLayout {
186+
constructor(options?: {
187+
maxWidth?: number,
188+
maxHeight?: number,
189+
wrapStyle?: string,
190+
verticalAlign?: string,
191+
horizontalAlign?: string,
192+
wrapHardBreaks?: boolean
193+
});
194+
};
195+
196+
export class ImageType {
197+
static getType(data: Buffer | Uint8Array): string | null;
198+
199+
static isPNG(view: DataView): boolean;
200+
201+
static isJPEG(view: DataView): boolean;
202+
203+
static isTIFF(view: DataView): boolean;
204+
205+
static isGIF(view: DataView): boolean;
206+
};
207+
208+
export function decode(data: Uint8Array | Buffer, onlyExtractFirstFrame?: boolean): Promise<GIF | Image>;
209+
210+
type colorFunction = (x: number, y: number) => number;
211+
212+
type PNGMetadata = {
213+
title?: string,
214+
author?: string,
215+
description?: string,
216+
copyright?: string,
217+
creationTime?: string | number | Date,
218+
software?: string,
219+
disclaimer?: string,
220+
warning?: string,
221+
source?: string,
222+
comment?: string
223+
};

ImageScript.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const { default: v2 } = require('./v2/framebuffer.js');
77
// old
88
const svglib = require('./wasm/node/svg.js');
99
const giflib = require('./wasm/node/gif.js');
10+
const pnglib = require('./wasm/node/png.js');
1011
const fontlib = require('./wasm/node/font.js');
1112
const jpeglib = require('./wasm/node/jpeg.js');
1213
const tifflib = require('./wasm/node/tiff.js');
@@ -1082,9 +1083,9 @@ class Image {
10821083
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
10831084

10841085
if (ImageType.isPNG(view)) { // PNG
1085-
const {width, height, pixels} = await png.decode(data);
1086+
const {width, height, framebuffer} = (await pnglib.init()).decode(data);
10861087
image = new Image(width, height);
1087-
image.bitmap.set(pixels);
1088+
image.bitmap.set(framebuffer);
10881089
} else if (ImageType.isJPEG(view)) { // JPEG
10891090
const framebuffer = (await jpeglib.init()).decode(data);
10901091

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Discord Server](https://img.shields.io/discord/691713541262147687.svg?label=Discord&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2&style=for-the-badge)](https://discord.gg/8hPrwAH)
44
[![Documentation](https://img.shields.io/badge/Documentation-informational?style=for-the-badge)](https://imagescript.matmen.dev/)
55
[![Github](https://img.shields.io/badge/Github-Repository-181717?logo=github&style=for-the-badge)](https://github.com/matmen/ImageScript)
6-
[![deno.land](https://shields.io/badge/deno.land-gray?logo=deno&style=for-the-badge)](https://deno.land/x/imagescript@1.2.9)
6+
[![deno.land](https://shields.io/badge/deno.land-gray?logo=deno&style=for-the-badge)](https://deno.land/x/imagescript)
77
[![NPM](https://nodei.co/npm/imagescript.png)](https://www.npmjs.com/package/imagescript)
88

99
---

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "imagescript",
3-
"version": "1.2.9",
3+
"version": "1.2.15",
44
"description": "zero-dependency javascript image manipulation",
55
"main": "ImageScript.js",
66
"types": "ImageScript.d.ts",
@@ -30,7 +30,7 @@
3030
"thumbnail"
3131
],
3232
"author": "Mathis Mensing <mathis@matmen.dev>",
33-
"license": "GPL-3.0-or-later",
33+
"license": "AGPL-3.0-or-later",
3434
"bugs": {
3535
"url": "https://github.com/matmen/ImageScript/issues"
3636
},

tests/font.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,15 @@ const panic = message => {
3434
const desired = await fs.readFile('./tests/targets/font-2.png');
3535
if (!desired.equals(Buffer.from(encoded))) panic('font 2 doesn\'t match');
3636
}
37+
38+
{
39+
const font = await Image.renderText(await fs.readFile('./tests/fonts/opensans bold.ttf'), 128, 'Extra\n-Test\nnewline');
40+
const encoded = await font.encode(1, {creationTime: 0, software: ''});
41+
42+
if (process.env.OVERWRITE_TEST)
43+
await fs.writeFile('./tests/targets/font-3.png', encoded);
44+
45+
const desired = await fs.readFile('./tests/targets/font-3.png');
46+
if (!desired.equals(Buffer.from(encoded))) panic('font 3 doesn\'t match');
47+
}
3748
})();

tests/fonts/opensans bold.ttf

219 KB
Binary file not shown.

tests/targets/font-3.png

16.7 KB
Loading

tsconfig.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es6",
4+
"module": "commonjs",
5+
"strict": true,
6+
"noImplicitAny": true,
7+
"strictNullChecks": true,
8+
"noImplicitThis": true,
9+
"alwaysStrict": true,
10+
"noUnusedLocals": true,
11+
"noUnusedParameters": true,
12+
"noImplicitReturns": true,
13+
"noFallthroughCasesInSwitch": true,
14+
"moduleResolution": "node",
15+
"allowJs": true,
16+
"allowSyntheticDefaultImports": true,
17+
"skipLibCheck": true,
18+
"lib": ["es6"]
19+
},
20+
"files": ["ImageScript.d.ts"]
21+
}

0 commit comments

Comments
 (0)