/** * Creates a copy of <code>param</code>. The source subsampling and and bands settings and the * destination bands and offset settings are copied. If <code>param</code> is a <code> * TIFFImageReadParam</code> then the <code>TIFFDecompressor</code> and <code>TIFFColorConverter * </code> settings are also copied; otherwise they are explicitly set to <code>null</code>. * * @param param the parameters to be copied. * @param copyTagSets whether the <code>TIFFTagSet</code> settings should be copied if set. * @return copied parameters. */ private ImageReadParam cloneImageReadParam(ImageReadParam param, boolean copyTagSets) { // Create a new TIFFImageReadParam. TIFFImageReadParam newParam = new TIFFImageReadParam(); // Copy the basic settings. newParam.setSourceSubsampling( param.getSourceXSubsampling(), param.getSourceYSubsampling(), param.getSubsamplingXOffset(), param.getSubsamplingYOffset()); newParam.setSourceBands(param.getSourceBands()); newParam.setDestinationBands(param.getDestinationBands()); newParam.setDestinationOffset(param.getDestinationOffset()); // Set the decompressor and color converter. if (param instanceof TIFFImageReadParam) { // Copy the settings from the input parameter. TIFFImageReadParam tparam = (TIFFImageReadParam) param; newParam.setTIFFDecompressor(tparam.getTIFFDecompressor()); newParam.setColorConverter(tparam.getColorConverter()); if (copyTagSets) { List tagSets = tparam.getAllowedTagSets(); if (tagSets != null) { Iterator tagSetIter = tagSets.iterator(); if (tagSetIter != null) { while (tagSetIter.hasNext()) { TIFFTagSet tagSet = (TIFFTagSet) tagSetIter.next(); newParam.addAllowedTagSet(tagSet); } } } } } else { // Set the decompressor and color converter to null. newParam.setTIFFDecompressor(null); newParam.setColorConverter(null); } return newParam; }
public TIFFRenderedImage( TIFFImageReader reader, int imageIndex, ImageReadParam readParam, int width, int height) throws IOException { this.reader = reader; this.imageIndex = imageIndex; this.tileParam = cloneImageReadParam(readParam, false); this.subsampleX = tileParam.getSourceXSubsampling(); this.subsampleY = tileParam.getSourceYSubsampling(); this.isSubsampling = this.subsampleX != 1 || this.subsampleY != 1; this.width = width / subsampleX; this.height = height / subsampleY; // If subsampling is being used, we may not match the // true tile grid exactly, but everything should still work this.tileWidth = reader.getTileWidth(imageIndex) / subsampleX; this.tileHeight = reader.getTileHeight(imageIndex) / subsampleY; Iterator iter = reader.getImageTypes(imageIndex); this.its = (ImageTypeSpecifier) iter.next(); tileParam.setDestinationType(its); }
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException { BufferedImage dst = null; try { // Calculate and return a Rectangle that identifies the region of // the // source image that should be read: // // 1. If param is null, the upper-left corner of the region is (0, // 0), // and the width and height are specified by the width and height // arguments. In other words, the entire image is read. // // 2. If param is not null // // 2.1 If param.getSourceRegion() returns a non-null Rectangle, the // region is calculated as the intersection of param's Rectangle // and the earlier (0, 0, width, height Rectangle). // // 2.2 param.getSubsamplingXOffset() is added to the region's x // coordinate and subtracted from its width. // // 2.3 param.getSubsamplingYOffset() is added to the region's y // coordinate and subtracted from its height. int width = getWidth(imageIndex); int height = getHeight(imageIndex); Rectangle sourceRegion = getSourceRegion(param, width, height); // Source subsampling is used to return a scaled-down source image. // Default 1 values for X and Y subsampling indicate that a // non-scaled // source image will be returned. int sourceXSubsampling = 1; int sourceYSubsampling = 1; // The destination offset determines the starting location in the // destination where decoded pixels are placed. Default (0, 0) // values indicate the upper-left corner. Point destinationOffset = new Point(0, 0); // If param is not null, override the source subsampling, and // destination offset defaults. if (param != null) { sourceXSubsampling = param.getSourceXSubsampling(); sourceYSubsampling = param.getSourceYSubsampling(); destinationOffset = param.getDestinationOffset(); } // Obtain a BufferedImage into which decoded pixels will be placed. // This destination will be returned to the application. // // 1. If param is not null // // 1.1 If param.getDestination() returns a BufferedImage // // 1.1.1 Return this BufferedImage // // Else // // 1.1.2 Invoke param.getDestinationType (). // // 1.1.3 If the returned ImageTypeSpecifier equals // getImageTypes (0) (see below), return its BufferedImage. // // 2. If param is null or a BufferedImage has not been obtained // // 2.1 Return getImageTypes (0)'s BufferedImage. dst = getDestination(param, getImageTypes(0), width, height); // Create a WritableRaster for the destination. WritableRaster wrDst = dst.getRaster(); JBIG2Bitmap bitmap = decoder .getPageAsJBIG2Bitmap(imageIndex) .getSlice(sourceRegion.x, sourceRegion.y, sourceRegion.width, sourceRegion.height); BufferedImage image = bitmap.getBufferedImage(); int newWidth = (int) (image.getWidth() * (1 / (double) sourceXSubsampling)); int newHeight = (int) (image.getHeight() * (1 / (double) sourceYSubsampling)); BufferedImage scaledImage = scaleImage(image.getRaster(), newWidth, newHeight, 1, 1); Raster raster = null; if (scaledImage != null) { raster = scaledImage.getRaster(); } else raster = image.getRaster(); wrDst.setRect(destinationOffset.x, destinationOffset.y, raster); } catch (RuntimeException e) { e.printStackTrace(); } return dst; }
public RawRenderedImage( RawImageInputStream iis, RawImageReader reader, ImageReadParam param, int imageIndex) throws IOException { this.iis = iis; this.reader = reader; this.param = param; this.imageIndex = imageIndex; this.position = iis.getImageOffset(imageIndex); this.originalDimension = iis.getImageDimension(imageIndex); ImageTypeSpecifier type = iis.getImageType(); sampleModel = originalSampleModel = type.getSampleModel(); colorModel = type.getColorModel(); // If the destination band is set used it sourceBands = (param == null) ? null : param.getSourceBands(); if (sourceBands == null) { nComp = originalSampleModel.getNumBands(); sourceBands = new int[nComp]; for (int i = 0; i < nComp; i++) sourceBands[i] = i; } else { sampleModel = originalSampleModel.createSubsetSampleModel(sourceBands); colorModel = ImageUtil.createColorModel(null, sampleModel); } nComp = sourceBands.length; destinationBands = (param == null) ? null : param.getDestinationBands(); if (destinationBands == null) { destinationBands = new int[nComp]; for (int i = 0; i < nComp; i++) destinationBands[i] = i; } Dimension dim = iis.getImageDimension(imageIndex); this.width = dim.width; this.height = dim.height; Rectangle sourceRegion = new Rectangle(0, 0, this.width, this.height); originalRegion = (Rectangle) sourceRegion.clone(); destinationRegion = (Rectangle) sourceRegion.clone(); if (param != null) { RawImageReader.computeRegionsWrapper( param, this.width, this.height, param.getDestination(), sourceRegion, destinationRegion); scaleX = param.getSourceXSubsampling(); scaleY = param.getSourceYSubsampling(); xOffset = param.getSubsamplingXOffset(); yOffset = param.getSubsamplingYOffset(); } sourceOrigin = new Point(sourceRegion.x, sourceRegion.y); if (!destinationRegion.equals(sourceRegion)) noTransform = false; this.tileDataSize = ImageUtil.getTileSize(originalSampleModel); this.tileWidth = originalSampleModel.getWidth(); this.tileHeight = originalSampleModel.getHeight(); this.tileGridXOffset = destinationRegion.x; this.tileGridYOffset = destinationRegion.y; this.originalNumXTiles = getNumXTiles(); this.width = destinationRegion.width; this.height = destinationRegion.height; this.minX = destinationRegion.x; this.minY = destinationRegion.y; sampleModel = sampleModel.createCompatibleSampleModel(tileWidth, tileHeight); maxXTile = originalDimension.width / tileWidth; maxYTile = originalDimension.height / tileHeight; }
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException { try { init(pIndex); processImageStarted(pIndex); // Some more waste of time and space... Dimension size = mSize; if (pParam != null) { // Source region // TODO: Maybe have to do some tests, to check if we are within bounds... Rectangle sourceRegion = pParam.getSourceRegion(); if (sourceRegion != null) { mImage = mImage.cropImage(sourceRegion); size = sourceRegion.getSize(); } // Subsampling if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) { int w = size.width / pParam.getSourceXSubsampling(); int h = size.height / pParam.getSourceYSubsampling(); mImage = mImage.sampleImage(w, h); size = new Dimension(w, h); } } if (abortRequested()) { processReadAborted(); return ImageUtil.createClear(size.width, size.height, null); } processImageProgress(10f); BufferedImage buffered = MagickUtil.toBuffered(mImage); processImageProgress(100f); /**/ // System.out.println("Created image: " + buffered); // System.out.println("ColorModel: " + buffered.getColorModel().getClass().getName()); // if (buffered.getColorModel() instanceof java.awt.image.IndexColorModel) { // java.awt.image.IndexColorModel cm = (java.awt.image.IndexColorModel) // buffered.getColorModel(); // for (int i = 0; i < cm.getMapSize(); i++) { // System.out.println("0x" + Integer.toHexString(cm.getRGB(i))); // } // } // */ /** * System.out.println("Colorspace: " + mImage.getColorspace()); System.out.println("Depth: " + * mImage.getDepth()); System.out.println("Format: " + mImage.getImageFormat()); * System.out.println("Type: " + mImage.getImageType()); System.out.println("IPTCProfile: " + * StringUtil.deepToString(mImage.getIptcProfile())); System.out.println("StorageClass: " + * mImage.getStorageClass()); // */ processImageComplete(); return buffered; } catch (MagickException e) { // Wrap in IIOException throw new IIOException(e.getMessage(), e); } }
/** * Load a specified a raster as a portion of the granule describe by this {@link * GranuleDescriptor}. * * @param imageReadParameters the {@link ImageReadParam} to use for reading. * @param index the index to use for the {@link ImageReader}. * @param cropBBox the bbox to use for cropping. * @param mosaicWorldToGrid the cropping grid to world transform. * @param request the incoming request to satisfy. * @param hints {@link Hints} to be used for creating this raster. * @return a specified a raster as a portion of the granule describe by this {@link * GranuleDescriptor}. * @throws IOException in case an error occurs. */ public GranuleLoadingResult loadRaster( final ImageReadParam imageReadParameters, final int index, final ReferencedEnvelope cropBBox, final MathTransform2D mosaicWorldToGrid, final RasterLayerRequest request, final Hints hints) throws IOException { if (LOGGER.isLoggable(java.util.logging.Level.FINER)) { final String name = Thread.currentThread().getName(); LOGGER.finer( "Thread:" + name + " Loading raster data for granuleDescriptor " + this.toString()); } ImageReadParam readParameters = null; int imageIndex; final ReferencedEnvelope bbox = inclusionGeometry != null ? new ReferencedEnvelope( granuleBBOX.intersection(inclusionGeometry.getEnvelopeInternal()), granuleBBOX.getCoordinateReferenceSystem()) : granuleBBOX; boolean doFiltering = false; if (filterMe) { doFiltering = Utils.areaIsDifferent(inclusionGeometry, baseGridToWorld, granuleBBOX); } // intersection of this tile bound with the current crop bbox final ReferencedEnvelope intersection = new ReferencedEnvelope( bbox.intersection(cropBBox), cropBBox.getCoordinateReferenceSystem()); if (intersection.isEmpty()) { if (LOGGER.isLoggable(java.util.logging.Level.FINE)) { LOGGER.fine( new StringBuilder("Got empty intersection for granule ") .append(this.toString()) .append(" with request ") .append(request.toString()) .append(" Resulting in no granule loaded: Empty result") .toString()); } return null; } ImageInputStream inStream = null; ImageReader reader = null; try { // // get info about the raster we have to read // // get a stream assert cachedStreamSPI != null : "no cachedStreamSPI available!"; inStream = cachedStreamSPI.createInputStreamInstance( granuleUrl, ImageIO.getUseCache(), ImageIO.getCacheDirectory()); if (inStream == null) return null; // get a reader and try to cache the relevant SPI if (cachedReaderSPI == null) { reader = ImageIOExt.getImageioReader(inStream); if (reader != null) cachedReaderSPI = reader.getOriginatingProvider(); } else reader = cachedReaderSPI.createReaderInstance(); if (reader == null) { if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) { LOGGER.warning( new StringBuilder("Unable to get s reader for granuleDescriptor ") .append(this.toString()) .append(" with request ") .append(request.toString()) .append(" Resulting in no granule loaded: Empty result") .toString()); } return null; } // set input reader.setInput(inStream); // Checking for heterogeneous granules if (request.isHeterogeneousGranules()) { // create read parameters readParameters = new ImageReadParam(); // override the overviews controller for the base layer imageIndex = ReadParamsController.setReadParams( request.getRequestedResolution(), request.getOverviewPolicy(), request.getDecimationPolicy(), readParameters, request.rasterManager, overviewsController); } else { imageIndex = index; readParameters = imageReadParameters; } // get selected level and base level dimensions final GranuleOverviewLevelDescriptor selectedlevel = getLevel(imageIndex, reader); // now create the crop grid to world which can be used to decide // which source area we need to crop in the selected level taking // into account the scale factors imposed by the selection of this // level together with the base level grid to world transformation AffineTransform2D cropWorldToGrid = new AffineTransform2D(selectedlevel.gridToWorldTransformCorner); cropWorldToGrid = (AffineTransform2D) cropWorldToGrid.inverse(); // computing the crop source area which lives into the // selected level raster space, NOTICE that at the end we need to // take into account the fact that we might also decimate therefore // we cannot just use the crop grid to world but we need to correct // it. final Rectangle sourceArea = CRS.transform(cropWorldToGrid, intersection).toRectangle2D().getBounds(); // gutter if (selectedlevel.baseToLevelTransform.isIdentity()) sourceArea.grow(2, 2); XRectangle2D.intersect( sourceArea, selectedlevel.rasterDimensions, sourceArea); // make sure roundings don't bother us // is it empty?? if (sourceArea.isEmpty()) { if (LOGGER.isLoggable(java.util.logging.Level.FINE)) { LOGGER.fine( "Got empty area for granuleDescriptor " + this.toString() + " with request " + request.toString() + " Resulting in no granule loaded: Empty result"); } return null; } else if (LOGGER.isLoggable(java.util.logging.Level.FINER)) { LOGGER.finer( "Loading level " + imageIndex + " with source region: " + sourceArea + " subsampling: " + readParameters.getSourceXSubsampling() + "," + readParameters.getSourceYSubsampling() + " for granule:" + granuleUrl); } // Setting subsampling int newSubSamplingFactor = 0; final String pluginName = cachedReaderSPI.getPluginClassName(); if (pluginName != null && pluginName.equals(ImageUtilities.DIRECT_KAKADU_PLUGIN)) { final int ssx = readParameters.getSourceXSubsampling(); final int ssy = readParameters.getSourceYSubsampling(); newSubSamplingFactor = ImageIOUtilities.getSubSamplingFactor2(ssx, ssy); if (newSubSamplingFactor != 0) { if (newSubSamplingFactor > maxDecimationFactor && maxDecimationFactor != -1) { newSubSamplingFactor = maxDecimationFactor; } readParameters.setSourceSubsampling(newSubSamplingFactor, newSubSamplingFactor, 0, 0); } } // set the source region readParameters.setSourceRegion(sourceArea); final RenderedImage raster; try { // read raster = request .getReadType() .read( readParameters, imageIndex, granuleUrl, selectedlevel.rasterDimensions, reader, hints, false); } catch (Throwable e) { if (LOGGER.isLoggable(java.util.logging.Level.FINE)) { LOGGER.log( java.util.logging.Level.FINE, "Unable to load raster for granuleDescriptor " + this.toString() + " with request " + request.toString() + " Resulting in no granule loaded: Empty result", e); } return null; } // use fixed source area sourceArea.setRect(readParameters.getSourceRegion()); // // setting new coefficients to define a new affineTransformation // to be applied to the grid to world transformation // ----------------------------------------------------------------------------------- // // With respect to the original envelope, the obtained planarImage // needs to be rescaled. The scaling factors are computed as the // ratio between the cropped source region sizes and the read // image sizes. // // place it in the mosaic using the coords created above; double decimationScaleX = ((1.0 * sourceArea.width) / raster.getWidth()); double decimationScaleY = ((1.0 * sourceArea.height) / raster.getHeight()); final AffineTransform decimationScaleTranform = XAffineTransform.getScaleInstance(decimationScaleX, decimationScaleY); // keep into account translation to work into the selected level raster space final AffineTransform afterDecimationTranslateTranform = XAffineTransform.getTranslateInstance(sourceArea.x, sourceArea.y); // now we need to go back to the base level raster space final AffineTransform backToBaseLevelScaleTransform = selectedlevel.baseToLevelTransform; // now create the overall transform final AffineTransform finalRaster2Model = new AffineTransform(baseGridToWorld); finalRaster2Model.concatenate(CoverageUtilities.CENTER_TO_CORNER); final double x = finalRaster2Model.getTranslateX(); final double y = finalRaster2Model.getTranslateY(); if (!XAffineTransform.isIdentity(backToBaseLevelScaleTransform, Utils.AFFINE_IDENTITY_EPS)) finalRaster2Model.concatenate(backToBaseLevelScaleTransform); if (!XAffineTransform.isIdentity(afterDecimationTranslateTranform, Utils.AFFINE_IDENTITY_EPS)) finalRaster2Model.concatenate(afterDecimationTranslateTranform); if (!XAffineTransform.isIdentity(decimationScaleTranform, Utils.AFFINE_IDENTITY_EPS)) finalRaster2Model.concatenate(decimationScaleTranform); // keep into account translation factors to place this tile finalRaster2Model.preConcatenate((AffineTransform) mosaicWorldToGrid); final Interpolation interpolation = request.getInterpolation(); // paranoiac check to avoid that JAI freaks out when computing its internal layouT on images // that are too small Rectangle2D finalLayout = ImageUtilities.layoutHelper( raster, (float) finalRaster2Model.getScaleX(), (float) finalRaster2Model.getScaleY(), (float) finalRaster2Model.getTranslateX(), (float) finalRaster2Model.getTranslateY(), interpolation); if (finalLayout.isEmpty()) { if (LOGGER.isLoggable(java.util.logging.Level.INFO)) LOGGER.info( "Unable to create a granuleDescriptor " + this.toString() + " due to jai scale bug creating a null source area"); return null; } ROI granuleLoadingShape = null; if (granuleROIShape != null) { final Point2D translate = mosaicWorldToGrid.transform(new DirectPosition2D(x, y), (Point2D) null); AffineTransform tx2 = new AffineTransform(); tx2.preConcatenate( AffineTransform.getScaleInstance( ((AffineTransform) mosaicWorldToGrid).getScaleX(), -((AffineTransform) mosaicWorldToGrid).getScaleY())); tx2.preConcatenate( AffineTransform.getScaleInstance( ((AffineTransform) baseGridToWorld).getScaleX(), -((AffineTransform) baseGridToWorld).getScaleY())); tx2.preConcatenate( AffineTransform.getTranslateInstance(translate.getX(), translate.getY())); granuleLoadingShape = (ROI) granuleROIShape.transform(tx2); } // apply the affine transform conserving indexed color model final RenderingHints localHints = new RenderingHints( JAI.KEY_REPLACE_INDEX_COLOR_MODEL, interpolation instanceof InterpolationNearest ? Boolean.FALSE : Boolean.TRUE); if (XAffineTransform.isIdentity(finalRaster2Model, Utils.AFFINE_IDENTITY_EPS)) { return new GranuleLoadingResult(raster, granuleLoadingShape, granuleUrl, doFiltering); } else { // // In case we are asked to use certain tile dimensions we tile // also at this stage in case the read type is Direct since // buffered images comes up untiled and this can affect the // performances of the subsequent affine operation. // final Dimension tileDimensions = request.getTileDimensions(); if (tileDimensions != null && request.getReadType().equals(ReadType.DIRECT_READ)) { final ImageLayout layout = new ImageLayout(); layout.setTileHeight(tileDimensions.width).setTileWidth(tileDimensions.height); localHints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout)); } else { if (hints != null && hints.containsKey(JAI.KEY_IMAGE_LAYOUT)) { final Object layout = hints.get(JAI.KEY_IMAGE_LAYOUT); if (layout != null && layout instanceof ImageLayout) { localHints.add( new RenderingHints(JAI.KEY_IMAGE_LAYOUT, ((ImageLayout) layout).clone())); } } } if (hints != null && hints.containsKey(JAI.KEY_TILE_CACHE)) { final Object cache = hints.get(JAI.KEY_TILE_CACHE); if (cache != null && cache instanceof TileCache) localHints.add(new RenderingHints(JAI.KEY_TILE_CACHE, (TileCache) cache)); } if (hints != null && hints.containsKey(JAI.KEY_TILE_SCHEDULER)) { final Object scheduler = hints.get(JAI.KEY_TILE_SCHEDULER); if (scheduler != null && scheduler instanceof TileScheduler) localHints.add(new RenderingHints(JAI.KEY_TILE_SCHEDULER, (TileScheduler) scheduler)); } boolean addBorderExtender = true; if (hints != null && hints.containsKey(JAI.KEY_BORDER_EXTENDER)) { final Object extender = hints.get(JAI.KEY_BORDER_EXTENDER); if (extender != null && extender instanceof BorderExtender) { localHints.add(new RenderingHints(JAI.KEY_BORDER_EXTENDER, (BorderExtender) extender)); addBorderExtender = false; } } // border extender if (addBorderExtender) { localHints.add(ImageUtilities.BORDER_EXTENDER_HINTS); } // boolean hasScaleX=!(Math.abs(finalRaster2Model.getScaleX()-1) < // 1E-2/(raster.getWidth()+1-raster.getMinX())); // boolean hasScaleY=!(Math.abs(finalRaster2Model.getScaleY()-1) < // 1E-2/(raster.getHeight()+1-raster.getMinY())); // boolean hasShearX=!(finalRaster2Model.getShearX() == 0.0); // boolean hasShearY=!(finalRaster2Model.getShearY() == 0.0); // boolean hasTranslateX=!(Math.abs(finalRaster2Model.getTranslateX()) < // 0.01F); // boolean hasTranslateY=!(Math.abs(finalRaster2Model.getTranslateY()) < // 0.01F); // boolean isTranslateXInt=!(Math.abs(finalRaster2Model.getTranslateX() - // (int) finalRaster2Model.getTranslateX()) < 0.01F); // boolean isTranslateYInt=!(Math.abs(finalRaster2Model.getTranslateY() - // (int) finalRaster2Model.getTranslateY()) < 0.01F); // // boolean isIdentity = finalRaster2Model.isIdentity() && // !hasScaleX&&!hasScaleY &&!hasTranslateX&&!hasTranslateY; // // TODO how can we check that the a skew is harmelss???? // if(isIdentity){ // // TODO check if we are missing anything like tiling or such that // comes from hints // return new GranuleLoadingResult(raster, granuleLoadingShape, // granuleUrl, doFiltering); // } // // // TOLERANCE ON PIXELS SIZE // // // Check and see if the affine transform is in fact doing // // a Translate operation. That is a scale by 1 and no rotation. // // In which case call translate. Note that only integer translate // // is applicable. For non-integer translate we'll have to do the // // affine. // // If the hints contain an ImageLayout hint, we can't use // // TranslateIntOpImage since it isn't capable of dealing with that. // // Get ImageLayout from renderHints if any. // ImageLayout layout = RIFUtil.getImageLayoutHint(localHints); // if ( !hasScaleX && // !hasScaleY && // !hasShearX&& // !hasShearY&& // isTranslateXInt&& // isTranslateYInt&& // layout == null) { // // It's a integer translate // return new GranuleLoadingResult(new TranslateIntOpImage(raster, // localHints, // (int) finalRaster2Model.getShearX(), // (int) // finalRaster2Model.getShearY()),granuleLoadingShape, granuleUrl, doFiltering); // } ImageWorker iw = new ImageWorker(raster); iw.setRenderingHints(localHints); iw.affine(finalRaster2Model, interpolation, request.getBackgroundValues()); return new GranuleLoadingResult( iw.getRenderedImage(), granuleLoadingShape, granuleUrl, doFiltering); } } catch (IllegalStateException e) { if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) { LOGGER.log( java.util.logging.Level.WARNING, new StringBuilder("Unable to load raster for granuleDescriptor ") .append(this.toString()) .append(" with request ") .append(request.toString()) .append(" Resulting in no granule loaded: Empty result") .toString(), e); } return null; } catch (org.opengis.referencing.operation.NoninvertibleTransformException e) { if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) { LOGGER.log( java.util.logging.Level.WARNING, new StringBuilder("Unable to load raster for granuleDescriptor ") .append(this.toString()) .append(" with request ") .append(request.toString()) .append(" Resulting in no granule loaded: Empty result") .toString(), e); } return null; } catch (TransformException e) { if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) { LOGGER.log( java.util.logging.Level.WARNING, new StringBuilder("Unable to load raster for granuleDescriptor ") .append(this.toString()) .append(" with request ") .append(request.toString()) .append(" Resulting in no granule loaded: Empty result") .toString(), e); } return null; } finally { try { if (request.getReadType() != ReadType.JAI_IMAGEREAD && inStream != null) { inStream.close(); } } finally { if (request.getReadType() != ReadType.JAI_IMAGEREAD && reader != null) { reader.dispose(); } } } }
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException { checkIndex(imageIndex); readHeader(); if (iis == null) throw new IllegalStateException("input is null"); BufferedImage img; clearAbortRequest(); processImageStarted(imageIndex); if (param == null) param = getDefaultReadParam(); sourceRegion = new Rectangle(0, 0, 0, 0); destinationRegion = new Rectangle(0, 0, 0, 0); computeRegions( param, this.width, this.height, param.getDestination(), sourceRegion, destinationRegion); scaleX = param.getSourceXSubsampling(); scaleY = param.getSourceYSubsampling(); // If the destination band is set used it sourceBands = param.getSourceBands(); destBands = param.getDestinationBands(); seleBand = (sourceBands != null) && (destBands != null); noTransform = destinationRegion.equals(new Rectangle(0, 0, width, height)) || seleBand; if (!seleBand) { sourceBands = new int[colorPlanes]; destBands = new int[colorPlanes]; for (int i = 0; i < colorPlanes; i++) destBands[i] = sourceBands[i] = i; } // If the destination is provided, then use it. Otherwise, create new one bi = param.getDestination(); // Get the image data. WritableRaster raster = null; if (bi == null) { if (sampleModel != null && colorModel != null) { sampleModel = sampleModel.createCompatibleSampleModel( destinationRegion.width + destinationRegion.x, destinationRegion.height + destinationRegion.y); if (seleBand) sampleModel = sampleModel.createSubsetSampleModel(sourceBands); raster = Raster.createWritableRaster(sampleModel, new Point(0, 0)); bi = new BufferedImage(colorModel, raster, false, null); } } else { raster = bi.getWritableTile(0, 0); sampleModel = bi.getSampleModel(); colorModel = bi.getColorModel(); noTransform &= destinationRegion.equals(raster.getBounds()); } byte bdata[] = null; // buffer for byte data if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE) bdata = (byte[]) ((DataBufferByte) raster.getDataBuffer()).getData(); readImage(bdata); if (abortRequested()) processReadAborted(); else processImageComplete(); return bi; }
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException { prepareRead(imageIndex, param); this.theImage = getDestination(param, getImageTypes(imageIndex), width, height); srcXSubsampling = imageReadParam.getSourceXSubsampling(); srcYSubsampling = imageReadParam.getSourceYSubsampling(); Point p = imageReadParam.getDestinationOffset(); dstXOffset = p.x; dstYOffset = p.y; // This could probably be made more efficient... Rectangle srcRegion = new Rectangle(0, 0, 0, 0); Rectangle destRegion = new Rectangle(0, 0, 0, 0); computeRegions(imageReadParam, width, height, theImage, srcRegion, destRegion); // Initial source pixel, taking source region and source // subsamplimg offsets into account sourceXOffset = srcRegion.x; sourceYOffset = srcRegion.y; pixelsToRead = destRegion.width * destRegion.height; pixelsRead = 0; processImageStarted(imageIndex); processImageProgress(0.0f); tilesAcross = (width + tileOrStripWidth - 1) / tileOrStripWidth; tilesDown = (height + tileOrStripHeight - 1) / tileOrStripHeight; int compression = getCompression(); // Attempt to get decompressor and color converted from the read param TIFFColorConverter colorConverter = null; if (imageReadParam instanceof TIFFImageReadParam) { TIFFImageReadParam tparam = (TIFFImageReadParam) imageReadParam; this.decompressor = tparam.getTIFFDecompressor(); colorConverter = tparam.getColorConverter(); } // If we didn't find one, use a standard decompressor if (this.decompressor == null) { if (compression == BaselineTIFFTagSet.COMPRESSION_NONE) { // Get the fillOrder field. TIFFField fillOrderField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); // Set the decompressor based on the fill order. if (fillOrderField != null && fillOrderField.getAsInt(0) == 2) { this.decompressor = new TIFFLSBDecompressor(); } else { this.decompressor = new TIFFNullDecompressor(); } } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) { this.decompressor = new TIFFFaxDecompressor(); } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4) { this.decompressor = new TIFFFaxDecompressor(); } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE) { this.decompressor = new TIFFFaxDecompressor(); } else if (compression == BaselineTIFFTagSet.COMPRESSION_PACKBITS) { if (DEBUG) { System.out.println("Using TIFFPackBitsDecompressor"); } this.decompressor = new TIFFPackBitsDecompressor(); } else if (compression == BaselineTIFFTagSet.COMPRESSION_LZW) { if (DEBUG) { System.out.println("Using TIFFLZWDecompressor"); } TIFFField predictorField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR); int predictor = ((predictorField == null) ? BaselineTIFFTagSet.PREDICTOR_NONE : predictorField.getAsInt(0)); this.decompressor = new TIFFLZWDecompressor(predictor); } else if (compression == BaselineTIFFTagSet.COMPRESSION_JPEG) { this.decompressor = new TIFFJPEGDecompressor(); } else if (compression == BaselineTIFFTagSet.COMPRESSION_ZLIB || compression == BaselineTIFFTagSet.COMPRESSION_DEFLATE) { TIFFField predictorField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR); int predictor = ((predictorField == null) ? BaselineTIFFTagSet.PREDICTOR_NONE : predictorField.getAsInt(0)); this.decompressor = new TIFFDeflateDecompressor(predictor); } else if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) { TIFFField JPEGProcField = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_PROC); if (JPEGProcField == null) { processWarningOccurred( "JPEGProc field missing; assuming baseline sequential JPEG process."); } else if (JPEGProcField.getAsInt(0) != BaselineTIFFTagSet.JPEG_PROC_BASELINE) { throw new IIOException( "Old-style JPEG supported for baseline sequential JPEG process only!"); } this.decompressor = new TIFFOldJPEGDecompressor(); // throw new IIOException("Old-style JPEG not supported!"); } else { throw new IIOException("Unsupported compression type (tag number = " + compression + ")!"); } if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR && compression != BaselineTIFFTagSet.COMPRESSION_JPEG && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) { boolean convertYCbCrToRGB = theImage.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB; TIFFDecompressor wrappedDecompressor = this.decompressor instanceof TIFFNullDecompressor ? null : this.decompressor; this.decompressor = new TIFFYCbCrDecompressor(wrappedDecompressor, convertYCbCrToRGB); } } if (DEBUG) { System.out.println("\nDecompressor class = " + decompressor.getClass().getName() + "\n"); } if (colorConverter == null) { if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB && theImage.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB) { colorConverter = new TIFFCIELabColorConverter(); } else if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR && !(this.decompressor instanceof TIFFYCbCrDecompressor) && compression != BaselineTIFFTagSet.COMPRESSION_JPEG && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) { colorConverter = new TIFFYCbCrColorConverter(imageMetadata); } } decompressor.setReader(this); decompressor.setMetadata(imageMetadata); decompressor.setImage(theImage); decompressor.setPhotometricInterpretation(photometricInterpretation); decompressor.setCompression(compression); decompressor.setSamplesPerPixel(samplesPerPixel); decompressor.setBitsPerSample(bitsPerSample); decompressor.setSampleFormat(sampleFormat); decompressor.setExtraSamples(extraSamples); decompressor.setColorMap(colorMap); decompressor.setColorConverter(colorConverter); decompressor.setSourceXOffset(sourceXOffset); decompressor.setSourceYOffset(sourceYOffset); decompressor.setSubsampleX(srcXSubsampling); decompressor.setSubsampleY(srcYSubsampling); decompressor.setDstXOffset(dstXOffset); decompressor.setDstYOffset(dstYOffset); decompressor.setSourceBands(sourceBands); decompressor.setDestinationBands(destinationBands); // Compute bounds on the tile indices for this source region. int minTileX = TIFFImageWriter.XToTileX(srcRegion.x, 0, tileOrStripWidth); int minTileY = TIFFImageWriter.YToTileY(srcRegion.y, 0, tileOrStripHeight); int maxTileX = TIFFImageWriter.XToTileX(srcRegion.x + srcRegion.width - 1, 0, tileOrStripWidth); int maxTileY = TIFFImageWriter.YToTileY(srcRegion.y + srcRegion.height - 1, 0, tileOrStripHeight); boolean isAbortRequested = false; if (planarConfiguration == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) { decompressor.setPlanar(true); int[] sb = new int[1]; int[] db = new int[1]; for (int tj = minTileY; tj <= maxTileY; tj++) { for (int ti = minTileX; ti <= maxTileX; ti++) { for (int band = 0; band < numBands; band++) { sb[0] = sourceBands[band]; decompressor.setSourceBands(sb); db[0] = destinationBands[band]; decompressor.setDestinationBands(db); // XXX decompressor.beginDecoding(); // The method abortRequested() is synchronized // so check it only once per loop just before // doing any actual decoding. if (abortRequested()) { isAbortRequested = true; break; } decodeTile(ti, tj, band); } if (isAbortRequested) break; reportProgress(); } if (isAbortRequested) break; } } else { // XXX decompressor.beginDecoding(); for (int tj = minTileY; tj <= maxTileY; tj++) { for (int ti = minTileX; ti <= maxTileX; ti++) { // The method abortRequested() is synchronized // so check it only once per loop just before // doing any actual decoding. if (abortRequested()) { isAbortRequested = true; break; } decodeTile(ti, tj, -1); reportProgress(); } if (isAbortRequested) break; } } if (isAbortRequested) { processReadAborted(); } else { processImageComplete(); } return theImage; }
/** * Tests the {@link OverviewsController} with support for different resolutions/different number * of overviews. * * <p>world_a.tif => Pixel Size = (0.833333333333333,-0.833333333333333); 4 overviews world_b.tif * => Pixel Size = (1.406250000000000,-1.406250000000000); 2 overviews * * @throws IOException * @throws MismatchedDimensionException * @throws FactoryException * @throws TransformException */ @Test public void testHeterogeneousGranules() throws IOException, MismatchedDimensionException, FactoryException, TransformException { final CoordinateReferenceSystem WGS84 = CRS.decode("EPSG:4326", true); final ReferencedEnvelope TEST_BBOX_A = new ReferencedEnvelope(-180, 0, -90, 90, WGS84); final ReferencedEnvelope TEST_BBOX_B = new ReferencedEnvelope(0, 180, 0, 90, WGS84); URL heterogeneousGranulesURL = TestData.url(this, "heterogeneous"); // // // // Initialize mosaic variables // // // final Hints hints = new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, WGS84); final AbstractGridFormat format = (AbstractGridFormat) GridFormatFinder.findFormat(heterogeneousGranulesURL, hints); Assert.assertNotNull(format); Assert.assertFalse("UknownFormat", format instanceof UnknownFormat); final ImageMosaicReader reader = (ImageMosaicReader) format.getReader(heterogeneousGranulesURL, hints); Assert.assertNotNull(reader); final int nOv = reader.getNumberOfOvervies(); final double[] hRes = reader.getHighestRes(); final RasterManager rasterManager = new RasterManager(reader); // // // // Initialize granules related variables // // // final File g1File = new File(DataUtilities.urlToFile(heterogeneousGranulesURL), "world_a.tif"); final File g2File = new File(DataUtilities.urlToFile(heterogeneousGranulesURL), "world_b.tif"); final ImageReadParam readParamsG1 = new ImageReadParam(); final ImageReadParam readParamsG2 = new ImageReadParam(); int imageIndexG1 = 0; int imageIndexG2 = 0; final GranuleDescriptor granuleDescriptor1 = new GranuleDescriptor(g1File.getAbsolutePath(), TEST_BBOX_A, spi, (Geometry) null, true); final GranuleDescriptor granuleDescriptor2 = new GranuleDescriptor(g2File.getAbsolutePath(), TEST_BBOX_B, spi, (Geometry) null, true); assertNotNull(granuleDescriptor1.toString()); assertNotNull(granuleDescriptor2.toString()); final OverviewsController ovControllerG1 = granuleDescriptor1.overviewsController; final OverviewsController ovControllerG2 = granuleDescriptor2.overviewsController; // // // // Initializing read request // // // final GeneralEnvelope envelope = reader.getOriginalEnvelope(); final GridEnvelope originalRange = reader.getOriginalGridRange(); final Rectangle rasterArea = new Rectangle( 0, 0, (int) Math.ceil(originalRange.getSpan(0) / 9.0), (int) Math.ceil(originalRange.getSpan(1) / 9.0)); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); final GridToEnvelopeMapper geMapper = new GridToEnvelopeMapper(range, envelope); geMapper.setPixelAnchor(PixelInCell.CELL_CENTER); final AffineTransform gridToWorld = geMapper.createAffineTransform(); final double requestedResolution[] = new double[] { XAffineTransform.getScaleX0(gridToWorld), XAffineTransform.getScaleY0(gridToWorld) }; TestSet at = null; if (nOv == 4 && Math.abs(hRes[0] - 0.833333333333) <= THRESHOLD) { at = at1; } else if (nOv == 2 && Math.abs(hRes[0] - 1.40625) <= THRESHOLD) { at = at2; } else { return; } // // // // Starting OverviewsController tests // // // final OverviewPolicy[] ovPolicies = new OverviewPolicy[] { OverviewPolicy.QUALITY, OverviewPolicy.SPEED, OverviewPolicy.NEAREST, OverviewPolicy.IGNORE }; for (int i = 0; i < ovPolicies.length; i++) { OverviewPolicy ovPolicy = ovPolicies[i]; LOGGER.info("Testing with OverviewPolicy = " + ovPolicy.toString()); imageIndexG1 = ReadParamsController.setReadParams( requestedResolution, ovPolicy, DecimationPolicy.ALLOW, readParamsG1, rasterManager, ovControllerG1); imageIndexG2 = ReadParamsController.setReadParams( requestedResolution, ovPolicy, DecimationPolicy.ALLOW, readParamsG2, rasterManager, ovControllerG2); assertSame(at.ot[i].g1.imageIndex, imageIndexG1); assertSame(at.ot[i].g2.imageIndex, imageIndexG2); assertSame(at.ot[i].g1.ssx, readParamsG1.getSourceXSubsampling()); assertSame(at.ot[i].g1.ssy, readParamsG1.getSourceYSubsampling()); assertSame(at.ot[i].g2.ssx, readParamsG2.getSourceXSubsampling()); assertSame(at.ot[i].g2.ssy, readParamsG2.getSourceYSubsampling()); } }
@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; }