document.addEventListener('DOMContentLoaded', function() { // DOM elements const fileInput = document.getElementById('file-input'); const uploadBtn = document.getElementById('upload-btn'); const dropZone = document.getElementById('drop-zone'); const imagePreview = document.getElementById('image-preview'); const imagePreviewContainer = document.getElementById('image-preview-container'); const emptyState = document.getElementById('empty-state'); const pageCountInput = document.getElementById('page-count'); const pageCountValue = document.getElementById('page-count-value'); const portraitBtn = document.getElementById('portrait'); const landscapeBtn = document.getElementById('landscape'); const previewControls = document.getElementById('preview-controls'); const generateBtn = document.getElementById('generate-btn'); const resultSection = document.getElementById('result-section'); const posterPages = document.getElementById('poster-pages'); const downloadAllBtn = document.getElementById('download-all'); const printAllBtn = document.getElementById('print-all'); // Current image and settings let currentImage = null; let currentOrientation = 'portrait'; let currentPageCount = 4; // Event listeners uploadBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', handleFileSelect); dropZone.addEventListener('dragover', handleDragOver); dropZone.addEventListener('dragleave', handleDragLeave); dropZone.addEventListener('drop', handleDrop); pageCountInput.addEventListener('input', updatePageCount); portraitBtn.addEventListener('click', () => setOrientation('portrait')); landscapeBtn.addEventListener('click', () => setOrientation('landscape')); generateBtn.addEventListener('click', generatePosterPages); downloadAllBtn.addEventListener('click', downloadAllPages); printAllBtn.addEventListener('click', printAllPages); document.getElementById('pdf-btn').addEventListener('click', generatePDF); // Update page count display function updatePageCount() { currentPageCount = parseInt(pageCountInput.value); pageCountValue.textContent = currentPageCount; } // Set orientation function setOrientation(orientation) { currentOrientation = orientation; if (orientation === 'portrait') { portraitBtn.classList.add('active', 'bg-indigo-100', 'text-indigo-700'); portraitBtn.classList.remove('border', 'border-gray-300'); landscapeBtn.classList.remove('active', 'bg-indigo-100', 'text-indigo-700'); landscapeBtn.classList.add('border', 'border-gray-300'); } else { landscapeBtn.classList.add('active', 'bg-indigo-100', 'text-indigo-700'); landscapeBtn.classList.remove('border', 'border-gray-300'); portraitBtn.classList.remove('active', 'bg-indigo-100', 'text-indigo-700'); portraitBtn.classList.add('border', 'border-gray-300'); } } // Handle file selection function handleFileSelect(e) { const file = e.target.files[0]; if (file && file.type.match('image.*')) { processImageFile(file); } } // Handle drag over function handleDragOver(e) { e.preventDefault(); e.stopPropagation(); dropZone.classList.add('highlight'); } // Handle drag leave function handleDragLeave(e) { e.preventDefault(); e.stopPropagation(); dropZone.classList.remove('highlight'); } // Handle drop function handleDrop(e) { e.preventDefault(); e.stopPropagation(); dropZone.classList.remove('highlight'); const file = e.dataTransfer.files[0]; if (file && file.type.match('image.*')) { processImageFile(file); } } // Process image file function processImageFile(file) { const reader = new FileReader(); reader.onload = function(e) { currentImage = new Image(); currentImage.onload = function() { showPreview(); }; currentImage.src = e.target.result; }; reader.readAsDataURL(file); } // Show preview function showPreview() { imagePreview.src = currentImage.src; imagePreviewContainer.classList.remove('hidden'); emptyState.classList.add('hidden'); previewControls.classList.remove('hidden'); } // Generate poster pages function generatePosterPages() { if (!currentImage) return; // Clear previous results posterPages.innerHTML = ''; resultSection.classList.remove('hidden'); // Calculate dimensions for each page const aspectRatio = currentImage.width / currentImage.height; let cols, rows; if (currentOrientation === 'portrait') { // For portrait orientation, we'll split vertically first cols = Math.ceil(Math.sqrt(currentPageCount * (210 / 297))); // A4 ratio rows = Math.ceil(currentPageCount / cols); } else { // For landscape orientation, we'll split horizontally first rows = Math.ceil(Math.sqrt(currentPageCount * (297 / 210))); // A4 ratio cols = Math.ceil(currentPageCount / rows); } // Create canvas for the entire image const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // Size canvas to maintain aspect ratio if (currentOrientation === 'portrait') { canvas.width = cols * 210; // A4 width in mm (approximate) canvas.height = (canvas.width / aspectRatio); // If height is less than needed for rows, adjust const neededHeight = rows * 297; if (canvas.height < neededHeight) { canvas.height = neededHeight; canvas.width = canvas.height * aspectRatio; } } else { canvas.height = rows * 210; // A4 height in mm (approximate) canvas.width = canvas.height * aspectRatio; // If width is less than needed for cols, adjust const neededWidth = cols * 297; if (canvas.width < neededWidth) { canvas.width = neededWidth; canvas.height = canvas.width / aspectRatio; } } // Draw the image on canvas ctx.drawImage(currentImage, 0, 0, canvas.width, canvas.height); // Calculate each page's dimensions const pageWidth = canvas.width / cols; const pageHeight = canvas.height / rows; // Create individual pages for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const pageIndex = row * cols + col; if (pageIndex >= currentPageCount) break; // Create page canvas const pageCanvas = document.createElement('canvas'); pageCanvas.width = 2480; // A4 at 300dpi pageCanvas.height = 3508; const pageCtx = pageCanvas.getContext('2d'); // Calculate source dimensions const sx = col * pageWidth; const sy = row * pageHeight; const sw = pageWidth; const sh = pageHeight; // Draw the portion of the image on the page pageCtx.drawImage( canvas, sx, sy, sw, sh, 0, 0, pageCanvas.width, pageCanvas.height ); // Add cut lines and page number addPageMarkings(pageCtx, pageCanvas.width, pageCanvas.height, pageIndex + 1); // Create page element const pageElement = document.createElement('div'); pageElement.className = 'poster-page relative'; // Create download button const downloadBtn = document.createElement('button'); downloadBtn.className = 'absolute top-2 left-2 bg-white bg-opacity-90 p-2 rounded-full shadow hover:bg-opacity-100 transition'; downloadBtn.innerHTML = ''; downloadBtn.onclick = () => downloadPage(pageCanvas, pageIndex + 1); // Add image and button to page const img = document.createElement('img'); img.src = pageCanvas.toDataURL('image/jpeg', 0.9); img.className = 'w-full h-auto'; pageElement.appendChild(img); pageElement.appendChild(downloadBtn); posterPages.appendChild(pageElement); } } feather.replace(); } // Add page markings (cut lines and page numbers) function addPageMarkings(ctx, width, height, pageNumber) { // Cut lines (5mm from edges) const cutMargin = 59; // 5mm at 300dpi (5/25.4*300) ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)'; ctx.lineWidth = 2; ctx.setLineDash([5, 5]); // Top and bottom lines ctx.beginPath(); ctx.moveTo(cutMargin, cutMargin); ctx.lineTo(width - cutMargin, cutMargin); ctx.moveTo(cutMargin, height - cutMargin); ctx.lineTo(width - cutMargin, height - cutMargin); ctx.stroke(); // Left and right lines ctx.beginPath(); ctx.moveTo(cutMargin, cutMargin); ctx.lineTo(cutMargin, height - cutMargin); ctx.moveTo(width - cutMargin, cutMargin); ctx.lineTo(width - cutMargin, height - cutMargin); ctx.stroke(); // Page number ctx.font = 'bold 40px Arial'; ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; ctx.textAlign = 'right'; ctx.textBaseline = 'bottom'; ctx.fillText(pageNumber.toString(), width - 20, height - 20); } // Download a single page function downloadPage(canvas, pageNumber) { const link = document.createElement('a'); link.download = `poster-page-${pageNumber}.jpg`; link.href = canvas.toDataURL('image/jpeg', 0.9); link.click(); } // Download all pages function downloadAllPages() { const pages = posterPages.querySelectorAll('.poster-page img'); pages.forEach((img, index) => { const link = document.createElement('a'); link.download = `poster-page-${index + 1}.jpg`; link.href = img.src; document.body.appendChild(link); link.click(); document.body.removeChild(link); }); } // Generate PDF of all pages function generatePDF() { if (posterPages.children.length === 0) return; // Include jsPDF library dynamically const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js'; script.onload = function() { const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: currentOrientation, unit: 'mm', format: 'a4' }); const pages = posterPages.querySelectorAll('.poster-page img'); const promises = []; // Convert all images to Image objects to get dimensions pages.forEach((img, index) => { const promise = new Promise((resolve) => { const tempImg = new Image(); tempImg.onload = function() { resolve({ src: img.src, width: tempImg.width, height: tempImg.height, index: index + 1 }); }; tempImg.src = img.src; }); promises.push(promise); }); Promise.all(promises).then((images) => { images.forEach((img, i) => { if (i > 0) { pdf.addPage('a4', currentOrientation); } // Calculate dimensions to fit A4 page (210x297mm or 297x210mm) const pageWidth = currentOrientation === 'portrait' ? 210 : 297; const pageHeight = currentOrientation === 'portrait' ? 297 : 210; // Maintain aspect ratio const imgAspect = img.width / img.height; const pageAspect = pageWidth / pageHeight; let width, height; if (imgAspect > pageAspect) { width = pageWidth; height = width / imgAspect; } else { height = pageHeight; width = height * imgAspect; } // Center the image const x = (pageWidth - width) / 2; const y = (pageHeight - height) / 2; pdf.addImage(img.src, 'JPEG', x, y, width, height); // Add page number pdf.setFontSize(12); pdf.setTextColor(150); pdf.text( `Page ${img.index}`, currentOrientation === 'portrait' ? 200 : 287, currentOrientation === 'portrait' ? 290 : 200, { align: 'right' } ); }); pdf.save('poster-pages.pdf'); }); }; document.head.appendChild(script); } // Print all pages function printAllPages() { if (posterPages.children.length === 0) return; // Create a print stylesheet const printStyle = document.createElement('style'); printStyle.innerHTML = ` @media print { body * { visibility: hidden; } .print-container, .print-container * { visibility: visible; } .print-container { position: absolute; left: 0; top: 0; width: 100%; height: 100%; margin: 0; padding: 0; page-break-after: always; } .print-page { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .print-page img { max-width: 100%; max-height: 100%; } } `; // Create a print container const printContainer = document.createElement('div'); printContainer.className = 'print-container'; // Clone all pages into print container const pages = posterPages.querySelectorAll('.poster-page'); pages.forEach(page => { const clone = page.cloneNode(true); const pageDiv = document.createElement('div'); pageDiv.className = 'print-page'; pageDiv.appendChild(clone); printContainer.appendChild(pageDiv); }); // Create print window const printWindow = window.open('', '', 'width=800,height=600'); printWindow.document.body.appendChild(printStyle); printWindow.document.body.appendChild(printContainer); printWindow.document.close(); // Trigger print after content loads printWindow.onload = function() { printWindow.print(); }; } });