Refine GPS-stripping approach
This commit is contained in:
parent
5ff6009329
commit
a09e3b2dba
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -30,8 +30,6 @@
|
||||
"nanoids",
|
||||
"nextjs",
|
||||
"parameterizes",
|
||||
"piexif",
|
||||
"piexifjs",
|
||||
"presigner",
|
||||
"Provia",
|
||||
"qaub",
|
||||
|
||||
@ -47,7 +47,6 @@
|
||||
"next-auth": "5.0.0-beta.18",
|
||||
"next-themes": "^0.3.0",
|
||||
"pg": "^8.12.0",
|
||||
"piexifjs": "^1.0.6",
|
||||
"postcss": "8.4.38",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
|
||||
56
pnpm-lock.yaml
generated
56
pnpm-lock.yaml
generated
@ -122,9 +122,6 @@ importers:
|
||||
pg:
|
||||
specifier: ^8.12.0
|
||||
version: 8.12.0
|
||||
piexifjs:
|
||||
specifier: ^1.0.6
|
||||
version: 1.0.6
|
||||
postcss:
|
||||
specifier: 8.4.38
|
||||
version: 8.4.38
|
||||
@ -3450,9 +3447,6 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
piexifjs@1.0.6:
|
||||
resolution: {integrity: sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag==}
|
||||
|
||||
pify@2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -4403,10 +4397,10 @@ snapshots:
|
||||
'@aws-crypto/sha1-browser': 3.0.0
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0
|
||||
'@aws-sdk/client-sts': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/client-sts': 3.590.0
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/middleware-bucket-endpoint': 3.587.0
|
||||
'@aws-sdk/middleware-expect-continue': 3.577.0
|
||||
'@aws-sdk/middleware-flexible-checksums': 3.587.0
|
||||
@ -4461,13 +4455,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sso-oidc@3.590.0':
|
||||
'@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0)':
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sts': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/client-sts': 3.590.0
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
'@aws-sdk/middleware-logger': 3.577.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.577.0
|
||||
@ -4504,6 +4498,7 @@ snapshots:
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sts'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sso@3.590.0':
|
||||
@ -4549,13 +4544,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0)':
|
||||
'@aws-sdk/client-sts@3.590.0':
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-node': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
'@aws-sdk/middleware-logger': 3.577.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.577.0
|
||||
@ -4592,7 +4587,6 @@ snapshots:
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/core@3.588.0':
|
||||
@ -4624,14 +4618,14 @@ snapshots:
|
||||
'@smithy/util-stream': 3.0.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@aws-sdk/credential-provider-ini@3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))':
|
||||
'@aws-sdk/credential-provider-ini@3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/client-sts': 3.590.0
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.587.0
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
'@aws-sdk/credential-provider-sso': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-sso': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/credential-provider-imds': 3.1.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
@ -4642,14 +4636,14 @@ snapshots:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/credential-provider-node@3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))':
|
||||
'@aws-sdk/credential-provider-node@3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.587.0
|
||||
'@aws-sdk/credential-provider-ini': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-ini': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
'@aws-sdk/credential-provider-sso': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))
|
||||
'@aws-sdk/credential-provider-sso': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/credential-provider-imds': 3.1.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
@ -4669,10 +4663,10 @@ snapshots:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
|
||||
'@aws-sdk/credential-provider-sso@3.590.0(@aws-sdk/client-sso-oidc@3.590.0)':
|
||||
'@aws-sdk/credential-provider-sso@3.590.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sso': 3.590.0
|
||||
'@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
'@smithy/shared-ini-file-loader': 3.1.0
|
||||
@ -4682,9 +4676,9 @@ snapshots:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.590.0(@aws-sdk/client-sso-oidc@3.590.0))':
|
||||
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.590.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.590.0(@aws-sdk/client-sso-oidc@3.590.0)
|
||||
'@aws-sdk/client-sts': 3.590.0
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
'@smithy/types': 3.0.0
|
||||
@ -4809,9 +4803,9 @@ snapshots:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
|
||||
'@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.590.0)':
|
||||
'@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.590.0(@aws-sdk/client-sts@3.590.0))':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0
|
||||
'@aws-sdk/client-sso-oidc': 3.590.0(@aws-sdk/client-sts@3.590.0)
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
'@smithy/shared-ini-file-loader': 3.1.0
|
||||
@ -8550,8 +8544,6 @@ snapshots:
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
piexifjs@1.0.6: {}
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pirates@4.0.6: {}
|
||||
|
||||
@ -108,6 +108,7 @@ export const addAllUploadsAction = async ({
|
||||
photoFormExif,
|
||||
imageResizedBase64,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
} = await extractImageDataFromBlobPath(url, {
|
||||
includeInitialPhotoFields: true,
|
||||
generateBlurData: BLUR_ENABLED,
|
||||
@ -152,6 +153,7 @@ export const addAllUploadsAction = async ({
|
||||
const updatedUrl = await convertUploadToPhoto(
|
||||
url,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
);
|
||||
if (updatedUrl) {
|
||||
stream.update({
|
||||
@ -184,6 +186,7 @@ export const updatePhotoAction = async (formData: FormData) =>
|
||||
|
||||
let url: string | undefined;
|
||||
if (photo.hidden && photo.url.includes(photo.id)) {
|
||||
// Backfill:
|
||||
// Anonymize storage url on update if necessary by
|
||||
// re-running image upload transfer logic
|
||||
url = await convertUploadToPhoto(photo.url);
|
||||
@ -303,6 +306,7 @@ export const syncPhotoAction = async (formData: FormData) =>
|
||||
photoFormExif,
|
||||
imageResizedBase64,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
} = await extractImageDataFromBlobPath(photo.url, {
|
||||
includeInitialPhotoFields: false,
|
||||
generateBlurData: BLUR_ENABLED,
|
||||
@ -316,6 +320,7 @@ export const syncPhotoAction = async (formData: FormData) =>
|
||||
const url = await convertUploadToPhoto(
|
||||
photo.url,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
);
|
||||
if (url) { photo.url = url; }
|
||||
}
|
||||
|
||||
@ -359,6 +359,7 @@ export default function PhotoForm({
|
||||
type="hidden"
|
||||
name="shouldStripGpsData"
|
||||
value={shouldStripGpsData ? 'true' : 'false'}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
{/* Actions */}
|
||||
|
||||
@ -11,7 +11,7 @@ import { ExifData, ExifParserFactory } from 'ts-exif-parser';
|
||||
import { PhotoFormData } from './form';
|
||||
import { FilmSimulation } from '@/simulation';
|
||||
import sharp, { Sharp } from 'sharp';
|
||||
import { GEO_PRIVACY_ENABLED } from '@/site/config';
|
||||
import { GEO_PRIVACY_ENABLED, PRO_MODE_ENABLED } from '@/site/config';
|
||||
|
||||
const IMAGE_WIDTH_RESIZE = 200;
|
||||
const IMAGE_WIDTH_BLUR = 200;
|
||||
@ -28,6 +28,7 @@ export const extractImageDataFromBlobPath = async (
|
||||
photoFormExif?: Partial<PhotoFormData>
|
||||
imageResizedBase64?: string
|
||||
shouldStripGpsData?: boolean
|
||||
fileBytes?: ArrayBuffer
|
||||
}> => {
|
||||
const {
|
||||
includeInitialPhotoFields,
|
||||
@ -100,6 +101,7 @@ export const extractImageDataFromBlobPath = async (
|
||||
},
|
||||
imageResizedBase64,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
};
|
||||
};
|
||||
|
||||
@ -134,20 +136,27 @@ export const blurImageFromUrl = async (url: string) =>
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(buffer => blurImage(buffer));
|
||||
|
||||
const GPS_NULL_STRING = '-';
|
||||
|
||||
export const removeGpsData = async (image: ArrayBuffer) =>
|
||||
generateBase64(image, sharp => sharp
|
||||
sharp(image)
|
||||
.withExifMerge({
|
||||
IFD3: {
|
||||
GPSVersionID: '-',
|
||||
GPSMapDatum: '-',
|
||||
GPSLatitudeRef: '-',
|
||||
GPSLatitude: '-',
|
||||
GPSLongitudeRef: '-',
|
||||
GPSLongitude: '-',
|
||||
GPSTimeStamp: '-',
|
||||
GPSAltitude: '-',
|
||||
GPSAltitudeRef: '-',
|
||||
GPSMapDatum: GPS_NULL_STRING,
|
||||
GPSLatitudeRef: GPS_NULL_STRING,
|
||||
GPSLatitude: GPS_NULL_STRING,
|
||||
GPSLongitudeRef: GPS_NULL_STRING,
|
||||
GPSLongitude: GPS_NULL_STRING,
|
||||
GPSTimeStamp: GPS_NULL_STRING,
|
||||
GPSAltitude: GPS_NULL_STRING,
|
||||
GPSAltitudeRef: GPS_NULL_STRING,
|
||||
GPSSatellites: GPS_NULL_STRING,
|
||||
GPSDestLatitude: GPS_NULL_STRING,
|
||||
GPSDestLongitudeRef: GPS_NULL_STRING,
|
||||
GPSDestDistance: GPS_NULL_STRING,
|
||||
GPSDestDistanceRef: GPS_NULL_STRING,
|
||||
GPSAreaInformation: GPS_NULL_STRING,
|
||||
},
|
||||
})
|
||||
.jpeg({ quality: 100 })
|
||||
);
|
||||
.toFormat('jpeg', { quality: PRO_MODE_ENABLED ? 100 : 80 })
|
||||
.toBuffer();
|
||||
|
||||
@ -5,28 +5,23 @@ import {
|
||||
moveFile,
|
||||
putFile,
|
||||
} from '@/services/storage';
|
||||
import { stripGpsFromFile } from '@/utility/exif-server';
|
||||
import { removeGpsData } from './server';
|
||||
|
||||
export const convertUploadToPhoto = async (
|
||||
urlOrigin: string,
|
||||
stripGps?: boolean,
|
||||
fileBytes?: ArrayBuffer,
|
||||
) => {
|
||||
const fileName = generateRandomFileNameForPhoto();
|
||||
const fileExtension = getExtensionFromStorageUrl(urlOrigin);
|
||||
const photoPath = `${fileName}.${fileExtension || 'jpg'}`;
|
||||
if (stripGps) {
|
||||
console.log('Fetching original file');
|
||||
const fileBytes = await fetch(urlOrigin, { cache: 'no-store' })
|
||||
.then(res => res.arrayBuffer());
|
||||
const fileWithoutGps = await stripGpsFromFile(fileBytes);
|
||||
console.log('Uploading file without GPS');
|
||||
const fileWithoutGps = await removeGpsData(
|
||||
fileBytes ?? await fetch(urlOrigin, { cache: 'no-store' })
|
||||
.then(res => res.arrayBuffer())
|
||||
);
|
||||
return putFile(fileWithoutGps, photoPath).then(async url => {
|
||||
if (url) {
|
||||
console.log('Deleting original file');
|
||||
await deleteFile(urlOrigin);
|
||||
} else {
|
||||
console.log('No url found');
|
||||
}
|
||||
if (url) { await deleteFile(urlOrigin); }
|
||||
return url;
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -33,13 +33,13 @@ export const awsS3PutObjectCommandForKey = (Key: string) =>
|
||||
new PutObjectCommand({ Bucket: AWS_S3_BUCKET, Key, ACL: 'public-read' });
|
||||
|
||||
export const awsS3Put = async (
|
||||
file: Blob,
|
||||
file: Buffer,
|
||||
fileName: string,
|
||||
): Promise<string> =>
|
||||
awsS3Client().send(new PutObjectCommand({
|
||||
Bucket: AWS_S3_BUCKET,
|
||||
Key: fileName,
|
||||
Body: Buffer.from(await file.arrayBuffer()),
|
||||
Body: file,
|
||||
ACL: 'public-read',
|
||||
}))
|
||||
.then(() => urlForKey(fileName));
|
||||
|
||||
@ -54,13 +54,13 @@ export const cloudflareR2PutObjectCommandForKey = (Key: string) =>
|
||||
new PutObjectCommand({ Bucket: CLOUDFLARE_R2_BUCKET, Key });
|
||||
|
||||
export const cloudflareR2Put = async (
|
||||
file: Blob,
|
||||
file: Buffer,
|
||||
fileName: string,
|
||||
): Promise<string> =>
|
||||
cloudflareR2Client().send(new PutObjectCommand({
|
||||
Bucket: CLOUDFLARE_R2_BUCKET,
|
||||
Key: fileName,
|
||||
Body: Buffer.from(await file.arrayBuffer()),
|
||||
Body: file,
|
||||
}))
|
||||
.then(() => urlForKey(fileName));
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ export const uploadPhotoFromClient = async (
|
||||
: vercelBlobUploadFromClient(file, `${PREFIX_UPLOAD}.${extension}`);
|
||||
|
||||
export const putFile = (
|
||||
file: Blob,
|
||||
file: Buffer,
|
||||
fileName: string,
|
||||
) => {
|
||||
switch (CURRENT_STORAGE) {
|
||||
|
||||
@ -29,7 +29,7 @@ export const vercelBlobUploadFromClient = async (
|
||||
.then(({ url }) => url);
|
||||
|
||||
export const vercelBlobPut = (
|
||||
file: File | Blob,
|
||||
file: Buffer,
|
||||
fileName: string,
|
||||
): Promise<string> =>
|
||||
put(fileName, file, {
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
// import * as PiExif from 'piexifjs';
|
||||
import { b64toBlob } from './data';
|
||||
import { removeGpsData } from '@/photo/server';
|
||||
|
||||
export const stripGpsFromFile = async (
|
||||
fileBytes: ArrayBuffer
|
||||
): Promise<Blob> => {
|
||||
// const base64 = Buffer.from(fileBytes).toString('base64');
|
||||
// const base64Url = `data:image/jpeg;base64,${base64}`;
|
||||
|
||||
// console.log('Stripping GPS from file');
|
||||
// const exifObject = PiExif.load(base64Url);
|
||||
// delete exifObject.GPS;
|
||||
// const exifDataWithoutGps = PiExif.dump(exifObject);
|
||||
|
||||
// console.log('Updating EXIF');
|
||||
// const data = PiExif.insert(
|
||||
// exifDataWithoutGps,
|
||||
// base64Url,
|
||||
// );
|
||||
|
||||
// console.log('EXIF updated');
|
||||
|
||||
// Removing EXIF data with Sharp
|
||||
return b64toBlob(await removeGpsData(fileBytes));
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user