// 设置PDF.js worker路径 pdfjsLib.GlobalWorkerOptions.workerSrc = 'cssjs/js/pdf.worker.js'; // 全局变量 let pdfDocument = null; let pdfFile = null; let renderedPages = []; // DOM元素 const uploadArea = document.getElementById('upload-area'); const pdfFileInput = document.getElementById('pdf-file-input'); const selectFileBtn = document.getElementById('select-file-btn'); const loadingContainer = document.getElementById('loading-container'); const pdfInfoContainer = document.getElementById('pdf-info-container'); const previewContainer = document.getElementById('preview-container'); const previewItems = document.getElementById('preview-items'); const exportBtn = document.getElementById('export-btn'); const combinePagesSwitch = document.getElementById('combine-pages-switch'); const highQualitySwitch = document.getElementById('high-quality-switch'); // PDF信息显示元素 const pdfNameValue = document.getElementById('pdf-name-value'); const pdfSizeValue = document.getElementById('pdf-size-value'); const pdfPagesValue = document.getElementById('pdf-pages-value'); // 事件监听器 document.addEventListener('DOMContentLoaded', function() { // 检查PDF.js是否正确加载 if (typeof pdfjsLib === 'undefined') { alert('PDF.js库加载失败,请确保pdf.js文件已正确放置'); return; } // 初始化事件监听 initEventListeners(); }); // 初始化事件监听器 function initEventListeners() { selectFileBtn.addEventListener('click', () => pdfFileInput.click()); pdfFileInput.addEventListener('change', handleFileSelect); exportBtn.addEventListener('click', exportImages); // 拖放功能 uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); if (e.dataTransfer.files.length > 0) { const file = e.dataTransfer.files[0]; if (file.type === 'application/pdf') { pdfFileInput.files = e.dataTransfer.files; handleFileSelect(e); } else { showError('请选择PDF文件'); } } }); } // 处理文件选择 function handleFileSelect(e) { const file = pdfFileInput.files[0]; if (!file) return; if (file.type !== 'application/pdf') { showError('请选择PDF文件'); return; } if (file.size > 20 * 1024 * 1024) { // 20MB showError('文件大小不能超过20MB'); return; } pdfFile = file; // 显示加载状态 uploadArea.style.display = 'none'; loadingContainer.style.display = 'block'; previewContainer.style.display = 'none'; pdfInfoContainer.style.display = 'none'; previewItems.innerHTML = ''; renderedPages = []; // 读取PDF文件 const reader = new FileReader(); reader.onload = function(event) { const typedArray = new Uint8Array(event.target.result); loadPdfFromData(typedArray); }; reader.readAsArrayBuffer(file); } // 从ArrayBuffer加载PDF function loadPdfFromData(data) { pdfjsLib.getDocument({ data }).promise .then(pdf => { pdfDocument = pdf; // 更新PDF信息 pdfNameValue.textContent = pdfFile.name; pdfSizeValue.textContent = formatFileSize(pdfFile.size); pdfPagesValue.textContent = pdf.numPages; // 渲染预览 renderPdfPreview(pdf); }) .catch(error => { console.error('PDF加载错误:', error); showError('无法加载PDF文件,请确保文件未损坏'); resetUI(); }); } // 渲染PDF预览 function renderPdfPreview(pdf) { const totalPages = pdf.numPages; let renderedCount = 0; // 更新加载文本 document.getElementById('loading-text').textContent = `正在渲染预览 (0/${totalPages})`; // 为每一页创建预览 for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) { pdf.getPage(pageNumber).then(page => { const scale = 0.5; // 预览缩放比例 const viewport = page.getViewport({ scale }); // 创建canvas元素 const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = viewport.width; canvas.height = viewport.height; // 渲染PDF页面到canvas const renderContext = { canvasContext: context, viewport: viewport }; page.render(renderContext).promise.then(() => { renderedCount++; document.getElementById('loading-text').textContent = `正在渲染预览 (${renderedCount}/${totalPages})`; // 存储渲染的页面 renderedPages[pageNumber - 1] = { pageNumber: pageNumber, canvas: canvas, width: viewport.width, height: viewport.height }; // 如果所有页面都已渲染,显示预览 if (renderedCount === totalPages) { displayPreviews(); } }); }); } } // 显示预览 function displayPreviews() { // 按页码排序 renderedPages.sort((a, b) => a.pageNumber - b.pageNumber); // 清空预览容器 previewItems.innerHTML = ''; // 添加每一页的预览 renderedPages.forEach(page => { const colDiv = document.createElement('div'); colDiv.className = 'col-md-6 col-lg-4 preview-item'; const pageNumberDiv = document.createElement('div'); pageNumberDiv.className = 'page-number'; pageNumberDiv.textContent = `第 ${page.pageNumber} 页`; // 克隆canvas以避免原始canvas被修改 const displayCanvas = document.createElement('canvas'); displayCanvas.width = page.canvas.width; displayCanvas.height = page.canvas.height; const displayContext = displayCanvas.getContext('2d'); displayContext.drawImage(page.canvas, 0, 0); colDiv.appendChild(displayCanvas); colDiv.appendChild(pageNumberDiv); previewItems.appendChild(colDiv); }); // 显示预览和控制面板 loadingContainer.style.display = 'none'; pdfInfoContainer.style.display = 'block'; previewContainer.style.display = 'block'; } // 导出图片 function exportImages() { if (!pdfDocument || renderedPages.length === 0) { showError('没有可导出的内容'); return; } const combinePages = combinePagesSwitch.checked; const highQuality = highQualitySwitch.checked; const scale = highQuality ? 2.0 : 1.0; // 显示加载状态 loadingContainer.style.display = 'block'; document.getElementById('loading-text').textContent = '正在准备导出...'; if (combinePages) { // 合并为单张图片 exportCombinedImage(scale); } else { // 导出为多张图片 exportMultipleImages(scale); } } // 导出合并的单张图片 function exportCombinedImage(scale) { // 计算合并后的图片尺寸 let totalHeight = 0; let maxWidth = 0; renderedPages.forEach(page => { totalHeight += page.height * (scale / 0.5); maxWidth = Math.max(maxWidth, page.width * (scale / 0.5)); }); // 创建合并的canvas const combinedCanvas = document.createElement('canvas'); combinedCanvas.width = maxWidth; combinedCanvas.height = totalHeight; const combinedContext = combinedCanvas.getContext('2d'); // 填充白色背景 combinedContext.fillStyle = '#FFFFFF'; combinedContext.fillRect(0, 0, combinedCanvas.width, combinedCanvas.height); // 重新渲染每一页到合并的canvas let currentY = 0; let renderedCount = 0; const renderNextPage = (index) => { if (index >= renderedPages.length) { // 所有页面都已渲染,导出图片 combinedCanvas.toBlob(blob => { saveAs(blob, `${pdfFile.name.replace('.pdf', '')}_combined.png`); loadingContainer.style.display = 'none'; }, 'image/png'); return; } const page = renderedPages[index]; // 更新加载文本 document.getElementById('loading-text').textContent = `正在合并页面 (${index + 1}/${renderedPages.length})`; // 获取原始页面 pdfDocument.getPage(page.pageNumber).then(pdfPage => { const viewport = pdfPage.getViewport({ scale }); // 创建临时canvas const tempCanvas = document.createElement('canvas'); tempCanvas.width = viewport.width; tempCanvas.height = viewport.height; const tempContext = tempCanvas.getContext('2d'); // 渲染到临时canvas const renderContext = { canvasContext: tempContext, viewport: viewport }; pdfPage.render(renderContext).promise.then(() => { // 将临时canvas的内容绘制到合并的canvas const x = (maxWidth - viewport.width) / 2; // 居中 combinedContext.drawImage(tempCanvas, x, currentY); // 更新Y坐标 currentY += viewport.height; // 渲染下一页 renderNextPage(index + 1); }); }); }; // 开始渲染第一页 renderNextPage(0); } // 导出多张图片 function exportMultipleImages(scale) { const zip = new JSZip(); const folder = zip.folder("images"); let processedCount = 0; // 更新加载文本 document.getElementById('loading-text').textContent = `正在导出图片 (0/${renderedPages.length})`; // 处理每一页 renderedPages.forEach((page, index) => { // 获取原始页面 pdfDocument.getPage(page.pageNumber).then(pdfPage => { const viewport = pdfPage.getViewport({ scale }); // 创建canvas const canvas = document.createElement('canvas'); canvas.width = viewport.width; canvas.height = viewport.height; const context = canvas.getContext('2d'); // 填充白色背景 context.fillStyle = '#FFFFFF'; context.fillRect(0, 0, canvas.width, canvas.height); // 渲染PDF页面到canvas const renderContext = { canvasContext: context, viewport: viewport }; pdfPage.render(renderContext).promise.then(() => { // 将canvas转换为blob canvas.toBlob(blob => { // 添加到zip folder.file(`page_${page.pageNumber}.png`, blob); processedCount++; document.getElementById('loading-text').textContent = `正在导出图片 (${processedCount}/${renderedPages.length})`; // 如果所有页面都已处理,生成并下载zip if (processedCount === renderedPages.length) { zip.generateAsync({ type: 'blob' }).then(content => { saveAs(content, `${pdfFile.name.replace('.pdf', '')}_images.zip`); loadingContainer.style.display = 'none'; }); } }, 'image/png'); }); }); }); } // 辅助函数 function formatFileSize(bytes) { if (bytes < 1024) return bytes + ' B'; else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + ' KB'; else return (bytes / 1048576).toFixed(2) + ' MB'; } function showError(message) { alert(message); } function resetUI() { uploadArea.style.display = 'block'; loadingContainer.style.display = 'none'; pdfInfoContainer.style.display = 'none'; previewContainer.style.display = 'none'; pdfFileInput.value = ''; }