Skip to content

Commit 595ca54

Browse files
feat: add base64 image encoding
1 parent bd5cc06 commit 595ca54

File tree

6 files changed

+78
-1
lines changed

6 files changed

+78
-1
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"rimraf": "^6.0.1",
9494
"tailwindcss": "^3.4.17",
9595
"typescript": "~5.7.3",
96+
"uint8-base64": "^1.0.0",
9697
"vite": "^6.0.8",
9798
"vitest": "^2.1.8"
9899
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`basic image 2 (jpeg) 1`] = `"/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2MBERISGBUYLxoaL2NCOEJjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY//AABEIAAUABQMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AOu0zTbmyvL+efUZbpLmTfHE+cQDLHaMk+oHbpQB/9k="`;
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { encode } from '../encode.js';
2+
import { encodeDataURL } from '../encodeDataURL.js';
3+
4+
test('basic image (png)', () => {
5+
const image = testUtils.createGreyImage([
6+
[0, 0, 0, 0, 0],
7+
[0, 255, 255, 255, 0],
8+
[0, 255, 0, 255, 0],
9+
[0, 255, 255, 255, 0],
10+
[255, 0, 255, 0, 255],
11+
]);
12+
const base64Url = encodeDataURL(image);
13+
14+
expect(base64Url).toBe(
15+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAAAAACoBHk5AAAAFklEQVR4XmNggID///+DSCCEskHM/wCAnQr2TY5mOAAAAABJRU5ErkJggg==',
16+
);
17+
});
18+
19+
test('basic image 2 (jpeg)', () => {
20+
const image = testUtils.createGreyImage([
21+
[255, 255, 255, 255, 255],
22+
[255, 0, 0, 0, 255],
23+
[255, 0, 0, 0, 255],
24+
[255, 0, 0, 0, 255],
25+
[255, 255, 255, 255, 255],
26+
]);
27+
const format = 'jpeg';
28+
const base64 = encodeDataURL(image, { format });
29+
const base64Data = Buffer.from(encode(image, { format })).toString('base64');
30+
expect(typeof base64).toBe('string');
31+
expect(base64Data).toMatchSnapshot();
32+
});
33+
34+
test('legacy image-js test', () => {
35+
const image = testUtils.createRgbaImage(
36+
`
37+
255 0 0 / 255 | 0 255 0 / 255 | 0 0 255 / 255
38+
255 255 0 / 255 | 255 0 255 / 255 | 0 255 255 / 255
39+
0 0 0 / 255 | 255 255 255 / 255 | 127 127 127 / 255
40+
`,
41+
);
42+
const format = 'jpeg';
43+
const url = encodeDataURL(image, { format });
44+
const base64Data = Buffer.from(encode(image, { format })).toString('base64');
45+
expect(typeof url).toBe('string');
46+
expect(base64Data).toBe(url.slice(url.indexOf(',') + 1));
47+
});

src/save/encode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface EncodeOptionsJpeg {
2929
export interface EncodeOptionsBmp {
3030
format: 'bmp';
3131
}
32-
const defaultPng: EncodeOptionsPng = { format: 'png' };
32+
export const defaultPng: EncodeOptionsPng = { format: 'png' };
3333

3434
/**
3535
* Encodes the image to the specified format

src/save/encodeDataURL.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { encode as uint8encode } from 'uint8-base64';
2+
3+
import type { Image } from '../Image.js';
4+
5+
import type {
6+
EncodeOptionsBmp,
7+
EncodeOptionsJpeg,
8+
EncodeOptionsPng,
9+
} from './encode.js';
10+
import { encode, defaultPng } from './encode.js';
11+
/**
12+
* Converts image into Data URL string.
13+
* @param image - Image to get base64 encoding from.
14+
* @param options - Encoding options.
15+
* @returns base64 string.
16+
*/
17+
export function encodeDataURL(
18+
image: Image,
19+
options: EncodeOptionsBmp | EncodeOptionsPng | EncodeOptionsJpeg = defaultPng,
20+
) {
21+
const buffer = encode(image, options);
22+
const base64 = uint8encode(buffer);
23+
const base64Data = new TextDecoder().decode(base64);
24+
return `data:image/${options.format};base64,${base64Data}`;
25+
}

src/save/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './encodePng.js';
33
export * from './encodeJpeg.js';
44
export * from './write.js';
55
export * from './writeCanvas.js';
6+
export * from './encodeDataURL.js';

0 commit comments

Comments
 (0)