mirror of
https://github.com/CorentinTh/it-tools.git
synced 2024-09-11 13:37:53 +03:00
feat(new tool): Potrace
Convert an raster image to vectorial SVG
This commit is contained in:
parent
b430baef40
commit
d15ab07109
@ -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 potrace } from './potrace';
|
||||
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,
|
||||
potrace,
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Development',
|
||||
|
12
src/tools/potrace/index.ts
Normal file
12
src/tools/potrace/index.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ArrowsShuffle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Image to SVG (potrace)',
|
||||
path: '/potrace',
|
||||
description: 'Convert an raster image to vectorial SVG',
|
||||
keywords: ['potrace', 'image', 'svg', 'raster', 'vectorial'],
|
||||
component: () => import('./potrace.vue'),
|
||||
icon: ArrowsShuffle,
|
||||
createdAt: new Date('2024-05-11'),
|
||||
});
|
94
src/tools/potrace/potrace.vue
Normal file
94
src/tools/potrace/potrace.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue';
|
||||
import potrace from 'potrace';
|
||||
import Base64 from 'js-base64';
|
||||
import TextareaCopyable from '@/components/TextareaCopyable.vue';
|
||||
|
||||
async function traceAsync(input: Uint8Array) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
potrace.trace(input, (err: Error, svg: string) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(svg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function posterizeAsync(input: Uint8Array) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
potrace.posterize(input, (err: Error, svg: string) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(svg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function file2Buffer(file: File) {
|
||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => {
|
||||
const buffer = reader.result as ArrayBuffer;
|
||||
resolve(buffer);
|
||||
});
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
const posterize = ref(true);
|
||||
const fileInput = ref() as Ref<File>;
|
||||
const svg = computedAsync(async () => {
|
||||
const trace = !posterize.value;
|
||||
try {
|
||||
const buffer = new Uint8Array(await file2Buffer(fileInput.value));
|
||||
return (trace ? await traceAsync(buffer) : await posterizeAsync(buffer));
|
||||
}
|
||||
catch (e: any) {
|
||||
return e.toString();
|
||||
}
|
||||
});
|
||||
|
||||
const svgBase64 = computed(() => `data:image/svg+xml;base64,${Base64.encode(svg.value)}`);
|
||||
|
||||
async function onUpload(file: File) {
|
||||
if (file) {
|
||||
fileInput.value = file;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-file-upload
|
||||
title="Drag and drop an image here, or click to select a file"
|
||||
:paste-image="true"
|
||||
@file-upload="onUpload"
|
||||
/>
|
||||
|
||||
<n-checkbox v-model:checked="posterize">
|
||||
Posterize?
|
||||
</n-checkbox>
|
||||
|
||||
<n-divider />
|
||||
|
||||
<div>
|
||||
<h3>Potrace result</h3>
|
||||
<TextareaCopyable
|
||||
:value="svg"
|
||||
:word-wrap="true"
|
||||
/>
|
||||
|
||||
<n-divider />
|
||||
|
||||
<img width="150" :src="svgBase64">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.n-upload-trigger) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user