{"record":{"id":"01d1caa1b14e5bcc","repo":"HMCL-dev/HMCL","slug":"invalid-greyscale-bit-depth-d","errorCode":null,"errorMessage":"Invalid greyscale bit-depth: %d","messagePattern":"Invalid greyscale bit-depth: (.+?)","errorType":"exception","errorClass":"PngIntegrityException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processors.java","lineNumber":46,"sourceCode":"     */\n    public static Argb8888ScanlineProcessor from(PngHeader header, PngScanlineBuffer scanlineReader, Argb8888Bitmap bitmap) throws PngException {\n\n        int bytesPerScanline = header.bytesPerRow;\n        switch (header.colourType) {\n            case PNG_GREYSCALE:\n                switch (header.bitDepth) {\n                    case 1:\n                        return new IndexedColourBits(bytesPerScanline, bitmap, 7, 0x01, PngConstants.SHIFTS_1, Argb8888Palette.forGreyscale(1));\n                    case 2:\n                        return new IndexedColourBits(bytesPerScanline, bitmap, 3, 0x03, PngConstants.SHIFTS_2, Argb8888Palette.forGreyscale(2));\n                    case 4:\n                        return new IndexedColourBits(bytesPerScanline, bitmap, 1, 0x0F, PngConstants.SHIFTS_4, Argb8888Palette.forGreyscale(4));\n                    case 8:\n                        return new Greyscale8(bytesPerScanline, bitmap);\n                    case 16:\n                        throw new PngFeatureException(\"Greyscale supports 1, 2, 4, 8 but not 16.\");\n                    default:\n                        throw new PngIntegrityException(String.format(\"Invalid greyscale bit-depth: %d\", header.bitDepth)); // TODO: should be in header parse.\n                }\n\n            case PNG_GREYSCALE_WITH_ALPHA:\n                switch (header.bitDepth) {\n                    case 4:\n                        return new Greyscale4Alpha(bytesPerScanline, bitmap);\n                    case 8:\n                        return new Greyscale8Alpha(bytesPerScanline, bitmap);\n                    case 16:\n                        return new Greyscale16Alpha(bytesPerScanline, bitmap);\n                    default:\n                        throw new PngIntegrityException(String.format(\"Invalid greyscale-with-alpha bit-depth: %d\", header.bitDepth)); // TODO: should be in header parse.\n                }\n\n            case PNG_INDEXED_COLOUR:\n                switch (header.bitDepth) {\n                    case 1:\n                        return new IndexedColourBits(bytesPerScanline, bitmap, 7, 0x01, PngConstants.SHIFTS_1);","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processors.java#L28-L64","documentation":"PngIntegrityException thrown when a greyscale (colour type 0) PNG declares a bit depth that is not one of the PNG-legal values 1, 2, 4, 8, or 16 (e.g. 0, 3, 5, 32). The processor factory has no case for such a depth, so it rejects the header as corrupt. The TODO notes this check ideally belongs in header parsing.","triggerScenarios":"Calling Argb8888Processors.from with a header of colourType PNG_GREYSCALE and bitDepth outside {1,2,4,8,16} — reached via the switch's default branch.","commonSituations":"Corrupt or fuzzed PNG files with tampered IHDR bytes; hand-crafted binary PNGs in tests; memory/bit corruption during file transfer; buggy custom encoders writing an invalid depth byte.","solutions":["Validate the IHDR bit depth (1/2/4/8/16 for greyscale) before constructing processors — ideally at header parse time as the TODO suggests","Reject or quarantine the file as structurally invalid","Re-obtain the image from a trusted source if corruption is suspected","Catch PngIntegrityException and surface a clear 'corrupt PNG header' error to the user"],"exampleFix":"// before: trusting the parsed header\nArgb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap); // throws for bitDepth=3\n// after: validate early\nif (header.colourType == PngColourType.PNG_GREYSCALE\n        && (header.bitDepth != 1 && header.bitDepth != 2 && header.bitDepth != 4\n            && header.bitDepth != 8 && header.bitDepth != 16)) {\n    throw new PngIntegrityException(\"IHDR bit depth invalid for greyscale: \" + header.bitDepth);\n}\nArgb8888ScanlineProcessor p = Argb8888Processors.from(header, bitmap);","handlingStrategy":"validation","validationCode":"if (header.colourType == PngColourType.PNG_GREYSCALE) {\n    int d = header.bitDepth;\n    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16) {\n        throw new IllegalArgumentException(\"Invalid greyscale bit depth: \" + d);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    processor = Argb8888Processors.from(header, bitmap);\n} catch (PngIntegrityException e) {\n    throw new IOException(\"Corrupt PNG IHDR: \" + e.getMessage(), e);\n}","preventionTips":["Validate the full IHDR (width, height, depth, colour type, interlace) at parse time","Fuzz-test your PNG ingestion path","Checksum-verify downloads before decoding","Reject files whose header fields violate the PNG spec table"],"tags":["png","bit-depth","corrupt-file","header-validation"],"backgroundTag":"invalid-config-value","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}