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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions