{"record":{"id":"8b7b10c62e62d16d","repo":"HMCL-dev/HMCL","slug":"trns-chunk-for-greyscale-image-must-be-exactly-len","errorCode":null,"errorMessage":"tRNS chunk for greyscale image must be exactly length=2, not %d","messagePattern":"tRNS chunk for greyscale image must be exactly length=2, not (.+?)","errorType":"exception","errorClass":"PngIntegrityException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processor.java","lineNumber":69,"sourceCode":"    @Override\n    public void processGamma(PngGamma gamma) throws PngException {\n        // No gamma processing is done at the moment.\n    }\n\n    @Override\n    public void processPalette(byte[] bytes, int position, int length) throws PngException {\n        //palette = Argb8888Palette.fromPaletteBytes(bytes, position, length);\n        //scanlineProcessor = Argb8888Processors.fromPalette(this.header, palette);\n        builder.receivePalette(Argb8888Palette.fromPaletteBytes(bytes, position, length));\n    }\n\n    @Override\n    public void processTransparency(byte[] bytes, int position, int length) throws PngException {\n        switch (header.colourType) {\n            case PNG_GREYSCALE: // colour type 0\n                // grey sample value (2 bytes)\n                if (length != 2) {\n                    throw new PngIntegrityException(String.format(\"tRNS chunk for greyscale image must be exactly length=2, not %d\", length));\n                }\n                builder.processTransparentGreyscale(bytes[0], bytes[1]);\n                break;\n\n            case PNG_TRUECOLOUR: // colour type 2\n                // red, green, blue samples, EACH with two bytes (16-bits)\n                builder.processTransparentTruecolour(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]);\n                break;\n\n            case PNG_INDEXED_COLOUR: // colour type 3\n                // This is a sequence of one-byte alpha values to apply to each palette entry starting at zero.\n                // The number of entries may be less than the size of the palette, but not more.\n                builder.processTransparentPalette(bytes, position, length);\n                break;\n\n            case PNG_GREYSCALE_WITH_ALPHA:\n            case PNG_TRUECOLOUR_WITH_ALPHA:\n            default:","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/Argb8888Processor.java#L51-L87","documentation":"PngIntegrityException thrown when a tRNS (transparency) chunk appears in a greyscale (colour type 0) PNG but its data length is not exactly 2 bytes. Per the PNG specification, a greyscale tRNS holds exactly one 16-bit sample value identifying the transparent grey level. The processor validates the chunk length before handing the two bytes to the builder.","triggerScenarios":"Calling processTransparency on an Argb8888Processor for a PNG_GREYSCALE image with a tRNS chunk whose length is anything other than 2 — e.g. a 1-byte or truncated tRNS, or a colour-type-2-style 6-byte tRNS left in a greyscale image.","commonSituations":"Corrupt or hand-edited PNG files; images converted between colour types with the tRNS chunk not rewritten; PNGs produced by buggy encoders that emit malformed tRNS chunks; truncated downloads that cut the chunk data short.","solutions":["Fix the PNG so the greyscale tRNS chunk contains exactly 2 bytes (one 16-bit grey sample value)","Re-encode or re-save the image with a compliant tool (e.g. pngcrush, ImageMagick) to regenerate a correct tRNS chunk","If the image truly is colour-type 2, fix the IHDR colour type so the 6-byte RGB tRNS matches","Catch PngIntegrityException and reject/fall back to decoding without transparency"],"exampleFix":"// before: tRNS data of 6 bytes on a colour-type-0 image\nbyte[] trns = {0, 0, 0, 0, 0, 0};\nprocessor.processTransparency(trns, 0, 6); // throws\n// after: exactly 2 bytes (transparent grey = 0x0000)\nbyte[] trns = {0, 0};\nprocessor.processTransparency(trns, 0, 2); // OK","handlingStrategy":"validation","validationCode":"if (header.colourType == PngColourType.PNG_GREYSCALE && trnsData.length != 2) {\n    throw new IllegalArgumentException(\"Greyscale tRNS must be exactly 2 bytes, got \" + trnsData.length);\n}\nprocessor.processTransparency(trnsData, 0, trnsData.length);","typeGuard":"boolean hasValidGreyscaleTrns(PngHeader header, byte[] trns) {\n    return header.colourType == PngColourType.PNG_GREYSCALE && trns != null && trns.length == 2;\n}","tryCatchPattern":"try {\n    processor.processTransparency(bytes, position, length);\n} catch (PngIntegrityException e) {\n    LOG.warn(\"Malformed tRNS chunk, ignoring transparency: \" + e.getMessage());\n    // proceed decoding without transparency\n}","preventionTips":["Validate chunk lengths against the PNG spec table for each colour type before dispatch","Re-save suspicious images with a compliant tool to normalize chunks","Never hand-edit binary PNG chunk data","Check for truncation (chunk length vs actual available bytes) before parsing"],"tags":["png","transparency","chunk-validation","apng"],"backgroundTag":"invalid-argument-format","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"}