
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片生成器</title>
<!-- 引入Font Awesome图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
body {
font-family: 'Roboto', Arial, sans-serif;
background-color: #f9f9f9;
color: #333;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
h1 {
font-size: 2rem;
margin-bottom: 1rem;
color: #444;
}
p {
font-size: 1rem;
color: #666;
margin-bottom: 2rem;
text-align: center;
}
.container {
width: 100%;
max-width: 500px;
padding: 2rem;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
text-align: center;
}
.custom-file-upload {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 0.8rem;
margin: 0.5rem 0;
border: none;
border-radius: 5px;
font-size: 1rem;
cursor: pointer;
text-align: center;
background-color: #007bff;
color: #fff;
transition: background-color 0.3s ease;
}
.custom-file-upload:hover {
background-color: #0056b3;
}
.custom-file-upload i {
margin-right: 0.5rem;
}
.file-name {
font-size: 0.9rem;
color: #444;
margin-top: 0.5rem;
word-break: break-all;
}
input[type="number"] {
width: 100%;
padding: 0.8rem;
margin: 0.5rem 0;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 1rem;
outline: none;
transition: border-color 0.3s ease;
}
input[type="number"]:hover {
border-color: #aaa;
}
button {
width: 100%;
padding: 0.8rem;
margin-top: 1rem;
background-color: #28a745;
color: #fff;
border: none;
border-radius: 5px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #218838;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.loading {
margin-top: 1rem;
font-size: 1rem;
color: #007bff;
}
.spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 3px solid rgba(0, 123, 255, 0.3);
border-top-color: #007bff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-right: 0.5rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
canvas {
display: none;
}
</style>
</head>
<body>
<div class="container">
<h1><i class="fas fa-image"></i> 图片生成器</h1>
<p>上传一张图片,设置需要生成的图片数量,程序会生成指定数量的图片并打包成ZIP文件下载。</p>
<!-- 自定义文件选择按钮 -->
<button id="uploadButton" class="custom-file-upload">
<i class="fas fa-upload"></i> 选择图片
</button>
<div id="fileName" class="file-name">未选择文件</div>
<!-- 设置生成图片数量 -->
<label for="imageCount"><i class="fas fa-copy"></i> 生成图片数量:</label>
<input type="number" id="imageCount" value="100" min="1">
<!-- 生成按钮 -->
<button id="generateButton" disabled>
<i class="fas fa-download"></i> 生成并下载ZIP
</button>
<!-- 加载动画 -->
<div id="loading" class="loading" style="display: none;">
<span class="spinner"></span> 正在生成,请稍候...
</div>
</div>
<canvas id="canvas"></canvas>
<!-- 引入JSZip库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script>
const uploadButton = document.getElementById('uploadButton');
const generateButton = document.getElementById('generateButton');
const imageCountInput = document.getElementById('imageCount');
const loadingDiv = document.getElementById('loading');
const fileNameDiv = document.getElementById('fileName');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let originalImage = null;
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/jpeg, image/png, image/gif';
fileInput.style.display = 'none';
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
let filePath = file.name;
if ('webkitRelativePath' in file && file.webkitRelativePath) {
filePath = file.webkitRelativePath;
} else if (file.path) {
filePath = file.path;
}
fileNameDiv.textContent = `已选择文件:${filePath}`;
const img = new Image();
img.src = URL.createObjectURL(file);
img.onload = () => {
originalImage = img;
canvas.width = img.width;
canvas.height = img.height;
generateButton.disabled = false;
};
} else {
fileNameDiv.textContent = '未选择文件';
generateButton.disabled = true;
}
});
uploadButton.addEventListener('click', () => {
fileInput.click();
});
generateButton.addEventListener('click', async () => {
const count = parseInt(imageCountInput.value, 10);
if (!originalImage || isNaN(count) || count <= 0) {
alert('请上传一张图片并输入有效的生成数量!');
return;
}
generateButton.disabled = true;
loadingDiv.style.display = 'block';
try {
const zip = new JSZip();
const folder = zip.folder('generated_images');
for (let i = 0; i < count; i++) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(originalImage, 0, 0);
applyRandomModification(ctx, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/png');
const base64Data = dataUrl.split(',')[1];
folder.file(`generated_image_${i + 1}.png`, base64Data, { base64: true });
}
const content = await zip.generateAsync({ type: 'blob' });
const link = document.createElement('a');
link.href = URL.createObjectURL(content);
link.download = 'generated_images.zip';
link.click();
alert(`${count}张图片已生成并打包为ZIP文件,默认保存到您的下载目录!`);
} catch (error) {
console.error('生成失败:', error);
alert('生成失败,请重试!');
} finally {
loadingDiv.style.display = 'none';
generateButton.disabled = false;
}
});
function applyRandomModification(ctx, width, height) {
const randomType = Math.floor(Math.random() * 3);
if (randomType === 0) {
ctx.globalAlpha = Math.random() * 0.5 + 0.5;
} else if (randomType === 1) {
const angle = (Math.random() - 0.5) * 30;
ctx.translate(width / 2, height / 2);
ctx.rotate((angle * Math.PI) / 180);
ctx.translate(-width / 2, -height / 2);
} else if (randomType === 2) {
for (let i = 0; i < 1000; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const color = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0.5)`;
ctx.fillStyle = color;
ctx.fillRect(x, y, 1, 1);
}
}
}
</script>
</body>
</html>