From 5698b9949551db6e26c6099414c1645dd13d0bf8 Mon Sep 17 00:00:00 2001 From: thomasrosen Date: Sat, 23 Jan 2021 12:49:53 +0000 Subject: [PATCH] thomasrosen published a site update --- asset-manifest.json | 6 +++--- index.html | 2 +- static/js/main.1c0446a4.chunk.js | 2 -- static/js/main.1c0446a4.chunk.js.map | 1 - static/js/main.2acad07c.chunk.js | 2 ++ static/js/main.2acad07c.chunk.js.map | 1 + 6 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 static/js/main.1c0446a4.chunk.js delete mode 100644 static/js/main.1c0446a4.chunk.js.map create mode 100644 static/js/main.2acad07c.chunk.js create mode 100644 static/js/main.2acad07c.chunk.js.map diff --git a/asset-manifest.json b/asset-manifest.json index 2389c2f..8b29099 100644 --- a/asset-manifest.json +++ b/asset-manifest.json @@ -1,8 +1,8 @@ { "files": { "main.css": "/static/css/main.9823fa1b.chunk.css", - "main.js": "/static/js/main.1c0446a4.chunk.js", - "main.js.map": "/static/js/main.1c0446a4.chunk.js.map", + "main.js": "/static/js/main.2acad07c.chunk.js", + "main.js.map": "/static/js/main.2acad07c.chunk.js.map", "runtime-main.js": "/static/js/runtime-main.338a13b0.js", "runtime-main.js.map": "/static/js/runtime-main.338a13b0.js.map", "static/js/2.7b4df116.chunk.js": "/static/js/2.7b4df116.chunk.js", @@ -44,6 +44,6 @@ "static/js/runtime-main.338a13b0.js", "static/js/2.7b4df116.chunk.js", "static/css/main.9823fa1b.chunk.css", - "static/js/main.1c0446a4.chunk.js" + "static/js/main.2acad07c.chunk.js" ] } \ No newline at end of file diff --git a/index.html b/index.html index a336007..516ab62 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -Volt Social Media Frame Generator
\ No newline at end of file +Volt Social Media Frame Generator
\ No newline at end of file diff --git a/static/js/main.1c0446a4.chunk.js b/static/js/main.1c0446a4.chunk.js deleted file mode 100644 index dfc662c..0000000 --- a/static/js/main.1c0446a4.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -(this["webpackJsonpprofile-picture-generator"]=this["webpackJsonpprofile-picture-generator"]||[]).push([[0],{22:function(e,t,a){},26:function(e,t,a){var r={"./ProfileFrame B&G Bars.png":[28,4],"./ProfileFrame Blue Bars.png":[29,5],"./ProfileFrame Green Bars.png":[30,6],"./ProfileFrame Mixed Bars.png":[31,7],"./ProfileFrame Purple.png":[32,8],"./ProfileFrame R&Y Bars.png":[33,9],"./ProfileFrame Red Bars.png":[34,10],"./ProfileFrame White Bars.png":[35,11],"./ProfileFrame Yellow Bars.png":[36,12]};function n(e){if(!a.o(r,e))return Promise.resolve().then((function(){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}));var t=r[e],n=t[0];return a.e(t[1]).then((function(){return a(n)}))}n.keys=function(){return Object.keys(r)},n.id=26,e.exports=n},27:function(e,t,a){"use strict";a.r(t);var r=a(1),n=a(0),c=a.n(n),s=a(11),o=a.n(s),i=a(10),u=a(9),l=a(2),b=(a(22),a(16)),f=a(5),j=a.n(f),d=a(8);var O=function(e){var t=e.onFrameChange,c=Object(n.useState)([]),s=Object(l.a)(c,2),o=s[0],i=s[1],u=Object(n.useState)(null),b=Object(l.a)(u,2),f=b[0],O=b[1];Object(n.useEffect)((function(){function e(){return(e=Object(d.a)(j.a.mark((function e(){return j.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:Promise.all(["ProfileFrame Purple","ProfileFrame Yellow Bars","ProfileFrame Red Bars","ProfileFrame Blue Bars","ProfileFrame Green Bars","ProfileFrame White Bars","ProfileFrame Mixed Bars","ProfileFrame R&Y Bars","ProfileFrame B&G Bars"].map(function(){var e=Object(d.a)(j.a.mark((function e(t){return j.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.t0=t,e.next=3,a(26)("./".concat(t,".png"));case 3:return e.t1=e.sent,e.abrupt("return",{name:e.t0,src:e.t1});case 5:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}())).then((function(e){i(e),O(e[0].src.default)}));case 1:case"end":return e.stop()}}),e)})))).apply(this,arguments)}!function(){e.apply(this,arguments)}()}),[]);var h=Object(n.useCallback)((function(e){O(e.target.dataset.src)}),[O]);return Object(n.useEffect)((function(){t(f)}),[t,f]),Object(r.jsxs)("div",{className:"FrameChooser",children:[Object(r.jsx)("h2",{children:"Choose a frame:"}),o.map((function(e){var t=e.src.default,a=f===t;return Object(r.jsx)("img",{alt:e.name,"data-src":t,src:t,className:a?"frame choosen":"frame",onClick:h},t)}))]})},h=a(13),g=a.n(h),m=a(14),p=a.n(m);function v(e,t,a){return Math.min(Math.max(t,e),a)}var x=function(e){var t=e.onChange,a=e.background,c=e.backgroundRatio,s=e.foreground,o=Object(n.useRef)(null),i=Object(n.useRef)(null),u=Object(n.useState)(!1),b=Object(l.a)(u,2),f=b[0],j=b[1],d=Object(n.useState)(null),O=Object(l.a)(d,2),h=O[0],m=O[1],x=Object(n.useState)(null),P=Object(l.a)(x,2),w=P[0],k=P[1],F=Object(n.useState)(0),y=Object(l.a)(F,2),C=y[0],S=y[1],B=Object(n.useState)(0),M=Object(l.a)(B,2),E=M[0],I=M[1],R=Object(n.useState)(0),U=Object(l.a)(R,2),D=U[0],N=U[1],L=Object(n.useState)(0),Y=Object(l.a)(L,2),A=Y[0],T=Y[1],X=Object(n.useState)(1),G=Object(l.a)(X,2),_=G[0],H=G[1],W=Object(n.useState)(300),J=Object(l.a)(W,2),V=J[0],q=J[1],z=Object(n.useState)(300),K=Object(l.a)(z,2),Q=K[0],Z=K[1],$=Object(n.useState)(300),ee=Object(l.a)($,2),te=ee[0],ae=ee[1],re=Object(n.useState)(300),ne=Object(l.a)(re,2),ce=ne[0],se=ne[1],oe=Object(n.useState)(0),ie=Object(l.a)(oe,2),ue=ie[0],le=ie[1],be=Object(n.useState)(0),fe=Object(l.a)(be,2),je=fe[0],de=fe[1],Oe=Object(n.useState)(0),he=Object(l.a)(Oe,2),ge=he[0],me=he[1],pe=Object(n.useState)(0),ve=Object(l.a)(pe,2),xe=ve[0],Pe=ve[1];Object(n.useEffect)((function(){t&&t({x:C,y:E,scale:_})}),[t,C,E,_]),Object(n.useEffect)((function(){if(o&&o.current){var e=o.current.offsetWidth,t=o.current.offsetHeight;se(t),ae(e);var a=1,r=1;c<1?a=1/c:c>1&&(r=1*c),q(a),Z(r)}}),[c,s]),Object(n.useEffect)((function(){var e=function(e,t,a,r,n){var c=Math.max(0,e*a-r)/2,s=Math.max(0,t*a-n)/2;return{rangeMaxX:c,rangeMinX:0-c,rangeMaxY:s,rangeMinY:0-s}}(V*te,Q*ce,_,te,ce),t=e.rangeMinX,a=e.rangeMinY,r=e.rangeMaxX,n=e.rangeMaxY;le(t),de(a),me(r),Pe(n)}),[V,Q,te,ce,_]),Object(n.useEffect)((function(){S(0),I(0),N(0),T(0),H(1)}),[a]);var we=Object(n.useCallback)((function(e){var t=1*e.target.dataset.x,a=1*e.target.dataset.y,r=v(t+e.deltaX,ue,ge),n=v(a+e.deltaY,je,xe);e.isFinal?(S(r||0),I(n||0),N(0),T(0)):(N(r-t||0),T(n-a||0))}),[ue,je,ge,xe]),ke=Object(n.useCallback)((function(e,t,a,r){e.preventDefault();var n=v(1*e.target.dataset.scale+t/200,1,8);H(n||1);var c=1*e.target.dataset.x,s=1*e.target.dataset.y;S(v(c,ue,ge)||0),I(v(s,je,xe)||0)}),[ue,je,ge,xe]);return Object(n.useEffect)((function(){if(!f&&o&&o.current){var e=o.current;e.addEventListener("mousedown",(function(e){return e.preventDefault()}),!1),m(new g.a(e,{direction:"DIRECTION_ALL"})),k(p()(e)),j(!0)}}),[o,f]),Object(n.useEffect)((function(){if(h&&w&&f&&o&&o.current)return h.on("pan",we),w.wheel(ke),function(){h.off("pan",we),w.unwheel()}}),[o,we,ke,f,h,w]),Object(r.jsxs)("div",{className:"Editor",ref:o,"data-x":C,"data-y":E,"data-scale":_,children:[Object(r.jsx)("img",{src:a,ref:i,alt:"",className:"background",style:{width:100*V+"%",height:100*Q+"%",transform:"translate3d(calc(-50% + ".concat(C+D,"px), calc(-50% + ").concat(E+A,"px), 0) scale(").concat(_,",").concat(_,")")}}),Object(r.jsx)("img",{src:s,alt:"",className:"foreground"})]})},P=a.p+"static/media/HeaderImage.1f39a672.svg",w=a(15),k=1080;var F=function(){var e=Object(n.useState)(null),t=Object(l.a)(e,2),a=t[0],c=t[1],s=Object(n.useState)(null),o=Object(l.a)(s,2),f=o[0],j=o[1],d=Object(n.useState)(1),h=Object(l.a)(d,2),g=h[0],m=h[1],p=Object(n.useState)(null),v=Object(l.a)(p,2),F=v[0],y=v[1],C=Object(n.useState)(0),S=Object(l.a)(C,2),B=S[0],M=S[1],E=Object(n.useState)(0),I=Object(l.a)(E,2),R=I[0],U=I[1],D=Object(n.useState)({x:0,y:0,scale:1}),N=Object(l.a)(D,2),L=N[0],Y=N[1],A=Object(n.useCallback)((function(e){c(e)}),[c]),T=Object(n.useCallback)((function(e){var t=e.x,a=e.y,r=e.scale;console.log({x:t,y:a,scale:r}),Y({x:t,y:a,scale:r})}),[]),X=Object(n.useCallback)((function(e){if(e){var t=new FileReader;t.onload=function(t){var a=new Image;a.onload=function(){var r,n;a.width {\n async function loadFrames(){\n Promise.all(\n [\n 'ProfileFrame Purple',\n 'ProfileFrame Yellow Bars',\n 'ProfileFrame Red Bars',\n 'ProfileFrame Blue Bars',\n 'ProfileFrame Green Bars',\n 'ProfileFrame White Bars',\n 'ProfileFrame Mixed Bars',\n 'ProfileFrame R&Y Bars',\n 'ProfileFrame B&G Bars',\n ]\n .map(async frame_filename => {\n return {\n name: frame_filename,\n src: await import(`./frames/${frame_filename}.png`),\n }\n })\n )\n .then(new_frames => {\n setFrames(new_frames)\n setChoosenFrame(new_frames[0].src.default)\n })\n }\n loadFrames()\n }, [])\n\n const handleImageChoosing = useCallback(event => {\n setChoosenFrame(event.target.dataset.src)\n }, [setChoosenFrame])\n\n useEffect(() => {\n onFrameChange(choosenFrame)\n }, [onFrameChange, choosenFrame])\n\n return (\n
\n

Choose a frame:

\n {\n frames.map(frame => {\n const frame_src_path = frame.src.default\n const isChoosen = choosenFrame === frame_src_path\n return {frame.name}\n })\n } \n
\n )\n}\n\nexport default FrameChooser\n","import { useEffect, useRef, useState, useCallback } from 'react'\n\nimport Hammer from 'hammerjs'\nimport Hamster from 'hamsterjs'\n\nfunction updateRange(imageWidth, imageHeight, imageScale, containerWidth, containerHeight) {\n\n const rangeX = Math.max(0, (imageWidth * imageScale) - containerWidth)\n const rangeY = Math.max(0, (imageHeight * imageScale) - containerHeight)\n\n const rangeMaxX = (rangeX / 2)\n const rangeMinX = 0 - rangeMaxX\n\n const rangeMaxY = (rangeY / 2)\n const rangeMinY = 0 - rangeMaxY\n\n return {\n rangeMaxX,\n rangeMinX,\n rangeMaxY,\n rangeMinY,\n }\n}\n\nfunction clamp(value, min, max) {\n return Math.min(Math.max(min, value), max)\n}\n\n\n\nlet minScale = 1;\nlet maxScale = 8;\n\n\n\nfunction Editor({ onChange, background, backgroundRatio, foreground }) {\n const editorRef = useRef(null)\n const backgroundImageRef = useRef(null)\n\n const [hammer_got_init, set_hammer_got_init] = useState(false)\n\n const [hammertime, set_hammertime] = useState(null)\n const [hamster, set_hamster] = useState(null)\n\n const [x, set_x] = useState(0)\n const [y, set_y] = useState(0)\n const [add_x, set_add_x] = useState(0)\n const [add_y, set_add_y] = useState(0)\n const [scale, set_scale] = useState(1)\n // const [add_scale, set_add_scale] = useState(0)\n\n const [photoWidth, setPhotoWidth] = useState(300)\n const [photoHeight, setPhotoHeight] = useState(300)\n const [editorWidth, setEditorWidth] = useState(300)\n const [editorHeight, setEditorHeight] = useState(300)\n\n const [rangeMinX, set_rangeMinX] = useState(0)\n const [rangeMinY, set_rangeMinY] = useState(0)\n const [rangeMaxX, set_rangeMaxX] = useState(0)\n const [rangeMaxY, set_rangeMaxY] = useState(0)\n\n useEffect(() => {\n if (!!onChange) {\n onChange({ x, y, scale})\n }\n }, [onChange, x, y, scale])\n\n useEffect(() => {\n if (!!editorRef && !!editorRef.current) {\n const new_editorWidth = editorRef.current.offsetWidth\n const new_editorHeight = editorRef.current.offsetHeight\n setEditorHeight(new_editorHeight)\n setEditorWidth(new_editorWidth)\n\n let new_photoWidth = 1\n let new_photoHeight = 1\n if (backgroundRatio < 1) {\n new_photoWidth = 1 / backgroundRatio\n } else if (backgroundRatio > 1) {\n new_photoHeight = 1 * backgroundRatio\n }\n\n setPhotoWidth(new_photoWidth)\n setPhotoHeight(new_photoHeight)\n }\n }, [\n backgroundRatio,\n foreground,\n ])\n\n useEffect(() => {\n const {\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n } = updateRange(photoWidth * editorWidth, photoHeight * editorHeight, scale, editorWidth, editorHeight)\n\n set_rangeMinX(rangeMinX)\n set_rangeMinY(rangeMinY)\n set_rangeMaxX(rangeMaxX)\n set_rangeMaxY(rangeMaxY)\n }, [\n photoWidth,\n photoHeight,\n editorWidth,\n editorHeight,\n scale,\n ])\n\n useEffect(() => {\n set_x(0)\n set_y(0)\n set_add_x(0)\n set_add_y(0)\n set_scale(1)\n }, [background])\n\n const handleMove = useCallback(event => {\n const prev_x = event.target.dataset.x * 1\n const prev_y = event.target.dataset.y * 1\n\n const new_x = clamp(prev_x + event.deltaX, rangeMinX, rangeMaxX)\n const new_y = clamp(prev_y + event.deltaY, rangeMinY, rangeMaxY)\n\n if (event.isFinal) {\n set_x(new_x || 0)\n set_y(new_y || 0)\n set_add_x(0)\n set_add_y(0)\n }else{\n set_add_x(new_x - prev_x || 0)\n set_add_y(new_y - prev_y || 0)\n }\n }, [\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n ])\n\n const handleScale = useCallback((event, delta, deltaX, deltaY) => {\n event.preventDefault()\n\n const prev_scale = event.target.dataset.scale * 1\n const new_scale = clamp(prev_scale + delta / 200, minScale, maxScale)\n set_scale(new_scale || 1)\n\n const prev_x = event.target.dataset.x * 1\n const prev_y = event.target.dataset.y * 1\n set_x(clamp(prev_x, rangeMinX, rangeMaxX) || 0)\n set_y(clamp(prev_y, rangeMinY, rangeMaxY) || 0)\n }, [\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n ])\n\n useEffect(() => {\n if (!hammer_got_init && !!editorRef && !!editorRef.current) {\n const element = editorRef.current\n\n element.addEventListener('mousedown', e => e.preventDefault(), false)\n\n set_hammertime(new Hammer(element, {\n direction: 'DIRECTION_ALL',\n }))\n\n set_hamster(Hamster(element))\n\n set_hammer_got_init(true)\n }\n }, [editorRef, hammer_got_init])\n\n useEffect(() => {\n if (!!hammertime && !!hamster && hammer_got_init && !!editorRef && !!editorRef.current) {\n hammertime.on('pan', handleMove)\n hamster.wheel(handleScale)\n\n return function () {\n hammertime.off('pan', handleMove)\n hamster.unwheel()\n }\n }\n }, [editorRef, handleMove, handleScale, hammer_got_init, hammertime, hamster])\n\n return (\n \n \n \n \n )\n}\n\nexport default Editor\n","export default __webpack_public_path__ + \"static/media/HeaderImage.1f39a672.svg\";","import { useState, useCallback } from 'react'\nimport './App.css'\nimport { useDropzone } from 'react-dropzone'\nimport FrameChooser from './FrameChooser.js'\nimport Editor from './Editor.js'\nimport HeaderImage from './HeaderImage.svg'\n\nimport mergeImages from 'merge-images'\n\nconst frameSize = 1080\n\nfunction getOrientation(file, callback) {\n // Source: http://stackoverflow.com/a/32490603\n // (With some modifications: I just made the code fit the style-guide.)\n const reader = new FileReader()\n\n reader.onload = function (event) {\n const view = new DataView(event.target.result)\n\n if (view.getUint16(0, false) !== 0xFFD8) {\n return callback(-2)\n }\n\n const length = view.byteLength\n let offset = 2\n\n while (offset < length) {\n const marker = view.getUint16(offset, false)\n offset += 2\n\n if (marker === 0xFFE1) {\n if (view.getUint32(offset += 2, false) !== 0x45786966) {\n return callback(-1)\n }\n const little = view.getUint16(offset += 6, false) === 0x4949\n offset += view.getUint32(offset + 4, little)\n const tags = view.getUint16(offset, little)\n offset += 2\n\n for (var i = 0; i < tags; i++) {\n if (view.getUint16(offset + (i * 12), little) === 0x0112) {\n return callback(view.getUint16(offset + (i * 12) + 8, little))\n }\n }\n } else if ((marker & 0xFF00) !== 0xFF00) {\n break\n } else {\n offset += view.getUint16(offset, false)\n }\n }\n return callback(-1)\n }\n\n reader.readAsArrayBuffer(file.slice(0, 64 * 1024))\n}\n\nfunction trigger_download(name, data){\n const a = document.createElement('a')\n document.body.appendChild(a)\n a.target = '_blank'\n a.download = name\n a.href = data\n a.click()\n}\n\nfunction App() {\n const [frameURL, setFrameURL] = useState(null)\n const [originalPhoto, setOriginalPhoto] = useState(null)\n const [originalPhotoRation, setOriginalPhotoRation] = useState(1)\n const [orientation, set_orientation] = useState(null)\n\n\n // const [combinedImage, set_combinedImage] = useState(null)\n\n const [width, set_width] = useState(0)\n const [height, set_height] = useState(0)\n\n const [cords, setCords] = useState({x:0, y:0, scale:1})\n\n const handleFrameURL = useCallback(newFrameURL => {\n setFrameURL(newFrameURL)\n }, [setFrameURL])\n\n const handleCordsChange = useCallback(({x, y, scale}) => {\n console.log({ x, y, scale })\n setCords({ x, y, scale })\n }, [])\n\n const handleReadFile = useCallback(file => {\n if (!(!!file)) {\n return;\n }\n\n const reader = new FileReader()\n reader.onload = reader_event => {\n const img = new Image()\n img.onload = function () {\n let width, height;\n if (img.width < img.height) {\n height = (img.height / img.width) * frameSize\n width = frameSize\n } else {\n height = frameSize\n width = (img.width / img.height) * frameSize\n }\n\n getOrientation(file, new_orientation => {\n let original_ration = 1\n // use the correct image orientation\n switch (new_orientation) {\n // Source: https://stackoverflow.com/a/30242954/2387277\n // Source: https://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin\n case 2:\n // horizontal flip\n original_ration = height / width\n break\n case 3:\n // 180° rotate left\n original_ration = height / width\n break\n case 4:\n // vertical flip\n original_ration = height / width\n break\n case 5:\n // vertical flip + 90 rotate right\n original_ration = width / height\n break\n case 6:\n // 90° rotate right\n original_ration = width / height\n break\n case 7:\n // horizontal flip + 90 rotate right\n original_ration = width / height\n break\n case 8:\n // 90° rotate left\n original_ration = width / height\n break\n default:\n original_ration = height / width\n break\n }\n\n set_width(width)\n set_height(height)\n setOriginalPhoto(reader_event.target.result)\n set_orientation(new_orientation)\n setOriginalPhotoRation(original_ration)\n })\n }\n img.src = reader_event.target.result\n }\n reader.readAsDataURL(file)\n }, [])\n\n const handleImage = useCallback(files_event => {\n handleReadFile(files_event.target.files[0])\n }, [handleReadFile])\n\n const onDrop = useCallback(acceptedFiles => {\n handleReadFile(acceptedFiles[0])\n }, [handleReadFile])\n\n const handleDownload = useCallback(() => {\n const img = new Image()\n img.onload = function () {\n const canvas = document.createElement('canvas')\n canvas.width = frameSize\n canvas.height = frameSize\n\n const ctx = canvas.getContext('2d', { alpha: true })\n\n // use the correct image orientation\n switch (orientation) {\n // Source: https://stackoverflow.com/a/30242954/2387277\n // Source: https://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin\n case 2:\n // horizontal flip\n ctx.translate(canvas.width, 0)\n ctx.scale(-1, 1)\n break\n case 3:\n // 180° rotate left\n ctx.translate(canvas.width, canvas.height)\n ctx.rotate(Math.PI)\n break\n case 4:\n // vertical flip\n ctx.translate(0, canvas.height)\n ctx.scale(1, -1)\n break\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.scale(1, -1)\n break\n case 6:\n // 90° rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.translate(0, -canvas.height)\n break\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.translate(canvas.width, -canvas.height)\n ctx.scale(-1, 1)\n break\n case 8:\n // 90° rotate left\n ctx.rotate(-0.5 * Math.PI)\n ctx.translate(-canvas.width, 0)\n break\n default:\n break\n }\n\n\n const width_scaled = width * cords.scale\n const height_scaled = height * cords.scale\n\n ctx.drawImage(\n img,\n cords.x * 3.5 + (frameSize - width_scaled) * 0.5,\n cords.y * 3.5 + (frameSize - height_scaled) * 0.5,\n width_scaled,\n height_scaled,\n )\n // ctx.drawImage(\n // img,\n // ((frameSize - width_scaled) * 0.5),\n // ((frameSize - height_scaled) * 0.5),\n // width_scaled,\n // height_scaled,\n // )\n\n const pngUrl = canvas.toDataURL()\n\n mergeImages([\n ...(pngUrl ? [pngUrl] : []),\n ...(frameURL ? [frameURL] : []),\n ])\n .then(b64 => {\n // set_combinedImage(b64)\n trigger_download('volt-profile-picture.png', b64)\n })\n\n }\n img.src = originalPhoto\n }, [\n originalPhoto,\n cords.x,\n cords.y,\n cords.scale,\n orientation,\n frameURL,\n height,\n width,\n ])\n\n const { isDragActive, getRootProps } = useDropzone({\n onDrop,\n accept: 'image/*',\n maxFiles: 1,\n noKeyboard: true,\n })\n\n\n return (\n
\n \"Volt\n\n
\n Drop your photo here ...\n
\n\n

Choose your Photo:

\n

It should best be a square image or your face in the middle. The photo is not saved and never leaves your computer.

\n\n \n\n {!!originalPhoto ? (<>\n \n ) : null}\n\n {!!originalPhoto && !!frameURL ? (<>\n

Edit your Photo:

\n

Your can reposition the image and scale it. Use pinch-to-zoom or scroll to scale.

\n\n \n\n \n ) : null}\n
\n )\n}\n\nexport default App\n","const reportWebVitals = onPerfEntry => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry)\n getFID(onPerfEntry)\n getFCP(onPerfEntry)\n getLCP(onPerfEntry)\n getTTFB(onPerfEntry)\n })\n }\n}\n\nexport default reportWebVitals\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport App from './App'\nimport reportWebVitals from './reportWebVitals'\n\nReactDOM.render(\n \n \n ,\n document.getElementById('root')\n)\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n"],"sourceRoot":""} \ No newline at end of file diff --git a/static/js/main.2acad07c.chunk.js b/static/js/main.2acad07c.chunk.js new file mode 100644 index 0000000..840dbd5 --- /dev/null +++ b/static/js/main.2acad07c.chunk.js @@ -0,0 +1,2 @@ +(this["webpackJsonpprofile-picture-generator"]=this["webpackJsonpprofile-picture-generator"]||[]).push([[0],{22:function(e,t,a){},26:function(e,t,a){var r={"./ProfileFrame B&G Bars.png":[28,4],"./ProfileFrame Blue Bars.png":[29,5],"./ProfileFrame Green Bars.png":[30,6],"./ProfileFrame Mixed Bars.png":[31,7],"./ProfileFrame Purple.png":[32,8],"./ProfileFrame R&Y Bars.png":[33,9],"./ProfileFrame Red Bars.png":[34,10],"./ProfileFrame White Bars.png":[35,11],"./ProfileFrame Yellow Bars.png":[36,12]};function n(e){if(!a.o(r,e))return Promise.resolve().then((function(){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}));var t=r[e],n=t[0];return a.e(t[1]).then((function(){return a(n)}))}n.keys=function(){return Object.keys(r)},n.id=26,e.exports=n},27:function(e,t,a){"use strict";a.r(t);var r=a(1),n=a(0),c=a.n(n),s=a(11),o=a.n(s),i=a(10),u=a(9),l=a(2),f=(a(22),a(16)),b=a(5),j=a.n(b),d=a(8);var h=function(e){var t=e.onFrameChange,c=Object(n.useState)([]),s=Object(l.a)(c,2),o=s[0],i=s[1],u=Object(n.useState)(null),f=Object(l.a)(u,2),b=f[0],h=f[1];Object(n.useEffect)((function(){function e(){return(e=Object(d.a)(j.a.mark((function e(){return j.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:Promise.all(["ProfileFrame Purple","ProfileFrame Yellow Bars","ProfileFrame Red Bars","ProfileFrame Blue Bars","ProfileFrame Green Bars","ProfileFrame White Bars","ProfileFrame Mixed Bars","ProfileFrame R&Y Bars","ProfileFrame B&G Bars"].map(function(){var e=Object(d.a)(j.a.mark((function e(t){return j.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.t0=t,e.next=3,a(26)("./".concat(t,".png"));case 3:return e.t1=e.sent,e.abrupt("return",{name:e.t0,src:e.t1});case 5:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}())).then((function(e){i(e),h(e[0].src.default)}));case 1:case"end":return e.stop()}}),e)})))).apply(this,arguments)}!function(){e.apply(this,arguments)}()}),[]);var O=Object(n.useCallback)((function(e){h(e.target.dataset.src)}),[h]);return Object(n.useEffect)((function(){t(b)}),[t,b]),Object(r.jsxs)("div",{className:"FrameChooser",children:[Object(r.jsx)("h2",{children:"Choose a frame:"}),o.map((function(e){var t=e.src.default,a=b===t;return Object(r.jsx)("img",{alt:e.name,"data-src":t,src:t,className:a?"frame choosen":"frame",onClick:O},t)}))]})},O=a(13),g=a.n(O),m=a(14),p=a.n(m);function v(e,t,a){return Math.min(Math.max(t,e),a)}var x=function(e){var t=e.onChange,a=e.background,c=e.backgroundRatio,s=e.foreground,o=Object(n.useRef)(null),i=Object(n.useRef)(null),u=Object(n.useState)(!1),f=Object(l.a)(u,2),b=f[0],j=f[1],d=Object(n.useState)(null),h=Object(l.a)(d,2),O=h[0],m=h[1],x=Object(n.useState)(null),P=Object(l.a)(x,2),w=P[0],k=P[1],F=Object(n.useState)(0),y=Object(l.a)(F,2),C=y[0],S=y[1],B=Object(n.useState)(0),M=Object(l.a)(B,2),E=M[0],D=M[1],I=Object(n.useState)(0),L=Object(l.a)(I,2),R=L[0],U=L[1],N=Object(n.useState)(0),Y=Object(l.a)(N,2),A=Y[0],T=Y[1],X=Object(n.useState)(1),G=Object(l.a)(X,2),H=G[0],W=G[1],_=Object(n.useState)(300),J=Object(l.a)(_,2),V=J[0],q=J[1],z=Object(n.useState)(300),K=Object(l.a)(z,2),Q=K[0],Z=K[1],$=Object(n.useState)(300),ee=Object(l.a)($,2),te=ee[0],ae=ee[1],re=Object(n.useState)(300),ne=Object(l.a)(re,2),ce=ne[0],se=ne[1],oe=Object(n.useState)(0),ie=Object(l.a)(oe,2),ue=ie[0],le=ie[1],fe=Object(n.useState)(0),be=Object(l.a)(fe,2),je=be[0],de=be[1],he=Object(n.useState)(0),Oe=Object(l.a)(he,2),ge=Oe[0],me=Oe[1],pe=Object(n.useState)(0),ve=Object(l.a)(pe,2),xe=ve[0],Pe=ve[1];Object(n.useEffect)((function(){t&&t({x:C,y:E,scale:H})}),[t,C,E,H]),Object(n.useEffect)((function(){if(o&&o.current){var e=o.current.offsetWidth,t=o.current.offsetHeight;se(t),ae(e);var a=1,r=1;c<1?a=1/c:c>1&&(r=1*c),q(a),Z(r)}}),[c,s]),Object(n.useEffect)((function(){var e=function(e,t,a,r,n){var c=Math.max(0,e*a-r)/2,s=Math.max(0,t*a-n)/2;return{rangeMaxX:c,rangeMinX:0-c,rangeMaxY:s,rangeMinY:0-s}}(V*te,Q*ce,H,te,ce),t=e.rangeMinX,a=e.rangeMinY,r=e.rangeMaxX,n=e.rangeMaxY;le(t),de(a),me(r),Pe(n)}),[V,Q,te,ce,H]),Object(n.useEffect)((function(){S(0),D(0),U(0),T(0),W(1)}),[a]);var we=Object(n.useCallback)((function(e){var t=1*e.target.dataset.x,a=1*e.target.dataset.y,r=v(t+e.deltaX,ue,ge),n=v(a+e.deltaY,je,xe);e.isFinal?(S(r||0),D(n||0),U(0),T(0)):(U(r-t||0),T(n-a||0))}),[ue,je,ge,xe]),ke=Object(n.useCallback)((function(e,t,a,r){e.preventDefault();var n=v(1*e.target.dataset.scale+t/200,1,8);W(n||1);var c=1*e.target.dataset.x,s=1*e.target.dataset.y;S(v(c,ue,ge)||0),D(v(s,je,xe)||0)}),[ue,je,ge,xe]);return Object(n.useEffect)((function(){if(!b&&o&&o.current){var e=o.current;e.addEventListener("mousedown",(function(e){e.preventDefault()}),!1),e.addEventListener("touchstart",(function(e){e.preventDefault()}),!1),e.addEventListener("touchend",(function(e){e.preventDefault()}),!1),e.addEventListener("touchmove",(function(e){e.preventDefault()}),!1),m(new g.a(e,{direction:"DIRECTION_ALL"})),k(p()(e)),j(!0)}}),[o,b]),Object(n.useEffect)((function(){if(O&&w&&b&&o&&o.current)return O.on("pan",we),w.wheel(ke),function(){O.off("pan",we),w.unwheel()}}),[o,we,ke,b,O,w]),Object(r.jsxs)("div",{className:"Editor",ref:o,"data-x":C,"data-y":E,"data-scale":H,children:[Object(r.jsx)("img",{src:a,ref:i,alt:"",className:"background",style:{width:100*V+"%",height:100*Q+"%",transform:"translate3d(calc(-50% + ".concat(C+R,"px), calc(-50% + ").concat(E+A,"px), 0) scale(").concat(H,",").concat(H,")")}}),Object(r.jsx)("img",{src:s,alt:"",className:"foreground"})]})},P=a.p+"static/media/HeaderImage.1f39a672.svg",w=a(15),k=1080;var F=function(){var e=Object(n.useState)(null),t=Object(l.a)(e,2),a=t[0],c=t[1],s=Object(n.useState)(null),o=Object(l.a)(s,2),b=o[0],j=o[1],d=Object(n.useState)(1),O=Object(l.a)(d,2),g=O[0],m=O[1],p=Object(n.useState)(null),v=Object(l.a)(p,2),F=v[0],y=v[1],C=Object(n.useState)(0),S=Object(l.a)(C,2),B=S[0],M=S[1],E=Object(n.useState)(0),D=Object(l.a)(E,2),I=D[0],L=D[1],R=Object(n.useState)({x:0,y:0,scale:1}),U=Object(l.a)(R,2),N=U[0],Y=U[1],A=Object(n.useCallback)((function(e){c(e)}),[c]),T=Object(n.useCallback)((function(e){var t=e.x,a=e.y,r=e.scale;console.log({x:t,y:a,scale:r}),Y({x:t,y:a,scale:r})}),[]),X=Object(n.useCallback)((function(e){if(e){var t=new FileReader;t.onload=function(t){var a=new Image;a.onload=function(){var r,n;a.width {\n async function loadFrames(){\n Promise.all(\n [\n 'ProfileFrame Purple',\n 'ProfileFrame Yellow Bars',\n 'ProfileFrame Red Bars',\n 'ProfileFrame Blue Bars',\n 'ProfileFrame Green Bars',\n 'ProfileFrame White Bars',\n 'ProfileFrame Mixed Bars',\n 'ProfileFrame R&Y Bars',\n 'ProfileFrame B&G Bars',\n ]\n .map(async frame_filename => {\n return {\n name: frame_filename,\n src: await import(`./frames/${frame_filename}.png`),\n }\n })\n )\n .then(new_frames => {\n setFrames(new_frames)\n setChoosenFrame(new_frames[0].src.default)\n })\n }\n loadFrames()\n }, [])\n\n const handleImageChoosing = useCallback(event => {\n setChoosenFrame(event.target.dataset.src)\n }, [setChoosenFrame])\n\n useEffect(() => {\n onFrameChange(choosenFrame)\n }, [onFrameChange, choosenFrame])\n\n return (\n
\n

Choose a frame:

\n {\n frames.map(frame => {\n const frame_src_path = frame.src.default\n const isChoosen = choosenFrame === frame_src_path\n return {frame.name}\n })\n } \n
\n )\n}\n\nexport default FrameChooser\n","import { useEffect, useRef, useState, useCallback } from 'react'\n\nimport Hammer from 'hammerjs'\nimport Hamster from 'hamsterjs'\n\nfunction updateRange(imageWidth, imageHeight, imageScale, containerWidth, containerHeight) {\n\n const rangeX = Math.max(0, (imageWidth * imageScale) - containerWidth)\n const rangeY = Math.max(0, (imageHeight * imageScale) - containerHeight)\n\n const rangeMaxX = (rangeX / 2)\n const rangeMinX = 0 - rangeMaxX\n\n const rangeMaxY = (rangeY / 2)\n const rangeMinY = 0 - rangeMaxY\n\n return {\n rangeMaxX,\n rangeMinX,\n rangeMaxY,\n rangeMinY,\n }\n}\n\nfunction clamp(value, min, max) {\n return Math.min(Math.max(min, value), max)\n}\n\n\n\nlet minScale = 1;\nlet maxScale = 8;\n\n\n\nfunction Editor({ onChange, background, backgroundRatio, foreground }) {\n const editorRef = useRef(null)\n const backgroundImageRef = useRef(null)\n\n const [hammer_got_init, set_hammer_got_init] = useState(false)\n\n const [hammertime, set_hammertime] = useState(null)\n const [hamster, set_hamster] = useState(null)\n\n const [x, set_x] = useState(0)\n const [y, set_y] = useState(0)\n const [add_x, set_add_x] = useState(0)\n const [add_y, set_add_y] = useState(0)\n const [scale, set_scale] = useState(1)\n // const [add_scale, set_add_scale] = useState(0)\n\n const [photoWidth, setPhotoWidth] = useState(300)\n const [photoHeight, setPhotoHeight] = useState(300)\n const [editorWidth, setEditorWidth] = useState(300)\n const [editorHeight, setEditorHeight] = useState(300)\n\n const [rangeMinX, set_rangeMinX] = useState(0)\n const [rangeMinY, set_rangeMinY] = useState(0)\n const [rangeMaxX, set_rangeMaxX] = useState(0)\n const [rangeMaxY, set_rangeMaxY] = useState(0)\n\n useEffect(() => {\n if (!!onChange) {\n onChange({ x, y, scale})\n }\n }, [onChange, x, y, scale])\n\n useEffect(() => {\n if (!!editorRef && !!editorRef.current) {\n const new_editorWidth = editorRef.current.offsetWidth\n const new_editorHeight = editorRef.current.offsetHeight\n setEditorHeight(new_editorHeight)\n setEditorWidth(new_editorWidth)\n\n let new_photoWidth = 1\n let new_photoHeight = 1\n if (backgroundRatio < 1) {\n new_photoWidth = 1 / backgroundRatio\n } else if (backgroundRatio > 1) {\n new_photoHeight = 1 * backgroundRatio\n }\n\n setPhotoWidth(new_photoWidth)\n setPhotoHeight(new_photoHeight)\n }\n }, [\n backgroundRatio,\n foreground,\n ])\n\n useEffect(() => {\n const {\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n } = updateRange(photoWidth * editorWidth, photoHeight * editorHeight, scale, editorWidth, editorHeight)\n\n set_rangeMinX(rangeMinX)\n set_rangeMinY(rangeMinY)\n set_rangeMaxX(rangeMaxX)\n set_rangeMaxY(rangeMaxY)\n }, [\n photoWidth,\n photoHeight,\n editorWidth,\n editorHeight,\n scale,\n ])\n\n useEffect(() => {\n set_x(0)\n set_y(0)\n set_add_x(0)\n set_add_y(0)\n set_scale(1)\n }, [background])\n\n const handleMove = useCallback(event => {\n const prev_x = event.target.dataset.x * 1\n const prev_y = event.target.dataset.y * 1\n\n const new_x = clamp(prev_x + event.deltaX, rangeMinX, rangeMaxX)\n const new_y = clamp(prev_y + event.deltaY, rangeMinY, rangeMaxY)\n\n if (event.isFinal) {\n set_x(new_x || 0)\n set_y(new_y || 0)\n set_add_x(0)\n set_add_y(0)\n }else{\n set_add_x(new_x - prev_x || 0)\n set_add_y(new_y - prev_y || 0)\n }\n }, [\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n ])\n\n const handleScale = useCallback((event, delta, deltaX, deltaY) => {\n event.preventDefault()\n\n const prev_scale = event.target.dataset.scale * 1\n const new_scale = clamp(prev_scale + delta / 200, minScale, maxScale)\n set_scale(new_scale || 1)\n\n const prev_x = event.target.dataset.x * 1\n const prev_y = event.target.dataset.y * 1\n set_x(clamp(prev_x, rangeMinX, rangeMaxX) || 0)\n set_y(clamp(prev_y, rangeMinY, rangeMaxY) || 0)\n }, [\n rangeMinX,\n rangeMinY,\n rangeMaxX,\n rangeMaxY,\n ])\n\n useEffect(() => {\n if (!hammer_got_init && !!editorRef && !!editorRef.current) {\n const element = editorRef.current\n\n element.addEventListener('mousedown', event => {\n event.preventDefault()\n // event.stopPropagation()\n }, false)\n element.addEventListener(\"touchstart\", event => {\n event.preventDefault()\n // event.stopPropagation()\n }, false)\n element.addEventListener(\"touchend\", event => {\n event.preventDefault()\n // event.stopPropagation()\n }, false)\n element.addEventListener(\"touchmove\", event => {\n event.preventDefault()\n // event.stopPropagation()\n }, false)\n\n set_hammertime(new Hammer(element, {\n direction: 'DIRECTION_ALL',\n }))\n\n set_hamster(Hamster(element))\n\n set_hammer_got_init(true)\n }\n }, [editorRef, hammer_got_init])\n\n useEffect(() => {\n if (!!hammertime && !!hamster && hammer_got_init && !!editorRef && !!editorRef.current) {\n hammertime.on('pan', handleMove)\n hamster.wheel(handleScale)\n\n return function () {\n hammertime.off('pan', handleMove)\n hamster.unwheel()\n }\n }\n }, [editorRef, handleMove, handleScale, hammer_got_init, hammertime, hamster])\n\n return (\n \n \n \n \n )\n}\n\nexport default Editor\n","export default __webpack_public_path__ + \"static/media/HeaderImage.1f39a672.svg\";","import { useState, useCallback } from 'react'\nimport './App.css'\nimport { useDropzone } from 'react-dropzone'\nimport FrameChooser from './FrameChooser.js'\nimport Editor from './Editor.js'\nimport HeaderImage from './HeaderImage.svg'\n\nimport mergeImages from 'merge-images'\n\nconst frameSize = 1080\n\nfunction getOrientation(file, callback) {\n // Source: http://stackoverflow.com/a/32490603\n // (With some modifications: I just made the code fit the style-guide.)\n const reader = new FileReader()\n\n reader.onload = function (event) {\n const view = new DataView(event.target.result)\n\n if (view.getUint16(0, false) !== 0xFFD8) {\n return callback(-2)\n }\n\n const length = view.byteLength\n let offset = 2\n\n while (offset < length) {\n const marker = view.getUint16(offset, false)\n offset += 2\n\n if (marker === 0xFFE1) {\n if (view.getUint32(offset += 2, false) !== 0x45786966) {\n return callback(-1)\n }\n const little = view.getUint16(offset += 6, false) === 0x4949\n offset += view.getUint32(offset + 4, little)\n const tags = view.getUint16(offset, little)\n offset += 2\n\n for (var i = 0; i < tags; i++) {\n if (view.getUint16(offset + (i * 12), little) === 0x0112) {\n return callback(view.getUint16(offset + (i * 12) + 8, little))\n }\n }\n } else if ((marker & 0xFF00) !== 0xFF00) {\n break\n } else {\n offset += view.getUint16(offset, false)\n }\n }\n return callback(-1)\n }\n\n reader.readAsArrayBuffer(file.slice(0, 64 * 1024))\n}\n\nfunction trigger_download(name, data){\n const a = document.createElement('a')\n document.body.appendChild(a)\n // a.target = '_blank'\n a.download = name\n a.href = data\n a.click()\n a.remove()\n}\n\nfunction App() {\n const [frameURL, setFrameURL] = useState(null)\n const [originalPhoto, setOriginalPhoto] = useState(null)\n const [originalPhotoRation, setOriginalPhotoRation] = useState(1)\n const [orientation, set_orientation] = useState(null)\n\n\n // const [combinedImage, set_combinedImage] = useState(null)\n\n const [width, set_width] = useState(0)\n const [height, set_height] = useState(0)\n\n const [cords, setCords] = useState({x:0, y:0, scale:1})\n\n const handleFrameURL = useCallback(newFrameURL => {\n setFrameURL(newFrameURL)\n }, [setFrameURL])\n\n const handleCordsChange = useCallback(({x, y, scale}) => {\n console.log({ x, y, scale })\n setCords({ x, y, scale })\n }, [])\n\n const handleReadFile = useCallback(file => {\n if (!(!!file)) {\n return;\n }\n\n const reader = new FileReader()\n reader.onload = reader_event => {\n const img = new Image()\n img.onload = function () {\n let width, height;\n if (img.width < img.height) {\n height = (img.height / img.width) * frameSize\n width = frameSize\n } else {\n height = frameSize\n width = (img.width / img.height) * frameSize\n }\n\n getOrientation(file, new_orientation => {\n let original_ration = 1\n // use the correct image orientation\n switch (new_orientation) {\n // Source: https://stackoverflow.com/a/30242954/2387277\n // Source: https://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin\n case 2:\n // horizontal flip\n original_ration = height / width\n break\n case 3:\n // 180° rotate left\n original_ration = height / width\n break\n case 4:\n // vertical flip\n original_ration = height / width\n break\n case 5:\n // vertical flip + 90 rotate right\n original_ration = width / height\n break\n case 6:\n // 90° rotate right\n original_ration = width / height\n break\n case 7:\n // horizontal flip + 90 rotate right\n original_ration = width / height\n break\n case 8:\n // 90° rotate left\n original_ration = width / height\n break\n default:\n original_ration = height / width\n break\n }\n\n set_width(width)\n set_height(height)\n setOriginalPhoto(reader_event.target.result)\n set_orientation(new_orientation)\n setOriginalPhotoRation(original_ration)\n })\n }\n img.src = reader_event.target.result\n }\n reader.readAsDataURL(file)\n }, [])\n\n const handleImage = useCallback(files_event => {\n handleReadFile(files_event.target.files[0])\n }, [handleReadFile])\n\n const onDrop = useCallback(acceptedFiles => {\n handleReadFile(acceptedFiles[0])\n }, [handleReadFile])\n\n const handleDownload = useCallback(() => {\n const img = new Image()\n img.onload = function () {\n const canvas = document.createElement('canvas')\n canvas.width = frameSize\n canvas.height = frameSize\n\n const ctx = canvas.getContext('2d', { alpha: true })\n\n // use the correct image orientation\n switch (orientation) {\n // Source: https://stackoverflow.com/a/30242954/2387277\n // Source: https://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin\n case 2:\n // horizontal flip\n ctx.translate(canvas.width, 0)\n ctx.scale(-1, 1)\n break\n case 3:\n // 180° rotate left\n ctx.translate(canvas.width, canvas.height)\n ctx.rotate(Math.PI)\n break\n case 4:\n // vertical flip\n ctx.translate(0, canvas.height)\n ctx.scale(1, -1)\n break\n case 5:\n // vertical flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.scale(1, -1)\n break\n case 6:\n // 90° rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.translate(0, -canvas.height)\n break\n case 7:\n // horizontal flip + 90 rotate right\n ctx.rotate(0.5 * Math.PI)\n ctx.translate(canvas.width, -canvas.height)\n ctx.scale(-1, 1)\n break\n case 8:\n // 90° rotate left\n ctx.rotate(-0.5 * Math.PI)\n ctx.translate(-canvas.width, 0)\n break\n default:\n break\n }\n\n\n const width_scaled = width * cords.scale\n const height_scaled = height * cords.scale\n\n ctx.drawImage(\n img,\n cords.x * 3.5 + (frameSize - width_scaled) * 0.5,\n cords.y * 3.5 + (frameSize - height_scaled) * 0.5,\n width_scaled,\n height_scaled,\n )\n // ctx.drawImage(\n // img,\n // ((frameSize - width_scaled) * 0.5),\n // ((frameSize - height_scaled) * 0.5),\n // width_scaled,\n // height_scaled,\n // )\n\n const pngUrl = canvas.toDataURL()\n\n mergeImages([\n ...(pngUrl ? [pngUrl] : []),\n ...(frameURL ? [frameURL] : []),\n ])\n .then(b64 => {\n // set_combinedImage(b64)\n trigger_download('volt-profile-picture.png', b64)\n })\n\n }\n img.src = originalPhoto\n }, [\n originalPhoto,\n cords.x,\n cords.y,\n cords.scale,\n orientation,\n frameURL,\n height,\n width,\n ])\n\n const { isDragActive, getRootProps } = useDropzone({\n onDrop,\n accept: 'image/*',\n maxFiles: 1,\n noKeyboard: true,\n })\n\n\n return (\n
\n \"Volt\n\n
\n Drop your photo here ...\n
\n\n

Choose your Photo:

\n

It should best be a square image or your face in the middle. The photo is not saved and never leaves your computer.

\n\n \n\n {!!originalPhoto ? (<>\n \n ) : null}\n\n {!!originalPhoto && !!frameURL ? (<>\n

Edit your Photo:

\n

Your can reposition the image and scale it. Use pinch-to-zoom or scroll to scale.

\n\n \n\n \n ) : null}\n
\n )\n}\n\nexport default App\n","const reportWebVitals = onPerfEntry => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry)\n getFID(onPerfEntry)\n getFCP(onPerfEntry)\n getLCP(onPerfEntry)\n getTTFB(onPerfEntry)\n })\n }\n}\n\nexport default reportWebVitals\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport App from './App'\nimport reportWebVitals from './reportWebVitals'\n\nReactDOM.render(\n \n \n ,\n document.getElementById('root')\n)\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n"],"sourceRoot":""} \ No newline at end of file