Archived
1
0
This repository has been archived on 2025-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
pdf2img/cssjs/js/main.js
Snowz 578a412bdd docs: 更新README和index.html,添加NGINX配置和浏览器兼容性说明
更新了README.md文件,增加了NGINX配置示例、浏览器兼容性说明、隐私说明和致谢部分。同时,修改了index.html文件,添加了favicon图标并调整了JS文件的加载顺序,确保FileSaver.js先加载。
2025-04-13 03:30:33 +08:00

378 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 导入依赖库
import * as pdfjsLib from './pdf.mjs';
import JSZip from './jszip.min.js';
// 设置PDF.js worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = 'cssjs/js/pdf.worker.mjs';
// 全局变量
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() {
// 初始化事件监听
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文件
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 = '';
}