Skip to content

Commit f22ea6c

Browse files
committed
Merge branch 'feat/image-ascii-art' into chore/all-my-stuffs
# Conflicts: # package.json # pnpm-lock.yaml # src/tools/index.ts # src/utils/ascii-lang-utils.ts
2 parents d03b31e + 1440c23 commit f22ea6c

File tree

6 files changed

+149
-0
lines changed

6 files changed

+149
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@
195195
"ical.js": "^2.0.1",
196196
"js-base64": "^3.7.7",
197197
"js-beautify": "^1.15.1",
198+
"image-to-ascii-art": "^0.0.4",
198199
"json5": "^2.2.3",
199200
"jsonpath": "^1.1.1",
200201
"jsonar-mod": "^1.9.0",

pnpm-lock.yaml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
declare module 'image-to-ascii-art' {
2+
interface ConfigInterface {
3+
// the integer of pixels drawn on the canvas.
4+
// it sets bigger,the generated ascii art will be more detailed.
5+
// it has two type to set:
6+
// 1. (0, 1] decimal.result is that this number multiplied by the number of pixels in the original image
7+
// 2. An integer greater than 1.
8+
drawWidth?: number;
9+
drawHeight?: number;
10+
// the integer that pick one for every how many pixels.
11+
// it must be an integer greater than 0.
12+
pickDensityHorizontal?: number;
13+
pickDensityVertical?: number;
14+
// set the char of every grey range.
15+
greyRangeChar?: GreyRangeChar[];
16+
// if a grey value can't match one of the 'greyRangeChar' config,use this char.
17+
defaultGreyChar?: string;
18+
}
19+
20+
class ImageToAsciiArt {
21+
constructor({ canvas, config = {} }: { canvas?: HTMLCanvasElement; config?: ConfigInterface } = {})
22+
public convert(image: string | HTMLImageElement): Promise<string>
23+
public destroy(): void
24+
}
25+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<script setup lang="ts">
2+
import { ImageToAsciiArt } from 'image-to-ascii-art';
3+
import TextareaCopyable from '@/components/TextareaCopyable.vue';
4+
import { languages, translateToLanguage } from '@/utils/ascii-lang-utils';
5+
6+
const inputBase64 = ref('');
7+
const language = useStorage('image-to-ascii-art:language', 'raw');
8+
const scale = ref(100);
9+
const errored = ref(false);
10+
const processing = ref(false);
11+
12+
function toBase64(file: File) {
13+
return new Promise<string>((resolve, reject) => {
14+
const reader = new FileReader();
15+
reader.readAsDataURL(file);
16+
reader.onload = () => resolve(reader.result?.toString() ?? '');
17+
reader.onerror = error => reject(error);
18+
});
19+
}
20+
21+
const languagesOptions = languages.map(lang => ({ value: lang.id, label: lang.name }));
22+
23+
const output = computedAsync(async () => {
24+
const inputBase64Value = inputBase64.value;
25+
if (!inputBase64Value) {
26+
return '';
27+
}
28+
const scaleValue = scale.value / 100.0;
29+
const languageValue = language.value;
30+
31+
let outputValue = '';
32+
processing.value = true;
33+
try {
34+
errored.value = false;
35+
36+
const imageToAsciiArt = new ImageToAsciiArt({
37+
config: {
38+
drawWidth: scaleValue,
39+
drawHeight: scaleValue * 0.4,
40+
},
41+
});
42+
outputValue = translateToLanguage(await imageToAsciiArt.convert(inputBase64Value), languageValue);
43+
imageToAsciiArt.destroy();
44+
}
45+
catch (e) {
46+
errored.value = true;
47+
}
48+
processing.value = false;
49+
50+
return outputValue;
51+
});
52+
53+
async function onFileUploaded(uploadedFile: File) {
54+
inputBase64.value = await toBase64(uploadedFile);
55+
}
56+
</script>
57+
58+
<template>
59+
<c-card style="max-width: 600px;">
60+
<div style="flex: 0 0 100%">
61+
<div mx-auto max-w-600px>
62+
<c-file-upload
63+
title="Drag and drop a Image file here, or click to select a file"
64+
paste-image
65+
@file-upload="onFileUploaded"
66+
/>
67+
</div>
68+
</div>
69+
70+
<n-form-item label="Output scale" label-placement="left" mt-2>
71+
<n-slider v-model:value="scale" :step="1" :min="1" :max="100" mr-2 />
72+
<n-input-number v-model:value="scale" size="small" :min="1" :max="100" />
73+
</n-form-item>
74+
75+
<c-select v-model:value="language" :options="languagesOptions" searchable mt-3 />
76+
77+
<n-divider />
78+
79+
<div v-if="processing" flex items-center justify-center>
80+
<n-spin size="medium" />
81+
<span class="ml-2">Processing...</span>
82+
</div>
83+
84+
<c-alert v-if="errored" mt-1 text-center type="error">
85+
Current settings resulted in error.
86+
</c-alert>
87+
88+
<n-form-item v-if="!processing && !errored" label="Ascii Art text:">
89+
<TextareaCopyable
90+
:value="output"
91+
mb-1 mt-1
92+
copy-placement="outside"
93+
/>
94+
</n-form-item>
95+
</c-card>
96+
</template>
97+
98+
<style lang="less">
99+
.n-code pre {
100+
font-size: 0.2em !important;
101+
}
102+
</style>

src/tools/image-to-ascii-art/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Artboard } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'Image to ASCII Art',
6+
path: '/image-to-ascii-art',
7+
description: 'Image to ASCII Art Generator',
8+
keywords: ['image', 'ascii', 'art'],
9+
component: () => import('./image-to-ascii-art.vue'),
10+
icon: Artboard,
11+
createdAt: new Date('2024-03-15'),
12+
});

src/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ import { tool as ecdsaKeyPairGenerator } from './ecdsa-key-pair-generator';
116116
import { tool as ed25519KeyPairGenerator } from './ed25519-key-pair-generator';
117117
import { tool as fileType } from './file-type';
118118
import { tool as htmlCleaner } from './html-cleaner';
119+
import { tool as imageToAsciiArt } from './image-to-ascii-art';
119120
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
120121
import { tool as numeronymGenerator } from './numeronym-generator';
121122
import { tool as macAddressGenerator } from './mac-address-generator';
@@ -347,6 +348,7 @@ export const toolsByCategory: ToolCategory[] = [
347348
svgPlaceholderGenerator,
348349
cameraRecorder,
349350
removeExif,
351+
imageToAsciiArt,
350352
],
351353
},
352354
{

0 commit comments

Comments
 (0)