Files
pixel-bead-pattern/out/_next/static/chunks/page-DBRuBfy6.js
T

1 line
46 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{r as e}from"./rolldown-runtime-C60lm6uB.js";import{i as t,r as n}from"./framework-BgSIrAUN.js";var r=e(n(),1),i=Object.entries({A:`#FAF4C8 #FFFFD5 #FEFF8B #FBED56 #F4D738 #FEAC4C #FE8B4C #FFDA45 #FF995B #F77C31 #FFDD99 #FE9F72 #FFC365 #FD543D #FFF365 #FFFF9F #FFE36E #FEBE7D #FD7C72 #FFD568 #FFE395 #F4F57D #E6C9B7 #F7F8A2 #FFD67D #FFC830`,B:`#E6EE31 #63F347 #9EF780 #5DE035 #35E352 #65E2A6 #3DAF80 #1C9C4F #27523A #95D3C2 #5D722A #166F41 #CAEB7B #ADE946 #2E5132 #C5ED9C #9BB13A #E6EE49 #24B88C #C2F0CC #156A6B #0B3C43 #303A21 #EEFCA5 #4E846D #8D7A35 #CCE1AF #9EE5B9 #C5E254 #E2FCB1 #B0E792 #9CAB5A`,C:`#E8FFE7 #A9F9FC #A0E2FB #41CCFF #01ACEB #50AAF0 #3677D2 #0F54C0 #324BCA #3EBCE2 #28DDDE #1C334D #CDE8FF #D5FDFF #22C4C6 #1557A8 #04D1F6 #1D3344 #1887A2 #176DAF #BEDDFF #67B4BE #C8E2FF #7CC4FF #A9E5E5 #3CAED8 #D3DFFA #BBCFED #34488E`,D:`#AEB4F2 #858EDD #2F54AF #182A84 #B843C5 #AC7BDE #8854B3 #E2D3FF #D5B9F8 #361851 #B9BAE1 #DE9AD4 #B90095 #8B279B #2F1F90 #E3E1EE #C4D4F6 #A45EC7 #D8C3D7 #9C32B2 #9A009B #333A95 #EBDAFC #7786E5 #494FC7 #DFC2F8`,E:`#FDD3CC #FEC0DF #FFB7E7 #E8649E #F551A2 #F13D74 #C63478 #FFDBE9 #E970CC #D33793 #FCDDD2 #F78FC3 #B5006D #FFD1BA #F8C7C9 #FFF3EB #FFE2EA #FFC7DB #FEBAD5 #D8C7D1 #BD9DA1 #B785A1 #937A8D #E1BCE8`,F:`#FD957B #FC3D46 #F74941 #FC283C #E7002F #943630 #971937 #BC0028 #E2677A #8A4526 #5A2121 #FD4E6A #F35744 #FFA9AD #D30022 #FEC2A6 #E69C79 #D37C46 #C1444A #CD9391 #F7B4C6 #FDC0D0 #F67E66 #E698AA #E54B4F`,G:`#FFE2CE #FFC4AA #F4C3A5 #E1B383 #EDB045 #E99C17 #9D5B3E #753832 #E6B483 #D98C39 #E0C593 #FFC890 #B7714A #8D614C #FCF9E0 #F2D9BA #78524B #FFE4CC #E07935 #A94023 #B88558`,H:`#FDFBFF #FEFFFF #B6B1BA #89858C #48464E #2F2B2F #000000 #E7D6DB #EDEDED #EEE9EA #CECDD5 #FFF5ED #F5ECD2 #CFD7D3 #98A6A8 #1D1414 #F1EDED #FFFDF0 #F6EFE2 #949FA3 #FFFBE1 #CACAD4 #9A9D94`,M:`#BCC6B8 #8AA386 #697D80 #E3D2BC #D0CCAA #B0A782 #B4A497 #B38281 #A58767 #C5B2BC #9F7594 #644749 #D19066 #C77362 #757D78`}).flatMap(([e,t])=>t.split(` `).map((t,n)=>[e+(n+1),t])),a=t(),o={x:0,y:0,width:1,height:1},s=!1;function c(e){fetch(`/api/usage`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e),keepalive:!0}).catch(()=>void 0)}var l=128,u=30,d=`bead-pattern-history`,f=`pixel-bead-pattern-history`,p=`patterns`;function m(){return typeof globalThis.crypto?.randomUUID==`function`?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function h(e){let t=Math.max(1,Math.floor(e)),n=``;for(;t>0;)--t,n=String.fromCharCode(65+t%26)+n,t=Math.floor(t/26);return n}function g(){return new Promise((e,t)=>{let n=indexedDB.open(f,1);n.onupgradeneeded=()=>{n.result.objectStoreNames.contains(p)||n.result.createObjectStore(p)},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}async function _(){let e=await g();return new Promise((t,n)=>{let r=e.transaction(p,`readonly`),i=r.objectStore(p).get(d);i.onsuccess=()=>t(Array.isArray(i.result)?i.result:[]),i.onerror=()=>n(i.error),r.oncomplete=()=>e.close()})}async function v(e){let t=await g();return new Promise((n,r)=>{let i=t.transaction(p,`readwrite`);i.objectStore(p).put(e,d),i.oncomplete=()=>{t.close(),n()},i.onerror=()=>{t.close(),r(i.error)},i.onabort=()=>{t.close(),r(i.error)}})}var y={A:`黄橙系`,B:`绿色系`,C:`蓝青系`,D:`紫蓝系`,E:`粉红系`,F:`红色系`,G:`肤棕系`,H:`黑白灰系`,M:`莫兰迪系`};function b([e,t,n]){let r=e=>{let t=e/255;return t<=.04045?t/12.92:((t+.055)/1.055)**2.4},i=r(e),a=r(t),o=r(n),s=Math.cbrt(.4122214708*i+.5363325363*a+.0514459929*o),c=Math.cbrt(.2119034982*i+.6806995451*a+.1073969566*o),l=Math.cbrt(.0883024619*i+.2817188376*a+.6299787005*o);return[.2104542553*s+.793617785*c-.0040720468*l,1.9779984951*s-2.428592205*c+.4505937099*l,.0259040371*s+.7827717662*c-.808675766*l]}function x(e,t){return Math.hypot(e[0]-t[0],e[1]-t[1],e[2]-t[2])}function S(e,t,n){let r=[n[0]-t[0],n[1]-t[1],n[2]-t[2]],i=r[0]**2+r[1]**2+r[2]**2;if(i<.07**2)return!1;let a=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],o=(a[0]*r[0]+a[1]*r[1]+a[2]*r[2])/i;return o<.12||o>.88?!1:x(e,[t[0]+r[0]*o,t[1]+r[1]*o,t[2]+r[2]*o])<=.025}var C=i.map(([e,t])=>{let n=[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];return{code:e,name:`MARD ${y[e[0]]}`,hex:t,rgb:n,lab:b(n)}}),w=new Map(C.map(e=>[e.code,e])),T=e=>[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)];function ee({entry:e}){let t=(0,r.useRef)(null);return(0,r.useEffect)(()=>{let n=t.current;if(!n)return;n.width=Math.max(1,e.width),n.height=Math.max(1,e.height);let r=n.getContext(`2d`);r&&(r.clearRect(0,0,n.width,n.height),e.codes.forEach((t,n)=>{if(!t)return;let i=w.get(t);i&&(r.fillStyle=i.hex,r.fillRect(n%e.width,Math.floor(n/e.width),1,1))}))},[e]),(0,a.jsx)(`div`,{className:`history-thumbnail`,"aria-label":`${e.name} 的完整格子图缩略图`,children:(0,a.jsx)(`canvas`,{ref:t})})}function E(e,t){let n=t[0],r=1/0;for(let i of t){let t=x(e,i.lab);t<r&&(r=t,n=i)}return n}var D=null;function te(e,t,n,r=32,i=16){let a=t,o=-1,s=n,c=-1;for(let r=0;r<n;r++)for(let n=0;n<t;n++)e[r*t+n]&&(a=Math.min(a,n),o=Math.max(o,n),s=Math.min(s,r),c=Math.max(c,r));if(o<a||c<s)return null;let l=o-a+1,u=c-s+1,d=Math.min((r-2)/l,(i-2)/u),f=Math.max(1,Math.round(l*d)),p=Math.max(1,Math.round(u*d)),m=Math.floor((r-f)/2),h=Math.floor((i-p)/2),g=new Uint8Array(r*i),_=0;for(let n=0;n<p;n++)for(let i=0;i<f;i++){let o=a+Math.min(l-1,Math.floor(i/d));e[(s+Math.min(u-1,Math.floor(n/d)))*t+o]&&(g[(h+n)*r+m+i]=1,_+=1)}return _>=3?{pixels:g,count:_}:null}function O(){if(D)return D;let e=document.createElement(`canvas`);e.width=96,e.height=48;let t=e.getContext(`2d`,{willReadFrequently:!0});return D=C.map(n=>{t.clearRect(0,0,e.width,e.height),t.fillStyle=`#ffffff`,t.fillRect(0,0,e.width,e.height),t.fillStyle=`#000000`,t.font=`700 28px Arial`,t.textAlign=`center`,t.textBaseline=`middle`,t.fillText(n.code,e.width/2,e.height/2);let r=t.getImageData(0,0,e.width,e.height).data,i=new Uint8Array(e.width*e.height);for(let e=0;e<i.length;e++){let t=e*4;r[t]*.299+r[t+1]*.587+r[t+2]*.114<150&&(i[e]=1)}return{code:n.code,glyph:te(i,e.width,e.height)}}),D}function ne(e,t){let n=0;for(let r=0;r<e.pixels.length;r++)e.pixels[r]&&t.pixels[r]&&(n+=1);return 2*n/Math.max(1,e.count+t.count)}function k(e,t,n,r,i){let a=new Map,o=Math.max(2,Math.floor(i*.12));for(let s=o;s<i-o;s++)for(let c=o;c<i-o;c++){let o=c/i,u=s/i;if(o>.34&&o<.66&&u>.27&&u<.73)continue;let d=((r+s)*t+n+c)*4,f=e[d+3],p=f<l?-1:e[d]>>4<<8|e[d+1]>>4<<4|e[d+2]>>4,m=a.get(p)??{count:0,red:0,green:0,blue:0,alpha:0};m.count+=1,m.red+=e[d],m.green+=e[d+1],m.blue+=e[d+2],m.alpha+=f,a.set(p,m)}let s=[...a.values()].sort((e,t)=>t.count-e.count)[0];return s?{rgb:[Math.round(s.red/s.count),Math.round(s.green/s.count),Math.round(s.blue/s.count)],alpha:Math.round(s.alpha/s.count)}:{rgb:[255,255,255],alpha:0}}function A(e,t,n,r,i,a){let o=new Uint8Array(i*i),s=Math.max(2,Math.floor(i*.12)),c=Math.max(2,Math.floor(i*.16));for(let u=c;u<i-c;u++)for(let c=s;c<i-s;c++){let s=((r+u)*t+n+c)*4;e[s+3]<l||Math.hypot(e[s]-a[0],e[s+1]-a[1],e[s+2]-a[2])>=72&&(o[u*i+c]=1)}return te(o,i,i)}function j(e,t){let n=``,r=0,i=O().map(e=>({template:e,distance:x(t,w.get(e.code).lab)})).sort((e,t)=>e.distance-t.distance).slice(0,24);for(let{template:t,distance:a}of i){let i=ne(e,t.glyph)-Math.min(.16,a*.35);i>r&&(r=i,n=t.code)}return{code:n,score:r}}function re(e,t,n,r,i){let a=Math.max(10,Math.min(36,Math.floor(4096/Math.max(n,r)))),o=document.createElement(`canvas`);o.width=n*a,o.height=r*a;let s=o.getContext(`2d`,{willReadFrequently:!0});s.imageSmoothingEnabled=!0,s.drawImage(e,t.x*e.naturalWidth,t.y*e.naturalHeight,t.width*e.naturalWidth,t.height*e.naturalHeight,0,0,o.width,o.height);let c=s.getImageData(0,0,o.width,o.height).data,u=[],d=0,f=0,p=0,m=new Map;for(let e=0;e<r;e++)for(let t=0;t<n;t++){let n=t*a,r=e*a,s=k(c,o.width,n,r,a),h=b(s.rgb),g=A(c,o.width,n,r,a,s.rgb),_=null;if(g){let e=``;for(let t=0;t<g.pixels.length;t++)e+=g.pixels[t]?`1`:`0`;_=m.get(e)??j(g,h),m.set(e,_)}if(_&&_.score>=.58&&w.has(_.code)){u.push({color:w.get(_.code)}),d+=1;continue}if(i){u.push({color:null}),p+=1;continue}let v=Math.hypot(h[1],h[2]);if(s.alpha<l||!g&&h[0]>.93&&v<.025){u.push({color:null}),p+=1;continue}u.push({color:E(h,C)}),f+=1}return{pixels:u,recognizedCodes:d,colorMatches:f,emptyCells:p}}function ie(e){let t=[],n=new Map;for(let r=0;r<e.length;r+=4){if(e[r+3]<l){t.push(null);continue}let i=e[r],a=e[r+1],o=e[r+2],s=i>>3<<10|a>>3<<5|o>>3;t.push(s);let c=n.get(s);c?(c.count+=1,c.red+=i,c.green+=a,c.blue+=o):n.set(s,{count:1,red:i,green:a,blue:o})}let r=[...n.entries()].map(([e,t])=>{let n=[t.red/t.count,t.green/t.count,t.blue/t.count];return{key:e,count:t.count,rgb:n,lab:b(n)}}).sort((e,t)=>t.count-e.count),i=[];for(let e of r){let t=-1,n=1/0;for(let r=0;r<i.length;r++){let a=x(e.lab,i[r].lab);a<n&&(n=a,t=r)}if(t>=0&&n<=.015){let n=i[t],r=n.count+e.count;n.rgb=n.rgb.map((t,i)=>(t*n.count+e.rgb[i]*e.count)/r),n.lab=n.lab.map((t,i)=>(t*n.count+e.lab[i]*e.count)/r),n.count=r}else i.push({count:e.count,rgb:[...e.rgb],lab:[...e.lab]})}let a=new Map;for(let e of r){let t=0,n=1/0;i.forEach((r,i)=>{let a=x(e.lab,r.lab);a<n&&(n=a,t=i)}),a.set(e.key,t)}return{pixelKeys:t,clusters:i,binClusters:a}}function ae(e,t){let n=new Map;for(let t of e){let e=E(t.lab,C),r=x(t.lab,e.lab),i=Math.hypot(t.lab[1],t.lab[2]),a=1+Math.min(.65,i*2.2)+(t.lab[0]<.28?.35:0),o=n.get(e.code)??{color:e,count:0,error:0,score:0};o.count+=t.count,o.error+=r*t.count,o.score+=t.count*a/(1+r*5),n.set(e.code,o)}let r=[],i=[...n.values()].sort((e,t)=>t.score-e.score||e.error/e.count-t.error/t.count);for(let e of i)r.every(t=>x(e.color.lab,t.lab)>=.035)&&r.push(e.color);return r.slice(0,Math.max(0,Math.min(t,r.length)))}function oe(e,t,n){let r=e.map(e=>E(e.lab,t));if(n<12)return r;let i=e.reduce((e,t)=>e+t.count,0),a=Math.max(24,i*.012),o=Math.min(8,Math.max(0,n-t.length)),s=[],c=e.map((e,t)=>({cluster:e,index:t,exact:E(e.lab,C)})).filter(({cluster:e,exact:t,index:n})=>e.count>=a&&t.code!==r[n].code).sort((e,t)=>t.cluster.count-e.cluster.count);for(let e of c){if(s.length>=o)break;if(s.some(t=>t.code===e.exact.code)){r[e.index]=e.exact;continue}Math.min(...t.map(t=>x(t.lab,e.exact.lab)))<.018||(s.push(e.exact),r[e.index]=e.exact)}return r}function se(e,t,n,r,i){if(i<12)return e;let a=[...e],o=[];for(let e=0;e<t.length;e+=4)o.push(t[e+3]<l?null:b([t[e],t[e+1],t[e+2]]));let s=new Uint8Array(n*r),c=[[-1,0],[1,0],[0,-1],[0,1]];for(let e=1;e<r-1;e++)for(let t=1;t<n-1;t++){let r=e*n+t,i=o[r];if(!i)continue;let a=0;for(let[r,s]of c){let c=o[(e+r)*n+t+s];if(!c){a=1/0;break}a=Math.max(a,x(i,c))}a<=.018&&(s[r]=1)}let u=new Set;for(let e=2;e<r-2;e++)for(let t=2;t<n-2;t++){let r=e*n+t;if(!s[r])continue;let i=0;for(let r=-1;r<=1;r++)for(let a=-1;a<=1;a++)s[(e+r)*n+t+a]&&(i+=1);if(i<7)continue;let c=o[r],l=E(c,Math.hypot(c[1],c[2])<.035?C.filter(e=>e.code.startsWith(`H`)):C);!u.has(l.code)&&u.size>=8||(u.add(l.code),a[r]=l)}return a}function ce(e,t,n){let r=new Map;e.forEach(e=>{e&&r.set(e.code,(r.get(e.code)??0)+1)});let i=[...e],a=0;for(let o=0;o<n;o++)for(let s=0;s<t;s++){let c=o*t+s,l=e[c];if(!l||(r.get(l.code)??0)>2)continue;let u=new Map;for(let r=-1;r<=1;r++)for(let i=-1;i<=1;i++){if(r===0&&i===0)continue;let a=o+r,c=s+i;if(a<0||c<0||a>=n||c>=t)continue;let d=e[a*t+c];if(!d||d.code===l.code)continue;let f=u.get(d.code)??{color:d,count:0};f.count+=1,u.set(d.code,f)}let d=[...u.values()].sort((e,t)=>t.count-e.count)[0];if(!d)continue;let f=(r.get(l.code)??0)===1?3:5;d.count<f||(i[c]=d.color,a+=1)}return{colors:i,changed:a}}function le(e,t,n,r,i){let a=[[1,1,1],[1,2,1],[1,1,1]],o=document.createElement(`canvas`);o.width=t*3,o.height=n*3;let s=o.getContext(`2d`,{willReadFrequently:!0});s.clearRect(0,0,o.width,o.height),s.imageSmoothingEnabled=!1,fe(s,e,o.width,o.height,r,i);let c=s.getImageData(0,0,o.width,o.height).data,u=new Uint8ClampedArray(t*n*4),d=new Float32Array(t*n);for(let e=0;e<n;e++)for(let n=0;n<t;n++){let r=[],i=0;for(let t=0;t<3;t++)for(let s=0;s<3;s++){let u=((e*3+t)*o.width+n*3+s)*4,d=a[t][s];if(c[u+3]<l){i+=d;continue}let f=[c[u],c[u+1],c[u+2]],p=b(f),m=s===1&&t===1,h,g=1/0;for(let e of r){let t=x(p,e.lab);t<g&&(h=e,g=t)}if(h&&g<=.04){let e=h.weight+d;h.lab=h.lab.map((t,n)=>(t*h.weight+p[n]*d)/e),h.weight=e,h.count+=1,h.samples.push({rgb:f,lab:p}),h.containsCenter||=m}else r.push({count:1,weight:d,lab:[...p],samples:[{rgb:f,lab:p}],containsCenter:m})}let s=(e*t+n)*4;if(i>=10/2||r.length===0){u[s+3]=0,d[e*t+n]=i/10;continue}let f=r.map(e=>{let t=e.weight;if(e.count<=2)for(let n=0;n<r.length;n++)for(let i=n+1;i<r.length;i++)r[n]===e||r[i]===e||r[n].weight+r[i].weight<e.weight||S(e.lab,r[n].lab,r[i].lab)&&(t=0);return{group:e,effectiveWeight:t}}).sort((e,t)=>t.effectiveWeight-e.effectiveWeight||t.group.weight-e.group.weight||Number(t.group.containsCenter)-Number(e.group.containsCenter))[0].group,p=f.samples.reduce((e,t)=>x(t.lab,f.lab)<x(e.lab,f.lab)?t:e);u[s]=p.rgb[0],u[s+1]=p.rgb[1],u[s+2]=p.rgb[2],u[s+3]=255,d[e*t+n]=f.weight/Math.max(1,10-i)}return{data:u,confidence:d}}function ue(e,t,n){let r=[...e],i=0;for(let a=0;a<n;a++)for(let o=0;o<t;o++){let s=a*t+o,c=e[s];if(!c)continue;let l=new Map,u=0;for(let r=-1;r<=1;r++)for(let i=-1;i<=1;i++){if(r===0&&i===0)continue;let s=a+r,d=o+i;if(s<0||d<0||s>=n||d>=t)continue;let f=e[s*t+d];if(!f)continue;if(f.code===c.code){u+=1;continue}let p=l.get(f.code)??{color:f,count:0};p.count+=1,l.set(f.code,p)}if(u>2)continue;let d=[...l.values()].sort((e,t)=>t.count-e.count).slice(0,3),f=null,p=0;for(let e=0;e<d.length;e++)for(let t=e+1;t<d.length;t++){if(d[e].count+d[t].count<4||!S(c.lab,d[e].color.lab,d[t].color.lab))continue;let n=d[e].count>=d[t].count?d[e]:d[t];n.count>p&&(f=n.color,p=n.count)}f&&(r[s]=f,i+=1)}return{colors:r,changed:i}}function de(e,t,n,r){let i=[...e],a=0,o=[-1,0,1];for(let s=0;s<r;s++)for(let c=0;c<n;c++){let l=s*n+c,u=e[l];if(!u||t[l]>=.625)continue;let d=Math.hypot(u.lab[1],u.lab[2]);if(u.lab[0]<.32||u.lab[0]>.96||d>.14)continue;let f=new Map,p=0,m=0;for(let i of o)for(let a of o){if(i===0&&a===0)continue;let o=s+i,l=c+a;if(o<0||l<0||o>=r||l>=n)continue;let d=o*n+l,h=e[d];if(!h)continue;h.code===u.code&&(m+=1);let g=f.get(h.code)??{color:h,count:0,confidentCount:0};g.count+=1,t[d]>=.625&&(g.confidentCount+=1),f.set(h.code,g),p+=1}if(m>0)continue;let h=[...f.values()].sort((e,t)=>t.count-e.count)[0];if(!h||h.color.code===u.code)continue;let g=p>=7?5:Math.max(2,Math.ceil(p*.67));h.count<g||h.confidentCount<Math.min(3,h.count)||x(u.lab,h.color.lab)>.075||(i[l]=h.color,a+=1)}return{colors:i,changed:a}}function fe(e,t,n,r,i,a){let o=a.x*t.naturalWidth,s=a.y*t.naturalHeight,c=a.width*t.naturalWidth,l=a.height*t.naturalHeight,u=c/l,d=n/r,f=o+c/2,p=s+l/2;if(i===`cover`){let i=c,a=l;u>d?i=l*d:a=c/d,e.drawImage(t,f-i/2,p-a/2,i,a,0,0,n,r);return}let m=n,h=r;u<d?(h=r,m=r*u):(m=n,h=n/u);let g=(n-m)/2,_=(r-h)/2;e.drawImage(t,o,s,c,l,g,_,m,h)}function pe(){let e=document.createElement(`canvas`);e.width=640,e.height=640;let t=e.getContext(`2d`),n=t.createLinearGradient(0,0,0,640);return n.addColorStop(0,`#bfe8f1`),n.addColorStop(.65,`#fff2ce`),n.addColorStop(1,`#f6c783`),t.fillStyle=n,t.fillRect(0,0,640,640),t.fillStyle=`#f6c742`,t.beginPath(),t.arc(488,134,70,0,Math.PI*2),t.fill(),t.fillStyle=`#58a95b`,t.beginPath(),t.moveTo(0,455),t.quadraticCurveTo(135,310,300,455),t.quadraticCurveTo(480,285,640,435),t.lineTo(640,640),t.lineTo(0,640),t.fill(),t.fillStyle=`#27865a`,t.beginPath(),t.moveTo(0,535),t.quadraticCurveTo(180,390,350,520),t.quadraticCurveTo(505,410,640,505),t.lineTo(640,640),t.lineTo(0,640),t.fill(),t.fillStyle=`#f7f5ed`,t.fillRect(245,390,152,126),t.fillStyle=`#d9383a`,t.beginPath(),t.moveTo(218,405),t.lineTo(321,323),t.lineTo(424,405),t.closePath(),t.fill(),t.fillStyle=`#754a32`,t.fillRect(300,447,43,69),t.fillStyle=`#79cbe1`,t.fillRect(258,415,39,37),t.fillRect(350,415,34,37),e.toDataURL(`image/png`)}function M(){let[e,t]=(0,r.useState)(``),[n,i]=(0,r.useState)(`示例:田野小屋`),[l,f]=(0,r.useState)(100),[p,g]=(0,r.useState)(100),[y,b]=(0,r.useState)(100),[x,S]=(0,r.useState)(100),[w,E]=(0,r.useState)(64),[D,te]=(0,r.useState)(`contain`),[O,ne]=(0,r.useState)(`dominant`),[k,A]=(0,r.useState)(o),[j,M]=(0,r.useState)(o),[N,me]=(0,r.useState)(`free`),[P,F]=(0,r.useState)(!1),[I,he]=(0,r.useState)(`source`),[L,ge]=(0,r.useState)(100),[R,_e]=(0,r.useState)(100),[ve,ye]=(0,r.useState)(!0),[be,xe]=(0,r.useState)(``),[Se,Ce]=(0,r.useState)(``),[we,Te]=(0,r.useState)(!1),[z,Ee]=(0,r.useState)([]),[B,V]=(0,r.useState)(new Set),[De,Oe]=(0,r.useState)(!1),[H,ke]=(0,r.useState)(8),[U,Ae]=(0,r.useState)(!0),[je,Me]=(0,r.useState)(!0),[Ne,Pe]=(0,r.useState)(``),[W,G]=(0,r.useState)(null),[Fe,Ie]=(0,r.useState)([]),[Le,Re]=(0,r.useState)(``),[ze,K]=(0,r.useState)(`示例图已准备好,可以直接转换`),q=(0,r.useRef)(null),Be=(0,r.useRef)(null);(0,r.useRef)(null);let Ve=(0,r.useRef)(null),He=(0,r.useRef)(null),Ue=(0,r.useRef)(null),J=(0,r.useRef)(null),Y=(0,r.useRef)(null),We=(0,r.useRef)(H),Ge=(0,r.useRef)(null),Ke=(0,r.useRef)(null),X=(0,r.useRef)(null),Z=(0,r.useRef)(null),Q=(0,r.useRef)(!1);(0,r.useEffect)(()=>{c({event:`page_view`});let e=!1;return(async()=>{try{let t=await _(),n=localStorage.getItem(d);if(t.length===0&&n){let e=JSON.parse(n);Array.isArray(e)&&(t=e.slice(0,u),await v(t)),localStorage.removeItem(d)}e||Ie(t.slice(0,u))}catch{e||K(`历史记录读取失败,请检查浏览器是否允许本地存储`)}})(),()=>{e=!0}},[]);let qe=(e=q.current,t=k,n=!0)=>{if(!e)return;let r=Math.max(8,Math.min(256,l)),i=Math.max(8,Math.min(256,p)),a,o=null;if(O===`dominant`){let n=le(e,r,i,D,t);a=n.data,o=n.confidence}else{let n=document.createElement(`canvas`);n.width=r,n.height=i;let o=n.getContext(`2d`,{willReadFrequently:!0});o.clearRect(0,0,r,i),fe(o,e,r,i,D,t),a=o.getImageData(0,0,r,i).data}let{pixelKeys:s,clusters:u,binClusters:d}=ie(a),m=oe(u,ae(u,Math.max(2,Math.min(w,C.length))),w),h=s.map(e=>e===null?null:m[d.get(e)??0]),_=0;if(o){let e=de(h,o,r,i);h=e.colors,_=e.changed;let t=ue(h,r,i);h=t.colors,_+=t.changed,h=se(h,a,r,i,w);let n=ce(h,r,i);h=n.colors,_+=n.changed}let v=h.map(e=>({color:e}));b(r),S(i),f(r),g(i),Ee(v),V(new Set);let y=O===`dominant`?`区域主色 · 清理 ${_} 个低可信孤立格`:`平滑取色`,x=new Set(h.filter(e=>e!==null).map(e=>e.code)).size,T=h.filter(e=>e!==null).length;n&&c({event:`conversion`,width:r,height:i,sampling_strategy:O,color_limit:w,actual_colors:x,bead_count:T,transparent_cells:r*i-T}),K(`已转换为 ${r} × ${i} · ${T} 颗拼豆 · ${y} · ${x} 种差异色`)};(0,r.useEffect)(()=>{let e=pe(),n=new Image;n.onload=()=>{q.current=n,t(e),qe(n,o,!1)},n.src=e},[]),(0,r.useEffect)(()=>{let e=He.current,t=q.current;if(!e||!t)return;let n=Math.max(8,Math.min(256,l||8))/Math.max(8,Math.min(256,p||8)),r=n>=1?600:Math.max(120,Math.round(600*n)),i=n>=1?Math.max(120,Math.round(600/n)):600;e.width=r,e.height=i;let a=e.getContext(`2d`);a.fillStyle=`#f7f5ed`,a.fillRect(0,0,r,i),fe(a,t,r,i,D,k)},[e,l,p,D,k]),(0,r.useEffect)(()=>{if(!P)return;let e=Ue.current,t=I===`pattern-import`?Ve.current:q.current;if(!e||!t)return;let n=Math.min(1200/t.naturalWidth,760/t.naturalHeight,1);e.width=Math.max(1,Math.round(t.naturalWidth*n)),e.height=Math.max(1,Math.round(t.naturalHeight*n));let r=e.getContext(`2d`);r.clearRect(0,0,e.width,e.height),r.drawImage(t,0,0,e.width,e.height)},[P,I,e,Se]),(0,r.useEffect)(()=>{if(!P)return;let e=document.body.style.overflow;document.body.style.overflow=`hidden`;let t=e=>{e.key===`Escape`&&F(!1)};return window.addEventListener(`keydown`,t),()=>{document.body.style.overflow=e,window.removeEventListener(`keydown`,t)}},[P]);let $=(0,r.useMemo)(()=>{let e=new Map;return z.forEach(({color:t})=>{t&&e.set(t.code,(e.get(t.code)??0)+1)}),C.filter(t=>e.has(t.code)).map(t=>({...t,count:e.get(t.code)})).sort((e,t)=>t.count-e.count)},[z]),Je=(0,r.useMemo)(()=>z.reduce((e,t)=>e+ +!!t.color,0),[z]),Ye=(0,r.useMemo)(()=>{let e=Ne.trim().toLowerCase();return $.filter(t=>!e||t.code.toLowerCase().includes(e)||t.name.includes(e)||t.hex.toLowerCase().includes(e))},[Ne,$]);(0,r.useEffect)(()=>{let e=J.current;if(!e||z.length===0)return;let t=H,n=Math.max(22,t),r=Math.min(window.devicePixelRatio||1,2);e.width=(y*t+n)*r,e.height=(x*t+n)*r,e.style.width=`${y*t+n}px`,e.style.height=`${x*t+n}px`;let i=e.getContext(`2d`);i.scale(r,r),i.fillStyle=`#ffffff`,i.fillRect(0,0,y*t+n,x*t+n),i.fillStyle=`#f0eee7`,i.fillRect(n,0,y*t,n),i.fillRect(0,n,n,x*t),i.strokeStyle=`rgba(32,38,36,.25)`,i.lineWidth=.6,i.font=`600 ${Math.max(7,Math.min(10,t*.35))}px Arial`,i.fillStyle=`#56605b`,i.textAlign=`center`,i.textBaseline=`middle`;let a=t<10?10:t<16?5:1;for(let e=0;e<y;e++){let r=n+e*t;i.strokeRect(r+.3,.3,t-.6,n-.6),(e===0||(e+1)%a===0)&&i.fillText(String(e+1),r+t/2,n/2)}for(let e=0;e<x;e++){let r=n+e*t;i.strokeRect(.3,r+.3,n-.6,t-.6),(e===0||(e+1)%a===0)&&i.fillText(String(e+1),n/2,r+t/2)}if(z.forEach(({color:e},r)=>{let a=n+r%y*t,o=n+Math.floor(r/y)*t;if(!e){i.clearRect(a,o,t,t),U&&(i.strokeStyle=`rgba(32,38,36,.12)`,i.lineWidth=.6,i.strokeRect(a+.3,o+.3,t-.6,t-.6));return}let s=B.size>0,c=B.has(e.code);if(De&&s&&!c?i.fillStyle=`#ffffff`:(i.fillStyle=e.hex,i.globalAlpha=s&&!c?.12:1,i.fillRect(a,o,t,t),i.globalAlpha=1),U&&(i.strokeStyle=s&&!c?`rgba(32,38,36,.07)`:`rgba(32,38,36,.22)`,i.lineWidth=.6,i.strokeRect(a+.3,o+.3,t-.6,t-.6)),je&&t>=22&&(!s||c)){let[n,r,s]=T(e.hex);i.fillStyle=n*.299+r*.587+s*.114>160?`#1f2925`:`#ffffff`,i.font=`600 ${Math.max(7,t*.28)}px Arial`,i.textAlign=`center`,i.textBaseline=`middle`,i.fillText(e.code,a+t/2,o+t/2)}}),U){i.strokeStyle=`rgba(32,38,36,.48)`,i.lineWidth=1.5;for(let e=5;e<y;e+=5){let r=n+e*t;i.beginPath(),i.moveTo(r,n),i.lineTo(r,n+x*t),i.stroke()}for(let e=5;e<x;e+=5){let r=n+e*t;i.beginPath(),i.moveTo(n,r),i.lineTo(n+y*t,r),i.stroke()}}},[z,y,x,H,B,De,U,je]),(0,r.useEffect)(()=>{We.current=H;let e=Ge.current;if(!e)return;Ge.current=null;let t=window.requestAnimationFrame(()=>{let{stage:t}=e,n=J.current;if(!n)return;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect(),a=i.left+i.width*e.canvasX,o=i.top+i.height*e.canvasY;t.scrollLeft+=a-(r.left+e.cursorX),t.scrollTop+=o-(r.top+e.cursorY)});return()=>window.cancelAnimationFrame(t)},[H]),(0,r.useEffect)(()=>{let e=Y.current;if(!e)return;let t=t=>{if(z.length===0||t.deltaY===0)return;t.preventDefault();let n=We.current,r=Math.max(3,Math.min(42,n+(t.deltaY<0?1:-1)));if(r===n)return;let i=e.getBoundingClientRect(),a=J.current?.getBoundingClientRect();Ge.current={stage:e,cursorX:t.clientX-i.left,cursorY:t.clientY-i.top,canvasX:a?(t.clientX-a.left)/Math.max(1,a.width):.5,canvasY:a?(t.clientY-a.top)/Math.max(1,a.height):.5},We.current=r,ke(r)};return e.addEventListener(`wheel`,t,{passive:!1}),()=>e.removeEventListener(`wheel`,t)},[z.length]);let Xe=n=>{let r=n.target.files?.[0];if(!r)return;if(!r.type.startsWith(`image/`)){K(`请选择 JPG、PNG 或 WebP 图片`);return}let a=URL.createObjectURL(r),s=new Image;s.onload=()=>{e.startsWith(`blob:`)&&URL.revokeObjectURL(e),q.current=s,t(a),i(r.name),A(o),M(o),K(`图片已载入,点击“重新转换”生成图纸`),qe(s,o)},s.src=a},Ze=()=>{he(`source`),M(k),F(!0)},Qe=e=>{let t=Ke.current;if(!t)return{x:0,y:0};let n=t.getBoundingClientRect();return{x:Math.max(0,Math.min(1,(e.clientX-n.left)/Math.max(1,n.width))),y:Math.max(0,Math.min(1,(e.clientY-n.top)/Math.max(1,n.height)))}},$e=(e,t,n,r)=>{let i=n>=e?1:-1,a=r>=t?1:-1,o=Math.abs(n-e),s=Math.abs(r-t);if(N===`square`){let n=I===`pattern-import`?Ve.current:q.current;if(!n)return;let r=n.naturalHeight/n.naturalWidth;o/Math.max(s,1e-4)>r?o=s*r:s=o/Math.max(r,1e-4);let c=i>0?1-e:e,l=a>0?1-t:t,u=Math.min(1,c/Math.max(o,1e-4),l/Math.max(s,1e-4));o*=u,s*=u}o=Math.max(.01,Math.min(1,o)),s=Math.max(.01,Math.min(1,s)),M({x:Math.max(0,Math.min(1-o,i>0?e:e-o)),y:Math.max(0,Math.min(1-s,a>0?t:t-s)),width:o,height:s})},et=e=>(j.width<.995||j.height<.995)&&e.x>=j.x&&e.x<=j.x+j.width&&e.y>=j.y&&e.y<=j.y+j.height,tt=e=>{if(me(e),e!==`square`)return;let t=I===`pattern-import`?Ve.current:q.current;if(!t)return;let n=j.x+j.width/2,r=j.y+j.height/2,i=Math.min(j.width*t.naturalWidth,j.height*t.naturalHeight),a=i/t.naturalWidth,o=i/t.naturalHeight;M({x:Math.max(0,Math.min(1-a,n-a/2)),y:Math.max(0,Math.min(1-o,r-o/2)),width:a,height:o})},nt=(e,t)=>{let n=e.handle;if(!n)return;let r=e.origin;if(N===`square`){$e(n.includes(`w`)?r.x+r.width:r.x,n.includes(`n`)?r.y+r.height:r.y,t.x,t.y);return}let i=.03,a=r.x,o=r.y,s=r.x+r.width,c=r.y+r.height;n.includes(`w`)&&(a=Math.max(0,Math.min(s-i,t.x))),n.includes(`e`)&&(s=Math.min(1,Math.max(a+i,t.x))),n.includes(`n`)&&(o=Math.max(0,Math.min(c-i,t.y))),n.includes(`s`)&&(c=Math.min(1,Math.max(o+i,t.y))),M({x:a,y:o,width:s-a,height:c-o})},rt=e=>{if(e.button!==0)return;let t=Qe(e);e.currentTarget.setPointerCapture(e.pointerId);let n=e.target.dataset.cropHandle;if(n){X.current={pointerId:e.pointerId,mode:`resize`,startX:t.x,startY:t.y,origin:j,handle:n},e.currentTarget.classList.add(`is-resizing-selection`);return}if(et(t)&&j.width>=.03&&j.height>=.03){X.current={pointerId:e.pointerId,mode:`move`,startX:t.x,startY:t.y,origin:j},e.currentTarget.classList.add(`is-moving-selection`);return}X.current={pointerId:e.pointerId,mode:`create`,startX:t.x,startY:t.y,origin:j},M({x:Math.min(.99,t.x),y:Math.min(.99,t.y),width:.01,height:.01})},it=e=>{let t=X.current,n=Qe(e);if(!t){e.currentTarget.classList.toggle(`can-move-selection`,et(n));return}if(t.pointerId===e.pointerId){if(t.mode===`resize`){nt(t,n);return}if(t.mode===`move`){let e=Math.max(0,Math.min(1-t.origin.width,t.origin.x+n.x-t.startX)),r=Math.max(0,Math.min(1-t.origin.height,t.origin.y+n.y-t.startY));M({...t.origin,x:e,y:r});return}$e(t.startX,t.startY,n.x,n.y)}},at=e=>{X.current?.pointerId===e.pointerId&&(X.current=null),e.currentTarget.classList.remove(`is-moving-selection`),e.currentTarget.classList.remove(`is-resizing-selection`),e.currentTarget.hasPointerCapture(e.pointerId)&&e.currentTarget.releasePointerCapture(e.pointerId)},ot=async()=>{let e=Ve.current,n=Math.max(1,Math.min(256,Math.round(L))),r=Math.max(1,Math.min(256,Math.round(R)));if(!e){K(`请先选择要导入的图纸图片`);return}if(j.width<.03||j.height<.03){K(`网格区域太小,请重新框选`);return}Te(!0),K(`正在读取 MARD 编码并匹配格子底色…`),await new Promise(e=>window.requestAnimationFrame(()=>e()));try{let a=re(e,j,n,r,ve),o=new Set(a.pixels.flatMap(({color:e})=>e?[e.code]:[])).size,s=a.pixels.reduce((e,{color:t})=>e+ +!!t,0);Ee(a.pixels),b(n),S(r),f(n),g(r),V(new Set),A(j),q.current=e,t(Se),i(`导入图纸:${be}`),F(!1),K(`已导入 ${n} × ${r} · 读取编码 ${a.recognizedCodes} 格 · 底色匹配 ${a.colorMatches} 格 · 空白 ${a.emptyCells} 格`),c({event:`pattern_import`,width:n,height:r,recognized_codes:a.recognizedCodes,color_matches:a.colorMatches,transparent_cells:a.emptyCells,actual_colors:o,bead_count:s,missing_code_as_empty:ve}),window.requestAnimationFrame(()=>document.getElementById(`pattern-preview`)?.scrollIntoView({behavior:`smooth`,block:`start`}))}catch{K(`图纸识别失败,请确认选框与网格行列准确后重试`)}finally{Te(!1)}},st=()=>{if(j.width<.03||j.height<.03){K(`框选区域太小,请在大图上拖出更大的选框`);return}if(I===`pattern-import`){ot();return}A(j),F(!1),qe(q.current,j)},ct=e=>{V(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},lt=e=>{if(e.button!==0)return;let t=Y.current;t&&(Q.current=!1,e.currentTarget.setPointerCapture(e.pointerId),Z.current={pointerId:e.pointerId,x:e.clientX,y:e.clientY,scrollLeft:t.scrollLeft,scrollTop:t.scrollTop,moved:!1})},ut=e=>{let t=Y.current,n=Z.current;if(!t||!n||n.pointerId!==e.pointerId)return;let r=e.clientX-n.x,i=e.clientY-n.y;!n.moved&&Math.hypot(r,i)<5||(n.moved=!0,t.classList.add(`is-dragging`),t.scrollLeft=n.scrollLeft-r,t.scrollTop=n.scrollTop-i,G(null))},dt=e=>{let t=Y.current,n=Z.current;!n||n.pointerId!==e.pointerId||(Q.current=n.moved,Z.current=null,t?.classList.remove(`is-dragging`),e.currentTarget.hasPointerCapture(e.pointerId)&&e.currentTarget.releasePointerCapture(e.pointerId))},ft=e=>{Z.current?.pointerId===e.pointerId&&(Z.current=null,Q.current=!1,Y.current?.classList.remove(`is-dragging`),e.currentTarget.hasPointerCapture(e.pointerId)&&e.currentTarget.releasePointerCapture(e.pointerId))},pt=e=>{Z.current?.pointerId===e.pointerId&&(Z.current=null,Q.current=!1,Y.current?.classList.remove(`is-dragging`))},mt=e=>{if(Q.current){Q.current=!1;return}let t=J.current;if(!t)return;let n=t.getBoundingClientRect(),r=Math.max(22,H),i=Math.floor((e.clientX-n.left-r)/H),a=Math.floor((e.clientY-n.top-r)/H),o=z[a*y+i];i>=0&&a>=0&&i<y&&a<x&&o?.color&&ct(o.color.code)},ht=e=>{if(Z.current?.moved){G(null);return}let t=J.current;if(!t)return;let n=t.getBoundingClientRect(),r=Math.max(22,H),i=Math.floor((e.clientX-n.left-r)/H),a=Math.floor((e.clientY-n.top-r)/H),o=z[a*y+i];if(i<0||a<0||i>=y||a>=x||!o?.color){G(null);return}G({row:a+1,column:i+1,color:o.color,left:e.clientX-n.left+14,top:e.clientY-n.top+14})},gt=async e=>{await v(e),Ie(e)},_t=async()=>{if(z.length)try{await gt([{id:m(),name:n.replace(/\.[^.]+$/,``)||`未命名图纸`,savedAt:new Date().toISOString(),width:y,height:x,colorLimit:w,codes:z.map(e=>e.color?.code??null)},...Fe].slice(0,u)),Re(``),K(`图纸已保存到本机历史记录`),requestAnimationFrame(()=>document.getElementById(`history-title`)?.scrollIntoView({behavior:`smooth`,block:`start`}))}catch{K(`保存历史失败,请检查浏览器是否允许本地存储或剩余空间是否充足`)}},vt=e=>{let t=new Map(C.map(e=>[e.code,e]));Ee(e.codes.map(e=>({color:e===null?null:t.get(e)??C[0]}))),b(e.width),S(e.height),f(e.width),g(e.height),E(e.colorLimit),i(e.name),V(new Set),K(`已恢复历史图纸:${e.name}`),document.getElementById(`pattern-preview`)?.scrollIntoView({behavior:`smooth`})},yt=async e=>{try{await gt(Fe.filter(t=>t.id!==e))}catch{K(`删除历史失败,请稍后重试`)}},bt=(0,r.useMemo)(()=>{let e=Le.trim().toLowerCase();return Fe.filter(t=>!e||t.name.toLowerCase().includes(e)||`${t.width}x${t.height}`.includes(e))},[Fe,Le]);return(0,a.jsxs)(`main`,{children:[(0,a.jsxs)(`header`,{className:`topbar`,children:[(0,a.jsxs)(`a`,{className:`brand`,href:`#top`,"aria-label":`豆格工坊首页`,children:[(0,a.jsxs)(`span`,{className:`brand-mark`,"aria-hidden":`true`,children:[(0,a.jsx)(`i`,{}),(0,a.jsx)(`i`,{}),(0,a.jsx)(`i`,{}),(0,a.jsx)(`i`,{})]}),(0,a.jsx)(`span`,{children:`豆格工坊`})]}),(0,a.jsx)(`span`,{className:`top-note`,children:`图片转拼豆图纸 · 本地处理`})]}),(0,a.jsxs)(`section`,{className:`hero`,id:`top`,children:[(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`eyebrow`,children:`PIXEL BEAD STUDIO`}),(0,a.jsxs)(`h1`,{children:[`把喜欢的图片,`,(0,a.jsx)(`br`,{}),(0,a.jsx)(`em`,{children:`变成一格一格的快乐。`})]}),(0,a.jsx)(`p`,{className:`hero-copy`,children:`上传图片,选择图纸大小和颜色数量;点击任意像素格,就能单独查看该颜色需要摆放的区域。`})]}),(0,a.jsxs)(`div`,{className:`hero-badge`,children:[(0,a.jsxs)(`strong`,{children:[y,` × `,x]}),(0,a.jsx)(`span`,{children:`当前图纸格数`})]})]}),(0,a.jsxs)(`section`,{className:`workspace`,"aria-label":`拼豆图纸转换工具`,children:[(0,a.jsxs)(`aside`,{className:`control-panel`,children:[(0,a.jsxs)(`div`,{className:`panel-heading`,children:[(0,a.jsx)(`span`,{children:`01`}),(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`h2`,{children:`图片与规格`}),(0,a.jsx)(`p`,{children:`先决定图纸需要多少格`})]})]}),(0,a.jsxs)(`div`,{className:`upload-card crop-preview`,style:{aspectRatio:`${Math.max(8,l||8)} / ${Math.max(8,p||8)}`},children:[(0,a.jsx)(`canvas`,{ref:He,"aria-label":`当前取景区域预览`}),(0,a.jsx)(`button`,{type:`button`,className:`upload-overlay`,onClick:()=>Be.current?.click(),children:`更换图片`}),(0,a.jsx)(`input`,{ref:Be,className:`file-input`,type:`file`,accept:`image/png,image/jpeg,image/webp`,onChange:Xe})]}),(0,a.jsx)(`p`,{className:`file-name`,title:n,children:n}),(0,a.jsx)(`button`,{className:`crop-select-button`,onClick:Ze,children:`选择取景区域`}),(0,a.jsx)(`button`,{className:`reset-crop`,onClick:()=>{A(o),M(o),K(`已恢复使用整张图片`)},children:`使用整张图片`}),s,(0,a.jsxs)(`div`,{className:`field-row`,children:[(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`span`,{children:`横向格数`}),(0,a.jsx)(`input`,{type:`number`,min:`8`,max:`256`,value:l,onChange:e=>f(Number(e.target.value))})]}),(0,a.jsx)(`span`,{className:`times`,children:`×`}),(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`span`,{children:`纵向格数`}),(0,a.jsx)(`input`,{type:`number`,min:`8`,max:`256`,value:p,onChange:e=>g(Number(e.target.value))})]})]}),(0,a.jsxs)(`label`,{className:`field`,children:[(0,a.jsxs)(`span`,{children:[`最多使用颜色 `,(0,a.jsx)(`b`,{children:w})]}),(0,a.jsx)(`input`,{type:`range`,min:`2`,max:`64`,value:w,onChange:e=>E(Number(e.target.value))})]}),(0,a.jsxs)(`label`,{className:`field`,children:[(0,a.jsx)(`span`,{children:`取色策略`}),(0,a.jsxs)(`select`,{value:O,onChange:e=>ne(e.target.value),children:[(0,a.jsx)(`option`,{value:`dominant`,children:`区域主色(减少杂色)`}),(0,a.jsx)(`option`,{value:`smooth`,children:`平滑取色(细节丰富)`})]})]}),(0,a.jsxs)(`label`,{className:`field`,children:[(0,a.jsx)(`span`,{children:`图片适应方式`}),(0,a.jsxs)(`select`,{value:D,onChange:e=>te(e.target.value),children:[(0,a.jsx)(`option`,{value:`contain`,children:`完整显示`}),(0,a.jsx)(`option`,{value:`cover`,children:`裁剪铺满`})]})]}),(0,a.jsx)(`button`,{className:`primary-button`,onClick:()=>qe(),children:`重新转换`}),(0,a.jsx)(`p`,{className:`privacy-note`,children:`图片只在当前浏览器中处理,不会上传到服务器。`})]}),(0,a.jsxs)(`section`,{className:`pattern-panel`,id:`pattern-preview`,children:[(0,a.jsxs)(`div`,{className:`pattern-toolbar`,children:[(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`section-kicker`,children:`02 / 图纸预览`}),(0,a.jsx)(`h2`,{children:`点击格子,筛选颜色`})]}),(0,a.jsxs)(`div`,{className:`zoom-control`,"aria-label":`图纸缩放`,children:[(0,a.jsx)(`button`,{onClick:()=>ke(e=>Math.max(3,e-1)),"aria-label":`缩小`,children:``}),(0,a.jsx)(`input`,{"aria-label":`缩放比例`,type:`range`,min:`3`,max:`42`,step:`1`,value:H,onChange:e=>ke(Number(e.target.value))}),(0,a.jsx)(`button`,{onClick:()=>ke(e=>Math.min(42,e+1)),"aria-label":`放大`,children:``}),(0,a.jsxs)(`output`,{children:[H,`px`]})]})]}),(0,a.jsx)(`div`,{className:`canvas-viewport`,children:(0,a.jsx)(`div`,{className:`canvas-stage`,ref:Y,title:`鼠标位于预览区时,可滚动滚轮缩放图纸`,children:(0,a.jsxs)(`div`,{className:`canvas-wrap`,children:[(0,a.jsx)(`canvas`,{ref:J,onPointerDown:lt,onPointerMove:ut,onPointerUp:dt,onPointerCancel:ft,onLostPointerCapture:pt,onContextMenu:e=>e.preventDefault(),onClick:mt,onMouseMove:ht,onMouseLeave:()=>G(null),"aria-label":`转换后的拼豆像素图,可拖动查看,轻点格子选择颜色`}),W&&(0,a.jsxs)(`div`,{className:`pixel-tooltip`,style:{left:W.left,top:W.top},children:[(0,a.jsx)(`span`,{className:`tooltip-swatch`,style:{backgroundColor:W.color.hex}}),(0,a.jsxs)(`strong`,{children:[`第 `,W.row,` 行 · 第 `,W.column,` 列`]}),(0,a.jsxs)(`small`,{children:[W.color.code,` · `,W.color.name,` · `,W.color.hex]})]})]})})}),(0,a.jsxs)(`div`,{className:`pattern-footer`,children:[(0,a.jsx)(`span`,{className:`status-dot`}),` `,(0,a.jsx)(`span`,{children:ze}),(0,a.jsxs)(`div`,{className:`view-options`,children:[(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`input`,{type:`checkbox`,checked:U,onChange:e=>Ae(e.target.checked)}),` 网格`]}),(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`input`,{type:`checkbox`,checked:je,onChange:e=>Me(e.target.checked)}),` 格内编号`]}),(0,a.jsx)(`button`,{className:`save-button`,onClick:_t,children:`保存历史`}),(0,a.jsx)(`button`,{onClick:()=>{if(!z.length)return;let e=Math.max(y,x),t=Math.max(24,Math.min(e<=120?56:e<=180?40:32,Math.floor(8120/e))),n=Math.max(48,t+16),r=y*t,i=x*t,a=n+r,o=Math.max(1,Math.floor((a-36)/128)),s=Math.ceil($.length/o),l=$.length>0?36+s*42:0,u=document.createElement(`canvas`);u.width=a,u.height=n+i+l;let d=u.getContext(`2d`);if(!d)return;d.fillStyle=`#ffffff`,d.fillRect(0,0,u.width,u.height),d.fillStyle=`#f0eee7`,d.fillRect(n,0,r,n),d.fillRect(0,n,n,i),d.strokeStyle=`rgba(32,38,36,.34)`,d.lineWidth=1,d.font=`700 ${Math.max(9,Math.floor(t*.32))}px Arial`,d.fillStyle=`#45504b`,d.textAlign=`center`,d.textBaseline=`middle`;for(let e=0;e<y;e+=1){let r=n+e*t;d.strokeRect(r+.5,.5,t-1,n-1),d.fillText(String(e+1),r+t/2,n/2)}for(let e=0;e<x;e+=1){let r=n+e*t;d.strokeRect(.5,r+.5,n-1,t-1),d.fillText(h(e+1),n/2,r+t/2)}z.forEach(({color:e},r)=>{let i=r%y,a=Math.floor(r/y),o=n+i*t,s=n+a*t;if(e){d.fillStyle=e.hex,d.fillRect(o,s,t,t);let n=e.code,[r,i,a]=T(e.hex);d.fillStyle=r*.299+i*.587+a*.114>160?`#18211d`:`#ffffff`;let c=Math.max(8,Math.floor(t*.31));for(d.font=`700 ${c}px Arial`;c>8&&d.measureText(n).width>t-5;)--c,d.font=`700 ${c}px Arial`;d.textAlign=`center`,d.textBaseline=`middle`,d.fillText(n,o+t/2,s+t/2)}d.strokeStyle=`rgba(32,38,36,.24)`,d.lineWidth=1,d.strokeRect(o+.5,s+.5,t-1,t-1)}),d.strokeStyle=`rgba(32,38,36,.58)`,d.lineWidth=2;for(let e=5;e<y;e+=5){let r=n+e*t;d.beginPath(),d.moveTo(r,n),d.lineTo(r,n+i),d.stroke()}for(let e=5;e<x;e+=5){let i=n+e*t;d.beginPath(),d.moveTo(n,i),d.lineTo(n+r,i),d.stroke()}d.strokeStyle=`#202624`,d.lineWidth=2,d.strokeRect(n,n,r,i);let f=n+i;$.length>0&&(d.strokeStyle=`#d7d2c7`,d.lineWidth=1,d.beginPath(),d.moveTo(0,f+.5),d.lineTo(a,f+.5),d.stroke(),$.forEach((e,t)=>{let n=t%o,r=Math.floor(t/o),i=18+n*128,a=f+18+r*42;d.fillStyle=e.hex,d.beginPath(),d.arc(i+12,a+13,10,0,Math.PI*2),d.fill(),d.strokeStyle=`rgba(32,38,36,.28)`,d.lineWidth=1,d.stroke(),d.fillStyle=`#202624`,d.font=`700 13px Arial`,d.textAlign=`left`,d.textBaseline=`middle`,d.fillText(`${e.code} · ${e.count}颗`,i+28,a+13)})),u.toBlob(e=>{if(!e){K(`PNG 生成失败,请减少图纸格数后重试`);return}let t=URL.createObjectURL(e),n=document.createElement(`a`);n.download=`拼豆图纸-${y}x${x}.png`,n.href=t,n.click(),window.setTimeout(()=>URL.revokeObjectURL(t),1e3),K(`高清 PNG 已生成:${u.width} × ${u.height}px,底部图例包含色号和用量`),c({event:`download_png`,width:y,height:x,colors:$.length,export_width:u.width,export_height:u.height})},`image/png`)},children:`下载高清 PNG`})]})]}),(0,a.jsxs)(`div`,{className:`pattern-legend`,children:[(0,a.jsxs)(`div`,{className:`legend-heading`,children:[(0,a.jsx)(`strong`,{children:`本图所需颜色与用量`}),(0,a.jsxs)(`span`,{children:[`按数量从多到少,共 `,$.length,` 色`]})]}),(0,a.jsx)(`div`,{className:`legend-list`,children:$.map(e=>(0,a.jsxs)(`button`,{className:B.has(e.code)?`active`:``,onClick:()=>ct(e.code),children:[(0,a.jsx)(`i`,{style:{backgroundColor:e.hex}}),(0,a.jsx)(`strong`,{children:e.code}),(0,a.jsx)(`span`,{children:e.name}),(0,a.jsxs)(`b`,{children:[e.count,` 颗`]})]},e.code))})]})]}),(0,a.jsxs)(`aside`,{className:`color-panel`,children:[(0,a.jsxs)(`div`,{className:`panel-heading`,children:[(0,a.jsx)(`span`,{children:`03`}),(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`h2`,{children:`分色查看`}),(0,a.jsxs)(`p`,{children:[$.length,` 种颜色 · `,Je,` 颗`]})]})]}),(0,a.jsxs)(`div`,{className:`search-box`,children:[(0,a.jsx)(`span`,{children:`⌕`}),(0,a.jsx)(`input`,{value:Ne,onChange:e=>Pe(e.target.value),placeholder:`输入 A6、MARD A 或 #FEAC4C`})]}),(0,a.jsxs)(`div`,{className:`selection-tools`,children:[(0,a.jsxs)(`label`,{className:`switch-row`,children:[(0,a.jsx)(`input`,{type:`checkbox`,checked:De,onChange:e=>Oe(e.target.checked)}),(0,a.jsx)(`span`,{className:`switch`}),(0,a.jsx)(`span`,{children:`只显示选中颜色`})]}),B.size>0&&(0,a.jsxs)(`button`,{onClick:()=>V(new Set),children:[`清除 `,B.size,` 项`]})]}),(0,a.jsx)(`div`,{className:`color-list`,children:Ye.map(e=>{let t=B.has(e.code);return(0,a.jsxs)(`button`,{className:`color-item ${t?`active`:``}`,onClick:()=>ct(e.code),"aria-pressed":t,children:[(0,a.jsx)(`span`,{className:`swatch`,style:{backgroundColor:e.hex}}),(0,a.jsxs)(`span`,{className:`color-meta`,children:[(0,a.jsxs)(`strong`,{children:[e.code,` · `,e.name]}),(0,a.jsx)(`small`,{children:e.hex})]}),(0,a.jsxs)(`b`,{children:[e.count,(0,a.jsx)(`small`,{children:`颗`})]})]},e.code)})}),(0,a.jsxs)(`p`,{className:`palette-note`,children:[(0,a.jsx)(`strong`,{children:`MARD 221 基础色卡`}),`:默认使用 A/B/C/D/E/F/G/H/M 九个系列。屏幕色值仅用于近似匹配,实体豆颜色会受批次、光线和屏幕影响。`]})]})]}),P&&(0,a.jsx)(`div`,{className:`crop-dialog-backdrop`,role:`presentation`,onMouseDown:e=>{e.target===e.currentTarget&&F(!1)},children:(0,a.jsxs)(`section`,{className:`crop-dialog`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`crop-dialog-title`,children:[(0,a.jsxs)(`div`,{className:`crop-dialog-header`,children:[I===`pattern-import`?(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`section-kicker`,children:`MARD PATTERN IMPORT`}),(0,a.jsx)(`h2`,{id:`crop-dialog-title`,children:`导入现成 MARD 图纸`}),(0,a.jsx)(`p`,{children:`选框边缘请贴合实际格子区域,不要包含外侧行列标尺;再填写网格的列数和行数。`})]}):(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`section-kicker`,children:`IMAGE CROP`}),(0,a.jsx)(`h2`,{id:`crop-dialog-title`,children:`框选需要转换的区域`}),(0,a.jsx)(`p`,{children:`框内拖动可移动,控制点可调整大小;生成格子时以所选区域正中心为采样基准。`})]}),(0,a.jsx)(`button`,{"aria-label":`关闭取景窗口`,onClick:()=>F(!1),children:`×`})]}),(0,a.jsxs)(`div`,{className:`crop-mode-bar`,children:[I===`pattern-import`?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(`div`,{className:`pattern-import-dimensions`,children:[(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`span`,{children:`横向列数`}),(0,a.jsx)(`input`,{"aria-label":`导入图纸横向列数`,type:`number`,min:`1`,max:`256`,value:L,onChange:e=>ge(Number(e.target.value))})]}),(0,a.jsx)(`b`,{children:`×`}),(0,a.jsxs)(`label`,{children:[(0,a.jsx)(`span`,{children:`纵向行数`}),(0,a.jsx)(`input`,{"aria-label":`导入图纸纵向行数`,type:`number`,min:`1`,max:`256`,value:R,onChange:e=>_e(Number(e.target.value))})]})]}),(0,a.jsxs)(`label`,{className:`pattern-import-empty-option`,children:[(0,a.jsx)(`input`,{type:`checkbox`,checked:ve,onChange:e=>ye(e.target.checked)}),` 没有识别到 MARD 编码的格子视为空白`]})]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(`span`,{children:`选框形状`}),(0,a.jsxs)(`div`,{className:`crop-mode-switch`,role:`group`,"aria-label":`选框形状`,children:[(0,a.jsx)(`button`,{className:N===`free`?`active`:``,"aria-pressed":N===`free`,onClick:()=>tt(`free`),children:`自由矩形`}),(0,a.jsx)(`button`,{className:N===`square`?`active`:``,"aria-pressed":N===`square`,onClick:()=>tt(`square`),children:`正方形`})]})]}),(0,a.jsxs)(`span`,{className:`crop-size-readout`,children:[`当前选框:`,Math.round(j.width*100),`% × `,Math.round(j.height*100),`%`]})]}),(0,a.jsx)(`div`,{className:`crop-dialog-scroll`,children:(0,a.jsxs)(`div`,{className:`crop-dialog-stage`,ref:Ke,onPointerDown:rt,onPointerMove:it,onPointerUp:at,onPointerCancel:at,onPointerLeave:e=>{X.current||e.currentTarget.classList.remove(`can-move-selection`)},children:[(0,a.jsx)(`canvas`,{ref:Ue,"aria-label":`可框选的原始大图`}),(0,a.jsx)(`div`,{className:`crop-selection-mask crop-selection-top`,style:{height:`${j.y*100}%`}}),(0,a.jsx)(`div`,{className:`crop-selection-mask crop-selection-left`,style:{top:`${j.y*100}%`,width:`${j.x*100}%`,height:`${j.height*100}%`}}),(0,a.jsx)(`div`,{className:`crop-selection-mask crop-selection-right`,style:{top:`${j.y*100}%`,left:`${(j.x+j.width)*100}%`,right:0,height:`${j.height*100}%`}}),(0,a.jsx)(`div`,{className:`crop-selection-mask crop-selection-bottom`,style:{top:`${(j.y+j.height)*100}%`}}),(0,a.jsxs)(`div`,{className:`crop-selection-box`,style:{left:`${j.x*100}%`,top:`${j.y*100}%`,width:`${j.width*100}%`,height:`${j.height*100}%`},children:[I===`pattern-import`&&L>0&&R>0&&(0,a.jsx)(`i`,{className:`pattern-import-grid-overlay`,style:{backgroundSize:`${100/L}% 100%, 100% ${100/R}%`},"aria-hidden":`true`}),[`nw`,`ne`,`sw`,`se`].map(e=>(0,a.jsx)(`i`,{className:`crop-resize-handle handle-${e}`,"data-crop-handle":e,"aria-hidden":`true`},e)),N===`free`&&[`n`,`s`,`e`,`w`].map(e=>(0,a.jsx)(`i`,{className:`crop-resize-handle crop-edge-handle handle-${e}`,"data-crop-handle":e,"aria-hidden":`true`},e))]})]})}),(0,a.jsxs)(`div`,{className:`crop-dialog-actions`,children:[(0,a.jsx)(`button`,{onClick:()=>{me(`free`),M(o)},children:`选择整张图`}),(0,a.jsx)(`span`,{children:I===`pattern-import`?`对齐越准确,格内编码与底色识别越可靠`:`框外拖动可重选,框内拖动可移动,控制点可缩放`}),(0,a.jsx)(`button`,{onClick:()=>F(!1),children:`取消`}),(0,a.jsx)(`button`,{className:`confirm`,disabled:we||j.width<.03||j.height<.03||I===`pattern-import`&&(L<1||L>256||R<1||R>256),onClick:st,children:I===`pattern-import`?we?`正在识别…`:`识别并导入`:`使用此区域`})]})]})}),(0,a.jsxs)(`section`,{className:`history-section`,"aria-labelledby":`history-title`,children:[(0,a.jsxs)(`div`,{className:`history-heading`,children:[(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`p`,{className:`section-kicker`,children:`LOCAL PATTERN ARCHIVE`}),(0,a.jsx)(`h2`,{id:`history-title`,children:`历史图纸`}),(0,a.jsx)(`p`,{children:`历史保存在当前浏览器,最多保留 30 份。`})]}),(0,a.jsxs)(`div`,{className:`search-box`,children:[(0,a.jsx)(`span`,{children:`⌕`}),(0,a.jsx)(`input`,{value:Le,onChange:e=>Re(e.target.value),placeholder:`按名称或 32x32 查询`})]})]}),bt.length?(0,a.jsx)(`div`,{className:`history-grid`,children:bt.map(e=>(0,a.jsxs)(`article`,{className:`history-card`,children:[(0,a.jsx)(ee,{entry:e}),(0,a.jsxs)(`div`,{children:[(0,a.jsx)(`h3`,{children:e.name}),(0,a.jsxs)(`p`,{children:[e.width,` × `,e.height,` · `,new Date(e.savedAt).toLocaleString(`zh-CN`,{hour12:!1})]})]}),(0,a.jsxs)(`div`,{className:`history-actions`,children:[(0,a.jsx)(`button`,{onClick:()=>vt(e),children:`打开`}),(0,a.jsx)(`button`,{onClick:()=>yt(e.id),children:`删除`})]})]},e.id))}):(0,a.jsx)(`div`,{className:`history-empty`,children:`还没有符合条件的历史图纸。转换完成后点击“保存历史”即可在这里查询。`})]})]})}export{M as default};