001/*
002 * $RCSfile: J2KImageWriteParamJava.java,v $
003 *
004 * 
005 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
006 * 
007 * Redistribution and use in source and binary forms, with or without
008 * modification, are permitted provided that the following conditions
009 * are met: 
010 * 
011 * - Redistribution of source code must retain the above copyright 
012 *   notice, this  list of conditions and the following disclaimer.
013 * 
014 * - Redistribution in binary form must reproduce the above copyright
015 *   notice, this list of conditions and the following disclaimer in 
016 *   the documentation and/or other materials provided with the
017 *   distribution.
018 * 
019 * Neither the name of Sun Microsystems, Inc. or the names of 
020 * contributors may be used to endorse or promote products derived 
021 * from this software without specific prior written permission.
022 * 
023 * This software is provided "AS IS," without a warranty of any 
024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035 * POSSIBILITY OF SUCH DAMAGES. 
036 * 
037 * You acknowledge that this software is not designed or intended for 
038 * use in the design, construction, operation or maintenance of any 
039 * nuclear facility. 
040 *
041 * $Revision: 1.2 $
042 * $Date: 2006/09/20 23:23:30 $
043 * $State: Exp $
044 */
045package com.github.jaiimageio.jpeg2000.impl;
046
047import java.awt.Rectangle;
048import java.awt.image.Raster;
049import java.awt.image.RenderedImage;
050import java.util.Locale;
051
052import javax.imageio.IIOImage;
053import javax.imageio.ImageWriteParam;
054
055import jj2000.j2k.IntegerSpec;
056import jj2000.j2k.ModuleSpec;
057import jj2000.j2k.StringSpec;
058import jj2000.j2k.entropy.CBlkSizeSpec;
059import jj2000.j2k.entropy.PrecinctSizeSpec;
060import jj2000.j2k.entropy.ProgressionSpec;
061import jj2000.j2k.entropy.encoder.LayersInfo;
062import jj2000.j2k.image.forwcomptransf.ForwCompTransfSpec;
063import jj2000.j2k.quantization.GuardBitsSpec;
064import jj2000.j2k.quantization.QuantStepSizeSpec;
065import jj2000.j2k.quantization.QuantTypeSpec;
066import jj2000.j2k.roi.MaxShiftSpec;
067import jj2000.j2k.wavelet.analysis.AnWTFilterSpec;
068
069import com.github.jaiimageio.jpeg2000.J2KImageWriteParam;
070
071/**
072 * A subclass of <code>ImageWriteParam</code> for writing images in
073 * the JPEG 2000 format.
074 *
075 * <p>JPEG 2000 plugin supports to losslessly or lossy compress gray-scale,
076 * RGB, and RGBA images with byte, unsigned short or short data type.  It also
077 * supports losslessly compress bilevel, and 8-bit indexed.  The result data
078 * is in the format of JP2 (JPEG 2000 Part 1 or baseline format).
079 *
080 * <p>Many encoding parameters for JPEG 2000 can be tile-component specific.
081 * These parameters are marked as <code>Yes</code> in the column <code>
082 * TC_SPEC</code> in the following parameter table.
083 * They must be provided according to the pattern:
084 * [&lt;tile-component idx>] &lt;param&gt; (repeated as many time as needed),
085 * where &lt;tile-component idx&gt; respect the following policy according to
086 * the degree of priority:
087 * <table>
088 * <tr><td>(1) t&lt;idx&gt; c&lt;idx&gt; : Tile-component specification.</td></tr>
089 * <tr><td>(2) t&lt;idx&gt; : Tile specification.</td></tr>
090 * <tr><td>(3) c&lt;idx&gt; : Component specification.</td></tr>
091 * <tr><td>(4) &lt;void&gt; : Default specification.</td></tr>
092 * </table>
093 * <p>Where the priorities of the specifications are:
094 * (1) > (2) > (3) > (4), (">" means "overrides")
095 *  &lt;idx&gt;: "," separates indexes, "-" separates bounds of indexes list.
096 *  (for example, 0,2-4 means indexes 0,2,3 and  4).
097 *
098 * <p>The parameters for encoding JPEG 2000 are listed in the following table:
099 *
100 *  * <p><table border=1>
101 * <caption><b>JPEG 2000 Plugin Decoding Parameters</b></caption>
102 * <tr><th>Parameter Name</th> <th>Description</th><th>TC_SPEC</th></tr>
103 * <tr>
104 *    <td>encodingRate</td>
105 *    <td> The bitrate in bits-per-pixel for encoding.  Should be set when
106 *    lossy compression scheme is used.  With the default value
107 *    <code>Double.MAX_VALUE</code>, a lossless compression will be done.
108 *    </td>
109 *    <td>No</td>
110 * </tr>
111 * <tr>
112 *    <td>lossless</td>
113 *    <td> Indicates using the loseless scheme or not.  It is equivalent to
114 *    use reversible quantization and 5x3 integer wavelet filters.  The
115 *    default is <code>true</code>.
116 *    </td>
117 *    <td>No</td>
118 * </tr>
119 * <tr>
120 *    <td>componentTransformation</td>
121 *    <td> Specifies to utilize the component transformation on some tiles.
122 *    If the wavelet transform is reversible (w5x3 filter), the Reversible
123 *    Component Transformation (RCT) is applied. If not reversible
124 *    (w9x7 filter), the Irreversible Component Transformation (ICT) is used.
125 *    </td>
126 *    <td>Yes, Tile_Specific</td>
127 * </tr>
128 * <tr>
129 *    <td>filters</td>
130 *    <td> Specifies which wavelet filters to use for the specified
131 *    tile-components.  JPEG 2000 part I only supports w5x3 and w9x7 filters.
132 *    </td>
133 *    <td>Yes</td>
134 * </tr>
135 * <tr>
136 *    <td>decompositionLevel</td>
137 *    <td> Specifies the wavelet decomposition levels to apply to
138 *    the image.  If it is 0, no wavelet transform is performed, in which
139 *    case the original image data will be sent to the encoder and an example
140 *    is the binary data.  All components and all tiles have the same number
141 *    of decomposition levels.  The default value is 5.
142 *    </td>
143 *    <td>No</td>
144 * </tr>
145 * <tr>
146 *    <td>guardBits</td>
147 *    <td> The number of bits used for each tile-component in the quantizer
148 *    to avoid overflow.  It takes values in the range 0 through 7.  The
149 *    default value is 2.
150 *    </td>
151 *    <td>Yes</td>
152 * </tr>
153 * <tr>
154 *    <td>quantizationStep</td>
155 *    <td> This parameter specifies the base normalized quantization step
156 *    size for the tiles/components.  It is normalized to a dynamic range
157 *    of 1 in the image domain.  This parameter is ignored in reversible
158 *    coding.  The default value is 0.0078125.
159 *    </td>
160 *    <td>Yes</td>
161 * </tr>
162 * <tr>
163 *    <td>quantizationType</td>
164 *    <td> Specifies which quantization type to use for specified
165 *    tiles/components.  Not specified for lossless compression.  By default,
166 *    the quantization step size is "expounded".  Supported quantization
167 *    types specification are : "reversible" (no quantization), "derived"
168 *    (derived quantization step size) and "expounded".
169 *    </td>
170 *    <td>Yes</td>
171 * </tr>
172 * <tr>
173 *    <td>codeBlockSize</td>
174 *    <td> Specifies the maximum code-block size to use for tile-component.
175 *    The maximum width and height is 1024, however the block size
176 *    (i.e. width x height) must not exceed 4096.  The minimum width and
177 *    height is 4.  The default values are (64, 64).
178 *    </td>
179 *    <td>Yes</td>
180 * </tr>
181 * <tr>
182 *    <td>progressionType</td>
183 *    <td> Specifies which type of progression should be used when generating
184 *    the codestream.
185 *    <p> The format is [&lt;tile index&gt;]
186 *    res|layer|res-pos|pos-comp|comp-pos [res_start comp_start layer_end
187 *    res_end comp_end prog] [[res_start comp_start layer_end res_end
188 *    comp_end prog]...] [[&lt;tile-component idx]...].
189 *    <p>The value "res" generates a resolution progressive
190 *    codestream with the number of layers specified by "layers" parameter.
191 *    The value "layer" generates a layer progressive codestream with
192 *    multiple layers.  In any case, the rate-allocation algorithm optimizes
193 *    for best quality in each layer.  The quality measure is mean squared
194 *    error (MSE) or a weighted version of it (WMSE).  If no progression
195 *    type is specified or imposed by other parameters, the default value
196 *    is "layer".  It is also possible to describe progression order
197 *    changes.  In this case, "res_start" is the index (from 0) of the
198 *    first resolution level, "comp_start" is the index (from 0) of the
199 *    first component, "layer_end" is the index (from 0) of the first layer
200 *    not included, "res_end" is the index (from 0) of the first
201 *    resolution level not included, "comp_end" is index (from 0) of
202 *    the first component not included and "prog" is the progression type
203 *    to be used for the rest of the tile/image.  Several progression
204 *    order changes can be specified, one after the other.
205 *    </td>
206 *    <td>Yes</td>
207 * </tr>
208 * <tr>
209 *    <td>packPacketHeaderInTile</td>
210 *    <td> Indicates that the packet headers are packed in the tiles' headers.
211 *    The default is false.
212 *    </td>
213 *    <td>No</td>
214 * </tr>
215 * <tr>
216 *    <td>packPacketHeaderInMain</td>
217 *    <td> Indicates that the packet headers are packed in the main header.
218 *    The default is false.
219 *    </td>
220 *    <td>No</td>
221 * </tr>
222 * <tr>
223 *    <td>packetPerTilePart</td>
224 *    <td> Specifies the maximum number of packets to be put into one tile-part.
225 *    Zero means putting all packets in the first tile-part of each tile.
226 *    </td>
227 *    <td>No</td>
228 * </tr>
229 * <tr>
230 *    <td>ROIs</td>
231 *    <td> Specifies ROIs shape and location.  The component index specifies
232 *    which components contain the ROI.  If this parameter is used, the
233 *    codestream is layer progressive by default unless it is overridden by
234 *    the <code>progressionType</code>.  A rectanglar or circular ROI can be
235 *    specified in the format: [&lt;component idx&gt;] R &lt;left&gt;
236 *    &lt;top&gt; &lt;width&gt; &lt;height&gt; or [&lt;component idx&gt;] C
237 *    &lt;center x&gt; &lt;center y&gt; &lt;radius&gt;. An arbitrary shape
238 *    can be assigned by [&lt;component idx&gt;] A &lt;PGM file&gt;
239 *    </td>
240 *    <td>Yes, component-specified</td>
241 * </tr>
242 * <tr>
243 *    <td>startLevelROI</td>
244 *    <td> This parameter defines the lowest resolution levels to belong to
245 *    the ROI.  By doing this, it is possible to avoid getting
246 *    information for the ROI at an early stage of transmission.
247 *    startLevelROI = 0 means the lowest resolution level belongs to
248 *    the ROI, 1 means the second lowest etc.  The default values, -1,
249 *    deactivates this parameter.
250 *    </td>
251 *    <td>No</td>
252 * </tr>
253 * <tr>
254 *    <td>alignROI</td>
255 *    <td> By specifying this parameter, the ROI mask will be limited to
256 *    covering only entire code-blocks.  The ROI coding can then be
257 *    performed without any actual scaling of the coefficients but by
258 *    instead scaling the distortion estimates.
259 *    </td>
260 *    <td>No</td>
261 * </tr>
262 * <tr>
263 *    <td>bypass</td>
264 *    <td> Uses the lazy coding mode with the entropy coder.  This will bypass
265 *    the MQ coder for some of the coding passes, where the distribution
266 *    is often close to uniform.  Since the MQ codeword will be terminated
267 *    at least once per lazy pass, it is important to use an efficient
268 *    termination algorithm, <code>methodForMQTermination</code>.
269 *    true enables, and false disables it.  The default value is false.
270 *    </td>
271 *    <td>Yes</td>
272 * </tr>
273 * <tr>
274 *    <td>resetMQ</td>
275 *    <td> If this is enabled the probability estimates of the MQ coder are
276 *    reset after each arithmetically coded (i.e. non-lazy) coding pass.
277 *    true enables, and false disables it.  The default value is false.
278 *    </td>
279 *    <td>Yes</td>
280 * </tr>
281 * <tr>
282 *    <td>terminateOnByte</td>
283 *    <td> If this is enabled the codeword (raw or MQ) is terminated on a byte
284 *    boundary after each coding pass. In this case it is important to use
285 *    an efficient termination algorithm, "methodForMQTermination".
286 *    true enables, and false disables it.  The default value is false.
287 *    </td>
288 *    <td>Yes</td>
289 * </tr>
290 * <tr>
291 *    <td>causalCXInfo</td>
292 *    <td> Uses vertically stripe causal context formation.  If this is
293 *    enabled the context formation process in one stripe is independant of
294 *    the next stripe (i.e. the one below it). true enables, and false
295 *    disables it.  The default value is false.
296 *    </td>
297 *    <td>Yes</td>
298 * </tr>
299 * <tr>
300 *    <td>codeSegSymbol</td>
301 *    <td> Inserts an error resilience segmentation symbol in the MQ codeword
302 *    at the end of each bit-plane (cleanup pass). Decoders can use this
303 *    information to detect and conceal errors. true enables, and false
304 *    disables it.  The default value is false.
305 *    </td>
306 *    <td>Yes</td>
307 * </tr>
308 * <tr>
309 *    <td>methodForMQTermination</td>
310 *    <td> Specifies the algorithm used to terminate the MQ codeword.  The
311 *    most efficient one is "near_opt", which delivers a codeword which
312 *    in almost all cases is the shortest possible.  The "easy" is a
313 *    simpler algorithm that delivers a codeword length that is close
314 *    to the previous one (in average 1 bit longer).  The "predict" is
315 *    almost the same as the "easy" but it leaves error resilient
316 *    information on the spare least significant bits (in average 3.5 bits),
317 *    which can be used by a decoder to detect errors.  The "full" algorithm
318 *    performs a full flush of the MQ coder and is highly inefficient.  It
319 *    is important to use a good termination policy since the MQ codeword
320 *    can be terminated quite often, specially if the "bypass" or
321 *    "terminateOnByte" parameters are enabled (in the normal case it would
322 *    be terminated once per code-block, while "terminateOnByte" is specified
323 *    it will be done almost 3 times per bit-plane in each code-block).
324 *    The default value is "near_opt".
325 *    </td>
326 *    <td>Yes</td>
327 * </tr>
328 * <tr>
329 *    <td>methodForMQLengthCalc</td>
330 *    <td> Specifies the algorithm to use in calculating the necessary MQ
331 *    length for each decoding pass.  The best one is "near_opt", which
332 *    performs a rather sophisticated calculation and provides the best
333 *    results.  The "lazy_good" and "lazy" are very simple algorithms
334 *    that provide rather conservative results. "lazy_good" performs
335 *    slightly better.  Please use the default unless the experiments
336 *    show the benefits of different length calculation algorithms.
337 *    The default value is "near_opt".
338 *    </td>
339 *    <td>Yes</td>
340 * </tr>
341 * <tr>
342 *    <td>precinctPartition</td>
343 *    <td> Specifies precinct partition dimensions for tiles/components.  They
344 *    are stored from those applied to the highest resolution to those
345 *    applied to the remaining resolutions in decreasing order.  If less
346 *    values than the number of decomposition levels are specified, then
347 *    the last two values are used for the remaining resolutions.
348 *    </td>
349 *    <td>Yes</td>
350 * </tr>
351 * <tr>
352 *    <td>layers</td>
353 *    <td> Explicitly specifies the codestream layer formation parameters.
354 *    The rate (double) parameter specifies the bitrate to which the first
355 *    layer should be optimized.  The layers (int) parameter, if present,
356 *    specifies the number of extra layers that should be added for
357 *    scalability.  These extra layers are not optimized.  Any extra rate
358 *    and layers parameters add more layers, in the same way.  An
359 *    additional layer is always added at the end, which is optimized
360 *    to the overall target bitrate of the bit stream. Any layers
361 *    (optimized or not) whose target bitrate is higher that the overall
362 *    target bitrate are silently ignored. The bitrates of the extra layers
363 *    that are added through the layers parameter are approximately
364 *    log-spaced between the other target bitrates.  If several (rate, layers)
365 *    constructs appear the rate parameters must appear in increasing order.
366 *    The rate allocation algorithm ensures that all coded layers have a
367 *    minimal reasonable size, if not these layers are silently ignored.
368 *    Default: 0.015 +20 2.0 +10.
369 *    </td>
370 *    <td>No</td>
371 * </tr>
372 * <tr>
373 *    <td>SOP</td>
374 *    <td>Specifies whether start of packet (SOP) markers should be used.
375 *    true enables, false disables it.  The default value is false.
376 *    </td>
377 *    <td>Yes</td>
378 * </tr>
379 * <tr>
380 *    <td>EPH</td>
381 *    <td>Specifies whether end of packet header (EPH) markers should be used.
382 *    true enables, false disables it.  The default value is false.
383 *    </td>
384 *    <td>Yes</td>
385 * </tr>
386 * </table>
387 */
388public class J2KImageWriteParamJava extends ImageWriteParam {
389    /**
390     * Indicates that the packet headers are packed in the tiles' headers.
391     */
392    private boolean packPacketHeaderInTile = false;
393
394    /**
395     * Indicates that the packet headers are packed in the main header.
396     */
397    private boolean packPacketHeaderInMain = false;
398
399    /**
400     * Specifies the maximum number of packets to be put into one tile-part.
401     * Zero means include all packets in first tile-part of each tile.
402     */
403    private int packetPerTilePart = 0;
404
405    /**
406     * The bitrate in bits-per-pixel for encoding.  Should be set when lossy
407     * compression scheme is used.  The default is
408     * <code>Double.MAX_VALUE</code>.
409     */
410    private double encodingRate = Double.MAX_VALUE;
411
412    /**
413     * Indicates using the loseless scheme or not.  It is equivalent to
414     * use reversible quantization and 5x3 integer wavelet filters.
415     */
416    private boolean lossless = true;
417
418    /** Specifies to utilize the component transformation with some tiles.
419     *  If the wavelet transform is reversible (w5x3 filter), the
420     *  Reversible Component Transformation (RCT) is applied. If not reversible
421     *  (w9x7 filter), the Irreversible Component Transformation (ICT)
422     *  is used.
423     */
424    private ForwCompTransfSpec componentTransformation = null;
425    private boolean enableCT = true;
426
427    /** Specifies which filters to use for the specified tile-components.
428     *  JPEG 2000 part I only supports w5x3 and w9x7 filters.
429     */
430    private AnWTFilterSpec filters = null;
431
432    /** Specifies the number of wavelet decomposition levels to apply to
433     *  the image.  If it is 0, no wavelet transform is performed, in which
434     *  case the original image data will be sent to the encoder and an
435     *  example is the binary data.  All components and all tiles have
436     *  the same number of decomposition levels. Default: 5.
437     */
438    private IntegerSpec decompositionLevel = null; // = 5;
439
440    /** The number of bits used for each tile-component in
441     *  the quantizer to avoid overflow.  It takes values in the range 0
442     *  through 7.  Default: 2.
443     */
444    private GuardBitsSpec guardBits = null;
445
446    /** This parameter specifies the base normalized quantization step
447     *  size for the tiles/components.  It is normalized to a dynamic range
448     *  of 1 in the image domain.  This parameter is ignored in reversible
449     *  coding.  Default: 0.0078125.
450     */
451    private QuantStepSizeSpec quantizationStep = null;
452
453    /** Specifies which quantization type to use for specified
454     *  tiles/components.  Not specified for lossless compression.  By
455     *  default , the quantization step size is "expounded".  Supported
456     *  quantization types specification are : "reversible" (no quantization),
457     *  "derived" (derived quantization step size) and "expounded".
458     */
459    private QuantTypeSpec quantizationType = null;
460
461    /** This parameter defines the lowest resolution levels to belong to
462     *  the ROI.  By doing this, it is possible to avoid only getting
463     *  information for the ROI at an early stage of transmission.
464     *  startLevelROI = 0 means the lowest resolution level belongs to
465     *  the ROI, 1 means the second lowest etc.  The default values, -1,
466     *  deactivates this parameter.
467     */
468    private int startLevelROI = -1;
469
470    /** By specifying this parameter, the ROI mask will be limited to
471     *  covering only entire code-blocks. The ROI coding can then be
472     *  performed without any actual scaling of the coefficients but
473     *  by instead scaling the distortion estimates.
474     */
475    private boolean alignROI = false;
476
477    /** Specifies ROIs shape and location. The component index specifies
478     *  which components contain the ROI.  If this parameter is used, the
479     *  codestream is layer progressive by default unless it is
480     *  overridden by the <code>progressionType</code>.
481     */
482    private MaxShiftSpec ROIs = null;
483
484    /** Specifies the maximum code-block size to use for tile-component.
485     *  The maximum width and height is 1024, however the image area
486     *  (i.e. width x height) must not exceed 4096. The minimum
487     *  width and height is 4.  Default: 64 64.
488     */
489    private CBlkSizeSpec codeBlockSize = null;
490
491    /** Uses the lazy coding mode with the entropy coder.  This will bypass
492     *  the MQ coder for some of the coding passes, where the distribution
493     *  is often close to uniform.  Since the MQ codeword will be terminated
494     *  at least once per lazy pass, it is important to use an efficient
495     *  termination algorithm, <code>methodForMQTermination</code>.
496     *  true enables, and false disables it.  Default: false.
497     */
498    private StringSpec bypass = null;
499
500    /** If this is enabled the probability estimates of the MQ coder are
501     *  reset after each arithmetically coded (i.e. non-lazy) coding pass.
502     *  true enables, and false disables it.  Default: false.
503     */
504    private StringSpec resetMQ = null;
505
506    /** If this is enabled the codeword (raw or MQ) is terminated on a byte
507     *  boundary after each coding pass. In this case it is important to
508     *  use an efficient termination algorithm, the "methodForMQTermination".
509     *  true enables, and false disables it.  Default: false.
510     */
511    private StringSpec terminateOnByte = null;
512
513    /** Uses vertically stripe causal context formation.  If this is
514     *  enabled the context formation process in one stripe is independant
515     *  of the next stripe (i.e. the one below it). true enables, and
516     *  false disables it.  Default: false.
517     */
518     private StringSpec causalCXInfo = null;
519
520    /** Inserts an error resilience segmentation symbol in the MQ codeword
521     *  at the end of each bit-plane (cleanup pass). Decoders can use this
522     *  information to detect and conceal errors. true enables,
523     *  and false disables it.  Default: false.
524     */
525     private StringSpec codeSegSymbol = null;
526
527    /** Specifies the algorithm used to terminate the MQ codeword.  The
528     *  most efficient one is "near_opt", which delivers a codeword which
529     *  in almost all cases is the shortest possible.  The "easy" is a
530     *  simpler algorithm that delivers a codeword length that is close
531     *  to the previous one (in average 1 bit longer).  The "predict" is
532     *  almost the same as the "easy" but it leaves error resilient
533     *  information on the spare least significant bits (in average
534     *  3.5 bits), which can be used by a decoder to detect errors.
535     *  The "full" algorithm performs a full flush of the MQ coder and
536     *  is highly inefficient.  It is important to use a good termination
537     *  policy since the MQ codeword can be terminated quite often,
538     *  specially if the "bypass" or "terminateOnByte" parameters are
539     *  enabled (in the normal case it would be terminated once per
540     *  code-block, while "terminateOnByte" is specified it will be
541     *  done almost 3 times per bit-plane in each code-block).
542     *  Default: near_opt.
543     */
544    private StringSpec methodForMQTermination = null;
545
546    /** Specifies the algorithm to use in calculating the necessary MQ
547     *  length for each decoding pass.  The best one is "near_opt", which
548     *  performs a rather sophisticated calculation and provides the best
549     *  results.  The "lazy_good" and "lazy" are very simple algorithms
550     *  that provide rather conservative results. "lazy_good" performs
551     *  slightly better.  Please use the default unless the experiments
552     *  show the benefits of different length calculation algorithms.
553     *  Default: near_opt.
554     */
555    private StringSpec methodForMQLengthCalc = null;
556
557    /** Specifies precinct partition dimensions for tiles/components.  They
558     *  are stored from those applied to the highest resolution to those
559     *  applied to the remaining resolutions in decreasing order.  If less
560     *  values than the number of decomposition levels are specified, then
561     *  the last two values are used for the remaining resolutions.
562     */
563    private PrecinctSizeSpec precinctPartition = null;
564
565    /** Specifies which type of progression should be used when generating
566     *  the codestream. The value "res" generates a resolution progressive
567     *  codestream with the number of layers specified by "layers" parameter.
568     *  The value "layer" generates a layer progressive codestream with
569     *  multiple layers.  In any case, the rate-allocation algorithm optimizes
570     *  for best quality in each layer.  The quality measure is mean squared
571     *  error (MSE) or a weighted version of it (WMSE).  If no progression
572     *  type is specified or imposed by other modules, the default value
573     *  is "layer".  It is also possible to describe progression order
574     *  changes.  In this case, "res_start" is the index (from 0) of the
575     *  first resolution level, "comp_start" is the index (from 0) of the
576     *  first component, "ly_end" is the index (from 0) of the first layer
577     *  not included, "res_end" is the index (from 0) of the first
578     *  resolution level not included, "comp_end" is index (from 0) of
579     *  the first component not included and "prog" is the progression type
580     *  to be used for the rest of the tile/image.  Several progression
581     *  order changes can be specified, one after the other.
582     */
583    private ProgressionSpec progressionType = null;
584
585    /**
586     * The specified (tile-component) progression.  Will be used to generate
587     * the progression type.
588     */
589    private String progressionName = null;
590
591    /** Explicitly specifies the codestream layer formation parameters.
592     *  The rate (double) parameter specifies the bitrate to which the first
593     *  layer should be optimized.  The layers (int) parameter, if present,
594     *  specifies the number of extra layers that should be added for
595     *  scalability.  These extra layers are not optimized.  Any extra rate
596     *  and layers parameters add more layers, in the same way.  An
597     *  additional layer is always added at the end, which is optimized
598     *  to the overall target bitrate of the bit stream. Any layers
599     *  (optimized or not) whose target bitrate is higher that the
600     *  overall target bitrate are silently ignored. The bitrates of
601     *  the extra layers that are added through the layers parameter
602     *  are approximately log-spaced between the other target bitrates.
603     *  If several (rate, layers) constructs appear the rate parameters
604     *  must appear in increasing order. The rate allocation algorithm
605     *  ensures that all coded layers have a minimal reasonable size,
606     *  if not these layers are silently ignored.  Default: 0.015 +20 2.0 +10.
607     */
608     private String layers = "0.015 +20 2.0 +10";
609
610    /** Specifies whether end of packet header (EPH) markers should be used.
611     *  true enables, false disables it.  Default: false.
612     */
613     private StringSpec EPH = null;
614
615    /** Specifies whether start of packet (SOP) markers should be used.
616     *  true enables, false disables it. Default: false.
617     */
618    private StringSpec SOP = null;
619
620    private int numTiles;
621    private int numComponents;
622
623    private RenderedImage imgsrc;
624    private Raster raster;
625
626    private int minX;
627    private int minY;
628
629    /** Constructor to set locales. */
630    public J2KImageWriteParamJava(RenderedImage imgsrc, Locale locale) {
631        super(locale);
632        setDefaults(imgsrc);
633    }
634
635    /** Constructor to set locales. */
636    public J2KImageWriteParamJava(IIOImage image,  ImageWriteParam param) {
637        super(param.getLocale());
638        if(image != null) {
639            if (image.hasRaster())
640                setDefaults(image.getRaster());
641            else
642                setDefaults(image.getRenderedImage());
643        }
644
645        setSourceRegion(param.getSourceRegion());
646        setSourceBands(param.getSourceBands());
647        try {
648            setTiling(param.getTileWidth(), param.getTileHeight(),
649                      param.getTileGridXOffset(), param.getTileGridYOffset());
650        } catch (IllegalStateException e) {
651            // tileing is not set do nothing.
652        }
653
654        setDestinationOffset(param.getDestinationOffset());
655        setSourceSubsampling(param.getSourceXSubsampling(),
656                             param.getSourceYSubsampling(),
657                             param.getSubsamplingXOffset(),
658                             param.getSubsamplingYOffset());
659        setDestinationType(param.getDestinationType());
660
661        J2KImageWriteParam j2kParam;
662        if(param instanceof J2KImageWriteParam) {
663            j2kParam = (J2KImageWriteParam)param;
664        } else {
665            j2kParam = new J2KImageWriteParam();
666        }
667
668        setDecompositionLevel(""+j2kParam.getNumDecompositionLevels());
669        setEncodingRate(j2kParam.getEncodingRate());
670        setLossless(j2kParam.getLossless());
671        setFilters(j2kParam.getFilter());
672        setEPH("" + j2kParam.getEPH());
673        setSOP("" + j2kParam.getSOP());
674        setProgressionName(j2kParam.getProgressionType());
675        int[] size = j2kParam.getCodeBlockSize();
676        setCodeBlockSize("" + size[0] +" " + size[1]);
677        enableCT = j2kParam.getComponentTransformation();
678        setComponentTransformation("" + enableCT);
679    }
680
681
682    /**
683     * Constructs a <code>J2KImageWriteParamJava</code> object with default
684     * values for all parameters.
685     */
686    public J2KImageWriteParamJava() {
687        super();
688        setSuperProperties();
689    }
690
691    /**
692     * Constructs a <code>J2KImageWriteParamJava</code> object with default
693     * values for all parameters.
694     */
695    public J2KImageWriteParamJava(RenderedImage imgsrc) {
696        super();
697        setDefaults(imgsrc);
698    }
699
700    /**
701     * Constructs a <code>J2KImageWriteParamJava</code> object with default
702     * values for all parameters.
703     */
704    public J2KImageWriteParamJava(Raster raster) {
705        super();
706        setDefaults(raster);
707    }
708
709    private void setSuperProperties() {
710        canOffsetTiles = true;
711        canWriteTiles = true;
712        canOffsetTiles = true;
713        canWriteProgressive = true;
714        tilingMode = MODE_EXPLICIT;
715    }
716
717    /** Set source */
718    private void setDefaults(Raster raster) {
719        // override the params in the super class
720        setSuperProperties();
721
722        if (raster != null) {
723            this.raster = raster;
724            tileGridXOffset = raster.getMinX();
725            tileGridYOffset = raster.getMinY();
726            tileWidth = raster.getWidth();
727            tileHeight = raster.getHeight();
728            tilingSet = true;
729
730            numTiles = 1;
731            numComponents = raster.getSampleModel().getNumBands();
732        }
733        setDefaults();
734    }
735
736    /** Set source */
737    private void setDefaults(RenderedImage imgsrc) {
738        // override the params in the super class
739        setSuperProperties();
740
741        tilingMode = MODE_EXPLICIT;
742
743        if (imgsrc != null) {
744            this.imgsrc = imgsrc;
745            tileGridXOffset = imgsrc.getTileGridXOffset();
746            tileGridYOffset = imgsrc.getTileGridYOffset();
747            tileWidth = imgsrc.getTileWidth();
748            tileHeight = imgsrc.getTileHeight();
749            tilingSet = true;
750
751            numTiles = imgsrc.getNumXTiles() * imgsrc.getNumYTiles();
752            numComponents = imgsrc.getSampleModel().getNumBands();
753        }
754        setDefaults();
755    }
756
757    private void setDefaults() {
758        setROIs(null);
759        setQuantizationType(null);
760        setQuantizationStep(null);
761        setGuardBits(null);
762        setFilters(null);
763        setDecompositionLevel(null);
764        setComponentTransformation(null);
765        setMethodForMQLengthCalc(null);
766        setMethodForMQTermination(null);
767        setCodeSegSymbol(null);
768        setCausalCXInfo(null);
769        setTerminateOnByte(null);
770        setResetMQ(null);
771        setBypass(null);
772        setCodeBlockSize(null);
773        setPrecinctPartition(null);
774        setSOP(null);
775        setEPH(null);
776    }
777
778    /** Sets <code>encodingRate</code> */
779    public void setEncodingRate(double rate) {
780        this.encodingRate = rate;
781    }
782
783    /** Gets <code>encodingRate</code> */
784    public double getEncodingRate() {
785        return encodingRate;
786    }
787
788    /** Sets <code>lossless</code> */
789    public void setLossless(boolean lossless) {
790        this.lossless = lossless;
791    }
792
793    /** Gets <code>encodingRate</code> */
794    public boolean getLossless() {
795        return lossless;
796    }
797    /** Sets <code>packetPerTilePart</code> */
798    public void setPacketPerTilePart(int packetPerTilePart) {
799        if (packetPerTilePart < 0)
800            throw new IllegalArgumentException(I18N.getString("J2KImageWriteParamJava0"));
801
802        this.packetPerTilePart = packetPerTilePart;
803        if (packetPerTilePart > 0) {
804            setSOP("true");
805            setEPH("true");
806        }
807    }
808
809    /** Gets <code>packetPerTilePart</code> */
810    public int getPacketPerTilePart() {
811        return packetPerTilePart;
812    }
813
814    /** Sets <code>packPacketHeaderInTile</code> */
815    public void setPackPacketHeaderInTile(boolean packPacketHeaderInTile) {
816        this.packPacketHeaderInTile = packPacketHeaderInTile;
817        if (packPacketHeaderInTile) {
818            setSOP("true");
819            setEPH("true");
820        }
821    }
822
823    /** Gets <code>packPacketHeaderInTile</code> */
824    public boolean getPackPacketHeaderInTile() {
825        return packPacketHeaderInTile;
826    }
827
828    /** Sets <code>packPacketHeaderInMain</code> */
829    public void setPackPacketHeaderInMain(boolean packPacketHeaderInMain) {
830        this.packPacketHeaderInMain = packPacketHeaderInMain;
831        if (packPacketHeaderInMain) {
832            setSOP("true");
833            setEPH("true");
834        }
835    }
836
837    /** Gets <code>packPacketHeaderInMain</code> */
838    public boolean getPackPacketHeaderInMain() {
839        return packPacketHeaderInMain;
840    }
841
842    /** Sets <code>alignROI</code> */
843    public void setAlignROI(boolean align) {
844        alignROI = align;
845    }
846
847    /** Gets <code>alignROI</code> */
848    public boolean getAlignROI() {
849        return alignROI;
850    }
851
852    /** Sets <code>ROIs</code> */
853    public void setROIs(String values) {
854        ROIs = new MaxShiftSpec(numTiles, numComponents, ModuleSpec.SPEC_TYPE_TILE_COMP, values);
855    }
856
857    /** Gets <code>ROIs</code> */
858    public MaxShiftSpec getROIs() {
859        return ROIs;
860    }
861
862    /** Sets <code>quantizationType</code> */
863    public void setQuantizationType(String values) {
864        quantizationType = new QuantTypeSpec(numTiles, numComponents,
865                ModuleSpec.SPEC_TYPE_TILE_COMP, this, values);
866    }
867
868    /** Gets <code>quantizationType</code> */
869    public QuantTypeSpec getQuantizationType() {
870        return quantizationType;
871    }
872
873    /** Sets <code>quantizationStep</code> */
874    public void setQuantizationStep(String values) {
875        quantizationStep = new QuantStepSizeSpec(numTiles,
876                                                 numComponents,
877                                                 ModuleSpec.SPEC_TYPE_TILE_COMP,
878                                                 this,
879                                                 values);
880    }
881
882    /** Gets <code>quantizationStep</code> */
883    public QuantStepSizeSpec getQuantizationStep() {
884        return quantizationStep;
885    }
886
887    /** Sets <code>guardBits</code> */
888    public void setGuardBits(String values) {
889        guardBits = new GuardBitsSpec(numTiles,
890                                      numComponents,
891                                      ModuleSpec.SPEC_TYPE_TILE_COMP,
892                                      this,
893                                      values);
894    }
895
896    /** Gets <code>guardBits</code> */
897    public GuardBitsSpec getGuardBits() {
898        return guardBits;
899    }
900
901    /** Sets <code>filters</code> */
902    // NOTE This also sets quantizationType and componentTransformation.
903    public void setFilters(String values) {
904        if (J2KImageWriteParam.FILTER_97.equals(values))
905            setQuantizationType ("expounded");
906        else
907            setQuantizationType("reversible");
908
909        filters = new AnWTFilterSpec(numTiles,
910                                     numComponents,
911                                     ModuleSpec.SPEC_TYPE_TILE_COMP,
912                                     (QuantTypeSpec)quantizationType,
913                                     this,
914                                     values);
915        setComponentTransformation(""+enableCT);
916    }
917
918    /** Gets <code>filters</code> */
919    public AnWTFilterSpec getFilters() {
920        return filters;
921    }
922
923    /** Sets <code>decompositionLevel</code> */
924    public void setDecompositionLevel(String values) {
925        decompositionLevel = new IntegerSpec(numTiles,
926                                             numComponents,
927                                             ModuleSpec.SPEC_TYPE_TILE_COMP,
928                                             this,
929                                             values,
930                                             "5");
931
932        // NOTE The precinctPartition depends upon decompositionLevel
933        // so it needs to be re-initialized. Note that the parameter of
934        // setPrecinctPartition() is not used in the current implementation.
935        setPrecinctPartition(null);
936    }
937
938    /** Gets <code>decompositionLevel</code> */
939    public IntegerSpec getDecompositionLevel() {
940        return decompositionLevel;
941    }
942
943    /** Sets <code>componentTransformation</code> */
944    // NOTE This requires filters having been set previously.
945    public void setComponentTransformation(String values) {
946        componentTransformation =
947            new ForwCompTransfSpec(numTiles,
948                                   numComponents,
949                                   ModuleSpec.SPEC_TYPE_TILE,
950                                   (AnWTFilterSpec)filters,
951                                   this,
952                                   values);
953    }
954
955    /** Gets <code>componentTransformation</code> */
956    public ForwCompTransfSpec getComponentTransformation() {
957        return componentTransformation;
958    }
959    /** Sets <code>methodForMQLengthCalc</code> */
960    public void setMethodForMQLengthCalc(String values) {
961        String[] strLcs = {"near_opt","lazy_good","lazy"};
962        methodForMQLengthCalc =
963            new StringSpec(numTiles,
964                           numComponents,
965                           ModuleSpec.SPEC_TYPE_TILE_COMP,
966                           "near_opt",
967                           strLcs,
968                           this,
969                           values);
970    }
971
972    /** Gets <code>methodForMQLengthCalc</code> */
973    public StringSpec getMethodForMQLengthCalc() {
974        return methodForMQLengthCalc;
975    }
976
977    /** Sets <code>methodForMQTermination</code> */
978    public void setMethodForMQTermination(String values) {
979        String[] strTerm = {"near_opt","easy","predict","full"};
980        methodForMQTermination =
981            new StringSpec(numTiles,
982                           numComponents,
983                           ModuleSpec.SPEC_TYPE_TILE_COMP,
984                           "near_opt",
985                           strTerm,
986                           this,
987                           values);
988    }
989
990    /** Gets <code>methodForMQTermination</code> */
991    public StringSpec getMethodForMQTermination() {
992        return methodForMQTermination;
993    }
994
995    /** Sets <code>codeSegSymbol</code> */
996    public void setCodeSegSymbol(String values) {
997        String[] strBoolean = {"true","false"};
998        codeSegSymbol =
999            new StringSpec(numTiles,
1000                           numComponents,
1001                           ModuleSpec.SPEC_TYPE_TILE_COMP,
1002                           "false",
1003                           strBoolean,
1004                           this,
1005                           values);
1006    }
1007
1008    /** Gets <code>codeSegSymbol</code> */
1009    public StringSpec getCodeSegSymbol() {
1010        return codeSegSymbol;
1011    }
1012
1013    /** Sets <code>causalCXInfo</code> */
1014    public void setCausalCXInfo(String values) {
1015        String[] strBoolean = {"true","false"};
1016        causalCXInfo = new StringSpec(numTiles,
1017                                      numComponents,
1018                                      ModuleSpec.SPEC_TYPE_TILE_COMP,
1019                                      "false",
1020                                      strBoolean,
1021                                      this,
1022                                      values);
1023    }
1024
1025    /** Gets <code>causalCXInfo</code> */
1026    public StringSpec getCausalCXInfo() {
1027        return causalCXInfo;
1028    }
1029
1030    /** Sets <code>terminateOnByte</code> */
1031    public void setTerminateOnByte(String values) {
1032        String[] strBoolean = {"true","false"};
1033        terminateOnByte = new StringSpec(numTiles,
1034                                         numComponents,
1035                                         ModuleSpec.SPEC_TYPE_TILE_COMP,
1036                                         "false",
1037                                         strBoolean,
1038                                         this,
1039                                         values);
1040    }
1041
1042    /** Gets <code>terminateOnByte</code> */
1043    public StringSpec getTerminateOnByte() {
1044        return terminateOnByte;
1045    }
1046
1047    /** Sets <code>resetMQ</code> */
1048    public void setResetMQ(String values) {
1049        String[] strBoolean = {"true","false"};
1050        resetMQ = new StringSpec(numTiles,
1051                                 numComponents,
1052                                 ModuleSpec.SPEC_TYPE_TILE_COMP,
1053                                 "false",
1054                                 strBoolean,
1055                                 this,
1056                                 values);
1057    }
1058
1059    /** Gets <code>resetMQ</code> */
1060    public StringSpec getResetMQ() {
1061        return resetMQ;
1062    }
1063
1064    /** Sets <code>bypass</code> */
1065    public void setBypass(String values) {
1066        String[] strBoolean = {"true","false"};
1067        bypass = new StringSpec(numTiles,
1068                                numComponents,
1069                                ModuleSpec.SPEC_TYPE_TILE_COMP,
1070                                "false",
1071                                strBoolean,
1072                                this,
1073                                values);
1074    }
1075
1076    /** Gets <code>bypass</code> */
1077    public StringSpec getBypass() {
1078        return bypass;
1079    }
1080
1081    /** Sets <code>codeBlockSize</code> */
1082    public void setCodeBlockSize(String values) {
1083        codeBlockSize = new CBlkSizeSpec(numTiles,
1084                                         numComponents,
1085                                         ModuleSpec.SPEC_TYPE_TILE_COMP,
1086                                         this,
1087                                         values);
1088    }
1089
1090    /** Gets <code>codeBlockSize</code> */
1091    public CBlkSizeSpec getCodeBlockSize() {
1092        return codeBlockSize;
1093    }
1094
1095    /** Sets <code>precinctPartition</code> */
1096    public void setPrecinctPartition(String values) {
1097        String[] strBoolean = {"true","false"};
1098        if (imgsrc != null)
1099            precinctPartition =
1100                new PrecinctSizeSpec(numTiles,
1101                                     numComponents,
1102                                     ModuleSpec.SPEC_TYPE_TILE_COMP,
1103                                     new RenderedImageSrc(imgsrc, this, null),
1104                                     decompositionLevel,
1105                                     this,
1106                                     values);
1107        else if (raster != null)
1108            precinctPartition =
1109                new PrecinctSizeSpec(numTiles,
1110                                     numComponents,
1111                                     ModuleSpec.SPEC_TYPE_TILE_COMP,
1112                                     new RenderedImageSrc(raster, this, null),
1113                                     decompositionLevel,
1114                                     this,
1115                                     values);
1116    }
1117
1118    /** Gets <code>precinctPartition</code> */
1119    public PrecinctSizeSpec getPrecinctPartition() {
1120        return precinctPartition;
1121    }
1122
1123    /** Sets <code>SOP</code> */
1124    public void setSOP(String values) {
1125            String[] strBoolean = {"true","false"};
1126            SOP = new StringSpec(numTiles,
1127                                 numComponents,
1128                                 ModuleSpec.SPEC_TYPE_TILE_COMP,
1129                                 "false",
1130                                 strBoolean,
1131                                 this,
1132                                 values);
1133    }
1134
1135    /** Gets <code>SOP</code> */
1136    public StringSpec getSOP() {
1137        return SOP;
1138    }
1139
1140    /** Sets <code>EPH</code> */
1141    public void setEPH(String values) {
1142        String[] strBoolean = {"true","false"};
1143        EPH = new StringSpec(numTiles,
1144                             numComponents,
1145                             ModuleSpec.SPEC_TYPE_TILE_COMP,
1146                             "false",
1147                             strBoolean,
1148                             this,
1149                             values);
1150    }
1151
1152    /** Gets <code>EPH</code> */
1153    public StringSpec getEPH() {
1154        return EPH;
1155    }
1156
1157    /** Sets <code>progressionName</code> */
1158    public void setProgressionName(String values) {
1159        progressionName = values;
1160    }
1161
1162    /** Gets <code>progressionType</code> */
1163    public String getProgressionName() {
1164        return progressionName;
1165    }
1166
1167    /** Sets <code>progressionType</code> */
1168    public void setProgressionType(LayersInfo lyrs, String values) {
1169        String[] strBoolean = {"true","false"};
1170        progressionType = new ProgressionSpec(numTiles,
1171                                              numComponents,
1172                                              lyrs.getTotNumLayers(),
1173                                              decompositionLevel,
1174                                              ModuleSpec.SPEC_TYPE_TILE_COMP,
1175                                              this,
1176                                              values);
1177    }
1178
1179    /** Gets <code>progressionType</code> */
1180    public ProgressionSpec getProgressionType() {
1181        return progressionType;
1182    }
1183
1184    /** Sets the <code>startLevelROI</code> */
1185    public void setStartLevelROI(int value) {
1186        startLevelROI = value;
1187    }
1188
1189    /** Gets <code>startLevel</code> */
1190    public int getStartLevelROI() {
1191        return startLevelROI;
1192    }
1193
1194    /** Sets the <code>layers</code> */
1195    public void setLayers(String value) {
1196        layers = value;
1197    }
1198
1199    /** Gets <code>layers</code> */
1200    public String getLayers() {
1201        return layers;
1202    }
1203
1204    /** Sets <code>minX</code> */
1205    public void setMinX(int minX) {
1206        this.minX = minX;
1207    }
1208
1209    /** Gets <code>minX</code> */
1210    public int getMinX() {
1211        return minX;
1212    }
1213
1214    /** Sets <code>minY</code> */
1215    public void setMinY(int minY) {
1216        this.minY = minY;
1217    }
1218
1219    /** Gets <code>minY</code> */
1220    public int getMinY() {
1221        return minY;
1222    }
1223
1224    /** Gets the number of tiles */
1225    public int getNumTiles() {
1226        Rectangle sourceRegion = getSourceRegion();
1227        if (sourceRegion == null) {
1228            if (imgsrc != null)
1229                sourceRegion = new Rectangle(imgsrc.getMinX(),
1230                                         imgsrc.getMinY(),
1231                                         imgsrc.getWidth(),
1232                                         imgsrc.getHeight());
1233            else  sourceRegion = raster.getBounds();
1234        } else {
1235            if (imgsrc != null)
1236                sourceRegion =
1237                    sourceRegion.intersection(new Rectangle(imgsrc.getMinX(),
1238                                         imgsrc.getMinY(),
1239                                         imgsrc.getWidth(),
1240                                         imgsrc.getHeight()));
1241            else  sourceRegion = sourceRegion.intersection(raster.getBounds());
1242        }
1243
1244        int scaleX = getSourceXSubsampling();
1245        int scaleY = getSourceYSubsampling();
1246        int xOffset = getSubsamplingXOffset();
1247        int yOffset = getSubsamplingYOffset();
1248
1249        int w = (sourceRegion.width - xOffset + scaleX - 1) / scaleX;
1250        int h = (sourceRegion.height - yOffset + scaleY - 1) / scaleY;
1251
1252        minX = (sourceRegion.x + xOffset) / scaleX;
1253        minY = (sourceRegion.y + yOffset) / scaleY;
1254
1255        numTiles = (int)((Math.floor((minX + w + tileWidth - 1.0) / tileWidth) -
1256                   Math.floor((double)minX/tileWidth) ) *
1257                   (Math.floor((minY + h + tileHeight - 1.0) / tileHeight) -
1258                   Math.floor((double)minY/tileHeight) ) );
1259        tileGridXOffset += (minX - tileGridXOffset) / tileWidth * tileWidth;
1260        tileGridYOffset += (minY - tileGridYOffset) / tileHeight * tileHeight;
1261
1262        return numTiles;
1263    }
1264
1265    /** Gets the number of components */
1266    public int getNumComponents() {
1267        return numComponents;
1268    }
1269
1270    /** Override the method setSourceBands in the super class.  This method
1271     *  should be called before any tile-specific parameter setting method
1272     *  to be called.
1273     */
1274    public void setSourceBands(int[] bands) {
1275        super.setSourceBands(bands);
1276        if (bands != null) {
1277            numComponents = bands.length;
1278            setDefaults();
1279        }
1280    }
1281
1282    /** Override the method setTiling in the super class.  This method
1283     *  should be called before any tile-specific parameter setting method
1284     *  to be called.
1285     */
1286    public void setTiling(int tw, int th, int xOff, int yOff) {
1287        super.setTiling(tw, th, xOff, yOff);
1288        getNumTiles();
1289        setDefaults();
1290    }
1291
1292    /** Override the method setSourceSubsampling in the super class.  This
1293     *  method should be called before any tile-specific parameter setting
1294     *  method to be called.
1295     */
1296    public void setSourceSubsampling(int sx, int sy, int xOff, int yOff) {
1297        super.setSourceSubsampling(sx, sy, xOff, yOff);
1298        getNumTiles();
1299        setDefaults();
1300    }
1301}