212 lines
6.9 KiB
HTML
212 lines
6.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>图片转PDF</title>
|
||
<style>
|
||
body {
|
||
font-family: Arial, sans-serif;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 20px;
|
||
margin: 0;
|
||
background-color: #f4f4f4;
|
||
}
|
||
h1 {
|
||
font-size: 2.5vw;
|
||
margin-bottom: 20px;
|
||
color: #333;
|
||
}
|
||
#image-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 15px;
|
||
justify-content: center;
|
||
margin: 20px 0;
|
||
padding: 10px;
|
||
border: 2px dashed #ccc;
|
||
background-color: #fff;
|
||
min-height: 100px;
|
||
width: 100%;
|
||
max-width: 1200px;
|
||
}
|
||
.image-item {
|
||
position: relative;
|
||
border: 1px solid #ccc;
|
||
overflow: hidden;
|
||
transition: transform 0.2s;
|
||
cursor: move; /* 提示用户可以拖拽 */
|
||
}
|
||
.image-item:hover {
|
||
transform: scale(1.05);
|
||
}
|
||
.image-item img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
.delete-btn {
|
||
position: absolute;
|
||
top: 5px;
|
||
right: 5px;
|
||
background-color: rgb(0, 0, 0);
|
||
opacity: 0.5;
|
||
color: white;
|
||
margin: 0;
|
||
border: none;
|
||
border-radius: 50%;
|
||
width: 20px;
|
||
height: 20px;
|
||
padding: 0;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
button {
|
||
padding: 10px 20px;
|
||
font-size: 16px;
|
||
background-color: #007BFF;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
margin-top: 20px;
|
||
}
|
||
button:hover {
|
||
background-color: #0056b3;
|
||
}
|
||
@media (max-width: 600px) {
|
||
h1 {
|
||
font-size: 5vw;
|
||
}
|
||
button {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>图片转PDF</h1>
|
||
<input type="file" id="file-input" multiple accept="image/*">
|
||
<div id="image-container"></div>
|
||
<button id="generate-pdf">生成PDF</button>
|
||
|
||
<!-- 引入外部库 -->
|
||
<script src="../../../libs/Sortable.min.js"></script>
|
||
<script src="../../../libs/pdf-lib.min.js"></script>
|
||
<script>
|
||
const fileInput = document.getElementById('file-input');
|
||
const imageContainer = document.getElementById('image-container');
|
||
const generateButton = document.getElementById('generate-pdf');
|
||
let images = [];
|
||
|
||
// 文件选择事件
|
||
fileInput.addEventListener('change', (e) => {
|
||
handleFiles(e.target.files);
|
||
});
|
||
|
||
// 生成PDF
|
||
generateButton.addEventListener('click', async () => {
|
||
if (images.length === 0) {
|
||
alert('请先添加至少一张图片!');
|
||
return;
|
||
}
|
||
const pdfDoc = await PDFLib.PDFDocument.create();
|
||
for (const image of images) {
|
||
const imgBytes = await fetch(image.src).then(res => res.arrayBuffer());
|
||
let img = image.file.type === 'image/png' ?
|
||
await pdfDoc.embedPng(imgBytes) :
|
||
await pdfDoc.embedJpg(imgBytes);
|
||
const page = pdfDoc.addPage([img.width, img.height]);
|
||
page.drawImage(img, { x: 0, y: 0, width: img.width, height: img.height });
|
||
}
|
||
const pdfBytes = await pdfDoc.save();
|
||
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = '图片合集.pdf';
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
});
|
||
|
||
// 处理文件
|
||
function handleFiles(files) {
|
||
Array.from(files).forEach(file => {
|
||
if (file.type.startsWith('image/')) {
|
||
const reader = new FileReader();
|
||
reader.onload = function(e) {
|
||
const imgWrapper = document.createElement('div');
|
||
imgWrapper.classList.add('image-item');
|
||
|
||
const img = document.createElement('img');
|
||
img.src = e.target.result;
|
||
|
||
const deleteBtn = document.createElement('button');
|
||
deleteBtn.classList.add('delete-btn');
|
||
deleteBtn.innerHTML = '×';
|
||
deleteBtn.addEventListener('click', () => {
|
||
imgWrapper.remove();
|
||
images = images.filter(item => item.src !== img.src);
|
||
});
|
||
|
||
imgWrapper.appendChild(img);
|
||
imgWrapper.appendChild(deleteBtn);
|
||
imageContainer.appendChild(imgWrapper);
|
||
images.push({ src: e.target.result, file });
|
||
|
||
setImageSize();
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 获取视口宽度
|
||
function getViewportWidth() {
|
||
return window.innerWidth || document.documentElement.clientWidth;
|
||
}
|
||
|
||
// 设置图片尺寸
|
||
function setImageSize() {
|
||
const viewportWidth = getViewportWidth();
|
||
const imageItems = document.querySelectorAll('.image-item');
|
||
let size = viewportWidth >= 1200 ? 150 : viewportWidth >= 600 ? 100 : 80;
|
||
imageItems.forEach(item => {
|
||
item.style.width = `${size}px`;
|
||
item.style.height = `${size}px`;
|
||
});
|
||
}
|
||
|
||
// 监听窗口resize事件
|
||
window.addEventListener('resize', setImageSize);
|
||
setImageSize();
|
||
|
||
// 拖拽导入支持
|
||
imageContainer.addEventListener('dragover', (e) => {
|
||
e.preventDefault();
|
||
});
|
||
imageContainer.addEventListener('drop', (e) => {
|
||
e.preventDefault();
|
||
if (e.dataTransfer.files.length > 0) {
|
||
handleFiles(e.dataTransfer.files);
|
||
}
|
||
});
|
||
|
||
// 初始化 Sortable.js 进行拖拽排序
|
||
new Sortable(imageContainer, {
|
||
animation: 150,
|
||
onEnd: function(evt) {
|
||
// 更新 images 数组顺序
|
||
const movedItem = images.splice(evt.oldIndex, 1)[0];
|
||
images.splice(evt.newIndex, 0, movedItem);
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |