403Webshell
Server IP : 217.154.3.148  /  Your IP : 216.73.216.90
Web Server : Apache
System : Linux blissful-wright.217-154-3-148.plesk.page 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : gracious-boyd_hfhh1h8vo9n ( 10000)
PHP Version : 8.3.31
Disable Function : opcache_get_status
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/components/MaskPost.ts
/**
 * Postprocessing für Occluder-Maske:
 *  - optional vorab weichzeichnen (anti-alias)
 *  - binär-thresholden
 *  - N Schritte 8-Nachbarschaft-DILATION (wächst Maske um ~growPx)
 *  - leichter Abschluss-Blur (weicher Rand)
 * Rückgabe: Data-URL PNG (grau=alpha)
 */
export async function processMask(
  maskDataUrl: string,
  growPx = 6,          // wie stark erweitern (≈ Pixel)
  preBlurPx = 1,       // kleiner Vorab-Blur glättet Löcher
  thresh = 0.45,       // 0..1: ab wann ein Pixel als "Maske=1" gilt
  finalBlurPx = 1      // weiche Kante am Ende
): Promise<string> {
  const img = await loadImg(maskDataUrl)
  const w = (img as any).naturalWidth || img.width
  const h = (img as any).naturalHeight || img.height
  const c = document.createElement('canvas')
  c.width = w; c.height = h
  const ctx = c.getContext('2d', { willReadFrequently: true })!

  // 1) Maske zeichnen (+ kleiner Vorab-Blur)
  if (preBlurPx > 0) (ctx as any).filter = `blur(${preBlurPx}px)`
  ctx.drawImage(img, 0, 0, w, h)
  ;(ctx as any).filter = 'none'

  // 2) ImageData holen und in Float-Alpha (0..1) konvertieren
  let id = ctx.getImageData(0, 0, w, h)
  const total = w * h
  const a = new Float32Array(total)
  let nonZero = 0
  for (let i = 0, j = 3; i < total; i++, j += 4) {
    const raw = id.data[j] / 255
    a[i] = raw
    if (raw > 0) nonZero += 1
  }

  let coverage = nonZero / Math.max(1, total)
  const originalCoverage = coverage
  let gamma = 0.65
  if (coverage < 0.03) gamma = 0.52
  else if (coverage < 0.08) gamma = 0.58
  else if (coverage < 0.18) gamma = 0.64
  else gamma = 0.72

  let inverted = false
  if (coverage > 0.55) {
    let invNonZero = 0
    for (let i = 0; i < total; i++) {
      const inv = 1 - a[i]
      if (inv > 0) invNonZero += 1
    }
    const invCoverage = invNonZero / Math.max(1, total)
    if (invCoverage < coverage * 0.6 && invCoverage + 0.02 < coverage) {
      for (let i = 0; i < total; i++) a[i] = 1 - a[i]
      coverage = invCoverage
      nonZero = invNonZero
      inverted = true
      gamma = coverage < 0.03 ? 0.52 : coverage < 0.08 ? 0.58 : coverage < 0.18 ? 0.64 : 0.72
      console.info('[mask] inverted high-coverage mask', {
        original: Number(originalCoverage.toFixed(3)),
        inverted: Number(coverage.toFixed(3)),
      })
    }
  }

  let boostedSum = 0
  let boostedMax = 0
  if (nonZero > 0) {
    for (let i = 0; i < total; i++) {
      const v = a[i]
      if (v <= 0) {
        a[i] = 0
        continue
      }
      const boosted = Math.pow(v, gamma)
      a[i] = boosted
      boostedSum += boosted
      if (boosted > boostedMax) boostedMax = boosted
    }
  }

  // If the mask is almost completely white, treat it as an inverted foreground mask.
  if (!inverted && coverage > 0.98) {
    nonZero = 0
    for (let i = 0; i < total; i++) {
      const inv = 1 - a[i]
      a[i] = inv
      if (inv > 0) nonZero += 1
    }
    coverage = nonZero / Math.max(1, total)
    gamma = coverage < 0.03 ? 0.52 : coverage < 0.08 ? 0.58 : coverage < 0.18 ? 0.64 : 0.72
    inverted = true
    if (coverage < 0.03) console.info('[mask] inverted near-full mask', { coverage: Number(coverage.toFixed(3)) })
  }

  let effectiveThresh = Math.max(0, Math.min(0.98, thresh))
  if (nonZero >= 64 && boostedMax > 0) {
    const mean = boostedSum / nonZero
    const tail = Math.max(0, boostedMax - mean)
    const minClamp = coverage < 0.03 ? 0.16 : coverage < 0.08 ? 0.2 : coverage < 0.18 ? 0.26 : 0.3
    const autoCandidate = Math.max(minClamp, Math.min(0.98, mean + tail * 0.12))
    const requestedBase = Math.max(minClamp, Math.min(0.98, thresh))
    const coverageClamp = coverage >= 0.7 ? 0.58
      : coverage >= 0.55 ? 0.5
      : coverage >= 0.4 ? 0.38
      : coverage >= 0.28 ? 0.3
      : minClamp
    const requested = Math.max(coverageClamp, requestedBase)

    if (requested <= autoCandidate) {
      effectiveThresh = requested
    } else if (coverage < 0.05) {
      effectiveThresh = requested
    } else {
      const slack = Math.max(0, Math.min(1, (0.25 - coverage) / 0.25))
      const blend = slack * slack
      effectiveThresh = requested * blend + autoCandidate * (1 - blend)
    }

    if (effectiveThresh < minClamp) effectiveThresh = minClamp

    if (Math.abs(effectiveThresh - requestedBase) > 0.015) {
      console.info('[mask] adaptive threshold', {
        requested: Number(thresh.toFixed(3)),
        requestedClamped: Number(requested.toFixed(3)),
        auto: Number(autoCandidate.toFixed(3)),
        used: Number(effectiveThresh.toFixed(3)),
        coverage: Number(coverage.toFixed(3)),
        gamma: Number(gamma.toFixed(2)),
      })
    }
  }

  // Kern (hoch-konfident) -> nutzen wir später zum Bereinigen der Maske.
  const core = new Uint8Array(total)
  let coreCount = 0

  const ensureCore = (cut: number) => {
    cut = Math.max(0, Math.min(0.98, cut))
    for (let i = 0; i < total; i++) {
      if (core[i]) continue
      if (a[i] >= cut) {
        core[i] = 1
        coreCount += 1
      }
    }
  }

  const initialCoreCut = Math.min(0.92, Math.max(0.52, effectiveThresh + 0.2))
  ensureCore(initialCoreCut)
  if (coreCount === 0 && nonZero > 0) ensureCore(Math.max(0.35, effectiveThresh + 0.1))
  if (coreCount === 0 && nonZero > 0) ensureCore(Math.max(0.25, effectiveThresh))
  if (coreCount === 0 && nonZero > 0) {
    let maxBoost = 0
    for (let i = 0; i < total; i++) if (a[i] > maxBoost) maxBoost = a[i]
    if (maxBoost > 0) ensureCore(Math.max(0.2, maxBoost * 0.72))
  }

  // 3) Threshold -> binary
  const bins = new Uint32Array(256)
  for (let i = 0; i < total; i++) {
    const v = Math.max(0, Math.min(1, a[i]))
    bins[Math.min(255, Math.round(v * 255))] += 1
  }

  const targetCoverage = Math.min(0.4, Math.max(coverage * 3, coverage + 0.12))
  const targetPixels = Math.max(1, Math.round(targetCoverage * total))
  let cumulative = 0
  let quantileBin = 255
  for (let b = 255; b >= 0; b--) {
    cumulative += bins[b]
    if (cumulative >= targetPixels) {
      quantileBin = b
      break
    }
  }
  const quantileThresh = quantileBin / 255
  const finalThresh = inverted ? quantileThresh : Math.min(effectiveThresh, quantileThresh)

  const bin = new Uint8Array(total)
  let binActive = 0
  for (let i = 0; i < total; i++) {
    if (a[i] >= finalThresh) {
      bin[i] = 1
      binActive += 1
    }
  }
  const postThreshCoverage = binActive / Math.max(1, total)

  // Entferne Komponenten, die nicht mit einem Kern verbunden sind
  if (coreCount > 0) {
    const queue = new Uint32Array(total)
    const localVisited = new Uint8Array(total)
    const component: number[] = []
    const sharedVisited = new Uint8Array(total)
    const componentCoreCut = Math.max(0.3, Math.min(0.9, effectiveThresh + 0.08))

    const flood = (start: number, visitMap: Uint8Array) => {
      let qh = 0
      let qt = 0
      queue[qt++] = start
      visitMap[start] = 1
      component.length = 0
      let hasCore = !!core[start]

      while (qh < qt) {
        const idx = queue[qh++]!
        component.push(idx)
        if (core[idx] || a[idx] >= componentCoreCut) hasCore = true
        const x = idx % w
        const y = (idx - x) / w

        const tryPush = (nx: number, ny: number) => {
          if (nx < 0 || ny < 0 || nx >= w || ny >= h) return
          const ni = ny * w + nx
          if (visitMap[ni] || !bin[ni]) return
          visitMap[ni] = 1
          queue[qt++] = ni
        }

        tryPush(x - 1, y)
        tryPush(x + 1, y)
        tryPush(x, y - 1)
        tryPush(x, y + 1)
      }

      return hasCore
    }

    for (let i = 0; i < total; i++) {
      if (!bin[i] || sharedVisited[i]) continue
      const hasCore = flood(i, sharedVisited)
      if (!hasCore) {
        component.length = 0
        const hasWeak = flood(i, localVisited)
        if (!hasWeak) {
          for (const idx of component) bin[idx] = 0
        } else {
          for (const idx of component) {
            if (a[idx] < componentCoreCut) bin[idx] = 0
          }
        }
        component.length = 0
      }
    }
  }

  // 4) Dilation-Schritte (8-neighborhood)
  let steps = Math.max(0, Math.round(growPx))
  if (postThreshCoverage < 0.06) {
    steps = Math.max(steps, Math.round(growPx * 1.5) || 2)
  } else if (postThreshCoverage < 0.12) {
    steps = Math.max(steps, Math.round(growPx * 1.2) || 1)
  }
  if (steps > 0) {
    const tmp = new Uint8Array(w * h)
  const growFloor = Math.max(0.1, Math.min(0.35, finalThresh * 0.75))
  const allowAggressive = coverage < 0.03
  for (let s = 0; s < steps; s++) {
    tmp.set(bin)
    for (let y = 0; y < h; y++) {
      const yMin = Math.max(0, y - 1)
      const yMax = Math.min(h - 1, y + 1)
        for (let x = 0; x < w; x++) {
          const idx = y * w + x
          if (bin[idx]) continue
          const xMin = Math.max(0, x - 1)
          const xMax = Math.min(w - 1, x + 1)
          let grow = false
          for (let ny = yMin; ny <= yMax && !grow; ny++) {
            const rowOffset = ny * w
            for (let nx = xMin; nx <= xMax; nx++) {
              if (bin[rowOffset + nx]) {
                grow = true
                break
              }
            }
          }
          if (grow) {
            if (a[idx] >= growFloor || (allowAggressive && s === 0)) {
              tmp[idx] = 1
            }
          }
        }
      }
      bin.set(tmp)
    }
  }

  // 5) Zurück in ImageData (Alpha-Kanal setzen)
  for (let i=0, j=3; i<w*h; i++, j+=4) {
    id.data[j] = bin[i] ? 255 : 0
    // Kanäle R,G,B egal – setzen wir neutral grau (optional)
    id.data[j-1] = id.data[j-2] = id.data[j-3] = 128
  }
  ctx.putImageData(id, 0, 0)

  // 6) Abschluss-Blur für weiche Kante
  if (finalBlurPx > 0) {
    const c2 = document.createElement('canvas')
    c2.width = w; c2.height = h
    const k = c2.getContext('2d')!
    k.drawImage(c, 0, 0)
    k.globalCompositeOperation = 'copy' // Alpha erhalten
    ;(k as any).filter = `blur(${finalBlurPx}px)`
    k.drawImage(c2, 0, 0) // self-blur
    return c2.toDataURL('image/png')
  }
  return c.toDataURL('image/png')
}

async function loadImg(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.crossOrigin = 'anonymous'
    img.onload = () => resolve(img)
    img.onerror = reject
    img.src = src
  })
}

Youez - 2016 - github.com/yon3zu
LinuXploit