Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const dropZone = document.getElementById('dropZone'); | |
| const imageUpload = document.getElementById('imageUpload'); | |
| const uploadBtn = document.getElementById('uploadBtn'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const previewContainer = document.getElementById('previewContainer'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const posterPages = document.getElementById('posterPages'); | |
| const printAllBtn = document.getElementById('printAllBtn'); | |
| const downloadAllBtn = document.getElementById('downloadAllBtn'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const pageCount = document.getElementById('pageCount'); | |
| const orientation = document.getElementById('orientation'); | |
| const overlapX = document.getElementById('overlapX'); | |
| const overlapY = document.getElementById('overlapY'); | |
| const showGrid = document.getElementById('showGrid'); | |
| const centerOverlap = document.getElementById('centerOverlap'); | |
| let uploadedImage = null; | |
| // Event Listeners | |
| uploadBtn.addEventListener('click', () => imageUpload.click()); | |
| imageUpload.addEventListener('change', handleImageUpload); | |
| dropZone.addEventListener('dragover', handleDragOver); | |
| dropZone.addEventListener('dragleave', handleDragLeave); | |
| dropZone.addEventListener('drop', handleDrop); | |
| generateBtn.addEventListener('click', generatePosterPages); | |
| printAllBtn.addEventListener('click', printAllPages); | |
| downloadAllBtn.addEventListener('click', downloadAllPages); | |
| resetBtn.addEventListener('click', resetApp); | |
| // Functions | |
| function handleImageUpload(e) { | |
| const file = e.target.files[0]; | |
| if (file && file.type.match('image.*')) { | |
| processImageFile(file); | |
| } | |
| } | |
| function handleDragOver(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| dropZone.classList.add('drag-over'); | |
| } | |
| function handleDragLeave(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| dropZone.classList.remove('drag-over'); | |
| } | |
| function handleDrop(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| dropZone.classList.remove('drag-over'); | |
| const file = e.dataTransfer.files[0]; | |
| if (file && file.type.match('image.*')) { | |
| processImageFile(file); | |
| } | |
| } | |
| function processImageFile(file) { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| uploadedImage = new Image(); | |
| uploadedImage.onload = function() { | |
| displayPreview(uploadedImage); | |
| generateBtn.disabled = false; | |
| }; | |
| uploadedImage.src = e.target.result; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| function displayPreview(image) { | |
| previewContainer.innerHTML = ''; | |
| const canvas = document.createElement('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const maxWidth = 400; | |
| const maxHeight = 300; | |
| let width = image.width; | |
| let height = image.height; | |
| if (width > maxWidth) { | |
| height = (maxWidth / width) * height; | |
| width = maxWidth; | |
| } | |
| if (height > maxHeight) { | |
| width = (maxHeight / height) * width; | |
| height = maxHeight; | |
| } | |
| canvas.width = width; | |
| canvas.height = height; | |
| ctx.drawImage(image, 0, 0, width, height); | |
| previewContainer.appendChild(canvas); | |
| } | |
| function generatePosterPages() { | |
| if (!uploadedImage) return; | |
| posterPages.innerHTML = ''; | |
| resultsSection.classList.remove('hidden'); | |
| const pages = parseInt(pageCount.value); | |
| const gridSize = Math.sqrt(pages); | |
| const orient = orientation.value; | |
| const overlapXPx = (parseInt(overlapX.value) / 25.4) * 96; // Convert mm to pixels (96dpi) | |
| const overlapYPx = (parseInt(overlapY.value) / 25.4) * 96; // Convert mm to pixels (96dpi) | |
| const showGuides = showGrid.checked; | |
| const centerOverlaps = centerOverlap.checked; | |
| // Calculate the size of each segment including overlaps | |
| const totalOverlapXPx = overlapXPx * (gridSize - 1); | |
| const totalOverlapYPx = overlapYPx * (gridSize - 1); | |
| // Original image dimensions minus total overlaps | |
| const baseWidth = uploadedImage.width - totalOverlapXPx; | |
| const baseHeight = uploadedImage.height - totalOverlapYPx; | |
| const segmentWidth = baseWidth / gridSize; | |
| const segmentHeight = baseHeight / gridSize; | |
| // Create a canvas for each page | |
| for (let row = 0; row < gridSize; row++) { | |
| for (let col = 0; col < gridSize; col++) { | |
| const pageNumber = row * gridSize + col + 1; | |
| const pageDiv = document.createElement('div'); | |
| pageDiv.className = 'poster-page relative'; | |
| const canvas = document.createElement('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Set canvas dimensions based on orientation | |
| if (orient === 'landscape') { | |
| canvas.width = 842; // A4 height as width (landscape) | |
| canvas.height = 595; // A4 width as height (landscape) | |
| } else { | |
| canvas.width = 595; // A4 width in pixels at 72dpi | |
| canvas.height = 842; // A4 height in pixels at 72dpi | |
| } | |
| // Calculate source rectangle with overlaps | |
| let sx = col * (segmentWidth) + (col * overlapXPx); | |
| let sy = row * (segmentHeight) + (row * overlapYPx); | |
| let sw = segmentWidth + (col < gridSize-1 ? overlapXPx : 0); | |
| let sh = segmentHeight + (row < gridSize-1 ? overlapYPx : 0); | |
| // Ensure we don't exceed image bounds | |
| sx = Math.max(0, Math.min(sx, uploadedImage.width - sw)); | |
| sy = Math.max(0, Math.min(sy, uploadedImage.height - sh)); | |
| sw = Math.min(sw, uploadedImage.width - sx); | |
| sh = Math.min(sh, uploadedImage.height - sy); | |
| // Draw the image segment | |
| ctx.save(); | |
| if (orient === 'diagonal') { | |
| // Diagonal orientation | |
| ctx.translate(canvas.width/2, canvas.height/2); | |
| ctx.rotate(Math.PI/4); | |
| ctx.drawImage( | |
| uploadedImage, | |
| sx, sy, sw, sh, | |
| -canvas.width/2, -canvas.height/2, canvas.width, canvas.height | |
| ); | |
| } else { | |
| // Standard orientation (portrait or landscape) | |
| // Maintain aspect ratio while filling canvas | |
| const imgRatio = sw / sh; | |
| const canvasRatio = canvas.width / canvas.height; | |
| let drawWidth, drawHeight, offsetX = 0, offsetY = 0; | |
| if (imgRatio > canvasRatio) { | |
| // Image is wider than canvas - fill width | |
| drawWidth = canvas.width; | |
| drawHeight = canvas.width / imgRatio; | |
| offsetY = (canvas.height - drawHeight) / 2; | |
| } else { | |
| // Image is taller than canvas - fill height | |
| drawHeight = canvas.height; | |
| drawWidth = canvas.height * imgRatio; | |
| offsetX = (canvas.width - drawWidth) / 2; | |
| } | |
| ctx.drawImage( | |
| uploadedImage, | |
| sx, sy, sw, sh, | |
| offsetX, offsetY, drawWidth, drawHeight | |
| ); | |
| } | |
| // Draw cutting guides if enabled | |
| if (showGuides) { | |
| ctx.strokeStyle = 'rgba(255, 0, 0, 0.7)'; | |
| ctx.lineWidth = 2; | |
| if (orient === 'portrait' || orient === 'landscape') { | |
| // Draw border for overlap areas | |
| const borderX = 10; | |
| const borderY = 10; | |
| const borderWidth = canvas.width - 20; | |
| const borderHeight = canvas.height - 20; | |
| ctx.strokeRect(borderX, borderY, borderWidth, borderHeight); | |
| // Draw center marks | |
| ctx.beginPath(); | |
| ctx.moveTo(canvas.width/2 - 15, canvas.height/2); | |
| ctx.lineTo(canvas.width/2 + 15, canvas.height/2); | |
| ctx.moveTo(canvas.width/2, canvas.height/2 - 15); | |
| ctx.lineTo(canvas.width/2, canvas.height/2 + 15); | |
| ctx.stroke(); | |
| } | |
| } | |
| // Draw border around the entire canvas | |
| ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; | |
| ctx.lineWidth = 2; | |
| ctx.strokeRect(0, 0, canvas.width, canvas.height); | |
| ctx.restore(); | |
| // Add page number | |
| const pageNumDiv = document.createElement('div'); | |
| pageNumDiv.className = 'absolute top-2 right-2 bg-white bg-opacity-80 px-2 py-1 rounded text-sm font-bold'; | |
| pageNumDiv.textContent = pageNumber; | |
| pageDiv.appendChild(pageNumDiv); | |
| // Add canvas to page | |
| pageDiv.appendChild(canvas); | |
| posterPages.appendChild(pageDiv); | |
| } | |
| } | |
| // Scroll to results | |
| resultsSection.scrollIntoView({ behavior: 'smooth' }); | |
| } | |
| function printAllPages() { | |
| window.print(); | |
| } | |
| function downloadAllPages() { | |
| alert('PDF generation would be implemented here with a library like jsPDF or browser print to PDF'); | |
| } | |
| function resetApp() { | |
| uploadedImage = null; | |
| previewContainer.innerHTML = ` | |
| <i data-feather="image" class="w-16 h-16 mx-auto text-gray-400 mb-3"></i> | |
| <p class="text-gray-600">Your image preview will appear here</p> | |
| `; | |
| feather.replace(); | |
| posterPages.innerHTML = ''; | |
| resultsSection.classList.add('hidden'); | |
| generateBtn.disabled = true; | |
| imageUpload.value = ''; | |
| } | |
| }); |