private Raster clipRowToRect( final Raster raster, final Rectangle rect, final int[] bands, final int xSub) { if (rect.contains(raster.getMinX(), 0, raster.getWidth(), 1) && xSub == 1 && bands == null /* TODO: Compare bands with that of raster */) { return raster; } return raster.createChild(rect.x / xSub, 0, rect.width / xSub, 1, 0, 0, bands); }
@Override public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException { Iterator<ImageTypeSpecifier> imageTypes = getImageTypes(imageIndex); ImageTypeSpecifier rawType = getRawImageType(imageIndex); if (header.getPaletteInfo() != PCX.PALETTEINFO_COLOR && header.getPaletteInfo() != PCX.PALETTEINFO_GRAY) { processWarningOccurred( String.format( "Unsupported color mode: %d, colors may look incorrect", header.getPaletteInfo())); } int width = getWidth(imageIndex); int height = getHeight(imageIndex); BufferedImage destination = getDestination(param, imageTypes, width, height); Rectangle srcRegion = new Rectangle(); Rectangle destRegion = new Rectangle(); computeRegions(param, width, height, destination, srcRegion, destRegion); WritableRaster destRaster = clipToRect( destination.getRaster(), destRegion, param != null ? param.getDestinationBands() : null); checkReadParamBandSettings(param, rawType.getNumBands(), destRaster.getNumBands()); int compression = header.getCompression(); // Wrap input (COMPRESSION_RLE is really the only value allowed) DataInput input = compression == PCX.COMPRESSION_RLE ? new DataInputStream( new DecoderStream(IIOUtil.createStreamAdapter(imageInput), new RLEDecoder())) : imageInput; int xSub = param != null ? param.getSourceXSubsampling() : 1; int ySub = param != null ? param.getSourceYSubsampling() : 1; processImageStarted(imageIndex); if (rawType.getColorModel() instanceof IndexColorModel && header.getChannels() > 1) { // Bit planes! // Create raster from a default 8 bit layout WritableRaster rowRaster = GRAYSCALE.createBufferedImage(header.getWidth(), 1).getRaster(); // Clip to source region Raster clippedRow = clipRowToRect( rowRaster, srcRegion, param != null ? param.getSourceBands() : null, param != null ? param.getSourceXSubsampling() : 1); int planeWidth = header.getBytesPerLine(); byte[] planeData = new byte[planeWidth * 8]; byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData(); for (int y = 0; y < height; y++) { switch (header.getBitsPerPixel()) { case 1: readRowByte( input, srcRegion, xSub, ySub, planeData, 0, planeWidth * header.getChannels(), destRaster, clippedRow, y); break; default: throw new AssertionError(); } int pixelPos = 0; for (int planePos = 0; planePos < planeWidth; planePos++) { BitRotator.bitRotateCW(planeData, planePos, planeWidth, rowDataByte, pixelPos, 1); pixelPos += 8; } processImageProgress(100f * y / height); if (y >= srcRegion.y + srcRegion.height) { break; } if (abortRequested()) { processReadAborted(); break; } } } else if (header.getBitsPerPixel() == 24 || header.getBitsPerPixel() == 32) { // Can't use width here, as we need to take bytesPerLine into account, and re-create a width // based on this int rowWidth = (header.getBytesPerLine() * 8) / header.getBitsPerPixel(); WritableRaster rowRaster = rawType.createBufferedImage(rowWidth, 1).getRaster(); // Clip to source region Raster clippedRow = clipRowToRect( rowRaster, srcRegion, param != null ? param.getSourceBands() : null, param != null ? param.getSourceXSubsampling() : 1); for (int y = 0; y < height; y++) { byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData(); readRowByte( input, srcRegion, xSub, ySub, rowDataByte, 0, rowDataByte.length, destRaster, clippedRow, y); processImageProgress(100f * y / height); if (y >= srcRegion.y + srcRegion.height) { break; } if (abortRequested()) { processReadAborted(); break; } } } else { // Can't use width here, as we need to take bytesPerLine into account, and re-create a width // based on this int rowWidth = (header.getBytesPerLine() * 8) / header.getBitsPerPixel(); WritableRaster rowRaster = rawType.createBufferedImage(rowWidth, 1).getRaster(); // Clip to source region Raster clippedRow = clipRowToRect( rowRaster, srcRegion, param != null ? param.getSourceBands() : null, param != null ? param.getSourceXSubsampling() : 1); for (int y = 0; y < height; y++) { for (int c = 0; c < header.getChannels(); c++) { WritableRaster destChannel = destRaster.createWritableChild( destRaster.getMinX(), destRaster.getMinY(), destRaster.getWidth(), destRaster.getHeight(), 0, 0, new int[] {c}); Raster srcChannel = clippedRow.createChild( clippedRow.getMinX(), 0, clippedRow.getWidth(), 1, 0, 0, new int[] {c}); switch (header.getBitsPerPixel()) { case 1: case 2: case 4: case 8: byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData(c); readRowByte( input, srcRegion, xSub, ySub, rowDataByte, 0, rowDataByte.length, destChannel, srcChannel, y); break; default: throw new AssertionError(); } if (abortRequested()) { break; } } processImageProgress(100f * y / height); if (y >= srcRegion.y + srcRegion.height) { break; } if (abortRequested()) { processReadAborted(); break; } } } processImageComplete(); return destination; }