diff --git a/components.d.ts b/components.d.ts index e9b1cd33..9071d5e9 100644 --- a/components.d.ts +++ b/components.d.ts @@ -120,6 +120,7 @@ declare module '@vue/runtime-core' { IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] IconMdiVideo: typeof import('~icons/mdi/video')['default'] + ImageExifReader: typeof import('./src/tools/image-exif-reader/image-exif-reader.vue')['default'] ImageResizer: typeof import('./src/tools/image-resizer/image-resizer.vue')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] diff --git a/package.json b/package.json index edbabcca..d7acce6d 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "emojilib": "^3.0.10", "fflate": "^0.8.2", "figlet": "^1.7.0", + "exifreader": "^4.20.0", "figue": "^1.2.0", "fuse.js": "^6.6.2", "hash-wasm": "^4.9.0", @@ -78,6 +79,7 @@ "ibantools": "^4.3.3", "js-base64": "^3.7.7", "json-editor-vue": "^0.17.2", + "jpeg-quality-estimator": "^1.0.1", "json5": "^2.2.3", "jszip": "^3.10.1", "jwt-decode": "^3.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1300ce02..b9ddfe3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,6 +104,9 @@ importers: emojilib: specifier: ^3.0.10 version: 3.0.10 + exifreader: + specifier: ^4.20.0 + version: 4.25.0 fflate: specifier: ^0.8.2 version: 0.8.2 @@ -128,6 +131,9 @@ importers: ibantools: specifier: ^4.3.3 version: 4.3.3 + jpeg-quality-estimator: + specifier: ^1.0.1 + version: 1.0.1 js-base64: specifier: ^3.7.7 version: 3.7.7 @@ -2407,6 +2413,10 @@ packages: '@vueuse/shared@11.2.0': resolution: {integrity: sha512-VxFjie0EanOudYSgMErxXfq6fo8vhr5ICI+BuE3I9FnX7ePllEsVrRQ7O6Q1TLgApeLuPKcHQxAXpP+KnlrJsg==} + '@xmldom/xmldom@0.9.5': + resolution: {integrity: sha512-6g1EwSs8cr8JhP1iBxzyVAWM6BIDvx9Y3FZRIQiMDzgG43Pxi8YkWOZ0nQj2NHgNzgXDZbJewFx/n+YAvMZrfg==} + engines: {node: '>=14.6'} + '@zhead/schema@1.0.0-beta.13': resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==} @@ -3336,6 +3346,9 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + exifreader@4.25.0: + resolution: {integrity: sha512-lPyPXWTUuYgoKdKf3rw2EDoE9Zl7xHoy/ehPNeQ4gFVNLzfLyNMP4oEI+sP0/Czp5r/2i7cFhqg5MHsl4FYtyw==} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -3926,6 +3939,9 @@ packages: resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} engines: {node: '>= 0.6.0'} + jpeg-quality-estimator@1.0.1: + resolution: {integrity: sha512-Znaq+msIqs8Gmhg9JSdDjxUAZMOwYXWIURrfluimn5u2yJ4QAEDhf0tnTMkv3ikcHJoJysG5ewxfbqUXyw/Djg==} + js-base64@3.7.7: resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} @@ -8488,6 +8504,9 @@ snapshots: - '@vue/composition-api' - vue + '@xmldom/xmldom@0.9.5': + optional: true + '@zhead/schema@1.0.0-beta.13': {} abab@2.0.6: {} @@ -9555,6 +9574,10 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + exifreader@4.25.0: + optionalDependencies: + '@xmldom/xmldom': 0.9.5 + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -10143,6 +10166,8 @@ snapshots: jmespath@0.16.0: {} + jpeg-quality-estimator@1.0.1: {} + js-base64@3.7.7: {} js-beautify@1.14.6: diff --git a/src/tools/image-exif-reader/image-exif-reader.vue b/src/tools/image-exif-reader/image-exif-reader.vue new file mode 100644 index 00000000..fee8aa3b --- /dev/null +++ b/src/tools/image-exif-reader/image-exif-reader.vue @@ -0,0 +1,155 @@ + + + diff --git a/src/tools/image-exif-reader/index.ts b/src/tools/image-exif-reader/index.ts new file mode 100644 index 00000000..c9c875f7 --- /dev/null +++ b/src/tools/image-exif-reader/index.ts @@ -0,0 +1,12 @@ +import { FileInfo } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Image EXIF/Metadata/GPS/JPEG Quality reader', + path: '/image-exif-reader', + description: 'Read EXIF, IPTC, XMP, GPS and other metadata, JPEG Quality, and other infos from images files', + keywords: ['image', 'exif', 'reader', 'iptc', 'gps', 'xmp', 'jpeg', 'quality'], + component: () => import('./image-exif-reader.vue'), + icon: FileInfo, + createdAt: new Date('2024-01-09'), +}); diff --git a/src/tools/image-exif-reader/jpeg-quality-estimator.d.ts b/src/tools/image-exif-reader/jpeg-quality-estimator.d.ts new file mode 100644 index 00000000..46ccc85c --- /dev/null +++ b/src/tools/image-exif-reader/jpeg-quality-estimator.d.ts @@ -0,0 +1,4 @@ +declare module 'jpeg-quality-estimator' { + const getJpegQuality: (file: Uint8Array) => number; + export default getJpegQuality; +} diff --git a/src/tools/index.ts b/src/tools/index.ts index 28e009c4..4993c55e 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -99,6 +99,7 @@ import { tool as macAddressLookup } from './mac-address-lookup'; import { tool as xmlFormatter } from './xml-formatter'; import { tool as dockerComposeToDockerRunConverter } from './docker-compose-to-docker-run-converter'; import { tool as dockerComposeConverter } from './docker-compose-converter'; +import { tool as imageExifReader } from './image-exif-reader'; import { tool as yamlViewer } from './yaml-viewer'; export const toolsByCategory: ToolCategory[] = [ @@ -172,7 +173,13 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Images and videos', - components: [qrCodeGenerator, wifiQrCodeGenerator, svgPlaceholderGenerator, cameraRecorder, imageResizer, ocrImage], + components: [ + qrCodeGenerator, + wifiQrCodeGenerator, + svgPlaceholderGenerator, + cameraRecorder, imageResizer, ocrImage, + imageExifReader, + ], }, { name: 'Development',