Skip to content

TypeError when image has no opaque pixels (fully transparent PNG) #2

Description

@csdog

Description

When an input image has no opaque pixels (all pixels have alpha === 0), clusterPixelsByCondition correctly skips them and returns an empty cluster list. However, autohue() then accesses clusters[0] without checking, which throws:

TypeError: Cannot read properties of undefined (reading 'averageRgb')

This can happen with fully transparent PNGs (common for stickers, logos, or empty canvas exports).

Edge clustering already guards with topClusters.length > 0 ? ... : primaryColor, but the primary/secondary path does not.

Steps to Reproduce

  1. Create a fully transparent PNG (e.g. empty 100×100 canvas → toDataURL('image/png'))
  2. Call autohue(dataUrl)
import autohue from 'autohue.js'

const canvas = document.createElement('canvas')
canvas.width = 100
canvas.height = 100
// do not draw anything => all alpha = 0
const dataUrl = canvas.toDataURL('image/png')

await autohue(dataUrl) // throws

Expected Behavior

Either:

  • Return a documented fallback result (e.g. #000000 or first pixel RGB), or
  • Reject with a clear, catchable error message (not TypeError on internal state)

Actual Behavior

Promise rejects with TypeError at approximately:

const primaryCluster = clusters[0]
const primaryColor = rgbToHex(primaryCluster.averageRgb)

Environment

  • autohue.js (npm latest as of 2026-07)
  • Browser / Chromium (Canvas getImageData)
  • Reproduced via minimal Vite + TypeScript demo

Suggested Fix

clusters.sort((a, b) => b.count - a.count)

if (clusters.length === 0) {
  const fallback = '#000000' // or derive from first pixel regardless of alpha
  return {
    primaryColor: fallback,
    secondaryColor: fallback,
    backgroundColor: {
      top: fallback,
      right: fallback,
      bottom: fallback,
      left: fallback,
    },
  }
}

const primaryCluster = clusters[0]
// ...

Note

clusterPixelsByCondition already skips transparent pixels:

if (data[index + 3] === 0) continue // 忽略透明像素

So this is an edge case for images that are entirely transparent, not a clustering bug.

Related

We hit the same case server-side when porting this logic to Rust; we added an empty-cluster fallback there. Happy to contribute a PR if maintainers agree on the desired fallback semantics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions