IOPaint/lama_cleaner/app/build/static/js/main.56b43b57.chunk.js.map
2021-11-15 22:21:01 +08:00

1 line
42 KiB
Plaintext

{"version":3,"sources":["components/Button.tsx","components/FileSelect.tsx","utils.ts","adapters/inpainting.ts","components/Slider.tsx","Editor.tsx","App.tsx","index.tsx"],"names":["Button","props","children","className","disabled","icon","primary","onClick","onDown","onUp","useState","active","setActive","background","role","onKeyDown","onPointerDown","ev","nativeEvent","onPointerUp","tabIndex","join","FileSelect","onSelection","dragHover","setDragHover","Math","random","toString","uploadElemId","onFileSelected","file","type","match","size","Error","e","alert","message","getFile","entry","a","Promise","resolve","getAllFileEntries","items","fileEntries","queue","i","length","push","webkitGetAsEntry","shift","isFile","isDirectory","readAllDirectoryEntries","createReader","directoryReader","entries","readEntriesPromise","readEntries","reject","preventDefault","dataTransfer","htmlFor","onDrop","onDragOver","stopPropagation","onDragLeave","id","name","onChange","currentTarget","files","accept","dataURItoBlob","dataURI","mime","split","binary","atob","array","charCodeAt","Blob","Uint8Array","loadImage","image","src","initSRC","img","onload","onerror","err","resizeImageFile","maxSize","reader","FileReader","Image","canvas","document","createElement","readerEvent","width","height","resized","getContext","drawImage","blob","toDataURL","File","originalWidth","originalHeight","resize","target","result","readAsDataURL","API_ENDPOINT","process","inpaint","imageFile","maskBase64","fd","FormData","append","mask","fetch","method","body","then","r","res","URL","createObjectURL","Slider","value","label","min","max","step","parseInt","BRUSH_COLOR","drawLines","ctx","lines","color","strokeStyle","lineCap","lineJoin","forEach","line","pts","lineWidth","beginPath","moveTo","x","y","pt","lineTo","stroke","Editor","brushSize","setBrushSize","isLoaded","setIsLoaded","useEffect","useImage","original","isOriginalLoaded","renders","setRenders","context","setContext","maskCanvas","setLines","setCoords","showBrush","setShowBrush","showOriginal","setShowOriginal","isInpaintingLoading","setIsInpaintingLoading","showSeparator","setShowSeparator","scale","setScale","windowSize","useWindowSize","draw","useCallback","clearRect","currRender","currentLine","refreshCanvasMask","naturalWidth","naturalHeight","rW","rH","onMouseMove","pageX","pageY","onPaint","px","py","onMouseDrag","offsetX","offsetY","removeEventListener","window","Date","now","newRender","addEventListener","onTouchMove","currLine","coords","getBoundingClientRect","touches","clientX","clientY","onPointerStart","onmouseenter","onmouseleave","onmousedown","undo","l","pop","handler","event","metaKey","ctrlKey","key","style","undefined","transform","transformOrigin","cursor","ref","round","transitionProperty","transitionTimingFunction","transitionDuration","alt","maxWidth","left","top","viewBox","fill","xmlns","d","setTimeout","base64","uri","link","href","download","dispatchEvent","MouseEvent","bubbles","cancelable","view","remove","downloadImage","replace","App","setFile","f","resizedFile","ReactDOM","render","getElementById"],"mappings":"uOAae,SAASA,EAAOC,GAC7B,IACEC,EAQED,EARFC,SACAC,EAOEF,EAPFE,UACAC,EAMEH,EANFG,SACAC,EAKEJ,EALFI,KACAC,EAIEL,EAJFK,QACAC,EAGEN,EAHFM,QACAC,EAEEP,EAFFO,OACAC,EACER,EADFQ,KAEF,EAA4BC,oBAAS,GAArC,mBAAOC,EAAP,KAAeC,EAAf,KACIC,EAAa,GAUjB,OATIP,IAAYF,IACdS,EAAa,8CAEXF,IACFE,EAAa,uBAEVP,GAAYK,IACfE,EAAa,oBAGb,sBACEC,KAAK,SACLC,UAAWR,EACXA,QAASA,EACTS,cAAe,SAACC,GACdL,GAAU,GACJ,OAANJ,QAAM,IAANA,KAASS,EAAGC,cAEdC,YAAa,SAACF,GACZL,GAAU,GACN,OAAJH,QAAI,IAAJA,KAAOQ,EAAGC,cAEZE,UAAW,EACXjB,UAAW,CACT,kDACAD,EAAW,YAAc,GACzBW,EACAT,EAAW,iCAAmC,GAC9CD,GACAkB,KAAK,KAnBT,UAqBGhB,EACD,sBAAMF,UAAU,gCAAhB,SAAiDD,O,WCpDxC,SAASoB,EAAWrB,GACjC,IAAQsB,EAAgBtB,EAAhBsB,YAER,EAAkCb,oBAAS,GAA3C,mBAAOc,EAAP,KAAkBC,EAAlB,KACA,EAAuBf,mBAAS,eAAD,OAAgBgB,KAAKC,SAASC,aAAtDC,EAAP,oBAEA,SAASC,EAAeC,GACtB,GAAKA,GAIWA,EAAKC,KAAKC,MAAM,WAIhC,IAEE,GAAIF,EAAKG,KAAO,SACd,MAAM,IAAIC,MAAM,kBAElBZ,EAAYQ,GACZ,MAAOK,GAEPC,MAAM,UAAD,OAAYD,EAAUE,WAvB0B,SA2B1CC,EA3B0C,8EA2BzD,WAAuBC,GAAvB,SAAAC,EAAA,+EACS,IAAIC,SAAQ,SAAAC,GACjBH,EAAMT,MAAK,SAACA,GAAD,OAAgBY,EAAQZ,UAFvC,4CA3ByD,+BAoC1Ca,EApC0C,8EAoCzD,WAAiCC,GAAjC,uBAAAJ,EAAA,sDAKE,IAJMK,EAA2B,GAE3BC,EAAQ,GAELC,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,GAAK,EACrCD,EAAMG,KAAKL,EAAMG,GAAGG,oBANxB,YAQSJ,EAAME,OAAS,GARxB,8BASUT,EAAQO,EAAMK,eATxB,IAUQZ,OAVR,EAUQA,EAAOa,QAVf,iCAYyBd,EAAQC,GAZjC,OAYYT,EAZZ,OAaMe,EAAYI,KAAKnB,GAbvB,oCAceS,QAdf,IAceA,OAdf,EAceA,EAAOc,aAdtB,6BAeMP,EAAMG,KAfZ,KAeMH,EAfN,mBAgBkBQ,EAAyBf,EAAcgB,gBAhBzD,gIAoBSV,GApBT,6CApCyD,+BA6D1CS,EA7D0C,8EA6DzD,WAAuCE,GAAvC,iBAAAhB,EAAA,6DACQiB,EAAU,GADlB,SAE0BC,EAAmBF,GAF7C,OAEMG,EAFN,mBAGSA,EAAYX,OAAS,GAH9B,wBAIIS,EAAQR,KAAR,MAAAQ,EAAO,YAASE,IAJpB,SAKwBD,EAAmBF,GAL3C,OAKIG,EALJ,uDAOSF,GAPT,6CA7DyD,+BA4E1CC,EA5E0C,8EA4EzD,WAAkCF,GAAlC,SAAAhB,EAAA,+EACS,IAAIC,SAAQ,SAACC,EAASkB,GAC3BJ,EAAgBG,YAAYjB,EAASkB,OAFzC,4CA5EyD,kEAkFzD,WAA0B5C,GAA1B,eAAAwB,EAAA,6DACExB,EAAG6C,iBADL,SAEsBlB,EAAkB3B,EAAG8C,aAAalB,OAFxD,OAEQA,EAFR,OAGEpB,GAAa,GACbK,EAAee,EAAM,IAJvB,4CAlFyD,sBAyFzD,OACE,uBACEmB,QAASnC,EACT1B,UAAU,qGAFZ,SAIE,sBACEA,UAAW,CACT,wEACA,oCACA,sCACA,cACAqB,EAAY,0BAA4B,+BACxCH,KAAK,KACP4C,OAtGmD,4CAuGnDC,WAAY,SAAAjD,GACVA,EAAGkD,kBACHlD,EAAG6C,iBACHrC,GAAa,IAEf2C,YAAa,kBAAM3C,GAAa,IAdlC,UAgBE,uBACE4C,GAAIxC,EACJyC,KAAMzC,EACNG,KAAK,OACL7B,UAAU,UACVoE,SAAU,SAAAtD,GAAO,IAAD,EACRc,EAAI,UAAGd,EAAGuD,cAAcC,aAApB,aAAG,EAAyB,GAClC1C,GACFD,EAAeC,IAGnB2C,OAAO,0BAET,mBAAGvE,UAAU,kBAAb,8CACA,mBAAGA,UAAU,YAAb,gDChID,SAASwE,EAAcC,GAI5B,IAHA,IAAMC,EAAOD,EAAQE,MAAM,KAAK,GAAGA,MAAM,KAAK,GAAGA,MAAM,KAAK,GACtDC,EAASC,KAAKJ,EAAQE,MAAM,KAAK,IACjCG,EAAQ,GACLjC,EAAI,EAAGA,EAAI+B,EAAO9B,OAAQD,GAAK,EACtCiC,EAAM/B,KAAK6B,EAAOG,WAAWlC,IAE/B,OAAO,IAAImC,KAAK,CAAC,IAAIC,WAAWH,IAAS,CAAEjD,KAAM6C,IAsD5C,SAASQ,EAAUC,EAAyBC,GACjD,OAAO,IAAI7C,SAAQ,SAACC,EAASkB,GAC3B,IAAM2B,EAAUF,EAAMC,IAChBE,EAAMH,EACZG,EAAIC,OAAS/C,EACb8C,EAAIE,QAAU,SAAAC,GACZH,EAAIF,IAAMC,EACV3B,EAAO+B,IAETH,EAAIF,IAAMA,KA6BP,SAASM,EACd9D,EACA+D,GAEA,IAAMC,EAAS,IAAIC,WACbV,EAAQ,IAAIW,MACZC,EAASC,SAASC,cAAc,UAuCtC,OAAO,IAAI1D,SAAQ,SAACC,EAASkB,GACtB9B,EAAKC,KAAKC,MAAM,YAIrB8D,EAAOL,OAAS,SAACW,GACff,EAAMI,OAAS,kBAAM/C,EA3CV,WAA8B,IAAD,EACpC2D,EAAkBhB,EAAlBgB,MAAOC,EAAWjB,EAAXiB,OAYb,GAVID,EAAQC,EACND,EAAQR,IACVS,GAAUT,EAAUQ,EACpBA,EAAQR,GAEDS,EAAST,IAClBQ,GAASR,EAAUS,EACnBA,EAAST,GAGPQ,IAAUhB,EAAMgB,OAASC,IAAWjB,EAAMiB,OAC5C,MAAO,CAAExE,OAAMyE,SAAS,GAM1B,GAHAN,EAAOI,MAAQA,EACfJ,EAAOK,OAASA,GACJL,EAAOO,WAAW,MAE5B,MAAM,IAAItE,MAAM,yBAElB,UAAA+D,EAAOO,WAAW,aAAlB,SAAyBC,UAAUpB,EAAO,EAAG,EAAGgB,EAAOC,GACvD,IACMI,EAAOhC,EADGuB,EAAOU,UAAU,eAKjC,MAAO,CACL7E,KAJQ,IAAI8E,KAAK,CAACF,GAAO5E,EAAKuC,KAAM,CACpCtC,KAAMD,EAAKC,OAIXwE,SAAS,EACTM,cAAexB,EAAMgB,MACrBS,eAAgBzB,EAAMiB,QAUOS,KAC7B1B,EAAMC,IAAMc,EAAYY,OAAOC,QAEjCnB,EAAOoB,cAAcpF,IAPnB8B,EAAO,IAAI1B,MAAM,oBClJhB,IAAMiF,EAAY,UAAMC,GAAN,YAEV,SAAeC,EAA9B,oC,4CAAe,WAAuBC,EAAiBC,GAAxC,mBAAA/E,EAAA,6DACPgF,EAAK,IAAIC,UACZC,OAAO,QAASJ,GACbK,EAAOjD,EAAc6C,GAC3BC,EAAGE,OAAO,OAAQC,GAJL,SAMKC,MAAMT,EAAc,CACpCU,OAAQ,OACRC,KAAMN,IACLO,KAHe,uCAGV,WAAMC,GAAN,SAAAxF,EAAA,+EACCwF,EAAEtB,QADH,2CAHU,uDANL,cAMPuB,EANO,yBAaNC,IAAIC,gBAAgBF,IAbd,2C,wBCMA,SAASG,EAAOpI,GAC7B,IAAQqI,EAAqCrI,EAArCqI,MAAO/D,EAA8BtE,EAA9BsE,SAAUgE,EAAoBtI,EAApBsI,MAAOC,EAAavI,EAAbuI,IAAKC,EAAQxI,EAARwI,IAE/BC,IAASD,GAAO,MAAQD,GAAO,IAAM,IAE3C,OACE,sBAAKrI,UAAU,gDAAf,UACE,+BAAOoI,IACP,uBACEpI,UAAW,CACT,iCACA,aACA,kBACAkB,KAAK,KACPW,KAAK,QACL0G,KAAMA,EACNF,IAAKA,EACLC,IAAKA,EACLH,MAAOA,EACP/D,SAAU,SAAAtD,GACRA,EAAG6C,iBACH7C,EAAGkD,kBACHI,EAASoE,SAAS1H,EAAGuD,cAAc8D,MAAO,WCxBpD,IACMM,EAAc,0BAWpB,SAASC,EACPC,EACAC,GAEC,IADDC,EACA,uDADQJ,EAERE,EAAIG,YAAcD,EAClBF,EAAII,QAAU,QACdJ,EAAIK,SAAW,QAEfJ,EAAMK,SAAQ,SAAAC,IACR,OAACA,QAAD,IAACA,OAAD,EAACA,EAAMC,IAAIrG,SAAWoG,EAAKnH,OAG/B4G,EAAIS,UAAYF,EAAKnH,KACrB4G,EAAIU,YACJV,EAAIW,OAAOJ,EAAKC,IAAI,GAAGI,EAAGL,EAAKC,IAAI,GAAGK,GACtCN,EAAKC,IAAIF,SAAQ,SAAAQ,GAAE,OAAId,EAAIe,OAAOD,EAAGF,EAAGE,EAAGD,MAC3Cb,EAAIgB,aAIO,SAASC,EAAO9J,GAC7B,IAAQ8B,EAAS9B,EAAT8B,KACR,EAAkCrB,mBAAS,IAA3C,mBAAOsJ,EAAP,KAAkBC,EAAlB,KACA,EHgCK,SAAkBlI,GACvB,MAAgBrB,mBAAS,IAAIuF,OAAtBX,EAAP,oBACA,EAAgC5E,oBAAS,GAAzC,mBAAOwJ,EAAP,KAAiBC,EAAjB,KAaA,OAXAC,qBAAU,WAMR,OALA9E,EAAMI,OAAS,WACbyE,GAAY,IAEdA,GAAY,GACZ7E,EAAMC,IAAM4C,IAAIC,gBAAgBrG,GACzB,WACLuD,EAAMI,OAAS,QAEhB,CAAC3D,EAAMuD,IAEH,CAACA,EAAO4E,GG/CsBG,CAAStI,GAA9C,mBAAOuI,EAAP,KAAiBC,EAAjB,KACA,EAA8B7J,mBAA6B,IAA3D,mBAAO8J,EAAP,KAAgBC,EAAhB,KACA,EAA8B/J,qBAA9B,mBAAOgK,EAAP,KAAgBC,EAAhB,KACA,EAAqBjK,oBAA4B,WAC/C,OAAOyF,SAASC,cAAc,aADzBwE,EAAP,oBAGA,EAA0BlK,mBAAiB,CAAC,CAAE4I,IAAK,MAAnD,mBAAOP,EAAP,KAAc8B,EAAd,KACA,EAA8BnK,mBAAS,CAAEgJ,GAAI,EAAGC,GAAI,IAApD,0BAASD,EAAT,EAASA,EAAGC,EAAZ,EAAYA,EAAKmB,EAAjB,KACA,EAAkCpK,oBAAS,GAA3C,mBAAOqK,EAAP,KAAkBC,EAAlB,KACA,EAAwCtK,oBAAS,GAAjD,mBAAOuK,EAAP,KAAqBC,EAArB,KACA,EAAsDxK,oBAAS,GAA/D,mBAAOyK,EAAP,KAA4BC,GAA5B,KACA,GAA0C1K,oBAAS,GAAnD,qBAAO2K,GAAP,MAAsBC,GAAtB,MACA,GAA0B5K,mBAAS,GAAnC,qBAAO6K,GAAP,MAAcC,GAAd,MACMC,GAAaC,cAEbC,GAAOC,uBAAY,WACvB,GAAKlB,EAAL,CAGAA,EAAQmB,UAAU,EAAG,EAAGnB,EAAQxE,OAAOI,MAAOoE,EAAQxE,OAAOK,QAC7D,IAAMuF,EAAatB,EAAQA,EAAQvH,OAAS,IAC5C,OAAI6I,QAAJ,IAAIA,OAAJ,EAAIA,EAAYvG,KACdmF,EAAQhE,UAAUoF,EAAY,EAAG,GAEjCpB,EAAQhE,UAAU4D,EAAU,EAAG,GAEjC,IAAMyB,EAAchD,EAAMA,EAAM9F,OAAS,GACzC4F,EAAU6B,EAAS,CAACqB,OACnB,CAACrB,EAAS3B,EAAOuB,EAAUE,IAExBwB,GAAoBJ,uBAAY,WACpC,KAAI,OAAClB,QAAD,IAACA,OAAD,EAACA,EAASxE,OAAOI,UAAS,OAACoE,QAAD,IAACA,OAAD,EAACA,EAASxE,OAAOK,QAC7C,MAAM,IAAIpE,MAAM,2BAElByI,EAAWtE,MAAX,OAAmBoE,QAAnB,IAAmBA,OAAnB,EAAmBA,EAASxE,OAAOI,MACnCsE,EAAWrE,OAAX,OAAoBmE,QAApB,IAAoBA,OAApB,EAAoBA,EAASxE,OAAOK,OACpC,IAAMuC,EAAM8B,EAAWnE,WAAW,MAClC,IAAKqC,EACH,MAAM,IAAI3G,MAAM,kCAElB0G,EAAUC,EAAKC,EAAO,WACrB,QAAC2B,QAAD,IAACA,OAAD,EAACA,EAASxE,OAAOK,OAAjB,OAAyBmE,QAAzB,IAAyBA,OAAzB,EAAyBA,EAASxE,OAAOI,MAAOyC,EAAO6B,IAG1DR,qBAAU,WACR,IAAI,OAACM,QAAD,IAACA,OAAD,EAACA,EAASxE,SAGVqE,EAAkB,CACpBG,EAAQxE,OAAOI,MAAQgE,EAAS2B,aAChCvB,EAAQxE,OAAOK,OAAS+D,EAAS4B,cACjC,IAAMC,EAAKV,GAAWnF,MAAQgE,EAAS2B,aACjCG,GAAMX,GAAWlF,OAxFR,KAwFiC+D,EAAS4B,cAEvDV,GADEW,EAAK,GAAKC,EAAK,EACR1K,KAAK8G,IAAI2D,EAAIC,GAEb,GAEXT,QAED,QAACjB,QAAD,IAACA,OAAD,EAACA,EAASxE,OAAQyF,GAAMrB,EAAUC,EAAkBkB,KAGvDrB,qBAAU,WACR,IAAMlE,EAAM,OAAGwE,QAAH,IAAGA,OAAH,EAAGA,EAASxE,OACxB,GAAKA,EAAL,CAIA,IAUMmG,EAAc,SAACpL,GACnB6J,EAAU,CAAEpB,EAAGzI,EAAGqL,MAAO3C,EAAG1I,EAAGsL,SAE3BC,EAAU,SAACC,EAAYC,GACV3D,EAAMA,EAAM9F,OAAS,GAC7BqG,IAAIpG,KAAK,CAAEwG,EAAG+C,EAAI9C,EAAG+C,IAC9Bf,MAEIgB,EAAc,SAAC1L,GACnB,IAAMwL,EAAKxL,EAAG2L,QACRF,EAAKzL,EAAG4L,QACdL,EAAQC,EAAIC,IAGRvL,EAAW,uCAAG,8BAAAsB,EAAA,yDACb6H,EAAS/E,IADI,wDAIlB6F,IAAuB,GACvBlF,EAAO4G,oBAAoB,YAAaH,GACxCI,OAAOD,oBAAoB,UAAW3L,GACtC6K,KAPkB,SASFgB,KAAKC,MATH,UAUE3F,EAAQvF,EAAM6I,EAAWhE,aAV3B,WAUVsB,EAVU,8BAYR,IAAI/F,MAAM,kBAZF,eAeV+K,EAAY,IAAIjH,MAfN,UAgBVZ,EAAU6H,EAAWhF,GAhBX,QAiBhBsC,EAAQtH,KAAKgK,GACbnE,EAAM7F,KAAK,CAAEoG,IAAK,KAElBmB,EAAW,YAAID,IACfK,EAAS,YAAI9B,IArBG,kDAwBhB1G,MAAM,KAAEC,QAAU,KAAEA,QAAU,KAAEV,YAxBhB,QA0BlBwJ,IAAuB,GACvBO,KA3BkB,0DAAH,qDA6BjBoB,OAAOI,iBAAiB,YAAad,GAErC,IAAMe,EAAc,SAACnM,GACnBA,EAAG6C,iBACH7C,EAAGkD,kBACH,IAAMkJ,EAAWtE,EAAMA,EAAM9F,OAAS,GAChCqK,EAASpH,EAAOqH,wBACtBF,EAAS/D,IAAIpG,KAAK,CAChBwG,GAAIzI,EAAGuM,QAAQ,GAAGC,QAAUH,EAAO5D,GAAK6B,GACxC5B,GAAI1I,EAAGuM,QAAQ,GAAGE,QAAUJ,EAAO3D,GAAK4B,KAE1CI,MAEIgC,EAAiB,SAAC1M,GACtB,GAAKqJ,EAAS/E,IAAd,CAGiBwD,EAAMA,EAAM9F,OAAS,GAC7Bf,KAAO8H,EAChB9D,EAAOiH,iBAAiB,YAAaR,GACrCI,OAAOI,iBAAiB,UAAWhM,GACnC,IAAMmM,EAASpH,EAAOqH,wBAChBd,GAAMxL,EAAGuM,QAAQ,GAAGC,QAAUH,EAAO5D,GAAK6B,GAC1CmB,GAAMzL,EAAGuM,QAAQ,GAAGE,QAAUJ,EAAO3D,GAAK4B,GAChDiB,EAAQC,EAAIC,KASd,OAPAxG,EAAOiH,iBAAiB,aAAcQ,GACtCzH,EAAOiH,iBAAiB,YAAaC,GACrClH,EAAOiH,iBAAiB,WAAYhM,GACpC+E,EAAO0H,aAAe,kBAAM5C,GAAa,IACzC9E,EAAO2H,aAAe,kBAAM7C,GAAa,IACzC9E,EAAO4H,YApFa,SAAC7M,GACdqJ,EAAS/E,MAGGwD,EAAMA,EAAM9F,OAAS,GAC7Bf,KAAO8H,EAChB9D,EAAOiH,iBAAiB,YAAaR,GACrCI,OAAOI,iBAAiB,UAAWhM,GACnCqL,EAAQvL,EAAG2L,QAAS3L,EAAG4L,WA8ElB,WACL3G,EAAO4G,oBAAoB,YAAaH,GACxCI,OAAOD,oBAAoB,YAAaT,GACxCU,OAAOD,oBAAoB,UAAW3L,GACtC+E,EAAO4G,oBAAoB,aAAca,GACzCzH,EAAO4G,oBAAoB,YAAaM,GACxClH,EAAO4G,oBAAoB,WAAY3L,GACvC+E,EAAO0H,aAAe,KACtB1H,EAAO2H,aAAe,KACtB3H,EAAO4H,YAAc,SAEtB,CACD9D,EACAU,EACA3I,EACA4J,GACA5C,EACAiD,GACApB,EACAN,EAAS/E,IACTiF,EACAF,EAAS4B,cACT5B,EAAS2B,aACTV,KAGF,IAAMwC,GAAOnC,uBAAY,WACvB,IAAMoC,EAAIjF,EACViF,EAAEC,MACFD,EAAEC,MACFpD,EAAS,GAAD,mBAAKmD,GAAL,CAAQ,CAAE1E,IAAK,OACvB,IAAMrB,EAAIuC,EACVvC,EAAEgG,MACFxD,EAAW,YAAIxC,MACd,CAACc,EAAOyB,IA6BX,OA1BAJ,qBAAU,WACR,IAAM8D,EAAU,SAACC,GACV3D,EAAQvH,UAGGkL,EAAMC,SAAWD,EAAME,UAA0B,MAAdF,EAAMG,MAEvDH,EAAMrK,iBACNiK,QAIJ,OADAhB,OAAOI,iBAAiB,UAAWe,GAC5B,WACLnB,OAAOD,oBAAoB,UAAWoB,MAEvC,CAAC1D,EAASuD,KAYX,sBACE5N,UAAW,CACT,6BACAgL,EACI,4DACA,GACM,IAAVI,GAAc,QAAU,IACxBlK,KAAK,KACPkN,MAAO,CACLhI,OAAkB,IAAVgF,GAAcjB,EAAS4B,cAAgBX,QAAQiD,GAT3D,UAYE,sBACErO,UAAW,CAAW,IAAVoL,GAAc,GAAK,YAAYlK,KAAK,KAChDkN,MAAO,CAAEE,UAAU,SAAD,OAAWlD,GAAX,KAAqBmD,gBAAiB,cAF1D,UAIE,wBACEvO,UAAU,aACVoO,MAAOxD,EAAY,CAAE4D,OAAQ,QAAW,GACxCC,IAAK,SAAA3G,GACH,GAAIA,IAAMyC,EAAS,CACjB,IAAM5B,EAAMb,EAAExB,WAAW,MACrBqC,GACF6B,EAAW7B,OAKnB,qBACE3I,UAAW,CACT,6CACA,kBACA,iBACAkL,GAAgB,aAAe,IAE/BhK,KAAK,KACPkN,MAAO,CACLjI,MAAO2E,EAAY,UACZvJ,KAAKmN,MAAMvE,EAAS2B,cADR,MAEf,MACJ1F,OAAQ+D,EAAS4B,cACjB4C,mBAAoB,gBACpBC,yBAA0B,+BAC1BC,mBAAoB,SAfxB,SAkBE,qBACE7O,UAAU,mBACVoF,IAAK+E,EAAS/E,IACd0J,IAAI,WACJ3I,MAAK,UAAKgE,EAAS2B,aAAd,MACL1F,OAAM,UAAK+D,EAAS4B,cAAd,MACNqC,MAAO,CACLjI,MAAM,GAAD,OAAKgE,EAAS2B,aAAd,MACL1F,OAAO,GAAD,OAAK+D,EAAS4B,cAAd,MACNgD,SAAU,eAMjBnE,GACC,qBACE5K,UAAU,2GACVoO,MAAO,CACLjI,MAAM,GAAD,OAAK0D,EAAYuB,GAAjB,MACLhF,OAAO,GAAD,OAAKyD,EAAYuB,GAAjB,MACN4D,KAAK,GAAD,OAAKzF,EAAL,MACJ0F,IAAI,GAAD,OAAKzF,EAAL,MACH8E,UAAW,2BAKjB,sBACEtO,UAAW,CACT,qCACA,yBACA,MACU,IAAVoL,GACI,mCACA,8CACJlK,KAAK,KART,UAUE,cAACgH,EAAD,CACEE,MACE,iCACE,sBAAMpI,UAAU,mBAAhB,mBADF,WAIFqI,IAAK,GACLC,IAAK,IACLH,MAAO0B,EACPzF,SAAU0F,IAEXO,EAAQvH,OACP,qCACE,cAACjD,EAAD,CACEK,KACE,qBACEiG,MAAM,KACNC,OAAO,IACP8I,QAAQ,WACRC,KAAK,OACLC,MAAM,6BACNpP,UAAU,UANZ,SAQE,sBACEqP,EAAE,+nBACFF,KAAK,mBAIX/O,QAASwN,KAEX,cAAC/N,EAAD,CACEK,KAAM,cAAC,IAAD,CAASF,UAAU,YACzBK,OAAQ,SAAAS,GACNA,EAAG6C,iBACHwH,IAAiB,GACjBJ,GAAgB,IAElBzK,KAAM,WACJyK,GAAgB,GAChBuE,YAAW,kBAAMnE,IAAiB,KAAQ,MAT9C,SAYGG,GAAWnF,MAAQ,IAAM,gBAAakI,OAI3C,6BAGF,cAACxO,EAAD,CACEM,SAAO,EACPD,KAAM,cAAC,IAAD,CAAcF,UAAU,YAC9BC,UAAWoK,EAAQvH,OACnB1C,QApJR,WACE,IAAMmP,EAAM,OAAGhF,QAAH,IAAGA,OAAH,EAAGA,EAASxE,OAAOU,UAAU7E,EAAKC,MAC9C,IAAK0N,EACH,MAAM,IAAIvN,MAAM,8BHxOf,SAAuBwN,EAAarL,GACzC,IAAMsL,EAAOzJ,SAASC,cAAc,KACpCwJ,EAAKC,KAAOF,EACZC,EAAKE,SAAWxL,EAGhBsL,EAAKG,cACH,IAAIC,WAAW,QAAS,CACtBC,SAAS,EACTC,YAAY,EACZC,KAAMpD,UAIV0C,YAAW,WAGTG,EAAKQ,WACJ,KGyNDC,CAAcX,EADD3N,EAAKuC,KAAKgM,QAAQ,kBAAmB,gBA2I9C,SAMG7E,GAAWnF,MAAQ,IAAM,gBAAakI,UCnUlC+B,MAxEf,WACE,MAAwB7P,qBAAxB,mBAAOqB,EAAP,KAAayO,EAAb,KACM/E,EAAaC,cAEnB,OACE,sBAAKvL,UAAU,6CAAf,UACE,wBAAQA,UAAU,6FAAlB,SACG4B,EACC,cAAC/B,EAAD,CACEK,KAAM,cAAC,IAAD,CAAeF,UAAU,YAC/BI,QAAS,WACPiQ,OAAQhC,IAHZ,SAMG/C,EAAWnF,MAAQ,IAAM,iBAAckI,IAG1C,+BAIJ,sBACErO,UAAW,CACT,gFAEA,8BACA,SACAkB,KAAK,KANT,SAQGU,EACC,cAACgI,EAAD,CAAQhI,KAAMA,IAEd,qCACE,qBACE5B,UAAW,CACT,yCACA,sDACAkB,KAAK,KAJT,SAME,qBAAKlB,UAAU,uEAAf,SACE,qBAAIA,UAAU,+CAAd,qDAEE,4BACE,mBAAG0P,KAAK,oCAAR,2BAMR,qBACE1P,UAAU,2BACVoO,MAAO,CAAEW,SAAU,SAFrB,SAIE,cAAC5N,EAAD,CACEC,YAAW,uCAAE,WAAMkP,GAAN,iBAAAhO,EAAA,sEAMDoD,EAAgB4K,EAAG,MANlB,gBAEHC,EAFG,EAET3O,KAFS,EAGTyE,QAHS,EAITM,cAJS,EAKTC,eAEFyJ,EAAQE,GAPG,2CAAF,mECzD3BC,IAASC,OAAO,cAAC,EAAD,IAASzK,SAAS0K,eAAe,W","file":"static/js/main.56b43b57.chunk.js","sourcesContent":["import React, { ReactNode, useState } from 'react'\n\ninterface ButtonProps {\n children?: ReactNode\n className?: string\n icon?: ReactNode\n primary?: boolean\n disabled?: boolean\n onClick?: () => void\n onDown?: (ev: PointerEvent) => void\n onUp?: (ev: PointerEvent) => void\n}\n\nexport default function Button(props: ButtonProps) {\n const {\n children,\n className,\n disabled,\n icon,\n primary,\n onClick,\n onDown,\n onUp,\n } = props\n const [active, setActive] = useState(false)\n let background = ''\n if (primary && !disabled) {\n background = 'bg-primary hover:bg-black hover:text-white'\n }\n if (active) {\n background = 'bg-black text-white'\n }\n if (!primary && !active) {\n background = 'hover:bg-primary'\n }\n return (\n <div\n role=\"button\"\n onKeyDown={onClick}\n onClick={onClick}\n onPointerDown={(ev: React.PointerEvent<HTMLDivElement>) => {\n setActive(true)\n onDown?.(ev.nativeEvent)\n }}\n onPointerUp={(ev: React.PointerEvent<HTMLDivElement>) => {\n setActive(false)\n onUp?.(ev.nativeEvent)\n }}\n tabIndex={-1}\n className={[\n 'inline-flex py-3 px-5 rounded-md cursor-pointer',\n children ? 'space-x-3' : '',\n background,\n disabled ? 'pointer-events-none opacity-50' : '',\n className,\n ].join(' ')}\n >\n {icon}\n <span className=\"whitespace-nowrap select-none\">{children}</span>\n </div>\n )\n}\n","import React, { useState } from 'react'\n\ntype FileSelectProps = {\n onSelection: (file: File) => void\n}\n\nexport default function FileSelect(props: FileSelectProps) {\n const { onSelection } = props\n\n const [dragHover, setDragHover] = useState(false)\n const [uploadElemId] = useState(`file-upload-${Math.random().toString()}`)\n\n function onFileSelected(file: File) {\n if (!file) {\n return\n }\n // Skip non-image files\n const isImage = file.type.match('image.*')\n if (!isImage) {\n return\n }\n try {\n // Check if file is larger than 20mb\n if (file.size > 20 * 1024 * 1024) {\n throw new Error('file too large')\n }\n onSelection(file)\n } catch (e) {\n // eslint-disable-next-line\n alert(`error: ${(e as any).message}`)\n }\n }\n\n async function getFile(entry: any): Promise<File> {\n return new Promise(resolve => {\n entry.file((file: File) => resolve(file))\n })\n }\n\n /* eslint-disable no-await-in-loop */\n\n // Drop handler function to get all files\n async function getAllFileEntries(items: DataTransferItemList) {\n const fileEntries: Array<File> = []\n // Use BFS to traverse entire directory/file structure\n const queue = []\n // Unfortunately items is not iterable i.e. no forEach\n for (let i = 0; i < items.length; i += 1) {\n queue.push(items[i].webkitGetAsEntry())\n }\n while (queue.length > 0) {\n const entry = queue.shift()\n if (entry?.isFile) {\n // Only append images\n const file = await getFile(entry)\n fileEntries.push(file)\n } else if (entry?.isDirectory) {\n queue.push(\n ...(await readAllDirectoryEntries((entry as any).createReader()))\n )\n }\n }\n return fileEntries\n }\n\n // Get all the entries (files or sub-directories) in a directory\n // by calling readEntries until it returns empty array\n async function readAllDirectoryEntries(directoryReader: any) {\n const entries = []\n let readEntries = await readEntriesPromise(directoryReader)\n while (readEntries.length > 0) {\n entries.push(...readEntries)\n readEntries = await readEntriesPromise(directoryReader)\n }\n return entries\n }\n\n /* eslint-enable no-await-in-loop */\n\n // Wrap readEntries in a promise to make working with readEntries easier\n // readEntries will return only some of the entries in a directory\n // e.g. Chrome returns at most 100 entries at a time\n async function readEntriesPromise(directoryReader: any): Promise<any> {\n return new Promise((resolve, reject) => {\n directoryReader.readEntries(resolve, reject)\n })\n }\n\n async function handleDrop(ev: React.DragEvent) {\n ev.preventDefault()\n const items = await getAllFileEntries(ev.dataTransfer.items)\n setDragHover(false)\n onFileSelected(items[0])\n }\n\n return (\n <label\n htmlFor={uploadElemId}\n className=\"block w-full h-full group relative cursor-pointer rounded-md font-medium focus-within:outline-none\"\n >\n <div\n className={[\n 'w-full h-full flex items-center justify-center px-6 pt-5 pb-6 text-md',\n 'border-2 border-dashed rounded-md',\n 'hover:border-black hover:bg-primary',\n 'text-center',\n dragHover ? 'border-black bg-primary' : 'bg-gray-100 border-gray-300',\n ].join(' ')}\n onDrop={handleDrop}\n onDragOver={ev => {\n ev.stopPropagation()\n ev.preventDefault()\n setDragHover(true)\n }}\n onDragLeave={() => setDragHover(false)}\n >\n <input\n id={uploadElemId}\n name={uploadElemId}\n type=\"file\"\n className=\"sr-only\"\n onChange={ev => {\n const file = ev.currentTarget.files?.[0]\n if (file) {\n onFileSelected(file)\n }\n }}\n accept=\"image/png, image/jpeg\"\n />\n <p className=\"hidden sm:block\">Click here or drag an image file</p>\n <p className=\"sm:hidden\">Tap here to load your picture</p>\n </div>\n </label>\n )\n}\n","import { useEffect, useState } from 'react'\n\nexport function dataURItoBlob(dataURI: string) {\n const mime = dataURI.split(',')[0].split(':')[1].split(';')[0]\n const binary = atob(dataURI.split(',')[1])\n const array = []\n for (let i = 0; i < binary.length; i += 1) {\n array.push(binary.charCodeAt(i))\n }\n return new Blob([new Uint8Array(array)], { type: mime })\n}\n\n// const dataURItoBlob = (dataURI: string) => {\n// const bytes =\n// dataURI.split(',')[0].indexOf('base64') >= 0\n// ? atob(dataURI.split(',')[1])\n// : unescape(dataURI.split(',')[1])\n// const mime = dataURI.split(',')[0].split(':')[1].split(';')[0]\n// const max = bytes.length\n// const ia = new Uint8Array(max)\n// for (var i = 0; i < max; i++) ia[i] = bytes.charCodeAt(i)\n// return new Blob([ia], { type: mime })\n// }\n\nexport function downloadImage(uri: string, name: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = name\n\n // this is necessary as link.click() does not work on the latest firefox\n link.dispatchEvent(\n new MouseEvent('click', {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n )\n\n setTimeout(() => {\n // For Firefox it is necessary to delay revoking the ObjectURL\n // window.URL.revokeObjectURL(base64)\n link.remove()\n }, 100)\n}\n\nexport function shareImage(base64: string, name: string) {\n const blob = dataURItoBlob(base64)\n const filesArray = [new File([blob], name, { type: 'image/jpeg' })]\n const shareData = {\n files: filesArray,\n }\n // eslint-disable-nextline\n const nav: any = navigator\n const canShare = nav.canShare && nav.canShare(shareData)\n const userAgent = navigator.userAgent || navigator.vendor\n const isMobile = /android|iPad|iPhone|iPod/i.test(userAgent)\n if (canShare && isMobile) {\n navigator.share(shareData)\n return true\n }\n return false\n}\n\nexport function loadImage(image: HTMLImageElement, src: string) {\n return new Promise((resolve, reject) => {\n const initSRC = image.src\n const img = image\n img.onload = resolve\n img.onerror = err => {\n img.src = initSRC\n reject(err)\n }\n img.src = src\n })\n}\n\nexport function useImage(file: File): [HTMLImageElement, boolean] {\n const [image] = useState(new Image())\n const [isLoaded, setIsLoaded] = useState(false)\n\n useEffect(() => {\n image.onload = () => {\n setIsLoaded(true)\n }\n setIsLoaded(false)\n image.src = URL.createObjectURL(file)\n return () => {\n image.onload = null\n }\n }, [file, image])\n\n return [image, isLoaded]\n}\n\n// https://stackoverflow.com/questions/23945494/use-html5-to-resize-an-image-before-upload\ninterface ResizeImageFileResult {\n file: File\n resized: boolean\n originalWidth?: number\n originalHeight?: number\n}\nexport function resizeImageFile(\n file: File,\n maxSize: number\n): Promise<ResizeImageFileResult> {\n const reader = new FileReader()\n const image = new Image()\n const canvas = document.createElement('canvas')\n\n const resize = (): ResizeImageFileResult => {\n let { width, height } = image\n\n if (width > height) {\n if (width > maxSize) {\n height *= maxSize / width\n width = maxSize\n }\n } else if (height > maxSize) {\n width *= maxSize / height\n height = maxSize\n }\n\n if (width === image.width && height === image.height) {\n return { file, resized: false }\n }\n\n canvas.width = width\n canvas.height = height\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n throw new Error('could not get context')\n }\n canvas.getContext('2d')?.drawImage(image, 0, 0, width, height)\n const dataUrl = canvas.toDataURL('image/jpeg')\n const blob = dataURItoBlob(dataUrl)\n const f = new File([blob], file.name, {\n type: file.type,\n })\n return {\n file: f,\n resized: true,\n originalWidth: image.width,\n originalHeight: image.height,\n }\n }\n\n return new Promise((resolve, reject) => {\n if (!file.type.match(/image.*/)) {\n reject(new Error('Not an image'))\n return\n }\n reader.onload = (readerEvent: any) => {\n image.onload = () => resolve(resize())\n image.src = readerEvent.target.result\n }\n reader.readAsDataURL(file)\n })\n}\n","import { dataURItoBlob } from '../utils'\n\nexport const API_ENDPOINT = `${process.env.REACT_APP_INPAINTING_URL}/inpaint`\n\nexport default async function inpaint(imageFile: File, maskBase64: string) {\n const fd = new FormData()\n fd.append('image', imageFile)\n const mask = dataURItoBlob(maskBase64)\n fd.append('mask', mask)\n\n const res = await fetch(API_ENDPOINT, {\n method: 'POST',\n body: fd,\n }).then(async r => {\n return r.blob()\n })\n\n return URL.createObjectURL(res)\n}\n","import React from 'react'\n\ntype SliderProps = {\n label?: any\n value?: number\n min?: number\n max?: number\n onChange: (value: number) => void\n}\n\nexport default function Slider(props: SliderProps) {\n const { value, onChange, label, min, max } = props\n\n const step = ((max || 100) - (min || 0)) / 100\n\n return (\n <div className=\"inline-flex items-center space-x-4 text-black\">\n <span>{label}</span>\n <input\n className={[\n 'appearance-none rounded-lg h-4',\n 'bg-primary',\n 'w-24 md:w-auto',\n ].join(' ')}\n type=\"range\"\n step={step}\n min={min}\n max={max}\n value={value}\n onChange={ev => {\n ev.preventDefault()\n ev.stopPropagation()\n onChange(parseInt(ev.currentTarget.value, 10))\n }}\n />\n </div>\n )\n}\n","import { DownloadIcon, EyeIcon } from '@heroicons/react/outline'\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { useWindowSize } from 'react-use'\nimport inpaint from './adapters/inpainting'\nimport Button from './components/Button'\nimport Slider from './components/Slider'\nimport { downloadImage, loadImage, shareImage, useImage } from './utils'\n\nconst TOOLBAR_SIZE = 200\nconst BRUSH_COLOR = 'rgba(189, 255, 1, 0.75)'\n\ninterface EditorProps {\n file: File\n}\n\ninterface Line {\n size?: number\n pts: { x: number; y: number }[]\n}\n\nfunction drawLines(\n ctx: CanvasRenderingContext2D,\n lines: Line[],\n color = BRUSH_COLOR\n) {\n ctx.strokeStyle = color\n ctx.lineCap = 'round'\n ctx.lineJoin = 'round'\n\n lines.forEach(line => {\n if (!line?.pts.length || !line.size) {\n return\n }\n ctx.lineWidth = line.size\n ctx.beginPath()\n ctx.moveTo(line.pts[0].x, line.pts[0].y)\n line.pts.forEach(pt => ctx.lineTo(pt.x, pt.y))\n ctx.stroke()\n })\n}\n\nexport default function Editor(props: EditorProps) {\n const { file } = props\n const [brushSize, setBrushSize] = useState(40)\n const [original, isOriginalLoaded] = useImage(file)\n const [renders, setRenders] = useState<HTMLImageElement[]>([])\n const [context, setContext] = useState<CanvasRenderingContext2D>()\n const [maskCanvas] = useState<HTMLCanvasElement>(() => {\n return document.createElement('canvas')\n })\n const [lines, setLines] = useState<Line[]>([{ pts: [] }])\n const [{ x, y }, setCoords] = useState({ x: -1, y: -1 })\n const [showBrush, setShowBrush] = useState(false)\n const [showOriginal, setShowOriginal] = useState(false)\n const [isInpaintingLoading, setIsInpaintingLoading] = useState(false)\n const [showSeparator, setShowSeparator] = useState(false)\n const [scale, setScale] = useState(1)\n const windowSize = useWindowSize()\n\n const draw = useCallback(() => {\n if (!context) {\n return\n }\n context.clearRect(0, 0, context.canvas.width, context.canvas.height)\n const currRender = renders[renders.length - 1]\n if (currRender?.src) {\n context.drawImage(currRender, 0, 0)\n } else {\n context.drawImage(original, 0, 0)\n }\n const currentLine = lines[lines.length - 1]\n drawLines(context, [currentLine])\n }, [context, lines, original, renders])\n\n const refreshCanvasMask = useCallback(() => {\n if (!context?.canvas.width || !context?.canvas.height) {\n throw new Error('canvas has invalid size')\n }\n maskCanvas.width = context?.canvas.width\n maskCanvas.height = context?.canvas.height\n const ctx = maskCanvas.getContext('2d')\n if (!ctx) {\n throw new Error('could not retrieve mask canvas')\n }\n drawLines(ctx, lines, 'white')\n }, [context?.canvas.height, context?.canvas.width, lines, maskCanvas])\n\n // Draw once the original image is loaded\n useEffect(() => {\n if (!context?.canvas) {\n return\n }\n if (isOriginalLoaded) {\n context.canvas.width = original.naturalWidth\n context.canvas.height = original.naturalHeight\n const rW = windowSize.width / original.naturalWidth\n const rH = (windowSize.height - TOOLBAR_SIZE) / original.naturalHeight\n if (rW < 1 || rH < 1) {\n setScale(Math.min(rW, rH))\n } else {\n setScale(1)\n }\n draw()\n }\n }, [context?.canvas, draw, original, isOriginalLoaded, windowSize])\n\n // Handle mouse interactions\n useEffect(() => {\n const canvas = context?.canvas\n if (!canvas) {\n return\n }\n\n const onMouseDown = (ev: MouseEvent) => {\n if (!original.src) {\n return\n }\n const currLine = lines[lines.length - 1]\n currLine.size = brushSize\n canvas.addEventListener('mousemove', onMouseDrag)\n window.addEventListener('mouseup', onPointerUp)\n onPaint(ev.offsetX, ev.offsetY)\n }\n const onMouseMove = (ev: MouseEvent) => {\n setCoords({ x: ev.pageX, y: ev.pageY })\n }\n const onPaint = (px: number, py: number) => {\n const currLine = lines[lines.length - 1]\n currLine.pts.push({ x: px, y: py })\n draw()\n }\n const onMouseDrag = (ev: MouseEvent) => {\n const px = ev.offsetX\n const py = ev.offsetY\n onPaint(px, py)\n }\n\n const onPointerUp = async () => {\n if (!original.src) {\n return\n }\n setIsInpaintingLoading(true)\n canvas.removeEventListener('mousemove', onMouseDrag)\n window.removeEventListener('mouseup', onPointerUp)\n refreshCanvasMask()\n try {\n const start = Date.now()\n const res = await inpaint(file, maskCanvas.toDataURL())\n if (!res) {\n throw new Error('empty response')\n }\n // TODO: fix the render if it failed loading\n const newRender = new Image()\n await loadImage(newRender, res)\n renders.push(newRender)\n lines.push({ pts: [] } as Line)\n\n setRenders([...renders])\n setLines([...lines])\n } catch (e: any) {\n // eslint-disable-next-line\n alert(e.message ? e.message : e.toString())\n }\n setIsInpaintingLoading(false)\n draw()\n }\n window.addEventListener('mousemove', onMouseMove)\n\n const onTouchMove = (ev: TouchEvent) => {\n ev.preventDefault()\n ev.stopPropagation()\n const currLine = lines[lines.length - 1]\n const coords = canvas.getBoundingClientRect()\n currLine.pts.push({\n x: (ev.touches[0].clientX - coords.x) / scale,\n y: (ev.touches[0].clientY - coords.y) / scale,\n })\n draw()\n }\n const onPointerStart = (ev: TouchEvent) => {\n if (!original.src) {\n return\n }\n const currLine = lines[lines.length - 1]\n currLine.size = brushSize\n canvas.addEventListener('mousemove', onMouseDrag)\n window.addEventListener('mouseup', onPointerUp)\n const coords = canvas.getBoundingClientRect()\n const px = (ev.touches[0].clientX - coords.x) / scale\n const py = (ev.touches[0].clientY - coords.y) / scale\n onPaint(px, py)\n }\n canvas.addEventListener('touchstart', onPointerStart)\n canvas.addEventListener('touchmove', onTouchMove)\n canvas.addEventListener('touchend', onPointerUp)\n canvas.onmouseenter = () => setShowBrush(true)\n canvas.onmouseleave = () => setShowBrush(false)\n canvas.onmousedown = onMouseDown\n\n return () => {\n canvas.removeEventListener('mousemove', onMouseDrag)\n window.removeEventListener('mousemove', onMouseMove)\n window.removeEventListener('mouseup', onPointerUp)\n canvas.removeEventListener('touchstart', onPointerStart)\n canvas.removeEventListener('touchmove', onTouchMove)\n canvas.removeEventListener('touchend', onPointerUp)\n canvas.onmouseenter = null\n canvas.onmouseleave = null\n canvas.onmousedown = null\n }\n }, [\n brushSize,\n context,\n file,\n draw,\n lines,\n refreshCanvasMask,\n maskCanvas,\n original.src,\n renders,\n original.naturalHeight,\n original.naturalWidth,\n scale,\n ])\n\n const undo = useCallback(() => {\n const l = lines\n l.pop()\n l.pop()\n setLines([...l, { pts: [] }])\n const r = renders\n r.pop()\n setRenders([...r])\n }, [lines, renders])\n\n // Handle Cmd+Z\n useEffect(() => {\n const handler = (event: KeyboardEvent) => {\n if (!renders.length) {\n return\n }\n const isCmdZ = (event.metaKey || event.ctrlKey) && event.key === 'z'\n if (isCmdZ) {\n event.preventDefault()\n undo()\n }\n }\n window.addEventListener('keydown', handler)\n return () => {\n window.removeEventListener('keydown', handler)\n }\n }, [renders, undo])\n\n function download() {\n const base64 = context?.canvas.toDataURL(file.type)\n if (!base64) {\n throw new Error('could not get canvas data')\n }\n const name = file.name.replace(/(\\.[\\w\\d_-]+)$/i, '_cleanup$1')\n downloadImage(base64, name)\n }\n\n return (\n <div\n className={[\n 'flex flex-col items-center',\n isInpaintingLoading\n ? 'animate-pulse-fast pointer-events-none transition-opacity'\n : '',\n scale !== 1 ? 'pb-24' : '',\n ].join(' ')}\n style={{\n height: scale !== 1 ? original.naturalHeight * scale : undefined,\n }}\n >\n <div\n className={[scale !== 1 ? '' : 'relative'].join(' ')}\n style={{ transform: `scale(${scale})`, transformOrigin: 'top center' }}\n >\n <canvas\n className=\"rounded-sm\"\n style={showBrush ? { cursor: 'none' } : {}}\n ref={r => {\n if (r && !context) {\n const ctx = r.getContext('2d')\n if (ctx) {\n setContext(ctx)\n }\n }\n }}\n />\n <div\n className={[\n 'absolute top-0 right-0 pointer-events-none',\n 'overflow-hidden',\n 'border-primary',\n showSeparator ? 'border-l-4' : '',\n // showOriginal ? 'border-opacity-100' : 'border-opacity-0',\n ].join(' ')}\n style={{\n width: showOriginal\n ? `${Math.round(original.naturalWidth)}px`\n : '0px',\n height: original.naturalHeight,\n transitionProperty: 'width, height',\n transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',\n transitionDuration: '300ms',\n }}\n >\n <img\n className=\"absolute right-0\"\n src={original.src}\n alt=\"original\"\n width={`${original.naturalWidth}px`}\n height={`${original.naturalHeight}px`}\n style={{\n width: `${original.naturalWidth}px`,\n height: `${original.naturalHeight}px`,\n maxWidth: 'none',\n }}\n />\n </div>\n </div>\n\n {showBrush && (\n <div\n className=\"hidden sm:block absolute rounded-full border border-primary bg-primary bg-opacity-80 pointer-events-none\"\n style={{\n width: `${brushSize * scale}px`,\n height: `${brushSize * scale}px`,\n left: `${x}px`,\n top: `${y}px`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n )}\n\n <div\n className={[\n 'flex items-center w-full max-w-3xl',\n 'space-x-3 sm:space-x-5',\n 'p-6',\n scale !== 1\n ? 'absolute bottom-0 justify-evenly'\n : 'relative justify-evenly sm:justify-between',\n ].join(' ')}\n >\n <Slider\n label={\n <span>\n <span className=\"hidden md:inline\">Brush</span> Size\n </span>\n }\n min={10}\n max={150}\n value={brushSize}\n onChange={setBrushSize}\n />\n {renders.length ? (\n <>\n <Button\n icon={\n <svg\n width=\"19\"\n height=\"9\"\n viewBox=\"0 0 19 9\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"w-6 h-6\"\n >\n <path\n d=\"M2 1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1H2ZM1 8H0V9H1V8ZM8 9C8.55228 9 9 8.55229 9 8C9 7.44771 8.55228 7 8 7V9ZM16.5963 7.42809C16.8327 7.92721 17.429 8.14016 17.9281 7.90374C18.4272 7.66731 18.6402 7.07103 18.4037 6.57191L16.5963 7.42809ZM16.9468 5.83205L17.8505 5.40396L16.9468 5.83205ZM0 1V8H2V1H0ZM1 9H8V7H1V9ZM1.66896 8.74329L6.66896 4.24329L5.33104 2.75671L0.331035 7.25671L1.66896 8.74329ZM16.043 6.26014L16.5963 7.42809L18.4037 6.57191L17.8505 5.40396L16.043 6.26014ZM6.65079 4.25926C9.67554 1.66661 14.3376 2.65979 16.043 6.26014L17.8505 5.40396C15.5805 0.61182 9.37523 -0.710131 5.34921 2.74074L6.65079 4.25926Z\"\n fill=\"currentColor\"\n />\n </svg>\n }\n onClick={undo}\n />\n <Button\n icon={<EyeIcon className=\"w-6 h-6\" />}\n onDown={ev => {\n ev.preventDefault()\n setShowSeparator(true)\n setShowOriginal(true)\n }}\n onUp={() => {\n setShowOriginal(false)\n setTimeout(() => setShowSeparator(false), 300)\n }}\n >\n {windowSize.width > 640 ? 'Original' : undefined}\n </Button>\n </>\n ) : (\n <></>\n )}\n\n <Button\n primary\n icon={<DownloadIcon className=\"w-6 h-6\" />}\n disabled={!renders.length}\n onClick={download}\n >\n {windowSize.width > 640 ? 'Download' : undefined}\n </Button>\n </div>\n </div>\n )\n}\n","import { ArrowLeftIcon } from '@heroicons/react/outline'\nimport React, { useState } from 'react'\nimport { useWindowSize } from 'react-use'\nimport Button from './components/Button'\nimport FileSelect from './components/FileSelect'\nimport Editor from './Editor'\nimport { resizeImageFile } from './utils'\n\nfunction App() {\n const [file, setFile] = useState<File>()\n const windowSize = useWindowSize()\n\n return (\n <div className=\"h-full full-visible-h-safari flex flex-col\">\n <header className=\"relative z-10 flex px-5 pt-3 justify-center sm:justify-between items-center sm:items-start\">\n {file ? (\n <Button\n icon={<ArrowLeftIcon className=\"w-6 h-6\" />}\n onClick={() => {\n setFile(undefined)\n }}\n >\n {windowSize.width > 640 ? 'Start new' : undefined}\n </Button>\n ) : (\n <></>\n )}\n </header>\n\n <main\n className={[\n 'h-full flex flex-1 flex-col sm:items-center sm:justify-center overflow-hidden',\n // file ? 'items-center justify-center' : '', // center on mobile\n 'items-center justify-center',\n 'pb-20',\n ].join(' ')}\n >\n {file ? (\n <Editor file={file} />\n ) : (\n <>\n <div\n className={[\n 'flex flex-col sm:flex-row items-center',\n 'space-y-5 sm:space-y-0 sm:space-x-6 p-5 pt-0 pb-10',\n ].join(' ')}\n >\n <div className=\"max-w-xl flex flex-col items-center sm:items-start p-0 m-0 space-y-5\">\n <h1 className=\"text-center sm:text-left text-xl sm:text-3xl\">\n Image inpainting powered by 🦙\n <u>\n <a href=\"https://github.com/saic-mdal/lama\">LaMa</a>\n </u>\n </h1>\n </div>\n </div>\n\n <div\n className=\"h-20 sm:h-52 px-4 w-full\"\n style={{ maxWidth: '800px' }}\n >\n <FileSelect\n onSelection={async f => {\n const {\n file: resizedFile,\n resized,\n originalWidth,\n originalHeight,\n } = await resizeImageFile(f, 1024)\n setFile(resizedFile)\n }}\n />\n </div>\n </>\n )}\n </main>\n </div>\n )\n}\n\nexport default App\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport './styles/index.css'\nimport App from './App'\n\nReactDOM.render(<App />, document.getElementById('root'))\n"],"sourceRoot":""}