This commit is contained in:
star7th
2025-04-16 22:47:19 +08:00
parent c783e67a0e
commit 8decc5bf1d
8 changed files with 709 additions and 3 deletions
+577
View File
@@ -0,0 +1,577 @@
'use client';
import React, { useState, useEffect, useRef, ChangeEvent } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faDownload, faTrash, faImage, faCopy, faCheck, faExchangeAlt, faUpload } from '@fortawesome/free-solid-svg-icons';
import ToolHeader from '@/components/ToolHeader';
import { useLanguage } from '@/context/LanguageContext';
import tools from '@/config/tools';
import BackToTop from '@/components/BackToTop';
// 添加CSS变量样式
const styles = {
container: "min-h-screen flex flex-col max-w-[1440px] mx-auto p-4 md:p-6",
card: "card p-6 mb-6",
inputLabel: "block text-secondary text-sm font-bold mb-2",
heading: "text-lg font-semibold mb-2 text-primary",
textArea: "search-input w-full h-56 font-mono text-sm",
switchBtn: "btn-secondary flex items-center justify-center my-4 mx-auto",
imageContainer: "bg-block rounded-lg p-4 min-h-64 flex items-center justify-center border border-purple-glow/15 mt-4",
image: "max-w-full max-h-96 object-contain",
placeholder: "text-tertiary",
actionBtn: "w-full",
actionBtnDisabled: "btn-secondary opacity-50 cursor-not-allowed w-full",
errorMsg: "mt-2 text-red-500 text-sm",
successMsg: "mt-2 text-green-500 text-sm",
copyBtn: "btn-secondary text-sm py-1 px-3 flex items-center",
fileUploadBtn: "btn-primary flex items-center justify-center cursor-pointer",
fileName: "ml-3 text-secondary text-sm",
tabs: "flex mb-6 border-b border-purple-glow/20",
tab: "py-2 px-4 cursor-pointer text-secondary border-b-2 border-transparent",
activeTab: "py-2 px-4 text-primary border-b-2 border-primary font-medium",
};
// 转换模式类型
type ConversionMode = 'base64_to_image' | 'image_to_base64';
export default function Base64ImageConverter() {
const { t } = useLanguage();
// 从工具配置中获取当前工具图标
const toolIcon = tools.find(tool => tool.code === 'base64_to_image')?.icon || faImage;
// 状态管理
const [conversionMode, setConversionMode] = useState<ConversionMode>('base64_to_image');
// Base64转图片状态
const [base64Input, setBase64Input] = useState('');
const [imageOutput, setImageOutput] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [mimeType, setMimeType] = useState<string>('');
const [fileName, setFileName] = useState<string>('image');
const [copied, setCopied] = useState(false);
// 图片转Base64状态
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
const [uploadedImage, setUploadedImage] = useState<string | null>(null);
const [base64Output, setBase64Output] = useState<string>('');
const [rawBase64Output, setRawBase64Output] = useState<string>('');
const [outputWithPrefix, setOutputWithPrefix] = useState<boolean>(true);
const [uploadError, setUploadError] = useState<string | null>(null);
const [uploadSuccess, setUploadSuccess] = useState<string | null>(null);
const [base64Copied, setBase64Copied] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
// 当Base64输入变化时处理转换(Base64转图片)
useEffect(() => {
if (conversionMode !== 'base64_to_image' || !base64Input.trim()) {
setImageOutput(null);
setError(null);
setMimeType('');
return;
}
try {
// 清除可能的数据URL前缀
const processedInput = base64Input.trim();
// 检查是否已经是完整的数据URL
if (processedInput.startsWith('data:')) {
// 从数据URL中提取MIME类型
const mimeMatch = processedInput.match(/^data:([^;]+);base64,/);
if (mimeMatch) {
setMimeType(mimeMatch[1]);
// 使用完整的数据URL
setImageOutput(processedInput);
setError(null);
// 根据MIME类型设置合适的文件扩展名
updateFileNameFromMimeType(mimeMatch[1]);
} else {
throw new Error(t('tools.base64_to_image.invalid_data_url'));
}
} else {
// 假设这是原始Base64,需要添加数据URL前缀
// 尝试推断MIME类型或使用默认值
const inferredMimeType = inferMimeTypeFromBase64(processedInput);
setMimeType(inferredMimeType);
// 创建完整的数据URL
const dataUrl = `data:${inferredMimeType};base64,${processedInput}`;
setImageOutput(dataUrl);
setError(null);
// 根据MIME类型设置合适的文件扩展名
updateFileNameFromMimeType(inferredMimeType);
}
} catch (err) {
console.error('Error processing base64:', err);
setError((err as Error).message || t('tools.base64_to_image.processing_error'));
setImageOutput(null);
}
}, [base64Input, conversionMode, t]);
// 从Base64数据推断MIME类型的简单逻辑
const inferMimeTypeFromBase64 = (base64String: string): string => {
// 默认为PNG
let mimeType = 'image/png';
// 检查前几个字符以尝试推断类型
// 注意:这是一个非常简化的版本,实际生产中可能需要更复杂的逻辑
const firstChars = base64String.substring(0, 4);
if (firstChars.startsWith('/9j/')) {
mimeType = 'image/jpeg';
} else if (firstChars.startsWith('iVBO') || firstChars.startsWith('IVBO')) {
mimeType = 'image/png';
} else if (firstChars.startsWith('R0lG')) {
mimeType = 'image/gif';
} else if (firstChars.startsWith('UE5H')) {
mimeType = 'image/png';
} else if (firstChars.startsWith('Qk0=')) {
mimeType = 'image/bmp';
} else if (firstChars.startsWith('PHN2')) {
mimeType = 'image/svg+xml';
} else if (firstChars.startsWith('AAAA')) {
mimeType = 'image/webp';
}
return mimeType;
};
// 根据MIME类型更新文件名的扩展名
const updateFileNameFromMimeType = (mime: string) => {
let extension = 'png'; // 默认扩展名
// 根据MIME类型设置扩展名
if (mime === 'image/jpeg' || mime === 'image/jpg') {
extension = 'jpg';
} else if (mime === 'image/png') {
extension = 'png';
} else if (mime === 'image/gif') {
extension = 'gif';
} else if (mime === 'image/bmp') {
extension = 'bmp';
} else if (mime === 'image/svg+xml') {
extension = 'svg';
} else if (mime === 'image/webp') {
extension = 'webp';
}
setFileName(`image.${extension}`);
};
// 清空输入和输出(Base64转图片)
const clearBase64ToImage = () => {
setBase64Input('');
setImageOutput(null);
setError(null);
setMimeType('');
setFileName('image');
};
// 清空输入和输出(图片转Base64)
const clearImageToBase64 = () => {
setUploadedFile(null);
setUploadedImage(null);
setBase64Output('');
setRawBase64Output('');
setUploadError(null);
setUploadSuccess(null);
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
// 下载图片
const downloadImage = () => {
if (!imageOutput) return;
const link = document.createElement('a');
link.href = imageOutput;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
// 加载示例Base64
const loadExample = () => {
// 一个简单的彩色渐变PNG图像的Base64
const exampleBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TtSIVByuIOGSoThZERRylikWwUNoKrTqYXPohNGlIUlwcBdeCgx+LVQcXZ10dXAVB8APE1cVJ0UVK/F9SaBHjwXE/3t173L0DhGaVqWbPOKBqlpFOxMVcflUMvCKIEMKIISgxU5+TZRm4jq97+Ph6F+NZ3uf+HANKwWSATySeY7phEW8QT29aOud94ggrSQrxOfGYQRckfuS67PIb55LDAs8MGZnUPHGEWCx1sdzFrGKoxFPEUUXVKN+fc1nhvMVZrdZZ+578hcGCtpLhOs1RJLCEJFIQIaOOCqqwEKNVI8VEmvbjHv4Rx58il0yuChg5FlCDCsnxg//B727N0uSEmxROAH0vtv0xAoR2gVbDtr+Pbbt1AgSegSut499oAjOfpDc6WuwIGNwGLq47mrIHXO4AQ0+GbMqO5KcpFIvA+xl9Uw4YuAUCa25vzX2cPgBpamX5Nxg4AiJlyl73eHdPd2//nmn39wNZjHKYJHtTZAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+cMEwwTIg9nvK0AAACbSURBVHja7dAxAQAgDMAwwL/n8SSBJ2uGLdite3YEhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEIYQhhCGEH8tC+O6BRrHuUAeAAAAAElFTkSuQmCC';
setBase64Input(exampleBase64);
};
// 复制现有Base64到剪贴板(Base64转图片)
const copyBase64 = () => {
if (!base64Input) return;
navigator.clipboard.writeText(base64Input)
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch(err => {
console.error('Failed to copy:', err);
setError(t('tools.base64_to_image.copy_failed'));
});
};
// 复制生成的Base64到剪贴板(图片转Base64
const copyGeneratedBase64 = () => {
if (!base64Output) return;
navigator.clipboard.writeText(base64Output)
.then(() => {
setBase64Copied(true);
setTimeout(() => setBase64Copied(false), 2000);
})
.catch(err => {
console.error('Failed to copy:', err);
setUploadError(t('tools.base64_to_image.copy_failed'));
});
};
// 切换转换模式
const toggleConversionMode = () => {
setConversionMode(prevMode =>
prevMode === 'base64_to_image' ? 'image_to_base64' : 'base64_to_image'
);
// 清空各自的状态
clearBase64ToImage();
clearImageToBase64();
};
// 处理文件上传(图片转Base64)
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
// 检查文件类型
if (!file.type.startsWith('image/')) {
setUploadError(t('tools.base64_to_image.invalid_image_file'));
return;
}
// 检查文件大小(限制为10MB
if (file.size > 10 * 1024 * 1024) {
setUploadError(t('tools.base64_to_image.file_too_large'));
return;
}
setUploadedFile(file);
setUploadError(null);
// 读取并显示图片预览
const reader = new FileReader();
reader.onload = (e) => {
const result = e.target?.result as string;
setUploadedImage(result);
// 提取Base64部分
const base64WithPrefix = result;
const base64Raw = result.split(',')[1];
setRawBase64Output(base64Raw);
setBase64Output(outputWithPrefix ? base64WithPrefix : base64Raw);
setUploadSuccess(t('tools.base64_to_image.conversion_success'));
};
reader.onerror = () => {
setUploadError(t('tools.base64_to_image.file_reading_error'));
};
reader.readAsDataURL(file);
};
// 切换输出格式(是否包含前缀)
const toggleOutputFormat = () => {
setOutputWithPrefix(!outputWithPrefix);
setBase64Output(outputWithPrefix ? rawBase64Output : (uploadedImage || ''));
};
// 保存Base64内容为文本文件
const saveBase64AsTextFile = () => {
if (!base64Output) return;
const blob = new Blob([base64Output], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = uploadedFile ? `${uploadedFile.name}.txt` : 'base64_data.txt';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
return (
<div className={styles.container}>
{/* 工具标题 */}
<ToolHeader
icon={toolIcon}
toolCode="base64_to_image"
title=""
description=""
/>
{/* 切换按钮 */}
<button
className={styles.switchBtn}
onClick={toggleConversionMode}
>
<FontAwesomeIcon icon={faExchangeAlt} className="mr-2 icon" />
{conversionMode === 'base64_to_image'
? t('tools.base64_to_image.switch_to_image_to_base64')
: t('tools.base64_to_image.switch_to_base64_to_image')
}
</button>
{/* 选项卡 */}
<div className={styles.tabs}>
<div
className={conversionMode === 'base64_to_image' ? styles.activeTab : styles.tab}
onClick={() => setConversionMode('base64_to_image')}
>
{t('tools.base64_to_image.base64_to_image_tab')}
</div>
<div
className={conversionMode === 'image_to_base64' ? styles.activeTab : styles.tab}
onClick={() => setConversionMode('image_to_base64')}
>
{t('tools.base64_to_image.image_to_base64_tab')}
</div>
</div>
{/* Base64转图片 */}
{conversionMode === 'base64_to_image' && (
<div className="flex flex-col lg:flex-row gap-6">
{/* 输入区域 */}
<div className="w-full lg:w-1/2">
<div className={styles.card}>
<h2 className={styles.heading}>{t('tools.base64_to_image.input_title')}</h2>
<label className={styles.inputLabel}>{t('tools.base64_to_image.base64_input')}</label>
<textarea
className={styles.textArea}
value={base64Input}
onChange={(e) => setBase64Input(e.target.value)}
placeholder={t('tools.base64_to_image.input_placeholder')}
spellCheck="false"
/>
{error && <div className={styles.errorMsg}>{error}</div>}
<div className="flex items-center justify-between mt-4">
<button
onClick={loadExample}
className="btn-secondary"
>
{t('tools.base64_to_image.load_example')}
</button>
<button
onClick={copyBase64}
disabled={!base64Input}
className={!base64Input ? styles.actionBtnDisabled : "btn-secondary"}
>
<FontAwesomeIcon icon={copied ? faCheck : faCopy} className="mr-2 icon" />
{copied ? t('common.copySuccess') : t('tools.base64_to_image.copy')}
</button>
<button
onClick={clearBase64ToImage}
className="btn-secondary"
>
<FontAwesomeIcon icon={faTrash} className="mr-2 icon" />
{t('tools.base64_to_image.clear_all')}
</button>
</div>
</div>
</div>
{/* 输出区域 */}
<div className="w-full lg:w-1/2">
<div className={styles.card}>
<h2 className={styles.heading}>{t('tools.base64_to_image.output_title')}</h2>
<div className={styles.imageContainer}>
{imageOutput ? (
<img
src={imageOutput}
alt={t('tools.base64_to_image.converted_image')}
className={styles.image}
/>
) : (
<div className={styles.placeholder}>
{t('tools.base64_to_image.no_image')}
</div>
)}
</div>
{imageOutput && (
<div className="mt-4">
<div className="flex justify-between items-center mb-2">
<span className="text-secondary text-sm">{t('tools.base64_to_image.image_type')}: {mimeType}</span>
<input
type="text"
className="search-input w-48"
value={fileName}
onChange={(e) => setFileName(e.target.value)}
placeholder={t('tools.base64_to_image.file_name')}
/>
</div>
<button
onClick={downloadImage}
className="btn-primary w-full"
disabled={!imageOutput}
>
<FontAwesomeIcon icon={faDownload} className="mr-2 icon" />
{t('tools.base64_to_image.download_image')}
</button>
</div>
)}
</div>
</div>
</div>
)}
{/* 图片转Base64 */}
{conversionMode === 'image_to_base64' && (
<div className="flex flex-col lg:flex-row gap-6">
{/* 输入区域 */}
<div className="w-full lg:w-1/2">
<div className={styles.card}>
<h2 className={styles.heading}>{t('tools.base64_to_image.image_input_title')}</h2>
<div className="mb-6">
<label className={styles.inputLabel}>
{t('tools.base64_to_image.select_image')}
</label>
<div className="flex items-center">
<label className={styles.fileUploadBtn}>
<FontAwesomeIcon icon={faUpload} className="mr-2 icon" />
{t('tools.base64_to_image.choose_file')}
<input
type="file"
className="hidden"
accept="image/*"
onChange={handleFileChange}
ref={fileInputRef}
/>
</label>
{uploadedFile && (
<span className={styles.fileName}>{uploadedFile.name}</span>
)}
</div>
</div>
{uploadError && <div className={styles.errorMsg}>{uploadError}</div>}
{uploadSuccess && <div className={styles.successMsg}>{uploadSuccess}</div>}
<div className={styles.imageContainer}>
{uploadedImage ? (
<img
src={uploadedImage}
alt={t('tools.base64_to_image.uploaded_image')}
className={styles.image}
/>
) : (
<div className={styles.placeholder}>
{t('tools.base64_to_image.no_uploaded_image')}
</div>
)}
</div>
<div className="flex items-center justify-end mt-4">
<button
onClick={clearImageToBase64}
className="btn-secondary"
disabled={!uploadedFile}
>
<FontAwesomeIcon icon={faTrash} className="mr-2 icon" />
{t('tools.base64_to_image.clear_all')}
</button>
</div>
</div>
</div>
{/* 输出区域 */}
<div className="w-full lg:w-1/2">
<div className={styles.card}>
<h2 className={styles.heading}>{t('tools.base64_to_image.base64_output_title')}</h2>
<div className="flex items-center mb-4">
<input
type="checkbox"
id="includePrefix"
checked={outputWithPrefix}
onChange={toggleOutputFormat}
className="mr-2 accent-[rgb(var(--color-primary))] w-4 h-4"
/>
<label htmlFor="includePrefix" className="text-secondary text-sm">
{t('tools.base64_to_image.include_prefix')}
</label>
</div>
<textarea
className={styles.textArea}
value={base64Output}
readOnly
placeholder={t('tools.base64_to_image.output_placeholder')}
spellCheck="false"
/>
{uploadedFile && base64Output && (
<div className="flex items-center justify-between mt-4">
<button
onClick={copyGeneratedBase64}
className="btn-secondary"
>
<FontAwesomeIcon icon={base64Copied ? faCheck : faCopy} className="mr-2 icon" />
{base64Copied ? t('common.copySuccess') : t('tools.base64_to_image.copy_base64')}
</button>
<button
onClick={saveBase64AsTextFile}
className="btn-primary"
>
<FontAwesomeIcon icon={faDownload} className="mr-2 icon" />
{t('tools.base64_to_image.save_as_text')}
</button>
</div>
)}
</div>
</div>
</div>
)}
{/* 使用说明 */}
<div className="card p-4 mb-6 mt-6">
<h3 className="text-md font-medium text-primary mb-2">{t('tools.base64_to_image.usage_guide')}</h3>
<ul className="list-disc list-inside text-sm space-y-1 text-tertiary">
{conversionMode === 'base64_to_image' ? (
<>
<li>{t('tools.base64_to_image.guide_1')}</li>
<li>{t('tools.base64_to_image.guide_2')}</li>
<li>{t('tools.base64_to_image.guide_3')}</li>
<li>{t('tools.base64_to_image.guide_4')}</li>
</>
) : (
<>
<li>{t('tools.base64_to_image.guide_5')}</li>
<li>{t('tools.base64_to_image.guide_6')}</li>
<li>{t('tools.base64_to_image.guide_7')}</li>
<li>{t('tools.base64_to_image.guide_8')}</li>
</>
)}
</ul>
</div>
{/* 回到顶部按钮 */}
<BackToTop />
</div>
);
}
+2 -1
View File
@@ -27,7 +27,8 @@ export const en = {
unicode_converter: tools.unicode_converter.en,
url_encoder: tools.url_encoder.en,
number_base_converter: tools.number_base_converter.en,
yml_properties_converter: tools.yml_properties_converter.en
yml_properties_converter: tools.yml_properties_converter.en,
base64_to_image: tools.base64_to_image.en
}
};
@@ -0,0 +1,55 @@
export const base64ToImageEn = {
title: 'Base64 Image Converter',
description: 'Convert between Base64 string and image',
// Base64 to Image
input_title: 'Input Base64 String',
output_title: 'Image Output',
base64_input: 'Base64 String',
input_placeholder: 'Paste your Base64 encoded image string here...',
load_example: 'Load Example',
clear_all: 'Clear',
copy: 'Copy Base64',
download_image: 'Download Image',
converted_image: 'Converted Image',
no_image: 'No image to display yet. Paste a Base64 string to convert.',
processing_error: 'Error processing Base64 string',
invalid_data_url: 'Invalid data URL format',
invalid_base64: 'Invalid Base64 encoded string',
copy_failed: 'Failed to copy to clipboard',
image_type: 'Image Type',
file_name: 'File Name',
// Image to Base64
image_input_title: 'Input Image',
base64_output_title: 'Base64 Output',
select_image: 'Select Image File',
choose_file: 'Choose File',
uploaded_image: 'Uploaded Image',
no_uploaded_image: 'No image uploaded yet. Select an image file to convert.',
output_placeholder: 'Base64 output will be displayed here...',
include_prefix: 'Include data URL prefix (data:image/type;base64,)',
copy_base64: 'Copy Base64',
save_as_text: 'Save as Text File',
invalid_image_file: 'Invalid image file. Please select a valid image.',
file_too_large: 'File is too large. Maximum size is 10MB.',
file_reading_error: 'Error reading file',
conversion_success: 'Image successfully converted to Base64',
// Tabs and mode switching
base64_to_image_tab: 'Base64 to Image',
image_to_base64_tab: 'Image to Base64',
switch_to_image_to_base64: 'Switch to Image to Base64',
switch_to_base64_to_image: 'Switch to Base64 to Image',
// Guides
usage_guide: 'Usage Guide',
guide_1: 'Paste a Base64 encoded string to convert it to an image',
guide_2: 'Supports both pure Base64 and data URL formats (data:image/png;base64,...)',
guide_3: 'The tool will attempt to detect the image format automatically',
guide_4: 'You can download the converted image with your preferred file name',
guide_5: 'Upload an image file to convert it to Base64 string',
guide_6: 'Choose whether to include the data URL prefix or only the raw Base64 data',
guide_7: 'The generated Base64 can be copied to clipboard or saved as a text file',
guide_8: 'Supported image formats include JPG, PNG, GIF, BMP, WebP, and SVG'
};
@@ -0,0 +1,9 @@
import { base64ToImageEn } from './en';
import { base64ToImageZh } from './zh';
const base64ToImage = {
en: base64ToImageEn,
zh: base64ToImageZh
};
export default base64ToImage;
@@ -0,0 +1,55 @@
export const base64ToImageZh = {
title: 'Base64图片转换器',
description: 'Base64字符串与图片互相转换',
// Base64转图片
input_title: '输入Base64字符串',
output_title: '图片输出',
base64_input: 'Base64字符串',
input_placeholder: '在此粘贴您的Base64编码图片字符串...',
load_example: '加载示例',
clear_all: '清空',
copy: '复制Base64',
download_image: '下载图片',
converted_image: '转换后的图片',
no_image: '暂无图片显示。粘贴Base64字符串进行转换。',
processing_error: '处理Base64字符串时出错',
invalid_data_url: '无效的数据URL格式',
invalid_base64: '无效的Base64编码字符串',
copy_failed: '复制到剪贴板失败',
image_type: '图片类型',
file_name: '文件名',
// 图片转Base64
image_input_title: '输入图片',
base64_output_title: 'Base64输出',
select_image: '选择图片文件',
choose_file: '选择文件',
uploaded_image: '已上传图片',
no_uploaded_image: '暂无已上传图片。选择图片文件进行转换。',
output_placeholder: 'Base64输出将显示在这里...',
include_prefix: '包含数据URL前缀(data:image/type;base64,',
copy_base64: '复制Base64',
save_as_text: '保存为文本文件',
invalid_image_file: '无效的图片文件。请选择有效的图片。',
file_too_large: '文件太大。最大大小为10MB。',
file_reading_error: '读取文件出错',
conversion_success: '图片已成功转换为Base64',
// 选项卡和模式切换
base64_to_image_tab: 'Base64转图片',
image_to_base64_tab: '图片转Base64',
switch_to_image_to_base64: '切换到图片转Base64',
switch_to_base64_to_image: '切换到Base64转图片',
// 使用指南
usage_guide: '使用指南',
guide_1: '粘贴Base64编码字符串将其转换为图片',
guide_2: '支持纯Base64和数据URL格式(data:image/png;base64,...',
guide_3: '工具会自动尝试检测图片格式',
guide_4: '可以使用您喜欢的文件名下载转换后的图片',
guide_5: '上传图片文件将其转换为Base64字符串',
guide_6: '选择是否包含数据URL前缀或仅保留原始Base64数据',
guide_7: '生成的Base64可以复制到剪贴板或保存为文本文件',
guide_8: '支持的图片格式包括JPG、PNG、GIF、BMP、WebP和SVG'
};
+3 -1
View File
@@ -22,6 +22,7 @@ import unicodeConverter from './unicode_converter';
import urlEncoder from './url_encoder';
import numberBaseConverter from './number_base_converter';
import ymlPropertiesConverter from './yml_properties_converter';
import base64ToImage from './base64_to_image';
export const tools = {
json_formatter: jsonFormatter,
@@ -47,7 +48,8 @@ export const tools = {
unicode_converter: unicodeConverter,
url_encoder: urlEncoder,
number_base_converter: numberBaseConverter,
yml_properties_converter: ymlPropertiesConverter
yml_properties_converter: ymlPropertiesConverter,
base64_to_image: base64ToImage
};
export default tools;
+2 -1
View File
@@ -27,7 +27,8 @@ export const zh = {
unicode_converter: tools.unicode_converter.zh,
url_encoder: tools.url_encoder.zh,
number_base_converter: tools.number_base_converter.zh,
yml_properties_converter: tools.yml_properties_converter.zh
yml_properties_converter: tools.yml_properties_converter.zh,
base64_to_image: tools.base64_to_image.zh
}
};
+6
View File
@@ -153,6 +153,12 @@ const tools: Tool[] = [
icon: faFileAlt,
category: ['code'],
keywords: ['yml', 'yaml', 'properties', 'yml转properties', 'properties转yml', '配置文件', '转换工具', 'yml互转properties', 'yaml互转properties', '配置转换', 'peizhi', 'pz', 'zhuanhuan', 'zh']
},
{
code: 'base64_to_image',
icon: faImage,
category: ['image', 'encoding'],
keywords: ['base64', 'base64转图片', '图片转base64', '图片', '解码', '编码', '转换', 'base64 to image', 'image to base64', 'image decoder', 'image encoder', 'tupian', 'tp', 'jm', 'bm', 'zhuanhuan', 'zh', 'base64转换']
}
] as Tool[];