mirror of
https://github.com/kunkunsh/kunkun-ext-image-processing.git
synced 2025-04-03 18:06:42 +00:00
87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
import type { API } from '../src/types.ts';
|
|
import { expose } from '@kunkun/api/runtime/deno';
|
|
import { image } from '@hk/photographer-toolbox';
|
|
import { convertDate } from './lib.ts';
|
|
import { ExifDateTime, ExifTool } from 'exiftool-vendored';
|
|
import sharp, { FormatEnum } from 'sharp';
|
|
|
|
export function batchSmartSetImageOriginalDate(
|
|
imagePaths: string[],
|
|
baseImagePath: string,
|
|
targetDate: ExifDateTime
|
|
) {
|
|
// Read metadata for all images
|
|
const loader = new ExifTool();
|
|
|
|
return loader
|
|
.read(baseImagePath)
|
|
.then(async (baseTags) => {
|
|
const baseOriginalDate = baseTags.DateTimeOriginal;
|
|
if (!baseOriginalDate) {
|
|
throw new Error('Base image has no DateTimeOriginal');
|
|
}
|
|
|
|
// Calculate offset between target and base dates
|
|
const targetMillis = targetDate.toMillis();
|
|
const baseMillis = ExifDateTime.from(baseOriginalDate)!.toMillis();
|
|
const offsetMillis = targetMillis - baseMillis;
|
|
|
|
// Read all image tags
|
|
const allTags = await Promise.all(imagePaths.map((path) => loader.read(path)));
|
|
|
|
// Update each image with offset-adjusted date
|
|
return Promise.all(
|
|
allTags.map((tags, i) => {
|
|
const originalDate = tags.DateTimeOriginal;
|
|
if (!originalDate) {
|
|
throw new Error(`Image ${imagePaths[i]} has no DateTimeOriginal`);
|
|
}
|
|
|
|
const imageMillis = ExifDateTime.from(originalDate)!.toMillis();
|
|
const newMillis = imageMillis + offsetMillis;
|
|
const newDate = ExifDateTime.fromMillis(newMillis);
|
|
|
|
// return setImageOriginalDate(imagePaths[i], newDate);
|
|
return loader.write(
|
|
imagePaths[i],
|
|
{
|
|
DateTimeOriginal: newDate
|
|
},
|
|
['-overwrite_original']
|
|
);
|
|
})
|
|
).then(() => Promise.resolve());
|
|
})
|
|
.finally(() => loader.end());
|
|
}
|
|
|
|
expose({
|
|
echo: (paths: string[]) => Promise.resolve(paths),
|
|
readImageMetadata: (imagePath: string) => image.readImageMetadata(imagePath).then(convertDate),
|
|
batchReadImageMetadata: async (paths: string[]) => {
|
|
const data = await image.batchReadImageMetadata(paths);
|
|
return data.map(convertDate);
|
|
},
|
|
batchSmartSetImageOriginalDate: (
|
|
imagePaths: string[],
|
|
baseImagePath: string,
|
|
targetDateIso: string
|
|
) => {
|
|
return image
|
|
.batchSmartSetImageOriginalDate(imagePaths, baseImagePath, ExifDateTime.from(targetDateIso))
|
|
.then(() => Promise.resolve())
|
|
.catch((err) => {
|
|
console.error(err);
|
|
throw new Error(err);
|
|
});
|
|
},
|
|
compressImage: async (
|
|
imagePath: string,
|
|
format: keyof FormatEnum,
|
|
quality: number,
|
|
outputPath: string
|
|
) => {
|
|
await image.compressImage(sharp(imagePath), format, quality).toFile(outputPath);
|
|
}
|
|
} satisfies API);
|