HMCL-dev/HMCL · error · PngIntegrityException
Invalid greyscale-with-alpha bit-depth
Error message
Invalid greyscale-with-alpha bit-depth: %d
What it means
PngIntegrityException thrown when a greyscale-with-alpha (colour type 4) PNG declares a bit depth other than the legal 8 or 16. Note the factory accepts a 4-bit case here but the switch's default still catches any other unsupported value. It signals a malformed IHDR rather than an unsupported feature.
Solutions
- Validate IHDR bit depth against the colour type before decoding (legal for type 4: 8 and 16 per PNG spec)
- Reject the file as corrupt at header-parse time
- Re-export or re-obtain the image from a reliable encoder
- Catch PngIntegrityException and report the invalid header to the caller
Example fix
// before: unchecked header
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap); // throws for bitDepth=2
// after: guard before construction
Set<Integer> legal = Set.of(8, 16);
if (header.colourType == PngColourType.PNG_GREYSCALE_WITH_ALPHA && !legal.contains(header.bitDepth)) {
throw new PngIntegrityException("IHDR bit depth invalid for greyscale+alpha: " + header.bitDepth);
}
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap); Defensive patterns
Strategy: validation
Validate before calling
if (header.colourType == PngColourType.PNG_GREYSCALE_WITH_ALPHA
&& !(header.bitDepth == 8 || header.bitDepth == 16)) {
throw new IllegalArgumentException("Invalid greyscale+alpha bit depth: " + header.bitDepth);
} Try / catch
try {
processor = Argb8888Processors.from(header, bitmap);
} catch (PngIntegrityException e) {
throw new IOException("Corrupt PNG IHDR: " + e.getMessage(), e);
} Prevention
- Enforce the spec's colour-type/bit-depth matrix during header parsing
- Sanitize third-party images before ingestion
- Log and reject rather than attempting best-effort decode of corrupt headers
When it happens
Trigger: Calling Argb8888Processors.from with a header of colourType PNG_GREYSCALE_WITH_ALPHA and bitDepth not in {4,8,16} — e.g. 1, 2, or any garbage value.
Common situations: Fuzzed or corrupted PNG headers; hand-written PNG generators writing wrong depth bytes; files damaged in transit; test fixtures with deliberately invalid IHDR values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Invalid greyscale bit-depth
- Invalid truecolour bit-depth
- Invalid indexed colour bit-depth
- Invalid truecolour with alpha bit-depth
- Valid greyscale bit depths are 1, 2, 4, 8, not
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/39b8de79ccde4854.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processors.java:58
return new IndexedColourBits(bytesPerScanline, bitmap, 1, 0x0F, PngConstants.SHIFTS_4, Argb8888Palette.forGreyscale(4));
case 8:
return new Greyscale8(bytesPerScanline, bitmap);
case 16:
throw new PngFeatureException("Greyscale supports 1, 2, 4, 8 but not 16.");
default:
throw new PngIntegrityException(String.format("Invalid greyscale bit-depth: %d", header.bitDepth)); // TODO: should be in header parse.
}
case PNG_GREYSCALE_WITH_ALPHA:
switch (header.bitDepth) {
case 4:
return new Greyscale4Alpha(bytesPerScanline, bitmap);
case 8:
return new Greyscale8Alpha(bytesPerScanline, bitmap);
case 16:
return new Greyscale16Alpha(bytesPerScanline, bitmap);
default:
throw new PngIntegrityException(String.format("Invalid greyscale-with-alpha bit-depth: %d", header.bitDepth)); // TODO: should be in header parse.
}
case PNG_INDEXED_COLOUR:
switch (header.bitDepth) {
case 1:
return new IndexedColourBits(bytesPerScanline, bitmap, 7, 0x01, PngConstants.SHIFTS_1);
case 2:
return new IndexedColourBits(bytesPerScanline, bitmap, 3, 0x03, PngConstants.SHIFTS_2);
case 4:
return new IndexedColourBits(bytesPerScanline, bitmap, 1, 0x0F, PngConstants.SHIFTS_4);
case 8:
return new IndexedColour8(bytesPerScanline, bitmap);
default:
throw new PngIntegrityException(String.format("Invalid indexed colour bit-depth: %d", header.bitDepth)); // TODO: should be in header parse.
}
case PNG_TRUECOLOUR:
switch (header.bitDepth) {View on GitHub (pinned to 24702dc5a0)