{"title":"Outlinegenerator","description":"\u003csection\u003e\n\n\u003cdiv class=\"sl-frame\"\u003e\n\n  \u003ch2\u003e🖋️ Line Art \u0026amp; Freisteller \u0026amp; Comic Generator\u003c\/h2\u003e\n  \u003cp class=\"sl-sub\"\u003eOutlines, Simple Lines, Freisteller \u0026amp; Comic · Live Vorschau\u003c\/p\u003e\n\n  \u003cinput type=\"file\" id=\"sl-upload\" accept=\"image\/*\"\u003e\n\n  \u003c!-- Modus --\u003e\n  \u003cdiv class=\"sl-modes\"\u003e\n    \u003clabel\u003e\u003cinput type=\"radio\" name=\"mode\" value=\"outline\" checked\u003e Outlines\u003c\/label\u003e\n    \u003clabel\u003e\u003cinput type=\"radio\" name=\"mode\" value=\"simple\"\u003e Simple Line\u003c\/label\u003e\n    \u003clabel\u003e\u003cinput type=\"radio\" name=\"mode\" value=\"freisteller\"\u003e Freisteller\u003c\/label\u003e\n    \u003clabel\u003e\u003cinput type=\"radio\" name=\"mode\" value=\"comic\"\u003e Comic\u003c\/label\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- Controls --\u003e\n  \u003cdiv class=\"sl-controls\"\u003e\n    \u003clabel\u003e\n      Linienfarbe\n      \u003cinput type=\"color\" id=\"sl-color\" value=\"#000000\"\u003e\n    \u003c\/label\u003e\n\n    \u003clabel\u003e\n      Empfindlichkeit\n      \u003cinput type=\"range\" id=\"sl-threshold\" min=\"20\" max=\"220\" value=\"120\"\u003e\n    \u003c\/label\u003e\n\n    \u003clabel\u003e\n      Hintergrundfarbe\n      \u003cinput type=\"color\" id=\"sl-bgcolor\" value=\"#ffffff\"\u003e\n    \u003c\/label\u003e\n\n    \u003clabel\u003e\n      Transparent\n      \u003cinput type=\"checkbox\" id=\"sl-transparent\"\u003e\n    \u003c\/label\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- Arbeitsfläche --\u003e\n  \u003ccanvas id=\"sl-canvas\"\u003e\u003c\/canvas\u003e\n\n  \u003cdiv class=\"sl-actions\"\u003e\n    \u003cbutton id=\"sl-download-png\"\u003ePNG\u003c\/button\u003e\n    \u003cbutton id=\"sl-download-jpg\"\u003eJPG\u003c\/button\u003e\n  \u003c\/div\u003e\n\n\u003c\/div\u003e\n\n\u003cstyle\u003e\n.sl-frame{\n  max-width:820px;\n  margin:40px auto;\n  padding:28px;\n  background:#111;\n  border-radius:18px;\n  color:#eee;\n  font-family:Arial, sans-serif;\n}\n\n.sl-frame h2{\n  text-align:center;\n  margin-bottom:6px;\n}\n\n.sl-sub{\n  text-align:center;\n  color:#aaa;\n  margin-bottom:22px;\n}\n\n.sl-frame input[type=file]{\n  width:100%;\n  margin-bottom:18px;\n}\n\n.sl-modes{\n  display:flex;\n  justify-content:center;\n  gap:24px;\n  margin-bottom:18px;\n  color:#ccc;\n}\n\n.sl-controls{\n  display:grid;\n  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));\n  gap:16px;\n  margin-bottom:18px;\n  font-size:14px;\n}\n\n.sl-controls label{\n  display:flex;\n  flex-direction:column;\n  gap:6px;\n}\n\n#sl-canvas{\n  width:100%;\n  background:#fff;\n  border-radius:12px;\n  border:1px solid #ccc;\n  margin-bottom:18px;\n  display:block;\n}\n\n.sl-actions{\n  display:flex;\n  justify-content:center;\n  gap:14px;\n}\n\n.sl-actions button{\n  padding:10px 24px;\n  border:none;\n  border-radius:10px;\n  background:#fff;\n  color:#000;\n  cursor:pointer;\n}\n\n.sl-controls input:disabled {\n  opacity:0.5;\n  cursor:not-allowed;\n}\n\u003c\/style\u003e\n\n\u003cscript\u003e\n(function(){\n  const upload = document.getElementById('sl-upload');\n  const canvas = document.getElementById('sl-canvas');\n  const ctx = canvas.getContext('2d');\n\n  const color = document.getElementById('sl-color');\n  const threshold = document.getElementById('sl-threshold');\n  const bg = document.getElementById('sl-bgcolor');\n  const transparent = document.getElementById('sl-transparent');\n\n  const tmp = document.createElement('canvas');\n  const tctx = tmp.getContext('2d',{willReadFrequently:true});\n\n  let original = null;\n\n  upload.onchange = e =\u003e {\n    const img = new Image();\n    img.onload = () =\u003e {\n      const scale = Math.min(1,1800\/Math.max(img.width,img.height));\n      canvas.width = tmp.width = img.width * scale;\n      canvas.height = tmp.height = img.height * scale;\n\n      tctx.clearRect(0,0,tmp.width,tmp.height);\n      tctx.drawImage(img,0,0,tmp.width,tmp.height);\n      original = tctx.getImageData(0,0,tmp.width,tmp.height);\n\n      render();\n    };\n    img.src = URL.createObjectURL(e.target.files[0]);\n  };\n\n  document.querySelectorAll(\n    '#sl-color,#sl-threshold,#sl-bgcolor,#sl-transparent,input[name=\"mode\"]'\n  ).forEach(el =\u003e el.oninput = render);\n\n  function render(){\n    if(!original) return;\n\n    const mode = document.querySelector('[name=mode]:checked').value;\n    const isFreisteller = mode === 'freisteller';\n    const isComic = mode === 'comic';\n\n    color.disabled = isFreisteller || isComic;\n    threshold.disabled = isFreisteller || isComic;\n\n    const src = original.data;\n    const out = new Uint8ClampedArray(src.length);\n\n    for(let i=0;i\u003csrc.length;i+=4){\n      const r=src[i], g=src[i+1], b=src[i+2];\n      const brightness = 0.299*r + 0.587*g + 0.114*b;\n\n      if(isFreisteller){\n        if(brightness \u003e threshold.value){\n          out[i+3]=0;\n        } else {\n          out[i]=r; out[i+1]=g; out[i+2]=b; out[i+3]=255;\n        }\n      } else if(isComic){\n        let pr = Math.floor(r\/64)*64;\n        let pg = Math.floor(g\/64)*64;\n        let pb = Math.floor(b\/64)*64;\n\n        if(brightness \u003c threshold.value){\n          pr=pg=pb=0;\n        }\n\n        out[i]=pr;\n        out[i+1]=pg;\n        out[i+2]=pb;\n        out[i+3] = 255; \/\/ Motiv sichtbar\n      } else {\n        const col = hex(color.value);\n        if(brightness \u003c threshold.value){\n          out[i]=col.r; out[i+1]=col.g; out[i+2]=col.b; out[i+3]=255;\n        } else {\n          out[i+3]=mode==='simple'?30:0;\n        }\n      }\n    }\n\n    tctx.putImageData(new ImageData(out,tmp.width,tmp.height),0,0);\n\n    ctx.clearRect(0,0,canvas.width,canvas.height);\n\n    \/\/ Hintergrund live malen\n    if(!transparent.checked){\n      ctx.fillStyle = bg.value;\n      ctx.fillRect(0,0,canvas.width,canvas.height);\n    }\n\n    ctx.drawImage(tmp,0,0);\n  }\n\n  function download(filename){\n    const a = document.createElement('a');\n    a.download = filename;\n    a.href = canvas.toDataURL('image\/png');\n    a.click();\n  }\n\n  document.getElementById('sl-download-png').onclick = ()=\u003edownload('line-art.png');\n  document.getElementById('sl-download-jpg').onclick = ()=\u003edownload('line-art.jpg');\n\n  function hex(h){\n    const n = parseInt(h.slice(1),16);\n    return {r:(n\u003e\u003e16)\u0026255,g:(n\u003e\u003e8)\u0026255,b:n\u0026255};\n  }\n})();\n\u003c\/script\u003e\n\n\u003c\/section\u003e\n\n{% schema %}\n{\n  \"name\": \"Line Art, Freisteller\",\n  \"settings\": [],\n  \"presets\": [\n    { \"name\": \"Line Art, Freisteller\" }\n  ]\n}\n{% endschema %}","products":[],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0779\/6578\/7470\/collections\/line-art_12.png?v=1779839248","url":"https:\/\/www.zoey-kunstdrucke.de\/collections\/outlinegenerator.oembed","provider":"Zoey Kunstdrucke","version":"1.0","type":"link"}