Skip to content

Commit a016bb5

Browse files
committed
Merge branch 'feat/removeexif' into chore/all-my-stuffs
# Conflicts: # components.d.ts # package.json # pnpm-lock.yaml # src/tools/index.ts # vite.config.ts
2 parents 8bffa36 + 476172a commit a016bb5

File tree

5 files changed

+111
-0
lines changed

5 files changed

+111
-0
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"@types/punycode": "^2.1.4",
8686
"@types/figlet": "^1.5.8",
8787
"@types/markdown-it": "^13.0.7",
88+
"@types/memorystream": "^0.3.4",
8889
"@vicons/material": "^0.12.0",
8990
"@vicons/tabler": "^0.12.0",
9091
"@vueuse/core": "^10.11.1",
@@ -121,6 +122,7 @@
121122
"email-normalizer": "^1.0.0",
122123
"emojilib": "^3.0.10",
123124
"fast_array_intersect": "^1.1.0",
125+
"exif-be-gone": "^1.5.1",
124126
"figlet": "^1.7.0",
125127
"figue": "^1.2.0",
126128
"flatten-anything": "^4.0.1",
@@ -169,6 +171,7 @@
169171
"markdown-it": "^14.0.0",
170172
"marked": "^10.0.0",
171173
"mathjs": "^11.9.1",
174+
"memorystream": "^0.3.1",
172175
"mime-types": "^2.1.35",
173176
"monaco-editor": "^0.43.0",
174177
"naive-ui": "^2.35.0",

pnpm-lock.yaml

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { tool as ipGeoLocation } from './ip-geo-location';
4949
import { tool as ocrImage } from './ocr-image';
5050
import { tool as safelinkDecoder } from './safelink-decoder';
5151
import { tool as mongoObjectidConverter } from './mongo-objectid-converter';
52+
import { tool as removeExif } from './remove-exif';
5253
import { tool as xmlToJson } from './xml-to-json';
5354
import { tool as jsonToXml } from './json-to-xml';
5455
import { tool as regexTester } from './regex-tester';
@@ -271,6 +272,7 @@ export const toolsByCategory: ToolCategory[] = [
271272
qrCodeDecoder,
272273
svgPlaceholderGenerator,
273274
cameraRecorder,
275+
removeExif,
274276
],
275277
},
276278
{

src/tools/remove-exif/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { PictureInPictureOff } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'Remove EXIF',
6+
path: '/remove-exif',
7+
description: 'Remove Exif from JPEG Files',
8+
keywords: ['remove', 'exif', 'jpeg'],
9+
component: () => import('./remove-exif.vue'),
10+
icon: PictureInPictureOff,
11+
createdAt: new Date('2024-07-14'),
12+
});

src/tools/remove-exif/remove-exif.vue

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script setup lang="ts">
2+
import { Buffer } from 'node:buffer';
3+
import { Base64 } from 'js-base64';
4+
import ExifTransformer from 'exif-be-gone';
5+
import MemoryStream from 'memorystream';
6+
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
7+
8+
const status = ref<'idle' | 'done' | 'error' | 'processing'>('idle');
9+
const file = ref<File | null>(null);
10+
11+
interface ToBufferMemoryStream extends MemoryStream {
12+
toBuffer(): Buffer
13+
}
14+
15+
const base64OutputFile = ref('');
16+
const fileName = ref('');
17+
const { download } = useDownloadFileFromBase64(
18+
{
19+
source: base64OutputFile,
20+
filename: fileName,
21+
extension: 'jpg',
22+
});
23+
24+
async function onFileUploaded(uploadedFile: File) {
25+
file.value = uploadedFile;
26+
const fileBuffer = await uploadedFile.arrayBuffer();
27+
28+
fileName.value = `noexif_${uploadedFile.name}`;
29+
status.value = 'processing';
30+
try {
31+
const inStream = MemoryStream.createReadStream(Buffer.from(fileBuffer));
32+
const outStream = MemoryStream.createWriteStream();
33+
const trans = new ExifTransformer();
34+
await new Promise((resolve, _reject) => {
35+
inStream.pipe(trans).pipe(outStream).on('finish', () => resolve(true));
36+
});
37+
38+
const outFileBuffer = (outStream as ToBufferMemoryStream).toBuffer();
39+
base64OutputFile.value = `data:image/File;base64,${Base64.fromUint8Array(outFileBuffer)}`;
40+
status.value = 'done';
41+
42+
download();
43+
}
44+
catch (e) {
45+
status.value = 'error';
46+
}
47+
}
48+
</script>
49+
50+
<template>
51+
<div>
52+
<div style="flex: 0 0 100%">
53+
<div mx-auto max-w-600px>
54+
<c-file-upload title="Drag and drop a Image file here, or click to select a file" accept="image/*" @file-upload="onFileUploaded" />
55+
</div>
56+
</div>
57+
58+
<div mt-3 flex justify-center>
59+
<c-alert v-if="status === 'error'" type="error">
60+
An error occured processing {{ fileName }}
61+
</c-alert>
62+
<n-spin
63+
v-if="status === 'processing'"
64+
size="small"
65+
/>
66+
</div>
67+
</div>
68+
</template>

0 commit comments

Comments
 (0)