1 /* ImageReader.java -- Decodes raster images. 2 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.imageio; 40 41 import java.awt.Point; 42 import java.awt.Rectangle; 43 import java.awt.image.BufferedImage; 44 import java.awt.image.Raster; 45 import java.awt.image.RenderedImage; 46 import java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.Iterator; 49 import java.util.List; 50 import java.util.Locale; 51 import java.util.ResourceBundle; 52 import java.util.MissingResourceException; 53 import java.util.Set; 54 55 import javax.imageio.event.IIOReadProgressListener; 56 import javax.imageio.event.IIOReadUpdateListener; 57 import javax.imageio.event.IIOReadWarningListener; 58 import javax.imageio.metadata.IIOMetadata; 59 import javax.imageio.spi.ImageReaderSpi; 60 import javax.imageio.stream.ImageInputStream; 61 62 /** 63 * A class for decoding images within the ImageIO framework. 64 * 65 * An ImageReader for a given format is instantiated by an 66 * ImageReaderSpi for that format. ImageReaderSpis are registered 67 * with the IIORegistry. 68 * 69 * The ImageReader API supports reading animated images that may have 70 * multiple frames; to support such images many methods take an index 71 * parameter. 72 * 73 * Images may also be read in multiple passes, where each successive 74 * pass increases the level of detail in the destination image. 75 */ 76 public abstract class ImageReader 77 { 78 private boolean aborted; 79 80 /** 81 * All locales available for localization of warning messages, or 82 * null if localization is not supported. 83 */ 84 protected Locale[] availableLocales = null; 85 86 /** 87 * true if the input source does not require metadata to be read, 88 * false otherwise. 89 */ 90 protected boolean ignoreMetadata = false; 91 92 /** 93 * An ImageInputStream from which image data is read. 94 */ 95 protected Object input = null; 96 97 /** 98 * The current locale used to localize warning messages, or null if 99 * no locale has been set. 100 */ 101 protected Locale locale = null; 102 103 /** 104 * The minimum index at which data can be read. Constantly 0 if 105 * seekForwardOnly is false, always increasing if seekForwardOnly is 106 * true. 107 */ 108 protected int minIndex = 0; 109 110 /** 111 * The image reader SPI that instantiated this reader. 112 */ 113 protected ImageReaderSpi originatingProvider = null; 114 115 /** 116 * A list of installed progress listeners. Initially null, meaning 117 * no installed listeners. 118 */ 119 protected List<IIOReadProgressListener> progressListeners = null; 120 121 /** 122 * true if this reader should only read data further ahead in the 123 * stream than its current location. false if it can read backwards 124 * in the stream. If this is true then caching can be avoided. 125 */ 126 protected boolean seekForwardOnly = false; 127 128 /** 129 * A list of installed update listeners. Initially null, meaning no 130 * installed listeners. 131 */ 132 protected List<IIOReadUpdateListener> updateListeners = null; 133 134 /** 135 * A list of installed warning listeners. Initially null, meaning 136 * no installed listeners. 137 */ 138 protected List<IIOReadWarningListener> warningListeners = null; 139 140 /** 141 * A list of warning locales corresponding with the list of 142 * installed warning listeners. Initially null, meaning no locales. 143 */ 144 protected List<Locale> warningLocales = null; 145 146 /** 147 * Construct an image reader. 148 * 149 * @param originatingProvider the provider that is constructing this 150 * image reader, or null 151 */ ImageReader(ImageReaderSpi originatingProvider)152 protected ImageReader(ImageReaderSpi originatingProvider) 153 { 154 this.originatingProvider = originatingProvider; 155 } 156 157 /** 158 * Request that reading be aborted. The unread contents of the 159 * image will be undefined. 160 * 161 * Readers should clear the abort flag before starting a read 162 * operation, then poll it periodically during the read operation. 163 */ abort()164 public void abort() 165 { 166 aborted = true; 167 } 168 169 /** 170 * Check if the abort flag is set. 171 * 172 * @return true if the current read operation should be aborted, 173 * false otherwise 174 */ abortRequested()175 protected boolean abortRequested() 176 { 177 return aborted; 178 } 179 180 /** 181 * Install a read progress listener. This method will return 182 * immediately if listener is null. 183 * 184 * @param listener a read progress listener or null 185 */ addIIOReadProgressListener(IIOReadProgressListener listener)186 public void addIIOReadProgressListener(IIOReadProgressListener listener) 187 { 188 if (listener == null) 189 return; 190 if (progressListeners == null) 191 progressListeners = new ArrayList (); 192 progressListeners.add(listener); 193 } 194 195 /** 196 * Install a read update listener. This method will return 197 * immediately if listener is null. 198 * 199 * @param listener a read update listener 200 */ addIIOReadUpdateListener(IIOReadUpdateListener listener)201 public void addIIOReadUpdateListener(IIOReadUpdateListener listener) 202 { 203 if (listener == null) 204 return; 205 if (updateListeners == null) 206 updateListeners = new ArrayList (); 207 updateListeners.add(listener); 208 } 209 210 /** 211 * Install a read warning listener. This method will return 212 * immediately if listener is null. Warning messages sent to this 213 * listener will be localized using the current locale. If the 214 * current locale is null then this reader will select a sensible 215 * default. 216 * 217 * @param listener a read warning listener 218 */ addIIOReadWarningListener(IIOReadWarningListener listener)219 public void addIIOReadWarningListener(IIOReadWarningListener listener) 220 { 221 if (listener == null) 222 return; 223 if (warningListeners == null) 224 warningListeners = new ArrayList (); 225 warningListeners.add(listener); 226 } 227 228 /** 229 * Check if this reader can handle raster data. Determines whether 230 * or not readRaster and readTileRaster throw 231 * UnsupportedOperationException. 232 * 233 * @return true if this reader supports raster data, false if not 234 */ canReadRaster()235 public boolean canReadRaster() 236 { 237 return false; 238 } 239 240 /** 241 * Clear the abort flag. 242 */ clearAbortRequest()243 protected void clearAbortRequest() 244 { 245 aborted = false; 246 } 247 248 /** 249 * Releases any resources allocated to this object. Subsequent 250 * calls to methods on this object will produce undefined results. 251 * 252 * The default implementation does nothing; subclasses should use 253 * this method ensure that native resources are released. 254 */ dispose()255 public void dispose() 256 { 257 // The default implementation does nothing. 258 } 259 260 /** 261 * Returns the aspect ratio of this image, the ration of its width 262 * to its height. The aspect ratio is useful when resizing an image 263 * while keeping its proportions constant. 264 * 265 * @param imageIndex the frame index 266 * 267 * @return the image's aspect ratio 268 * 269 * @exception IllegalStateException if input is null 270 * @exception IndexOutOfBoundsException if the frame index is 271 * out-of-bounds 272 * @exception IOException if a read error occurs 273 */ getAspectRatio(int imageIndex)274 public float getAspectRatio(int imageIndex) 275 throws IOException 276 { 277 if (input == null) 278 throw new IllegalStateException("input is null"); 279 280 return (float) (getWidth(imageIndex) / getHeight(imageIndex)); 281 } 282 283 /** 284 * Retrieve the available locales. Return null if no locales are 285 * available or a clone of availableLocales. 286 * 287 * @return an array of locales or null 288 */ getAvailableLocales()289 public Locale[] getAvailableLocales() 290 { 291 if (availableLocales == null) 292 return null; 293 294 return (Locale[]) availableLocales.clone(); 295 } 296 297 /** 298 * Retrieve the default read parameters for this reader's image 299 * format. 300 * 301 * The default implementation returns new ImageReadParam(). 302 * 303 * @return image reading parameters 304 */ getDefaultReadParam()305 public ImageReadParam getDefaultReadParam() 306 { 307 return new ImageReadParam(); 308 } 309 310 /** 311 * Retrieve the format of the input source. 312 * 313 * @return the input source format name 314 * 315 * @exception IOException if a read error occurs 316 */ getFormatName()317 public String getFormatName() 318 throws IOException 319 { 320 return originatingProvider.getFormatNames()[0]; 321 } 322 323 /** 324 * Get the height of the input image in pixels. If the input image 325 * is resizable then a default height is returned. 326 * 327 * @param imageIndex the frame index 328 * 329 * @return the height of the input image 330 * 331 * @exception IllegalStateException if input has not been set 332 * @exception IndexOutOfBoundsException if the frame index is 333 * out-of-bounds 334 * @exception IOException if a read error occurs 335 */ getHeight(int imageIndex)336 public abstract int getHeight(int imageIndex) 337 throws IOException; 338 339 /** 340 * Get the metadata associated with this image. If the reader is 341 * set to ignore metadata or does not support reading metadata, or 342 * if no metadata is available then null is returned. 343 * 344 * @param imageIndex the frame index 345 * 346 * @return a metadata object, or null 347 * 348 * @exception IllegalStateException if input has not been set 349 * @exception IndexOutOfBoundsException if the frame index is 350 * out-of-bounds 351 * @exception IOException if a read error occurs 352 */ getImageMetadata(int imageIndex)353 public abstract IIOMetadata getImageMetadata(int imageIndex) 354 throws IOException; 355 356 /** 357 * Get an iterator over the collection of image types into which 358 * this reader can decode image data. This method is guaranteed to 359 * return at least one valid image type specifier. 360 * 361 * The elements of the iterator should be ordered; the first element 362 * should be the most appropriate image type for this decoder, 363 * followed by the second-most appropriate, and so on. 364 * 365 * @param imageIndex the frame index 366 * 367 * @return an iterator over a collection of image type specifiers 368 * 369 * @exception IllegalStateException if input has not been set 370 * @exception IndexOutOfBoundsException if the frame index is 371 * out-of-bounds 372 * @exception IOException if a read error occurs 373 */ getImageTypes(int imageIndex)374 public abstract Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) 375 throws IOException; 376 377 /** 378 * Set the input source to the given object, specify whether this 379 * reader should be allowed to read input from the data stream more 380 * than once, and specify whether this reader should ignore metadata 381 * in the input stream. The input source must be set before many 382 * methods can be called on this reader. (see all ImageReader 383 * methods that throw IllegalStateException). If input is null then 384 * the current input source will be removed. 385 * 386 * Unless this reader has direct access with imaging hardware, input 387 * should be an ImageInputStream. 388 * 389 * @param input the input source object 390 * @param seekForwardOnly true if this reader should be allowed to 391 * read input from the data stream more than once, false otherwise 392 * @param ignoreMetadata true if this reader should ignore metadata 393 * associated with the input source, false otherwise 394 * 395 * @exception IllegalArgumentException if input is not a valid input 396 * source for this reader and is not an ImageInputStream 397 */ setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata)398 public void setInput(Object input, 399 boolean seekForwardOnly, 400 boolean ignoreMetadata) 401 { 402 Class[] okClasses = originatingProvider.getInputTypes(); 403 if (okClasses == null) 404 { 405 if (!(input instanceof ImageInputStream)) 406 throw new IllegalArgumentException(); 407 } 408 else 409 { 410 boolean classOk = false; 411 for (int i = 0; i < okClasses.length; ++i) 412 if (okClasses[i].isInstance(input)) 413 classOk = true; 414 if (!classOk) 415 throw new IllegalArgumentException(); 416 } 417 418 this.input = input; 419 this.seekForwardOnly = seekForwardOnly; 420 this.ignoreMetadata = ignoreMetadata; 421 this.minIndex = 0; 422 } 423 424 /** 425 * Set the input source to the given object and specify whether this 426 * reader should be allowed to read input from the data stream more 427 * than once. The input source must be set before many methods can 428 * be called on this reader. (see all ImageReader methods that throw 429 * IllegalStateException). If input is null then the current input 430 * source will be removed. 431 * 432 * @param in the input source object 433 * @param seekForwardOnly true if this reader should be allowed to 434 * read input from the data stream more than once, false otherwise 435 * 436 * @exception IllegalArgumentException if input is not a valid input 437 * source for this reader and is not an ImageInputStream 438 */ setInput(Object in, boolean seekForwardOnly)439 public void setInput(Object in, boolean seekForwardOnly) 440 { 441 setInput(in, seekForwardOnly, false); 442 } 443 444 /** 445 * Set the input source to the given object. The input source must 446 * be set before many methods can be called on this reader. (see all 447 * ImageReader methods that throw IllegalStateException). If input 448 * is null then the current input source will be removed. 449 * 450 * @param input the input source object 451 * 452 * @exception IllegalArgumentException if input is not a valid input 453 * source for this reader and is not an ImageInputStream 454 */ setInput(Object input)455 public void setInput(Object input) 456 { 457 setInput(input, false, false); 458 } 459 460 /** 461 * Get this reader's image input source. null is returned if the 462 * image source has not been set. 463 * 464 * @return an image input source object, or null 465 */ getInput()466 public Object getInput() 467 { 468 return input; 469 } 470 471 /** 472 * Get this reader's locale. null is returned if the locale has not 473 * been set. 474 * 475 * @return this reader's locale, or null 476 */ getLocale()477 public Locale getLocale() 478 { 479 return locale; 480 } 481 482 /** 483 * Return the number of images available from the image input 484 * source, not including thumbnails. This method will return 1 485 * unless this reader is reading an animated image. 486 * 487 * Certain multi-image formats do not encode the total number of 488 * images. When reading images in those formats it may be necessary 489 * to repeatedly call read, incrementing the image index at each 490 * call, until an IndexOutOfBoundsException is thrown. 491 * 492 * The allowSearch parameter determines whether all images must be 493 * available at all times. When allowSearch is false, getNumImages 494 * will return -1 if the total number of images is unknown. 495 * Otherwise this method returns the number of images. 496 * 497 * @param allowSearch true if all images should be available at 498 * once, false otherwise 499 * 500 * @return -1 if allowSearch is false and the total number of images 501 * is currently unknown, or the number of images 502 * 503 * @exception IllegalStateException if input has not been set, or if 504 * seekForwardOnly is true 505 * @exception IOException if a read error occurs 506 */ getNumImages(boolean allowSearch)507 public abstract int getNumImages(boolean allowSearch) 508 throws IOException; 509 510 /** 511 * Get the number of thumbnails associated with an image. 512 * 513 * @param imageIndex the frame index 514 * 515 * @return the number of thumbnails associated with this image 516 */ getNumThumbnails(int imageIndex)517 public int getNumThumbnails(int imageIndex) 518 throws IOException 519 { 520 return 0; 521 } 522 523 /** 524 * Get the ImageReaderSpi that created this reader or null. 525 * 526 * @return an ImageReaderSpi, or null 527 */ getOriginatingProvider()528 public ImageReaderSpi getOriginatingProvider() 529 { 530 return originatingProvider; 531 } 532 533 /** 534 * Get the metadata associated with the image being read. If the 535 * reader is set to ignore metadata or does not support reading 536 * metadata, or if no metadata is available then null is returned. 537 * This method returns metadata associated with the entirety of the 538 * image data, whereas getImageMetadata(int) returns metadata 539 * associated with a frame within a multi-image data stream. 540 * 541 * @return metadata associated with the image being read, or null 542 * 543 * @exception IOException if a read error occurs 544 */ getStreamMetadata()545 public abstract IIOMetadata getStreamMetadata() 546 throws IOException; 547 548 /** 549 * Get the height of a thumbnail image. 550 * 551 * @param imageIndex the frame index 552 * @param thumbnailIndex the thumbnail index 553 * 554 * @return the height of the thumbnail image 555 * 556 * @exception UnsupportedOperationException if this reader does not 557 * support thumbnails 558 * @exception IllegalStateException if input is null 559 * @exception IndexOutOfBoundsException if either index is 560 * out-of-bounds 561 * @exception IOException if a read error occurs 562 */ getThumbnailHeight(int imageIndex, int thumbnailIndex)563 public int getThumbnailHeight(int imageIndex, int thumbnailIndex) 564 throws IOException 565 { 566 return readThumbnail(imageIndex, thumbnailIndex).getHeight(); 567 } 568 569 /** 570 * Get the width of a thumbnail image. 571 * 572 * @param imageIndex the frame index 573 * @param thumbnailIndex the thumbnail index 574 * 575 * @return the width of the thumbnail image 576 * 577 * @exception UnsupportedOperationException if this reader does not 578 * support thumbnails 579 * @exception IllegalStateException if input is null 580 * @exception IndexOutOfBoundsException if either index is 581 * out-of-bounds 582 * @exception IOException if a read error occurs 583 */ getThumbnailWidth(int imageIndex, int thumbnailIndex)584 public int getThumbnailWidth(int imageIndex, int thumbnailIndex) 585 throws IOException 586 { 587 return readThumbnail(imageIndex, thumbnailIndex).getWidth(); 588 } 589 590 /** 591 * Get the X coordinate in pixels of the top-left corner of the 592 * first tile in this image. 593 * 594 * @param imageIndex the frame index 595 * 596 * @return the X coordinate of this image's first tile 597 * 598 * @exception IllegalStateException if input is needed but the input 599 * source is not set 600 * @exception IndexOutOfBoundsException if the frame index is 601 * out-of-bounds 602 * @exception IOException if a read error occurs 603 */ getTileGridXOffset(int imageIndex)604 public int getTileGridXOffset(int imageIndex) 605 throws IOException 606 { 607 return 0; 608 } 609 610 /** 611 * Get the Y coordinate in pixels of the top-left corner of the 612 * first tile in this image. 613 * 614 * @param imageIndex the frame index 615 * 616 * @return the Y coordinate of this image's first tile 617 * 618 * @exception IllegalStateException if input is needed but the input 619 * source is not set 620 * @exception IndexOutOfBoundsException if the frame index is 621 * out-of-bounds 622 * @exception IOException if a read error occurs 623 */ getTileGridYOffset(int imageIndex)624 public int getTileGridYOffset(int imageIndex) 625 throws IOException 626 { 627 return 0; 628 } 629 630 /** 631 * Get the height of an image tile. 632 * 633 * @param imageIndex the frame index 634 * 635 * @return the tile height for the given image 636 * 637 * @exception IllegalStateException if input is null 638 * @exception IndexOutOfBoundsException if the frame index is 639 * out-of-bounds 640 * @exception IOException if a read error occurs 641 */ getTileHeight(int imageIndex)642 public int getTileHeight(int imageIndex) 643 throws IOException 644 { 645 return getHeight(imageIndex); 646 } 647 648 /** 649 * Get the width of an image tile. 650 * 651 * @param imageIndex the frame index 652 * 653 * @return the tile width for the given image 654 * 655 * @exception IllegalStateException if input is null 656 * @exception IndexOutOfBoundsException if the frame index is 657 * out-of-bounds 658 * @exception IOException if a read error occurs 659 */ getTileWidth(int imageIndex)660 public int getTileWidth(int imageIndex) 661 throws IOException 662 { 663 return getWidth(imageIndex); 664 } 665 666 /** 667 * Get the width of the input image in pixels. If the input image 668 * is resizable then a default width is returned. 669 * 670 * @param imageIndex the image's index 671 * 672 * @return the width of the input image 673 * 674 * @exception IllegalStateException if input has not been set 675 * @exception IndexOutOfBoundsException if the frame index is 676 * out-of-bounds 677 * @exception IOException if a read error occurs 678 */ getWidth(int imageIndex)679 public abstract int getWidth(int imageIndex) 680 throws IOException; 681 682 /** 683 * Check whether or not the given image has thumbnails associated 684 * with it. 685 * 686 * @return true if the given image has thumbnails, false otherwise 687 * 688 * @exception IllegalStateException if input is null 689 * @exception IndexOutOfBoundsException if the frame index is 690 * out-of-bounds 691 * @exception IOException if a read error occurs 692 */ hasThumbnails(int imageIndex)693 public boolean hasThumbnails(int imageIndex) 694 throws IOException 695 { 696 return getNumThumbnails(imageIndex) > 0; 697 } 698 699 /** 700 * Check if this image reader ignores metadata. This method simply 701 * returns the value of ignoreMetadata. 702 * 703 * @return true if metadata is being ignored, false otherwise 704 */ isIgnoringMetadata()705 public boolean isIgnoringMetadata() 706 { 707 return ignoreMetadata; 708 } 709 710 /** 711 * Check if the given image is sub-divided into equal-sized 712 * non-overlapping pixel rectangles. 713 * 714 * A reader may expose tiling in the underlying format, hide it, or 715 * simulate tiling even if the underlying format is not tiled. 716 * 717 * @return true if the given image is tiled, false otherwise 718 * 719 * @exception IllegalStateException if input is null 720 * @exception IndexOutOfBoundsException if the frame index is 721 * out-of-bounds 722 * @exception IOException if a read error occurs 723 */ isImageTiled(int imageIndex)724 public boolean isImageTiled(int imageIndex) 725 throws IOException 726 { 727 return false; 728 } 729 730 /** 731 * Check if all pixels in this image are readily accessible. This 732 * method should return false for compressed formats. The return 733 * value is a hint as to the efficiency of certain image reader 734 * operations. 735 * 736 * @param imageIndex the frame index 737 * 738 * @return true if random pixel access is fast, false otherwise 739 * 740 * @exception IllegalStateException if input is null and it is 741 * needed to determine the return value 742 * @exception IndexOutOfBoundsException if the frame index is 743 * out-of-bounds but the frame data must be accessed to determine 744 * the return value 745 * @exception IOException if a read error occurs 746 */ isRandomAccessEasy(int imageIndex)747 public boolean isRandomAccessEasy(int imageIndex) 748 throws IOException 749 { 750 return false; 751 } 752 753 /** 754 * Check if this image reader may only seek forward within the input 755 * stream. 756 * 757 * @return true if this reader may only seek forward, false 758 * otherwise 759 */ isSeekForwardOnly()760 public boolean isSeekForwardOnly() 761 { 762 return seekForwardOnly; 763 } 764 765 /** 766 * Notifies all installed read progress listeners that image loading 767 * has completed by calling their imageComplete methods. 768 */ processImageComplete()769 protected void processImageComplete() 770 { 771 if (progressListeners != null) 772 { 773 Iterator it = progressListeners.iterator(); 774 775 while (it.hasNext()) 776 { 777 IIOReadProgressListener listener = 778 (IIOReadProgressListener) it.next(); 779 listener.imageComplete (this); 780 } 781 } 782 } 783 784 /** 785 * Notifies all installed read progress listeners that a certain 786 * percentage of the image has been loaded, by calling their 787 * imageProgress methods. 788 * 789 * @param percentageDone the percentage of image data that has been 790 * loaded 791 */ processImageProgress(float percentageDone)792 protected void processImageProgress(float percentageDone) 793 { 794 if (progressListeners != null) 795 { 796 Iterator it = progressListeners.iterator(); 797 798 while (it.hasNext()) 799 { 800 IIOReadProgressListener listener = 801 (IIOReadProgressListener) it.next(); 802 listener.imageProgress(this, percentageDone); 803 } 804 } 805 } 806 /** 807 * Notifies all installed read progress listeners, by calling their 808 * imageStarted methods, that image loading has started on the given 809 * image. 810 * 811 * @param imageIndex the frame index of the image that has started 812 * loading 813 */ processImageStarted(int imageIndex)814 protected void processImageStarted(int imageIndex) 815 { 816 if (progressListeners != null) 817 { 818 Iterator it = progressListeners.iterator(); 819 820 while (it.hasNext()) 821 { 822 IIOReadProgressListener listener = 823 (IIOReadProgressListener) it.next(); 824 listener.imageStarted(this, imageIndex); 825 } 826 } 827 } 828 829 /** 830 * Notifies all installed read update listeners, by calling their 831 * imageUpdate methods, that the set of samples has changed. 832 * 833 * @param image the buffered image that is being updated 834 * @param minX the X coordinate of the top-left pixel in this pass 835 * @param minY the Y coordinate of the top-left pixel in this pass 836 * @param width the total width of the rectangle covered by this 837 * pass, including skipped pixels 838 * @param height the total height of the rectangle covered by this 839 * pass, including skipped pixels 840 * @param periodX the horizontal sample interval 841 * @param periodY the vertical sample interval 842 * @param bands the affected bands in the destination 843 */ processImageUpdate(BufferedImage image, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands)844 protected void processImageUpdate(BufferedImage image, int minX, int minY, 845 int width, int height, int periodX, 846 int periodY, int[] bands) 847 { 848 if (updateListeners != null) 849 { 850 Iterator it = updateListeners.iterator(); 851 852 while (it.hasNext()) 853 { 854 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 855 listener.imageUpdate(this, image, minX, minY, width, height, 856 periodX, periodY, bands); 857 } 858 } 859 } 860 861 /** 862 * Notifies all installed update progress listeners, by calling 863 * their passComplete methods, that a progressive pass has 864 * completed. 865 * 866 * @param image the image that has being updated 867 */ processPassComplete(BufferedImage image)868 protected void processPassComplete(BufferedImage image) 869 { 870 if (updateListeners != null) 871 { 872 Iterator it = updateListeners.iterator(); 873 874 while (it.hasNext()) 875 { 876 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 877 listener.passComplete(this, image); 878 } 879 } 880 } 881 882 /** 883 * Notifies all installed read update listeners, by calling their 884 * passStarted methods, that a new pass has begun. 885 * 886 * @param image the buffered image that is being updated 887 * @param pass the current pass number 888 * @param minPass the pass at which decoding will begin 889 * @param maxPass the pass at which decoding will end 890 * @param minX the X coordinate of the top-left pixel in this pass 891 * @param minY the Y coordinate of the top-left pixel in this pass 892 * @param width the total width of the rectangle covered by this 893 * pass, including skipped pixels 894 * @param height the total height of the rectangle covered by this 895 * pass, including skipped pixels 896 * @param periodX the horizontal sample interval 897 * @param periodY the vertical sample interval 898 * @param bands the affected bands in the destination 899 */ processPassStarted(BufferedImage image, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands)900 protected void processPassStarted(BufferedImage image, int pass, int minPass, 901 int maxPass, int minX, int minY, 902 int periodX, int periodY, int[] bands) 903 { 904 if (updateListeners != null) 905 { 906 Iterator it = updateListeners.iterator(); 907 908 while (it.hasNext()) 909 { 910 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 911 listener.passStarted(this, image, pass, minPass, maxPass, minX, 912 minY, periodX, periodY, bands); 913 } 914 } 915 } 916 917 /** 918 * Notifies all installed read progress listeners that image loading 919 * has been aborted by calling their readAborted methods. 920 */ processReadAborted()921 protected void processReadAborted() 922 { 923 if (progressListeners != null) 924 { 925 Iterator it = progressListeners.iterator(); 926 927 while (it.hasNext()) 928 { 929 IIOReadProgressListener listener = 930 (IIOReadProgressListener) it.next(); 931 listener.readAborted(this); 932 } 933 } 934 } 935 /** 936 * Notifies all installed read progress listeners, by calling their 937 * sequenceComplete methods, that a sequence of images has completed 938 * loading. 939 */ processSequenceComplete()940 protected void processSequenceComplete() 941 { 942 if (progressListeners != null) 943 { 944 Iterator it = progressListeners.iterator(); 945 946 while (it.hasNext()) 947 { 948 IIOReadProgressListener listener = 949 (IIOReadProgressListener) it.next(); 950 listener.sequenceComplete(this); 951 } 952 } 953 } 954 955 /** 956 * Notifies all installed read progress listeners, by calling their 957 * sequenceStarted methods, a sequence of images has started 958 * loading. 959 * 960 * @param minIndex the index of the first image in the sequence 961 */ processSequenceStarted(int minIndex)962 protected void processSequenceStarted(int minIndex) 963 { 964 965 if (progressListeners != null) 966 { 967 Iterator it = progressListeners.iterator(); 968 969 while (it.hasNext()) 970 { 971 IIOReadProgressListener listener = 972 (IIOReadProgressListener) it.next(); 973 listener.sequenceStarted(this, minIndex); 974 } 975 } 976 } 977 978 /** 979 * Notifies all installed read progress listeners, by calling their 980 * thumbnailComplete methods, that a thumbnail has completed 981 * loading. 982 */ processThumbnailComplete()983 protected void processThumbnailComplete() 984 { 985 if (progressListeners != null) 986 { 987 Iterator it = progressListeners.iterator(); 988 989 while (it.hasNext()) 990 { 991 IIOReadProgressListener listener = 992 (IIOReadProgressListener) it.next(); 993 listener.thumbnailComplete(this); 994 } 995 } 996 } 997 998 /** 999 * Notifies all installed update progress listeners, by calling 1000 * their thumbnailPassComplete methods, that a progressive pass has 1001 * completed on a thumbnail. 1002 * 1003 * @param thumbnail the thumbnail that has being updated 1004 */ processThumbnailPassComplete(BufferedImage thumbnail)1005 protected void processThumbnailPassComplete(BufferedImage thumbnail) 1006 { 1007 if (updateListeners != null) 1008 { 1009 Iterator it = updateListeners.iterator(); 1010 1011 while (it.hasNext()) 1012 { 1013 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 1014 listener.thumbnailPassComplete(this, thumbnail); 1015 } 1016 } 1017 } 1018 1019 /** 1020 * Notifies all installed read update listeners, by calling their 1021 * thumbnailPassStarted methods, that a new pass has begun. 1022 * 1023 * @param thumbnail the thumbnail that is being updated 1024 * @param pass the current pass number 1025 * @param minPass the pass at which decoding will begin 1026 * @param maxPass the pass at which decoding will end 1027 * @param minX the X coordinate of the top-left pixel in this pass 1028 * @param minY the Y coordinate of the top-left pixel in this pass 1029 * @param width the total width of the rectangle covered by this 1030 * pass, including skipped pixels 1031 * @param height the total height of the rectangle covered by this 1032 * pass, including skipped pixels 1033 * @param periodX the horizontal sample interval 1034 * @param periodY the vertical sample interval 1035 * @param bands the affected bands in the destination 1036 */ processThumbnailPassStarted(BufferedImage thumbnail, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands)1037 protected void processThumbnailPassStarted(BufferedImage thumbnail, int pass, 1038 int minPass, int maxPass, int minX, 1039 int minY, int periodX, int periodY, 1040 int[] bands) 1041 { 1042 if (updateListeners != null) 1043 { 1044 Iterator it = updateListeners.iterator(); 1045 1046 while (it.hasNext()) 1047 { 1048 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 1049 listener.thumbnailPassStarted(this, thumbnail, pass, minPass, 1050 maxPass, minX, minY, periodX, 1051 periodY, bands); 1052 } 1053 } 1054 } 1055 1056 /** 1057 * Notifies all installed read progress listeners that a certain 1058 * percentage of a thumbnail has been loaded, by calling their 1059 * thumbnailProgress methods. 1060 * 1061 * @param percentageDone the percentage of thumbnail data that has 1062 * been loaded 1063 */ processThumbnailProgress(float percentageDone)1064 protected void processThumbnailProgress(float percentageDone) 1065 { 1066 if (progressListeners != null) 1067 { 1068 Iterator it = progressListeners.iterator(); 1069 1070 while (it.hasNext()) 1071 { 1072 IIOReadProgressListener listener = 1073 (IIOReadProgressListener) it.next(); 1074 listener.thumbnailProgress(this, percentageDone); 1075 } 1076 } 1077 } 1078 1079 /** 1080 * Notifies all installed read progress listeners, by calling their 1081 * imageStarted methods, that thumbnail loading has started on the 1082 * given thumbnail of the given image. 1083 * 1084 * @param imageIndex the frame index of the image one of who's 1085 * thumbnails has started loading 1086 * @param thumbnailIndex the index of the thumbnail that has started 1087 * loading 1088 */ processThumbnailStarted(int imageIndex, int thumbnailIndex)1089 protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) 1090 { 1091 if (progressListeners != null) 1092 { 1093 Iterator it = progressListeners.iterator(); 1094 1095 while (it.hasNext()) 1096 { 1097 IIOReadProgressListener listener = 1098 (IIOReadProgressListener) it.next(); 1099 listener.thumbnailStarted(this, imageIndex, thumbnailIndex); 1100 } 1101 } 1102 } 1103 1104 /** 1105 * Notifies all installed read update listeners, by calling their 1106 * thumbnailUpdate methods, that the set of samples has changed. 1107 * 1108 * @param image the buffered image that is being updated 1109 * @param minX the X coordinate of the top-left pixel in this pass 1110 * @param minY the Y coordinate of the top-left pixel in this pass 1111 * @param width the total width of the rectangle covered by this 1112 * pass, including skipped pixels 1113 * @param height the total height of the rectangle covered by this 1114 * pass, including skipped pixels 1115 * @param periodX the horizontal sample interval 1116 * @param periodY the vertical sample interval 1117 * @param bands the affected bands in the destination 1118 */ processThumbnailUpdate(BufferedImage image, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands)1119 protected void processThumbnailUpdate(BufferedImage image, int minX, int minY, 1120 int width, int height, int periodX, 1121 int periodY, int[] bands) 1122 { 1123 if (updateListeners != null) 1124 { 1125 Iterator it = updateListeners.iterator(); 1126 1127 while (it.hasNext()) 1128 { 1129 IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); 1130 listener.thumbnailUpdate(this, image, minX, minY, width, height, 1131 periodX, periodY, bands); 1132 } 1133 } 1134 } 1135 1136 /** 1137 * Notifies all installed warning listeners, by calling their 1138 * warningOccurred methods, that a warning message has been raised. 1139 * 1140 * @param warning the warning message 1141 * 1142 * @exception IllegalArgumentException if warning is null 1143 */ processWarningOccurred(String warning)1144 protected void processWarningOccurred(String warning) 1145 { 1146 if (warning == null) 1147 throw new IllegalArgumentException ("null argument"); 1148 if (warningListeners != null) 1149 { 1150 Iterator it = warningListeners.iterator(); 1151 1152 while (it.hasNext()) 1153 { 1154 IIOReadWarningListener listener = 1155 (IIOReadWarningListener) it.next(); 1156 listener.warningOccurred(this, warning); 1157 } 1158 } 1159 } 1160 1161 /** 1162 * Notify all installed warning listeners, by calling their 1163 * warningOccurred methods, that a warning message has been raised. 1164 * The warning message is retrieved from a resource bundle, using 1165 * the given basename and keyword. 1166 * 1167 * @param baseName the basename of the resource from which to 1168 * retrieve the warning message 1169 * @param keyword the keyword used to retrieve the warning from the 1170 * resource bundle 1171 * 1172 * @exception IllegalArgumentException if either baseName or keyword 1173 * is null 1174 * @exception IllegalArgumentException if no resource bundle is 1175 * found using baseName 1176 * @exception IllegalArgumentException if the given keyword produces 1177 * no results from the resource bundle 1178 * @exception IllegalArgumentException if the retrieved object is 1179 * not a String 1180 */ processWarningOccurred(String baseName, String keyword)1181 protected void processWarningOccurred(String baseName, 1182 String keyword) 1183 { 1184 if (baseName == null || keyword == null) 1185 throw new IllegalArgumentException ("null argument"); 1186 1187 ResourceBundle b = null; 1188 1189 try 1190 { 1191 b = ResourceBundle.getBundle(baseName, getLocale()); 1192 } 1193 catch (MissingResourceException e) 1194 { 1195 throw new IllegalArgumentException ("no resource bundle found"); 1196 } 1197 1198 Object str = null; 1199 1200 try 1201 { 1202 str = b.getObject(keyword); 1203 } 1204 catch (MissingResourceException e) 1205 { 1206 throw new IllegalArgumentException ("no results found for keyword"); 1207 } 1208 1209 if (! (str instanceof String)) 1210 throw new IllegalArgumentException ("retrieved object not a String"); 1211 1212 String warning = (String) str; 1213 1214 if (warningListeners != null) 1215 { 1216 Iterator it = warningListeners.iterator(); 1217 1218 while (it.hasNext()) 1219 { 1220 IIOReadWarningListener listener = 1221 (IIOReadWarningListener) it.next(); 1222 listener.warningOccurred(this, warning); 1223 } 1224 } 1225 } 1226 1227 /** 1228 * Read the given frame into a buffered image using the given read 1229 * parameters. Listeners will be notified of image loading progress 1230 * and warnings. 1231 * 1232 * @param imageIndex the index of the frame to read 1233 * @param param the image read parameters to use when reading 1234 * 1235 * @return a buffered image 1236 * 1237 * @exception IllegalStateException if input is null 1238 * @exception IndexOutOfBoundsException if the frame index is 1239 * out-of-bounds 1240 * @exception IOException if a read error occurs 1241 */ read(int imageIndex, ImageReadParam param)1242 public abstract BufferedImage read(int imageIndex, ImageReadParam param) 1243 throws IOException; 1244 1245 /** 1246 * Check if this reader supports reading thumbnails. 1247 * 1248 * @return true if this reader supports reading thumbnails, false 1249 * otherwise 1250 */ readerSupportsThumbnails()1251 public boolean readerSupportsThumbnails() 1252 { 1253 return false; 1254 } 1255 1256 /** 1257 * Read raw raster data. The image type specifier in param is 1258 * ignored but all other parameters are used. Offset parameters are 1259 * translated into the raster's coordinate space. This method may 1260 * be implemented by image readers that want to provide direct 1261 * access to raw image data. 1262 * 1263 * @param imageIndex the frame index 1264 * @param param the image read parameters 1265 * 1266 * @return a raster containing the read image data 1267 * 1268 * @exception UnsupportedOperationException if this reader doesn't 1269 * support rasters 1270 * @exception IllegalStateException if input is null 1271 * @exception IndexOutOfBoundsException if the frame index is 1272 * out-of-bounds 1273 * @exception IOException if a read error occurs 1274 */ readRaster(int imageIndex, ImageReadParam param)1275 public Raster readRaster(int imageIndex, ImageReadParam param) 1276 throws IOException 1277 { 1278 throw new UnsupportedOperationException(); 1279 } 1280 1281 /** 1282 * Read a thumbnail. 1283 * 1284 * @param imageIndex the frame index 1285 * @param thumbnailIndex the thumbnail index 1286 * 1287 * @return a buffered image of the thumbnail 1288 * 1289 * @exception UnsupportedOperationException if this reader doesn't 1290 * support thumbnails 1291 * @exception IllegalStateException if input is null 1292 * @exception IndexOutOfBoundsException if either the frame index or 1293 * the thumbnail index is out-of-bounds 1294 * @exception IOException if a read error occurs 1295 * 1296 */ readThumbnail(int imageIndex, int thumbnailIndex)1297 public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) 1298 throws IOException 1299 { 1300 throw new UnsupportedOperationException(); 1301 } 1302 1303 /** 1304 * Uninstall all read progress listeners. 1305 */ removeAllIIOReadProgressListeners()1306 public void removeAllIIOReadProgressListeners() 1307 { 1308 progressListeners = null; 1309 } 1310 1311 /** 1312 * Uninstall all read update listeners. 1313 */ removeAllIIOReadUpdateListeners()1314 public void removeAllIIOReadUpdateListeners() 1315 { 1316 updateListeners = null; 1317 } 1318 1319 /** 1320 * Uninstall all read warning listeners. 1321 */ removeAllIIOReadWarningListeners()1322 public void removeAllIIOReadWarningListeners() 1323 { 1324 warningListeners = null; 1325 } 1326 1327 /** 1328 * Uninstall the given read progress listener. 1329 * 1330 * @param listener the listener to remove 1331 */ removeIIOReadProgressListener(IIOReadProgressListener listener)1332 public void removeIIOReadProgressListener(IIOReadProgressListener listener) 1333 { 1334 if (listener == null) 1335 return; 1336 if (progressListeners != null) 1337 { 1338 progressListeners.remove(listener); 1339 } 1340 } 1341 1342 /** 1343 * Uninstall the given read update listener. 1344 * 1345 * @param listener the listener to remove 1346 */ removeIIOReadUpdateListener(IIOReadUpdateListener listener)1347 public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) 1348 { 1349 if (listener == null) 1350 return; 1351 1352 if (updateListeners != null) 1353 { 1354 updateListeners.remove(listener); 1355 } 1356 } 1357 1358 /** 1359 * Uninstall the given read warning listener. 1360 * 1361 * @param listener the listener to remove 1362 */ removeIIOReadWarningListener(IIOReadWarningListener listener)1363 public void removeIIOReadWarningListener(IIOReadWarningListener listener) 1364 { 1365 if (listener == null) 1366 return; 1367 if (warningListeners != null) 1368 { 1369 warningListeners.remove(listener); 1370 } 1371 } 1372 1373 /** 1374 * Set the current locale or use the default locale. 1375 * 1376 * @param locale the locale to set, or null 1377 */ setLocale(Locale locale)1378 public void setLocale(Locale locale) 1379 { 1380 if (locale != null) 1381 { 1382 // Check if its a valid locale. 1383 boolean found = false; 1384 1385 if (availableLocales != null) 1386 for (int i = availableLocales.length - 1; i >= 0; --i) 1387 if (availableLocales[i].equals(locale)) 1388 found = true; 1389 1390 if (! found) 1391 throw new IllegalArgumentException("looale not available"); 1392 } 1393 1394 this.locale = locale; 1395 } 1396 1397 /** 1398 * Check that the given read parameters have valid source and 1399 * destination band settings. If the param.getSourceBands() returns 1400 * null, the array is assumed to include all band indices, 0 to 1401 * numSrcBands - 1; likewise if param.getDestinationBands() returns 1402 * null, it is assumed to be an array containing indices 0 to 1403 * numDstBands - 1. A failure will cause this method to throw 1404 * IllegalArgumentException. 1405 * 1406 * @param param the image parameters to check 1407 * @param numSrcBands the number of input source bands 1408 * @param numDstBands the number of ouput destination bands 1409 * 1410 * @exception IllegalArgumentException if either the given source or 1411 * destination band indices are invalid 1412 */ checkReadParamBandSettings(ImageReadParam param, int numSrcBands, int numDstBands)1413 protected static void checkReadParamBandSettings(ImageReadParam param, 1414 int numSrcBands, 1415 int numDstBands) 1416 { 1417 int[] srcBands = param.getSourceBands(); 1418 int[] dstBands = param.getDestinationBands(); 1419 boolean lengthsDiffer = false; 1420 boolean srcOOB = false; 1421 boolean dstOOB = false; 1422 1423 if (srcBands == null) 1424 { 1425 if (dstBands == null) 1426 { 1427 if (numSrcBands != numDstBands) 1428 lengthsDiffer = true; 1429 } 1430 else 1431 { 1432 if (numSrcBands != dstBands.length) 1433 lengthsDiffer = true; 1434 1435 for (int i = 0; i < dstBands.length; i++) 1436 if (dstBands[i] > numSrcBands - 1) 1437 { 1438 dstOOB = true; 1439 break; 1440 } 1441 } 1442 } 1443 else 1444 { 1445 if (dstBands == null) 1446 { 1447 if (srcBands.length != numDstBands) 1448 lengthsDiffer = true; 1449 1450 for (int i = 0; i < srcBands.length; i++) 1451 if (srcBands[i] > numDstBands - 1) 1452 { 1453 srcOOB = true; 1454 break; 1455 } 1456 } 1457 else 1458 { 1459 if (srcBands.length != dstBands.length) 1460 lengthsDiffer = true; 1461 1462 for (int i = 0; i < srcBands.length; i++) 1463 if (srcBands[i] > numDstBands - 1) 1464 { 1465 srcOOB = true; 1466 break; 1467 } 1468 1469 for (int i = 0; i < dstBands.length; i++) 1470 if (dstBands[i] > numSrcBands - 1) 1471 { 1472 dstOOB = true; 1473 break; 1474 } 1475 } 1476 } 1477 1478 if (lengthsDiffer) 1479 throw new IllegalArgumentException ("array lengths differ"); 1480 1481 if (srcOOB) 1482 throw new IllegalArgumentException ("source band index" 1483 + " out-of-bounds"); 1484 1485 if (dstOOB) 1486 throw new IllegalArgumentException ("destination band index" 1487 + " out-of-bounds"); 1488 } 1489 1490 /** 1491 * Calcluate the source and destination regions that will be read 1492 * from and written to, given image parameters and/or a destination 1493 * buffered image. The source region will be clipped if any of its 1494 * bounds are outside the destination region. Clipping will account 1495 * for subsampling and destination offsets. Likewise, the 1496 * destination region is clipped to the given destination image, if 1497 * it is not null, using the given image parameters, if they are not 1498 * null. IllegalArgumentException is thrown if either region will 1499 * contain 0 pixels after clipping. 1500 * 1501 * @param param read parameters, or null 1502 * @param srcWidth the width of the source image 1503 * @param srcHeight the height of the source image 1504 * @param image the destination image, or null 1505 * @param srcRegion a rectangle whose values will be set to the 1506 * clipped source region 1507 * @param destRegion a rectangle whose values will be set to the 1508 * clipped destination region 1509 * 1510 * @exception IllegalArgumentException if either srcRegion or 1511 * destRegion is null 1512 * @exception IllegalArgumentException if either of the calculated 1513 * regions is empty 1514 */ computeRegions(ImageReadParam param, int srcWidth, int srcHeight, BufferedImage image, Rectangle srcRegion, Rectangle destRegion)1515 protected static void computeRegions (ImageReadParam param, 1516 int srcWidth, 1517 int srcHeight, 1518 BufferedImage image, 1519 Rectangle srcRegion, 1520 Rectangle destRegion) 1521 { 1522 if (srcRegion == null || destRegion == null) 1523 throw new IllegalArgumentException ("null region"); 1524 1525 if (srcWidth == 0 || srcHeight == 0) 1526 throw new IllegalArgumentException ("zero-sized region"); 1527 1528 srcRegion = getSourceRegion(param, srcWidth, srcHeight); 1529 if (image != null) 1530 destRegion = new Rectangle (0, 0, image.getWidth(), image.getHeight()); 1531 else 1532 destRegion = new Rectangle (0, 0, srcWidth, srcHeight); 1533 1534 if (param != null) 1535 { 1536 Point offset = param.getDestinationOffset(); 1537 1538 if (offset.x < 0) 1539 { 1540 srcRegion.x -= offset.x; 1541 srcRegion.width += offset.x; 1542 } 1543 if (offset.y < 0) 1544 { 1545 srcRegion.y -= offset.y; 1546 srcRegion.height += offset.y; 1547 } 1548 1549 srcRegion.width = srcRegion.width > destRegion.width 1550 ? destRegion.width : srcRegion.width; 1551 srcRegion.height = srcRegion.height > destRegion.height 1552 ? destRegion.height : srcRegion.height; 1553 1554 if (offset.x >= 0) 1555 { 1556 destRegion.x += offset.x; 1557 destRegion.width -= offset.x; 1558 } 1559 if (offset.y >= 0) 1560 { 1561 destRegion.y += offset.y; 1562 destRegion.height -= offset.y; 1563 } 1564 } 1565 1566 if (srcRegion.isEmpty() || destRegion.isEmpty()) 1567 throw new IllegalArgumentException ("zero-sized region"); 1568 } 1569 1570 /** 1571 * Return a suitable destination buffered image. If 1572 * param.getDestination() is non-null, then it is returned, 1573 * otherwise a buffered image is created using 1574 * param.getDestinationType() if it is non-null and also in the 1575 * given imageTypes collection, or the first element of imageTypes 1576 * otherwise. 1577 * 1578 * @param param image read parameters from which a destination image 1579 * or image type is retrieved, or null 1580 * @param imageTypes a collection of legal image types 1581 * @param width the width of the source image 1582 * @param height the height of the source image 1583 * 1584 * @return a suitable destination buffered image 1585 * 1586 * @exception IIOException if param.getDestinationType() does not 1587 * return an image type in imageTypes 1588 * @exception IllegalArgumentException if imageTypes is null or 1589 * empty, or if a non-ImageTypeSpecifier object is retrieved from 1590 * imageTypes 1591 * @exception IllegalArgumentException if the resulting destination 1592 * region is empty 1593 * @exception IllegalArgumentException if the product of width and 1594 * height is greater than Integer.MAX_VALUE 1595 */ getDestination(ImageReadParam param, Iterator<ImageTypeSpecifier> imageTypes, int width, int height)1596 protected static BufferedImage getDestination (ImageReadParam param, 1597 Iterator<ImageTypeSpecifier> imageTypes, 1598 int width, 1599 int height) 1600 throws IIOException 1601 { 1602 if (imageTypes == null || !imageTypes.hasNext()) 1603 throw new IllegalArgumentException ("imageTypes null or empty"); 1604 1605 if (width < 0 || height < 0) 1606 throw new IllegalArgumentException ("negative dimension"); 1607 1608 // test for overflow 1609 if (width * height < Math.min (width, height)) 1610 throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); 1611 1612 BufferedImage dest = null; 1613 ImageTypeSpecifier destType = null; 1614 1615 if (param != null) 1616 { 1617 dest = param.getDestination (); 1618 if (dest == null) 1619 { 1620 ImageTypeSpecifier type = param.getDestinationType(); 1621 if (type != null) 1622 { 1623 Iterator it = imageTypes; 1624 1625 while (it.hasNext()) 1626 { 1627 Object o = it.next (); 1628 if (! (o instanceof ImageTypeSpecifier)) 1629 throw new IllegalArgumentException ("non-ImageTypeSpecifier object"); 1630 1631 ImageTypeSpecifier t = (ImageTypeSpecifier) o; 1632 if (t.equals (type)) 1633 { 1634 dest = t.createBufferedImage (width, height); 1635 break; 1636 } 1637 if (destType == null) 1638 throw new IIOException ("invalid destination type"); 1639 1640 } 1641 } 1642 } 1643 } 1644 if (dest == null) 1645 { 1646 Rectangle srcRegion = new Rectangle (); 1647 Rectangle destRegion = new Rectangle (); 1648 1649 computeRegions (param, width, height, null, srcRegion, destRegion); 1650 1651 if (destRegion.isEmpty()) 1652 throw new IllegalArgumentException ("destination region empty"); 1653 1654 if (destType == null) 1655 { 1656 Object o = imageTypes.next(); 1657 if (! (o instanceof ImageTypeSpecifier)) 1658 throw new IllegalArgumentException ("non-ImageTypeSpecifier" 1659 + " object"); 1660 1661 dest = ((ImageTypeSpecifier) o).createBufferedImage 1662 (destRegion.width, destRegion.height); 1663 } 1664 else 1665 dest = destType.createBufferedImage 1666 (destRegion.width, destRegion.height); 1667 } 1668 return dest; 1669 } 1670 1671 /** 1672 * Get the metadata associated with this image. If the reader is 1673 * set to ignore metadata or does not support reading metadata, or 1674 * if no metadata is available then null is returned. 1675 * 1676 * This more specific version of getImageMetadata(int) can be used 1677 * to restrict metadata retrieval to specific formats and node 1678 * names, which can limit the amount of data that needs to be 1679 * processed. 1680 * 1681 * @param imageIndex the frame index 1682 * @param formatName the format of metadata requested 1683 * @param nodeNames a set of Strings specifiying node names to be 1684 * retrieved 1685 * 1686 * @return a metadata object, or null 1687 * 1688 * @exception IllegalStateException if input has not been set 1689 * @exception IndexOutOfBoundsException if the frame index is 1690 * out-of-bounds 1691 * @exception IllegalArgumentException if formatName is null 1692 * @exception IllegalArgumentException if nodeNames is null 1693 * @exception IOException if a read error occurs 1694 */ getImageMetadata(int imageIndex, String formatName, Set<String> nodeNames)1695 public IIOMetadata getImageMetadata (int imageIndex, 1696 String formatName, 1697 Set<String> nodeNames) 1698 throws IOException 1699 { 1700 if (formatName == null || nodeNames == null) 1701 throw new IllegalArgumentException ("null argument"); 1702 1703 return getImageMetadata (imageIndex); 1704 } 1705 1706 /** 1707 * Get the index at which the next image will be read. If 1708 * seekForwardOnly is true then the returned value will increase 1709 * monotonically each time an image frame is read. If 1710 * seekForwardOnly is false then the returned value will always be 1711 * 0. 1712 * 1713 * @return the current frame index 1714 */ getMinIndex()1715 public int getMinIndex() 1716 { 1717 return minIndex; 1718 } 1719 1720 /** 1721 * Get the image type specifier that most closely represents the 1722 * internal data representation used by this reader. This value 1723 * should be included in the return value of getImageTypes. 1724 * 1725 * @param imageIndex the frame index 1726 * 1727 * @return an image type specifier 1728 * 1729 * @exception IllegalStateException if input has not been set 1730 * @exception IndexOutOfBoundsException if the frame index is 1731 * out-of-bounds 1732 * @exception IOException if a read error occurs 1733 */ getRawImageType(int imageIndex)1734 public ImageTypeSpecifier getRawImageType (int imageIndex) 1735 throws IOException 1736 { 1737 return getImageTypes(imageIndex).next(); 1738 } 1739 1740 /** 1741 * Calculate a source region based on the given source image 1742 * dimensions and parameters. Subsampling offsets and a source 1743 * region are taken from the given image read parameters and used to 1744 * clip the given image dimensions, returning a new rectangular 1745 * region as a result. 1746 * 1747 * @param param image parameters, or null 1748 * @param srcWidth the width of the source image 1749 * @param srcHeight the height of the source image 1750 * 1751 * @return a clipped rectangle 1752 */ getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight)1753 protected static Rectangle getSourceRegion (ImageReadParam param, 1754 int srcWidth, 1755 int srcHeight) 1756 { 1757 Rectangle clippedRegion = new Rectangle (0, 0, srcWidth, srcHeight); 1758 1759 if (param != null) 1760 { 1761 Rectangle srcRegion = param.getSourceRegion(); 1762 1763 if (srcRegion != null) 1764 { 1765 clippedRegion.x = srcRegion.x > clippedRegion.x 1766 ? srcRegion.x : clippedRegion.x; 1767 clippedRegion.y = srcRegion.y > clippedRegion.y 1768 ? srcRegion.y : clippedRegion.y; 1769 clippedRegion.width = srcRegion.width > clippedRegion.width 1770 ? srcRegion.width : clippedRegion.width; 1771 clippedRegion.height = srcRegion.height > clippedRegion.height 1772 ? srcRegion.height : clippedRegion.height; 1773 } 1774 1775 int xOffset = param.getSubsamplingXOffset(); 1776 1777 clippedRegion.x += xOffset; 1778 clippedRegion.width -= xOffset; 1779 1780 int yOffset = param.getSubsamplingYOffset(); 1781 1782 clippedRegion.y += yOffset; 1783 clippedRegion.height -= yOffset; 1784 } 1785 return clippedRegion; 1786 } 1787 1788 /** 1789 * Get the metadata associated with the image being read. If the 1790 * reader is set to ignore metadata or does not support reading 1791 * metadata, or if no metadata is available then null is returned. 1792 * This method returns metadata associated with the entirety of the 1793 * image data, whereas getStreamMetadata() returns metadata 1794 * associated with a frame within a multi-image data stream. 1795 * 1796 * This more specific version of getStreamMetadata() can be used to 1797 * restrict metadata retrieval to specific formats and node names, 1798 * which can limit the amount of data that needs to be processed. 1799 * 1800 * @param formatName the format of metadata requested 1801 * @param nodeNames a set of Strings specifiying node names to be 1802 * retrieved 1803 * 1804 * @return metadata associated with the image being read, or null 1805 * 1806 * @exception IllegalArgumentException if formatName is null 1807 * @exception IllegalArgumentException if nodeNames is null 1808 * @exception IOException if a read error occurs 1809 */ getStreamMetadata(String formatName, Set<String> nodeNames)1810 public IIOMetadata getStreamMetadata (String formatName, 1811 Set<String> nodeNames) 1812 throws IOException 1813 { 1814 if (formatName == null || nodeNames == null) 1815 throw new IllegalArgumentException ("null argument"); 1816 1817 return getStreamMetadata(); 1818 } 1819 1820 /** 1821 * Read the given frame all at once, using default image read 1822 * parameters, and return a buffered image. 1823 * 1824 * The returned image will be formatted according to the 1825 * currently-preferred image type specifier. 1826 * 1827 * Installed read progress listeners, update progress listeners and 1828 * warning listeners will be notified of read progress, changes in 1829 * sample sets and warnings respectively. 1830 * 1831 * @param imageIndex the index of the image frame to read 1832 * 1833 * @return a buffered image 1834 * 1835 * @exception IllegalStateException if input has not been set 1836 * @exception IndexOutOfBoundsException if the frame index is 1837 * out-of-bounds 1838 * @exception IOException if a read error occurs 1839 */ read(int imageIndex)1840 public BufferedImage read (int imageIndex) 1841 throws IOException 1842 { 1843 return read (imageIndex, null); 1844 } 1845 1846 /** 1847 * Read the given frame all at once, using the given image read 1848 * parameters, and return an IIOImage. The IIOImage will contain a 1849 * buffered image as returned by getDestination. 1850 * 1851 * Installed read progress listeners, update progress listeners and 1852 * warning listeners will be notified of read progress, changes in 1853 * sample sets and warnings respectively. 1854 * 1855 * The source and destination band settings are checked with a call 1856 * to checkReadParamBandSettings. 1857 * 1858 * @param imageIndex the index of the image frame to read 1859 * @param param the image read parameters 1860 * 1861 * @return an IIOImage 1862 * 1863 * @exception IllegalStateException if input has not been set 1864 * @exception IndexOutOfBoundsException if the frame index is 1865 * out-of-bounds 1866 * @exception IllegalArgumentException if param.getSourceBands() and 1867 * param.getDestinationBands() are incompatible 1868 * @exception IllegalArgumentException if either the source or 1869 * destination image regions are empty 1870 * @exception IOException if a read error occurs 1871 */ readAll(int imageIndex, ImageReadParam param)1872 public IIOImage readAll (int imageIndex, 1873 ImageReadParam param) 1874 throws IOException 1875 { 1876 checkReadParamBandSettings (param, 1877 param.getSourceBands().length, 1878 param.getDestinationBands().length); 1879 1880 List l = new ArrayList (); 1881 1882 for (int i = 0; i < getNumThumbnails (imageIndex); i++) 1883 l.add (readThumbnail(imageIndex, i)); 1884 1885 return new IIOImage (getDestination(param, getImageTypes(imageIndex), 1886 getWidth(imageIndex), 1887 getHeight(imageIndex)), 1888 l, 1889 getImageMetadata (imageIndex)); 1890 } 1891 1892 /** 1893 * Read all image frames all at once, using the given image read 1894 * parameters iterator, and return an iterator over a collection of 1895 * IIOImages. Each IIOImage in the collection will contain a 1896 * buffered image as returned by getDestination. 1897 * 1898 * Installed read progress listeners, update progress listeners and 1899 * warning listeners will be notified of read progress, changes in 1900 * sample sets and warnings respectively. 1901 * 1902 * Each set of source and destination band settings are checked with 1903 * a call to checkReadParamBandSettings. 1904 * 1905 * @param params iterator over the image read parameters 1906 * 1907 * @return an IIOImage 1908 * 1909 * @exception IllegalStateException if input has not been set 1910 * @exception IllegalArgumentException if a non-ImageReadParam is 1911 * found in params 1912 * @exception IllegalArgumentException if param.getSourceBands() and 1913 * param.getDestinationBands() are incompatible 1914 * @exception IllegalArgumentException if either the source or 1915 * destination image regions are empty 1916 * @exception IOException if a read error occurs 1917 */ readAll(Iterator<? extends ImageReadParam> params)1918 public Iterator<IIOImage> readAll (Iterator<? extends ImageReadParam> params) 1919 throws IOException 1920 { 1921 List l = new ArrayList (); 1922 int index = 0; 1923 1924 while (params.hasNext()) 1925 { 1926 if (params != null && ! (params instanceof ImageReadParam)) 1927 throw new IllegalArgumentException ("non-ImageReadParam found"); 1928 1929 l.add (readAll(index++, (ImageReadParam) params.next ())); 1930 } 1931 1932 return l.iterator(); 1933 } 1934 1935 /** 1936 * Read a rendered image. This is a more general counterpart to 1937 * read (int, ImageReadParam). All image data may not be read 1938 * before this method returns and so listeners will not necessarily 1939 * be notified. 1940 * 1941 * @param imageIndex the index of the image frame to read 1942 * @param param the image read parameters 1943 * 1944 * @return a rendered image 1945 * 1946 * @exception IllegalStateException if input is null 1947 * @exception IndexOutOfBoundsException if the frame index is 1948 * out-of-bounds 1949 * @exception IllegalArgumentException if param.getSourceBands() and 1950 * param.getDestinationBands() are incompatible 1951 * @exception IllegalArgumentException if either the source or 1952 * destination image regions are empty 1953 * @exception IOException if a read error occurs 1954 */ readAsRenderedImage(int imageIndex, ImageReadParam param)1955 public RenderedImage readAsRenderedImage (int imageIndex, 1956 ImageReadParam param) 1957 throws IOException 1958 { 1959 return read (imageIndex, param); 1960 } 1961 1962 /** 1963 * Read the given tile into a buffered image. If the tile 1964 * coordinates are out-of-bounds an exception is thrown. If the 1965 * image is not tiled then the coordinates 0, 0 are expected and the 1966 * entire image will be read. 1967 * 1968 * @param imageIndex the frame index 1969 * @param tileX the horizontal tile coordinate 1970 * @param tileY the vertical tile coordinate 1971 * 1972 * @return the contents of the tile as a buffered image 1973 * 1974 * @exception IllegalStateException if input is null 1975 * @exception IndexOutOfBoundsException if the frame index is 1976 * out-of-bounds 1977 * @exception IllegalArgumentException if the tile coordinates are 1978 * out-of-bounds 1979 * @exception IOException if a read error occurs 1980 */ readTile(int imageIndex, int tileX, int tileY)1981 public BufferedImage readTile (int imageIndex, int tileX, int tileY) 1982 throws IOException 1983 { 1984 if (tileX != 0 || tileY != 0) 1985 throw new IllegalArgumentException ("tileX not 0 or tileY not 0"); 1986 1987 return read (imageIndex); 1988 } 1989 1990 /** 1991 * Read the given tile into a raster containing the raw image data. 1992 * If the tile coordinates are out-of-bounds an exception is thrown. 1993 * If the image is not tiled then the coordinates 0, 0 are expected 1994 * and the entire image will be read. 1995 * 1996 * @param imageIndex the frame index 1997 * @param tileX the horizontal tile coordinate 1998 * @param tileY the vertical tile coordinate 1999 * 2000 * @return the contents of the tile as a raster 2001 * 2002 * @exception UnsupportedOperationException if rasters are not 2003 * supported 2004 * @exception IllegalStateException if input is null 2005 * @exception IndexOutOfBoundsException if the frame index is 2006 * out-of-bounds 2007 * @exception IllegalArgumentException if the tile coordinates are 2008 * out-of-bounds 2009 * @exception IOException if a read error occurs 2010 */ readTileRaster(int imageIndex, int tileX, int tileY)2011 public Raster readTileRaster (int imageIndex, int tileX, int tileY) 2012 throws IOException 2013 { 2014 if (!canReadRaster()) 2015 throw new UnsupportedOperationException ("cannot read rasters"); 2016 2017 if (tileX != 0 || tileY != 0) 2018 throw new IllegalArgumentException ("tileX not 0 or tileY not 0"); 2019 2020 return readRaster (imageIndex, null); 2021 } 2022 2023 /** 2024 * Reset this reader's internal state. 2025 */ reset()2026 public void reset () 2027 { 2028 setInput (null, false); 2029 setLocale (null); 2030 removeAllIIOReadUpdateListeners (); 2031 removeAllIIOReadWarningListeners (); 2032 removeAllIIOReadProgressListeners (); 2033 clearAbortRequest (); 2034 } 2035 } 2036