{"id":213,"date":"2026-06-26T21:48:09","date_gmt":"2026-06-26T21:48:09","guid":{"rendered":"https:\/\/toolskit.site\/?page_id=213"},"modified":"2026-06-26T21:48:10","modified_gmt":"2026-06-26T21:48:10","slug":"213-2","status":"publish","type":"page","link":"https:\/\/toolskit.site\/index.php\/213-2\/","title":{"rendered":""},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Mehndi Stencil Pro<\/title>\n<style>\n  :root {\n    --bg: #0f0f14;\n    --panel: #17172b;\n    --card: #1e1e35;\n    --border: #2e2e55;\n    --gold: #c9a96e;\n    --gold2: #f0d080;\n    --green: #2ecc71;\n    --red: #e74c3c;\n    --text: #e8e8f0;\n    --muted: #888;\n    --radius: 12px;\n  }\n  * { margin:0; padding:0; box-sizing:border-box; }\n  body {\n    background: var(--bg);\n    color: var(--text);\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    min-height: 100vh;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    padding: 16px;\n    gap: 14px;\n  }\n\n  \/* HEADER *\/\n  .header { text-align:center; padding: 8px 0 4px; }\n  .header h1 {\n    font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em;\n    background: linear-gradient(120deg, var(--gold), var(--gold2), var(--gold));\n    -webkit-background-clip: text; -webkit-text-fill-color: transparent;\n  }\n  .header p { color: var(--muted); font-size: 0.82rem; margin-top: 3px; }\n\n  \/* UPLOAD *\/\n  .upload-area {\n    width: 100%; max-width: 640px;\n    border: 2px dashed var(--border);\n    border-radius: var(--radius);\n    background: var(--panel);\n    padding: 28px 20px;\n    text-align: center;\n    cursor: pointer;\n    transition: all 0.2s;\n    position: relative;\n  }\n  .upload-area:hover, .upload-area.drag { border-color: var(--gold); background: #1e1e35; }\n  .upload-area .upload-icon { font-size: 2.4rem; margin-bottom: 8px; }\n  .upload-area h3 { font-size: 1rem; color: var(--gold); margin-bottom: 4px; }\n  .upload-area p { font-size: 0.78rem; color: var(--muted); }\n  #fileInput { display:none; }\n\n  \/* PRESETS *\/\n  .presets-row {\n    display: flex; gap: 8px; flex-wrap: wrap; justify-content: center;\n    width: 100%; max-width: 640px;\n  }\n  .preset-btn {\n    padding: 7px 14px; border-radius: 20px;\n    border: 1px solid var(--border);\n    background: var(--panel); color: var(--muted);\n    font-size: 0.78rem; font-weight: 600; cursor: pointer;\n    transition: all 0.18s;\n  }\n  .preset-btn:hover { border-color: var(--gold); color: var(--gold); }\n  .preset-btn.active { background: var(--gold); color: #0f0f14; border-color: var(--gold); }\n\n  \/* MAIN LAYOUT *\/\n  .main { display:flex; gap:14px; width:100%; max-width:960px; flex-wrap:wrap; justify-content:center; }\n\n  \/* CONTROLS PANEL *\/\n  .controls-panel {\n    background: var(--panel);\n    border: 1px solid var(--border);\n    border-radius: var(--radius);\n    padding: 16px;\n    width: 240px;\n    min-width: 220px;\n    display: flex; flex-direction: column; gap: 10px;\n  }\n  .section-title {\n    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em;\n    text-transform: uppercase; color: var(--gold); margin-bottom: 2px;\n    padding-bottom: 5px; border-bottom: 1px solid var(--border);\n  }\n  .ctrl { display:flex; flex-direction:column; gap:4px; }\n  .ctrl-header { display:flex; justify-content:space-between; align-items:center; }\n  .ctrl-label { font-size: 0.78rem; color: var(--text); }\n  .ctrl-val {\n    font-size: 0.75rem; font-weight: 700; color: var(--gold2);\n    background: var(--card); padding: 1px 6px; border-radius: 4px;\n    min-width: 32px; text-align: center;\n  }\n  input[type=range] {\n    width: 100%; accent-color: var(--gold); height: 4px;\n    background: var(--border); border-radius: 2px;\n  }\n  .toggle-row {\n    display: flex; align-items: center; justify-content: space-between;\n    font-size: 0.78rem; color: var(--text);\n  }\n  .toggle {\n    position: relative; width: 36px; height: 20px;\n  }\n  .toggle input { opacity:0; width:0; height:0; }\n  .toggle-slider {\n    position: absolute; inset: 0; background: var(--border);\n    border-radius: 20px; cursor: pointer; transition: 0.2s;\n  }\n  .toggle-slider:before {\n    content:''; position:absolute; width:14px; height:14px;\n    left:3px; top:3px; background:#fff; border-radius:50%; transition:0.2s;\n  }\n  .toggle input:checked + .toggle-slider { background: var(--gold); }\n  .toggle input:checked + .toggle-slider:before { transform: translateX(16px); }\n\n  \/* ACTION BTNS *\/\n  .action-btns { display:flex; flex-direction:column; gap:7px; margin-top:4px; }\n  .btn {\n    padding: 9px; border-radius: 8px; border: none;\n    font-size: 0.82rem; font-weight: 700; cursor: pointer;\n    transition: all 0.18s; text-align: center;\n  }\n  .btn-gold { background: linear-gradient(135deg,#c9a96e,#a07840); color:#fff; }\n  .btn-gold:hover { opacity:0.88; transform: translateY(-1px); }\n  .btn-outline { background:transparent; border:1px solid var(--border); color: var(--muted); }\n  .btn-outline:hover { border-color: var(--gold); color: var(--gold); }\n  .btn-dl { background: #1a4a2e; color: var(--green); border: 1px solid #2ecc7144; }\n  .btn-dl:hover { background: #1e5a38; }\n  .btn-dl2 { background: #2a1a3a; color: #b080ff; border: 1px solid #b080ff44; }\n  .btn-dl2:hover { background: #341e4a; }\n\n  \/* CANVAS AREA *\/\n  .canvas-area {\n    flex: 1; min-width: 300px;\n    display: flex; flex-direction: column; gap: 10px;\n  }\n  .canvas-wrapper {\n    background: var(--panel); border: 1px solid var(--border);\n    border-radius: var(--radius); padding: 12px;\n    display: flex; flex-direction: column; gap: 8px;\n  }\n  .canvas-header { display:flex; justify-content:space-between; align-items:center; }\n  .canvas-label { font-size: 0.72rem; font-weight: 700; color: var(--gold); text-transform:uppercase; letter-spacing:0.07em; }\n  .canvas-info { font-size: 0.7rem; color: var(--muted); }\n  .canvas-container {\n    position: relative; border-radius: 8px; overflow: hidden;\n    background: repeating-conic-gradient(#ffffff08 0% 25%, transparent 0% 50%) 0 0 \/ 16px 16px;\n    cursor: crosshair; user-select: none;\n  }\n  #resultCanvas, #origCanvas {\n    display: block; width: 100%; border-radius: 8px; max-height: 480px; object-fit: contain;\n  }\n  \/* SLIDER COMPARE *\/\n  .compare-wrap { position:relative; border-radius:8px; overflow:hidden; }\n  .compare-wrap canvas { display:block; width:100%; }\n  .compare-divider {\n    position:absolute; top:0; bottom:0; width:2px; background:#fff;\n    pointer-events:none; z-index:3;\n  }\n  .compare-label-l, .compare-label-r {\n    position:absolute; top:8px; font-size:0.65rem; font-weight:700;\n    background:#0009; padding:2px 7px; border-radius:4px; z-index:4;\n    text-transform:uppercase; letter-spacing:0.06em;\n  }\n  .compare-label-l { left:8px; color:#fff; }\n  .compare-label-r { right:8px; color: var(--gold); }\n\n  \/* TABS *\/\n  .view-tabs { display:flex; gap:6px; }\n  .vtab {\n    padding: 4px 12px; border-radius: 6px; border: 1px solid var(--border);\n    background: transparent; color: var(--muted); font-size: 0.72rem; font-weight: 600;\n    cursor: pointer; transition:0.15s;\n  }\n  .vtab.active { background: var(--card); border-color: var(--gold); color: var(--gold); }\n\n  \/* STATUS *\/\n  .status-bar {\n    display: flex; align-items: center; gap: 8px;\n    background: var(--card); border-radius: 8px; padding: 8px 12px;\n    font-size: 0.78rem; min-height: 36px;\n  }\n  .status-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }\n  .dot-idle { background: var(--muted); }\n  .dot-processing { background: var(--gold); animation: pulse 0.7s infinite alternate; }\n  .dot-done { background: var(--green); }\n  .dot-error { background: var(--red); }\n  @keyframes pulse { from{opacity:1} to{opacity:0.3} }\n\n  .hidden { display:none !important; }\n  .placeholder {\n    display:flex; flex-direction:column; align-items:center; justify-content:center;\n    min-height:200px; color:var(--muted); font-size:0.85rem; gap:8px;\n  }\n  .placeholder-icon { font-size:3rem; opacity:0.3; }\n\n  \/* HISTOGRAM *\/\n  #histCanvas { width:100%; height:50px; border-radius:6px; }\n\n  @media(max-width:600px) {\n    .controls-panel { width:100%; }\n    .main { flex-direction:column; }\n  }\n<\/style>\n<\/head>\n<body>\n\n<div class=\"header\">\n  <h1>\ud83c\udf3f Mehndi Stencil Pro<\/h1>\n  <p>Professional mehndi design extractor \u2014 best quality output<\/p>\n<\/div>\n\n<!-- UPLOAD -->\n<div class=\"upload-area\" id=\"uploadArea\" onclick=\"document.getElementById('fileInput').click()\">\n  <div class=\"upload-icon\">\ud83d\udcf7<\/div>\n  <h3>Mehndi Photo Upload Karein<\/h3>\n  <p>Click karein ya drag &#038; drop \u2014 JPG \/ PNG supported<\/p>\n  <p style=\"margin-top:6px;font-size:0.7rem;color:#555\">High resolution photo = better result<\/p>\n<\/div>\n<input type=\"file\" id=\"fileInput\" accept=\"image\/*\">\n\n<!-- PRESETS -->\n<div class=\"presets-row\" id=\"presetsRow\" style=\"display:none\">\n  <button class=\"preset-btn active\" onclick=\"applyPreset('stencil',this)\">\ud83c\udfa8 Stencil<\/button>\n  <button class=\"preset-btn\" onclick=\"applyPreset('lasercut',this)\">\u26a1 Laser Cut<\/button>\n  <button class=\"preset-btn\" onclick=\"applyPreset('tattoo',this)\">\ud83d\udd8b Tattoo Flash<\/button>\n  <button class=\"preset-btn\" onclick=\"applyPreset('coloring',this)\">\ud83d\udd8c Coloring Book<\/button>\n  <button class=\"preset-btn\" onclick=\"applyPreset('clean',this)\">\u2728 Ultra Clean<\/button>\n<\/div>\n\n<!-- MAIN -->\n<div class=\"main\" id=\"mainArea\" style=\"display:none\">\n\n  <!-- CONTROLS -->\n  <div class=\"controls-panel\">\n\n    <div>\n      <div class=\"section-title\">\u2699 Processing<\/div>\n      <div style=\"display:flex;flex-direction:column;gap:8px;margin-top:8px\">\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Threshold<\/span>\n            <span class=\"ctrl-val\" id=\"vThreshold\">128<\/span>\n          <\/div>\n          <input type=\"range\" id=\"threshold\" min=\"30\" max=\"240\" value=\"128\" oninput=\"sliderUpdate('threshold','vThreshold');scheduleProcess()\">\n        <\/div>\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Edge Strength<\/span>\n            <span class=\"ctrl-val\" id=\"vEdge\">70<\/span>\n          <\/div>\n          <input type=\"range\" id=\"edgeStrength\" min=\"0\" max=\"150\" value=\"70\" oninput=\"sliderUpdate('edgeStrength','vEdge');scheduleProcess()\">\n        <\/div>\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Gaussian Blur<\/span>\n            <span class=\"ctrl-val\" id=\"vBlur\">1.0<\/span>\n          <\/div>\n          <input type=\"range\" id=\"blurRadius\" min=\"0\" max=\"30\" value=\"5\" step=\"1\" oninput=\"sliderUpdate('blurRadius','vBlur',0.2);scheduleProcess()\">\n        <\/div>\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Dilate \/ Thicken<\/span>\n            <span class=\"ctrl-val\" id=\"vDilate\">1<\/span>\n          <\/div>\n          <input type=\"range\" id=\"dilate\" min=\"0\" max=\"5\" value=\"1\" step=\"1\" oninput=\"sliderUpdate('dilate','vDilate');scheduleProcess()\">\n        <\/div>\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Noise Removal<\/span>\n            <span class=\"ctrl-val\" id=\"vNoise\">2<\/span>\n          <\/div>\n          <input type=\"range\" id=\"noiseRemove\" min=\"0\" max=\"8\" value=\"2\" step=\"1\" oninput=\"sliderUpdate('noiseRemove','vNoise');scheduleProcess()\">\n        <\/div>\n\n        <div class=\"ctrl\">\n          <div class=\"ctrl-header\">\n            <span class=\"ctrl-label\">Contrast Boost<\/span>\n            <span class=\"ctrl-val\" id=\"vContrast\">1.4<\/span>\n          <\/div>\n          <input type=\"range\" id=\"contrast\" min=\"10\" max=\"40\" value=\"14\" oninput=\"sliderUpdate('contrast','vContrast',0.1);scheduleProcess()\">\n        <\/div>\n\n      <\/div>\n    <\/div>\n\n    <div>\n      <div class=\"section-title\">\ud83c\udf9b Mode<\/div>\n      <div style=\"display:flex;flex-direction:column;gap:6px;margin-top:8px\">\n        <div class=\"toggle-row\">\n          <span>Skin Tone Remove<\/span>\n          <label class=\"toggle\"><input type=\"checkbox\" id=\"skinRemove\" checked onchange=\"scheduleProcess()\"><span class=\"toggle-slider\"><\/span><\/label>\n        <\/div>\n        <div class=\"toggle-row\">\n          <span>Adaptive Threshold<\/span>\n          <label class=\"toggle\"><input type=\"checkbox\" id=\"adaptive\" onchange=\"scheduleProcess()\"><span class=\"toggle-slider\"><\/span><\/label>\n        <\/div>\n        <div class=\"toggle-row\">\n          <span>Invert (White BG)<\/span>\n          <label class=\"toggle\"><input type=\"checkbox\" id=\"invert\" onchange=\"scheduleProcess()\"><span class=\"toggle-slider\"><\/span><\/label>\n        <\/div>\n        <div class=\"toggle-row\">\n          <span>Anti-alias Edges<\/span>\n          <label class=\"toggle\"><input type=\"checkbox\" id=\"antialias\" checked onchange=\"scheduleProcess()\"><span class=\"toggle-slider\"><\/span><\/label>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div>\n      <div class=\"section-title\">\ud83d\udcca Histogram<\/div>\n      <canvas id=\"histCanvas\" style=\"margin-top:6px\"><\/canvas>\n    <\/div>\n\n    <div class=\"action-btns\">\n      <button class=\"btn btn-gold\" onclick=\"processNow()\">\ud83d\udd04 Process Now<\/button>\n      <button class=\"btn btn-dl\" onclick=\"downloadPNG()\">\u2b07 Download PNG<\/button>\n      <button class=\"btn btn-dl2\" onclick=\"downloadSVG()\">\u2b07 Export SVG<\/button>\n      <button class=\"btn btn-outline\" onclick=\"resetToDefault()\">\u21a9 Reset<\/button>\n    <\/div>\n\n  <\/div>\n\n  <!-- CANVAS AREA -->\n  <div class=\"canvas-area\">\n\n    <!-- View mode tabs -->\n    <div style=\"display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:6px\">\n      <div class=\"view-tabs\">\n        <button class=\"vtab active\" onclick=\"setView('result',this)\">Result<\/button>\n        <button class=\"vtab\" onclick=\"setView('compare',this)\">Compare<\/button>\n        <button class=\"vtab\" onclick=\"setView('original',this)\">Original<\/button>\n      <\/div>\n      <div class=\"canvas-info\" id=\"imgInfo\">\u2014<\/div>\n    <\/div>\n\n    <!-- Result view -->\n    <div class=\"canvas-wrapper\" id=\"viewResult\">\n      <div class=\"canvas-container\">\n        <div class=\"placeholder\" id=\"placeholder\">\n          <div class=\"placeholder-icon\">\ud83c\udf3f<\/div>\n          <span>Photo upload karein to start<\/span>\n        <\/div>\n        <canvas id=\"resultCanvas\" style=\"display:none\"><\/canvas>\n      <\/div>\n    <\/div>\n\n    <!-- Compare view -->\n    <div class=\"canvas-wrapper hidden\" id=\"viewCompare\">\n      <div class=\"compare-wrap\" id=\"compareWrap\">\n        <canvas id=\"compareCanvas\"><\/canvas>\n        <div class=\"compare-divider\" id=\"compareDivider\"><\/div>\n        <div class=\"compare-label-l\">Original<\/div>\n        <div class=\"compare-label-r\">Stencil<\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Original view -->\n    <div class=\"canvas-wrapper hidden\" id=\"viewOriginal\">\n      <div class=\"canvas-container\">\n        <canvas id=\"origCanvas\"><\/canvas>\n      <\/div>\n    <\/div>\n\n    <!-- Status -->\n    <div class=\"status-bar\">\n      <div class=\"status-dot dot-idle\" id=\"statusDot\"><\/div>\n      <span id=\"statusText\">Tayyar hai \u2014 photo upload karein<\/span>\n    <\/div>\n\n  <\/div>\n<\/div>\n\n<!-- Hidden processing canvases -->\n<canvas id=\"procCanvas\" style=\"display:none\"><\/canvas>\n<canvas id=\"origHidden\" style=\"display:none\"><\/canvas>\n\n<script>\n\/\/ ===================== STATE =====================\nlet origImg = null;\nlet processTimer = null;\nlet viewMode = 'result';\nlet compareX = 0.5;\nlet compareDragging = false;\n\n\/\/ ===================== UPLOAD =====================\nconst uploadArea = document.getElementById('uploadArea');\nuploadArea.addEventListener('dragover', e => { e.preventDefault(); uploadArea.classList.add('drag'); });\nuploadArea.addEventListener('dragleave', () => uploadArea.classList.remove('drag'));\nuploadArea.addEventListener('drop', e => {\n  e.preventDefault(); uploadArea.classList.remove('drag');\n  const f = e.dataTransfer.files[0];\n  if (f && f.type.startsWith('image\/')) loadImage(f);\n});\ndocument.getElementById('fileInput').addEventListener('change', e => {\n  if (e.target.files[0]) loadImage(e.target.files[0]);\n});\n\nfunction loadImage(file) {\n  const reader = new FileReader();\n  reader.onload = ev => {\n    const img = new Image();\n    img.onload = () => {\n      origImg = img;\n      \/\/ Draw to hidden origCanvas\n      const oc = document.getElementById('origHidden');\n      oc.width = img.width; oc.height = img.height;\n      oc.getContext('2d').drawImage(img, 0, 0);\n      \/\/ Draw to visible origCanvas\n      const vis = document.getElementById('origCanvas');\n      vis.width = img.width; vis.height = img.height;\n      vis.getContext('2d').drawImage(img, 0, 0);\n      \/\/ Show UI\n      document.getElementById('mainArea').style.display = 'flex';\n      document.getElementById('presetsRow').style.display = 'flex';\n      document.getElementById('placeholder').style.display = 'none';\n      document.getElementById('resultCanvas').style.display = 'block';\n      document.getElementById('imgInfo').textContent = `${img.width}\u00d7${img.height}px`;\n      processNow();\n    };\n    img.src = ev.target.result;\n  };\n  reader.readAsDataURL(file);\n}\n\n\/\/ ===================== SLIDER HELPER =====================\nfunction sliderUpdate(id, valId, factor=1) {\n  const v = parseFloat(document.getElementById(id).value) * factor;\n  document.getElementById(valId).textContent = Number.isInteger(factor) || factor===1 ? Math.round(v) : v.toFixed(1);\n}\n\nfunction scheduleProcess() {\n  clearTimeout(processTimer);\n  processTimer = setTimeout(processNow, 180);\n}\n\n\/\/ ===================== GAUSSIAN BLUR =====================\nfunction gaussianKernel(radius) {\n  const sigma = Math.max(radius \/ 3, 0.5);\n  const size = Math.ceil(radius) * 2 + 1;\n  const kernel = new Float32Array(size * size);\n  let sum = 0;\n  const half = Math.floor(size \/ 2);\n  for (let y = 0; y < size; y++) {\n    for (let x = 0; x < size; x++) {\n      const dx = x - half, dy = y - half;\n      const val = Math.exp(-(dx*dx + dy*dy) \/ (2*sigma*sigma));\n      kernel[y*size+x] = val;\n      sum += val;\n    }\n  }\n  for (let i = 0; i < kernel.length; i++) kernel[i] \/= sum;\n  return { kernel, size, half };\n}\n\nfunction applyGaussianBlur(gray, w, h, radius) {\n  if (radius < 0.5) return gray;\n  const { kernel, size, half } = gaussianKernel(radius);\n  const out = new Float32Array(w * h);\n  for (let y = 0; y < h; y++) {\n    for (let x = 0; x < w; x++) {\n      let sum = 0;\n      for (let ky = 0; ky < size; ky++) {\n        for (let kx = 0; kx < size; kx++) {\n          const sy = Math.min(h-1, Math.max(0, y + ky - half));\n          const sx = Math.min(w-1, Math.max(0, x + kx - half));\n          sum += gray[sy*w+sx] * kernel[ky*size+kx];\n        }\n      }\n      out[y*w+x] = sum;\n    }\n  }\n  return out;\n}\n\n\/\/ ===================== SOBEL EDGE =====================\nfunction sobelEdge(gray, w, h) {\n  const edge = new Float32Array(w * h);\n  for (let y = 1; y < h-1; y++) {\n    for (let x = 1; x < w-1; x++) {\n      const gx =\n        -gray[(y-1)*w+(x-1)] - 2*gray[y*w+(x-1)] - gray[(y+1)*w+(x-1)]\n        +gray[(y-1)*w+(x+1)] + 2*gray[y*w+(x+1)] + gray[(y+1)*w+(x+1)];\n      const gy =\n        -gray[(y-1)*w+(x-1)] - 2*gray[(y-1)*w+x] - gray[(y-1)*w+(x+1)]\n        +gray[(y+1)*w+(x-1)] + 2*gray[(y+1)*w+x] + gray[(y+1)*w+(x+1)];\n      edge[y*w+x] = Math.sqrt(gx*gx + gy*gy);\n    }\n  }\n  return edge;\n}\n\n\/\/ ===================== ADAPTIVE THRESHOLD =====================\nfunction adaptiveThreshold(gray, w, h, blockSize=15, C=10) {\n  const half = Math.floor(blockSize \/ 2);\n  const out = new Uint8Array(w * h);\n  for (let y = 0; y < h; y++) {\n    for (let x = 0; x < w; x++) {\n      let sum = 0, count = 0;\n      for (let dy = -half; dy <= half; dy++) {\n        for (let dx = -half; dx <= half; dx++) {\n          const sy = y+dy, sx = x+dx;\n          if (sy>=0&&sy<h&#038;&#038;sx>=0&&sx<w) { sum+=gray[sy*w+sx]; count++; }\n        }\n      }\n      out[y*w+x] = gray[y*w+x] < (sum\/count - C) ? 0 : 255;\n    }\n  }\n  return out;\n}\n\n\/\/ ===================== MORPHOLOGICAL =====================\nfunction erode(bin, w, h, r=1) {\n  const out = new Uint8Array(w*h).fill(255);\n  for (let y=r;y<h-r;y++) for (let x=r;x<w-r;x++) {\n    let ok=true;\n    outer: for (let dy=-r;dy<=r;dy++) for (let dx=-r;dx<=r;dx++) {\n      if (bin[(y+dy)*w+(x+dx)]===0){out[y*w+x]=0;ok=false;break outer;}\n    }\n  }\n  return out;\n}\n\nfunction dilate(bin, w, h, r=1) {\n  const out = new Uint8Array(w*h).fill(255);\n  for (let y=r;y<h-r;y++) for (let x=r;x<w-r;x++) {\n    for (let dy=-r;dy<=r;dy++) for (let dx=-r;dx<=r;dx++) {\n      if (bin[(y+dy)*w+(x+dx)]===0){out[y*w+x]=0;break;}\n    }\n  }\n  return out;\n}\n\n\/\/ ===================== SKIN DETECTION =====================\nfunction isSkin(r, g, b) {\n  \/\/ HSV-based skin detection\n  const max = Math.max(r,g,b), min = Math.min(r,g,b);\n  const delta = max - min;\n  let h = 0;\n  if (delta > 0) {\n    if (max===r) h = 60*((g-b)\/delta % 6);\n    else if (max===g) h = 60*((b-r)\/delta+2);\n    else h = 60*((r-g)\/delta+4);\n    if (h<0) h+=360;\n  }\n  const s = max===0 ? 0 : delta\/max;\n  const v = max\/255;\n  \/\/ Skin: warm hue, medium saturation, not too dark\/bright\n  return (h>=0&&h<=40) &#038;&#038; (s>=0.1&&s<=0.85) &#038;&#038; (v>=0.3&&v<=0.97);\n}\n\n\/\/ ===================== MAIN PROCESS =====================\nfunction processNow() {\n  if (!origImg) return;\n  setStatus('processing', '\u23f3 Processing...');\n\n  setTimeout(() => {\n    try {\n      const threshold = parseInt(document.getElementById('threshold').value);\n      const edgeStr = parseInt(document.getElementById('edgeStrength').value);\n      const blurR = parseInt(document.getElementById('blurRadius').value) * 0.2;\n      const dilateR = parseInt(document.getElementById('dilate').value);\n      const noiseR = parseInt(document.getElementById('noiseRemove').value);\n      const contrastMul = parseInt(document.getElementById('contrast').value) * 0.1;\n      const skinRm = document.getElementById('skinRemove').checked;\n      const adaptiveMode = document.getElementById('adaptive').checked;\n      const invertMode = document.getElementById('invert').checked;\n      const antialiasMode = document.getElementById('antialias').checked;\n\n      const w = origImg.width, h = origImg.height;\n      const pc = document.getElementById('procCanvas');\n      pc.width = w; pc.height = h;\n      const ctx = pc.getContext('2d');\n      ctx.drawImage(origImg, 0, 0);\n      const imgData = ctx.getImageData(0, 0, w, h);\n      const d = imgData.data;\n\n      \/\/ 1. Extract grayscale + skin mask\n      const gray = new Float32Array(w * h);\n      const skinMask = new Uint8Array(w * h);\n      const histData = new Int32Array(256);\n\n      for (let i = 0; i < w*h; i++) {\n        const r=d[i*4], g=d[i*4+1], b=d[i*4+2];\n        \/\/ Contrast boost\n        const rc = Math.min(255,((r\/255-0.5)*contrastMul+0.5)*255);\n        const gc = Math.min(255,((g\/255-0.5)*contrastMul+0.5)*255);\n        const bc = Math.min(255,((b\/255-0.5)*contrastMul+0.5)*255);\n        gray[i] = 0.299*rc + 0.587*gc + 0.114*bc;\n        skinMask[i] = (skinRm &#038;&#038; isSkin(r,g,b)) ? 1 : 0;\n        histData[Math.round(gray[i])]++;\n      }\n\n      \/\/ 2. Gaussian blur\n      const blurred = applyGaussianBlur(gray, w, h, blurR);\n\n      \/\/ 3. Edge detection (Sobel)\n      const edges = sobelEdge(blurred, w, h);\n\n      \/\/ Normalize edges\n      let maxEdge = 0;\n      for (let i=0; i<edges.length; i++) if(edges[i]>maxEdge) maxEdge=edges[i];\n      if (maxEdge > 0) for (let i=0; i<edges.length; i++) edges[i] = edges[i]\/maxEdge*255;\n\n      \/\/ 4. Build binary map\n      let binary = new Uint8Array(w * h);\n\n      if (adaptiveMode) {\n        const adaptBin = adaptiveThreshold(blurred, w, h, 25, 8);\n        for (let i=0; i<w*h; i++) {\n          const edgeBonus = edges[i] * (edgeStr\/100);\n          binary[i] = (adaptBin[i]===0 || edgeBonus > 80) ? 0 : 255;\n        }\n      } else {\n        for (let i=0; i<w*h; i++) {\n          const edgeVal = edges[i] * (edgeStr\/80);\n          const darkVal = blurred[i] < threshold ? (threshold - blurred[i]) * 0.7 : 0;\n          const combined = Math.min(255, edgeVal + darkVal);\n          binary[i] = combined > threshold * 0.25 ? 0 : 255;\n        }\n      }\n\n      \/\/ 5. Apply skin mask (make skin white = background)\n      if (skinRm) {\n        const skinBlurred = applyGaussianBlur(Float32Array.from(skinMask.map(v=>v*255)), w, h, 2);\n        for (let i=0; i<w*h; i++) {\n          if (skinBlurred[i] > 80) binary[i] = 255;\n        }\n      }\n\n      \/\/ 6. Noise removal (erode then dilate = opening)\n      if (noiseR > 0) {\n        binary = dilate(erode(binary, w, h, noiseR), w, h, noiseR);\n      }\n\n      \/\/ 7. Dilate\/thicken lines\n      if (dilateR > 0) {\n        binary = dilate(binary, w, h, dilateR);\n      }\n\n      \/\/ 8. Invert if needed\n      if (invertMode) { for (let i=0; i<binary.length; i++) binary[i] = 255-binary[i]; }\n\n      \/\/ 9. Write to output with optional antialiasing\n      const outData = ctx.createImageData(w, h);\n      const od = outData.data;\n\n      if (antialiasMode) {\n        \/\/ Soft edges via distance-based AA\n        const dist = computeDistanceField(binary, w, h);\n        for (let i=0; i<w*h; i++) {\n          const d_ = dist[i];\n          let val;\n          if (binary[i]===0) {\n            val = d_<2 ? Math.round(d_\/2*80) : 0;\n          } else {\n            val = d_<2 ? Math.round(255-d_\/2*80) : 255;\n          }\n          od[i*4]=val; od[i*4+1]=val; od[i*4+2]=val; od[i*4+3]=255;\n        }\n      } else {\n        for (let i=0; i<w*h; i++) {\n          const v=binary[i];\n          od[i*4]=v; od[i*4+1]=v; od[i*4+2]=v; od[i*4+3]=255;\n        }\n      }\n\n      \/\/ Draw result\n      const rc2 = document.getElementById('resultCanvas');\n      rc2.width = w; rc2.height = h;\n      rc2.getContext('2d').putImageData(outData, 0, 0);\n\n      \/\/ Draw histogram\n      drawHistogram(histData);\n\n      \/\/ Update compare canvas\n      updateCompare();\n\n      setStatus('done', `\u2705 Done! ${w}\u00d7${h}px \u2014 Download karein`);\n    } catch(e) {\n      setStatus('error', '\u274c Error: ' + e.message);\n      console.error(e);\n    }\n  }, 30);\n}\n\n\/\/ Simple approximate distance field (1-pass approximate)\nfunction computeDistanceField(bin, w, h) {\n  const dist = new Float32Array(w*h).fill(999);\n  for (let y=0;y<h;y++) for (let x=0;x<w;x++) {\n    const i=y*w+x;\n    if (bin[i]===0) {\n      \/\/ Check 4-neighbors for boundary\n      const isEdge = (x>0&&bin[i-1]===255)||(x<w-1&#038;&#038;bin[i+1]===255)||\n                     (y>0&&bin[i-w]===255)||(y<h-1&#038;&#038;bin[i+w]===255);\n      if (isEdge) dist[i]=0; else dist[i]=2;\n    } else {\n      const isEdge = (x>0&&bin[i-1]===0)||(x<w-1&#038;&#038;bin[i+1]===0)||\n                     (y>0&&bin[i-w]===0)||(y<h-1&#038;&#038;bin[i+w]===0);\n      if (isEdge) dist[i]=0; else dist[i]=2;\n    }\n  }\n  return dist;\n}\n\n\/\/ ===================== HISTOGRAM =====================\nfunction drawHistogram(data) {\n  const hc = document.getElementById('histCanvas');\n  hc.width = 256; hc.height = 50;\n  const ctx = hc.getContext('2d');\n  let max = 0;\n  for (let i=0;i<256;i++) if(data[i]>max) max=data[i];\n  ctx.fillStyle = '#1e1e35';\n  ctx.fillRect(0,0,256,50);\n  for (let i=0;i<256;i++) {\n    const h = Math.round(data[i]\/max*48);\n    const t = i\/255;\n    ctx.fillStyle = `rgba(${Math.round(200*t+50*(1-t))},${Math.round(160*t+100*(1-t))},${Math.round(80*t+200*(1-t))},0.85)`;\n    ctx.fillRect(i, 50-h, 1, h);\n  }\n}\n\n\/\/ ===================== COMPARE VIEW =====================\nfunction updateCompare() {\n  const orig = document.getElementById('origHidden');\n  const result = document.getElementById('resultCanvas');\n  if (!orig.width || !result.width) return;\n  const cc = document.getElementById('compareCanvas');\n  cc.width = orig.width; cc.height = orig.height;\n  const ctx = cc.getContext('2d');\n  const splitX = Math.round(orig.width * compareX);\n  \/\/ Left: original\n  ctx.drawImage(orig, 0, 0);\n  \/\/ Right: result (clip)\n  ctx.save();\n  ctx.beginPath(); ctx.rect(splitX, 0, orig.width-splitX, orig.height);\n  ctx.clip();\n  ctx.drawImage(result, 0, 0);\n  ctx.restore();\n  \/\/ Divider\n  const div = document.getElementById('compareDivider');\n  div.style.left = (compareX*100)+'%';\n}\n\n\/\/ Compare drag\nconst compareWrap = document.getElementById('compareWrap');\ncompareWrap.addEventListener('mousedown', e => { compareDragging=true; updateComparePos(e); });\ncompareWrap.addEventListener('mousemove', e => { if(compareDragging) updateComparePos(e); });\ncompareWrap.addEventListener('mouseup', () => compareDragging=false);\ncompareWrap.addEventListener('touchstart', e => { compareDragging=true; updateComparePos(e.touches[0]); });\ncompareWrap.addEventListener('touchmove', e => { e.preventDefault(); updateComparePos(e.touches[0]); });\ncompareWrap.addEventListener('touchend', () => compareDragging=false);\n\nfunction updateComparePos(e) {\n  const rect = compareWrap.getBoundingClientRect();\n  compareX = Math.max(0.02, Math.min(0.98, (e.clientX - rect.left) \/ rect.width));\n  updateCompare();\n}\n\n\/\/ ===================== VIEW TABS =====================\nfunction setView(v, btn) {\n  viewMode = v;\n  document.querySelectorAll('.vtab').forEach(t=>t.classList.remove('active'));\n  btn.classList.add('active');\n  document.getElementById('viewResult').classList.toggle('hidden', v!=='result');\n  document.getElementById('viewCompare').classList.toggle('hidden', v!=='compare');\n  document.getElementById('viewOriginal').classList.toggle('hidden', v!=='original');\n  if (v==='compare') updateCompare();\n}\n\n\/\/ ===================== STATUS =====================\nfunction setStatus(type, msg) {\n  const dot = document.getElementById('statusDot');\n  dot.className = 'status-dot';\n  if (type==='processing') dot.classList.add('dot-processing');\n  else if (type==='done') dot.classList.add('dot-done');\n  else if (type==='error') dot.classList.add('dot-error');\n  else dot.classList.add('dot-idle');\n  document.getElementById('statusText').textContent = msg;\n}\n\n\/\/ ===================== PRESETS =====================\nconst presets = {\n  stencil:   { threshold:120, edgeStrength:70,  blurRadius:5,  dilate:1, noiseRemove:2, contrast:14, skinRemove:true,  adaptive:false, invert:false, antialias:true },\n  lasercut:  { threshold:100, edgeStrength:110, blurRadius:3,  dilate:2, noiseRemove:3, contrast:18, skinRemove:true,  adaptive:false, invert:false, antialias:false },\n  tattoo:    { threshold:140, edgeStrength:60,  blurRadius:8,  dilate:1, noiseRemove:4, contrast:16, skinRemove:true,  adaptive:true,  invert:false, antialias:true },\n  coloring:  { threshold:160, edgeStrength:50,  blurRadius:10, dilate:0, noiseRemove:5, contrast:12, skinRemove:true,  adaptive:true,  invert:true,  antialias:true },\n  clean:     { threshold:110, edgeStrength:90,  blurRadius:4,  dilate:1, noiseRemove:6, contrast:20, skinRemove:true,  adaptive:false, invert:false, antialias:true },\n};\n\nfunction applyPreset(name, btn) {\n  const p = presets[name];\n  if (!p) return;\n  document.querySelectorAll('.preset-btn').forEach(b=>b.classList.remove('active'));\n  btn.classList.add('active');\n  document.getElementById('threshold').value = p.threshold;\n  document.getElementById('edgeStrength').value = p.edgeStrength;\n  document.getElementById('blurRadius').value = p.blurRadius;\n  document.getElementById('dilate').value = p.dilate;\n  document.getElementById('noiseRemove').value = p.noiseRemove;\n  document.getElementById('contrast').value = p.contrast;\n  document.getElementById('skinRemove').checked = p.skinRemove;\n  document.getElementById('adaptive').checked = p.adaptive;\n  document.getElementById('invert').checked = p.invert;\n  document.getElementById('antialias').checked = p.antialias;\n  \/\/ Update displayed values\n  sliderUpdate('threshold','vThreshold');\n  sliderUpdate('edgeStrength','vEdge');\n  sliderUpdate('blurRadius','vBlur',0.2);\n  sliderUpdate('dilate','vDilate');\n  sliderUpdate('noiseRemove','vNoise');\n  sliderUpdate('contrast','vContrast',0.1);\n  processNow();\n}\n\nfunction resetToDefault() { applyPreset('stencil', document.querySelector('.preset-btn')); }\n\n\/\/ ===================== DOWNLOAD =====================\nfunction downloadPNG() {\n  const c = document.getElementById('resultCanvas');\n  if (!c.width) { alert('Pehle process karein!'); return; }\n  const a = document.createElement('a');\n  a.download = 'mehndi_stencil_pro.png';\n  a.href = c.toDataURL('image\/png');\n  a.click();\n}\n\nfunction downloadSVG() {\n  const c = document.getElementById('resultCanvas');\n  if (!c.width) { alert('Pehle process karein!'); return; }\n  setStatus('processing', '\u23f3 SVG generate ho raha hai...');\n  setTimeout(() => {\n    try {\n      const w = c.width, h = c.height;\n      const ctx = c.getContext('2d');\n      const id = ctx.getImageData(0, 0, w, h);\n      const d = id.data;\n      \/\/ Simple run-length encoding to SVG rects\n      let paths = '';\n      for (let y=0;y<h;y++) {\n        let runStart=-1;\n        for (let x=0;x<=w;x++) {\n          const isDark = x<w &#038;&#038; d[(y*w+x)*4]<128;\n          if (isDark &#038;&#038; runStart===-1) runStart=x;\n          else if (!isDark &#038;&#038; runStart!==-1) {\n            paths += `<rect x=\"${runStart}\" y=\"${y}\" width=\"${x-runStart}\" height=\"1\"\/>`;\n            runStart=-1;\n          }\n        }\n      }\n      const svg = `<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"${w}\" height=\"${h}\" viewBox=\"0 0 ${w} ${h}\"><rect width=\"${w}\" height=\"${h}\" fill=\"white\"\/><g fill=\"black\">${paths}<\/g><\/svg>`;\n      const blob = new Blob([svg], {type:'image\/svg+xml'});\n      const url = URL.createObjectURL(blob);\n      const a = document.createElement('a');\n      a.download = 'mehndi_stencil.svg';\n      a.href = url;\n      a.click();\n      setTimeout(()=>URL.revokeObjectURL(url), 1000);\n      setStatus('done','\u2705 SVG download ho gaya!');\n    } catch(e) { setStatus('error','SVG error: '+e.message); }\n  }, 50);\n}\n\n\/\/ Init slider labels\nsliderUpdate('threshold','vThreshold');\nsliderUpdate('edgeStrength','vEdge');\nsliderUpdate('blurRadius','vBlur',0.2);\nsliderUpdate('dilate','vDilate');\nsliderUpdate('noiseRemove','vNoise');\nsliderUpdate('contrast','vContrast',0.1);\n<\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>Mehndi Stencil Pro \ud83c\udf3f Mehndi Stencil Pro Professional mehndi design extractor \u2014 best quality output \ud83d\udcf7 Mehndi Photo Upload Karein Click karein ya drag &#038; drop \u2014 JPG \/ PNG supported High resolution photo = better result \ud83c\udfa8 Stencil \u26a1 Laser Cut \ud83d\udd8b Tattoo Flash \ud83d\udd8c Coloring Book \u2728 Ultra Clean \u2699 Processing Threshold 128 &#8230; <a title=\"\" class=\"read-more\" href=\"https:\/\/toolskit.site\/index.php\/213-2\/\" aria-label=\"Read more about \">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-213","page","type-page","status-publish"],"_links":{"self":[{"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/pages\/213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/comments?post=213"}],"version-history":[{"count":1,"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/pages\/213\/revisions"}],"predecessor-version":[{"id":214,"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/pages\/213\/revisions\/214"}],"wp:attachment":[{"href":"https:\/\/toolskit.site\/index.php\/wp-json\/wp\/v2\/media?parent=213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}