Vercel/src/utility/exif.ts

78 lines
2.2 KiB
TypeScript

import { OrientationTypes, type ExifData } from 'ts-exif-parser';
import { formatNumberToFraction, roundToString } from './number';
import * as PiExif from 'piexifjs';
const OFFSET_REGEX = /[+-]\d\d:\d\d/;
export const getOffsetFromExif = (data: ExifData) =>
Object.values(data.tags as any)
.find((value: any) =>
typeof value === 'string' &&
OFFSET_REGEX.test(value)
) as string | undefined;
export const getAspectRatioFromExif = (data: ExifData): number => {
// Using '||' operator to handle `Orientation` unexpectedly being '0'
const orientation = data.tags?.Orientation || OrientationTypes.TOP_LEFT;
const width = data.imageSize?.width ?? 3.0;
const height = data.imageSize?.height ?? 2.0;
switch (orientation) {
case OrientationTypes.TOP_LEFT:
case OrientationTypes.TOP_RIGHT:
case OrientationTypes.BOTTOM_RIGHT:
case OrientationTypes.BOTTOM_LEFT:
case OrientationTypes.LEFT_TOP:
case OrientationTypes.RIGHT_BOTTOM:
return width / height;
case OrientationTypes.RIGHT_TOP:
case OrientationTypes.LEFT_BOTTOM:
return height / width;
}
};
export const formatAperture = (aperture?: number) =>
aperture
? `ƒ/${roundToString(aperture)}`
: undefined;
export const formatIso = (iso?: number) =>
iso ? `ISO ${iso.toLocaleString()}` : undefined;
export const formatExposureTime = (exposureTime = 0) =>
exposureTime > 0
? exposureTime < 1
? `1/${Math.floor(1 / exposureTime)}s`
: `${exposureTime}s`
: undefined;
export const formatExposureCompensation = (exposureCompensation?: number) => {
if (
exposureCompensation &&
Math.abs(exposureCompensation) > 0.01
) {
return `${formatNumberToFraction(exposureCompensation)}ev`;
} else {
return undefined;
}
};
export const removeGpsFromFile = async (
fileBytes: ArrayBuffer
): Promise<Blob> => {
const base64 = Buffer.from(fileBytes).toString('base64');
const base64Url = `data:image/jpeg;base64,${base64}`;
const exifObject = PiExif.load(base64Url) as Record<string, any>;
delete exifObject.GPS;
const exifDataWithoutGps = PiExif.dump(exifObject);
const data = PiExif.insert(
exifDataWithoutGps,
base64Url,
);
return fetch(data, { cache: 'no-store' }).then(res => res.blob());
};