Path: blob/master/src/java.desktop/share/classes/javax/imageio/IIOParam.java
41152 views
/*1* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio;2627import java.awt.Point;28import java.awt.Rectangle;2930/**31* A superclass of all classes describing how streams should be32* decoded or encoded. This class contains all the variables and33* methods that are shared by {@code ImageReadParam} and34* {@code ImageWriteParam}.35*36* <p> This class provides mechanisms to specify a source region and a37* destination region. When reading, the source is the stream and38* the in-memory image is the destination. When writing, these are39* reversed. In the case of writing, destination regions may be used40* only with a writer that supports pixel replacement.41* <p>42* Decimation subsampling may be specified for both readers43* and writers, using a movable subsampling grid.44* <p>45* Subsets of the source and destination bands may be selected.46*47*/48public abstract class IIOParam {4950/**51* The source region, on {@code null} if none is set.52*/53protected Rectangle sourceRegion = null;5455/**56* The decimation subsampling to be applied in the horizontal57* direction. By default, the value is {@code 1}.58* The value must not be negative or 0.59*/60protected int sourceXSubsampling = 1;6162/**63* The decimation subsampling to be applied in the vertical64* direction. By default, the value is {@code 1}.65* The value must not be negative or 0.66*/67protected int sourceYSubsampling = 1;6869/**70* A horizontal offset to be applied to the subsampling grid before71* subsampling. The first pixel to be used will be offset this72* amount from the origin of the region, or of the image if no73* region is specified.74*/75protected int subsamplingXOffset = 0;7677/**78* A vertical offset to be applied to the subsampling grid before79* subsampling. The first pixel to be used will be offset this80* amount from the origin of the region, or of the image if no81* region is specified.82*/83protected int subsamplingYOffset = 0;8485/**86* An array of {@code int}s indicating which source bands87* will be used, or {@code null}. If {@code null}, the88* set of source bands to be used is as described in the comment89* for the {@code setSourceBands} method. No value should90* be allowed to be negative.91*/92protected int[] sourceBands = null;9394/**95* An {@code ImageTypeSpecifier} to be used to generate a96* destination image when reading, or to set the output color type97* when writing. If non has been set the value will be98* {@code null}. By default, the value is {@code null}.99*/100protected ImageTypeSpecifier destinationType = null;101102/**103* The offset in the destination where the upper-left decoded104* pixel should be placed. By default, the value is (0, 0).105*/106protected Point destinationOffset = new Point(0, 0);107108/**109* The default {@code IIOParamController} that will be110* used to provide settings for this {@code IIOParam}111* object when the {@code activateController} method112* is called. This default should be set by subclasses113* that choose to provide their own default controller,114* usually a GUI, for setting parameters.115*116* @see IIOParamController117* @see #getDefaultController118* @see #activateController119*/120protected IIOParamController defaultController = null;121122/**123* The {@code IIOParamController} that will be124* used to provide settings for this {@code IIOParam}125* object when the {@code activateController} method126* is called. This value overrides any default controller,127* even when null.128*129* @see IIOParamController130* @see #setController(IIOParamController)131* @see #hasController()132* @see #activateController()133*/134protected IIOParamController controller = null;135136/**137* Protected constructor may be called only by subclasses.138*/139protected IIOParam() {140controller = defaultController;141}142143/**144* Sets the source region of interest. The region of interest is145* described as a rectangle, with the upper-left corner of the146* source image as pixel (0, 0) and increasing values down and to147* the right. The actual number of pixels used will depend on148* the subsampling factors set by {@code setSourceSubsampling}.149* If subsampling has been set such that this number is zero,150* an {@code IllegalStateException} will be thrown.151*152* <p> The source region of interest specified by this method will153* be clipped as needed to fit within the source bounds, as well154* as the destination offsets, width, and height at the time of155* actual I/O.156*157* <p> A value of {@code null} for {@code sourceRegion}158* will remove any region specification, causing the entire image159* to be used.160*161* @param sourceRegion a {@code Rectangle} specifying the162* source region of interest, or {@code null}.163*164* @exception IllegalArgumentException if165* {@code sourceRegion} is non-{@code null} and either166* {@code sourceRegion.x} or {@code sourceRegion.y} is167* negative.168* @exception IllegalArgumentException if169* {@code sourceRegion} is non-{@code null} and either170* {@code sourceRegion.width} or171* {@code sourceRegion.height} is negative or 0.172* @exception IllegalStateException if subsampling is such that173* this region will have a subsampled width or height of zero.174*175* @see #getSourceRegion176* @see #setSourceSubsampling177* @see ImageReadParam#setDestinationOffset178* @see ImageReadParam#getDestinationOffset179*/180public void setSourceRegion(Rectangle sourceRegion) {181if (sourceRegion == null) {182this.sourceRegion = null;183return;184}185186if (sourceRegion.x < 0) {187throw new IllegalArgumentException("sourceRegion.x < 0!");188}189if (sourceRegion.y < 0){190throw new IllegalArgumentException("sourceRegion.y < 0!");191}192if (sourceRegion.width <= 0) {193throw new IllegalArgumentException("sourceRegion.width <= 0!");194}195if (sourceRegion.height <= 0) {196throw new IllegalArgumentException("sourceRegion.height <= 0!");197}198199// Throw an IllegalStateException if region falls between subsamples200if (sourceRegion.width <= subsamplingXOffset) {201throw new IllegalStateException202("sourceRegion.width <= subsamplingXOffset!");203}204if (sourceRegion.height <= subsamplingYOffset) {205throw new IllegalStateException206("sourceRegion.height <= subsamplingYOffset!");207}208209this.sourceRegion = (Rectangle)sourceRegion.clone();210}211212/**213* Returns the source region to be used. The returned value is214* that set by the most recent call to215* {@code setSourceRegion}, and will be {@code null} if216* there is no region set.217*218* @return the source region of interest as a219* {@code Rectangle}, or {@code null}.220*221* @see #setSourceRegion222*/223public Rectangle getSourceRegion() {224if (sourceRegion == null) {225return null;226}227return (Rectangle)sourceRegion.clone();228}229230/**231* Specifies a decimation subsampling to apply on I/O. The232* {@code sourceXSubsampling} and233* {@code sourceYSubsampling} parameters specify the234* subsampling period (<i>i.e.</i>, the number of rows and columns235* to advance after every source pixel). Specifically, a period of236* 1 will use every row or column; a period of 2 will use every237* other row or column. The {@code subsamplingXOffset} and238* {@code subsamplingYOffset} parameters specify an offset239* from the region (or image) origin for the first subsampled pixel.240* Adjusting the origin of the subsample grid is useful for avoiding241* seams when subsampling a very large source image into destination242* regions that will be assembled into a complete subsampled image.243* Most users will want to simply leave these parameters at 0.244*245* <p> The number of pixels and scanlines to be used are calculated246* as follows.247* <p>248* The number of subsampled pixels in a scanline is given by249* <p>250* {@code truncate[(width - subsamplingXOffset + sourceXSubsampling - 1)251* / sourceXSubsampling]}.252* <p>253* If the region is such that this width is zero, an254* {@code IllegalStateException} is thrown.255* <p>256* The number of scanlines to be used can be computed similarly.257*258* <p>The ability to set the subsampling grid to start somewhere259* other than the source region origin is useful if the260* region is being used to create subsampled tiles of a large image,261* where the tile width and height are not multiples of the262* subsampling periods. If the subsampling grid does not remain263* consistent from tile to tile, there will be artifacts at the tile264* boundaries. By adjusting the subsampling grid offset for each265* tile to compensate, these artifacts can be avoided. The tradeoff266* is that in order to avoid these artifacts, the tiles are not all267* the same size. The grid offset to use in this case is given by:268* <br>269* grid offset = [period - (region offset modulo period)] modulo period)270*271* <p> If either {@code sourceXSubsampling} or272* {@code sourceYSubsampling} is 0 or negative, an273* {@code IllegalArgumentException} will be thrown.274*275* <p> If either {@code subsamplingXOffset} or276* {@code subsamplingYOffset} is negative or greater than or277* equal to the corresponding period, an278* {@code IllegalArgumentException} will be thrown.279*280* <p> There is no {@code unsetSourceSubsampling} method;281* simply call {@code setSourceSubsampling(1, 1, 0, 0)} to282* restore default values.283*284* @param sourceXSubsampling the number of columns to advance285* between pixels.286* @param sourceYSubsampling the number of rows to advance between287* pixels.288* @param subsamplingXOffset the horizontal offset of the first subsample289* within the region, or within the image if no region is set.290* @param subsamplingYOffset the horizontal offset of the first subsample291* within the region, or within the image if no region is set.292* @exception IllegalArgumentException if either period is293* negative or 0, or if either grid offset is negative or greater than294* the corresponding period.295* @exception IllegalStateException if the source region is such that296* the subsampled output would contain no pixels.297*/298public void setSourceSubsampling(int sourceXSubsampling,299int sourceYSubsampling,300int subsamplingXOffset,301int subsamplingYOffset) {302if (sourceXSubsampling <= 0) {303throw new IllegalArgumentException("sourceXSubsampling <= 0!");304}305if (sourceYSubsampling <= 0) {306throw new IllegalArgumentException("sourceYSubsampling <= 0!");307}308if (subsamplingXOffset < 0 ||309subsamplingXOffset >= sourceXSubsampling) {310throw new IllegalArgumentException311("subsamplingXOffset out of range!");312}313if (subsamplingYOffset < 0 ||314subsamplingYOffset >= sourceYSubsampling) {315throw new IllegalArgumentException316("subsamplingYOffset out of range!");317}318319// Throw an IllegalStateException if region falls between subsamples320if (sourceRegion != null) {321if (subsamplingXOffset >= sourceRegion.width ||322subsamplingYOffset >= sourceRegion.height) {323throw new IllegalStateException("region contains no pixels!");324}325}326327this.sourceXSubsampling = sourceXSubsampling;328this.sourceYSubsampling = sourceYSubsampling;329this.subsamplingXOffset = subsamplingXOffset;330this.subsamplingYOffset = subsamplingYOffset;331}332333/**334* Returns the number of source columns to advance for each pixel.335*336* <p>If {@code setSourceSubsampling} has not been called, 1337* is returned (which is the correct value).338*339* @return the source subsampling X period.340*341* @see #setSourceSubsampling342* @see #getSourceYSubsampling343*/344public int getSourceXSubsampling() {345return sourceXSubsampling;346}347348/**349* Returns the number of rows to advance for each pixel.350*351* <p>If {@code setSourceSubsampling} has not been called, 1352* is returned (which is the correct value).353*354* @return the source subsampling Y period.355*356* @see #setSourceSubsampling357* @see #getSourceXSubsampling358*/359public int getSourceYSubsampling() {360return sourceYSubsampling;361}362363/**364* Returns the horizontal offset of the subsampling grid.365*366* <p>If {@code setSourceSubsampling} has not been called, 0367* is returned (which is the correct value).368*369* @return the source subsampling grid X offset.370*371* @see #setSourceSubsampling372* @see #getSubsamplingYOffset373*/374public int getSubsamplingXOffset() {375return subsamplingXOffset;376}377378/**379* Returns the vertical offset of the subsampling grid.380*381* <p>If {@code setSourceSubsampling} has not been called, 0382* is returned (which is the correct value).383*384* @return the source subsampling grid Y offset.385*386* @see #setSourceSubsampling387* @see #getSubsamplingXOffset388*/389public int getSubsamplingYOffset() {390return subsamplingYOffset;391}392393/**394* Sets the indices of the source bands to be used. Duplicate395* indices are not allowed.396*397* <p> A {@code null} value indicates that all source bands398* will be used.399*400* <p> At the time of reading, an401* {@code IllegalArgumentException} will be thrown by the402* reader or writer if a value larger than the largest available403* source band index has been specified or if the number of source404* bands and destination bands to be used differ. The405* {@code ImageReader.checkReadParamBandSettings} method may406* be used to automate this test.407*408* <p> Semantically, a copy is made of the array; changes to the409* array contents subsequent to this call have no effect on410* this {@code IIOParam}.411*412* @param sourceBands an array of integer band indices to be413* used.414*415* @exception IllegalArgumentException if {@code sourceBands}416* contains a negative or duplicate value.417*418* @see #getSourceBands419* @see ImageReadParam#setDestinationBands420* @see ImageReader#checkReadParamBandSettings421*/422public void setSourceBands(int[] sourceBands) {423if (sourceBands == null) {424this.sourceBands = null;425} else {426int numBands = sourceBands.length;427for (int i = 0; i < numBands; i++) {428int band = sourceBands[i];429if (band < 0) {430throw new IllegalArgumentException("Band value < 0!");431}432for (int j = i + 1; j < numBands; j++) {433if (band == sourceBands[j]) {434throw new IllegalArgumentException("Duplicate band value!");435}436}437438}439this.sourceBands = (sourceBands.clone());440}441}442443/**444* Returns the set of source bands to be used. The returned445* value is that set by the most recent call to446* {@code setSourceBands}, or {@code null} if there have447* been no calls to {@code setSourceBands}.448*449* <p> Semantically, the array returned is a copy; changes to450* array contents subsequent to this call have no effect on this451* {@code IIOParam}.452*453* @return the set of source bands to be used, or454* {@code null}.455*456* @see #setSourceBands457*/458public int[] getSourceBands() {459if (sourceBands == null) {460return null;461}462return (sourceBands.clone());463}464465/**466* Sets the desired image type for the destination image, using an467* {@code ImageTypeSpecifier}.468*469* <p> When reading, if the layout of the destination has been set470* using this method, each call to an {@code ImageReader}471* {@code read} method will return a new472* {@code BufferedImage} using the format specified by the473* supplied type specifier. As a side effect, any destination474* {@code BufferedImage} set by475* {@code ImageReadParam.setDestination(BufferedImage)} will476* no longer be set as the destination. In other words, this477* method may be thought of as calling478* {@code setDestination((BufferedImage)null)}.479*480* <p> When writing, the destination type maybe used to determine481* the color type of the image. The {@code SampleModel}482* information will be ignored, and may be {@code null}. For483* example, a 4-banded image could represent either CMYK or RGBA484* data. If a destination type is set, its485* {@code ColorModel} will override any486* {@code ColorModel} on the image itself. This is crucial487* when {@code setSourceBands} is used since the image's488* {@code ColorModel} will refer to the entire image rather489* than to the subset of bands being written.490*491* @param destinationType the {@code ImageTypeSpecifier} to492* be used to determine the destination layout and color type.493*494* @see #getDestinationType495*/496public void setDestinationType(ImageTypeSpecifier destinationType) {497this.destinationType = destinationType;498}499500/**501* Returns the type of image to be returned by the read, if one502* was set by a call to503* {@code setDestination(ImageTypeSpecifier)}, as an504* {@code ImageTypeSpecifier}. If none was set,505* {@code null} is returned.506*507* @return an {@code ImageTypeSpecifier} describing the508* destination type, or {@code null}.509*510* @see #setDestinationType511*/512public ImageTypeSpecifier getDestinationType() {513return destinationType;514}515516/**517* Specifies the offset in the destination image at which future518* decoded pixels are to be placed, when reading, or where a519* region will be written, when writing.520*521* <p> When reading, the region to be written within the522* destination {@code BufferedImage} will start at this523* offset and have a width and height determined by the source524* region of interest, the subsampling parameters, and the525* destination bounds.526*527* <p> Normal writes are not affected by this method, only writes528* performed using {@code ImageWriter.replacePixels}. For529* such writes, the offset specified is within the output stream530* image whose pixels are being modified.531*532* <p> There is no {@code unsetDestinationOffset} method;533* simply call {@code setDestinationOffset(new Point(0, 0))} to534* restore default values.535*536* @param destinationOffset the offset in the destination, as a537* {@code Point}.538*539* @exception IllegalArgumentException if540* {@code destinationOffset} is {@code null}.541*542* @see #getDestinationOffset543* @see ImageWriter#replacePixels544*/545public void setDestinationOffset(Point destinationOffset) {546if (destinationOffset == null) {547throw new IllegalArgumentException("destinationOffset == null!");548}549this.destinationOffset = (Point)destinationOffset.clone();550}551552/**553* Returns the offset in the destination image at which pixels are554* to be placed.555*556* <p> If {@code setDestinationOffsets} has not been called,557* a {@code Point} with zero X and Y values is returned558* (which is the correct value).559*560* @return the destination offset as a {@code Point}.561*562* @see #setDestinationOffset563*/564public Point getDestinationOffset() {565return (Point)destinationOffset.clone();566}567568/**569* Sets the {@code IIOParamController} to be used570* to provide settings for this {@code IIOParam}571* object when the {@code activateController} method572* is called, overriding any default controller. If the573* argument is {@code null}, no controller will be574* used, including any default. To restore the default, use575* {@code setController(getDefaultController())}.576*577* @param controller An appropriate578* {@code IIOParamController}, or {@code null}.579*580* @see IIOParamController581* @see #getController582* @see #getDefaultController583* @see #hasController584* @see #activateController()585*/586public void setController(IIOParamController controller) {587this.controller = controller;588}589590/**591* Returns whatever {@code IIOParamController} is currently592* installed. This could be the default if there is one,593* {@code null}, or the argument of the most recent call594* to {@code setController}.595*596* @return the currently installed597* {@code IIOParamController}, or {@code null}.598*599* @see IIOParamController600* @see #setController601* @see #getDefaultController602* @see #hasController603* @see #activateController()604*/605public IIOParamController getController() {606return controller;607}608609/**610* Returns the default {@code IIOParamController}, if there611* is one, regardless of the currently installed controller. If612* there is no default controller, returns {@code null}.613*614* @return the default {@code IIOParamController}, or615* {@code null}.616*617* @see IIOParamController618* @see #setController(IIOParamController)619* @see #getController620* @see #hasController621* @see #activateController()622*/623public IIOParamController getDefaultController() {624return defaultController;625}626627/**628* Returns {@code true} if there is a controller installed629* for this {@code IIOParam} object. This will return630* {@code true} if {@code getController} would not631* return {@code null}.632*633* @return {@code true} if a controller is installed.634*635* @see IIOParamController636* @see #setController(IIOParamController)637* @see #getController638* @see #getDefaultController639* @see #activateController()640*/641public boolean hasController() {642return (controller != null);643}644645/**646* Activates the installed {@code IIOParamController} for647* this {@code IIOParam} object and returns the resulting648* value. When this method returns {@code true}, all values649* for this {@code IIOParam} object will be ready for the650* next read or write operation. If {@code false} is651* returned, no settings in this object will have been disturbed652* (<i>i.e.</i>, the user canceled the operation).653*654* <p> Ordinarily, the controller will be a GUI providing a user655* interface for a subclass of {@code IIOParam} for a656* particular plug-in. Controllers need not be GUIs, however.657*658* @return {@code true} if the controller completed normally.659*660* @exception IllegalStateException if there is no controller661* currently installed.662*663* @see IIOParamController664* @see #setController(IIOParamController)665* @see #getController666* @see #getDefaultController667* @see #hasController668*/669public boolean activateController() {670if (!hasController()) {671throw new IllegalStateException("hasController() == false!");672}673return getController().activate(this);674}675}676677678