private BufferedImage readImage()

in src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java [258:380]


    private BufferedImage readImage(final PcxHeader pcxHeader, final InputStream is, final ByteSource byteSource) throws ImagingException, IOException {
        final int xSize = pcxHeader.xMax - pcxHeader.xMin + 1;
        if (xSize < 0) {
            throw new ImagingException("Image width is negative");
        }
        final int ySize = pcxHeader.yMax - pcxHeader.yMin + 1;
        if (ySize < 0) {
            throw new ImagingException("Image height is negative");
        }
        if (pcxHeader.nPlanes <= 0 || 4 < pcxHeader.nPlanes) {
            throw new ImagingException("Unsupported/invalid image with " + pcxHeader.nPlanes + " planes");
        }
        final RleReader rleReader;
        if (pcxHeader.encoding == PcxHeader.ENCODING_UNCOMPRESSED) {
            rleReader = new RleReader(false);
        } else if (pcxHeader.encoding == PcxHeader.ENCODING_RLE) {
            rleReader = new RleReader(true);
        } else {
            throw new ImagingException("Unsupported/invalid image encoding " + pcxHeader.encoding);
        }
        final int scanlineLength = pcxHeader.bytesPerLine * pcxHeader.nPlanes;
        final byte[] scanline = Allocator.byteArray(scanlineLength);
        if ((pcxHeader.bitsPerPixel == 1 || pcxHeader.bitsPerPixel == 2 || pcxHeader.bitsPerPixel == 4 || pcxHeader.bitsPerPixel == 8)
                && pcxHeader.nPlanes == 1) {
            final int bytesPerImageRow = (xSize * pcxHeader.bitsPerPixel + 7) / 8;
            final byte[] image = Allocator.byteArray(ySize * bytesPerImageRow);
            for (int y = 0; y < ySize; y++) {
                rleReader.read(is, scanline);
                System.arraycopy(scanline, 0, image, y * bytesPerImageRow, bytesPerImageRow);
            }
            final DataBufferByte dataBuffer = new DataBufferByte(image, image.length);
            int[] palette;
            if (pcxHeader.bitsPerPixel == 1) {
                palette = new int[] { 0x000000, 0xffffff };
            } else if (pcxHeader.bitsPerPixel == 8) {
                // Normally the palette is read 769 bytes from the end of the
                // file.
                // However DCX files have multiple PCX images in one file, so
                // there could be extra data before the end! So try look for the
                // palette
                // immediately after the image data first.
                palette = read256ColorPalette(is);
                if (palette == null) {
                    palette = read256ColorPaletteFromEndOfFile(byteSource);
                }
                if (palette == null) {
                    throw new ImagingException("No 256 color palette found in image that needs it");
                }
            } else {
                palette = pcxHeader.colormap;
            }
            final WritableRaster raster;
            if (pcxHeader.bitsPerPixel == 8) {
                raster = Raster.createInterleavedRaster(dataBuffer, xSize, ySize, bytesPerImageRow, 1, new int[] { 0 }, null);
            } else {
                raster = Raster.createPackedRaster(dataBuffer, xSize, ySize, pcxHeader.bitsPerPixel, null);
            }
            final IndexColorModel colorModel = new IndexColorModel(pcxHeader.bitsPerPixel, 1 << pcxHeader.bitsPerPixel, palette, 0, false, -1,
                    DataBuffer.TYPE_BYTE);
            return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Properties());
        }
        if (pcxHeader.bitsPerPixel == 1 && 2 <= pcxHeader.nPlanes && pcxHeader.nPlanes <= 4) {
            final IndexColorModel colorModel = new IndexColorModel(pcxHeader.nPlanes, 1 << pcxHeader.nPlanes, pcxHeader.colormap, 0, false, -1,
                    DataBuffer.TYPE_BYTE);
            final BufferedImage image = new BufferedImage(xSize, ySize, BufferedImage.TYPE_BYTE_BINARY, colorModel);
            final byte[] unpacked = Allocator.byteArray(xSize);
            for (int y = 0; y < ySize; y++) {
                rleReader.read(is, scanline);
                int nextByte = 0;
                Arrays.fill(unpacked, (byte) 0);
                for (int plane = 0; plane < pcxHeader.nPlanes; plane++) {
                    for (int i = 0; i < pcxHeader.bytesPerLine; i++) {
                        final int b = 0xff & scanline[nextByte++];
                        for (int j = 0; j < 8 && 8 * i + j < unpacked.length; j++) {
                            unpacked[8 * i + j] |= (byte) ((b >> 7 - j & 0x1) << plane);
                        }
                    }
                }
                image.getRaster().setDataElements(0, y, xSize, 1, unpacked);
            }
            return image;
        }
        if (pcxHeader.bitsPerPixel == 8 && pcxHeader.nPlanes == 3) {
            final byte[][] image = new byte[3][];
            final int xySize = xSize * ySize;
            image[0] = Allocator.byteArray(xySize);
            image[1] = Allocator.byteArray(xySize);
            image[2] = Allocator.byteArray(xySize);
            for (int y = 0; y < ySize; y++) {
                rleReader.read(is, scanline);
                System.arraycopy(scanline, 0, image[0], y * xSize, xSize);
                System.arraycopy(scanline, pcxHeader.bytesPerLine, image[1], y * xSize, xSize);
                System.arraycopy(scanline, 2 * pcxHeader.bytesPerLine, image[2], y * xSize, xSize);
            }
            final DataBufferByte dataBuffer = new DataBufferByte(image, image[0].length);
            final WritableRaster raster = Raster.createBandedRaster(dataBuffer, xSize, ySize, xSize, new int[] { 0, 1, 2 }, new int[] { 0, 0, 0 }, null);
            final ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, Transparency.OPAQUE,
                    DataBuffer.TYPE_BYTE);
            return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Properties());
        }
        if ((pcxHeader.bitsPerPixel != 24 || pcxHeader.nPlanes != 1) && (pcxHeader.bitsPerPixel != 32 || pcxHeader.nPlanes != 1)) {
            throw new ImagingException("Invalid/unsupported image with bitsPerPixel " + pcxHeader.bitsPerPixel + " and planes " + pcxHeader.nPlanes);
        }
        final int rowLength = 3 * xSize;
        final byte[] image = Allocator.byteArray(rowLength * ySize);
        for (int y = 0; y < ySize; y++) {
            rleReader.read(is, scanline);
            if (pcxHeader.bitsPerPixel == 24) {
                System.arraycopy(scanline, 0, image, y * rowLength, rowLength);
            } else {
                for (int x = 0; x < xSize; x++) {
                    image[y * rowLength + 3 * x] = scanline[4 * x];
                    image[y * rowLength + 3 * x + 1] = scanline[4 * x + 1];
                    image[y * rowLength + 3 * x + 2] = scanline[4 * x + 2];
                }
            }
        }
        final DataBufferByte dataBuffer = new DataBufferByte(image, image.length);
        final WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, xSize, ySize, rowLength, 3, new int[] { 2, 1, 0 }, null);
        final ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, Transparency.OPAQUE,
                DataBuffer.TYPE_BYTE);
        return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Properties());
    }