HMCL-dev/HMCL · error · PngIntegrityException

Invalid indexed colour bit-depth

Error message

Invalid indexed colour bit-depth: %d

What it means

PngIntegrityException thrown when an indexed-colour (colour type 3) PNG declares a bit depth other than the PNG-legal 1, 2, 4, or 8. Indexed colour cannot be 16-bit, so anything outside the four legal values means the IHDR is corrupt or was produced by a broken encoder.

Solutions

  1. Validate IHDR bit depth (1/2/4/8 for indexed colour) during header parsing before constructing processors
  2. Reject the file as structurally invalid
  3. Re-encode the image with a compliant tool to regenerate a correct IHDR
  4. Catch PngIntegrityException and report a corrupt-header error

Example fix

// before: 16-bit indexed PNG passed straight through
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap); // throws for bitDepth=16
// after: validate colour-type/depth pair first
if (header.colourType == PngColourType.PNG_INDEXED_COLOUR
        && !(header.bitDepth == 1 || header.bitDepth == 2 || header.bitDepth == 4 || header.bitDepth == 8)) {
    throw new PngIntegrityException("IHDR bit depth invalid for indexed colour: " + header.bitDepth);
}
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap);
Defensive patterns

Strategy: validation

Validate before calling

if (header.colourType == PngColourType.PNG_INDEXED_COLOUR
        && !(header.bitDepth == 1 || header.bitDepth == 2 || header.bitDepth == 4 || header.bitDepth == 8)) {
    throw new IllegalArgumentException("Invalid indexed bit depth: " + header.bitDepth);
}

Try / catch

try {
    processor = Argb8888Processors.from(header, bitmap);
} catch (PngIntegrityException e) {
    throw new IOException("Corrupt PNG IHDR (indexed depth): " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling Argb8888Processors.from with a header of colourType PNG_INDEXED_COLOUR and bitDepth not in {1,2,4,8} — notably 16, or garbage values like 0 or 3.

Common situations: Fuzzed/corrupted palette PNGs; naive encoders that copy a 16-bit depth byte when converting from RGB; hand-crafted PNG binaries in tests; damaged downloads.

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


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/91f456c5cab7de6d. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processors.java:72

                        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) {
                    case 8:
                        return new Truecolour8(bytesPerScanline, bitmap);
                    case 16:
                        return new Truecolour16(bytesPerScanline, bitmap);
                    default:
                        throw new PngIntegrityException(String.format("Invalid truecolour bit-depth: %d", header.bitDepth)); // TODO: should be in header parse.

                }

            case PNG_TRUECOLOUR_WITH_ALPHA:
                switch (header.bitDepth) {
                    case 8:
                        return new Truecolour8Alpha(bytesPerScanline, bitmap);
                    case 16:

View on GitHub (pinned to 24702dc5a0)