/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Metadata for the JPEG plug-in.
*/
//////// Private variables
private static final boolean debug = false;
/**
* A copy of <code>markerSequence</code>, created the first time the
* <code>markerSequence</code> is modified. This is used by reset
* to restore the original state.
*/
/**
* Set to <code>true</code> when reading a thumbnail stored as
* JPEG. This is used to enforce the prohibition of JFIF thumbnails
* containing any JFIF marker segments, and to ensure generation of
* a correct native subtree during <code>getAsTree</code>.
*/
private boolean inThumb = false;
/**
* Set by the chroma node construction method to signal the
* presence or absence of an alpha channel to the transparency
* node construction method. Used only when constructing a
* standard metadata tree.
*/
private boolean hasAlpha;
//////// end of private variables
/////// Package-access variables
/**
* All data is a list of <code>MarkerSegment</code> objects.
* When accessing the list, use the tag to identify the particular
* subclass. Any JFIF marker segment must be the first element
* of the list if it is present, and any JFXX or APP2ICC marker
* segments are subordinate to the JFIF marker segment. This
* list is package visible so that the writer can access it.
* @see #MarkerSegment
*/
/**
* Indicates whether this object represents stream or image
* metadata. Package-visible so the writer can see it.
*/
final boolean isStream;
/////// End of package-access variables
/////// Constructors
/**
* Constructor containing code shared by other constructors.
*/
super(true, // Supports standard format
// But if we are stream metadata, adjust the variables
if (isStream) {
}
}
/*
* Constructs a <code>JPEGMetadata</code> object by reading the
* contents of an <code>ImageInputStream</code>. Has package-only
* access.
*
* @param isStream A boolean indicating whether this object will be
* stream or image metadata.
* @param isThumb A boolean indicating whether this metadata object
* is for an image or for a thumbnail stored as JPEG.
* @param iis An <code>ImageInputStream</code> from which to read
* the metadata.
* @param reader The <code>JPEGImageReader</code> calling this
* constructor, to which warnings should be sent.
*/
boolean isThumb,
// The first three bytes should be FF, SOI, FF
throw new IIOException ("Image format error");
}
boolean done = false;
while (!done) {
byte [] buf;
int ptr;
if (debug) {
}
case 0:
if (debug) {
}
break;
if (isStream) {
throw new IIOException
("SOF not permitted in stream metadata");
}
break;
break;
break;
break;
// Either JFIF, JFXX, or unknown APP0
if (inThumb) {
// Leave newGuy null
// Read a dummy to skip the segment
new JFIFMarkerSegment(buffer);
} else if (isStream) {
throw new IIOException
("JFIF not permitted in stream metadata");
} else if (markerSequence.isEmpty() == false) {
throw new IIOException
("JFIF APP0 must be first marker after SOI");
} else {
}
if (isStream) {
throw new IIOException
("JFXX not permitted in stream metadata");
}
if (inThumb) {
throw new IIOException
("JFXX markers not allowed in JFIF JPEG thumbnail");
}
(JFIFMarkerSegment.class, true);
throw new IIOException
("JFXX encountered without prior JFIF!");
}
// newGuy remains null
} else {
}
break;
// Either an ICC profile or unknown APP2
) {
if (isStream) {
throw new IIOException
("ICC profiles not permitted in stream metadata");
}
(JFIFMarkerSegment.class, true);
throw new IIOException
("ICC APP2 encountered without prior JFIF!");
}
// newGuy remains null
} else {
}
break;
// Either Adobe or unknown APP14
if (isStream) {
throw new IIOException
("Adobe APP14 markers not permitted in stream metadata");
}
} else {
}
break;
break;
if (isStream) {
throw new IIOException
("SOS not permitted in stream metadata");
}
break;
if (debug) {
}
break;
done = true;
break;
default:
break;
}
if (debug) {
}
}
}
// Now that we've read up to the EOI, we need to push back
// whatever is left in the buffer, so that the next read
// in the native code will work.
if (!isConsistent()) {
throw new IIOException("Inconsistent metadata read from stream");
}
}
/**
* Constructs a default stream <code>JPEGMetadata</code> object appropriate
* for the given write parameters.
*/
this(true, false);
if (!jparam.areTablesSet()) {
}
}
jparam.getACHuffmanTables()));
} else {
// default tables.
JPEG.getDefaultHuffmanTables(false)));
}
// Defensive programming
if (!isConsistent()) {
throw new InternalError("Default stream metadata is inconsistent");
}
}
/**
* Constructs a default image <code>JPEGMetadata</code> object appropriate
* for the given image type and write parameters.
*/
this(false, false);
boolean wantJFIF = true;
boolean wantAdobe = false;
boolean willSubsample = true;
boolean wantICC = false;
boolean wantProg = false;
boolean wantOptimized = false;
boolean wantExtended = false;
boolean wantQTables = true;
boolean wantHTables = true;
int numComponents = 0;
// Ignore the destination type.
}
}
// The only progressive mode that makes sense here is MODE_DEFAULT
if (param.canWriteProgressive()) {
// the param may not be one of ours, so it may return false.
// If so, the following would throw an exception
wantProg = true;
wantOptimized = true;
wantHTables = false;
}
}
if (param instanceof JPEGImageWriteParam) {
if (jparam.areTablesSet()) {
wantQTables = false; // If the param has them, metadata shouldn't
wantHTables = false;
wantExtended = true;
}
}
// Progressive forces optimized, regardless of param setting
// so consult the param re optimized only if not progressive
if (!wantProg) {
if (wantOptimized) {
wantHTables = false;
}
}
}
// compression quality should determine the q tables. Note that this
// will be ignored if we already decided not to create any.
// Again, the param may not be one of ours, so we must check that it
// supports compression settings
if (param.canWriteCompressed()) {
}
}
}
// We are done with the param, now for the image types
switch(type) {
case ColorSpace.TYPE_GRAY:
willSubsample = false;
if (hasExtraComponents) { // e.g. alpha
wantJFIF = false;
}
break;
case ColorSpace.TYPE_3CLR:
wantJFIF = false;
if (hasAlpha) {
}
}
break;
case ColorSpace.TYPE_YCbCr:
if (hasExtraComponents) { // e.g. K or alpha
wantJFIF = false;
if (!hasAlpha) { // Not alpha, so must be K
wantAdobe = true;
}
}
break;
wantJFIF = false;
wantAdobe = true;
willSubsample = false;
if (hasAlpha) {
}
break;
default:
// Everything else is not subsampled, gets no special marker,
// and component ids are 1 - N
wantJFIF = false;
willSubsample = false;
}
switch(type) {
case ColorSpace.TYPE_GRAY:
willSubsample = false;
if (hasExtraComponents) { // e.g. alpha
wantJFIF = false;
}
break;
// without alpha we just accept the JFIF defaults
if (hasAlpha) {
wantJFIF = false;
}
break;
case ColorSpace.TYPE_3CLR:
wantJFIF = false;
willSubsample = false;
willSubsample = true;
wantAdobe = true;
if (hasAlpha) {
}
}
break;
case ColorSpace.TYPE_YCbCr:
if (hasExtraComponents) { // e.g. K or alpha
wantJFIF = false;
if (!hasAlpha) { // then it must be K
wantAdobe = true;
}
}
break;
case ColorSpace.TYPE_CMYK:
wantJFIF = false;
wantAdobe = true;
break;
default:
// Everything else is not subsampled, gets no special marker,
// and component ids are 0 - N
wantJFIF = false;
willSubsample = false;
}
}
// do we want an ICC profile?
wantICC = true;
}
// Now step through the markers, consulting our variables.
if (wantJFIF) {
if (wantICC) {
try {
} catch (IOException e) {} // Can't happen here
}
}
// Adobe
if (wantAdobe) {
}
// dqt
if (wantQTables) {
}
// dht
if (wantHTables) {
}
// sof
// sos
if (!wantProg) { // Default progression scans are done in the writer
}
// Defensive programming
if (!isConsistent()) {
throw new InternalError("Default image metadata is inconsistent");
}
}
////// End of constructors
// Utilities for dealing with the marker sequence.
// The first ones have package access for access from the writer.
/**
* Returns the first MarkerSegment object in the list
* with the given tag, or null if none is found.
*/
return seg;
}
}
return null;
}
/**
* Returns the first or last MarkerSegment object in the list
* of the given class, or null if none is found.
*/
if (first) {
return seg;
}
}
} else {
while (iter.hasPrevious()) {
return seg;
}
}
}
return null;
}
/**
* Returns the index of the first or last MarkerSegment in the list
* of the given class, or -1 if none is found.
*/
if (first) {
return i;
}
}
} else {
return i;
}
}
}
return -1;
}
private int findLastUnknownMarkerSegmentPosition() {
return i;
}
}
return -1;
}
// Implement Cloneable, but restrict access
try {
} catch (CloneNotSupportedException e) {} // won't happen
if (markerSequence != null) {
}
return newGuy;
}
/**
* Returns a deep copy of the current marker sequence.
*/
if (markerSequence == null) {
return null;
}
}
return retval;
}
// Tree methods
if (formatName == null) {
throw new IllegalArgumentException("null formatName!");
}
if (isStream) {
return getNativeTree();
}
} else {
return getNativeTree();
}
if (formatName.equals
return getStandardTree();
}
}
throw new IllegalArgumentException("Unsupported format name: "
+ formatName);
}
if (isStream) {
} else {
if (!inThumb) {
findMarkerSegment(JFIFMarkerSegment.class, true);
}
} else {
}
}
}
return root;
}
// Standard tree node methods
hasAlpha = false; // Unless we find otherwise
// Colorspace type - follow the rules in the spec
// First get the SOF marker segment, if there is one
findMarkerSegment(SOFMarkerSegment.class, true);
// No image, so no chroma
return null;
}
// get the number of channels
// is there a JFIF marker segment?
if (numChannels == 1) {
} else {
}
return chroma;
}
// How about an Adobe marker segment?
case JPEG.ADOBE_YCCK:
break;
break;
case JPEG.ADOBE_UNKNOWN:
if (numChannels == 3) {
} else if (numChannels == 4) {
}
break;
}
return chroma;
}
// Neither marker. Check components
if (numChannels < 3) {
if (numChannels == 2) {
hasAlpha = true;
}
return chroma;
}
boolean idsAreJFIF = true;
idsAreJFIF = false;
}
}
if (idsAreJFIF) {
if (numChannels == 4) {
hasAlpha = true;
}
return chroma;
}
// Check against the letters
if ((numChannels == 4)
hasAlpha = true;
}
return chroma;
}
if ((numChannels == 4)
hasAlpha = true;
}
return chroma;
}
// Finally, 3-channel subsampled are YCbCr, unsubsampled are RGB
// 4-channel subsampled are YCbCrA, unsubsampled are CMYK
boolean subsampled = false;
subsampled = true;
break;
}
}
if (subsampled) {
if (numChannels == 4) {
hasAlpha = true;
}
return chroma;
}
// Not subsampled. numChannels < 3 is taken care of above
if (numChannels == 3) {
} else {
}
return chroma;
}
// CompressionTypeName
// Lossless - false
// NumProgressiveScans - count sos segments
int sosCount = 0;
sosCount++;
}
}
if (sosCount != 0) {
}
return compression;
}
// If we have a JFIF marker segment, we know a little
// otherwise all we know is the orientation, which is always normal
// Aspect Ratio is width of pixel / height of pixel
float aspectRatio;
// In this case they just encode aspect ratio directly
} else {
// They are true densities (e.g. dpi) and must be inverted
}
// Pixel size
// 1 == dpi, 2 == dpc
new IIOMetadataNode("HorizontalPixelSize");
new IIOMetadataNode("VerticalPixelSize");
}
}
return dim;
}
// Add a text entry for each COM Marker Segment
}
}
}
return text;
}
if (hasAlpha == true) {
}
return trans;
}
// Editing
public boolean isReadOnly() {
return false;
}
throws IIOInvalidTreeException {
if (formatName == null) {
throw new IllegalArgumentException("null formatName!");
}
throw new IllegalArgumentException("null root!");
}
if (resetSequence == null) {
} else {
copy = cloneSequence();
}
if (isStream &&
} else if (!isStream &&
} else if (!isStream &&
} else {
throw new IllegalArgumentException("Unsupported format name: "
+ formatName);
}
if (!isConsistent()) {
throw new IIOInvalidTreeException
("Merged tree is invalid; original restored", root);
}
}
root);
}
throw new IIOInvalidTreeException(
"JPEGvariety and markerSequence nodes must be present", root);
}
}
/**
* Merge a JFIF subtree into the marker sequence, if the subtree
* is non-empty.
* If a JFIF marker exists, update it from the subtree.
* If none exists, create one from the subtree and insert it at the
* beginning of the marker sequence.
*/
throws IIOInvalidTreeException {
// is there already a jfif marker segment?
} else {
// Add it as the first element in the list.
}
}
}
throws IIOInvalidTreeException {
} else {
}
}
}
/**
* Merge the given DQT node into the marker sequence. If there already
* exist DQT marker segments in the sequence, then each table in the
* node replaces the first table, in any DQT segment, with the same
* table id. If none of the existing DQT segments contain a table with
* the same id, then the table is added to the last existing DQT segment.
* If there are no DQT segments, then a new one is created and added
* as follows:
* If there are DHT segments, the new DQT segment is inserted before the
* first one.
* If there are no DHT segments, the new DQT segment is inserted before
* an SOF segment, if there is one.
* If there is no SOF segment, the new DQT segment is inserted before
* the first SOS segment, if there is one.
* If there is no SOS segment, the new DQT segment is added to the end
* of the sequence.
*/
// First collect any existing DQT nodes into a local list
if (seg instanceof DQTMarkerSegment) {
}
}
null,
"qtableId",
0, 3,
true);
int tableIndex = -1;
tableIndex = k;
break;
}
}
}
} else {
}
}
} else {
if (firstDHT != -1) {
} else if (firstSOF != -1) {
} else if (firstSOS != -1) {
} else {
}
}
}
/**
* Merge the given DHT node into the marker sequence. If there already
* exist DHT marker segments in the sequence, then each table in the
* node replaces the first table, in any DHT segment, with the same
* table class and table id. If none of the existing DHT segments contain
* a table with the same class and id, then the table is added to the last
* existing DHT segment.
* If there are no DHT segments, then a new one is created and added
* as follows:
* If there are DQT segments, the new DHT segment is inserted immediately
* following the last DQT segment.
* If there are no DQT segments, the new DHT segment is inserted before
* an SOF segment, if there is one.
* If there is no SOF segment, the new DHT segment is inserted before
* the first SOS segment, if there is one.
* If there is no SOS segment, the new DHT segment is added to the end
* of the sequence.
*/
// First collect any existing DQT nodes into a local list
if (seg instanceof DHTMarkerSegment) {
}
}
"htableId",
0, 3,
true);
"class",
0, 1,
true);
int tableIndex = -1;
tableIndex = k;
break;
}
}
}
} else {
}
}
} else {
if (lastDQT != -1) {
} else if (firstSOF != -1) {
} else if (firstSOS != -1) {
} else {
}
}
}
/**
* Merge the given DRI node into the marker sequence.
* If there already exists a DRI marker segment, the restart interval
* value is updated.
* If there is no DRI segment, then a new one is created and added as
* follows:
* If there is an SOF segment, the new DRI segment is inserted before
* it.
* If there is no SOF segment, the new DRI segment is inserted before
* the first SOS segment, if there is one.
* If there is no SOS segment, the new DRI segment is added to the end
* of the sequence.
*/
} else {
if (firstSOF != -1) {
} else if (firstSOS != -1) {
} else {
}
}
}
/**
* Merge the given COM node into the marker sequence.
* A new COM marker segment is created and added to the sequence
* using insertCOMMarkerSegment.
*/
}
/**
* Insert a new COM marker segment into an appropriate place in the
* marker sequence, as follows:
* If there already exist COM marker segments, the new one is inserted
* after the last one.
* If there are no COM segments, the new COM segment is inserted after the
* JFIF segment, if there is one.
* If there is no JFIF segment, the new COM segment is inserted after the
* Adobe marker segment, if there is one.
* If there is no Adobe segment, the new COM segment is inserted
* at the beginning of the sequence.
*/
if (lastCOM != -1) {
} else if (hasJFIF) {
} else if (firstAdobe != -1) {
} else {
}
}
/**
* Merge the given Adobe APP14 node into the marker sequence.
* If there already exists an Adobe marker segment, then its attributes
* are updated from the node.
* If there is no Adobe segment, then a new one is created and added
* using insertAdobeMarkerSegment.
*/
} else {
}
}
/**
* Insert the given AdobeMarkerSegment into the marker sequence, as
* follows (we assume there is no Adobe segment yet):
* If there is a JFIF segment, then the new Adobe segment is inserted
* after it.
* If there is no JFIF segment, the new Adobe segment is inserted after the
* last Unknown segment, if there are any.
* If there are no Unknown segments, the new Adobe segment is inserted
* at the beginning of the sequence.
*/
boolean hasJFIF =
if (hasJFIF) {
} else if (lastUnknown != -1) {
} else {
}
}
/**
* Merge the given Unknown node into the marker sequence.
* A new Unknown marker segment is created and added to the sequence as
* follows:
* If there already exist Unknown marker segments, the new one is inserted
* after the last one.
* If there are no Unknown marker segments, the new Unknown marker segment
* is inserted after the JFIF segment, if there is one.
* If there is no JFIF segment, the new Unknown segment is inserted before
* the Adobe marker segment, if there is one.
* If there is no Adobe segment, the new Unknown segment is inserted
* at the beginning of the sequence.
*/
if (lastUnknown != -1) {
} else if (hasJFIF) {
} if (firstAdobe != -1) {
} else {
}
}
/**
* Merge the given SOF node into the marker sequence.
* If there already exists an SOF marker segment in the sequence, then
* its values are updated from the node.
* If there is no SOF segment, then a new one is created and added as
* follows:
* If there are any SOS segments, the new SOF segment is inserted before
* the first one.
* If there is no SOS segment, the new SOF segment is added to the end
* of the sequence.
*
*/
} else {
if (firstSOS != -1) {
} else {
}
}
}
/**
* Merge the given SOS node into the marker sequence.
* If there already exists a single SOS marker segment, then the values
* are updated from the node.
* If there are more than one existing SOS marker segments, then an
* IIOInvalidTreeException is thrown, as SOS segments cannot be merged
* into a set of progressive scans.
* If there are no SOS marker segments, a new one is created and added
* to the end of the sequence.
*/
throw new IIOInvalidTreeException
("Can't merge SOS node into a tree with > 1 SOS node", node);
}
} else {
}
}
private boolean transparencyDone;
transparencyDone = false;
} else {
}
}
}
/*
* In general, it could be possible to convert all non-pixel data to some
* textual form and include it in comments, but then this would create the
* expectation that these comment forms be recognized by the reader, thus
* creating a defacto extension to JPEG metadata capabilities. This is
* probably best avoided, so the following convert only text nodes to
* comments, and lose the keywords as well.
*/
throws IIOInvalidTreeException {
// ColorSpaceType can change the target colorspace for compression
// This must take any transparency node into account as well, as
// that affects the number of channels (if alpha is present). If
// a transparency node is dealt with here, set a flag to indicate
// this to the transparency processor below. If we discover that
// the nodes are not in order, throw an exception as the tree is
// invalid.
if (transparencyDone) {
throw new IIOInvalidTreeException
("Transparency node must follow Chroma node", node);
}
// If there is no ColorSpaceType node, we have nothing to do
return;
}
int numChannels = 0;
boolean wantJFIF = false;
boolean wantAdobe = false;
int transform = 0;
boolean willSubsample = false;
numChannels = 1;
wantJFIF = true;
numChannels = 3;
wantJFIF = true;
willSubsample = true;
numChannels = 3;
wantAdobe = true;
numChannels = 3;
wantAdobe = true;
numChannels = 3;
numChannels = 4;
wantAdobe = true;
willSubsample = true;
numChannels = 4;
wantAdobe = true;
numChannels = 4;
} else { // We can't handle them, so don't modify any metadata
return;
}
boolean wantAlpha = false;
break; // out of for
}
}
if (wantAlpha) {
numChannels++;
wantJFIF = false;
wantAdobe = false;
}
}
// If the metadata specifies progressive, then the number of channels
// must match, so that we can modify all the existing SOS marker segments.
// If they don't match, we don't know what to do with SOS so we can't do
// the merge. We then just return silently.
// An exception would not be appropriate. A warning might, but we have
// nowhere to send it to.
return;
}
}
// JFIF header might be removed
}
// Now add a JFIF if we do want one, but only if it isn't stream metadata
}
// Adobe header might be removed or the transform modified, if it isn't
// stream metadata
if (wantAdobe) {
} else {
}
}
boolean updateQtables = false;
boolean updateHtables = false;
boolean progressive = false;
int [] newTableSelectors = willSubsample
// Keep the old componentSpecs array
// SOF might be modified
// Now replace the SOF with a new one; it might be the same, but
// this is easier.
false, // we never need extended
ids,
numChannels));
// Now suss out if subsampling changed and set the boolean for
// updating the q tables
// if the old componentSpec q table selectors don't match
// the new ones, update the qtables. The new selectors are already
// in place in the new SOF segment above.
updateQtables = true;
}
}
if (progressive) {
// if the component ids are different, update all the existing scans
// ignore Huffman tables
boolean idsDiffer = false;
idsDiffer = true;
}
}
if (idsDiffer) {
// update the ids in each SOS marker segment
if (seg instanceof SOSMarkerSegment) {
int oldSelector =
// Find the position in the old componentSpecs array
// of the old component with the old selector
// and replace the component selector with the
// new id at the same position, as these match
// the new component specs array in the SOF created
// above.
ids[j];
}
}
}
}
}
}
} else {
// htables - if the old htable selectors don't match the new ones,
// update the tables.
!= newTableSelectors[i])
!= newTableSelectors[i])) {
updateHtables = true;
}
}
// Might be the same as the old one, but this is easier.
ids,
numChannels));
}
}
} else {
// should be stream metadata if there isn't an SOF, but check it anyway
if (isStream) {
// update tables - routines below check if it's really necessary
updateQtables = true;
updateHtables = true;
}
}
if (updateQtables) {
if (seg instanceof DQTMarkerSegment) {
}
}
// If there are no tables, don't add them, as the metadata encodes an
// abbreviated stream.
// If we are not subsampling, we just need one, so don't do anything
// Is it really necessary? There should be at least 2 tables.
// If there is only one, assume it's a scaled "standard"
// luminance table, extract the scaling factor, and generate a
// scaled "standard" chrominance table.
// Find the table with selector 1.
boolean found = false;
found = true;
}
}
}
if (!found) {
// find the table with selector 0. There should be one.
}
}
}
// Assuming that the table with id 0 is a luminance table,
// compute a new chrominance table of the same quality and
// add it to the last DQT segment
}
}
}
if (updateHtables) {
if (seg instanceof DHTMarkerSegment) {
}
}
// If there are no tables, don't add them, as the metadata encodes an
// abbreviated stream.
// If we are not subsampling, we just need one, so don't do anything
// Is it really necessary? There should be at least 2 dc and 2 ac
// tables. If there is only one, add a
// "standard " chrominance table.
boolean found = false;
found = true;
}
}
}
if (!found) {
// Create new standard dc and ac chrominance tables and add them
// to the last DHT segment
}
}
}
}
boolean returnValue = false;
if (alpha.hasAttributes()) {
returnValue = true;
}
}
}
transparencyDone = true;
return returnValue;
}
throws IIOInvalidTreeException {
// NumProgressiveScans is ignored. Progression must be enabled on the
// ImageWriteParam.
// No-op
}
throws IIOInvalidTreeException {
// No-op
}
throws IIOInvalidTreeException {
// Pixel Aspect Ratio or pixel size can be incorporated if there is,
// or can be, a JFIF segment
// Can there be one?
// Criteria:
// SOF must be present with 1 or 3 channels, (stream metadata fails this)
// Component ids must be JFIF compatible.
boolean canHaveJFIF = false;
canHaveJFIF = true; // remaining tests are negative
canHaveJFIF = false;
}
// if Adobe present, transform = ADOBE_UNKNOWN for 1-channel,
// ADOBE_YCC for 3-channel.
true);
canHaveJFIF = false;
}
}
}
}
// If so, create one and insert it into the sequence. Note that
// default is just pixel ratio at 1:1
if (canHaveJFIF) {
jfif = new JFIFMarkerSegment();
}
}
}
}
}
}
/*
* Return a pair of integers whose ratio (x/y) approximates the given
* float value.
*/
float epsilon = 0.005F;
// Normalize
// Deal with min case
}
// Deal with max case
if (value >= 255) {
}
// Remember if we invert
boolean inverted = false;
if (value < 1.0) {
inverted = true;
}
// First approximation
int y = 1;
float ratio = (float) x;
// Increment y and compute a new x
y++;
ratio = (float)x/(float)y;
}
}
throws IIOInvalidTreeException {
// No-op
}
throws IIOInvalidTreeException {
// Convert to comments. For the moment ignore the encoding issue.
// Ignore keywords, language, and encoding (for the moment).
// If compression tag is present, use only entries with "none".
boolean copyIt = true;
copyIt = false;
}
}
if (copyIt) {
}
}
}
throws IIOInvalidTreeException {
// This might indicate that an alpha channel is being added or removed.
// The nodes must appear in order, and a Chroma node will process any
// transparency, so process it here only if there was no Chroma node
// Do nothing for stream metadata
if (!transparencyDone && !isStream) {
// do we have alpha already? If the number of channels is 2 or 4,
// we do, as we don't support CMYK, nor can we add alpha to it
// The number of channels can be determined from the SOF
(JFIFMarkerSegment.class, true);
(AdobeMarkerSegment.class, true);
(SOFMarkerSegment.class, true);
(SOSMarkerSegment.class, true);
// We can do nothing for progressive, as we don't know how to
// modify the scans.
return;
}
// Do we already have alpha? We can tell by the number of channels
// We must have an sof, or we can't do anything further
// proceed only if the old state and the new state differ
if (wantAlpha) { // Adding alpha
numChannels++;
}
// If an adobe marker is present, transform must be UNKNOWN
}
// Add a component spec with appropriate parameters to SOF
}
// Add a component spec with appropriate parameters to SOS
}
} else { // Removing alpha
numChannels--;
// Remove a component spec from SOF
for (int i = 0; i < numChannels; i++) {
}
// Remove a component spec from SOS
for (int i = 0; i < numChannels; i++) {
}
}
}
}
}
}
throws IIOInvalidTreeException {
if (formatName == null) {
throw new IllegalArgumentException("null formatName!");
}
throw new IllegalArgumentException("null root!");
}
if (isStream &&
} else if (!isStream &&
} else if (!isStream &&
// In this case a reset followed by a merge is correct
} else {
throw new IllegalArgumentException("Unsupported format name: "
+ formatName);
}
}
if (resetSequence == null) {
}
markerSequence = new ArrayList();
// Build a whole new marker sequence from the tree
root);
}
if (!isStream) {
throw new IIOInvalidTreeException(
"JPEGvariety and markerSequence nodes must be present", root);
}
}
}
}
throws IIOInvalidTreeException{
// for all the children, add a marker segment
} else {
throw new IIOInvalidTreeException("Invalid "
}
}
}
/**
* Check that this metadata object is in a consistent state and
* return <code>true</code> if it is or <code>false</code>
* otherwise. All the constructors and modifiers should call
* this method at the end to guarantee that the data is always
* consistent, as the writer relies on this.
*/
private boolean isConsistent() {
true);
true);
true);
boolean retval = true;
if (!isStream) {
// SOF numBands = total scan bands
int numScanBands = countScanBands();
if (numScanBands != numSOFBands) {
retval = false;
}
}
// If JFIF is present, component ids are 1-3, bands are 1 or 3
retval = false;
}
for (int i = 0; i < numSOFBands; i++) {
retval = false;
}
}
// If both JFIF and Adobe are present,
// Adobe transform == unknown for gray,
// YCC for 3-chan.
&& (((numSOFBands == 1)
|| ((numSOFBands == 3)
retval = false;
}
}
} else {
// stream can't have jfif, adobe, sof, or sos
true);
retval = false;
}
}
}
return retval;
}
/**
* Returns the total number of bands referenced in all SOS marker
* segments, including 0 if there are no SOS marker segments.
*/
private int countScanBands() {
if (seg instanceof SOSMarkerSegment) {
}
}
}
}
}
///// Writer support
boolean ignoreJFIF,
boolean forceJFIF,
boolean ignoreAdobe,
int newAdobeTransform,
throws IOException {
if (forceJFIF) {
// Write a default JFIF segment, including thumbnails
// This won't be duplicated below because forceJFIF will be
// set only if there is no JFIF present already.
writer);
if ((ignoreAdobe == false)
// Not compatible, so ignore Adobe.
ignoreAdobe = true;
}
}
}
// Iterate over each MarkerSegment
if (seg instanceof JFIFMarkerSegment) {
if (ignoreJFIF == false) {
if (iccProfile != null) {
}
} // Otherwise ignore it, as requested
} else if (seg instanceof AdobeMarkerSegment) {
if (ignoreAdobe == false) {
} else if (forceJFIF) {
// If adobe isn't JFIF compatible, ignore it
} else {
}
} else {
}
} // Otherwise ignore it, as requested
} else {
}
}
}
//// End of writer support
public void reset() {
}
}
public void print() {
}
}
}