1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
|
/*
* ImageCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Vector;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.Operation;
import net.sourceforge.jiu.ops.WrongParameterException;
import net.sourceforge.jiu.data.PixelImage;
/**
* The base class for <em>image codecs</em>, operations to read images from or write them to streams.
* A codec should support one file format only.
* The word codec is derived from <em>enCOder DECoder</em>.
*
* <h3>Usage</h3>
* The codecs differ quite a bit in what they support.
* But here are two code snippets that demonstrate how to do loading and saving in general.
*
* <h4>Load image</h4>
* <pre>
* ImageCodec codec = new BMPCodec(); // BMPCodec is just an example
* codec.setFile("image.bmp", CodecMode.LOAD);
* codec.process();
* PixelImage image = codec.getImage();
* </pre>
*
* <h4>Save image</h4>
* <pre>
* PixelImage image = ...; // the image to be saved
* ImageCodec codec = new BMPCodec(); // BMPCodec is just an example
* codec.setFile("image.bmp", CodecMode.SAVE);
* codec.setImage(image);
* codec.process();
* </pre>
*
* <h3>I/O objects</h3>
* There are several set and get methods for I/O objects, including
* DataInput, DataOutput, InputStream, OutputStream and RandomAccessFile.
* If you are just using the codec (and not developing one) make it easier
* for yourself and use {@link #setFile(String, CodecMode)}.
* That way the picking of the right type of I/O class and the creation of a
* buffered stream wrapper is done automatically.
* <p>
* Codecs have different requirements concerning I/O objects.
* If an image is to be loaded, it's enough for some formats to linearly read
* from an {@link java.io.InputStream} to load the image.
* However, some formats (like TIFF) require random access.
* <p>
* When implementing a codec, take care that as many I/O classes as possible can be used.
* If possible, call {@link #getInputAsDataInput} when loading and {@link #getOutputAsDataOutput}
* when saving.
* That way, input / output streams, RandomAccessFiles and arbitrary DataInput / DataOutput objects
* can be used.
* <p>
* <h3>Mode</h3>
* Codecs can be used to save images or load them, or both.
* As was g; by default, no mode (of enumeration type {@link CodecMode})
* is specified and {@link #getMode()} returns <code>null</code>.
* Mode only has two possible values, {@link CodecMode#LOAD} and
* {@link CodecMode#SAVE}.
* In some cases, the codec can find out whether to load or save from the I/O objects
* that were given to it; if it has an input stream, something must be loaded,
* if it has an output stream, something is to be saved.
* If a codec demands a {@link RandomAccessFile}, there is no way to find out
* the mode automatically, that is why {@link #setRandomAccessFile} also has an
* argument of type {@link CodecMode}.
* <p>
* <strong>Bounds</strong>; to load or save only part of an image.
* Defining bounds is optional; by default, the complete image is loaded
* or saved (no bounds).
* Using {@link #setBounds(int, int, int, int)}, one can specify the
* rectangle which will be loaded or saved.
* <p>
* <strong>PixelImage object</strong>; get and set methods for the image which is to be
* loaded or saved.
* If an image is to be loaded, a PixelImage object can optionally be specified so that the image will
* be written to that object; image type and resolution must of course match the image
* from input.
* Normally, the codec will create the appropriate image object
* itself.
* If an image is to be saved, an image object <em>must</em> be provided, otherwise there
* is nothing to do.
* <p>
* <strong>Image index</strong>; the index of the image that is to be loaded (int value, default
* is 0). For image formats that support more than one image in one stream, the index of the
* image to be loaded (zero-based) can be specified using {@link #setImageIndex(int)}.
*
* <h3>Textual comments</h3>
* Some file formats allow for the inclusion of textual comments, to
* store a description, creator, copyright owner or anything else within the image
* file without actually drawing that text on the image itself.
* Some codecs support reading and writing of comments.
*
* <h3>Other methods</h3>
* <p>
* Each file format must be able to return its name ({@link #getFormatName()}) and
* file extensions that are typical for it ({@link #getFileExtensions()}).
* <p>
* A related method suggests a file extension for a given PixelImage object ({@link #suggestFileExtension(PixelImage)}).
* That method need not be implemented, the default version returns simply <code>null</code>.
* However, it is encouraged that codec implementors provide this method as well.
* Most file formats only have one typical extension (e. g. <code>.bmp</code>).
* However, for a file format like PNM, the extension depends on the image type (a grayscale
* image would end in <code>.pgm</code>, a color image in <code>.ppm</code>).
* <p>
* @author Marco Schmidt
*/
public abstract class ImageCodec extends Operation
{
private int boundsX1;
private int boundsY1;
private int boundsX2;
private int boundsY2;
private boolean boundsAvail;
private int boundsWidth;
private int boundsHeight;
private Vector comments;
private int dpiX;
private int dpiY;
private DataInput din;
private DataOutput dout;
private PixelImage image;
private int imageIndex;
private InputStream in;
private CodecMode mode;
private OutputStream out;
private RandomAccessFile raf;
/**
* This constructor will be called by descendants.
* The bounds state is initialized to <em>no bounds</em>.
*/
public ImageCodec()
{
super();
comments = new Vector();
removeBounds();
}
/**
* Appends a comment to the internal list of comments.
* If the argument comment is non-null, it will be added to the internal
* list of comment strings.
* @param comment the comment to be added
*/
public void appendComment(String comment)
{
if (comment != null)
{
comments.addElement(comment);
}
}
/**
* If bounds were defined for this codec, this method tests if the
* bounds rectangle fits into the rectangle <code>(0, 0) / (width - 1, height - 1)</code>.
* If the bounds are incorrect, a {@link WrongParameterException}
* is thrown, otherwise nothing happens.
* To be used within codecs that support the bounds concept.
*/
public void checkBounds(int width, int height) throws WrongParameterException
{
if (!hasBounds())
{
return;
}
int x1 = getBoundsX1();
if (x1 >= width)
{
throw new WrongParameterException("Codec bounds x1 (" + x1 +
") must be smaller than image width (" + width + ").");
}
int x2 = getBoundsX2();
if (x2 >= width)
{
throw new WrongParameterException("Codec bounds x2 (" + x2 +
") must be smaller than image width (" + width + ").");
}
int y1 = getBoundsY1();
if (y1 >= height)
{
throw new WrongParameterException("Codec bounds y1 (" + y1 +
") must be smaller than image height (" + height + ").");
}
int y2 = getBoundsY2();
if (y2 >= height)
{
throw new WrongParameterException("Codec bounds y2 (" + y2 +
") must be smaller than image height (" + height + ").");
}
}
/**
* If an image object was provided to be used for loading via {@link #setImage},
* this method checks if its resolution is the same as the bounds' resolution.
* If the two differ, a {@link net.sourceforge.jiu.ops.WrongParameterException} is thrown.
* @throws WrongParameterException if image resolution and bounds dimension differ
*/
public void checkImageResolution() throws WrongParameterException
{
PixelImage image = getImage();
if (image != null)
{
if (image.getWidth() != getBoundsWidth())
{
throw new WrongParameterException("Specified input image must have width equal to getBoundsWidth().");
}
if (image.getHeight() != getBoundsHeight())
{
throw new WrongParameterException("Specified input image must have height equal to getBoundsHeight().");
}
}
}
/**
* Calls the close method of all input and output I/O objects
* that were given to this object.
* Catches and ignores any IOException objects that may be
* thrown in the process.
* Note that not all I/O objects have a close method (e.g. {@link java.io.DataInput}
* and {@link java.io.DataOutput} have not).
*/
public void close()
{
try
{
if (in != null)
{
in.close();
}
if (out != null)
{
out.close();
}
if (raf != null)
{
raf.close();
}
}
catch (IOException ioe)
{
}
}
/**
* Returns x coordinate of the upper left corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return x coordinate of the upper left corner of the bounds
*/
public int getBoundsX1()
{
return boundsX1;
}
/**
* Returns x coordinate of the lower right corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return x coordinate of the lower right corner of the bounds
*/
public int getBoundsX2()
{
return boundsX2;
}
/**
* Returns y coordinate of the upper left corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return y coordinate of the upper left corner of the bounds
*/
public int getBoundsY1()
{
return boundsY1;
}
/**
* Returns y coordinate of the lower right corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return y coordinate of the lower right corner of the bounds
*/
public int getBoundsY2()
{
return boundsY2;
}
/**
* Returns the height of the rectangle specified by bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* This equals {@link #getBoundsY2()} - {@link #getBoundsY1()} + 1.
* @return height of bounds rectangle
*/
public int getBoundsHeight()
{
return boundsHeight;
}
/**
* Returns the width of the rectangle specified by bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* This equals {@link #getBoundsX2()} - {@link #getBoundsX1()} + 1.
* @return width of bounds rectangle
*/
public int getBoundsWidth()
{
return boundsWidth;
}
/**
* Returns a comment from the internal list of comments.
* @param index the index of the comment to be returned, must be from
* <code>0</code> to {@link #getNumComments()}<code> - 1</code>; if this is not
* the case, <code>null</code> will be returned
* @see #getNumComments
* @see #appendComment
* @see #removeAllComments
*/
public String getComment(int index)
{
if (index >= 0 && index < comments.size())
{
return (String)comments.elementAt(index);
}
else
{
return null;
}
}
/**
* Returns a {@link java.io.DataInput} object if one was provided
* via {@link #setDataInput(DataInput)} or <code>null</code> otherwise.
* @return the DataInput object
*/
public DataInput getDataInput()
{
return din;
}
/**
* Returns a {@link java.io.DataOutput} object if one was provided
* via {@link #setDataOutput(DataOutput)} or <code>null</code> otherwise.
* @return the DataInput object
*/
public DataOutput getDataOutput()
{
return dout;
}
/**
* Returns the horizontal physical resolution of the image associated
* with this codec.
* This resolution value was either retrieved from an image file or
* set via {@link #setDpi(int, int)}.
* @return horizontal physical resolution in dpi
* @see #getDpiY
*/
public int getDpiX()
{
return dpiX;
}
/**
* Returns the vertical physical resolution of the image associated
* with this codec.
* This resolution value was either retrieved from an image file or
* set via {@link #setDpi(int, int)}.
* @return horizontal physical resolution in dpi
* @see #getDpiX
*/
public int getDpiY()
{
return dpiY;
}
/**
* Returns all file extensions that are typical for this file format.
* The default implementation in ImageCodec returns <code>null</code>.
* The file extension strings should include a leading dot
* and are supposed to be lower case (if that is allowed for
* the given file format).
* Example: <code>{".jpg", ".jpeg"}</code> for the JPEG file format.
* @return String array with typical file extensions
*/
public String[] getFileExtensions()
{
return null;
}
/**
* Returns the name of the file format supported by this codec.
* All classes extending {@link ImageCodec} must override this method.
* When overriding, leave out any words in a particular language so
* that this format name can be understood by everyone.
* Usually it is enough to return the format creator plus a typical
* abbreviation, e.g. <code>Microsoft BMP</code> or <code>Portable Anymap (PNM)</code>.
* @return name of the file format supported by this codec
*/
public abstract String getFormatName();
/**
* Returns the image object stored in this codec.
* This is either an image given to this object via
* {@link #setImage(PixelImage)} or it was created by the codec
* itself during a loading operation.
* @return PixelImage object stored in this codec
*/
public PixelImage getImage()
{
return image;
}
/**
* Returns the zero-based index of the image to be loaded.
* Default is zero.
* @return zero-based image index value
*/
public int getImageIndex()
{
return imageIndex;
}
/**
* Returns a {@link java.io.DataInput} object if one was specified
* using {@link #setDataInput(DataInput)},
* or creates a {@link java.io.DataInputStream} if an
* {@link java.io.InputStream} was specified,
* or returns a {@link java.io.RandomAccessFile} if one was specified
* (RandomAccessFile implements DataInput).
* If neither of those has been given to this object, <code>null</code> is returned.
* @return DataInput object or <code>null</code>
*/
public DataInput getInputAsDataInput()
{
DataInput din = getDataInput();
if (din != null)
{
return din;
}
RandomAccessFile raf = getRandomAccessFile();
if (getMode() == CodecMode.LOAD && raf != null)
{
return raf;
}
InputStream in = getInputStream();
if (in != null)
{
if (in instanceof DataInput)
{
return (DataInput)in;
}
else
{
return new DataInputStream(in);
}
}
return null;
}
/**
* Returns an {@link java.io.InputStream} object that was given to
* this codec via {@link #setInputStream(InputStream)}
* (or <code>null</code> otherwise).
* @return InputStream object
*/
public InputStream getInputStream()
{
return in;
}
/**
* Return the <a target="_top" href="http://www.faqs.org/rfcs/rfc2045.html">MIME</a>
* (Multipurpose Internet Mail Extensions) type strings for this format, or <code>null</code>
* if none are available.
* @return MIME type strings or null
*/
public abstract String[] getMimeTypes();
/**
* Returns the mode this codec is in.
* Can be <code>null</code>, so that the codec will have to find out
* itself what to do.
* @return codec mode (load or save)
*/
public CodecMode getMode()
{
return mode;
}
/**
* Returns the current number of comments in the internal comment list.
* @return number of comments in the internal comment list
*/
public int getNumComments()
{
return comments.size();
}
/**
* Attempts to return an output object as a {@link java.io.DataOutput} object.
* @return a DataOutput object or null if that was not possible
*/
public DataOutput getOutputAsDataOutput()
{
DataOutput dout = getDataOutput();
if (dout != null)
{
return dout;
}
OutputStream out = getOutputStream();
if (out != null)
{
if (out instanceof DataOutput)
{
return (DataOutput)out;
}
else
{
return new DataOutputStream(out);
}
}
RandomAccessFile raf = getRandomAccessFile();
if (raf != null && getMode() == CodecMode.SAVE)
{
return raf;
}
return null;
}
/**
* Returns an {@link java.io.OutputStream} object that was given to
* this codec via {@link #setOutputStream(OutputStream)}
* (or <code>null</code> otherwise).
* @return OutputStream object
*/
public OutputStream getOutputStream()
{
return out;
}
/**
* Returns a {@link java.io.RandomAccessFile} object that was given to
* this codec via {@link #setRandomAccessFile(RandomAccessFile, CodecMode)}
* (or <code>null</code> otherwise).
* @return RandomAccessFile object
*/
public RandomAccessFile getRandomAccessFile()
{
return raf;
}
/**
* Returns if bounds have been specified.
* @return if bounds have been specified
* @see #removeBounds()
* @see #setBounds(int, int, int, int)
*/
public boolean hasBounds()
{
return boundsAvail;
}
protected void initModeFromIOObjects() throws MissingParameterException
{
if (getMode() != null)
{
return;
}
if (getInputStream() != null || getDataInput() != null)
{
mode = CodecMode.LOAD;
}
else
if (getOutputStream() != null || getDataOutput() != null)
{
mode = CodecMode.SAVE;
}
else
{
throw new MissingParameterException("No streams or files available.");
}
}
/**
* Returns if this codec is able to load images in the file format supported by this codec.
* If <code>true</code> is returned this does not necessarily mean that all files in this
* format can be read, but at least some.
* @return if loading is supported
*/
public abstract boolean isLoadingSupported();
/**
* Returns if this codec is able to save images in the file format supported by this codec.
* If <code>true</code> is returned this does not necessarily mean that all types files in this
* format can be written, but at least some.
* @return if saving is supported
*/
public abstract boolean isSavingSupported();
/**
* Returns if an image row given by its number (zero-based) must be loaded
* in the context of the current bounds.
* <p>
* Example: if vertical bounds have been set to 34 and 37, image rows 34 to
* 37 as arguments to this method would result in <code>true</code>, anything
* else (e.g. 12 or 45) would result in <code>false</code>.
*
* @param row the number of the row to be checked
* @return if row must be loaded, regarding the current bounds
*/
public boolean isRowRequired(int row)
{
if (hasBounds())
{
return (row >= boundsY1 && row <= boundsY2);
}
else
{
return (row >= 0 && row < getImage().getHeight());
}
}
/**
* Returns if the tile formed by the argument coordinates
* form a rectangle that overlaps with the bounds.
* If no bounds were defined, returns <code>true</code>.
* @param x1
* @param y1
* @param x2
* @param y2
* @return if the argument tile is required
*/
public boolean isTileRequired(int x1, int y1, int x2, int y2)
{
if (hasBounds())
{
return !
(getBoundsY2() < y1 ||
getBoundsY1() > y2 ||
getBoundsX2() < x1 ||
getBoundsX1() > x2);
}
else
{
return true;
}
}
/**
* Removes all entries from the internal list of comments.
*/
public void removeAllComments()
{
comments.removeAllElements();
}
/**
* If bounds were set using {@link #setBounds(int, int, int, int)}, these
* bounds are no longer regarded after the call to this method.
*/
public void removeBounds()
{
boundsAvail = false;
}
/**
* Sets the bounds of a rectangular part of the image that
* is to be loaded or saved, instead of the complete image.
*/
public void setBounds(int x1, int y1, int x2, int y2)
{
if (x1 < 0 || y1 < 0 || x2 < x1 || y2 < y1)
{
throw new IllegalArgumentException("Not a valid bounds rectangle: " +
"x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2=" + y2);
}
boundsX1 = x1;
boundsY1 = y1;
boundsX2 = x2;
boundsY2 = y2;
boundsAvail = true;
boundsWidth = x2 - x1 + 1;
boundsHeight = y2 - y1 + 1;
}
/**
* If no bounds have been set ({@link #hasBounds()} returns <code>false</code>),
* this method will set the bounds to <code>0, 0, width - 1, height - 1</code>.
* By calling this method somewhere in the codec, no distinction has to
* be made for the two cases <em>bounds have been defined</em> and
* <em>bounds have not been defined</em>.
* @param width width of the image to be loaded or saved
* @param height height of the image to be loaded or saved
*/
public void setBoundsIfNecessary(int width, int height)
{
if (!hasBounds())
{
setBounds(0, 0, width - 1, height - 1);
}
}
/**
* Specifies a DataInput object to be used for loading.
* @param dataInput DataInput object to be used for loading an image
*/
public void setDataInput(DataInput dataInput)
{
din = dataInput;
}
/**
* Sets a {@link java.io.DataOutput} object to be used for saving
* an image.
* @param dataOutput the object to be used for output
*/
public void setDataOutput(DataOutput dataOutput)
{
dout = dataOutput;
}
/**
* Sets the DPI values to be stored in the file to the argument values.
* @param horizontalDpi horizontal physical resolution in DPI (dots per inch)
* @param verticalDpi vertical physical resolution in DPI (dots per inch)
* @see #getDpiX
* @see #getDpiY
*/
public void setDpi(int horizontalDpi, int verticalDpi)
{
dpiX = horizontalDpi;
dpiY = verticalDpi;
}
/**
* Gives a File object and a codec mode to this codec and attempts
* to initialize the appropriate I/O objects.
* Simply calls {@link #setFile(String, CodecMode)} with the absolute
* path of the File object.
* @param file File object for the file to be used
* @param codecMode defines whether an image is to be loaded from or saved to the file
*/
public void setFile(File file, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
setFile(file.getAbsolutePath(), codecMode);
}
/**
* Gives a file name and codec mode to the codec which will then
* try to create the corresponding I/O object.
* The default implementation in ImageCodec creates a DataInputStream object
* wrapped around a BufferedInputStream wrapped around a FileInputStream for
* CodecMode.LOAD.
* Similar for CodecMode.SAVE: a DataOutputStream around a BufferedOutputStream
* object around a FileOutputStream object.
* Codecs that need different I/O objects must override this method
* (some codecs may need random access and thus require a RandomAccessFile object).
* @param fileName name of the file to be used for loading or saving
* @param codecMode defines whether file is to be used for loading or saving
*/
public void setFile(String fileName, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
if (isLoadingSupported())
{
setInputStream(new BufferedInputStream(new FileInputStream(fileName)));
}
else
{
throw new UnsupportedCodecModeException("Loading is not supported for this codec (" + getFormatName() + ").");
}
}
else
{
if (isSavingSupported())
{
setOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
}
else
{
throw new UnsupportedCodecModeException("Saving is not supported for this codec (" + getFormatName() + ").");
}
}
}
/**
* Give an image to this codec to be used for loading an image into it
* or saving the image.
* @param img image object to save or to load data into
*/
public void setImage(PixelImage img)
{
image = img;
}
/**
* Sets the index of the image to be loaded to the argument value
* (which must be zero or larger).
* @param index int index value (zero-based) of the image to be loaded
* @throws IllegalArgumentException if the argument is negative
*/
public void setImageIndex(int index)
{
if (index < 0)
{
throw new IllegalArgumentException("The index must be 0 or larger.");
}
imageIndex = index;
}
/**
* An {@link java.io.InputStream} can be given to this codec using this method.
* @param inputStream InputStream object to read from
*/
public void setInputStream(InputStream inputStream)
{
in = inputStream;
}
/**
* A method to give an {@link java.io.OutputStream} to this codec to be used
* for saving an image.
* @param outputStream the output stream to be used by this codec
*/
public void setOutputStream(OutputStream outputStream)
{
out = outputStream;
}
/**
* A method to give a {@link java.io.RandomAccessFile} to this codec to be used
* for loading or saving an image.
* It is not possible to determine from a RandomAccessFile object whether it
* was opened in read-only or read-and-write mode.
* To let the codec know whether the object is to be used for loading or saving
* the second argument is of type CodecMode.
* @param randomAccessFile the file to be used for loading or saving
* @param codecMode tells the codec whether the file is to be used for loading or saving
*/
public void setRandomAccessFile(RandomAccessFile randomAccessFile, CodecMode codecMode)
{
if (randomAccessFile == null)
{
throw new IllegalArgumentException("Argument RandomAccessFile must be non-null.");
}
if (codecMode == null)
{
throw new IllegalArgumentException("Argument codec mode must be non-null.");
}
raf = randomAccessFile;
mode = codecMode;
}
/**
* Attempts to suggest a filename extension.
* The type of the argument image will be taken into consideration,
* although this will be necessary for some file formats only (as an
* example, PNM has different extensions for different image types, see
* {@link PNMCodec}).
* This default implementation always returns <code>null</code>.
* @param image the image that is to be written to a file
* @return the file extension, including a leading dot, or <code>null</code> if no file extension can be recommended
*/
public String suggestFileExtension(PixelImage image)
{
return null;
}
}
|