1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 /** 18 * @author Rustem V. Rafikov 19 * @version $Revision: 1.3 $ 20 */ 21 22 package javax.imageio; 23 24 import javax.imageio.stream.ImageInputStream; 25 import javax.imageio.stream.ImageOutputStream; 26 import javax.imageio.spi.*; 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.util.Iterator; 32 import java.util.Arrays; 33 import java.awt.image.BufferedImage; 34 import java.awt.image.RenderedImage; 35 import java.net.URL; 36 37 /** 38 * The ImageIO class provides static methods to perform reading and writing 39 * operations using registered ImageReader and ImageWriter objects. 40 * 41 * @since Android 1.0 42 */ 43 public final class ImageIO { 44 45 /** 46 * The constant registry. 47 */ 48 private static final IIORegistry registry = IIORegistry.getDefaultInstance(); 49 50 /** 51 * Instantiates a new ImageIO. 52 */ 53 private ImageIO() { 54 } 55 56 /** 57 * Scans for plug-ins in the class path, loads spi classes, and registers 58 * them with the IIORegistry. 59 */ 60 public static void scanForPlugins() { 61 throw new UnsupportedOperationException("Not supported yet"); 62 } 63 64 /** 65 * Sets flag which indicates whether a cache file is used when creating 66 * ImageInputStreams and ImageOutputStreams or not. 67 * 68 * @param useCache 69 * the use cache flag. 70 */ 71 public static void setUseCache(boolean useCache) { 72 throw new UnsupportedOperationException("Not supported yet"); 73 } 74 75 /** 76 * Gets the flag which indicates whether a cache file is used when creating 77 * ImageInputStreams and ImageOutputStreams or not. This method returns the 78 * current value which is set by setUseCache method. 79 * 80 * @return the use cache flag. 81 */ 82 public static boolean getUseCache() { 83 // TODO implement 84 return false; 85 } 86 87 /** 88 * Sets the cache directory. 89 * 90 * @param cacheDirectory 91 * the File which specifies a cache directory. 92 */ 93 public static void setCacheDirectory(File cacheDirectory) { 94 throw new UnsupportedOperationException("Not supported yet"); 95 } 96 97 /** 98 * Gets the directory where cache files are created, returned the file which 99 * is set by setCacheDirectory method, or null. 100 * 101 * @return the File object which is set by setCacheDirectory method, or 102 * null. 103 */ 104 public static File getCacheDirectory() { 105 // TODO implement 106 // -- null indicates system-dep default temporary directory 107 return null; 108 } 109 110 /** 111 * Creates an ImageInputStream from the specified Object. The specified 112 * Object should obtain the input source such as File, or InputStream. 113 * 114 * @param input 115 * the input Object such as File, or InputStream. 116 * @return the ImageInputStream object, or null. 117 * @throws IOException 118 * if an I/O exception has occurred. 119 */ 120 public static ImageInputStream createImageInputStream(Object input) throws IOException { 121 122 if (input == null) { 123 throw new IllegalArgumentException("input source cannot be NULL"); 124 } 125 126 Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class, 127 true); 128 129 while (it.hasNext()) { 130 ImageInputStreamSpi spi = it.next(); 131 if (spi.getInputClass().isInstance(input)) { 132 return spi.createInputStreamInstance(input); 133 } 134 } 135 return null; 136 } 137 138 /** 139 * Creates an ImageOutputStream using the specified Object. The specified 140 * Object should obtain the output source such as File, or OutputStream. 141 * 142 * @param output 143 * the output Object such as File, or OutputStream. 144 * @return the ImageOutputStream object, or null. 145 * @throws IOException 146 * if an I/O exception has occurred. 147 */ 148 public static ImageOutputStream createImageOutputStream(Object output) throws IOException { 149 if (output == null) { 150 throw new IllegalArgumentException("output destination cannot be NULL"); 151 } 152 153 Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders( 154 ImageOutputStreamSpi.class, true); 155 156 while (it.hasNext()) { 157 ImageOutputStreamSpi spi = it.next(); 158 if (spi.getOutputClass().isInstance(output)) { 159 // todo - use getUseCache and getCacheDir here 160 return spi.createOutputStreamInstance(output); 161 } 162 } 163 return null; 164 } 165 166 /** 167 * Gets the array of format names as String which can be decoded by 168 * registered ImageReader objects. 169 * 170 * @return the array of format names. 171 */ 172 public static String[] getReaderFormatNames() { 173 throw new UnsupportedOperationException("Not supported yet"); 174 } 175 176 /** 177 * Gets the array of MIME types as String which can be decoded by registered 178 * ImageReader objects. 179 * 180 * @return the array of MIME types. 181 */ 182 public static String[] getReaderMIMETypes() { 183 throw new UnsupportedOperationException("Not supported yet"); 184 } 185 186 /** 187 * Gets the Iterator of registered ImageReader which are able to decode an 188 * input data specified by input Object. 189 * 190 * @param input 191 * the input Object with encoded data such as ImageInputStream 192 * object. 193 * @return the Iterator of registered ImageReader. 194 */ 195 public static Iterator<ImageReader> getImageReaders(Object input) { 196 if (input == null) { 197 throw new NullPointerException("input cannot be NULL"); 198 } 199 200 Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class, 201 new CanReadFilter(input), true); 202 203 return new SpiIteratorToReadersIteratorWrapper(it); 204 } 205 206 /** 207 * Gets the Iterator of registered ImageReader which are able to decode the 208 * specified format. 209 * 210 * @param formatName 211 * the format name such as "jpeg", or "gif". 212 * @return the Iterator of registered ImageReader. 213 */ 214 public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) { 215 if (formatName == null) { 216 throw new NullPointerException("format name cannot be NULL"); 217 } 218 219 Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class, 220 new FormatFilter(formatName), true); 221 222 return new SpiIteratorToReadersIteratorWrapper(it); 223 } 224 225 /** 226 * Gets the Iterator which lists the registered ImageReader objects that are 227 * able to decode files with the specified suffix. 228 * 229 * @param fileSuffix 230 * the file suffix such as "jpg". 231 * @return the Iterator of registered ImageReaders. 232 */ 233 public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) { 234 if (fileSuffix == null) { 235 throw new NullPointerException("suffix cannot be NULL"); 236 } 237 Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class, 238 new SuffixFilter(fileSuffix), true); 239 240 return new SpiIteratorToReadersIteratorWrapper(it); 241 } 242 243 /** 244 * Gets the Iterator of registered ImageReader objects that are able to 245 * decode files with the specified MIME type. 246 * 247 * @param MIMEType 248 * the MIME type such as "image/jpeg". 249 * @return the Iterator of registered ImageReaders. 250 */ 251 public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) { 252 throw new UnsupportedOperationException("Not supported yet"); 253 } 254 255 /** 256 * Gets an array of Strings giving the names of the formats supported by 257 * registered ImageWriter objects. 258 * 259 * @return the array of format names. 260 */ 261 public static String[] getWriterFormatNames() { 262 throw new UnsupportedOperationException("Not supported yet"); 263 } 264 265 /** 266 * Gets an array of Strings giving the MIME types of the formats supported 267 * by registered ImageWriter objects. 268 * 269 * @return the array of MIME types. 270 */ 271 public static String[] getWriterMIMETypes() { 272 throw new UnsupportedOperationException("Not supported yet"); 273 } 274 275 /** 276 * Gets the Iterator which lists the registered ImageReader objects that are 277 * able to encode the specified image format. 278 * 279 * @param formatName 280 * the image format name such as "jpeg". 281 * @return the Iterator of registered ImageWriter. 282 */ 283 public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) { 284 if (formatName == null) { 285 throw new NullPointerException("format name cannot be NULL"); 286 } 287 288 Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class, 289 new FormatFilter(formatName), true); 290 291 return new SpiIteratorToWritersIteratorWrapper(it); 292 } 293 294 /** 295 * Gets the Iterator which lists the registered ImageReader objects that are 296 * able to encode the specified suffix. 297 * 298 * @param fileSuffix 299 * the file suffix such as "jpg". 300 * @return the Iterator of registered ImageWriter. 301 */ 302 public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) { 303 if (fileSuffix == null) { 304 throw new NullPointerException("suffix cannot be NULL"); 305 } 306 Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class, 307 new SuffixFilter(fileSuffix), true); 308 return new SpiIteratorToWritersIteratorWrapper(it); 309 } 310 311 /** 312 * Gets the Iterator which lists the registered ImageReader objects that are 313 * able to encode the specified MIME type. 314 * 315 * @param MIMEType 316 * the MIME type such as "image/jpeg". 317 * @return the Iterator of registered ImageWriter. 318 */ 319 public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) { 320 throw new UnsupportedOperationException("Not supported yet"); 321 } 322 323 /** 324 * Gets an ImageWriter object which corresponds to the specified 325 * ImageReader, or returns null if the specified ImageReader is not 326 * registered. 327 * 328 * @param reader 329 * the specified ImageReader. 330 * @return the ImageWriter, or null. 331 */ 332 public static ImageWriter getImageWriter(ImageReader reader) { 333 throw new UnsupportedOperationException("Not supported yet"); 334 } 335 336 /** 337 * Gets an ImageReader object which corresponds to the specified 338 * ImageWriter, or returns null if the specified ImageWriter is not 339 * registered. 340 * 341 * @param writer 342 * the registered ImageWriter object. 343 * @return the ImageReader. 344 */ 345 public static ImageReader getImageReader(ImageWriter writer) { 346 throw new UnsupportedOperationException("Not supported yet"); 347 } 348 349 /** 350 * Gets the Iterator of ImageWriter objects which are able to encode images 351 * with the specified ImageTypeSpecifier and format. 352 * 353 * @param type 354 * the ImageTypeSpecifier, which defines layout. 355 * @param formatName 356 * the format name. 357 * @return the Iterator of ImageWriter objects. 358 */ 359 public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type, String formatName) { 360 if (type == null) { 361 throw new NullPointerException("type cannot be NULL"); 362 } 363 364 if (formatName == null) { 365 throw new NullPointerException("format name cannot be NULL"); 366 } 367 368 Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class, 369 new FormatAndEncodeFilter(type, formatName), true); 370 371 return new SpiIteratorToWritersIteratorWrapper(it); 372 } 373 374 /** 375 * Gets the Iterator of registered ImageTranscoders which are able to 376 * transcode the metadata of the specified ImageReader object to a suitable 377 * object for encoding by the specified ImageWriter. 378 * 379 * @param reader 380 * the specified ImageReader. 381 * @param writer 382 * the specified ImageWriter. 383 * @return the Iterator of registered ImageTranscoders. 384 */ 385 public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader, 386 ImageWriter writer) { 387 throw new UnsupportedOperationException("Not supported yet"); 388 } 389 390 /** 391 * Reads image data from the specified File and decodes it using the 392 * appropriate registered ImageReader object. The File is wrapped in an 393 * ImageInputStream. 394 * 395 * @param input 396 * the File to be read. 397 * @return the BufferedImage decoded from the specified File, or null. 398 * @throws IOException 399 * if an I/O exception has occurred. 400 */ 401 public static BufferedImage read(File input) throws IOException { 402 if (input == null) { 403 throw new IllegalArgumentException("input == null!"); 404 } 405 406 ImageInputStream stream = createImageInputStream(input); 407 return read(stream); 408 } 409 410 /** 411 * Reads image data from the specified InputStream and decodes it using an 412 * appropriate registered an ImageReader object. 413 * 414 * @param input 415 * the InputStream. 416 * @return the BufferedImage decoded from the specified InputStream, or 417 * null. 418 * @throws IOException 419 * if an I/O exception has occurred. 420 */ 421 public static BufferedImage read(InputStream input) throws IOException { 422 if (input == null) { 423 throw new IllegalArgumentException("input == null!"); 424 } 425 426 ImageInputStream stream = createImageInputStream(input); 427 return read(stream); 428 } 429 430 /** 431 * Reads image data from the specified URL and decodes it using the 432 * appropriate registered ImageReader object. 433 * 434 * @param input 435 * the URL to be read. 436 * @return the BufferedImage decoded from the specified URL, or null. 437 * @throws IOException 438 * if an I/O exception has occurred. 439 */ 440 public static BufferedImage read(URL input) throws IOException { 441 if (input == null) { 442 throw new IllegalArgumentException("input == null!"); 443 } 444 445 InputStream stream = input.openStream(); 446 BufferedImage res = read(stream); 447 stream.close(); 448 449 return res; 450 } 451 452 /** 453 * Reads image data from the specified ImageInputStream and decodes it using 454 * appropriate registered an ImageReader object. 455 * 456 * @param stream 457 * the ImageInputStream. 458 * @return the BufferedImage decoded from the specified ImageInputStream, or 459 * null. 460 * @throws IOException 461 * if an I/O exception has occurred. 462 */ 463 public static BufferedImage read(ImageInputStream stream) throws IOException { 464 if (stream == null) { 465 throw new IllegalArgumentException("stream == null!"); 466 } 467 468 Iterator<ImageReader> imageReaders = getImageReaders(stream); 469 if (!imageReaders.hasNext()) { 470 return null; 471 } 472 473 ImageReader reader = imageReaders.next(); 474 reader.setInput(stream, false, true); 475 BufferedImage res = reader.read(0); 476 reader.dispose(); 477 478 try { 479 stream.close(); 480 } catch (IOException e) { 481 // Stream could be already closed, proceed silently in this case 482 } 483 484 return res; 485 } 486 487 /** 488 * Writes the specified image in the specified format (using an appropriate 489 * ImageWriter) to the specified ImageOutputStream. 490 * 491 * @param im 492 * the RenderedImage. 493 * @param formatName 494 * the format name. 495 * @param output 496 * the ImageOutputStream where Image to be written. 497 * @return true, if Image is written successfully, false otherwise. 498 * @throws IOException 499 * if an I/O exception has occurred. 500 */ 501 public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) 502 throws IOException { 503 504 if (im == null) { 505 throw new IllegalArgumentException("image cannot be NULL"); 506 } 507 if (formatName == null) { 508 throw new IllegalArgumentException("format name cannot be NULL"); 509 } 510 if (output == null) { 511 throw new IllegalArgumentException("output cannot be NULL"); 512 } 513 514 Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), 515 formatName); 516 if (it.hasNext()) { 517 ImageWriter writer = it.next(); 518 writer.setOutput(output); 519 writer.write(im); 520 output.flush(); 521 writer.dispose(); 522 return true; 523 } 524 return false; 525 } 526 527 /** 528 * Writes the specified image in the specified format (using an appropriate 529 * ImageWriter) to the specified File. 530 * 531 * @param im 532 * the RenderedImage. 533 * @param formatName 534 * the format name. 535 * @param output 536 * the output File where Image to be written. 537 * @return true, if Image is written successfully, false otherwise. 538 * @throws IOException 539 * if an I/O exception has occurred. 540 */ 541 public static boolean write(RenderedImage im, String formatName, File output) 542 throws IOException { 543 544 if (output == null) { 545 throw new IllegalArgumentException("output cannot be NULL"); 546 } 547 548 if (output.exists()) { 549 output.delete(); 550 } 551 552 ImageOutputStream ios = createImageOutputStream(output); 553 boolean rt = write(im, formatName, ios); 554 ios.close(); 555 return rt; 556 } 557 558 /** 559 * Writes the specified image in the specified format (using an appropriate 560 * ImageWriter) to the specified OutputStream. 561 * 562 * @param im 563 * the RenderedImage. 564 * @param formatName 565 * the format name. 566 * @param output 567 * the OutputStream where Image is to be written. 568 * @return true, if Image is written successfully, false otherwise. 569 * @throws IOException 570 * if an I/O exception has occurred. 571 */ 572 public static boolean write(RenderedImage im, String formatName, OutputStream output) 573 throws IOException { 574 575 if (output == null) { 576 throw new IllegalArgumentException("output cannot be NULL"); 577 } 578 579 ImageOutputStream ios = createImageOutputStream(output); 580 boolean rt = write(im, formatName, ios); 581 ios.close(); 582 return rt; 583 } 584 585 /** 586 * Filter to match spi by format name. 587 */ 588 static class FormatFilter implements ServiceRegistry.Filter { 589 590 /** 591 * The name. 592 */ 593 private String name; 594 595 /** 596 * Instantiates a new format filter. 597 * 598 * @param name 599 * the name. 600 */ 601 public FormatFilter(String name) { 602 this.name = name; 603 } 604 605 public boolean filter(Object provider) { 606 ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; 607 return Arrays.asList(spi.getFormatNames()).contains(name); 608 } 609 } 610 611 /** 612 * Filter to match spi by format name and encoding possibility. 613 */ 614 static class FormatAndEncodeFilter extends FormatFilter { 615 616 /** 617 * The type. 618 */ 619 private ImageTypeSpecifier type; 620 621 /** 622 * Instantiates a new format and encode filter. 623 * 624 * @param type 625 * the type. 626 * @param name 627 * the name. 628 */ 629 public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) { 630 super(name); 631 this.type = type; 632 } 633 634 @Override 635 public boolean filter(Object provider) { 636 ImageWriterSpi spi = (ImageWriterSpi)provider; 637 return super.filter(provider) && spi.canEncodeImage(type); 638 } 639 } 640 641 /** 642 * Filter to match spi by suffix. 643 */ 644 static class SuffixFilter implements ServiceRegistry.Filter { 645 646 /** 647 * The suf. 648 */ 649 private String suf; 650 651 /** 652 * Instantiates a new suffix filter. 653 * 654 * @param suf 655 * the suf. 656 */ 657 public SuffixFilter(String suf) { 658 this.suf = suf; 659 } 660 661 public boolean filter(Object provider) { 662 ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; 663 return Arrays.asList(spi.getFileSuffixes()).contains(suf); 664 } 665 } 666 667 /** 668 * Filter to match spi by decoding possibility. 669 */ 670 static class CanReadFilter implements ServiceRegistry.Filter { 671 672 /** 673 * The input. 674 */ 675 private Object input; 676 677 /** 678 * Instantiates a new can read filter. 679 * 680 * @param input 681 * the input. 682 */ 683 public CanReadFilter(Object input) { 684 this.input = input; 685 } 686 687 public boolean filter(Object provider) { 688 ImageReaderSpi spi = (ImageReaderSpi)provider; 689 try { 690 return spi.canDecodeInput(input); 691 } catch (IOException e) { 692 return false; 693 } 694 } 695 } 696 697 /** 698 * Wraps Spi's iterator to ImageWriter iterator. 699 */ 700 static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> { 701 702 /** 703 * The backend. 704 */ 705 private Iterator<ImageWriterSpi> backend; 706 707 /** 708 * Instantiates a new spi iterator to writers iterator wrapper. 709 * 710 * @param backend 711 * the backend. 712 */ 713 public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) { 714 this.backend = backend; 715 } 716 717 /** 718 * Next. 719 * 720 * @return the image writer. 721 */ 722 public ImageWriter next() { 723 try { 724 return backend.next().createWriterInstance(); 725 } catch (IOException e) { 726 e.printStackTrace(); 727 return null; 728 } 729 } 730 731 /** 732 * Checks for next. 733 * 734 * @return true, if successful. 735 */ 736 public boolean hasNext() { 737 return backend.hasNext(); 738 } 739 740 /** 741 * Removes the. 742 */ 743 public void remove() { 744 throw new UnsupportedOperationException( 745 "Use deregisterServiceprovider instead of Iterator.remove()"); 746 } 747 } 748 749 /** 750 * Wraps spi's iterator to ImageReader iterator. 751 */ 752 static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> { 753 754 /** 755 * The backend. 756 */ 757 private Iterator<ImageReaderSpi> backend; 758 759 /** 760 * Instantiates a new spi iterator to readers iterator wrapper. 761 * 762 * @param backend 763 * the backend. 764 */ 765 public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) { 766 this.backend = backend; 767 } 768 769 /** 770 * Next. 771 * 772 * @return the image reader. 773 */ 774 public ImageReader next() { 775 try { 776 return backend.next().createReaderInstance(); 777 } catch (IOException e) { 778 e.printStackTrace(); 779 return null; 780 } 781 } 782 783 /** 784 * Checks for next. 785 * 786 * @return true, if successful. 787 */ 788 public boolean hasNext() { 789 return backend.hasNext(); 790 } 791 792 /** 793 * Removes the. 794 */ 795 public void remove() { 796 throw new UnsupportedOperationException( 797 "Use deregisterServiceprovider instead of Iterator.remove()"); 798 } 799 } 800 } 801