HMCL-dev/HMCL · error · PngIntegrityException
Illegal to have tRNS chunk with image type
Error message
Illegal to have tRNS chunk with image type
What it means
PngIntegrityException thrown when a tRNS chunk is present for a colour type that must not carry one: greyscale-with-alpha (4), truecolour-with-alpha (6), or any unrecognized colour type. Per the PNG spec, images whose samples already include an alpha channel are fully transparent-capable, so tRNS is illegal. The processor rejects this as an integrity violation.
Solutions
- Remove the tRNS chunk from the PNG (e.g. with pngcrush -rem trns or an image editor re-save)
- If transparency is needed, encode the alpha directly in the image's alpha channel instead of tRNS
- Verify the IHDR colour type matches the chunk set produced by the encoder
- Catch PngIntegrityException and treat the file as invalid or strip transparency
Example fix
// before: tRNS chunk kept on a RGBA (colour type 6) image
pngWriter.writeChunk("tRNS", trnsData); // processor throws
// after: drop tRNS for alpha-channel colour types
if (colourType != GREYSCALE_WITH_ALPHA && colourType != TRUECOLOUR_WITH_ALPHA) {
pngWriter.writeChunk("tRNS", trnsData);
} Defensive patterns
Strategy: validation
Validate before calling
if ((header.colourType == PngColourType.PNG_GREYSCALE_WITH_ALPHA
|| header.colourType == PngColourType.PNG_TRUECOLOUR_WITH_ALPHA)
&& chunkPresent("tRNS")) {
throw new IllegalArgumentException("tRNS is illegal for alpha-channel colour types");
} Type guard
boolean tRnsAllowed(PngHeader header) {
return header.colourType == PngColourType.PNG_GREYSCALE
|| header.colourType == PngColourType.PNG_TRUECOLOUR
|| header.colourType == PngColourType.PNG_INDEXED_COLOUR;
} Try / catch
try {
processor.processTransparency(bytes, position, length);
} catch (PngIntegrityException e) {
LOG.warn("Illegal tRNS for image type, skipping: " + e.getMessage());
} Prevention
- Strip tRNS chunks when converting images to alpha-channel colour types
- Verify colour type / chunk-set consistency when generating PNGs
- Use pngcrush or similar to sanitize third-party images
When it happens
Trigger: Calling processTransparency on an Argb8888Processor when header.colourType is PNG_GREYSCALE_WITH_ALPHA or PNG_TRUECOLOUR_WITH_ALPHA, or falls into the default branch with an unknown colour type.
Common situations: PNG files edited to add an alpha channel while retaining a legacy tRNS chunk; broken encoders emitting tRNS for RGBA images; files converted from palette to RGBA with chunks copied over verbatim.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- tRNS chunk for greyscale image must be exactly length=2, not
- Received tRNS data but no palette is in place
- Received tRNS data length is invalid. Should be >1 && <
- acTL chunk length must be
- fcTL chunk length must be
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/216813c440262eae.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processor.java:88
}
builder.processTransparentGreyscale(bytes[0], bytes[1]);
break;
case PNG_TRUECOLOUR: // colour type 2
// red, green, blue samples, EACH with two bytes (16-bits)
builder.processTransparentTruecolour(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]);
break;
case PNG_INDEXED_COLOUR: // colour type 3
// This is a sequence of one-byte alpha values to apply to each palette entry starting at zero.
// The number of entries may be less than the size of the palette, but not more.
builder.processTransparentPalette(bytes, position, length);
break;
case PNG_GREYSCALE_WITH_ALPHA:
case PNG_TRUECOLOUR_WITH_ALPHA:
default:
throw new PngIntegrityException("Illegal to have tRNS chunk with image type " + header.colourType.name);
}
}
/**
* The only supported animation type is not "NOT_ANIMATED".
*/
// @Override
// public PngAnimationType chooseApngImageType(PngAnimationType type, PngFrameControl currentFrame) throws PngException {
// scanlineProcessor = Argb8888ScanlineProcessor.from(header, scanlineReader, currentFrame);
// return PngAnimationType.NOT_ANIMATED;
// }
@Override
public void processDefaultImageData(InputStream inputStream, PngChunkCode code, int position, int length) throws IOException, PngException {
if (!builder.wantDefaultImage()) {
inputStream.skip(length); // important!
return;
}
View on GitHub (pinned to 24702dc5a0)