Skip to content

Option to disable premultiply on raster source fetch #13634

@Plantain

Description

@Plantain

Motivation

This is a backport/upstream of functionality we use internally to ship multi-band weather rasters to a custom layer, and I thought it might be useful to others too.

In those cases, premultiplication silently corrupts the red, green, and blue channels before application code can read them. The result is incorrect colors, wrong decoded values, and invalid downstream rendering.

Allowing premultiplication to be disabled would let custom layers get the exact byte values of all channels of image data.

Design Alternatives

  1. Do nothing.
    This keeps current behavior but leaves packed-data raster sources unsupported.

  2. Custom source pipelines.
    This works, but it forces applications to reimplement tile loading, caching, decoding, and texture management just to avoid premultiplication.

  3. Add a new source type for raw raster data.
    This is more explicit, but it adds a lot of API and implementation surface for what is fundamentally one decode/upload behavior switch.

  4. Add a per-layer option.
    This is the wrong level. Premultiplication happens when the raster source is decoded and uploaded, before layers consume it.

  5. Add a per-source raster option.
    This is the smallest API that matches where the problem occurs.

Design

Add a new raster source option:

premultiply: boolean

Default:
true

Behavior:

  • true: preserve current behavior
  • false: decode and upload raster tiles without alpha premultiplication, so RGBA bytes remain unchanged

Advantages:

  • minimal API change
  • backward compatible by default
  • supports packed-data raster workflows without requiring a custom loader

Potential drawbacks:

  • adds one more source option to the style spec

Mock-Up

Developer-facing style:

{
  "sources": {
    "packed-raster": {
      "type": "raster",
      "tiles": ["https://example.com/tiles/{z}/{x}/{y}.webp"],
      "tileSize": 256,
      "premultiply": false
    }
  }
}

Developer-facing effect:

  • when sampling the source, channel values are the original tile bytes
  • A can safely be used as a data channel

End-user effect:

  • raster-derived rendering is correct for packed RGBA data
  • no visible change for ordinary raster imagery, since the default remains true

Concepts

The main concept is “alpha premultiplication”:

  • premultiplied: RGB may be scaled by A
  • non-premultiplied: RGBA channels are preserved as authored

This does not introduce a new rendering model. It only exposes control over an existing decode/upload behavior that is currently implicit.

Implementation

JavaScript:

  • extend raster source spec with premultiply?: boolean
  • default to true
  • when premultiply === false:
    • avoid image-loading paths that force premultiplication
    • use a fetch/ArrayBuffer/ImageBitmap path where possible
    • call createImageBitmap(blob, { premultiplyAlpha: 'none' })
    • upload textures with unpack premultiplication disabled
  • when premultiply !== false, keep the current path unchanged

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions