Dizikendra

DiziScan — Document Studio
DS
DiziScan Professional Document Studio
0 / 0
📄
Pages appear here
📑

Welcome to DiziScan

Import images or PDF documents, edit pages, run OCR, add signatures and watermarks, then export or print.

or drag & drop files anywhere in this workspace
Ready
Zoom 100%
DiziScan

✍ Add Digital Signature

Mouse/touch দিয়ে নিচে signature আঁকুন অথবা আপনার signature image upload করুন।

✂ Crop Page

Mouse/touch দিয়ে image-এর উপর drag করে crop area select করুন। Corner handle টেনে size পরিবর্তন করুন।

📷 Camera Capture

🔎 OCR Text

`; win.document.open();win.document.write(html);win.document.close(); }async function runOCR(){ const p=currentPage(); if(!p){toast("Select a page first");return} if(!window.Tesseract){toast("OCR engine is loading");return} openModal("ds-ocr-modal"); if($("ds-ocr-text")) $("ds-ocr-text").value=""; if($("ds-ocr-progress")) $("ds-ocr-progress").style.width="0%"; status("OCR processing..."); try{ const result=await Tesseract.recognize( fullyComposedCanvas(p).toDataURL("image/png"), "eng", {logger:m=>{ if(m.status==="recognizing text" && $("ds-ocr-progress")){ $("ds-ocr-progress").style.width=Math.round((m.progress||0)*100)+"%"; } }} ); if($("ds-ocr-text")) $("ds-ocr-text").value=result.data.text||"No text detected."; status("Ready"); }catch(e){ if($("ds-ocr-text")) $("ds-ocr-text").value="OCR error: "+e.message; status("Ready"); } }function copyOCR(){ const text = $("ds-ocr-text") ? $("ds-ocr-text").value : ""; navigator.clipboard?.writeText(text) .then(()=>toast("OCR text copied")) .catch(()=>toast("Copy failed")); }/* Signature Drawing + Upload */ let signatureMode="draw"; let signatureHasInk=false; let signatureUploadedData=null; let signaturePointerDown=false; let signatureLast=null;function setupSignatureCanvas(){ const c=$("ds-signature-canvas"); if(!c) return; const r=c.getBoundingClientRect(); const dpr=Math.max(1,window.devicePixelRatio||1); c.width=Math.max(1,Math.round(r.width*dpr)); c.height=Math.max(1,Math.round(r.height*dpr)); const ctx=c.getContext("2d"); ctx.setTransform(dpr,0,0,dpr,0,0); ctx.clearRect(0,0,r.width,r.height); ctx.strokeStyle="#111827"; ctx.lineWidth=3; ctx.lineCap="round"; ctx.lineJoin="round"; signatureHasInk=false; }function signaturePoint(e){ const c=$("ds-signature-canvas"),r=c.getBoundingClientRect(); return { x:Math.max(0,Math.min(r.width,e.clientX-r.left)), y:Math.max(0,Math.min(r.height,e.clientY-r.top)) }; }function signatureDown(e){ if(signatureMode!=="draw")return; e.preventDefault(); const c=$("ds-signature-canvas"); try{c.setPointerCapture(e.pointerId)}catch(_){} signaturePointerDown=true; signatureLast=signaturePoint(e); signatureHasInk=true; const ctx=c.getContext("2d"); ctx.beginPath(); ctx.arc(signatureLast.x,signatureLast.y,1.2,0,Math.PI*2); ctx.fillStyle="#111827"; ctx.fill(); }function signatureMove(e){ if(!signaturePointerDown || signatureMode!=="draw")return; e.preventDefault(); const c=$("ds-signature-canvas"); const p=signaturePoint(e),ctx=c.getContext("2d"); ctx.strokeStyle="#111827"; ctx.lineWidth=3; ctx.lineCap="round"; ctx.lineJoin="round"; ctx.beginPath(); ctx.moveTo(signatureLast.x,signatureLast.y); ctx.lineTo(p.x,p.y); ctx.stroke(); signatureLast=p; }function signatureUp(e){ if(!signaturePointerDown)return; e.preventDefault(); signaturePointerDown=false; try{$("ds-signature-canvas").releasePointerCapture(e.pointerId)}catch(_){} signatureLast=null; }function clearSignature(){ const c=$("ds-signature-canvas"); if(!c) return; const r=c.getBoundingClientRect(); const dpr=Math.max(1,window.devicePixelRatio||1); const ctx=c.getContext("2d"); ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0,0,c.width,c.height); ctx.setTransform(dpr,0,0,dpr,0,0); signatureHasInk=false; signatureUploadedData=null; signatureMode="draw"; if($("ds-sign-upload")) $("ds-sign-upload").value=""; if($("ds-sign-upload-preview-wrap")) $("ds-sign-upload-preview-wrap").style.display="none"; c.classList.add("ds-signature-active"); }function openSignature(){ if(!currentPage()){toast("Select a page first");return} openModal("ds-sign-modal"); signatureMode="draw"; signatureUploadedData=null; if($("ds-sign-upload-preview-wrap")) $("ds-sign-upload-preview-wrap").style.display="none"; setTimeout(()=>{ setupSignatureCanvas(); if($("ds-signature-canvas")) $("ds-signature-canvas").classList.add("ds-signature-active"); },150); }function imageWithoutWhiteBackground(img){ const c=document.createElement("canvas"); c.width=img.naturalWidth||img.width; c.height=img.naturalHeight||img.height; const ctx=c.getContext("2d"); ctx.drawImage(img,0,0,c.width,c.height); const pixels=ctx.getImageData(0,0,c.width,c.height); const d=pixels.data; for(let i=0;i238 && (max-min)<22){ d[i+3]=0; }else if(min>215 && (max-min)<30){ d[i+3]=Math.max(0,255-(min-215)*6); } } ctx.putImageData(pixels,0,0); return c; }function loadSignatureUpload(file){ if(!file)return; if(!/^image\/(png|jpeg|webp)$/.test(file.type)){ toast("Please upload PNG, JPG or WEBP signature"); return; } const reader=new FileReader(); reader.onload=()=>{ signatureUploadedData=reader.result; signatureMode="upload"; if($("ds-sign-upload-preview")) $("ds-sign-upload-preview").src=signatureUploadedData; if($("ds-sign-upload-preview-wrap")) $("ds-sign-upload-preview-wrap").style.display="block"; if($("ds-signature-canvas")) $("ds-signature-canvas").classList.remove("ds-signature-active"); toast("Signature image loaded"); }; reader.readAsDataURL(file); }function getSignatureForInsert(){ return new Promise(resolve=>{ if(signatureMode==="upload" && signatureUploadedData){ const img=new Image(); img.onload=()=>{ const processed = ($("ds-sign-remove-white") && $("ds-sign-remove-white").checked) ? imageWithoutWhiteBackground(img) : img; resolve({ element: processed, dataUrl: (processed.toDataURL ? processed.toDataURL("image/png") : signatureUploadedData), width: img.naturalWidth || img.width, height: img.naturalHeight || img.height }); }; img.src=signatureUploadedData; return; } if(!signatureHasInk){resolve(null);return} const c=$("ds-signature-canvas"); const out=document.createElement("canvas"); out.width=c.width;out.height=c.height; out.getContext("2d").drawImage(c,0,0); const img=new Image(); img.onload=()=>{ resolve({ element: img, dataUrl: out.toDataURL("image/png"), width: out.width, height: out.height }); }; img.src = out.toDataURL("image/png"); }); }async function saveSignature(){ const p=currentPage();if(!p)return; const sig=await getSignatureForInsert(); if(!sig){ toast("Please draw or upload a signature first"); return; }snapshot(); const targetW = Math.min(p.canvas.width * 0.35, Math.max(180, p.canvas.width * 0.30)); const targetH = sig.height * (targetW / sig.width); const targetX = p.canvas.width - targetW - 40; const targetY = p.canvas.height - targetH - 40;p.signature = { imgElement: sig.element, imgData: sig.dataUrl, x: targetX, y: targetY, width: targetW, height: targetH };closeModal("ds-sign-modal"); render(); toast("Signature added! Drag to reposition."); }const sigCanvas = $("ds-signature-canvas"); if(sigCanvas){ sigCanvas.addEventListener("pointerdown",signatureDown); sigCanvas.addEventListener("pointermove",signatureMove); sigCanvas.addEventListener("pointerup",signatureUp); sigCanvas.addEventListener("pointercancel",signatureUp); }const signDrawTab = $("ds-sign-draw-tab"); if(signDrawTab){ signDrawTab.onclick=()=>{ signatureMode="draw"; signatureUploadedData=null; if($("ds-sign-upload-preview-wrap")) $("ds-sign-upload-preview-wrap").style.display="none"; setTimeout(()=>{ setupSignatureCanvas(); if($("ds-signature-canvas")) $("ds-signature-canvas").classList.add("ds-signature-active"); },30); }; }if($("ds-sign-upload-btn")) $("ds-sign-upload-btn").onclick=()=>$("ds-sign-upload")&&$("ds-sign-upload").click(); if($("ds-sign-upload")) $("ds-sign-upload").onchange=e=>loadSignatureUpload(e.target.files[0]); if($("ds-sign-clear")) $("ds-sign-clear").onclick=clearSignature; if($("ds-sign-save")) $("ds-sign-save").onclick=saveSignature;window.addEventListener("resize",()=>{ if($("ds-sign-modal") && $("ds-sign-modal").classList.contains("open") && signatureMode==="draw"){ setupSignatureCanvas(); } });function undo(){ if(!state.history.length){toast("Nothing to undo");return} const now=state.pages.map(p=>clonePage(p)); state.future.push(now); state.pages=state.history.pop(); state.current=Math.min(state.current,state.pages.length-1); render();toast("Undo"); } function redo(){ if(!state.future.length){toast("Nothing to redo");return} const now=state.pages.map(p=>clonePage(p)); state.history.push(now); state.pages=state.future.pop(); state.current=Math.min(state.current,state.pages.length-1); render();toast("Redo"); }function openModal(id){ const el=$(id); if(el) el.classList.add("open"); } function closeModal(id){ const el=$(id); if(el) el.classList.remove("open"); }/* Interactive Crop */ const cropState={drag:false,resize:false,handle:null,sx:0,sy:0,rect:null}; function cropPointer(e){const r=$("ds-crop-canvas").getBoundingClientRect(),t=e.touches?e.touches[0]:e;return{x:Math.max(0,Math.min(r.width,t.clientX-r.left)),y:Math.max(0,Math.min(r.height,t.clientY-r.top))}} function cropRect(){const o=$("ds-crop-overlay");return{x:parseFloat(o.style.left)||0,y:parseFloat(o.style.top)||0,w:parseFloat(o.style.width)||0,h:parseFloat(o.style.height)||0}} function setCropRect(x,y,w,h){ const c=$("ds-crop-canvas");if(!c)return; const r=c.getBoundingClientRect(); w=Math.max(12,Math.min(w,r.width));h=Math.max(12,Math.min(h,r.height)); x=Math.max(0,Math.min(x,r.width-w));y=Math.max(0,Math.min(y,r.height-h)); const o=$("ds-crop-overlay"); if(o){ o.style.left=x+"px";o.style.top=y+"px";o.style.width=w+"px";o.style.height=h+"px"; } const sx=c.width/r.width,sy=c.height/r.height; if($("crop-x")) $("crop-x").value=Math.round(x*sx); if($("crop-y")) $("crop-y").value=Math.round(y*sy); if($("crop-w")) $("crop-w").value=Math.round(w*sx); if($("crop-h")) $("crop-h").value=Math.round(h*sy); } function openCrop(){ const p=currentPage();if(!p){toast("Import a document first");return} const src=processedCanvas(p),c=$("ds-crop-canvas"); c.width=src.width;c.height=src.height; c.getContext("2d").drawImage(src,0,0); openModal("ds-crop-modal"); setTimeout(()=>{ const r=c.getBoundingClientRect(); if($("ds-crop-overlay")) $("ds-crop-overlay").style.display="block"; setCropRect(0,0,r.width,r.height); },100); } function cropStart(e){ e.preventDefault(); const p=cropPointer(e),t=e.target; cropState.sx=p.x;cropState.sy=p.y; cropState.rect=cropRect(); if(t.classList.contains("ds-crop-handle")){ cropState.resize=true; cropState.handle=[...t.classList].find(x=>["nw","ne","sw","se"].includes(x)); }else cropState.drag=true; } function cropMove(e){ if(!cropState.drag&&!cropState.resize)return; e.preventDefault(); const p=cropPointer(e),r=cropState.rect,dx=p.x-cropState.sx,dy=p.y-cropState.sy; if(cropState.drag){setCropRect(r.x+dx,r.y+dy,r.w,r.h);return} let x=r.x,y=r.y,w=r.w,h=r.h; if(cropState.handle==="se"){w=r.w+dx;h=r.h+dy} if(cropState.handle==="sw"){x=r.x+dx;w=r.w-dx;h=r.h+dy} if(cropState.handle==="ne"){y=r.y+dy;h=r.h-dy;w=r.w+dx} if(cropState.handle==="nw"){x=r.x+dx;w=r.w-dx;y=r.y+dy;h=r.h-dy} setCropRect(x,y,w,h); } function cropEnd(){cropState.drag=false;cropState.resize=false;cropState.handle=null;}const cropOverlay = $("ds-crop-overlay"); if(cropOverlay){ cropOverlay.addEventListener("mousedown",cropStart); cropOverlay.addEventListener("touchstart",cropStart,{passive:false}); } window.addEventListener("mousemove",cropMove); window.addEventListener("touchmove",cropMove,{passive:false}); window.addEventListener("mouseup",cropEnd); window.addEventListener("touchend",cropEnd);["crop-x","crop-y","crop-w","crop-h"].forEach(id=>{ const el = $(id); if(el){ el.addEventListener("input",()=>{ const c=$("ds-crop-canvas");if(!c)return; const r=c.getBoundingClientRect(),sx=r.width/c.width,sy=r.height/c.height; setCropRect(Number($("crop-x").value||0)*sx,Number($("crop-y").value||0)*sy,Number($("crop-w").value||c.width)*sx,Number($("crop-h").value||c.height)*sy); }); } });if($("ds-crop-full")) $("ds-crop-full").onclick=()=>{ const c=$("ds-crop-canvas");if(!c)return; const r=c.getBoundingClientRect();setCropRect(0,0,r.width,r.height); };function applyCrop(){ const p=currentPage();if(!p)return; const c=$("ds-crop-canvas");if(!c)return; const r=c.getBoundingClientRect(),sx=c.width/r.width,sy=c.height/r.height; const x=Math.max(0,Number($("crop-x")?$("crop-x").value:0)||0); const y=Math.max(0,Number($("crop-y")?$("crop-y").value:0)||0); const w=Math.max(1,Math.min(c.width-x,Number($("crop-w")?$("crop-w").value:c.width)||c.width)); const h=Math.max(1,Math.min(c.height-y,Number($("crop-h")?$("crop-h").value:c.height)||c.height)); snapshot(); const out=document.createElement("canvas"); out.width=w;out.height=h; out.getContext("2d").drawImage(c,x,y,w,h,0,0,w,h); p.canvas=out; p.brightness=100;p.contrast=100;p.saturation=100;p.grayscale=false; closeModal("ds-crop-modal"); render(); toast("Crop applied"); }/* Camera */ let cameraStream=null,capturedData=null; async function openCamera(){ if(!navigator.mediaDevices?.getUserMedia){toast("Camera is not supported by this browser.");return} openModal("ds-camera-modal"); try{ const facing = $("ds-camera-facing") ? $("ds-camera-facing").value : "environment"; cameraStream=await navigator.mediaDevices.getUserMedia({video:{facingMode:{ideal:facing},width:{ideal:1920},height:{ideal:1080}},audio:false}); if($("ds-camera-video")) $("ds-camera-video").srcObject=cameraStream; }catch(e){ closeModal("ds-camera-modal");toast("Camera permission was denied or unavailable."); } } function stopCamera(){ if(cameraStream){cameraStream.getTracks().forEach(t=>t.stop());cameraStream=null} if($("ds-camera-video")) $("ds-camera-video").srcObject=null; capturedData=null; if($("ds-camera-preview-wrap")) $("ds-camera-preview-wrap").style.display="none"; if($("ds-camera-use")) $("ds-camera-use").disabled=true; } function takeCameraShot(){ const v=$("ds-camera-video"),c=$("ds-camera-canvas"); if(!v || !v.videoWidth){toast("Camera is not ready");return} c.width=v.videoWidth;c.height=v.videoHeight; c.getContext("2d").drawImage(v,0,0); capturedData=c.toDataURL("image/jpeg",.94); if($("ds-camera-preview")) $("ds-camera-preview").src=capturedData; if($("ds-camera-preview-wrap")) $("ds-camera-preview-wrap").style.display="block"; if($("ds-camera-use")) $("ds-camera-use").disabled=false; toast("Photo captured"); } function useCapturedImage(){ if(!capturedData)return; const img=new Image(); img.onload=()=>{ const c=document.createElement("canvas"); c.width=img.naturalWidth;c.height=img.naturalHeight; c.getContext("2d").drawImage(img,0,0); snapshot(); state.pages.push(makePage(c)); state.current=state.pages.length-1; stopCamera(); closeModal("ds-camera-modal"); render(); toast("Captured page added"); }; img.src=capturedData; }/* Event Attachments */ const openFileInput = () => $("ds-file") && $("ds-file").click(); if($("ds-import-btn")) $("ds-import-btn").onclick = openFileInput; if($("ds-import2")) $("ds-import2").onclick = openFileInput; if($("ds-welcome-import")) $("ds-welcome-import").onclick = openFileInput;if($("ds-file")) $("ds-file").onchange = e => { importFiles([...e.target.files]); e.target.value = ""; };if($("ds-blank")) $("ds-blank").onclick = addBlank; if($("ds-duplicate")) $("ds-duplicate").onclick = duplicate; if($("ds-delete")) $("ds-delete").onclick = () => deletePage(); if($("ds-rotl")) $("ds-rotl").onclick = () => rotate(-90); if($("ds-rotr")) $("ds-rotr").onclick = () => rotate(90); if($("ds-flipx")) $("ds-flipx").onclick = () => flip(true); if($("ds-flipy")) $("ds-flipy").onclick = () => flip(false); if($("ds-crop")) $("ds-crop").onclick = openCrop; if($("ds-sign")) $("ds-sign").onclick = openSignature; if($("ds-sign2")) $("ds-sign2").onclick = openSignature; if($("ds-ocr")) $("ds-ocr").onclick = runOCR; if($("ds-reset")) $("ds-reset").onclick = resetAdjust; if($("ds-adjust-reset")) $("ds-adjust-reset").onclick = resetAdjust; if($("ds-prev")) $("ds-prev").onclick = () => { if(state.current>0){ state.current--; render(); } }; if($("ds-next")) $("ds-next").onclick = () => { if(state.current { state.zoom=Math.min(3, state.zoom+0.1); render(); }; if($("ds-zoom-out")) $("ds-zoom-out").onclick = () => { state.zoom=Math.max(0.25, state.zoom-0.1); render(); }; if($("ds-zoom-reset")) $("ds-zoom-reset").onclick = () => { state.zoom=1; render(); }; if($("ds-undo")) $("ds-undo").onclick = undo; if($("ds-redo")) $("ds-redo").onclick = redo; if($("ds-watermark")) $("ds-watermark").onclick = () => $("ds-water-text") && $("ds-water-text").focus(); if($("ds-apply-watermark")) $("ds-apply-watermark").onclick = applyWatermark; if($("ds-remove-watermark-btn")) $("ds-remove-watermark-btn").onclick = removeWatermark; if($("ds-remove-signature-btn")) $("ds-remove-signature-btn").onclick = removeSignature; if($("ds-image")) $("ds-image").onclick = exportImage; if($("ds-save-image")) $("ds-save-image").onclick = exportImage; if($("ds-export-pdf")) $("ds-export-pdf").onclick = exportPDF; if($("ds-pdf-btn")) $("ds-pdf-btn").onclick = exportPDF; if($("ds-print-btn")) $("ds-print-btn").onclick = printDocument; if($("ds-print2")) $("ds-print2").onclick = printDocument; if($("ds-scan-btn")) $("ds-scan-btn").onclick = openCamera; if($("ds-capture")) $("ds-capture").onclick = openCamera;if($("ds-dpi")) $("ds-dpi").oninput = e => { if($("ds-dpi-value")) $("ds-dpi-value").textContent = e.target.value; if(Number(e.target.value) > 600) toast("1200 DPI is prepared for Pro scanner integration"); };if($("ds-out-dpi")) $("ds-out-dpi").oninput = e => { if($("ds-out-dpi-val")) $("ds-out-dpi-val").textContent = e.target.value; }; if($("ds-target-kb-range")) $("ds-target-kb-range").oninput = e => { if($("ds-target-kb")) $("ds-target-kb").value = e.target.value; }; if($("ds-target-kb")) $("ds-target-kb").oninput = e => { if($("ds-target-kb-range")) $("ds-target-kb-range").value = Math.min(5000, Math.max(50, Number(e.target.value)||50)); }; if($("ds-water-opacity")) $("ds-water-opacity").oninput = e => { if($("ds-water-val")) $("ds-water-val").textContent = e.target.value + "%"; };function adjust(){ const p=currentPage();if(!p)return; p.brightness=Number($("ds-bright")?$("ds-bright").value:100); p.contrast=Number($("ds-contrast")?$("ds-contrast").value:100); p.saturation=Number($("ds-saturation")?$("ds-saturation").value:100); p.grayscale=$("ds-grayscale")?$("ds-grayscale").checked:false; if($("ds-bright-val")) $("ds-bright-val").textContent=p.brightness+"%"; if($("ds-contrast-val")) $("ds-contrast-val").textContent=p.contrast+"%"; if($("ds-saturation-val")) $("ds-saturation-val").textContent=p.saturation+"%"; render(); } ["ds-bright","ds-contrast","ds-saturation","ds-grayscale"].forEach(id=>{ const el = $(id); if(el) el.addEventListener("input", adjust); });if($("ds-crop-apply")) $("ds-crop-apply").onclick = applyCrop; if($("ds-ocr-copy")) $("ds-ocr-copy").onclick = copyOCR;if($("ds-camera-shot")) $("ds-camera-shot").onclick = takeCameraShot; if($("ds-camera-use")) $("ds-camera-use").onclick = useCapturedImage; if($("ds-camera-facing")) $("ds-camera-facing").onchange = async()=>{ if(cameraStream){ stopCamera(); await openCamera(); } }; if($("ds-camera-flash")) $("ds-camera-flash").onclick = async()=>{ const t=cameraStream?.getVideoTracks?.()[0], cap=t?.getCapabilities?.(); if(cap?.torch){ await t.applyConstraints({advanced:[{torch:true}]}); toast("Flash toggled"); }else toast("Flash control is not available on this device"); };document.querySelectorAll("[data-close]").forEach(b=>{ b.onclick=()=>{ if(b.dataset.close==="ds-camera-modal") stopCamera(); closeModal(b.dataset.close); }; });const stage = $("ds-stage"); if(stage){ stage.addEventListener("dragover", e => { e.preventDefault(); stage.classList.add("dragover"); }); stage.addEventListener("dragleave", () => stage.classList.remove("dragover")); stage.addEventListener("drop", e => { e.preventDefault(); stage.classList.remove("dragover"); importFiles([...e.dataTransfer.files]); }); }window.addEventListener("keydown", e => { if((e.ctrlKey||e.metaKey) && e.key.toLowerCase()==="z"){ e.preventDefault(); undo(); } if((e.ctrlKey||e.metaKey) && e.key.toLowerCase()==="y"){ e.preventDefault(); redo(); } if(e.key==="Delete" && !["INPUT","TEXTAREA"].includes(document.activeElement.tagName)) deletePage(); });render();})();
Scroll to Top