UNPKG

document-scanner-vue

Version:

Vue 3 Document Scanner with OpenCV.js - Mobile optimized with camera/gallery support

86 lines 99.9 kB
"use strict";var We=Object.create;var he=Object.defineProperty;var ze=Object.getOwnPropertyDescriptor;var Ge=Object.getOwnPropertyNames;var je=Object.getPrototypeOf,Xe=Object.prototype.hasOwnProperty;var qe=(o,t,n)=>t in o?he(o,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):o[t]=n;var Ye=(o,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Ge(t))!Xe.call(o,s)&&s!==n&&he(o,s,{get:()=>t[s],enumerable:!(r=ze(t,s))||r.enumerable});return o};var Je=(o,t,n)=>(n=o!=null?We(je(o)):{},Ye(t||!o||!o.__esModule?he(n,"default",{value:o,enumerable:!0}):n,o));var ye=(o,t,n)=>qe(o,typeof t!="symbol"?t+"":t,n);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),Pe=require("@vueuse/core"),Ze=require("jspdf");function Ke(o){if(!cv||!cv.imread)throw console.error("OpenCV (cv.imread) is not available."),new Error("OpenCV (cv.imread) is not available.");return cv.imread(o)}function Qe(o){if(!cv||!cv.imshow)throw console.error("OpenCV (cv.imshow) is not available."),new Error("OpenCV (cv.imshow) is not available.");const t=document.createElement("canvas");return cv.imshow(t,o),t.toDataURL("image/jpeg")}function et(o,t,n,r,s){let a=0;const c=t/r;a+=c*1e6;const m=[.707,1,1.414];let d=0;for(const w of m){const I=Math.abs(n-w);I<.3&&(d=Math.max(d,(.3-I)*1e5))}a+=d,s&&(a+=5e4),c>.1&&(a+=1e5),c>.2&&(a+=2e5),(n<.05||n>20)&&(a-=15e4);const g=cv.boundingRect(o),R=Math.min(g.width,g.height),P=Math.max(g.width,g.height);return R>10&&P>20&&(a+=25e3),R>50&&P>100&&(a+=5e4),R>100&&P>200&&(a+=75e3),t>10&&(a+=1e4),a}async function ue(o){if(!cv||!cv.Mat||!cv.cvtColor||!cv.GaussianBlur||!cv.Canny||!cv.findContours||!cv.arcLength||!cv.approxPolyDP||!cv.contourArea)return console.error("A required OpenCV function is not available in detectDocumentCorners."),null;let t=null,n=null,r=null,s=null,a=null;try{const c=new Image;c.src=o,await new Promise((h,p)=>{c.onload=()=>h(),c.onerror=L=>p(new Error("Image load failed in detectDocumentCorners"))}),t=cv.imread(c);const m=t.cols,d=t.rows,g=m*d;console.log(`[DEBUG] Original image dimensions: ${m}x${d}, Total area: ${g}`);let R=t,P=1;const w=1200,I=Math.max(m,d);if(I>w){P=w/I;const h=Math.round(m*P),p=Math.round(d*P);n=new cv.Mat;const L=new cv.Size(h,p);cv.resize(t,n,L,0,0,cv.INTER_AREA),R=n,console.log(`[DEBUG] Downsampled to: ${h}x${p} (factor: ${P.toFixed(3)}) for processing`)}else console.log("[DEBUG] No downsampling needed, processing at original size");r=new cv.Mat,cv.cvtColor(R,r,cv.COLOR_RGBA2GRAY,0),s=new cv.Mat,cv.GaussianBlur(r,s,new cv.Size(5,5),0,0,cv.BORDER_DEFAULT);const A=R.cols*R.rows;console.log(`[DEBUG] Processing dimensions: ${R.cols}x${R.rows}, Processing area: ${A}`);const F=g>8e6,$=g>2e6;console.log(`[DEBUG] Image classification: ${F?"High-res (likely mobile camera)":$?"Medium-res":"Low-res (likely compressed)"}`);const l=h=>F?h*.1:$?h*.5:h,i=(h,p)=>F?{low:Math.max(1,Math.round(h*.6)),high:Math.max(5,Math.round(p*.7))}:$?{low:Math.max(1,Math.round(h*.8)),high:Math.max(5,Math.round(p*.9))}:{low:h,high:p},u=[{name:"Standard",cannyLow:i(50,150).low,cannyHigh:i(50,150).high,areaThreshold:l(.05),minAspectRatio:.5,maxAspectRatio:2,approxEpsilon:.015},{name:"Relaxed",cannyLow:i(30,100).low,cannyHigh:i(30,100).high,areaThreshold:l(.03),minAspectRatio:.3,maxAspectRatio:3,approxEpsilon:.02},{name:"VeryRelaxed",cannyLow:i(75,200).low,cannyHigh:i(75,200).high,areaThreshold:l(.01),minAspectRatio:.2,maxAspectRatio:4,approxEpsilon:.025},{name:"Aggressive",cannyLow:i(20,80).low,cannyHigh:i(20,80).high,areaThreshold:l(.005),minAspectRatio:.1,maxAspectRatio:5,approxEpsilon:.03},{name:"DocumentFocused",cannyLow:i(40,120).low,cannyHigh:i(40,120).high,areaThreshold:l(.15),minAspectRatio:.4,maxAspectRatio:2.5,approxEpsilon:.02,useDocumentHeuristics:!0,usePreprocessing:!0},{name:"Enhanced",cannyLow:i(25,75).low,cannyHigh:i(25,75).high,areaThreshold:l(.08),minAspectRatio:.3,maxAspectRatio:3,approxEpsilon:.025,useDocumentHeuristics:!0,usePreprocessing:!0}];for(const h of u){const p=A*h.areaThreshold;console.log(`[DEBUG] Trying ${h.name} strategy... (adaptive threshold: ${(h.areaThreshold*100).toFixed(4)}%, min area: ${p.toFixed(0)} pixels)`);let L=null,T=null,_=null;try{L=new cv.Mat;let z=s;if(h.usePreprocessing){console.log(`[DEBUG] ${h.name}: Applying preprocessing (CLAHE contrast enhancement)`),z=new cv.Mat;const S=new cv.CLAHE(2,new cv.Size(8,8));S.apply(s,z),S.delete()}if(cv.Canny(z,L,h.cannyLow,h.cannyHigh),T=new cv.MatVector,_=new cv.Mat,cv.findContours(L,T,_,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE),console.log(`[DEBUG] ${h.name}: Found ${T.size()} initial contours.`),T.size()===0){h.usePreprocessing&&z!==s&&z.delete();continue}let E=0,D={notFourSided:0,notConvex:0,tooSmall:0,badAspectRatio:0,passed:0},b=null,U=-1;for(let S=0;S<T.size();++S){const q=T.get(S),G=cv.arcLength(q,!0),O=new cv.Mat;if(cv.approxPolyDP(q,O,h.approxEpsilon*G,!0),O.rows!==4){D.notFourSided++,O.delete();continue}E++;const j=cv.isContourConvex(O),X=cv.contourArea(O),J=cv.boundingRect(O),Z=J.width/J.height;if(!j){D.notConvex++,E<=10&&console.log(`[DEBUG] ${h.name} Contour ${S} (4-sided): REJECTED - Not convex. Area=${X.toFixed(0)}, AR=${Z.toFixed(2)}`),O.delete();continue}if(X<p){D.tooSmall++,E<=10&&console.log(`[DEBUG] ${h.name} Contour ${S} (4-sided): REJECTED - Too small. Area=${X.toFixed(0)} < ${p.toFixed(0)}, AR=${Z.toFixed(2)}`),O.delete();continue}if(Z<h.minAspectRatio||Z>h.maxAspectRatio){D.badAspectRatio++,E<=10&&console.log(`[DEBUG] ${h.name} Contour ${S} (4-sided): REJECTED - Bad aspect ratio. Area=${X.toFixed(0)}, AR=${Z.toFixed(2)} (Range: ${h.minAspectRatio}-${h.maxAspectRatio})`),O.delete();continue}let oe=X;h.useDocumentHeuristics&&(oe=et(O,X,Z,A,j)),D.passed++;const le=j?"CONVEX":"NON-CONVEX",se=h.useDocumentHeuristics?`, Score=${oe.toFixed(0)}`:"";console.log(`[DEBUG] ${h.name} Contour ${S} (4-sided): PASSED ALL FILTERS. Area=${X.toFixed(0)}, AR=${Z.toFixed(2)}, W=${J.width}, H=${J.height}, ${le}${se}`),oe>U&&(console.log(`[DEBUG] ${h.name} NEW BEST CONTOUR FOUND (Contour ${S}): Area=${X.toFixed(0)}, AR=${Z.toFixed(2)}, W=${J.width}, H=${J.height}, ${le}${se}`),U=oe,b&&b.delete(),b=O.clone()),O.delete()}if(console.log(`[DEBUG] ${h.name} Summary: 4-sided candidates=${E}, Rejections: notConvex=${D.notConvex}, tooSmall=${D.tooSmall}, badAR=${D.badAspectRatio}, passed=${D.passed}`),h.usePreprocessing&&z!==s&&z.delete(),b){console.log(`[DEBUG] ${h.name} strategy SUCCESS! Found suitable contour with score ${U.toFixed(0)}.`),a&&a.delete(),a=b;break}else console.log(`[DEBUG] ${h.name} strategy failed, trying next...`)}finally{L&&L.delete(),T&&T.delete(),_&&_.delete()}}if(!a)return console.log("[DEBUG] All strategies failed - no suitable 4-point contour found."),null;const f=[];for(let h=0;h<a.rows;++h){const p=a.data32S[h*2],L=a.data32S[h*2+1],T=P<1?Math.round(p/P):p,_=P<1?Math.round(L/P):L;f.push({x:T,y:_})}console.log(`[DEBUG] Scaling coordinates back to original size (factor: ${(1/P).toFixed(3)})`),f.sort((h,p)=>h.y-p.y);const v=f.slice(0,2).sort((h,p)=>h.x-p.x),M=f.slice(2,4).sort((h,p)=>h.x-p.x);return[v[0],v[1],M[1],M[0]]}catch(c){return console.error("Error in detectDocumentCorners:",c),null}finally{t&&t.delete(),n&&n.delete(),r&&r.delete(),s&&s.delete(),a&&a.delete()}}async function $e(o,t,n){return new Promise((r,s)=>{const a=new Image;a.onload=()=>{try{console.log("[cvUtils] Image loaded for perspective transform. Input corners:",t,"Options:",n);const[c,m,d,g]=t,R=Math.sqrt((m.x-c.x)**2+(m.y-c.y)**2),P=Math.sqrt((d.x-g.x)**2+(d.y-g.y)**2);let w=Math.max(Math.floor(R),Math.floor(P));const I=Math.sqrt((g.x-c.x)**2+(g.y-c.y)**2),A=Math.sqrt((d.x-m.x)**2+(d.y-m.y)**2);let F=Math.max(Math.floor(I),Math.floor(A)),$=n!=null&&n.outputWidth&&n.outputWidth>0?n.outputWidth:w,l=n!=null&&n.outputHeight&&n.outputHeight>0?n.outputHeight:F;if(($<=0||l<=0)&&(console.warn("[cvUtils] Calculated or provided output dimensions are invalid, falling back to detected max dimensions."),$=w,l=F,$<=0||l<=0)){console.error("[cvUtils] Fallback dimensions also invalid. Cannot process."),s(new Error("Invalid output dimensions for perspective transform."));return}console.log(`[cvUtils] Effective output dimensions for transform: ${$}x${l}`);const i=cv.matFromArray(4,1,cv.CV_32FC2,[c.x,c.y,m.x,m.y,d.x,d.y,g.x,g.y]),u=cv.matFromArray(4,1,cv.CV_32FC2,[0,0,$-1,0,$-1,l-1,0,l-1]),f=cv.getPerspectiveTransform(i,u),v=cv.imread(a),M=new cv.Mat,x=new cv.Size($,l);cv.warpPerspective(v,M,f,x,cv.INTER_LINEAR,cv.BORDER_CONSTANT,new cv.Scalar);const h=document.createElement("canvas");cv.imshow(h,M);const p=h.toDataURL("image/jpeg");v.delete(),M.delete(),f.delete(),i.delete(),u.delete(),r({imageDataURL:p,processedWidth:$,processedHeight:l})}catch(c){console.error("[cvUtils] Error in applyPerspectiveTransform:",c),s(c)}},a.onerror=c=>{console.error("[cvUtils] Failed to load image for perspective transform:",c),s(new Error("Image failed to load for processing."))},a.src=o})}async function Le(o,t){return!cv||!cv.rotate?(console.error("OpenCV rotation functions not available"),o):new Promise((n,r)=>{const s=new Image;s.onload=()=>{let a=null,c=null;try{switch(a=Ke(s),c=new cv.Mat,(t%360+360)%360){case 0:a.copyTo(c);break;case 90:cv.rotate(a,c,cv.ROTATE_90_CLOCKWISE);break;case 180:cv.rotate(a,c,cv.ROTATE_180);break;case 270:cv.rotate(a,c,cv.ROTATE_90_COUNTERCLOCKWISE);break;default:console.warn(`Unsupported rotation angle ${t}. Returning original image.`),a.copyTo(c);break}const d=Qe(c);n(d)}catch(m){console.error("Error rotating image:",m),r(m)}finally{a&&a.delete(),c&&c.delete()}},s.onerror=()=>{r(new Error("Failed to load image for rotation"))},s.src=o})}function ke(o){if(!o||o.length!==4)return console.warn("sortCornersForConsistentOrientation: Invalid corners provided."),o;const t=[...o],n=t.reduce((d,g)=>g.x+g.y<d.x+d.y?g:d),r=t.reduce((d,g)=>g.x+g.y>d.x+d.y?g:d),s=t.filter(d=>d!==n&&d!==r),a=s[0].y<s[1].y?s[0]:s[0].y>s[1].y?s[1]:s[0].x>s[1].x?s[0]:s[1],c=s.find(d=>d!==a),m=[n,a,r,c];return console.log("[IP] Sorted corners for consistent orientation:",{original:o,sorted:m}),m}function de(o,t,n,r){if(!o||o.length!==4)return console.warn("transformCornersForRotation: Invalid corners provided."),null;const s=(t%360+360)%360,a=o.map(c=>{switch(s){case 0:return{x:c.x,y:c.y};case 90:return{x:r-c.y,y:c.x};case 180:return{x:n-c.x,y:r-c.y};case 270:return{x:c.y,y:n-c.x};default:return console.warn(`transformCornersForRotation: Unsupported rotation angle ${t}`),{x:c.x,y:c.y}}});return a.length===4?[a[0],a[1],a[2],a[3]]:(console.error("transformCornersForRotation: Failed to produce 4 rotated coordinates."),null)}function tt(o,t,n,r){if(!o||o.length!==4)return console.warn("transformDisplayCornersToBase: Invalid displayCorners provided."),null;const s=(t%360+360)%360;let a,c;s===90||s===270?(a=r,c=n):(a=n,c=r);const m=o.map(d=>{switch(s){case 0:return{x:d.x,y:d.y};case 90:return{x:d.y,y:a-d.x};case 180:return{x:a-d.x,y:c-d.y};case 270:return{x:c-d.y,y:d.x};default:return console.warn(`transformDisplayCornersToBase: Unsupported rotation angle ${t}`),{x:d.x,y:d.y}}});return m.length===4?[m[0],m[1],m[2],m[3]]:(console.error("transformDisplayCornersToBase: Failed to produce 4 base coordinates."),null)}function Ne(o){if(!o||o.length!==4)return 0;const t=o;return .5*Math.abs(t[0].x*t[1].y+t[1].x*t[2].y+t[2].x*t[3].y+t[3].x*t[0].y-(t[1].x*t[0].y+t[2].x*t[1].y+t[3].x*t[2].y+t[0].x*t[3].y))}function ge(o,t,n){return[{x:n,y:n},{x:o-n,y:n},{x:o-n,y:t-n},{x:n,y:t-n}]}console.log("[UIP] opencvUtils imported:",typeof ue,typeof $e);const zn=[{name:"A4 Portrait",ratio:1/Math.sqrt(2)},{name:"A4 Landscape",ratio:Math.sqrt(2)},{name:"Letter Portrait",ratio:8.5/11},{name:"Letter Landscape",ratio:11/8.5},{name:"Legal Portrait",ratio:8.5/14},{name:"Legal Landscape",ratio:14/8.5},{name:"Square",ratio:1},{name:"ID Card/Credit Card",ratio:85.6/53.98},{name:"Business Card (US)",ratio:3.5/2},{name:"Business Card (EU)",ratio:85/55}];const nt=!1;function Ie(o){const t=e.ref(null),n=e.ref(null),r=e.ref(0),s=e.ref(!1),a=e.readonly(t),c=e.readonly(n),m=e.readonly(r),d=e.readonly(s);async function g(l){if(!o.value||!l)return console.warn("[ImgProc] OpenCV not ready or no image data URL for edge detection."),null;s.value=!0;try{const i=await ue(l);return i&&i.length===4?(t.value=Object.freeze(i),n.value=Object.freeze(i),t.value):(console.warn("[ImgProc] Edge detection did not return 4 corners."),t.value=null,n.value=null,null)}catch(i){return console.error("[ImgProc] Error during edge detection:",i),t.value=null,n.value=null,null}finally{s.value=!1}}async function R(l,i,u){if(!o.value||!l||!i||i.length!==4)return console.warn("[ImgProc] Prerequisites for perspective transform not met."),null;s.value=!0;try{const f=ke([...i]);let v,M;if(!nt){if(u){const[h,p,L,T]=f,_=(G,O)=>Math.sqrt((G.x-O.x)**2+(G.y-O.y)**2),z=_(h,p),E=_(T,L),D=Math.max(Math.floor(z),Math.floor(E)),b=_(h,T),U=_(p,L),S=Math.max(Math.floor(b),Math.floor(U)),q=Math.max(D,S);u.ratio<1?(M=q,v=Math.round(M*u.ratio)):(v=q,M=Math.round(v/u.ratio)),console.log(`[ImgProc] Using selected format: ${u.name}. Target output: ${v}x${M}`)}}const x=await $e(l,f,{outputWidth:v,outputHeight:M});return x&&x.imageDataURL?x:null}catch(f){return console.error("[ImgProc] Error during perspective transform:",f),null}finally{s.value=!1}}function P(l){l&&l.length===4?n.value=Object.freeze([...l]):l===null?n.value=null:console.warn("[ImgProc] Attempted to set invalid adjusted corners.")}function w(){console.log("[ImgProc] resetActiveImageState called"),t.value=null,n.value=null,r.value=0,s.value=!1}function I(l){r.value=(l%360+360)%360}function A(l){l?(console.log("[ImgProc] Syncing state from page:",l.id),t.value=l.corners?Object.freeze([...l.corners]):null,n.value=l.corners?Object.freeze([...l.corners]):null,r.value=l.currentRotation):(console.log("[ImgProc] No page to sync from, resetting active image state."),w())}async function F(l,i){if(!o.value||!l)return console.warn("[ImgProc] OpenCV not ready or no image data URL for rotation."),l;try{return s.value=!0,await Le(l,i)}catch(u){return console.error("[ImgProc] Error during image rotation:",u),l}finally{s.value=!1}}function $(l,i,u,f){if(!l||l.length!==4)return null;const v=de([...l],i,u,f);return Object.freeze(v)}return{detectedCorners:a,adjustedCorners:c,currentRotation:m,isProcessing:d,detectEdges:g,performPerspectiveTransform:R,setAdjustedCorners:P,resetActiveImageState:w,setRotation:I,syncStateFromPage:A,rotateImageData:F,transformCornersForRotationIncrement:$}}function ot(o){return!o||o.length!==4?(console.warn("[calculateOriginalAspectRatio] Requires 4 corner points."),null):at(o)}function at(o){const[t,n,r,s]=o,a=(w,I)=>Math.sqrt(Math.pow(I.x-w.x,2)+Math.pow(I.y-w.y,2)),c=a(t,n),m=a(s,r),d=Math.max(c,m),g=a(t,s),R=a(n,r),P=Math.max(g,R);return P===0?(console.warn("[calculateSimpleAspectRatio] Calculated effective height is zero."),1):d/P}const rt=Object.freeze(Object.defineProperty({__proto__:null,calculateOriginalAspectRatio:ot,useImageProcessing:Ie},Symbol.toStringTag,{value:"Module"}));let Re=(o=21)=>crypto.getRandomValues(new Uint8Array(o)).reduce((t,n)=>(n&=63,n<36?t+=n.toString(36):n<62?t+=(n-26).toString(36).toUpperCase():n>62?t+="-":t+="_",t),"");function K(o){o&&o.startsWith("blob:")?URL.revokeObjectURL(o):console.warn("Attempted to revoke a non-blob URL or an empty URL:",o)}function Ae(){const o=e.ref([]),t=e.ref(null),n=e.computed(()=>t.value&&o.value.find(l=>l.id===t.value)||null),r=l=>o.value.find(i=>i.id===l),s=e.computed(()=>e.readonly(o.value)),a=e.computed(()=>{const l=t.value?o.value.findIndex(f=>f.id===t.value):-1,i=l!==-1?l+1:o.value.length>0?1:0,u=o.value.length;return`${i}/${u}`}),c=e.computed(()=>o.value.length),m=async(l,i)=>{let u=null;if(typeof window<"u"&&!window.cv)throw new Error("OpenCV is not loaded yet. Please wait for the scanner to initialize.");try{i("Loading image...",0),u=URL.createObjectURL(l);const f=new Image;return await new Promise(async(M,x)=>{f.onload=async()=>{try{console.log(`[usePageManager] Image loaded successfully for ${l.name}, dimensions: ${f.naturalWidth}x${f.naturalHeight}`),i("Analyzing document...",20),console.log(`[usePageManager] Starting corner detection for ${l.name}...`);const h=await ue(u);console.log(`[usePageManager] Corner detection completed for ${l.name}, found:`,(h==null?void 0:h.length)||0,"corners"),i("Processing corners...",40);let p;h&&h.length===4?p=[h[0],h[1],h[2],h[3]]:(console.warn(`[usePageManager] Corners not detected or invalid for ${l.name}, using fallback.`),p=ge(f.naturalWidth,f.naturalHeight,32)),i("Auto-processing document...",60);const L=Re(),T={id:L,originalFile:l,originalFileName:l.name,originalImageDataURL:u,originalWidth:f.naturalWidth,originalHeight:f.naturalHeight,corners:p,currentRotation:0,processedImageDataURL:null,processedWidth:null,processedHeight:null,timestampProcessed:null,mode:"preview",timestampAdded:Date.now(),outputFormat:{name:"Letter Portrait",ratio:8.5/11,dimensions:'8.5" × 11"',category:"standard"}};o.value.push(T);try{i("Processing document...",80);const{useImageProcessing:_}=await Promise.resolve().then(()=>rt),{ref:z}=await import("vue"),E=z(!0),{performPerspectiveTransform:D}=_(E),b=await D(u,p,T.outputFormat);if(b&&b.imageDataURL){const U=o.value.findIndex(S=>S.id===L);U!==-1&&(o.value[U]={...o.value[U],processedImageDataURL:b.imageDataURL,processedWidth:b.processedWidth,processedHeight:b.processedHeight,timestampProcessed:Date.now(),mode:"preview"}),console.log(`[usePageManager] Auto-processed page ${L} successfully`)}else{console.warn(`[usePageManager] Auto-processing failed for ${L}, keeping in edit mode`);const U=o.value.findIndex(S=>S.id===L);U!==-1&&(o.value[U]={...o.value[U],mode:"edit"})}}catch(_){console.warn(`[usePageManager] Auto-processing error for ${L}:`,_);const z=o.value.findIndex(E=>E.id===L);z!==-1&&(o.value[z]={...o.value[z],mode:"edit"})}i("Complete!",100),M(L)}catch(h){console.error(`[usePageManager] Error processing image ${l.name} after load:`,h),u&&K(u),x(h)}},f.onerror=h=>{console.error(`[usePageManager] Error loading image ${l.name} (img.onerror):`,h),u&&K(u),x(new Error(`Failed to load image: ${l.name}`))},u?f.src=u:x(new Error("Failed to create object URL for image"))})}catch(f){throw console.error(`[usePageManager] Failed to process file ${l.name} into a Page object:`,f),u&&K(u),f}},d=async l=>{const i=[];for(const u of l){let f=null;try{f=URL.createObjectURL(u);const v=new Image,M=new Promise(async(x,h)=>{v.onload=async()=>{try{const p=await ue(f);let L;p&&p.length===4?L=[p[0],p[1],p[2],p[3]]:(console.warn(`[usePageManager] Corners not detected or invalid for ${u.name}, using fallback.`),L=ge(v.naturalWidth,v.naturalHeight,32));const T={id:Re(),originalFile:u,originalFileName:u.name,originalImageDataURL:f,originalWidth:v.naturalWidth,originalHeight:v.naturalHeight,corners:L,currentRotation:0,processedImageDataURL:null,processedWidth:null,processedHeight:null,timestampProcessed:null,mode:"edit",timestampAdded:Date.now(),outputFormat:{name:"Letter Portrait",ratio:8.5/11,dimensions:'8.5" × 11"',category:"standard"}};o.value.push(T),i.push(T.id),x()}catch(p){console.error(`[usePageManager] Error processing image ${u.name} after load:`,p),f&&K(f),h(p)}},v.onerror=p=>{console.error(`[usePageManager] Error loading image ${u.name} (img.onerror):`,p),f&&K(f),h(new Error(`Failed to load image: ${u.name}`))}});v.src=f,await M}catch(v){throw console.error(`[usePageManager] Failed to process file ${u.name} into a Page object:`,v),f&&K(f),v}}return i.length>0&&!t.value?g(i[0]):i.length>0&&t.value,i},g=l=>{if(console.log("[usePageManager] Selecting page:",l),l===null){t.value=null;return}o.value.some(u=>u.id===l)?t.value=l:(console.warn(`[usePageManager] Attempted to select non-existent page: ${l}`),o.value.length>0?t.value=o.value[0].id:t.value=null)},R=(l,i)=>{const u=o.value.findIndex(f=>f.id===l);if(u!==-1){const f=o.value[u];let v={...f},M=!1;const x=f.corners?[...f.corners]:null;if(i.currentRotation!==void 0&&i.currentRotation!==v.currentRotation)if(console.log(`[usePageManager] Updating rotation from ${v.currentRotation} to ${i.currentRotation} for page ${l}`),v.currentRotation=i.currentRotation,M=!0,x){const h=de(x,v.currentRotation,v.originalWidth,v.originalHeight);h?(v.corners=h,console.log("[usePageManager] Corners transformed due to rotation change:",v.corners)):(console.warn(`[usePageManager] Corner transformation returned null for rotation ${v.currentRotation}. Setting corners to null.`),v.corners=null)}else v.corners=null;i.corners!==void 0&&(console.log(`[usePageManager] Explicitly updating corners for page ${l} to:`,i.corners,`(rotation: ${v.currentRotation})`),v.corners=i.corners?[...i.corners]:null,M||(M=!0)),M&&(console.log(`[usePageManager] Resetting processed image for page ${l} due to rotation or corner change.`),v.processedImageDataURL=null,v.processedWidth=null,v.processedHeight=null,v.timestampProcessed=null,v.mode==="preview"&&(v.mode="edit")),i.processedImageDataURL!==void 0&&!M&&(v.processedImageDataURL=i.processedImageDataURL,v.processedWidth=i.processedWidth!==void 0?i.processedWidth:null,v.processedHeight=i.processedHeight!==void 0?i.processedHeight:null,i.processedImageDataURL?(v.timestampProcessed=Date.now(),v.mode=i.mode!==void 0?i.mode:"preview"):(v.timestampProcessed=null,v.mode="edit")),i.mode!==void 0&&i.mode!==v.mode&&(v.mode=i.mode),i.outputFormat!==void 0&&(v.outputFormat=i.outputFormat,console.log(`[usePageManager] Updated outputFormat for page ${l}:`,i.outputFormat)),o.value.splice(u,1,v),console.log("[usePageManager] Updated page data for:",l,JSON.parse(JSON.stringify(i)),"Resulting page:",JSON.parse(JSON.stringify(v)))}else console.warn(`[usePageManager] Cannot update page data: Page with ID ${l} not found.`)},P=l=>{var u,f;const i=o.value.findIndex(v=>v.id===l);if(i!==-1){const v=o.value[i];if((u=v.originalImageDataURL)!=null&&u.startsWith("blob:")&&K(v.originalImageDataURL),(f=v.processedImageDataURL)!=null&&f.startsWith("blob:")&&K(v.processedImageDataURL),o.value.splice(i,1),console.log(`[usePageManager] Deleted page: ${l}`),t.value===l)if(o.value.length>0){const M=Math.min(i,o.value.length-1);g(o.value[M].id)}else g(null)}else console.warn(`[usePageManager] Cannot delete page: Page with ID ${l} not found.`)},w=()=>{o.value.forEach(l=>{var i,u;(i=l.originalImageDataURL)!=null&&i.startsWith("blob:")&&K(l.originalImageDataURL),(u=l.processedImageDataURL)!=null&&u.startsWith("blob:")&&K(l.processedImageDataURL)}),o.value=[],t.value=null,console.log("[usePageManager] All pages cleared.")},I=(l,i)=>{if(l<0||l>=o.value.length||i<0||i>=o.value.length){console.warn(`[usePageManager] Invalid reorder indices: from ${l} to ${i}`);return}if(l===i)return;const u=[...o.value],[f]=u.splice(l,1);u.splice(i,0,f),o.value=u,console.log(`[usePageManager] Reordered page from index ${l} to ${i}`)},A=()=>{if(o.value.length===0){console.warn("[usePageManager] No pages available to navigate");return}const l=t.value?o.value.findIndex(u=>u.id===t.value):-1;if(l===-1){g(o.value[0].id);return}const i=Math.min(l+1,o.value.length-1);i!==l?(g(o.value[i].id),console.log(`[usePageManager] Moved to next page: index ${i}`)):console.log("[usePageManager] Already at last page")},F=()=>{if(o.value.length===0){console.warn("[usePageManager] No pages available to navigate");return}const l=t.value?o.value.findIndex(u=>u.id===t.value):-1;if(l===-1){g(o.value[0].id);return}const i=Math.max(l-1,0);i!==l?(g(o.value[i].id),console.log(`[usePageManager] Moved to previous page: index ${i}`)):console.log("[usePageManager] Already at first page")},$=()=>{o.value.forEach(l=>{var i,u;if((i=l.originalImageDataURL)!=null&&i.startsWith("blob:"))try{K(l.originalImageDataURL)}catch(f){console.warn("Error revoking original URL",f)}if((u=l.processedImageDataURL)!=null&&u.startsWith("blob:"))try{K(l.processedImageDataURL)}catch(f){console.warn("Error revoking processed URL",f)}})};return{pages:s,activePageId:e.readonly(t),currentPage:n,pageCountDisplay:a,totalPages:c,addFilesAsPages:d,addFileAsPageWithProgress:m,selectPage:g,updatePageData:R,deletePage:P,getPageById:r,clearAllPages:w,reorderPages:I,moveToNextPage:A,moveToPrevPage:F,cleanupAllObjectURLs:$}}function st(o){const t=e.ref(!1),n=e.ref(""),r=e.ref(0);return{isLoading:t,processingStatus:n,processingProgress:r,handleFilesSelected:async a=>{if(console.log("[useDocumentProcessing] handleFilesSelected with files:",a.length),a.length!==0){console.log("[useDocumentProcessing] Proceeding with file processing..."),console.log("[useDocumentProcessing] Setting loading state..."),t.value=!0,n.value="Processing images...",r.value=0;try{console.log("[useDocumentProcessing] Getting current page count...");const c=o.pageManager.pages.value.length;console.log("[useDocumentProcessing] Current page count:",c),console.log("[useDocumentProcessing] Phase 1: Setting initial status..."),n.value="Loading images...",r.value=20;const m=a.length;console.log("[useDocumentProcessing] Starting to process",m,"files...");for(let g=0;g<m;g++){const R=a[g];console.log(`[useDocumentProcessing] Processing file ${g+1}/${m}:`,R.name,"size:",R.size,"type:",R.type),n.value=`Processing image ${g+1} of ${m}...`,r.value=20+g/m*60;try{console.log(`[useDocumentProcessing] Calling addFileAsPageWithProgress for file ${g+1}...`),await o.pageManager.addFileAsPageWithProgress(R,(P,w)=>{console.log(`[useDocumentProcessing] Progress callback - Status: ${P}, Progress: ${w}`),n.value=P,r.value=20+g/m*60+w/m*60}),console.log(`[useDocumentProcessing] Successfully processed file ${g+1}:`,R.name)}catch(P){throw console.error(`[useDocumentProcessing] Error processing file ${g+1} (${R.name}):`,P),P}}console.log("[useDocumentProcessing] All files processed, finalizing..."),n.value="Finalizing...",r.value=90;const d=o.pageManager.pages.value;if(console.log("[useDocumentProcessing] New pages count:",d.length,"vs previous:",c),d.length>c){const g=d[c].id;console.log("[useDocumentProcessing] Selecting newly added page:",g),o.pageManager.selectPage(g)}r.value=100,n.value="Complete!",console.log("[useDocumentProcessing] Processing complete!"),setTimeout(()=>{console.log("[useDocumentProcessing] Clearing processing status..."),n.value="",r.value=0},500)}catch(c){console.error("[useDocumentProcessing] Error processing files:",c),console.error("[useDocumentProcessing] Error stack:",c instanceof Error?c.stack:"No stack trace"),n.value="Error processing images",setTimeout(()=>{n.value="",r.value=0},2e3)}finally{console.log("[useDocumentProcessing] Setting loading to false..."),t.value=!1}}}}}function it(o){const t=e.ref(!1),n=e.ref(""),r=e.ref(0),s=e.ref(new Map),a=e.ref(null),c=(l,i)=>`${l}-${i}`,m=l=>{Array.from(s.value.keys()).filter(u=>u.startsWith(`${l}-`)).forEach(u=>{const f=s.value.get(u);f&&f.startsWith("blob:")&&URL.revokeObjectURL(f),s.value.delete(u)})},d=()=>{s.value.forEach(l=>{l.startsWith("blob:")&&URL.revokeObjectURL(l)}),s.value.clear()},g=e.computed(()=>o.pageManager.currentPage.value),R=async(l,i)=>{if(i===0)return l.originalImageDataURL;const u=c(l.id,i),f=s.value.get(u);if(f)return f;if(!o.isOpenCVReady.value)return console.warn("[useImageOperations] OpenCV not ready for rotation generation"),l.originalImageDataURL;try{console.log(`[useImageOperations] Generating ${i}° rotation for page ${l.id}`);const v=await o.rotateImageData(l.originalImageDataURL,i);return s.value.set(u,v),v}catch(v){return console.error(`[useImageOperations] Error generating ${i}° rotation:`,v),l.originalImageDataURL}};e.watch(()=>g.value?[g.value.id,g.value.currentRotation]:null,async l=>{if(!l||!g.value){a.value=null;return}const[i,u]=l,f=g.value;try{const v=await R(f,u);a.value=v}catch(v){console.error("[useImageOperations] Error updating rotated image:",v),a.value=f.originalImageDataURL}},{immediate:!0});const P=e.computed(()=>a.value),w=e.computed(()=>g.value?g.value.mode==="preview"&&g.value.processedImageDataURL?g.value.processedImageDataURL:P.value:null);return{isLoading:t,processingStatus:n,processingProgress:r,currentDisplayPage:g,rotatedImageDataURLByRotation:P,imageSrcForPreviewComponent:w,processActivePage:async l=>{if(!g.value){console.warn("[useImageOperations] processActivePage: No current page.");return}const i=g.value,u=P.value;if(!u){console.warn("[useImageOperations] processActivePage: No image data available for processing.");return}const f=i.corners;if(!f||f.length!==4){console.warn(`[useImageOperations] processActivePage: Valid corners not available for page '${i.id}'.`);return}t.value=!0,n.value="Processing document...",r.value=50;try{console.log(`[useImageOperations] Processing page '${i.id}' with image:`,u===P.value?"rotated":"original","and corners:",f);const v=await o.performPerspectiveTransform(u,f,l);if(!v||!v.imageDataURL){console.error(`[useImageOperations] Perspective transform failed for page '${i.id}'.`),n.value="Processing failed",setTimeout(()=>{n.value="",r.value=0},2e3),t.value=!1;return}r.value=90,n.value="Finalizing...",o.pageManager.updatePageData(i.id,{processedImageDataURL:v.imageDataURL,processedWidth:v.processedWidth,processedHeight:v.processedHeight,mode:"preview"}),console.log(`[useImageOperations] Page '${i.id}' processed successfully.`),r.value=100,n.value="Complete!",setTimeout(()=>{n.value="",r.value=0},500)}catch(v){console.error(`[useImageOperations] Error processing page '${i.id}':`,v),n.value="Error processing document",setTimeout(()=>{n.value="",r.value=0},2e3)}finally{t.value=!1}},resetCornersForCurrentPage:()=>{if(g.value){const l=g.value;if(!P.value){console.warn("[useImageOperations] Reset corners: No image data available.");return}let u=l.originalWidth,f=l.originalHeight;(l.currentRotation===90||l.currentRotation===270)&&(u=l.originalHeight,f=l.originalWidth);const v=.1,M=u*v,x=f*v,h=[{x:M,y:x},{x:u-M,y:x},{x:u-M,y:f-x},{x:M,y:f-x}];o.pageManager.updatePageData(l.id,{corners:h}),console.log(`[useImageOperations] Corners reset to default box for page ${l.id}:`,h)}else console.warn("[useImageOperations] Reset corners: No current page.")},rotateCurrentPage:async l=>{if(!g.value){console.warn("[useImageOperations] Rotate: No current page.");return}const i=g.value,u=l==="left"?-90:90;let f=(i.currentRotation+u+360)%360;if(!i.originalImageDataURL){console.warn("[useImageOperations] Rotate: No original image data available.");return}console.log(`[useImageOperations] Rotating page ${i.id} by ${u}°...`),t.value=!0,n.value=`Rotating image ${u>0?"right":"left"}...`,r.value=30;try{r.value=60;let v,M=i.originalWidth,x=i.originalHeight;(i.currentRotation===90||i.currentRotation===270)&&(M=i.originalHeight,x=i.originalWidth),i.corners&&(console.log(`[useImageOperations] Transforming current corners by ${u}° using dimensions ${M}x${x}`),v=o.transformCornersForRotationIncrement(i.corners,u,M,x),console.log("[useImageOperations] Transformed corners:",v)),r.value=90,o.pageManager.updatePageData(i.id,{currentRotation:f,processedImageDataURL:void 0,processedWidth:void 0,processedHeight:void 0,corners:v}),r.value=100,n.value="Rotation complete!",console.log(`[useImageOperations] Successfully rotated page ${i.id} to ${f}°, corners ${v?"transformed (adjusted)":"reset for re-detection"}`),setTimeout(()=>{n.value="",r.value=0},500)}catch(v){console.error(`[useImageOperations] Error rotating page ${i.id}:`,v),n.value="Rotation failed",o.pageManager.updatePageData(i.id,{currentRotation:i.currentRotation}),setTimeout(()=>{n.value="",r.value=0},2e3)}finally{t.value=!1}},applyPerspectiveTransformAndGetDataURL:async l=>{const i=o.pageManager.getPageById(l);if(!i)return console.error("Cannot apply perspective transform: page not found for id",l),null;if(!i.corners)return console.error("Cannot apply perspective transform: corners are null for page",i.id),null;try{const u=await o.performPerspectiveTransform(i.originalImageDataURL,i.corners);if(u){const f=new Image;await new Promise((v,M)=>{f.onload=v,f.onerror=x=>{console.error("Error loading processed image to get dimensions:",x),M(x)},f.src=u.imageDataURL}),o.pageManager.updatePageData(i.id,{processedImageDataURL:u.imageDataURL,processedWidth:f.naturalWidth,processedHeight:f.naturalHeight,mode:"preview"})}return(u==null?void 0:u.imageDataURL)||null}catch(u){return console.error("Error applying perspective transform for page:",i.id,u),o.pageManager.updatePageData(i.id,{mode:"edit"}),null}},clearPageCache:m,clearAllCache:d}}function Fe(o){const{showFullscreenScanner:t,isProcessingPdf:n,currentDisplayPage:r,pageManager:s,onCloseScanner:a,onDiscardProcessedImage:c}=o;return Pe.onKeyStroke("Escape",m=>{var d;m.preventDefault(),n.value?((d=r.value)==null?void 0:d.mode)==="preview"?c():a():t.value&&a()}),Pe.onKeyStroke("ArrowLeft",m=>{if(n.value&&(m.preventDefault(),s.currentPage.value&&s.pages.value.length>1)){const d=s.pages.value.findIndex(g=>g.id===s.currentPage.value.id);d>0&&s.selectPage(s.pages.value[d-1].id)}}),Pe.onKeyStroke("ArrowRight",m=>{if(n.value&&(m.preventDefault(),s.currentPage.value&&s.pages.value.length>1)){const d=s.pages.value.findIndex(g=>g.id===s.currentPage.value.id);d<s.pages.value.length-1&&s.selectPage(s.pages.value[d+1].id)}}),{}}function Oe({currentDisplayPage:o,pageManager:t}){return e.watch(o,n=>{if(n&&n.id&&n.mode==="edit"){let r=!1,s=n.corners;if(n.corners){const a=Ne(n.corners),c=n.currentRotation===90||n.currentRotation===270?n.originalHeight:n.originalWidth,m=n.currentRotation===90||n.currentRotation===270?n.originalWidth:n.originalHeight,d=c*m,g=d>8e6,R=d>2e6;let P=.05;g?P=.005:R&&(P=.025);const w=d*P;if(a<w){console.warn(`[useCornerValidation] Watcher: corners area for page ${n.id} is too small (${a} < ${w}). Resetting to default. Image: ${g?"High-res":R?"Medium-res":"Low-res"} (${c}x${m})`);const I=ge(n.originalWidth,n.originalHeight,32);s=de(I,n.currentRotation,n.originalWidth,n.originalHeight),r=!0}}else{console.log(`[useCornerValidation] Watcher: corners for page ${n.id} are null. Setting default.`);const a=ge(n.originalWidth,n.originalHeight,32);s=de(a,n.currentRotation,n.originalWidth,n.originalHeight),r=!0}r&&t.currentPage.value&&t.currentPage.value.id===n.id&&t.updatePageData(n.id,{corners:s})}},{immediate:!1,deep:!0}),{}}const lt={class:"loading-spinner d-flex flex-column align-items-center justify-content-center p-4 bg-white rounded shadow-lg"},ct={class:"spinner-border text-primary",role:"status"},ut={class:"visually-hidden"},dt={class:"h5 text-secondary mt-3 ds-loading-message"},gt=e.defineComponent({__name:"LoadingSpinner",props:{message:{type:String,default:"Loading..."}},setup(o){const t=o;return(n,r)=>(e.openBlock(),e.createElementBlock("div",lt,[e.createElementVNode("div",ct,[e.createElementVNode("span",ut,e.toDisplayString(t.message),1)]),e.createElementVNode("p",dt,e.toDisplayString(t.message),1)]))}}),ae=(o,t)=>{const n=o.__vccOpts||o;for(const[r,s]of t)n[r]=s;return n},mt=ae(gt,[["__scopeId","data-v-936490dc"]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Ee=o=>o.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),pt=o=>o.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,n,r)=>r?r.toUpperCase():n.toLowerCase()),ft=o=>{const t=pt(o);return t.charAt(0).toUpperCase()+t.slice(1)},vt=(...o)=>o.filter((t,n,r)=>!!t&&t.trim()!==""&&r.indexOf(t)===n).join(" ").trim();/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */var fe={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const ht=({size:o,strokeWidth:t=2,absoluteStrokeWidth:n,color:r,iconNode:s,name:a,class:c,...m},{slots:d})=>e.h("svg",{...fe,width:o||fe.width,height:o||fe.height,stroke:r||fe.stroke,"stroke-width":n?Number(t)*24/Number(o):t,class:vt("lucide",...a?[`lucide-${Ee(ft(a))}-icon`,`lucide-${Ee(a)}`]:["lucide-icon"]),...m},[...s.map(g=>e.h(...g)),...d.default?[d.default()]:[]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Q=(o,t)=>(n,{slots:r})=>e.h(ht,{...n,iconNode:t,name:o},r);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Te=Q("camera",[["path",{d:"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z",key:"1tc9qg"}],["circle",{cx:"12",cy:"13",r:"3",key:"1vg3eu"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const yt=Q("chevron-left",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Pt=Q("chevron-right",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const wt=Q("crop",[["path",{d:"M6 2v14a2 2 0 0 0 2 2h14",key:"ron5a4"}],["path",{d:"M18 22V8a2 2 0 0 0-2-2H2",key:"7s9ehn"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Rt=Q("file-text",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const be=Q("image",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const It=Q("images",[["path",{d:"M18 22H4a2 2 0 0 1-2-2V6",key:"pblm9e"}],["path",{d:"m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18",key:"nf6bnh"}],["circle",{cx:"12",cy:"8",r:"2",key:"1822b1"}],["rect",{width:"16",height:"16",x:"6",y:"2",rx:"2",key:"12espp"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Ct=Q("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Et=Q("square-dashed",[["path",{d:"M5 3a2 2 0 0 0-2 2",key:"y57alp"}],["path",{d:"M19 3a2 2 0 0 1 2 2",key:"18rm91"}],["path",{d:"M21 19a2 2 0 0 1-2 2",key:"1j7049"}],["path",{d:"M5 21a2 2 0 0 1-2-2",key:"sbafld"}],["path",{d:"M9 3h1",key:"1yesri"}],["path",{d:"M9 21h1",key:"15o7lz"}],["path",{d:"M14 3h1",key:"1ec4yj"}],["path",{d:"M14 21h1",key:"v9vybs"}],["path",{d:"M3 9v1",key:"1r0deq"}],["path",{d:"M21 9v1",key:"mxsmne"}],["path",{d:"M3 14v1",key:"vnatye"}],["path",{d:"M21 14v1",key:"169vum"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const bt=Q("square-pen",[["path",{d:"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7",key:"1m0v6g"}],["path",{d:"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",key:"ohrbg2"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const xt=Q("trash-2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const xe=Q("undo-dot",[["path",{d:"M21 17a9 9 0 0 0-15-6.7L3 13",key:"8mp6z9"}],["path",{d:"M3 7v6h6",key:"1v2h90"}],["circle",{cx:"12",cy:"17",r:"1",key:"1ixnty"}]]);/** * @license lucide-vue-next v0.511.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */const Dt=Q("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]),St={class:"document-scanner-initial-trigger d-flex align-items-center justify-content-center p-3",style:{"min-height":"100px"}},Mt=["disabled"],$t={key:0,class:"d-flex align-items-center"},Lt={class:"ds-status-message"},kt={key:1,class:"d-flex align-items-center"},Nt={class:"ds-button-text"},At=e.defineComponent({__name:"ScannerTriggerButton",props:{buttonSize:{default:"md"},label:{default:"Scan Documents"},isLoading:{type:Boolean,default:!1},processingStatus:{default:""}},emits:["click"],setup(o,{emit:t}){const n=o,r=t,s=()=>{n.isLoading||r("click")};return(a,c)=>(e.openBlock(),e.createElementBlock("div",St,[e.createElementVNode("button",{onClick:s,class:e.normalizeClass(["btn btn-primary ds-button-text",[`btn-${a.buttonSize}`,{disabled:a.isLoading}]]),disabled:a.isLoading,title:"Scan documents with camera"},[a.isLoading?(e.openBlock(),e.createElementBlock("div",$t,[c[0]||(c[0]=e.createElementVNode("div",{class:"spinner-border spinner-border-sm me-2",role:"status"},[e.createElementVNode("span",{class:"visually-hidden"},"Loading...")],-1)),e.createElementVNode("span",Lt,e.toDisplayString(a.processingStatus||"Processing..."),1)])):(e.openBlock(),e.createElementBlock("div",kt,[e.createVNode(e.unref(Te),{size:36,class:"me-2"}),e.createElementVNode("span",Nt,e.toDisplayString(a.label),1)]))],10,Mt)]))}}),Ft=ae(At,[["__scopeId","data-v-9b2761ee"]]),De=[{name:"Letter Portrait",ratio:8.5/11,dimensions:'8.5" × 11"',category:"standard"},{name:"Letter Landscape",ratio:11/8.5,dimensions:'11" × 8.5"',category:"standard"},{name:"A4 Portrait",ratio:1/Math.sqrt(2),dimensions:"210 × 297mm",category:"standard"},{name:"A4 Landscape",ratio:Math.sqrt(2),dimensions:"297 × 210mm",category:"standard"},{name:"Legal Portrait",ratio:8.5/14,dimensions:'8.5" × 14"',category:"standard"},{name:"Legal Landscape",ratio:14/8.5,dimensions:'14" × 8.5"',category:"standard"},{name:"Square",ratio:1,dimensions:"1:1",category:"standard"}];function Ot(){const o=e.ref(!1),t=e.computed(()=>o.value),n=m=>{o.value=m},r=()=>{n(!1)},s=()=>{n(!0)},a=m=>(m==null?void 0:m.outputFormat)||De[0],c=(m,d,g)=>{g(m,{outputFormat:d})};return{isVisible:e.computed(()=>o.value),shouldShow:t,availableFormats:e.computed(()=>De),setVisible:n,hide:r,show:s,getPageFormat:a,setPageFormat:c}}const Tt={class:"image-preview-container d-flex flex-column w-100 h-100 overflow-hidden bg-dark position-relative user-select-none","data-testid":"image-preview",style:{"max-width":"100%","max-height":"100%"}},Ut={key:0,class:"navigation-buttons"},_t={class:"page-counter"},Vt=["data-testid"],Ht=["src"],Bt=30,Wt=e.defineComponent({__name:"ImagePreview",props:{imageDataURL:{},initialCorners:{},isProcessedPreview:{type:Boolean},isEditMode:{type:Boolean},pageManager:{}},emits:["corners-adjusted"],setup(o,{expose:t,emit:n}){const r={MAGNIFIER_SIZE:"100",MAGNIFIER_ZOOM:"2",MAGNIFIER_BORDER_COLOR:"#555",MAGNIFIER_BG_COLOR:"rgba(230, 230, 230, 0.85)",MAGNIFIER_CROSSHAIR_COLOR:"white",MAGNIFIER_CROSSHAIR_LINE_WIDTH:"1",HANDLE_RADIUS:"8",HANDLE_COLOR:"rgba(0, 123, 255, 0.7)",ACTIVE_HANDLE_COLOR:"rgba(200, 200, 0, 0.3)",LINE_COLOR:"rgba(255, 0, 0, 0.7)",LINE_WIDTH:"2"};function s(y,C){return typeof window<"u"&&getComputedStyle(document.documentElement).getPropertyValue(y).trim()||C}const a=o,c=n,m=a.pageManager||{moveToNextPage:()=>{},moveToPrevPage:()=>{},totalPages:e.computed(()=>0),pageCountDisplay:e.computed(()=>"0/0")},{moveToNextPage:d,moveToPrevPage:g,totalPages:R,pageCountDisplay:P}=m,w=e.computed(()=>R.value>1&&!h.value);e.computed(()=>R.value>1);const I=e.ref(null),A=e.ref(null),F=e.ref(null);let $=null,l=null;const i=e.ref(null),u=e.ref(null),f=e.ref(null),v=e.ref(!1),M=e.ref(null),x=e.computed(()=>a.isProcessedPreview??!1),h=e.computed(()=>a.isEditMode??!1),p=e.ref({imageWidth:0,imageHeight:0,canvasWidth:0,canvasHeight:0,renderWidth:0,renderHeight:0,offsetX:0,offsetY:0,scale:1,isReady:!1}),L=e.ref(!1),T=e.ref(null),_=e.ref(parseFloat(s("--magnifier-size",r.MAGNIFIER_SIZE))),z=e.ref(parseFloat(s("--magnifier-zoom",r.MAGNIFIER_ZOOM))),E={TOP_LEFT:0,BOTTOM_LEFT:3},D=e.computed(()=>{if(!L.value||!T.value)return{display:"none"};const y={position:"absolute",width:`${_.value}px`,height:`${_.value}px`,borderRadius:"50%",border:`2px solid ${s("--magnifier-border-color",r.MAGNIFIER_BORDER_COLOR)}`,boxShadow:"0 0 10px rgba(0,0,0,0.3)",pointerEvents:"none",zIndex:"1001",top:"15px",backgroundColor:s("--magnifier-bg-color",r.MAGNIFIER_BG_COLOR),opacity:"1 !important"};return T.value==="top-right"?y.right="15px":y.left="15px",y});e.watch(()=>a.imageDataURL,y=>{console.log("[IP] imageDataURL changed:",y?"has URL":"is null"),p.value.isReady=!1,i.value=null,u.value=null,f.value=null,y||j()},{immediate:!0}),e.watch(()=>a.initialCorners,y=>{console.log("[IP] initialCorners changed:",y),y&&y.length===4?(i.value=JSON.parse(JSON.stringify(y)),p.value.isReady&&S()):!y&&A.value&&A.value.complete&&p.value.isReady},{immediate:!0,deep:!0});const b=async()=>{const y=A.value,C=I.value;if(!y||!C||!y.complete||y.naturalWidth===0){console.warn("[IP] onImageLoad: Image or canvas not ready or image has no dimensions."),p.value.isReady=!1;return}console.log("[IP] Image loaded:",y.src.substring(0,50),`(${y.naturalWidth}x${y.naturalHeight})`),p.value.imageWidth=y.naturalWidth,p.value.imageHeight=y.naturalHeight,await e.nextTick();let H=0;const B=5,W=50,ne=async()=>{if(!C.parentElement)return console.warn("[IP] Canvas parent element not found during image load setup."),!1;const ee=C.parentElement.clientWidth,re=C.parentElement.clientHeight;return ee===0||re===0?(H++,console.log(`[IP] Container dimensions zero, retry ${H}/${B} in ${W}ms`),console.log("[IP] Debug info:",{parentElement:C.parentElement.tagName,parentClass:C.parentElement.className,parentStyle:C.parentElement.getAttribute("style"),clientWidth:C.parentElement.clientWidth,clientHeight:C.parentElement.clientHeight,offsetWidth:C.parentElement.offsetWidth,offsetHeight:C.parentElement.offsetHeight,scrollWidth:C.parentElement.scrollWidth,scrollHeight:C.parentElement.scrollHeight,computedDisplay:window.getComputedStyle(C.parentElement).display,computedWidth:window.getComputedStyle(C.parentElement).width,computedHeight:window.getComputedStyle(C.parentElement).height,computedFlex:window.getComputedStyle(C.parentElement).flex,grandParent:C.parentElement.parentElement?{tagName:C.parentElement.parentElement.tagName,className:C.parentElement.parentElement.className,clientWidth:C.parentElement.parentElement.clientWidth,clientHeight:C.parentElement.parentElement.clientHeight}:null}),H<B?(await new Promise(pe=>setTimeout(pe,W)),ne()):(console.warn("[IP] Container dimensions still zero after all retries."),!1)):!0};if(await ne()){if(U(),!p.value.isReady){console.warn("[IP] Render parameters could not be established after image load.");return}}else{console.warn("[IP] Using fallback dimensions due to layout issues");const ee=Math.min(window.innerWidth-40,800),re=Math.min(window.innerHeight-200,600);if(C.parentElement){if(C.parentElement.style.width=`${ee}px`,C.parentElement.style.height=`${re}px`,C.parentElement.style.minWidth=`${ee}px`,C.parentElement.style.minHeight=`${re}px`,C.parentElement.style.display="flex",C.parentElement.style.flexDirection="column",console.log(`[IP] Forced parent dimensions to ${ee}x${re}`),await e.nextTick(),U(),!p.value.isReady){console.error("[IP] Still failed after forced dimensions");return}}else{p.value.isReady=!1;return}}$=C.getContext("2d"),F.value&&(l=F.value.getContext("2d"),F.value.width=_.value,F.value.height=_.value),!i.value&&!x.value&&(console.log("[IP] No initial corners provided, setting default corners."),O()),S(),console.log("[IP] Initial draw complete after image load.")},U=()=>{const y=I.value,C=A.value;if(!y||!C||!C.complete||!y.parentElement){console.warn("[IP] calcRenderParams: Prerequisites not met."),p.value.isReady=!1;return}const H=y.parentElement.clientWidth,B=y.parentElement.clientHeight;if(H===0||B===0){console.warn("[IP] calcRenderParams: Container dimensions are zero.",{containerWidth:H,containerHeight:B,parentElement:y.parentElement.tagName,parentStyles:window.getComputedStyle(y.parentElement)}),p.value.isReady=!1;return}if(p.value.canvasWidth=H,p.value.canvasHeight=B,y.width=p.value.canvasWidth,y.height=p.value.canvasHeight,F.value){const pe=parseFloat(s("--magnifier-size",r.MAGNIFIER_SIZE));_.value!==pe&&(_.value=pe),F.value.width=_.value,F.value.height=_.value}const W=parseFloat(s("--magnifier-zoom",r.MAGNIFIER_ZOOM));z.value!==W&&(z.value=W);let ne=p.value.imageWidth,me=p.value.imageHeight;const