2024-11-05 11:49:21 +08:00
|
|
|
import { readFileSync } from 'node:fs';
|
2025-02-21 10:30:20 +08:00
|
|
|
import { tmpdir } from 'node:os';
|
|
|
|
import { join } from 'node:path';
|
2024-11-05 11:49:21 +08:00
|
|
|
import {
|
|
|
|
base64Encoded,
|
|
|
|
imageInfo,
|
|
|
|
imageInfoOfBase64,
|
|
|
|
resizeImg,
|
|
|
|
resizeImgBase64,
|
2025-03-25 22:45:05 +08:00
|
|
|
} from 'src/img';
|
|
|
|
import getJimp from 'src/img/get-jimp';
|
2025-03-24 09:50:27 +08:00
|
|
|
import {
|
|
|
|
cropByRect,
|
|
|
|
jimpFromBase64,
|
|
|
|
jimpToBase64,
|
|
|
|
paddingToMatchBlock,
|
|
|
|
saveBase64Image,
|
|
|
|
} from 'src/img/transform';
|
2024-08-26 18:50:33 +08:00
|
|
|
import { getFixture } from 'tests/utils';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
|
|
|
|
describe('image utils', () => {
|
|
|
|
const image = getFixture('icon.png');
|
|
|
|
it('imageInfo', async () => {
|
|
|
|
const info = await imageInfo(image);
|
|
|
|
expect(info).toMatchSnapshot();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('base64Encoded', () => {
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
expect(base64).toMatchSnapshot();
|
|
|
|
|
|
|
|
const headlessBase64 = base64Encoded(image, false);
|
|
|
|
expect(headlessBase64).toMatchSnapshot();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('base64 + imageInfo', async () => {
|
|
|
|
const image = getFixture('icon.png');
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
const info = await imageInfoOfBase64(base64);
|
2024-11-05 11:49:21 +08:00
|
|
|
expect(info.width).toMatchSnapshot();
|
|
|
|
expect(info.height).toMatchSnapshot();
|
2024-08-26 18:50:33 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('jpeg + base64 + imageInfo', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
const info = await imageInfoOfBase64(base64);
|
2024-11-05 11:49:21 +08:00
|
|
|
expect(info.width).toMatchSnapshot();
|
|
|
|
expect(info.height).toMatchSnapshot();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('jimp + imageInfo', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const jimp = await getJimp();
|
|
|
|
const jimpImage = await jimp.read(image);
|
|
|
|
const info = await imageInfo(jimpImage);
|
|
|
|
expect(info.width).toMatchSnapshot();
|
|
|
|
expect(info.height).toMatchSnapshot();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('resizeImgBase64', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
const resizedBase64 = await resizeImgBase64(base64, {
|
|
|
|
width: 100,
|
|
|
|
height: 100,
|
|
|
|
});
|
|
|
|
expect(resizedBase64).toContain(';base64,');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('resize image', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const buffer = await resizeImg(readFileSync(image), {
|
|
|
|
width: 100,
|
|
|
|
height: 100,
|
|
|
|
});
|
|
|
|
expect(buffer).toBeDefined();
|
2024-08-26 18:50:33 +08:00
|
|
|
});
|
|
|
|
|
2025-02-21 10:30:20 +08:00
|
|
|
it('paddingToMatchBlock', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const base64 = base64Encoded(image);
|
2025-03-24 09:50:27 +08:00
|
|
|
const jimpImage = await jimpFromBase64(base64);
|
|
|
|
const result = await paddingToMatchBlock(jimpImage);
|
|
|
|
|
|
|
|
const width = result.bitmap.width;
|
|
|
|
expect(width).toMatchSnapshot();
|
2025-02-21 10:30:20 +08:00
|
|
|
|
2025-03-24 09:50:27 +08:00
|
|
|
const height = result.bitmap.height;
|
|
|
|
expect(height).toMatchSnapshot();
|
2025-02-21 10:30:20 +08:00
|
|
|
|
|
|
|
const tmpFile = join(tmpdir(), 'heytea-padded.jpeg');
|
|
|
|
await saveBase64Image({
|
2025-03-24 09:50:27 +08:00
|
|
|
base64Data: await jimpToBase64(result),
|
2025-02-21 10:30:20 +08:00
|
|
|
outputPath: tmpFile,
|
|
|
|
});
|
2025-03-24 09:50:27 +08:00
|
|
|
// console.log('tmpFile', tmpFile);
|
2025-02-21 10:30:20 +08:00
|
|
|
});
|
|
|
|
|
2025-03-24 09:50:27 +08:00
|
|
|
it('cropByRect, with padding', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
const croppedBase64 = await cropByRect(
|
|
|
|
base64,
|
|
|
|
{
|
|
|
|
left: 200,
|
|
|
|
top: 80,
|
|
|
|
width: 100,
|
|
|
|
height: 400,
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(croppedBase64).toBeTruthy();
|
|
|
|
|
|
|
|
const info = await imageInfoOfBase64(croppedBase64);
|
|
|
|
// biome-ignore lint/style/noUnusedTemplateLiteral: by intention
|
|
|
|
expect(info.width).toMatchInlineSnapshot(`112`);
|
|
|
|
// biome-ignore lint/style/noUnusedTemplateLiteral: by intention
|
|
|
|
expect(info.height).toMatchInlineSnapshot(`420`);
|
|
|
|
|
|
|
|
const tmpFile = join(tmpdir(), 'heytea-cropped.jpeg');
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: croppedBase64,
|
|
|
|
outputPath: tmpFile,
|
|
|
|
});
|
|
|
|
console.log('cropped image saved to', tmpFile);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('cropByRect, without padding', async () => {
|
|
|
|
const image = getFixture('heytea.jpeg');
|
|
|
|
const base64 = base64Encoded(image);
|
|
|
|
const croppedBase64 = await cropByRect(
|
|
|
|
base64,
|
|
|
|
{
|
|
|
|
left: 200,
|
|
|
|
top: 80,
|
|
|
|
width: 100,
|
|
|
|
height: 400,
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(croppedBase64).toBeTruthy();
|
|
|
|
|
|
|
|
const info = await imageInfoOfBase64(croppedBase64);
|
|
|
|
// biome-ignore lint/style/noUnusedTemplateLiteral: by intention
|
|
|
|
expect(info.width).toMatchInlineSnapshot(`100`);
|
|
|
|
// biome-ignore lint/style/noUnusedTemplateLiteral: by intention
|
|
|
|
expect(info.height).toMatchInlineSnapshot(`400`);
|
|
|
|
|
|
|
|
const tmpFile = join(tmpdir(), 'heytea-cropped-2.jpeg');
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: croppedBase64,
|
|
|
|
outputPath: tmpFile,
|
|
|
|
});
|
|
|
|
console.log('cropped image saved to', tmpFile);
|
|
|
|
});
|
2024-08-26 18:50:33 +08:00
|
|
|
// it(
|
|
|
|
// 'profile',
|
|
|
|
// async () => {
|
|
|
|
// let count = 100;
|
|
|
|
// console.time('alignCoordByTrim');
|
|
|
|
// while (count--) {
|
|
|
|
// const file = getFixture('long-text.png');
|
|
|
|
// await alignCoordByTrim(file, {
|
|
|
|
// left: 440,
|
|
|
|
// top: 50,
|
|
|
|
// width: 200,
|
|
|
|
// height: 150,
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
// console.timeEnd('alignCoordByTrim');
|
|
|
|
// },
|
|
|
|
// 10 * 1000,
|
|
|
|
// );
|
|
|
|
});
|