Skip to content

Semi-transparent pixels lose precision due to premultiplied alpha in canvas #4

Description

@ben4d85

This is a great tool that has made my tileset creation workflow a lot simpler and much more convenient!

However, I noticed a small bug related to loss of precision in the alpha channel.

When passing a tileset that contains semi-transparent pixels through the tool, the output pixel values are slightly off from the input — typically by 1 per channel.

Example:

  • Input pixel: rgba(82, 142, 53, 166)
  • Output pixel: rgba(81, 141, 54, 166)

Suspected cause:

This appears to be a consequence of the browser's HTML Canvas API storing pixels internally in premultiplied alpha format. When drawImage() is called with a source containing semi-transparent pixels, the browser converts straight alpha → premultiplied → straight alpha across the round-trip, and integer rounding at each step causes the small drift.

Suggested fix:

Rather than relying on drawImage() for pixel copying, the tile rearrangement could be done by reading raw pixel data (e.g. via getImageData() or by decoding the PNG bytes directly) and writing it back via putImageData(), which accepts straight RGBA and bypasses the lossy premultiplied conversion. The tool already manipulates raw PNG bytes for the color correction metadata stripping, so a similar approach may be feasible for pixel data too.

This would ensure pixel-perfect output for tilesets that use semi-transparency, such as shadow layers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions