小天管理 发表于 2024年9月2日 发表于 2024年9月2日 比如说,我想要个 图片分割并 zip 下载 的功能,但是我又不懂 canvas 也不知道浏览器能不能直接打包 zip 。只要告诉它: 生成一个 image splitter 组件,用户上传一张照片,选择行、列数量,点击按钮,就会自动分割,并打包成 zip 格式自动下载。 就会生成一个功能完整的组件: 'use client' import React, { useState } from 'react'; import JSZip from 'jszip'; import { saveAs } from 'file-saver'; const ImageSplitter = () => { const [image, setImage] = useState<File | null>(null); const [rows, setRows] = useState(3); const [cols, setCols] = useState(3); const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.files && e.target.files[0]) { setImage(e.target.files[0]); } }; const handleSplitImage = async () => { if (!image) return; const img = new Image(); img.src = URL.createObjectURL(image); img.onload = async () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) return; const zip = new JSZip(); const { width, height } = img; const pieceWidth = width / cols; const pieceHeight = height / rows; for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { canvas.width = pieceWidth; canvas.height = pieceHeight; ctx.drawImage( img, c * pieceWidth, r * pieceHeight, pieceWidth, pieceHeight, 0, 0, pieceWidth, pieceHeight ); const dataUrl = canvas.toDataURL('image/png'); const base64Data = dataUrl.split(',')[1]; zip.file(`piece_${r}_${c}.png`, base64Data, { base64: true }); } } const content = await zip.generateAsync({ type: 'blob' }); saveAs(content, 'image_pieces.zip'); }; }; return ( <div className="flex flex-col items-center justify-center p-4"> <div className="bg-white shadow-md rounded-lg p-6 w-full max-w-md"> <label className="block mb-2"> Upload an image: <input type="file" accept="image/*" onChange={handleImageUpload} className="mb-4 w-full p-2 border border-gray-300 rounded" /> </label> <label className="block mb-2"> Enter number of rows: <input type="number" value={rows} onChange={(e) => setRows(parseInt(e.target.value))} min="1" className="mb-4 w-full p-2 border border-gray-300 rounded" /> </label> <label className="block mb-2"> Enter number of columns: <input type="number" value={cols} onChange={(e) => setCols(parseInt(e.target.value))} min="1" className="mb-4 w-full p-2 border border-gray-300 rounded" /> </label> <button onClick={handleSplitImage} className="w-full bg-blue-500 text-white p-2 rounded hover:bg-blue-600 transition" > Split Image </button> </div> </div> ); }; export default ImageSplitter; 当然一开始样式有点丑,我补充了一句:使用 tailwind 优化一下样式,要现代感,柔色调 大体效果就出来了: https://imagesplitter.org/
已推荐帖子