From 1df6d8eec961334b19a0c8edbebf64e642dbdc2c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:45:00 +0000 Subject: [PATCH 1/3] feat: add ImageToDataUrl tool - Add `src/pages/ImageToDataUrl.jsx` to convert images to Base64 or URL-encoded Data URLs. - Update `src/routes.jsx` to include the new tool in the navigation. - Tool supports PNG, JPG, GIF, WEBP, SVG. - Provides URL-encoded option specifically for SVGs as requested. - Shows image preview and file info. - Warns if image size exceeds 200KB. Co-authored-by: sabeerbikba <59386700+sabeerbikba@users.noreply.github.com> --- src/pages/ImageToDataUrl.jsx | 247 +++++++++++++++++++++++++++++++++++ src/routes.jsx | 12 ++ 2 files changed, 259 insertions(+) create mode 100644 src/pages/ImageToDataUrl.jsx diff --git a/src/pages/ImageToDataUrl.jsx b/src/pages/ImageToDataUrl.jsx new file mode 100644 index 0000000..c73bc9f --- /dev/null +++ b/src/pages/ImageToDataUrl.jsx @@ -0,0 +1,247 @@ +import { useState, useRef } from "react"; +import { toast } from "react-toastify"; +import ToolBoxLayout from "@/common/ToolBoxLayout"; +import ToolBox from "@/common/ToolBox"; +import Btn from "@/common/BasicBtn"; +import CopyBtn from "@/common/CopyBtn"; +import cn from "@/utils/cn"; + +const ImageToDataUrl = () => { + const [file, setFile] = useState(null); + const [previewUrl, setPreviewUrl] = useState(""); + const [dataUrl, setDataUrl] = useState(""); + const [svgUrlEncoded, setSvgUrlEncoded] = useState(""); + const [outputType, setOutputType] = useState("base64"); // 'base64' or 'url-encoded' + // const [isProcessing, setIsProcessing] = useState(false); // Unused for now as operations are fast enough or async handled simply + + const fileInputRef = useRef(null); + + // Constants + const RECOMMENDED_SIZE_BYTES = 200 * 1024; // 200KB + const SUPPORTED_TYPES = [ + "image/png", + "image/jpeg", + "image/jpg", + "image/gif", + "image/webp", + "image/svg+xml", + ]; + + const handleFileChange = (e) => { + const selectedFile = e.target.files[0]; + if (selectedFile) { + processFile(selectedFile); + } + }; + + const processFile = (selectedFile) => { + if (!SUPPORTED_TYPES.includes(selectedFile.type)) { + toast.error( + "Unsupported file type. Please select PNG, JPG, GIF, WEBP, or SVG." + ); + return; + } + + // setIsProcessing(true); + setFile(selectedFile); + + // Create preview URL + if (previewUrl) { + URL.revokeObjectURL(previewUrl); + } + const objectUrl = URL.createObjectURL(selectedFile); + setPreviewUrl(objectUrl); + + // Reset output + setDataUrl(""); + setSvgUrlEncoded(""); + setOutputType("base64"); + + // Base64 Reader + const reader = new FileReader(); + reader.onload = () => { + setDataUrl(reader.result); + // setIsProcessing(false); + }; + reader.onerror = () => { + toast.error("Error reading file."); + // setIsProcessing(false); + }; + reader.readAsDataURL(selectedFile); + + // SVG URL Encoded Reader + if (selectedFile.type === "image/svg+xml") { + const textReader = new FileReader(); + textReader.onload = () => { + const content = textReader.result; + // Basic URL encoding for SVG data URI + // Using encodeURIComponent but ensuring quotes are safer + const encoded = + "data:image/svg+xml," + + encodeURIComponent(content) + .replace(/'/g, "%27") + .replace(/"/g, "%22"); + setSvgUrlEncoded(encoded); + }; + textReader.readAsText(selectedFile); + } + }; + + const handleClear = () => { + setFile(null); + if (previewUrl) { + URL.revokeObjectURL(previewUrl); + } + setPreviewUrl(""); + setDataUrl(""); + setSvgUrlEncoded(""); + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + }; + + const formatFileSize = (bytes) => { + if (bytes === 0) return "0 Bytes"; + const k = 1024; + const sizes = ["Bytes", "KB", "MB", "GB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; + }; + + const isLargeFile = file && file.size > RECOMMENDED_SIZE_BYTES; + const isSvg = file && file.type === "image/svg+xml"; + + const currentOutput = + outputType === "url-encoded" && isSvg ? svgUrlEncoded : dataUrl; + + return ( + + +
+
+ +
+

+ Supported formats: PNG, JPG, GIF, WEBP, SVG +

+

+ Recommended size: < 200KB +

+ fileInputRef.current?.click()} + classNames="!w-40" + /> +
+
+ + {file && ( +
+
+ {previewUrl && ( + Preview + )} +
+ +
+

Image Info

+
+
Name:
+
{file.name}
+ +
Size:
+
+ {formatFileSize(file.size)} +
+ +
Type:
+
{file.type}
+
+ + {isLargeFile && ( +
+ Warning: Image is larger than recommended (200KB). Data URLs can significantly increase file size and affect page load performance. +
+ )} + + +
+
+ )} +
+
+ + +
+ {file ? ( + <> + {isSvg && ( +
+ + +
+ )} + +
+