< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java

Print this page




  49 import java.util.Iterator;
  50 import java.util.ListIterator;
  51 import java.io.IOException;
  52 import java.awt.color.ICC_Profile;
  53 import java.awt.color.ICC_ColorSpace;
  54 import java.awt.color.ColorSpace;
  55 import java.awt.image.BufferedImage;
  56 import java.awt.image.ColorModel;
  57 import java.awt.Point;
  58 
  59 /**
  60  * Metadata for the JPEG plug-in.
  61  */
  62 public class JPEGMetadata extends IIOMetadata implements Cloneable {
  63 
  64     //////// Private variables
  65 
  66     private static final boolean debug = false;
  67 
  68     /**
  69      * A copy of <code>markerSequence</code>, created the first time the
  70      * <code>markerSequence</code> is modified.  This is used by reset
  71      * to restore the original state.
  72      */
  73     private List<MarkerSegment> resetSequence = null;
  74 
  75     /**
  76      * Set to <code>true</code> when reading a thumbnail stored as
  77      * JPEG.  This is used to enforce the prohibition of JFIF thumbnails
  78      * containing any JFIF marker segments, and to ensure generation of
  79      * a correct native subtree during <code>getAsTree</code>.
  80      */
  81     private boolean inThumb = false;
  82 
  83     /**
  84      * Set by the chroma node construction method to signal the
  85      * presence or absence of an alpha channel to the transparency
  86      * node construction method.  Used only when constructing a
  87      * standard metadata tree.
  88      */
  89     private boolean hasAlpha;
  90 
  91     //////// end of private variables
  92 
  93     /////// Package-access variables
  94 
  95     /**
  96      * All data is a list of <code>MarkerSegment</code> objects.
  97      * When accessing the list, use the tag to identify the particular
  98      * subclass.  Any JFIF marker segment must be the first element
  99      * of the list if it is present, and any JFXX or APP2ICC marker
 100      * segments are subordinate to the JFIF marker segment.  This
 101      * list is package visible so that the writer can access it.
 102      * @see #MarkerSegment
 103      */
 104     List<MarkerSegment> markerSequence = new ArrayList<>();
 105 
 106     /**
 107      * Indicates whether this object represents stream or image
 108      * metadata.  Package-visible so the writer can see it.
 109      */
 110     final boolean isStream;
 111 
 112     /////// End of package-access variables
 113 
 114     /////// Constructors
 115 
 116     /**
 117      * Constructor containing code shared by other constructors.
 118      */
 119     JPEGMetadata(boolean isStream, boolean inThumb) {
 120         super(true,  // Supports standard format
 121               JPEG.nativeImageMetadataFormatName,  // and a native format
 122               JPEG.nativeImageMetadataFormatClassName,
 123               null, null);  // No other formats
 124         this.inThumb = inThumb;
 125         // But if we are stream metadata, adjust the variables
 126         this.isStream = isStream;
 127         if (isStream) {
 128             nativeMetadataFormatName = JPEG.nativeStreamMetadataFormatName;
 129             nativeMetadataFormatClassName =
 130                 JPEG.nativeStreamMetadataFormatClassName;
 131         }
 132     }
 133 
 134     /*
 135      * Constructs a <code>JPEGMetadata</code> object by reading the
 136      * contents of an <code>ImageInputStream</code>.  Has package-only
 137      * access.
 138      *
 139      * @param isStream A boolean indicating whether this object will be
 140      * stream or image metadata.
 141      * @param isThumb A boolean indicating whether this metadata object
 142      * is for an image or for a thumbnail stored as JPEG.
 143      * @param iis An <code>ImageInputStream</code> from which to read
 144      * the metadata.
 145      * @param reader The <code>JPEGImageReader</code> calling this
 146      * constructor, to which warnings should be sent.
 147      */
 148     JPEGMetadata(boolean isStream,
 149                  boolean isThumb,
 150                  ImageInputStream iis,
 151                  JPEGImageReader reader) throws IOException {
 152         this(isStream, isThumb);
 153 
 154         JPEGBuffer buffer = new JPEGBuffer(iis);
 155 
 156         buffer.loadBuf(0);
 157 
 158         // The first three bytes should be FF, SOI, FF
 159         if (((buffer.buf[0] & 0xff) != 0xff)
 160             || ((buffer.buf[1] & 0xff) != JPEG.SOI)
 161             || ((buffer.buf[2] & 0xff) != 0xff)) {
 162             throw new IIOException ("Image format error");
 163         }
 164 
 165         boolean done = false;


 348                 markerSequence.add(newGuy);
 349                 if (debug) {
 350                     newGuy.print();
 351                 }
 352                 newGuy = null;
 353             }
 354         }
 355 
 356         // Now that we've read up to the EOI, we need to push back
 357         // whatever is left in the buffer, so that the next read
 358         // in the native code will work.
 359 
 360         buffer.pushBack();
 361 
 362         if (!isConsistent()) {
 363             throw new IIOException("Inconsistent metadata read from stream");
 364         }
 365     }
 366 
 367     /**
 368      * Constructs a default stream <code>JPEGMetadata</code> object appropriate
 369      * for the given write parameters.
 370      */
 371     JPEGMetadata(ImageWriteParam param, JPEGImageWriter writer) {
 372         this(true, false);
 373 
 374         JPEGImageWriteParam jparam = null;
 375 
 376         if ((param != null) && (param instanceof JPEGImageWriteParam)) {
 377             jparam = (JPEGImageWriteParam) param;
 378             if (!jparam.areTablesSet()) {
 379                 jparam = null;
 380             }
 381         }
 382         if (jparam != null) {
 383             markerSequence.add(new DQTMarkerSegment(jparam.getQTables()));
 384             markerSequence.add
 385                 (new DHTMarkerSegment(jparam.getDCHuffmanTables(),
 386                                       jparam.getACHuffmanTables()));
 387         } else {
 388             // default tables.
 389             markerSequence.add(new DQTMarkerSegment(JPEG.getDefaultQTables()));
 390             markerSequence.add(new DHTMarkerSegment(JPEG.getDefaultHuffmanTables(true),
 391                                                     JPEG.getDefaultHuffmanTables(false)));
 392         }
 393 
 394         // Defensive programming
 395         if (!isConsistent()) {
 396             throw new InternalError("Default stream metadata is inconsistent");
 397         }
 398     }
 399 
 400     /**
 401      * Constructs a default image <code>JPEGMetadata</code> object appropriate
 402      * for the given image type and write parameters.
 403      */
 404     JPEGMetadata(ImageTypeSpecifier imageType,
 405                  ImageWriteParam param,
 406                  JPEGImageWriter writer) {
 407         this(false, false);
 408 
 409         boolean wantJFIF = true;
 410         boolean wantAdobe = false;
 411         int transform = JPEG.ADOBE_UNKNOWN;
 412         boolean willSubsample = true;
 413         boolean wantICC = false;
 414         boolean wantProg = false;
 415         boolean wantOptimized = false;
 416         boolean wantExtended = false;
 417         boolean wantQTables = true;
 418         boolean wantHTables = true;
 419         float quality = JPEG.DEFAULT_QUALITY;
 420         byte[] componentIDs = { 1, 2, 3, 4};
 421         int numComponents = 0;


2231             } else if (childName.equals("com")) {
2232                 markerSequence.add(new COMMarkerSegment(node));
2233             } else if (childName.equals("app14Adobe")) {
2234                 markerSequence.add(new AdobeMarkerSegment(node));
2235             } else if (childName.equals("unknown")) {
2236                 markerSequence.add(new MarkerSegment(node));
2237             } else if (childName.equals("sof")) {
2238                 markerSequence.add(new SOFMarkerSegment(node));
2239             } else if (childName.equals("sos")) {
2240                 markerSequence.add(new SOSMarkerSegment(node));
2241             } else {
2242                 throw new IIOInvalidTreeException("Invalid "
2243                     + (isStream ? "stream " : "image ") + "child: "
2244                     + childName, node);
2245             }
2246         }
2247     }
2248 
2249     /**
2250      * Check that this metadata object is in a consistent state and
2251      * return <code>true</code> if it is or <code>false</code>
2252      * otherwise.  All the constructors and modifiers should call
2253      * this method at the end to guarantee that the data is always
2254      * consistent, as the writer relies on this.
2255      */
2256     private boolean isConsistent() {
2257         SOFMarkerSegment sof =
2258             (SOFMarkerSegment) findMarkerSegment(SOFMarkerSegment.class,
2259                                                  true);
2260         JFIFMarkerSegment jfif =
2261             (JFIFMarkerSegment) findMarkerSegment(JFIFMarkerSegment.class,
2262                                                   true);
2263         AdobeMarkerSegment adobe =
2264             (AdobeMarkerSegment) findMarkerSegment(AdobeMarkerSegment.class,
2265                                                    true);
2266         boolean retval = true;
2267         if (!isStream) {
2268             if (sof != null) {
2269                 // SOF numBands = total scan bands
2270                 int numSOFBands = sof.componentSpecs.length;
2271                 int numScanBands = countScanBands();




  49 import java.util.Iterator;
  50 import java.util.ListIterator;
  51 import java.io.IOException;
  52 import java.awt.color.ICC_Profile;
  53 import java.awt.color.ICC_ColorSpace;
  54 import java.awt.color.ColorSpace;
  55 import java.awt.image.BufferedImage;
  56 import java.awt.image.ColorModel;
  57 import java.awt.Point;
  58 
  59 /**
  60  * Metadata for the JPEG plug-in.
  61  */
  62 public class JPEGMetadata extends IIOMetadata implements Cloneable {
  63 
  64     //////// Private variables
  65 
  66     private static final boolean debug = false;
  67 
  68     /**
  69      * A copy of {@code markerSequence}, created the first time the
  70      * {@code markerSequence} is modified.  This is used by reset
  71      * to restore the original state.
  72      */
  73     private List<MarkerSegment> resetSequence = null;
  74 
  75     /**
  76      * Set to {@code true} when reading a thumbnail stored as
  77      * JPEG.  This is used to enforce the prohibition of JFIF thumbnails
  78      * containing any JFIF marker segments, and to ensure generation of
  79      * a correct native subtree during {@code getAsTree}.
  80      */
  81     private boolean inThumb = false;
  82 
  83     /**
  84      * Set by the chroma node construction method to signal the
  85      * presence or absence of an alpha channel to the transparency
  86      * node construction method.  Used only when constructing a
  87      * standard metadata tree.
  88      */
  89     private boolean hasAlpha;
  90 
  91     //////// end of private variables
  92 
  93     /////// Package-access variables
  94 
  95     /**
  96      * All data is a list of {@code MarkerSegment} objects.
  97      * When accessing the list, use the tag to identify the particular
  98      * subclass.  Any JFIF marker segment must be the first element
  99      * of the list if it is present, and any JFXX or APP2ICC marker
 100      * segments are subordinate to the JFIF marker segment.  This
 101      * list is package visible so that the writer can access it.
 102      * @see #MarkerSegment
 103      */
 104     List<MarkerSegment> markerSequence = new ArrayList<>();
 105 
 106     /**
 107      * Indicates whether this object represents stream or image
 108      * metadata.  Package-visible so the writer can see it.
 109      */
 110     final boolean isStream;
 111 
 112     /////// End of package-access variables
 113 
 114     /////// Constructors
 115 
 116     /**
 117      * Constructor containing code shared by other constructors.
 118      */
 119     JPEGMetadata(boolean isStream, boolean inThumb) {
 120         super(true,  // Supports standard format
 121               JPEG.nativeImageMetadataFormatName,  // and a native format
 122               JPEG.nativeImageMetadataFormatClassName,
 123               null, null);  // No other formats
 124         this.inThumb = inThumb;
 125         // But if we are stream metadata, adjust the variables
 126         this.isStream = isStream;
 127         if (isStream) {
 128             nativeMetadataFormatName = JPEG.nativeStreamMetadataFormatName;
 129             nativeMetadataFormatClassName =
 130                 JPEG.nativeStreamMetadataFormatClassName;
 131         }
 132     }
 133 
 134     /*
 135      * Constructs a {@code JPEGMetadata} object by reading the
 136      * contents of an {@code ImageInputStream}.  Has package-only
 137      * access.
 138      *
 139      * @param isStream A boolean indicating whether this object will be
 140      * stream or image metadata.
 141      * @param isThumb A boolean indicating whether this metadata object
 142      * is for an image or for a thumbnail stored as JPEG.
 143      * @param iis An {@code ImageInputStream} from which to read
 144      * the metadata.
 145      * @param reader The {@code JPEGImageReader} calling this
 146      * constructor, to which warnings should be sent.
 147      */
 148     JPEGMetadata(boolean isStream,
 149                  boolean isThumb,
 150                  ImageInputStream iis,
 151                  JPEGImageReader reader) throws IOException {
 152         this(isStream, isThumb);
 153 
 154         JPEGBuffer buffer = new JPEGBuffer(iis);
 155 
 156         buffer.loadBuf(0);
 157 
 158         // The first three bytes should be FF, SOI, FF
 159         if (((buffer.buf[0] & 0xff) != 0xff)
 160             || ((buffer.buf[1] & 0xff) != JPEG.SOI)
 161             || ((buffer.buf[2] & 0xff) != 0xff)) {
 162             throw new IIOException ("Image format error");
 163         }
 164 
 165         boolean done = false;


 348                 markerSequence.add(newGuy);
 349                 if (debug) {
 350                     newGuy.print();
 351                 }
 352                 newGuy = null;
 353             }
 354         }
 355 
 356         // Now that we've read up to the EOI, we need to push back
 357         // whatever is left in the buffer, so that the next read
 358         // in the native code will work.
 359 
 360         buffer.pushBack();
 361 
 362         if (!isConsistent()) {
 363             throw new IIOException("Inconsistent metadata read from stream");
 364         }
 365     }
 366 
 367     /**
 368      * Constructs a default stream {@code JPEGMetadata} object appropriate
 369      * for the given write parameters.
 370      */
 371     JPEGMetadata(ImageWriteParam param, JPEGImageWriter writer) {
 372         this(true, false);
 373 
 374         JPEGImageWriteParam jparam = null;
 375 
 376         if ((param != null) && (param instanceof JPEGImageWriteParam)) {
 377             jparam = (JPEGImageWriteParam) param;
 378             if (!jparam.areTablesSet()) {
 379                 jparam = null;
 380             }
 381         }
 382         if (jparam != null) {
 383             markerSequence.add(new DQTMarkerSegment(jparam.getQTables()));
 384             markerSequence.add
 385                 (new DHTMarkerSegment(jparam.getDCHuffmanTables(),
 386                                       jparam.getACHuffmanTables()));
 387         } else {
 388             // default tables.
 389             markerSequence.add(new DQTMarkerSegment(JPEG.getDefaultQTables()));
 390             markerSequence.add(new DHTMarkerSegment(JPEG.getDefaultHuffmanTables(true),
 391                                                     JPEG.getDefaultHuffmanTables(false)));
 392         }
 393 
 394         // Defensive programming
 395         if (!isConsistent()) {
 396             throw new InternalError("Default stream metadata is inconsistent");
 397         }
 398     }
 399 
 400     /**
 401      * Constructs a default image {@code JPEGMetadata} object appropriate
 402      * for the given image type and write parameters.
 403      */
 404     JPEGMetadata(ImageTypeSpecifier imageType,
 405                  ImageWriteParam param,
 406                  JPEGImageWriter writer) {
 407         this(false, false);
 408 
 409         boolean wantJFIF = true;
 410         boolean wantAdobe = false;
 411         int transform = JPEG.ADOBE_UNKNOWN;
 412         boolean willSubsample = true;
 413         boolean wantICC = false;
 414         boolean wantProg = false;
 415         boolean wantOptimized = false;
 416         boolean wantExtended = false;
 417         boolean wantQTables = true;
 418         boolean wantHTables = true;
 419         float quality = JPEG.DEFAULT_QUALITY;
 420         byte[] componentIDs = { 1, 2, 3, 4};
 421         int numComponents = 0;


2231             } else if (childName.equals("com")) {
2232                 markerSequence.add(new COMMarkerSegment(node));
2233             } else if (childName.equals("app14Adobe")) {
2234                 markerSequence.add(new AdobeMarkerSegment(node));
2235             } else if (childName.equals("unknown")) {
2236                 markerSequence.add(new MarkerSegment(node));
2237             } else if (childName.equals("sof")) {
2238                 markerSequence.add(new SOFMarkerSegment(node));
2239             } else if (childName.equals("sos")) {
2240                 markerSequence.add(new SOSMarkerSegment(node));
2241             } else {
2242                 throw new IIOInvalidTreeException("Invalid "
2243                     + (isStream ? "stream " : "image ") + "child: "
2244                     + childName, node);
2245             }
2246         }
2247     }
2248 
2249     /**
2250      * Check that this metadata object is in a consistent state and
2251      * return {@code true} if it is or {@code false}
2252      * otherwise.  All the constructors and modifiers should call
2253      * this method at the end to guarantee that the data is always
2254      * consistent, as the writer relies on this.
2255      */
2256     private boolean isConsistent() {
2257         SOFMarkerSegment sof =
2258             (SOFMarkerSegment) findMarkerSegment(SOFMarkerSegment.class,
2259                                                  true);
2260         JFIFMarkerSegment jfif =
2261             (JFIFMarkerSegment) findMarkerSegment(JFIFMarkerSegment.class,
2262                                                   true);
2263         AdobeMarkerSegment adobe =
2264             (AdobeMarkerSegment) findMarkerSegment(AdobeMarkerSegment.class,
2265                                                    true);
2266         boolean retval = true;
2267         if (!isStream) {
2268             if (sof != null) {
2269                 // SOF numBands = total scan bands
2270                 int numSOFBands = sof.componentSpecs.length;
2271                 int numScanBands = countScanBands();


< prev index next >