HMCL-dev/HMCL · error · PngFeatureException

ARGB8888 doesn't support PNG mode

Error message

ARGB8888 doesn't support PNG mode 

What it means

PngFeatureException thrown when the PNG colour type is not one of the five standard types the ARGB8888 backend handles (0, 2, 3, 4, 6). Any other/unrecognized colourType value falls through the switch's default branch and is rejected as an unsupported feature rather than a corrupt file.

Solutions

  1. Use a decoder backend that supports the image's colour type, or convert the image to a standard type (e.g. RGBA 8-bit) before decoding
  2. Validate the IHDR colour type against {0,2,3,4,6} during header parsing and reject nonstandard values early
  3. Re-encode the image with a mainstream tool to normalize the colour type
  4. Catch PngFeatureException and route to an alternative decoder or show a 'format not supported' message

Example fix

// before: unsupported colour type byte 7 decoded directly
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap); // throws
// after: pre-validate and convert if needed
int typeByte = header.colourType.ordinal(); // or raw value
if (typeByte != 0 && typeByte != 2 && typeByte != 3 && typeByte != 4 && typeByte != 6) {
    header = convertToRgba8(header, bitmap); // or reject the file
}
Argb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap);
Defensive patterns

Strategy: try-catch

Validate before calling

int t = header.colourTypeValue();
if (t != 0 && t != 2 && t != 3 && t != 4 && t != 6) {
    throw new IllegalArgumentException("Nonstandard PNG colour type: " + t);
}

Type guard

boolean isStandardColourType(PngHeader header) {
    switch (header.colourType) {
        case PNG_GREYSCALE:
        case PNG_TRUECOLOUR:
        case PNG_INDEXED_COLOUR:
        case PNG_GREYSCALE_WITH_ALPHA:
        case PNG_TRUECOLOUR_WITH_ALPHA:
            return true;
        default:
            return false;
    }
}

Try / catch

try {
    processor = Argb8888Processors.from(header, bitmap);
} catch (PngFeatureException e) {
    // unknown colour type: try generic decoder or notify 'format not supported'
    processor = genericDecoderFactory.from(header, bitmap);
}

Prevention

When it happens

Trigger: Calling Argb8888Processors.from with a header whose colourType is not one of PNG_GREYSCALE, PNG_TRUECOLOUR, PNG_INDEXED_COLOUR, PNG_GREYSCALE_WITH_ALPHA, PNG_TRUECOLOUR_WITH_ALPHA — e.g. a newly added or nonstandard colour-type byte.

Common situations: PNG files with reserved or future colour-type values; memory-corrupted IHDR colour byte that still looks like a type enum; custom extended PNG variants; enum deserialization producing an unexpected constant.

Related errors


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

Appendix: source

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

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

                }

            default:
                throw new PngFeatureException("ARGB8888 doesn't support PNG mode " + header.colourType.name());
        }
    }

    /**
     * Transforms 1-, 2-, 4-bit indexed colour source pixels to ARGB8888 pixels.
     */
    public static class IndexedColourBits extends Argb8888ScanlineProcessor {

        private int highBit;
        private int mask;
        private byte[] shifts;

        public IndexedColourBits(int bytesPerScanline, Argb8888Bitmap bitmap, int highBit, int mask, byte[] shifts) {
            this(bytesPerScanline, bitmap, highBit, mask, shifts, null);
        }

        public IndexedColourBits(int bytesPerScanline, Argb8888Bitmap bitmap, int highBit, int mask, byte[] shifts, Argb8888Palette palette) {
            super(bytesPerScanline, bitmap);

View on GitHub (pinned to 24702dc5a0)