private void initializeRead(int imageIndex, J2KImageReadParamJava param, J2KMetadata metadata) { try { iis.mark(); in = new IISRandomAccessIO(iis); // **** File Format **** // If the codestream is wrapped in the jp2 fileformat, Read the // file format wrapper ff = new FileFormatReader(in, metadata); ff.readFileFormat(); in.seek(ff.getFirstCodeStreamPos()); hi = new HeaderInfo(); try { hd = new HeaderDecoder(in, j2krparam, hi); } catch (EOFException e) { throw new RuntimeException(I18N.getString("J2KReadState2")); } catch (IOException ioe) { throw new RuntimeException(ioe); } this.width = hd.getImgWidth(); this.height = hd.getImgHeight(); Rectangle sourceRegion = param.getSourceRegion(); sourceOrigin = new Point(); sourceRegion = new Rectangle(hd.getImgULX(), hd.getImgULY(), this.width, this.height); // if the subsample rate for components are not consistent boolean compConsistent = true; stepX = hd.getCompSubsX(0); stepY = hd.getCompSubsY(0); for (int i = 1; i < nComp; i++) { if (stepX != hd.getCompSubsX(i) || stepY != hd.getCompSubsY(i)) throw new RuntimeException(I18N.getString("J2KReadState12")); } // Get minimum number of resolution levels available across // all tile-components. int minResLevels = hd.getDecoderSpecs().dls.getMin(); // Set current resolution level. this.resolution = param != null ? param.getResolution() : minResLevels; if (resolution < 0 || resolution > minResLevels) { resolution = minResLevels; } // Convert source region to lower resolution level. if (resolution != minResLevels || stepX != 1 || stepY != 1) { sourceRegion = J2KImageReader.getReducedRect(sourceRegion, minResLevels, resolution, stepX, stepY); } destinationRegion = (Rectangle) sourceRegion.clone(); J2KImageReader.computeRegionsWrapper( param, false, this.width, this.height, param.getDestination(), sourceRegion, destinationRegion); sourceOrigin = new Point(sourceRegion.x, sourceRegion.y); scaleX = param.getSourceXSubsampling(); scaleY = param.getSourceYSubsampling(); xOffset = param.getSubsamplingXOffset(); yOffset = param.getSubsamplingYOffset(); this.width = destinationRegion.width; this.height = destinationRegion.height; Point tileOffset = hd.getTilingOrigin(null); this.tileWidth = hd.getNomTileWidth(); this.tileHeight = hd.getNomTileHeight(); // Convert tile 0 to lower resolution level. if (resolution != minResLevels || stepX != 1 || stepY != 1) { Rectangle tileRect = new Rectangle(tileOffset); tileRect.width = tileWidth; tileRect.height = tileHeight; tileRect = J2KImageReader.getReducedRect(tileRect, minResLevels, resolution, stepX, stepY); tileOffset = tileRect.getLocation(); tileWidth = tileRect.width; tileHeight = tileRect.height; } tileXOffset = tileOffset.x; tileYOffset = tileOffset.y; // Set the tile step sizes. These values are used because it // is possible that tiles will be empty. In particular at lower // resolution levels when subsampling is used this may be the // case. This method of calculation will work at least for // Profile-0 images. if (tileWidth * (1 << (minResLevels - resolution)) * stepX > hd.getNomTileWidth()) { tileStepX = (tileWidth * (1 << (minResLevels - resolution)) * stepX + hd.getNomTileWidth() - 1) / hd.getNomTileWidth(); } else { tileStepX = 1; } if (tileHeight * (1 << (minResLevels - resolution)) * stepY > hd.getNomTileHeight()) { tileStepY = (tileHeight * (1 << (minResLevels - resolution)) * stepY + hd.getNomTileHeight() - 1) / hd.getNomTileHeight(); } else { tileStepY = 1; } if (!destinationRegion.equals(sourceRegion)) noTransform = false; // **** Header decoder **** // Instantiate header decoder and read main header decSpec = hd.getDecoderSpecs(); // **** Instantiate decoding chain **** // Get demixed bitdepths nComp = hd.getNumComps(); int[] depth = new int[nComp]; for (int i = 0; i < nComp; i++) depth[i] = hd.getOriginalBitDepth(i); // Get channel mapping ChannelDefinitionBox cdb = null; if (metadata != null) cdb = (ChannelDefinitionBox) metadata.getElement("JPEG2000ChannelDefinitionBox"); channelMap = new int[nComp]; if (cdb != null && metadata.getElement("JPEG2000PaletteBox") == null) { short[] assoc = cdb.getAssociation(); short[] types = cdb.getTypes(); short[] channels = cdb.getChannel(); for (int i = 0; i < types.length; i++) if (types[i] == 0) channelMap[channels[i]] = assoc[i] - 1; else if (types[i] == 1 || types[i] == 2) channelMap[channels[i]] = channels[i]; } else { for (int i = 0; i < nComp; i++) channelMap[i] = i; } // **** Bitstream reader **** try { boolean logJJ2000Messages = Boolean.getBoolean("jj2000.j2k.decoder.log"); breader = BitstreamReaderAgent.createInstance(in, hd, j2krparam, decSpec, logJJ2000Messages, hi); } catch (IOException e) { throw new RuntimeException( I18N.getString("J2KReadState3") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } catch (IllegalArgumentException e) { throw new RuntimeException( I18N.getString("J2KReadState4") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } // **** Entropy decoder **** try { entdec = hd.createEntropyDecoder(breader, j2krparam); } catch (IllegalArgumentException e) { throw new RuntimeException( I18N.getString("J2KReadState5") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } // **** ROI de-scaler **** try { roids = hd.createROIDeScaler(entdec, j2krparam, decSpec); } catch (IllegalArgumentException e) { throw new RuntimeException( I18N.getString("J2KReadState6") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } // **** Dequantizer **** try { deq = hd.createDequantizer(roids, depth, decSpec); } catch (IllegalArgumentException e) { throw new RuntimeException( I18N.getString("J2KReadState7") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } // **** Inverse wavelet transform *** try { // full page inverse wavelet transform invWT = InverseWT.createInstance(deq, decSpec); } catch (IllegalArgumentException e) { throw new RuntimeException( I18N.getString("J2KReadState8") + " " + ((e.getMessage() != null) ? (":\n" + e.getMessage()) : "")); } int res = breader.getImgRes(); int mrl = decSpec.dls.getMin(); invWT.setImgResLevel(res); // **** Data converter **** (after inverse transform module) converter = new ImgDataConverter(invWT, 0); // **** Inverse component transformation **** ictransf = new InvCompTransf(converter, decSpec, depth); // If the destination band is set used it sourceBands = j2krparam.getSourceBands(); if (sourceBands == null) { sourceBands = new int[nComp]; for (int i = 0; i < nComp; i++) sourceBands[i] = i; } nComp = sourceBands.length; destinationBands = j2krparam.getDestinationBands(); if (destinationBands == null) { destinationBands = new int[nComp]; for (int i = 0; i < nComp; i++) destinationBands[i] = i; } J2KImageReader.checkReadParamBandSettingsWrapper( param, hd.getNumComps(), destinationBands.length); levelShift = new int[nComp]; minValues = new int[nComp]; maxValues = new int[nComp]; fracBits = new int[nComp]; dataBlocks = new DataBlkInt[nComp]; depth = new int[nComp]; bandOffsets = new int[nComp]; maxDepth = 0; isSigned = false; for (int i = 0; i < nComp; i++) { depth[i] = hd.getOriginalBitDepth(sourceBands[i]); if (depth[i] > maxDepth) maxDepth = depth[i]; dataBlocks[i] = new DataBlkInt(); // XXX: may need to change if ChannelDefinition is used to // define the color channels, such as BGR order bandOffsets[i] = i; if (hd.isOriginalSigned(sourceBands[i])) isSigned = true; else { levelShift[i] = 1 << (ictransf.getNomRangeBits(sourceBands[i]) - 1); } // Get the number of bits in the image, and decide what the max // value should be, depending on whether it is signed or not int nomRangeBits = ictransf.getNomRangeBits(sourceBands[i]); maxValues[i] = (1 << (isSigned == true ? (nomRangeBits - 1) : nomRangeBits)) - 1; minValues[i] = isSigned ? -(maxValues[i] + 1) : 0; fracBits[i] = ictransf.getFixedPoint(sourceBands[i]); } iis.reset(); } catch (IllegalArgumentException e) { throw new RuntimeException(e.getMessage(), e); } catch (Error e) { if (e.getMessage() != null) throw new RuntimeException(e.getMessage(), e); else { throw new RuntimeException(I18N.getString("J2KReadState9"), e); } } catch (RuntimeException e) { if (e.getMessage() != null) throw new RuntimeException(I18N.getString("J2KReadState10") + " " + e.getMessage(), e); else { throw new RuntimeException(I18N.getString("J2KReadState10"), e); } } catch (Throwable e) { throw new RuntimeException(I18N.getString("J2KReadState10"), e); } }
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; }