Spaces:
Running
Running
File size: 6,196 Bytes
34bcbf8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /**
* pdf-generator.js
* Generates High-Resolution Image PDF using html2canvas
* to preserve exact Devanagari ligatures and fonts,
* optimized for 2-5MB file sizes via JPEG compression.
*/
function generateAadhaarPDF() {
return new Promise((resolve, reject) => {
const { jsPDF } = window.jspdf;
const now = new Date();
const timeStamp = `${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;
const nameInput = document.getElementById('in-name-en');
const nameVal = nameInput && nameInput.value ? nameInput.value.trim().replace(/\s+/g, '_') : 'Applicant';
const fileName = `${nameVal}_Aadhaar_${timeStamp}.pdf`;
const ws = document.getElementById('workspace');
const previewArea = document.querySelector('.preview-area');
// Show preview area off-screen so html2canvas can capture it
const originalPreviewDisplay = previewArea ? previewArea.style.display : '';
const originalPreviewPosition = previewArea ? previewArea.style.position : '';
const originalPreviewLeft = previewArea ? previewArea.style.left : '';
if (previewArea) {
previewArea.style.setProperty('display', 'flex', 'important');
previewArea.style.position = 'fixed';
previewArea.style.left = '-9999px';
previewArea.style.top = '0';
}
// Temporarily remove scale transforms so html2canvas captures full A4 layout
const originalTransform = ws.style.transform;
const originalShadow = ws.style.boxShadow;
ws.style.transform = 'none';
ws.style.boxShadow = 'none';
// FIX: html2canvas blurs "background-size: cover" CSS images and misaligns them
// Calculate precise mathematical dimensions mirroring 'cover' logic in mm natively
const bgImgNative = new Image();
bgImgNative.onload = () => {
const pageRatio = 210 / 297;
const imgRatio = bgImgNative.naturalWidth / bgImgNative.naturalHeight;
let drawW, drawH, drawX, drawY;
if (imgRatio > pageRatio) {
drawH = 297;
drawW = (297 / bgImgNative.naturalHeight) * bgImgNative.naturalWidth;
drawX = (210 - drawW) / 2;
drawY = 0;
} else {
drawW = 210;
drawH = (210 / bgImgNative.naturalWidth) * bgImgNative.naturalHeight;
drawX = 0;
drawY = (297 - drawH) / 2;
}
bgImgNative.style.position = 'absolute';
bgImgNative.style.width = drawW + 'mm';
bgImgNative.style.height = drawH + 'mm';
bgImgNative.style.left = drawX + 'mm';
bgImgNative.style.top = drawY + 'mm';
bgImgNative.style.objectFit = 'fill';
bgImgNative.style.zIndex = '0';
bgImgNative.id = 'temp-bg-native';
const originalBgLayer = document.querySelector('.bg-layer');
const oldDisplay = originalBgLayer ? originalBgLayer.style.display : '';
if (originalBgLayer) originalBgLayer.style.display = 'none';
ws.prepend(bgImgNative);
// Timeout ensures DOM repaints before capture
setTimeout(() => {
html2canvas(ws, {
scale: 4, // 7x scale increases Sharpness dramatically and lands around ~5-8MB resulting JPEG size
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff',
logging: false,
onclone: (clonedDoc) => {
const clonedWs = clonedDoc.getElementById('workspace');
if (clonedWs) {
clonedWs.style.transform = 'none';
clonedWs.style.boxShadow = 'none';
}
// Force exact 6.3pt (8.4px) on requested text elements inside the cloned capturing DOM!
const exactEls = clonedDoc.querySelectorAll('.inroltext, .hindi-name, .english-name, .dob-text, .gender-text, .address-hi-text, .address-en-text, .address-hi-label, .address-en-label');
exactEls.forEach(el => {
el.style.fontSize = '8.4px';
});
}
}).then(canvas => {
// Restore UI immediately
ws.style.transform = originalTransform;
ws.style.boxShadow = originalShadow;
if (originalBgLayer) originalBgLayer.style.display = oldDisplay;
const tempBg = document.getElementById('temp-bg-native');
if (tempBg) tempBg.remove();
// Restore preview area state
if (previewArea) {
previewArea.style.removeProperty('display');
previewArea.style.position = originalPreviewPosition;
previewArea.style.left = originalPreviewLeft;
previewArea.style.top = '';
}
// JPEG encoding at 1.0 provides the absolute maximum fidelity
const imgData = canvas.toDataURL('image/jpeg', 1.0);
const doc = new jsPDF('portrait', 'mm', 'a4');
doc.addImage(imgData, 'JPEG', 0, 0, 210, 297);
doc.save(fileName);
resolve(fileName);
}).catch(err => {
console.error("PDF Generation Error:", err);
ws.style.transform = originalTransform;
ws.style.boxShadow = originalShadow;
if (originalBgLayer) originalBgLayer.style.display = oldDisplay;
const tempBg = document.getElementById('temp-bg-native');
if (tempBg) tempBg.remove();
if (previewArea) {
previewArea.style.removeProperty('display');
previewArea.style.position = originalPreviewPosition;
previewArea.style.left = originalPreviewLeft;
previewArea.style.top = '';
}
reject(err);
});
}, 150);
};
bgImgNative.src = EMBEDDED_BG;
});
} |