在开发过程中,可能会遇到文件相互转换的需求,比如pdf 转图片等,现在市面上都是一些收费的,比如WPS需要会员才可以实现,也有一些小程序相关的,都是收费的,如何实现本地免费的把pdf转图片的小工具呢,可以直接使用Cursor编程,
可以在COMPOSER中,直接提问:
"你是一个高级开发工程师,请实现一个网页端的把pdf 转成图片的功能页面"
然后它会来帮你实现一个将 PDF 转换为图片的网页工具1这里将使用 pdf.js 库来处理 PDF 文件,并将其渲染为图片。
自动生成的index.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>
<!-- 引入 PDF.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.upload-area {
border: 2px dashed #ddd;
border-radius: 8px;
padding: 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
}
.upload-area:hover {
border-color: #4CAF50;
}
.upload-area.dragover {
background-color: #e8f5e9;
border-color: #4CAF50;
}
.button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin: 10px 0;
}
.button:hover {
background-color: #45a049;
}
.button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.progress {
margin: 20px 0;
display: none;
}
.progress-bar {
height: 20px;
background-color: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background-color: #4CAF50;
width: 0%;
transition: width 0.3s ease;
}
.images-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-top: 20px;
}
.image-item {
position: relative;
border: 1px solid #ddd;
padding: 10px;
border-radius: 4px;
}
.image-item img {
width: 100%;
height: auto;
display: block;
}
.image-item .download-btn {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px 10px;
border-radius: 4px;
text-decoration: none;
font-size: 12px;
}
.status {
margin: 10px 0;
padding: 10px;
border-radius: 4px;
}
.error {
background-color: #ffebee;
color: #c62828;
}
.success {
background-color: #e8f5e9;
color: #2e7d32;
}
</style>
</head>
<body>
<div class="container">
<h1>PDF 转图片工具</h1>
<div class="upload-area" id="dropZone">
<p>将 PDF 文件拖放到此处,或点击选择文件</p>
<input type="file" id="fileInput" accept=".pdf" style="display: none;">
</div>
<div class="status" id="status"></div>
<div class="progress" id="progress">
<p>转换进度:<span id="progressText">0%</span></p>
<div class="progress-bar">
<div class="progress-bar-fill" id="progressBar"></div>
</div>
</div>
<div class="images-container" id="imagesContainer"></div>
</div>
<script>
// 设置 PDF.js 的 worker 路径
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const status = document.getElementById('status');
const progress = document.getElementById('progress');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const imagesContainer = document.getElementById('imagesContainer');
// 处理拖放
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('dragover');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
const file = e.dataTransfer.files[0];
if (file && file.type === 'application/pdf') {
handlePDF(file);
} else {
showStatus('请选择有效的 PDF 文件', 'error');
}
});
// 处理点击上传
dropZone.addEventListener('click', () => {
fileInput.click();
});
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file && file.type === 'application/pdf') {
handlePDF(file);
} else {
showStatus('请选择有效的 PDF 文件', 'error');
}
});
async function handlePDF(file) {
try {
showStatus('正在处理 PDF 文件...', 'success');
progress.style.display = 'block';
imagesContainer.innerHTML = '';
const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
const totalPages = pdf.numPages;
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale: 1.5 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
await page.render({
canvasContext: context,
viewport: viewport
}).promise;
const imageUrl = canvas.toDataURL('image/png');
addImageToContainer(imageUrl, pageNum);
// 更新进度
const percent = Math.round((pageNum / totalPages) * 100);
progressBar.style.width = `${percent}%`;
progressText.textContent = `${percent}%`;
}
showStatus('PDF 转换完成!', 'success');
} catch (error) {
showStatus(`转换失败: ${error.message}`, 'error');
} finally {
progress.style.display = 'none';
}
}
function addImageToContainer(imageUrl, pageNum) {
const div = document.createElement('div');
div.className = 'image-item';
const img = document.createElement('img');
img.src = imageUrl;
const downloadLink = document.createElement('a');
downloadLink.href = imageUrl;
downloadLink.download = `page-${pageNum}.png`;
downloadLink.className = 'download-btn';
downloadLink.textContent = '下载';
div.appendChild(img);
div.appendChild(downloadLink);
imagesContainer.appendChild(div);
}
function showStatus(message, type) {
status.textContent = message;
status.className = `status ${type}`;
}
</script>
</body>
</html>
直接拖拽文件,而且还有进度条,图片网格布局显示,质量也很清晰,如果需要添加更多功能(如批量下载、图片压缩、格式选择等),还可以继续帮你完善。
"添加一个一键打包下载所有图片的功能"
它帮你添加一个一键打包下载所有图片的功能,使用 JSZip 库来实现压缩包下载。
<!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>
<!-- 引入 PDF.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<!-- 引入 JSZip -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.upload-area {
border: 2px dashed #ddd;
border-radius: 8px;
padding: 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
}
.upload-area:hover {
border-color: #4CAF50;
}
.upload-area.dragover {
background-color: #e8f5e9;
border-color: #4CAF50;
}
.button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin: 10px 0;
}
.button:hover {
background-color: #45a049;
}
.button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.progress {
margin: 20px 0;
display: none;
}
.progress-bar {
height: 20px;
background-color: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background-color: #4CAF50;
width: 0%;
transition: width 0.3s ease;
}
.images-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-top: 20px;
}
.image-item {
position: relative;
border: 1px solid #ddd;
padding: 10px;
border-radius: 4px;
}
.image-item img {
width: 100%;
height: auto;
display: block;
}
.image-item .download-btn {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px 10px;
border-radius: 4px;
text-decoration: none;
font-size: 12px;
}
.status {
margin: 10px 0;
padding: 10px;
border-radius: 4px;
}
.error {
background-color: #ffebee;
color: #c62828;
}
.success {
background-color: #e8f5e9;
color: #2e7d32;
}
.download-all-btn {
display: none;
margin: 20px 0;
background-color: #2196F3;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.download-all-btn:hover {
background-color: #1976D2;
}
</style>
</head>
<body>
<div class="container">
<h1>PDF 转图片工具</h1>
<div class="upload-area" id="dropZone">
<p>将 PDF 文件拖放到此处,或点击选择文件</p>
<input type="file" id="fileInput" accept=".pdf" style="display: none;">
</div>
<div class="status" id="status"></div>
<button id="downloadAllBtn" class="download-all-btn">打包下载所有图片</button>
<div class="progress" id="progress">
<p>转换进度:<span id="progressText">0%</span></p>
<div class="progress-bar">
<div class="progress-bar-fill" id="progressBar"></div>
</div>
</div>
<div class="images-container" id="imagesContainer"></div>
</div>
<script>
// 设置 PDF.js 的 worker 路径
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const status = document.getElementById('status');
const progress = document.getElementById('progress');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const imagesContainer = document.getElementById('imagesContainer');
const downloadAllBtn = document.getElementById('downloadAllBtn');
let convertedImages = []; // 存储所有转换后的图片数据
// 处理拖放
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('dragover');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
const file = e.dataTransfer.files[0];
if (file && file.type === 'application/pdf') {
handlePDF(file);
} else {
showStatus('请选择有效的 PDF 文件', 'error');
}
});
// 处理点击上传
dropZone.addEventListener('click', () => {
fileInput.click();
});
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file && file.type === 'application/pdf') {
handlePDF(file);
} else {
showStatus('请选择有效的 PDF 文件', 'error');
}
});
async function handlePDF(file) {
try {
showStatus('正在处理 PDF 文件...', 'success');
progress.style.display = 'block';
imagesContainer.innerHTML = '';
convertedImages = []; // 清空之前的图片数据
downloadAllBtn.style.display = 'none';
const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
const totalPages = pdf.numPages;
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale: 1.5 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
await page.render({
canvasContext: context,
viewport: viewport
}).promise;
const imageUrl = canvas.toDataURL('image/png');
// 存储图片数据
convertedImages.push({
url: imageUrl,
pageNum: pageNum
});
addImageToContainer(imageUrl, pageNum);
// 更新进度
const percent = Math.round((pageNum / totalPages) * 100);
progressBar.style.width = `${percent}%`;
progressText.textContent = `${percent}%`;
}
showStatus('PDF 转换完成!', 'success');
downloadAllBtn.style.display = 'block';
} catch (error) {
showStatus(`转换失败: ${error.message}`, 'error');
} finally {
progress.style.display = 'none';
}
}
// 添加打包下载功能
downloadAllBtn.addEventListener('click', async () => {
try {
showStatus('正在打包图片...', 'success');
const zip = new JSZip();
// 获取原始文件名(不包含扩展名)
const originalFileName = fileInput.files[0]?.name.replace('.pdf', '') || 'pdf-images';
// 添加所有图片到压缩包
convertedImages.forEach(({url, pageNum}) => {
// 将 base64 图片数据转换为二进制
const imageData = url.split(',')[1];
zip.file(`${originalFileName}-page-${pageNum}.png`, imageData, {base64: true});
});
// 生成压缩包
const content = await zip.generateAsync({type: 'blob'});
// 创建下载链接
const downloadUrl = URL.createObjectURL(content);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = `${originalFileName}-images.zip`;
// 触发下载
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 清理
URL.revokeObjectURL(downloadUrl);
showStatus('打包下载完成!', 'success');
} catch (error) {
showStatus(`打包失败: ${error.message}`, 'error');
}
});
function addImageToContainer(imageUrl, pageNum) {
const div = document.createElement('div');
div.className = 'image-item';
const img = document.createElement('img');
img.src = imageUrl;
const downloadLink = document.createElement('a');
downloadLink.href = imageUrl;
downloadLink.download = `page-${pageNum}.png`;
downloadLink.className = 'download-btn';
downloadLink.textContent = '下载';
div.appendChild(img);
div.appendChild(downloadLink);
imagesContainer.appendChild(div);
}
function showStatus(message, type) {
status.textContent = message;
status.className = `status ${type}`;
}
</script>
</body>
</html>
好了,这个就可以放在本地直接使用了,Cursor 太牛了