private Raster readSubsampledRaster(WritableRaster raster) throws IOException { if (raster == null) raster = Raster.createWritableRaster( sampleModel.createCompatibleSampleModel( destinationRegion.x + destinationRegion.width, destinationRegion.y + destinationRegion.height), new Point(destinationRegion.x, destinationRegion.y)); int pixbuf[] = null; // line buffer for pixel data boolean prog = false; // Flag for progressive data Point nT = ictransf.getNumTiles(null); int numBands = sourceBands.length; Rectangle destRect = raster.getBounds().intersection(destinationRegion); int offx = destinationRegion.x; int offy = destinationRegion.y; int sourceSX = (destRect.x - offx) * scaleX + sourceOrigin.x; int sourceSY = (destRect.y - offy) * scaleY + sourceOrigin.y; int sourceEX = (destRect.width - 1) * scaleX + sourceSX; int sourceEY = (destRect.height - 1) * scaleY + sourceSY; int startXTile = (sourceSX - tileXOffset) / tileWidth; int startYTile = (sourceSY - tileYOffset) / tileHeight; int endXTile = (sourceEX - tileXOffset) / tileWidth; int endYTile = (sourceEY - tileYOffset) / tileHeight; startXTile = clip(startXTile, 0, nT.x - 1); startYTile = clip(startYTile, 0, nT.y - 1); endXTile = clip(endXTile, 0, nT.x - 1); endYTile = clip(endYTile, 0, nT.y - 1); int totalXTiles = endXTile - startXTile + 1; int totalYTiles = endYTile - startYTile + 1; int totalTiles = totalXTiles * totalYTiles; // Start the data delivery to the cached consumers tile by tile for (int y = startYTile; y <= endYTile; y++) { if (reader.getAbortRequest()) break; // Loop on horizontal tiles for (int x = startXTile; x <= endXTile; x++) { if (reader.getAbortRequest()) break; float initialFraction = (x - startXTile + (y - startYTile) * totalXTiles) / totalTiles; ictransf.setTile(x * tileStepX, y * tileStepY); int sx = hd.getCompSubsX(0); int cTileWidth = (ictransf.getTileWidth() + sx - 1) / sx; int sy = hd.getCompSubsY(0); int cTileHeight = (ictransf.getTileHeight() + sy - 1) / sy; // Offsets within the tile. int tx = 0; int ty = 0; // The region for this tile int startX = tileXOffset + x * tileWidth; int startY = tileYOffset + y * tileHeight; // sourceSX is guaranteed to be >= startX if (sourceSX > startX) { if (startX >= hd.getImgULX()) { tx = sourceSX - startX; // Intra-tile offset. cTileWidth -= tx; // Reduce effective width. } startX = sourceSX; // Absolute position. } // sourceSY is guaranteed to be >= startY if (sourceSY > startY) { if (startY >= hd.getImgULY()) { ty = sourceSY - startY; // Intra-tile offset. cTileHeight -= ty; // Reduce effective width. } startY = sourceSY; // Absolute position. } // Decrement dimensions if end position is within tile. if (sourceEX < startX + cTileWidth - 1) { cTileWidth += sourceEX - startX - cTileWidth + 1; } if (sourceEY < startY + cTileHeight - 1) { cTileHeight += sourceEY - startY - cTileHeight + 1; } // The start X in the destination int x1 = (startX + scaleX - 1 - sourceOrigin.x) / scaleX; int x2 = (startX + scaleX - 1 + cTileWidth - sourceOrigin.x) / scaleX; int lineLength = x2 - x1; if (pixbuf == null || pixbuf.length < lineLength) pixbuf = new int[lineLength]; // line buffer for pixel data x2 = (x2 - 1) * scaleX + sourceOrigin.x - startX; int y1 = (startY + scaleY - 1 - sourceOrigin.y) / scaleY; x1 += offx; y1 += offy; // check to see if we have YCbCr data boolean ycbcr = false; for (int i = 0; i < numBands; i++) { DataBlkInt db = dataBlocks[i]; db.ulx = tx; db.uly = ty + cTileHeight - 1; db.w = cTileWidth; db.h = 1; try { ictransf.getInternCompData(db, channelMap[sourceBands[i]]); } catch (ArrayIndexOutOfBoundsException e) { ycbcr = true; break; } } // Deliver in lines to reduce memory usage for (int l = ty, m = y1; l < ty + cTileHeight; l += scaleY, m++) { if (reader.getAbortRequest()) break; if (ycbcr) { DataBlkInt lum = dataBlocks[0]; DataBlkInt cb = dataBlocks[1]; DataBlkInt cr = dataBlocks[2]; lum.ulx = tx; lum.uly = l; lum.w = cTileWidth; lum.h = 1; ictransf.getInternCompData(lum, channelMap[sourceBands[0]]); prog = prog || lum.progressive; cb.ulx = tx; cb.uly = l; cb.w = cTileWidth / 2; cb.h = 1; ictransf.getInternCompData(cb, channelMap[sourceBands[1]]); prog = prog || cb.progressive; cr.ulx = tx; cr.uly = l; cr.w = cTileWidth / 2; cr.h = 1; ictransf.getInternCompData(cr, channelMap[sourceBands[2]]); prog = prog || cr.progressive; int[] lumdata = lum.data; int[] cbdata = cb.data; int[] crdata = cr.data; int k1 = lum.offset + x2; int fracBit = fracBits[0]; int lS = levelShift[0]; int min = minValues[0]; int max = maxValues[0]; int[][] pix = new int[3][lineLength]; for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) { int red = (lumdata[k1] >> fracBit) + lS; red = (red < min) ? min : ((red > max) ? max : red); int cIndex = k1 / 2; int chrom1 = cbdata[cIndex]; int chrom2 = crdata[cIndex]; int lumval = red; red = (int) (chrom2 * 1.542 + lumval); int blue = (int) (lumval + 1.772 * chrom1 - 0.886); int green = (int) (lumval - 0.34413 * chrom1 - 0.71414 * chrom2 - 0.1228785); if (red > 255) red = 255; if (green > 255) green = 255; if (blue > 255) blue = 255; if (red < 0) red = 0; if (green < 0) green = 0; if (blue < 0) blue = 0; pix[0][j] = red; pix[1][j] = green; pix[2][j] = blue; } raster.setSamples(x1, m, lineLength, 1, destinationBands[0], pix[0]); raster.setSamples(x1, m, lineLength, 1, destinationBands[1], pix[1]); raster.setSamples(x1, m, lineLength, 1, destinationBands[2], pix[2]); continue; } // Request line data for (int i = 0; i < numBands; i++) { DataBlkInt db = dataBlocks[i]; db.ulx = tx; db.uly = l; db.w = ycbcr && i > 0 ? cTileWidth / 2 : cTileWidth; db.h = 1; ictransf.getInternCompData(db, channelMap[sourceBands[i]]); prog = prog || db.progressive; int[] data = db.data; int k1 = db.offset + x2; int fracBit = fracBits[i]; int lS = levelShift[i]; int min = minValues[i]; int max = maxValues[i]; if (ImageUtil.isBinary(sampleModel)) { // Force min max to 0 and 1. min = 0; max = 1; if (bytebuf == null || bytebuf.length < cTileWidth * numBands) bytebuf = new byte[cTileWidth * numBands]; for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) { int tmp = (data[k1] >> fracBit) + lS; bytebuf[j] = (byte) ((tmp < min) ? min : ((tmp > max) ? max : tmp)); } ImageUtil.setUnpackedBinaryData(bytebuf, raster, new Rectangle(x1, m, lineLength, 1)); } else { for (int j = lineLength - 1; j >= 0; j--, k1 -= scaleX) { int tmp = (data[k1] >> fracBit) + lS; pixbuf[j] = (tmp < min) ? min : ((tmp > max) ? max : tmp); } // Send the line data to the BufferedImage raster.setSamples(x1, m, lineLength, 1, destinationBands[i], pixbuf); } } if (destImage != null) reader.processImageUpdateWrapper( destImage, x1, m, cTileWidth, 1, 1, 1, destinationBands); float fraction = initialFraction + (l - ty + 1.0F) / cTileHeight / totalTiles; reader.processImageProgressWrapper(100.0f * fraction); } } // End loop on horizontal tiles } // End loop on vertical tiles return raster; }
public Raster getTile(int tileX, int tileY, WritableRaster raster) throws IOException { Point nT = ictransf.getNumTiles(null); if (noTransform) { if (tileX >= nT.x || tileY >= nT.y) throw new IllegalArgumentException(I18N.getString("J2KImageReader0")); ictransf.setTile(tileX * tileStepX, tileY * tileStepY); // The offset of the active tiles is the same for all components, // since we don't support different component dimensions. int tOffx; int tOffy; int cTileWidth; int cTileHeight; if (raster != null && (this.resolution < hd.getDecoderSpecs().dls.getMin()) || stepX != 1 || stepY != 1) { tOffx = raster.getMinX(); tOffy = raster.getMinY(); cTileWidth = Math.min(raster.getWidth(), ictransf.getTileWidth()); cTileHeight = Math.min(raster.getHeight(), ictransf.getTileHeight()); } else { tOffx = ictransf.getCompULX(0) - (ictransf.getImgULX() + ictransf.getCompSubsX(0) - 1) / ictransf.getCompSubsX(0) + destinationRegion.x; tOffy = ictransf.getCompULY(0) - (ictransf.getImgULY() + ictransf.getCompSubsY(0) - 1) / ictransf.getCompSubsY(0) + destinationRegion.y; cTileWidth = ictransf.getTileWidth(); cTileHeight = ictransf.getTileHeight(); } if (raster == null) raster = Raster.createWritableRaster(sampleModel, new Point(tOffx, tOffy)); int numBands = sampleModel.getNumBands(); if (tOffx + cTileWidth >= destinationRegion.width + destinationRegion.x) cTileWidth = destinationRegion.width + destinationRegion.x - tOffx; if (tOffy + cTileHeight >= destinationRegion.height + destinationRegion.y) cTileHeight = destinationRegion.height + destinationRegion.y - tOffy; // create the line buffer for pixel data if it is not large enough // or null if (pixbuf == null || pixbuf.length < cTileWidth * numBands) pixbuf = new int[cTileWidth * numBands]; boolean prog = false; // Deliver in lines to reduce memory usage for (int l = 0; l < cTileHeight; l++) { if (reader.getAbortRequest()) break; // Request line data for (int i = 0; i < numBands; i++) { if (reader.getAbortRequest()) break; DataBlkInt db = dataBlocks[i]; db.ulx = 0; db.uly = l; db.w = cTileWidth; db.h = 1; ictransf.getInternCompData(db, channelMap[sourceBands[i]]); prog = prog || db.progressive; int[] data = db.data; int k1 = db.offset + cTileWidth - 1; int fracBit = fracBits[i]; int lS = levelShift[i]; int min = minValues[i]; int max = maxValues[i]; if (ImageUtil.isBinary(sampleModel)) { // Force min max to 0 and 1. min = 0; max = 1; if (bytebuf == null || bytebuf.length < cTileWidth * numBands) bytebuf = new byte[cTileWidth * numBands]; for (int j = cTileWidth - 1; j >= 0; j--) { int tmp = (data[k1--] >> fracBit) + lS; bytebuf[j] = (byte) ((tmp < min) ? min : ((tmp > max) ? max : tmp)); } ImageUtil.setUnpackedBinaryData( bytebuf, raster, new Rectangle(tOffx, tOffy + l, cTileWidth, 1)); } else { for (int j = cTileWidth - 1; j >= 0; j--) { int tmp = (data[k1--] >> fracBit) + lS; pixbuf[j] = (tmp < min) ? min : ((tmp > max) ? max : tmp); } raster.setSamples(tOffx, tOffy + l, cTileWidth, 1, destinationBands[i], pixbuf); } } } } else { readSubsampledRaster(raster); } return raster; }