Compare commits

...

6 Commits

Author SHA1 Message Date
sharevb
ef1b615a45
Merge d3ee99a2b0 into e876d03608 2024-05-13 12:52:23 -05:00
Corentin Thomasset
e876d03608
chore(version): release 2024.05.13-a0bc346 2024-05-13 10:54:18 +02:00
Corentin Thomasset
81cf6b5483
docs(changelog): update changelog for 2024.05.13-a0bc346 2024-05-13 10:54:18 +02:00
Corentin THOMASSET
a0bc3468b2
chore(issues): prevent empty issues (#1078) 2024-05-13 08:44:04 +00:00
Corentin THOMASSET
5a7b0f9636
chore(issues): removed old issue templates (#1077) 2024-05-13 08:11:47 +00:00
sharevb
d3ee99a2b0 feat(new tool): HEIC Converter
Fix #997
2024-04-28 21:27:19 +02:00
14 changed files with 313 additions and 74 deletions

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -1,5 +1,5 @@
name: 🚀 New feature proposal
description: Propose a new feature to be added to IT-Tools.
description: Propose a new feature/enhancement or tool idea for IT-Tools
labels: ['enhancement', 'triage']
body:

View File

@ -1,19 +0,0 @@
---
name: New tool request
about: Suggest a new tool idea
title: '[NEW TOOL]'
labels: new tool
assignees: CorentinTh
---
**What tool do you want?**
Example: a token generator
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Is their example of this tool in the wild?**
Provide link to already existing tool or npm packages if any exists
**Additional context**
Add any other context about the feature request here.

View File

@ -1,13 +0,0 @@
---
name: Other request
about: Any request that does not concern a tool creation, a new feature request on a tool or a bug
title: '[OTHER] '
labels:
assignees: CorentinTh
---
**Describe the solution you'd like**
A clear and concise description of what you want.
**Additional context**
Add any other context about the feature request here.

View File

@ -1,13 +0,0 @@
---
name: Tool improvement
about: Improvement on an existing tool
title: '[TOOL IMPROVEMENT]'
labels: enhancement
assignees: CorentinTh
---
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context about the feature request here.

View File

@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## Version 2024.05.10-33e5294
## Version 2024.05.13-a0bc346
### Features
- **i18n**: added German translation (#1038) (2c2fb21)
@ -33,12 +33,20 @@ All notable changes to this project will be documented in this file. See [standa
- **i18n**: added locales per tool (#861) (95698cb)
### Chores
- **issues**: prevent empty issues (#1078) (a0bc346)
- **issues**: removed old issue templates (#1077) (5a7b0f9)
- **node**: upgraded node version in CI workflows (b59942a)
- **version**: release 2024.05.10-33e5294 (38d5687)
- **issues**: improved issues template (2852c30)
- **issues**: improved bug issue template (#1046) (a799234)
### Documentation
- **changelog**: update changelog for 2024.05.10-33e5294 (9dfd347)
## Version 2023.12.21-5ed3693
### Features
- **i18n**: improve chinese i18n (#757) (2e56641)
- **i18n**: add tooltip and favoriteButton i18n (#756) (a1037cf)
- **i18n**: add Chinese translation base (#718) (8f99eb6)
@ -46,6 +54,7 @@ All notable changes to this project will be documented in this file. See [standa
- **new tool**: numeronym generator (#729) (e07e2ae)
### Bug fixes
- **jwt-parser**: jwt claim array support (#799) (5ed3693)
- **camera-recorder**: stop camera on navigation (#782) (80e46c9)
- **doc**: updated create new tool command in readme (#762) (7a70dbb)
@ -54,6 +63,7 @@ All notable changes to this project will be documented in this file. See [standa
- **eta**: corrected example (#737) (821cbea)
### Refactoring
- **about, i18n**: improved i18n dx with markdown (#753) (bd3edcb)
- **token, i18n**: complete fr translation (#752) (de1ee69)
- **uuid generator**: uuid version picker (#751) (38586ca)
@ -63,6 +73,7 @@ All notable changes to this project will be documented in this file. See [standa
- **bcrypt**: fix input label align (#721) (093ff31)
### Chores
- **deps**: switched from oui to oui-data for mac address lookup (#693) (0fe9a20)
- **deps**: update unocss monorepo to ^0.57.0 (#638) (2e396d8)
- **docker**: added armv7 plateform for docker releases (#722) (fe1de8c)
@ -70,19 +81,23 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.11.02-7d94e11
### Features
- **i18n**: language selector (#710) (e86fd96)
### Bug fixes
- **dockerfile**: revert replacement of nginx image with non-privileged one (#716) (7d94e11)
- **encryption**: alert on decryption error (#711) (02b0d0d)
### Refactoring
- **math-evaluator**: improved description (e87f4b1)
- **math-evaluator**: improved search and UX (#713) (58de897)
## Version 2023.11.01-e164afb
### Features
- **command-palette**: clear prompt on palette close (#708) (d013696)
- **command-palette**: added about page in command palette (99b1eb9)
- **new tool**: random MAC address generator (#657) (cc3425d)
@ -101,11 +116,13 @@ All notable changes to this project will be documented in this file. See [standa
- **new tool**: text diff and comparator (#588) (81bfe57)
### Bug fixes
- **deps**: fix issue on slugify (#593) (#673) (720201a)
- **deps**: update dependency monaco-editor to ^0.43.0 (#620) (e371ef7)
- **deps**: update dependency sql-formatter to v13 (#606) (c7d4562)
### Refactoring
- **ui**: better ui demo preview menu (#664) (015c673)
- **color-converter**: improved color-converter UX (#701) (abb8335)
- **docker**: improved docker config (#700) (020e9cb)
@ -122,6 +139,7 @@ All notable changes to this project will be documented in this file. See [standa
- **bcrypt**: fix typo (#604) (e18bae1)
### Chores
- **deps**: clean unused dependencies (#709) (e164afb)
- **deps**: update docker/setup-qemu-action action to v3 (#627) (4365226)
- **deps**: update docker/setup-buildx-action action to v3 (#626) (57ecda1)
@ -136,19 +154,23 @@ All notable changes to this project will be documented in this file. See [standa
- **deps**: update dependency typescript to ~5.2.0 (#587) (f3e14fc)
### Doc
- **readme**: added contributors list (#622) (557b304)
- **hosting**: added cloudron in the other hosting solutions section (#589) (06c3547)
## Version 2023.08.21-6f93cba
### Features
- **copy**: support legacy copy to clipboard for older browser (#581) (6f93cba)
- **new tool**: string obfuscator (#575) (c58d6e3)
### Bug fixes
- **deps**: update dependency sql-formatter to v12 (#520) (2bcb77a)
### Chores
- **deps**: switched to fucking typescript v5 (#501) (76b2761)
- **deps**: update dependency @antfu/eslint-config to ^0.40.0 (#552) (6ff9a01)
- **deps**: update dependency prettier to v3 (#564) (a2b9b15)
@ -158,6 +180,7 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.08.16-9bd4ad4
### Features
- **Case Converter**: Add lowercase and uppercase (#534) (7b6232a)
- **new tool**: emoji picker (#551) (93f7cf0)
- **ui**: added c-select in the ui lib (#550) (dfa1ba8)
@ -178,6 +201,7 @@ All notable changes to this project will be documented in this file. See [standa
- **base64-string-converter**: switch to encode and decode url safe base64 strings (#392) (0b20f1c)
### Bug fixes
- **deps**: update dependency uuid to v9 (#566) (5e12991)
- **deps**: update dependency mathjs to v11 (#519) (7924456)
- **deps**: update dependency @vueuse/router to v10 (#516) (ea0f27c)
@ -197,6 +221,7 @@ All notable changes to this project will be documented in this file. See [standa
- **ipv4-converter**: removed readonly on input (7aed9c5)
### Refactoring
- **navbar**: consistent spacing in navbar buttons (#507) (30f88fc)
- **ui**: remove n-text (#506) (72c98a3)
- **ui**: replaced some n-input to c-input (#505) (05ea545)
@ -209,6 +234,7 @@ All notable changes to this project will be documented in this file. See [standa
- **ui**: replaced some n-input with c-input-text (f7fc779)
### Chores
- **deps**: update dependency vitest to ^0.34.0 (#562) (9bd4ad4)
- **deps**: update dependency node to v18.17.1 (#560) (65a9474)
- **deps**: update dependency unocss to ^0.55.0 (#561) (85cc7a8)
@ -249,47 +275,58 @@ All notable changes to this project will be documented in this file. See [standa
- **lint**: switched to a better lint config (33c9b66)
### Refacor
- **transformers**: use monospace font for JSON and SQL text areas (#476) (ba4876d)
### Documentation
- **ide**: updated vscode extensions settings (#472) (847323c)
### Chors
- **deps**: updated vueuse dependency version (8515c24)
## Version 2023.05.14-77f2efc
### Features
- **list-converter**: a small converter who deals with column based data and do some stuff with it (#387) (83a7b3b)
- **new tool**: phone parser and normalizer (ce3150c)
### Bug fixes
- **phone-parser**: use default country code (a43c546)
- **home**: prevent weird blue border on card (3f6c8f0)
### Refactoring
- **ui**: replaced some n-input with c-input-text (77f2efc)
### Chores
- **issues**: updated new tool request issue template (edae4c6)
### Ui-lib
- **new-component**: added text input component in the c-lib (aad8d84)
- **button**: size variants (401f13f)
## Version 2023.04.23-92bd835
### Features
- **ui-lib**: demo pages for c-lib components (92bd835)
- **new-tool**: diff of two json objects (362f2fa)
- **ipv4-range-expander**: expands a given IPv4 start and end address to a valid IPv4 subnet (#366) (df989e2)
- **date converter**: auto focus main input (6d22025)
### Bug fixes
- **ts**: cleaned legacy typechecking warning (e88c1d5)
- **mac-address-lookup**: added copy handler on button click (c311e38)
### Refactoring
- **ui-lib**: prevent c-button to shrink (61ece23)
- **ui**: replaced naive ui cards with custom ones (f080933)
- **clean**: removed unused lodash import (bb32513)
@ -299,48 +336,60 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.04.14-dbad773
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (dbad773)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-f9b77b7
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (f9b77b7)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-2f0d239
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (2f0d239)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-474cae4
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (474cae4)
- **version**: reset CHANGELOG content to support new format (85cb0ff)

2
components.d.ts vendored
View File

@ -82,6 +82,7 @@ declare module '@vue/runtime-core' {
GitMemo: typeof import('./src/tools/git-memo/git-memo.vue')['default']
'GitMemo.content': typeof import('./src/tools/git-memo/git-memo.content.md')['default']
HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default']
HeicConverter: typeof import('./src/tools/heic-converter/heic-converter.vue')['default']
HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']
'Home.page': typeof import('./src/pages/Home.page.vue')['default']
HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']
@ -129,6 +130,7 @@ declare module '@vue/runtime-core' {
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
NCode: typeof import('naive-ui')['NCode']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NColorPicker: typeof import('naive-ui')['NColorPicker']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDivider: typeof import('naive-ui')['NDivider']
NEllipsis: typeof import('naive-ui')['NEllipsis']

View File

@ -1,6 +1,6 @@
{
"name": "it-tools",
"version": "2024.5.10-33e5294",
"version": "2024.5.13-a0bc346",
"description": "Collection of handy online tools for developers, with great UX. ",
"keywords": [
"productivity",
@ -61,9 +61,11 @@
"figlet": "^1.7.0",
"figue": "^1.2.0",
"fuse.js": "^6.6.2",
"heic-convert": "^2.1.0",
"highlight.js": "^11.7.0",
"iarna-toml-esm": "^3.0.5",
"ibantools": "^4.3.3",
"js-base64": "^3.7.7",
"json5": "^2.2.3",
"jwt-decode": "^3.1.2",
"libphonenumber-js": "^1.10.28",

View File

@ -83,6 +83,9 @@ dependencies:
fuse.js:
specifier: ^6.6.2
version: 6.6.2
heic-convert:
specifier: ^2.1.0
version: 2.1.0
highlight.js:
specifier: ^11.7.0
version: 11.7.0
@ -92,6 +95,9 @@ dependencies:
ibantools:
specifier: ^4.3.3
version: 4.3.3
js-base64:
specifier: ^3.7.7
version: 3.7.7
json5:
specifier: ^2.2.3
version: 2.2.3
@ -3351,7 +3357,7 @@ packages:
dependencies:
'@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1
'@vueuse/shared': 10.7.2(vue@3.3.4)
'@vueuse/shared': 10.9.0(vue@3.3.4)
unhead: 0.5.1
vue: 3.3.4
transitivePeerDependencies:
@ -3993,10 +3999,10 @@ packages:
- vue
dev: false
/@vueuse/shared@10.7.2(vue@3.3.4):
resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==}
/@vueuse/shared@10.9.0(vue@3.3.4):
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
dependencies:
vue-demi: 0.14.6(vue@3.3.4)
vue-demi: 0.14.7(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
@ -5994,6 +6000,22 @@ packages:
tslib: 2.5.0
dev: false
/heic-convert@2.1.0:
resolution: {integrity: sha512-1qDuRvEHifTVAj3pFIgkqGgJIr0M3X7cxEPjEp0oG4mo8GFjq99DpCo8Eg3kg17Cy0MTjxpFdoBHOatj7ZVKtg==}
engines: {node: '>=12.0.0'}
dependencies:
heic-decode: 2.0.0
jpeg-js: 0.4.4
pngjs: 6.0.0
dev: false
/heic-decode@2.0.0:
resolution: {integrity: sha512-NU+zsiDvdL+EebyTjrEqjkO2XYI7FgLhQzsbmO8dnnYce3S0PBSDm/ZyI4KpcGPXYEdb5W72vp/AQFuc4F8ASg==}
engines: {node: '>=8.0.0'}
dependencies:
libheif-js: 1.17.1
dev: false
/highlight.js@11.7.0:
resolution: {integrity: sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==}
engines: {node: '>=12.0.0'}
@ -6472,6 +6494,14 @@ packages:
hasBin: true
dev: true
/jpeg-js@0.4.4:
resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
dev: false
/js-base64@3.7.7:
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
dev: false
/js-beautify@1.14.6:
resolution: {integrity: sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==}
engines: {node: '>=10'}
@ -6656,6 +6686,11 @@ packages:
type-check: 0.4.0
dev: true
/libheif-js@1.17.1:
resolution: {integrity: sha512-g9wBm/CasGZMjmH3B2sD9+AO7Y5+79F0oPS+sdAulSxQeYeCeiTIP+lDqvlPofD+y76wvfVtotKZ8AuvZQnWgg==}
engines: {node: '>=8.0.0'}
dev: false
/libphonenumber-js@1.10.28:
resolution: {integrity: sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw==}
dev: false
@ -7429,6 +7464,11 @@ packages:
engines: {node: '>=10.13.0'}
dev: false
/pngjs@6.0.0:
resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==}
engines: {node: '>=12.13.0'}
dev: false
/postcss-selector-parser@6.0.13:
resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
engines: {node: '>=4'}
@ -9151,8 +9191,8 @@ packages:
vue: 3.3.4
dev: false
/vue-demi@0.14.6(vue@3.3.4):
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
/vue-demi@0.14.7(vue@3.3.4):
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
@ -9442,6 +9482,7 @@ packages:
/workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
dependencies:
workbox-background-sync: 7.0.0
workbox-core: 7.0.0

View File

@ -1,8 +1,13 @@
import { extension as getExtensionFromMime } from 'mime-types';
import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types';
import type { Ref } from 'vue';
import _ from 'lodash';
export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
export {
getMimeTypeFromBase64,
getMimeTypeFromExtension, getExtensionFromMimeType,
useDownloadFileFromBase64, useDownloadFileFromBase64Refs,
previewImageFromBase64,
};
const commonMimeTypesSignatures = {
'JVBERi0': 'application/pdf',
@ -36,30 +41,78 @@ function getFileExtensionFromMimeType({
defaultExtension?: string
}) {
if (mimeType) {
return getExtensionFromMime(mimeType) ?? defaultExtension;
return getExtensionFromMimeType(mimeType) ?? defaultExtension;
}
return defaultExtension;
}
function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }:
{ sourceValue: string; filename?: string; extension?: string; fileMimeType?: string }) {
if (sourceValue === '') {
throw new Error('Base64 string is empty');
}
const defaultExtension = extension ?? 'txt';
const { mimeType } = getMimeTypeFromBase64({ base64String: sourceValue });
let base64String = sourceValue;
if (!mimeType) {
const targetMimeType = fileMimeType ?? getMimeTypeFromExtension(defaultExtension);
base64String = `data:${targetMimeType};base64,${sourceValue}`;
}
const cleanExtension = extension ?? getFileExtensionFromMimeType(
{ mimeType, defaultExtension });
let cleanFileName = filename ?? `file.${cleanExtension}`;
if (extension && !cleanFileName.endsWith(`.${extension}`)) {
cleanFileName = `${cleanFileName}.${cleanExtension}`;
}
const a = document.createElement('a');
a.href = base64String;
a.download = cleanFileName;
a.click();
}
function useDownloadFileFromBase64(
{ source, filename, extension, fileMimeType }:
{ source: Ref<string>; filename?: string; extension?: string; fileMimeType?: string }) {
return {
download() {
if (source.value === '') {
throw new Error('Base64 string is empty');
}
const { mimeType } = getMimeTypeFromBase64({ base64String: source.value });
const base64String = mimeType
? source.value
: `data:text/plain;base64,${source.value}`;
const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`;
const a = document.createElement('a');
a.href = base64String;
a.download = cleanFileName;
a.click();
downloadFromBase64({ sourceValue: source.value, filename, extension, fileMimeType });
},
};
}
function useDownloadFileFromBase64Refs(
{ source, filename, extension }:
{ source: Ref<string>; filename?: Ref<string>; extension?: Ref<string> }) {
return {
download() {
downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value });
},
};
}
function previewImageFromBase64(base64String: string): HTMLImageElement {
if (base64String === '') {
throw new Error('Base64 string is empty');
}
const img = document.createElement('img');
img.src = base64String;
const container = document.createElement('div');
container.appendChild(img);
const previewContainer = document.getElementById('previewContainer');
if (previewContainer) {
previewContainer.innerHTML = '';
previewContainer.appendChild(container);
}
else {
throw new Error('Preview container element not found');
}
return img;
}

View File

@ -0,0 +1,30 @@
declare module 'heic-convert/browser' {
interface ConversionOptions {
/**
* the HEIC file buffer
*/
buffer: ArrayBufferLike;
/**
* output format
*/
format: "JPEG" | "PNG";
/**
* the JPEG compression quality, between 0 and 1
* @default 0.92
*/
quality?: number;
}
interface Convertible {
convert(): Promise<ArrayBuffer>;
}
/** @async */
declare function convert(image: ConversionOptions): Promise<ArrayBuffer>;
declare namespace convert {
/** @async */
function all(image: ConversionOptions): Promise<Convertible[]>;
}
export default convert;
}

View File

@ -0,0 +1,87 @@
<script setup lang="ts">
import { Base64 } from 'js-base64';
import heicConvert from 'heic-convert/browser';
import { useDownloadFileFromBase64Refs } from '@/composable/downloadBase64';
const status = ref<'idle' | 'done' | 'error' | 'processing'>('idle');
const file = ref<File | null>(null);
const base64OutputImage = ref('');
const fileName = ref('');
const format = ref('jpg');
const formats = [
{ value: 'jpg', label: 'JPEG' },
{ value: 'png', label: 'PNG' },
];
const { download } = useDownloadFileFromBase64Refs(
{
source: base64OutputImage,
filename: fileName,
});
async function onFileUploaded(uploadedFile: File) {
file.value = uploadedFile;
const fileBuffer = await uploadedFile.arrayBuffer();
fileName.value = `${uploadedFile.name}.${format.value}`;
status.value = 'processing';
try {
let convertFormat;
if (format.value === 'jpg') {
convertFormat = 'JPEG';
}
else if (format.value === 'png') {
convertFormat = 'PNG';
}
else {
throw new Error('unknown format');
}
const outputBuffer = await heicConvert({
buffer: new Uint8Array(fileBuffer),
format: convertFormat as ('JPEG' | 'PNG'),
quality: 0.98,
});
base64OutputImage.value = `data:image/${convertFormat.toLowerCase()};base64,${Base64.fromUint8Array(new Uint8Array(outputBuffer))}`;
status.value = 'done';
download();
}
catch (e) {
status.value = 'error';
}
}
</script>
<template>
<div>
<c-select
v-model:value="format"
:options="formats"
label="Output format"
/>
<div style="flex: 0 0 100%" mt-3>
<div mx-auto max-w-600px>
<c-file-upload
title="Drag and drop a HEIC file here, or click to select a file"
accept=".heic,.heif" @file-upload="onFileUploaded"
/>
</div>
</div>
<div mt-3 flex justify-center>
<img :src="base64OutputImage" max-w-300px>
</div>
<div mt-3 flex justify-center>
<c-alert v-if="status === 'error'" type="error">
An error occured processing {{ fileName }}. HEIC/HEIF is invalid.
</c-alert>
<n-spin
v-if="status === 'processing'"
size="small"
/>
</div>
</div>
</template>

View File

@ -0,0 +1,12 @@
import { Photo } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'HEIC Converter',
path: '/heic-converter',
description: 'HEIC Converter to JPEG or PNG',
keywords: ['heic', 'heif', 'convert', 'decoder', 'converter'],
component: () => import('./heic-converter.vue'),
icon: Photo,
createdAt: new Date('2024-04-28'),
});

View File

@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer';
import { tool as textToUnicode } from './text-to-unicode';
import { tool as safelinkDecoder } from './safelink-decoder';
import { tool as heicConverter } from './heic-converter';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
@ -132,7 +133,13 @@ export const toolsByCategory: ToolCategory[] = [
},
{
name: 'Images and videos',
components: [qrCodeGenerator, wifiQrCodeGenerator, svgPlaceholderGenerator, cameraRecorder],
components: [
qrCodeGenerator,
wifiQrCodeGenerator,
svgPlaceholderGenerator,
cameraRecorder,
heicConverter,
],
},
{
name: 'Development',