{"id":875,"date":"2026-07-29T18:34:52","date_gmt":"2026-07-29T13:04:52","guid":{"rendered":"https:\/\/pr.hostingage.com\/?page_id=875"},"modified":"2026-08-02T12:13:22","modified_gmt":"2026-08-02T06:43:22","slug":"%e0%a4%aa%e0%a4%be%e0%a4%b8%e0%a4%aa%e0%a5%8b%e0%a4%b0%e0%a5%8d%e0%a4%9f-%e0%a4%b8%e0%a4%be%e0%a4%87%e0%a4%9c%e0%a4%bc-%e0%a4%ab%e0%a5%8b%e0%a4%9f%e0%a5%8b-%e0%a4%ae%e0%a5%87%e0%a4%95%e0%a4%b0","status":"publish","type":"page","link":"https:\/\/pr.hostingage.com\/hi\/passport-size-photo-maker\/","title":{"rendered":"\u092a\u093e\u0938\u092a\u094b\u0930\u094d\u091f \u0938\u093e\u0907\u091c\u093c \u092b\u094b\u091f\u094b \u092e\u0947\u0915\u0930"},"content":{"rendered":"\n    <style>\n    .css_photopass-wrap{\n      --pp-paper:#FAFAF6;\n      --pp-ink:#1B2430;\n      --pp-ink-soft:#4A5568;\n      --pp-line:#DCDDD5;\n      --pp-panel:#FFFFFF;\n      --pp-accent:#C8442C;\n      --pp-accent-soft:#F3D9D2;\n      --pp-blue:#3E5C76;\n      --pp-radius:2px;\n\n      background:var(--pp-paper);\n      color:var(--pp-ink);\n      font-family:'Inter',sans-serif;\n    }\n    .css_photopass-wrap *{box-sizing:border-box;}\n    .css_photopass-mono{font-family:'Space Mono',monospace;}\n\n    \/* ---- Layout ---- *\/\n    .css_photopass-layout{\n      display:grid;\n      grid-template-columns:1fr 1fr;\n      gap:1px;\n      background:var(--pp-line);\n      max-width:1120px;\n      margin:0 auto;\n      border-left:1px solid var(--pp-line);\n      border-right:1px solid var(--pp-line);\n      border-top:1px solid var(--pp-line);\n    }\n    @media (max-width:860px){\n      .css_photopass-layout{grid-template-columns:1fr;}\n    }\n    .css_photopass-panel{\n      background:var(--pp-panel);\n      padding:32px 36px 40px;\n    }\n    .css_photopass-step-label{\n      font-family:'Space Mono',monospace;\n      font-size:12px;\n      letter-spacing:0.08em;\n      text-transform:uppercase;\n      color:var(--pp-ink-soft);\n      margin-bottom:22px;\n      display:flex;\n      align-items:baseline;\n      gap:8px;\n    }\n    .css_photopass-step-num{\n      color:var(--pp-accent);\n      font-weight:700;\n    }\n\n    \/* ---- Fields ---- *\/\n    .css_photopass-wrap .css_photopass-field{margin-bottom:18px;}\n    .css_photopass-wrap .css_photopass-field label{\n      display:block;\n      font-size:13px;\n      font-weight:600;\n      margin-bottom:6px;\n      color:var(--pp-ink);\n    }\n    .css_photopass-wrap select,\n    .css_photopass-wrap input[type=\"file\"],\n    .css_photopass-wrap input[type=\"number\"]{\n      width:100%;\n      padding:10px 12px;\n      border:1px solid var(--pp-line);\n      border-radius:var(--pp-radius);\n      background:#fff;\n      font-family:'Inter',sans-serif;\n      font-size:14px;\n      color:var(--pp-ink);\n    }\n    .css_photopass-wrap select:focus,\n    .css_photopass-wrap input:focus{\n      outline:2px solid var(--pp-blue);\n      outline-offset:1px;\n    }\n    .css_photopass-wrap input[type=\"range\"]{\n      width:100%;\n      accent-color:var(--pp-accent);\n    }\n    .css_photopass-inline-inputs{display:flex;align-items:center;gap:10px;}\n    .css_photopass-x-sep{color:var(--pp-ink-soft);font-family:'Space Mono',monospace;}\n    .css_photopass-hint{\n      font-size:12px;\n      color:var(--pp-ink-soft);\n      margin-top:-6px;\n    }\n\n    \/* ---- Crop stage ---- *\/\n    .css_photopass-crop-stage{\n      position:relative;\n      display:flex;\n      align-items:center;\n      justify-content:center;\n      min-height:280px;\n      background:#F0F0EC;\n      border:1px solid var(--pp-line);\n      margin-bottom:18px;\n      overflow:hidden;\n    }\n    .css_photopass-wrap #photopass_cropCanvas{\n      display:none;\n      cursor:grab;\n      touch-action:none;\n    }\n    .css_photopass-wrap #photopass_cropCanvas.css_photopass-active{display:block;}\n    .css_photopass-wrap #photopass_cropCanvas:active{cursor:grabbing;}\n    .css_photopass-crop-empty{\n      font-size:13px;\n      color:var(--pp-ink-soft);\n      font-family:'Space Mono',monospace;\n    }\n    .css_photopass-crop-brackets{position:absolute;inset:0;pointer-events:none;display:none;}\n    .css_photopass-crop-brackets.css_photopass-active{display:block;}\n    .css_photopass-bracket{\n      position:absolute;\n      width:14px;height:14px;\n      border-color:var(--pp-accent);\n      border-style:solid;\n      border-width:0;\n    }\n    .css_photopass-bracket.css_photopass-tl{top:0;left:0;border-top-width:2px;border-left-width:2px;}\n    .css_photopass-bracket.css_photopass-tr{top:0;right:0;border-top-width:2px;border-right-width:2px;}\n    .css_photopass-bracket.css_photopass-bl{bottom:0;left:0;border-bottom-width:2px;border-left-width:2px;}\n    .css_photopass-bracket.css_photopass-br{bottom:0;right:0;border-bottom-width:2px;border-right-width:2px;}\n\n    \/* ---- Sheet meta ---- *\/\n    .css_photopass-sheet-meta{\n      display:flex;\n      gap:1px;\n      background:var(--pp-line);\n      border:1px solid var(--pp-line);\n      margin-bottom:18px;\n    }\n    .css_photopass-meta-block{\n      flex:1;\n      background:#fff;\n      padding:12px 14px;\n    }\n    .css_photopass-meta-label{\n      display:block;\n      font-size:11px;\n      text-transform:uppercase;\n      letter-spacing:0.06em;\n      color:var(--pp-ink-soft);\n      margin-bottom:4px;\n    }\n    .css_photopass-meta-value{font-size:15px;font-weight:700;}\n\n    \/* ---- Buttons ---- *\/\n    .css_photopass-wrap .css_photopass-btn-primary,\n    .css_photopass-wrap .css_photopass-btn-secondary{\n      font-family:'Inter',sans-serif;\n      font-size:14px;\n      font-weight:600;\n      padding:12px 18px;\n      border-radius:var(--pp-radius);\n      cursor:pointer;\n      border:1px solid var(--pp-ink);\n      transition:opacity .15s ease;\n    }\n    .css_photopass-wrap .css_photopass-btn-primary{\n      background:var(--pp-ink);\n      color:#fff;\n      width:100%;\n      margin-bottom:18px;\n    }\n    .css_photopass-wrap .css_photopass-btn-secondary{\n      background:#fff;\n      color:var(--pp-ink);\n      flex:1;\n    }\n    .css_photopass-wrap .css_photopass-btn-primary:disabled,\n    .css_photopass-wrap .css_photopass-btn-secondary:disabled{\n      opacity:0.35;\n      cursor:not-allowed;\n    }\n    .css_photopass-wrap .css_photopass-btn-primary:not(:disabled):hover,\n    .css_photopass-wrap .css_photopass-btn-secondary:not(:disabled):hover{\n      opacity:0.82;\n    }\n    .css_photopass-export-row{display:flex;gap:12px;}\n\n    \/* ---- Sheet stage ---- *\/\n    .css_photopass-sheet-stage{\n      position:relative;\n      display:flex;\n      align-items:center;\n      justify-content:center;\n      min-height:280px;\n      background:#F0F0EC;\n      border:1px solid var(--pp-line);\n      margin-bottom:18px;\n      padding:10px;\n    }\n    .css_photopass-wrap #photopass_sheetCanvas{\n      display:none;\n      max-width:100%;\n      max-height:420px;\n      box-shadow:0 1px 6px rgba(0,0,0,0.15);\n    }\n    .css_photopass-wrap #photopass_sheetCanvas.css_photopass-active{display:block;}\n    .css_photopass-sheet-empty{\n      font-size:13px;\n      color:var(--pp-ink-soft);\n      font-family:'Space Mono',monospace;\n    }\n\n    \/* ---- Footer ---- *\/\n    .css_photopass-foot{\n      text-align:center;\n      font-size:12px;\n      color:var(--pp-ink-soft);\n      padding:24px 20px 40px;\n      max-width:1120px;\n      margin:0 auto;\n      border-left:1px solid var(--pp-line);\n      border-right:1px solid var(--pp-line);\n      border-bottom:1px solid var(--pp-line);\n    }\n    <\/style>\n\n    <div class=\"css_photopass-wrap\" id=\"photopass_wrap\">\n\n      <main class=\"css_photopass-layout\">\n\n        <!-- STEP 1: Upload + Crop -->\n        <section class=\"css_photopass-panel\" id=\"photopass_step1\">\n          <div class=\"css_photopass-step-label\"><span class=\"css_photopass-step-num\">01<\/span> Upload &amp; position<\/div>\n\n          <div class=\"css_photopass-field\">\n            <label for=\"photopass_fileInput\">Photo file<\/label>\n            <input type=\"file\" id=\"photopass_fileInput\" accept=\"image\/*\">\n          <\/div>\n\n          <div class=\"css_photopass-field\">\n            <label for=\"photopass_sizeSelect\">Photo size<\/label>\n            <select id=\"photopass_sizeSelect\">\n              <option value=\"35x45\">35 \u00d7 45 mm \u2014 Passport (India \/ EU)<\/option>\n              <option value=\"51x51\">51 \u00d7 51 mm \u2014 2\u00d72 in (US Visa)<\/option>\n              <option value=\"33x48\">33 \u00d7 48 mm \u2014 Schengen Visa<\/option>\n              <option value=\"40x60\">40 \u00d7 60 mm<\/option>\n              <option value=\"25x35\">25 \u00d7 35 mm<\/option>\n              <option value=\"custom\">Custom size\u2026<\/option>\n            <\/select>\n          <\/div>\n\n          <div class=\"css_photopass-field css_photopass-inline-inputs\" id=\"photopass_customSizeRow\" hidden style=\"display:none;\">\n            <div style=\"width:100%;\">\n              <label>Custom size (mm)<\/label>\n              <div class=\"css_photopass-inline-inputs\">\n                <input type=\"number\" id=\"photopass_customW\" placeholder=\"Width\" min=\"10\" max=\"120\" value=\"35\">\n                <span class=\"css_photopass-x-sep\">\u00d7<\/span>\n                <input type=\"number\" id=\"photopass_customH\" placeholder=\"Height\" min=\"10\" max=\"120\" value=\"45\">\n              <\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"css_photopass-crop-stage\" id=\"photopass_cropStage\">\n            <canvas id=\"photopass_cropCanvas\"><\/canvas>\n            <div class=\"css_photopass-crop-brackets\" id=\"photopass_cropBrackets\">\n              <span class=\"css_photopass-bracket css_photopass-tl\"><\/span><span class=\"css_photopass-bracket css_photopass-tr\"><\/span>\n              <span class=\"css_photopass-bracket css_photopass-bl\"><\/span><span class=\"css_photopass-bracket css_photopass-br\"><\/span>\n            <\/div>\n            <div class=\"css_photopass-crop-empty\" id=\"photopass_cropEmpty\">Upload a photo to begin<\/div>\n          <\/div>\n\n          <div class=\"css_photopass-field\">\n            <label for=\"photopass_zoomRange\">Zoom <span id=\"photopass_zoomVal\" class=\"css_photopass-mono\">1.00\u00d7<\/span><\/label>\n            <input type=\"range\" id=\"photopass_zoomRange\" min=\"1\" max=\"3\" step=\"0.01\" value=\"1\" disabled>\n          <\/div>\n          <p class=\"css_photopass-hint\">Drag the photo inside the frame to reposition it.<\/p>\n\n          <button id=\"photopass_downloadSingleBtn\" class=\"css_photopass-btn-primary\" disabled>Download Single Photo<\/button>\n        <\/section>\n\n        <!-- STEP 2: Sheet setup -->\n        <section class=\"css_photopass-panel\" id=\"photopass_step2\">\n          <div class=\"css_photopass-step-label\"><span class=\"css_photopass-step-num\">02<\/span> Print sheet<\/div>\n\n          <div class=\"css_photopass-field\">\n            <label for=\"photopass_paperSelect\">Paper size<\/label>\n            <select id=\"photopass_paperSelect\">\n              <option value=\"4x6\">6 \u00d7 4 in (152 \u00d7 102 mm, landscape)<\/option>\n              <option value=\"a4\">A4 (297 \u00d7 210 mm, landscape)<\/option>\n            <\/select>\n          <\/div>\n\n          <div class=\"css_photopass-sheet-meta\">\n            <div class=\"css_photopass-meta-block\">\n              <span class=\"css_photopass-meta-label\">Layout<\/span>\n              <span class=\"css_photopass-meta-value css_photopass-mono\" id=\"photopass_gridInfo\">\u2014<\/span>\n            <\/div>\n            <div class=\"css_photopass-meta-block\">\n              <span class=\"css_photopass-meta-label\">Photos \/ sheet<\/span>\n              <span class=\"css_photopass-meta-value css_photopass-mono\" id=\"photopass_countInfo\">\u2014<\/span>\n            <\/div>\n          <\/div>\n\n          <button id=\"photopass_generateBtn\" class=\"css_photopass-btn-primary\" disabled>Generate print sheet<\/button>\n\n          <div class=\"css_photopass-sheet-stage\" id=\"photopass_sheetStage\">\n            <canvas id=\"photopass_sheetCanvas\"><\/canvas>\n            <div class=\"css_photopass-sheet-empty\" id=\"photopass_sheetEmpty\">Sheet preview appears here<\/div>\n          <\/div>\n\n          <div class=\"css_photopass-export-row\">\n            <button id=\"photopass_downloadPng\" class=\"css_photopass-btn-secondary\" disabled>Download PNG<\/button>\n            <button id=\"photopass_downloadPdf\" class=\"css_photopass-btn-secondary\" disabled>Download PDF<\/button>\n          <\/div>\n        <\/section>\n\n      <\/main>\n\n      <footer class=\"css_photopass-foot\">\n        <span class=\"css_photopass-mono\">300 DPI<\/span> print-ready output \u00b7 runs entirely in your browser, nothing is uploaded\n      <\/footer>\n\n    <\/div>\n\n    <script>\n    (function(){\n      \/* ===================== CONSTANTS ===================== *\/\n      const DPI = 300;\n      const mmToPx = mm => Math.round((mm \/ 25.4) * DPI);\n\n      const PHOTO_SIZES = {\n        \"35x45\": { w: 35, h: 45 },\n        \"51x51\": { w: 51, h: 51 },\n        \"33x48\": { w: 33, h: 48 },\n        \"40x60\": { w: 40, h: 60 },\n        \"25x35\": { w: 25, h: 35 }\n      };\n\n      const PAPER_SIZES = {\n        \"4x6\": { w: 152.4, h: 101.6 },\n        \"a4\":  { w: 210,   h: 297   }\n      };\n\n      const PAPER_LAYOUT = {\n        \"4x6\": { marginXMm: 2,   marginYMm: 2,   gapMm: 2, rotateTile: false, rotateSheetForExport: false },\n        \"a4\":  { marginXMm: 4.5, marginYMm: 1.4, gapMm: 2, rotateTile: true,  rotateSheetForExport: true  }\n      };\n\n      \/* ===================== STATE ===================== *\/\n      let img = null;\n      let photoSize = PHOTO_SIZES[\"35x45\"];\n      let paperSize = PAPER_SIZES[\"4x6\"];\n\n      let baseScale = 1;\n      let zoom = 1;\n      let offsetX = 0, offsetY = 0;\n      let dragging = false;\n      let dragStart = { x: 0, y: 0 };\n      let offsetStart = { x: 0, y: 0 };\n\n      \/* ===================== DOM ===================== *\/\n      const wrap        = document.getElementById('photopass_wrap');\n      const fileInput    = wrap.querySelector('#photopass_fileInput');\n      const sizeSelect   = wrap.querySelector('#photopass_sizeSelect');\n      const customRow    = wrap.querySelector('#photopass_customSizeRow');\n      const customW      = wrap.querySelector('#photopass_customW');\n      const customH      = wrap.querySelector('#photopass_customH');\n      const cropStage    = wrap.querySelector('#photopass_cropStage');\n      const cropCanvas   = wrap.querySelector('#photopass_cropCanvas');\n      const cropEmpty    = wrap.querySelector('#photopass_cropEmpty');\n      const cropBrackets = wrap.querySelector('#photopass_cropBrackets');\n      const zoomRange    = wrap.querySelector('#photopass_zoomRange');\n      const zoomVal      = wrap.querySelector('#photopass_zoomVal');\n\n      const paperSelect  = wrap.querySelector('#photopass_paperSelect');\n      const gridInfo     = wrap.querySelector('#photopass_gridInfo');\n      const countInfo    = wrap.querySelector('#photopass_countInfo');\n      const generateBtn  = wrap.querySelector('#photopass_generateBtn');\n      const sheetStage   = wrap.querySelector('#photopass_sheetStage');\n      const sheetCanvas  = wrap.querySelector('#photopass_sheetCanvas');\n      const sheetEmpty   = wrap.querySelector('#photopass_sheetEmpty');\n      const downloadSingleBtn = wrap.querySelector('#photopass_downloadSingleBtn');\n      const downloadPngBtn = wrap.querySelector('#photopass_downloadPng');\n      const downloadPdfBtn = wrap.querySelector('#photopass_downloadPdf');\n\n      const cropCtx = cropCanvas.getContext('2d');\n\n      \/* ===================== PHOTO SIZE \/ CUSTOM ===================== *\/\n      function currentPhotoSize() {\n        if (sizeSelect.value === 'custom') {\n          const w = parseFloat(customW.value) || 35;\n          const h = parseFloat(customH.value) || 45;\n          return { w, h };\n        }\n        return PHOTO_SIZES[sizeSelect.value];\n      }\n\n      sizeSelect.addEventListener('change', () => {\n        const isCustom = sizeSelect.value === 'custom';\n        customRow.hidden = !isCustom;\n        customRow.style.display = isCustom ? 'flex' : 'none';\n        photoSize = currentPhotoSize();\n        layoutCropCanvas();\n        updateSheetMeta();\n      });\n      customW.addEventListener('input', () => { photoSize = currentPhotoSize(); layoutCropCanvas(); updateSheetMeta(); });\n      customH.addEventListener('input', () => { photoSize = currentPhotoSize(); layoutCropCanvas(); updateSheetMeta(); });\n\n      paperSelect.addEventListener('change', () => {\n        paperSize = PAPER_SIZES[paperSelect.value];\n        updateSheetMeta();\n      });\n\n      \/* ===================== UPLOAD ===================== *\/\n      fileInput.addEventListener('change', (e) => {\n        const file = e.target.files[0];\n        if (!file) return;\n        const reader = new FileReader();\n        reader.onload = (ev) => {\n          const image = new Image();\n          image.onload = () => {\n            img = image;\n            cropEmpty.style.display = 'none';\n            cropCanvas.classList.add('css_photopass-active');\n            cropBrackets.classList.add('css_photopass-active');\n            zoomRange.disabled = false;\n            downloadSingleBtn.disabled = false;\n            layoutCropCanvas();\n            resetTransform();\n            drawCrop();\n            updateSheetMeta();\n          };\n          image.src = ev.target.result;\n        };\n        reader.readAsDataURL(file);\n      });\n\n      \/* ===================== CROP CANVAS SIZING ===================== *\/\n      function layoutCropCanvas() {\n        photoSize = currentPhotoSize();\n        const stageMax = 260;\n        const ratio = photoSize.w \/ photoSize.h;\n        let cw, ch;\n        if (ratio >= 1) { cw = stageMax; ch = stageMax \/ ratio; }\n        else            { ch = stageMax; cw = stageMax * ratio; }\n        cropCanvas.width = Math.round(cw);\n        cropCanvas.height = Math.round(ch);\n        if (img) { resetTransform(); drawCrop(); }\n      }\n\n      function resetTransform() {\n        if (!img) return;\n        baseScale = Math.max(cropCanvas.width \/ img.width, cropCanvas.height \/ img.height);\n        zoom = 1;\n        zoomRange.value = 1;\n        zoomVal.textContent = '1.00\u00d7';\n        offsetX = (cropCanvas.width - img.width * baseScale) \/ 2;\n        offsetY = (cropCanvas.height - img.height * baseScale) \/ 2;\n      }\n\n      function clampOffset() {\n        const scale = baseScale * zoom;\n        const iw = img.width * scale, ih = img.height * scale;\n        const minX = cropCanvas.width - iw, maxX = 0;\n        const minY = cropCanvas.height - ih, maxY = 0;\n        offsetX = Math.min(maxX, Math.max(minX, offsetX));\n        offsetY = Math.min(maxY, Math.max(minY, offsetY));\n      }\n\n      function drawCrop() {\n        if (!img) return;\n        const scale = baseScale * zoom;\n        cropCtx.clearRect(0, 0, cropCanvas.width, cropCanvas.height);\n        cropCtx.drawImage(img, offsetX, offsetY, img.width * scale, img.height * scale);\n      }\n\n      \/* ---- zoom ---- *\/\n      zoomRange.addEventListener('input', () => {\n        if (!img) return;\n        const oldScale = baseScale * zoom;\n        const cx = cropCanvas.width \/ 2, cy = cropCanvas.height \/ 2;\n        const relX = (cx - offsetX) \/ oldScale;\n        const relY = (cy - offsetY) \/ oldScale;\n        zoom = parseFloat(zoomRange.value);\n        zoomVal.textContent = zoom.toFixed(2) + '\u00d7';\n        const newScale = baseScale * zoom;\n        offsetX = cx - relX * newScale;\n        offsetY = cy - relY * newScale;\n        clampOffset();\n        drawCrop();\n      });\n\n      \/* ---- drag to pan (mouse + touch) ---- *\/\n      function startDrag(x, y) {\n        if (!img) return;\n        dragging = true;\n        dragStart = { x, y };\n        offsetStart = { x: offsetX, y: offsetY };\n      }\n      function moveDrag(x, y) {\n        if (!dragging) return;\n        offsetX = offsetStart.x + (x - dragStart.x);\n        offsetY = offsetStart.y + (y - dragStart.y);\n        clampOffset();\n        drawCrop();\n      }\n      function endDrag() { dragging = false; }\n\n      cropCanvas.addEventListener('mousedown', (e) => {\n        const r = cropCanvas.getBoundingClientRect();\n        startDrag(e.clientX - r.left, e.clientY - r.top);\n      });\n      window.addEventListener('mousemove', (e) => {\n        const r = cropCanvas.getBoundingClientRect();\n        moveDrag(e.clientX - r.left, e.clientY - r.top);\n      });\n      window.addEventListener('mouseup', endDrag);\n\n      cropCanvas.addEventListener('touchstart', (e) => {\n        const r = cropCanvas.getBoundingClientRect();\n        const t = e.touches[0];\n        startDrag(t.clientX - r.left, t.clientY - r.top);\n      }, { passive: true });\n      cropCanvas.addEventListener('touchmove', (e) => {\n        const r = cropCanvas.getBoundingClientRect();\n        const t = e.touches[0];\n        moveDrag(t.clientX - r.left, t.clientY - r.top);\n      }, { passive: true });\n      cropCanvas.addEventListener('touchend', endDrag);\n\n      \/* ===================== RENDER SINGLE PHOTO AT PRINT RES ===================== *\/\n      function renderPhotoCanvas() {\n        const w = mmToPx(photoSize.w), h = mmToPx(photoSize.h);\n        const out = document.createElement('canvas');\n        out.width = w; out.height = h;\n        const ctx = out.getContext('2d');\n        const factor = w \/ cropCanvas.width;\n        const scale = baseScale * zoom * factor;\n        ctx.drawImage(img, offsetX * factor, offsetY * factor, img.width * scale, img.height * scale);\n        return out;\n      }\n\n      \/* ===================== SHEET GRID MATH ===================== *\/\n      function computeGrid() {\n        photoSize = currentPhotoSize();\n        const cfg = PAPER_LAYOUT[paperSelect.value];\n        const paperWpx = mmToPx(paperSize.w), paperHpx = mmToPx(paperSize.h);\n\n        const cellWmm = cfg.rotateTile ? photoSize.h : photoSize.w;\n        const cellHmm = cfg.rotateTile ? photoSize.w : photoSize.h;\n        const cellWpx = mmToPx(cellWmm), cellHpx = mmToPx(cellHmm);\n\n        const marginXPx = mmToPx(cfg.marginXMm), marginYPx = mmToPx(cfg.marginYMm), gapPx = mmToPx(cfg.gapMm);\n\n        const usableW = paperWpx - 2 * marginXPx;\n        const usableH = paperHpx - 2 * marginYPx;\n\n        const cols = Math.max(0, Math.floor((usableW + gapPx) \/ (cellWpx + gapPx)));\n        const rows = Math.max(0, Math.floor((usableH + gapPx) \/ (cellHpx + gapPx)));\n\n        return { cols, rows, total: cols * rows, paperWpx, paperHpx, cellWpx, cellHpx, marginXPx, marginYPx, gapPx, rotateTile: cfg.rotateTile, rotateSheetForExport: cfg.rotateSheetForExport };\n      }\n\n      function updateSheetMeta() {\n        const g = computeGrid();\n        if (g.total > 0) {\n          gridInfo.textContent = `${g.cols} \u00d7 ${g.rows}`;\n          countInfo.textContent = `${g.total}`;\n        } else {\n          gridInfo.textContent = '\u2014';\n          countInfo.textContent = '0 (photo too large for paper)';\n        }\n        generateBtn.disabled = !img || g.total === 0;\n      }\n\n      \/* ===================== GENERATE SHEET ===================== *\/\n      generateBtn.addEventListener('click', () => {\n        if (!img) return;\n        const g = computeGrid();\n        if (g.total === 0) return;\n\n        const baseTile = renderPhotoCanvas();\n\n        let tile = baseTile;\n        if (g.rotateTile) {\n          const rotated = document.createElement('canvas');\n          rotated.width = baseTile.height;\n          rotated.height = baseTile.width;\n          const rctx = rotated.getContext('2d');\n          rctx.translate(rotated.width \/ 2, rotated.height \/ 2);\n          rctx.rotate(-Math.PI \/ 2);\n          rctx.drawImage(baseTile, -baseTile.width \/ 2, -baseTile.height \/ 2);\n          tile = rotated;\n        }\n\n        const raw = document.createElement('canvas');\n        raw.width = g.paperWpx;\n        raw.height = g.paperHpx;\n        const rctx2 = raw.getContext('2d');\n        rctx2.fillStyle = '#FFFFFF';\n        rctx2.fillRect(0, 0, raw.width, raw.height);\n\n        const usedW = g.cols * g.cellWpx + (g.cols - 1) * g.gapPx;\n        const usedH = g.rows * g.cellHpx + (g.rows - 1) * g.gapPx;\n        const startX = (raw.width - usedW) \/ 2;\n        const startY = (raw.height - usedH) \/ 2;\n\n        rctx2.lineWidth = 2;\n        rctx2.strokeStyle = '#999999';\n\n        for (let r = 0; r < g.rows; r++) {\n          for (let c = 0; c < g.cols; c++) {\n            const x = startX + c * (g.cellWpx + g.gapPx);\n            const y = startY + r * (g.cellHpx + g.gapPx);\n            rctx2.drawImage(tile, x, y, g.cellWpx, g.cellHpx);\n            rctx2.strokeRect(x + 1, y + 1, g.cellWpx - 2, g.cellHpx - 2);\n          }\n        }\n\n        if (g.rotateSheetForExport) {\n          sheetCanvas.width = raw.height;\n          sheetCanvas.height = raw.width;\n          const fctx = sheetCanvas.getContext('2d');\n          fctx.translate(sheetCanvas.width \/ 2, sheetCanvas.height \/ 2);\n          fctx.rotate(Math.PI \/ 2);\n          fctx.drawImage(raw, -raw.width \/ 2, -raw.height \/ 2);\n        } else {\n          sheetCanvas.width = raw.width;\n          sheetCanvas.height = raw.height;\n          sheetCanvas.getContext('2d').drawImage(raw, 0, 0);\n        }\n\n        sheetEmpty.style.display = 'none';\n        sheetCanvas.classList.add('css_photopass-active');\n        downloadPngBtn.disabled = false;\n        downloadPdfBtn.disabled = false;\n      });\n\n      \/* ===================== EXPORT ===================== *\/\n      downloadSingleBtn.addEventListener('click', () => {\n        if (!img) return;\n        const single = renderPhotoCanvas();\n        const link = document.createElement('a');\n        link.download = `photo-${photoSize.w}x${photoSize.h}mm.png`;\n        link.href = single.toDataURL('image\/png');\n        link.click();\n      });\n\n      downloadPngBtn.addEventListener('click', () => {\n        const link = document.createElement('a');\n        link.download = 'photo-sheet.png';\n        link.href = sheetCanvas.toDataURL('image\/png');\n        link.click();\n      });\n\n      downloadPdfBtn.addEventListener('click', () => {\n        if (!window.jspdf) {\n          alert('PDF library is still loading, please try again in a moment.');\n          return;\n        }\n        const { jsPDF } = window.jspdf;\n        const cfg = PAPER_LAYOUT[paperSelect.value];\n        const exportSize = cfg.rotateSheetForExport\n          ? { w: paperSize.h, h: paperSize.w }\n          : { w: paperSize.w, h: paperSize.h };\n        const orientation = exportSize.w > exportSize.h ? 'landscape' : 'portrait';\n        const doc = new jsPDF({ unit: 'mm', format: [exportSize.w, exportSize.h], orientation });\n        const dataUrl = sheetCanvas.toDataURL('image\/png');\n        doc.addImage(dataUrl, 'PNG', 0, 0, exportSize.w, exportSize.h);\n        doc.save('photo-sheet.pdf');\n      });\n\n      \/* ===================== INIT ===================== *\/\n      layoutCropCanvas();\n      updateSheetMeta();\n\n    })();\n    <\/script>\n\n    \n<hr \/>\n<p>Generate Passport size photo in your browser, no upload, all your media uploaded here are stay within your browser and when you click on download png or download pdf it will download immediately.<\/p>\n<p>Most of the website available in internet are smartly store the uploaded media to there storage and use for any other purpose but we are 100% guarantee in this webpage your media \/ photo will not upload to any server and stays within your browser.<\/p>\n<p>Making Passport size photo is much difficult for me in 2020 so i was created this tool for the persons who strugles like me to generate passport size photo, globally they accept 35 X 45 mm passport size photo which is default available as first option in this tool, if you want to change the dimension you are freely change the dimension so it will fit to your needs.<\/p>\n<p>If you want hassle free usage and for the testing or daily usage then bookmark this page so it will show on book mark page and never forgot and you will visit exact website and one more help needed from your end is please share this webpage on social media platforms like facebook, instagram, x.com, reddit, pinterest and other platforms, so it will be more useful if we grow<\/p>\n<p>If you have any questions kindly <strong><a href=\"https:\/\/pr.hostingage.com\/contact\/\">contact us through this page<\/a><\/strong>, or mail to us <a href=\"mailto:contact@printatestpage.net\"><strong>contact@printatestpage.net<\/strong><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Thanks in advance<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Generate Passport size photo in your browser, no upload, all your media uploaded here are stay within your browser and when you click on download png or download pdf it &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"\u092a\u093e\u0938\u092a\u094b\u0930\u094d\u091f \u0938\u093e\u0907\u091c\u093c \u092b\u094b\u091f\u094b \u092e\u0947\u0915\u0930\" class=\"read-more button\" href=\"https:\/\/pr.hostingage.com\/hi\/passport-size-photo-maker\/#more-875\" aria-label=\"\u092a\u093e\u0938\u092a\u094b\u0930\u094d\u091f \u0938\u093e\u0907\u091c\u093c \u092b\u094b\u091f\u094b \u092e\u0947\u0915\u0930 \u0915\u0947 \u092c\u093e\u0930\u0947 \u092e\u0947\u0902 \u0914\u0930 \u092a\u0922\u093c\u0947\u0902\">\u0914\u0930 \u092a\u0922\u093c\u0947\u0902<\/a><\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-875","page","type-page","status-publish"],"_links":{"self":[{"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/pages\/875","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/comments?post=875"}],"version-history":[{"count":3,"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/pages\/875\/revisions"}],"predecessor-version":[{"id":897,"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/pages\/875\/revisions\/897"}],"wp:attachment":[{"href":"https:\/\/pr.hostingage.com\/hi\/wp-json\/wp\/v2\/media?parent=875"}],"curies":[{"name":"\u0921\u092c\u094d\u0932\u094d\u092f\u0942\u092a\u0940","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}