Skip to content

Fix: Ensure non-premultiplied alpha for textures#245

Open
AntonPieper wants to merge 2 commits intomarkusfisch:masterfrom
AntonPieper:non-premultiplied
Open

Fix: Ensure non-premultiplied alpha for textures#245
AntonPieper wants to merge 2 commits intomarkusfisch:masterfrom
AntonPieper:non-premultiplied

Conversation

@AntonPieper
Copy link
Contributor

This pull request resolves a long-standing issue where textures with transparency were incorrectly converted to premultiplied alpha during various bitmap operations. This would cause visual artifacts like dark fringes around transparent edges, as the alpha channel was effectively being applied twice.

A big thank you to @SpartanJoe193 for reporting and providing detailed examples in both issues!

Closes #238, Closes #242.

The Problem

As discussed in the issues, the root cause was more complex than simply setting inPremultiplied = false during the initial texture load. While that was the first step, the core issue was that any subsequent bitmap manipulation—like cropping or rotating—using standard Android methods (Canvas, Matrix) would implicitly re-premultiply the alpha channel, undoing the initial load setting and corrupting the color data in transparent areas.

The Solution

To fix this, all standard bitmap operations within the texture processing pipeline have been replaced with manual, pixel-level transformations. These new methods correctly handle and preserve the non-premultiplied (straight alpha) state of the texture data through all steps:

  • Loading: Textures are now explicitly loaded with inPremultiplied = false.
  • Cropping & Rotation: Custom pixel-by-pixel logic now performs these operations, avoiding the Canvas and its automatic premultiplication.
  • Scaling: A manual bilinear interpolation implementation is used for resizing, ensuring color integrity is maintained.

Note

The new methods are implemented in software and may be slower than the previous hardware-accelerated Canvas operations. This is a necessary trade-off for correctness. The performance of these new methods can be a target for future optimization.


How to Verify the Fix

You can easily verify the fix using the test texture and shader below.

1. Test Image

Save and import the following test image. It contains three vertical bars and has an alpha gradient.

straight_alpha_test

2. Test Shader

Use this shader. It displays the texture. The left half shows the correct blending for straight alpha, while the right half simulates the old, incorrect behavior.

Click to expand the example shader
#version 300 es

precision mediump float;

uniform sampler2D sampleTex;
uniform vec2 resolution;
uniform vec2 touch;

out vec4 fragColor;

void main() {
	fragColor = vec4(1.0);

	vec2 uv = gl_FragCoord.xy/ resolution;
	vec4 texColor = texture(sampleTex, uv);

	// 3. Determine the final color based on screen position
	float handle = touch.x;

	if (gl_FragCoord.x < handle) {
		// --- LEFT SIDE: CORRECT rendering for straight alpha ---
		fragColor.rgb = texColor.rgb;
	} else {
		// --- RIGHT SIDE: SIMULATE incorrect handling ---
		fragColor.rgb = texColor.rgb * texColor.a;
	}

	// 5. Draw a white dividing line for clarity
	if (abs(gl_FragCoord.x - handle) < 1.0) {
		fragColor = vec4(1.0); // White
	}
}

3. Steps

  1. Add the test shader to the editor.
  2. Import the test image from above as sampleTex.
  3. Run the shader and use touch input to move the dividing line.

Expected Result

The left side of the preview will show the complete, solid color data. The right side will simulate the old, incorrect behavior which gets darker as the alpha drops.

Perform rotation manually on pixel data before cropping to avoid creating premultiplied intermediate bitmaps that could crash when handling rotated textures.

Also ensure temporary rotated bitmaps are tracked and recycled, validate crop bounds, log errors with the correct tag, and create the final bitmap with the original config as non-premultiplied before setting pixels to preserve correct pixel format and avoid premultiplication issues.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Premultiplied Alpha is still unresolved Fix premultiplied alpha

1 participant