8143342: Integrate Java Image I/O support for TIFF per JEP 262
Port TIFF reader and writer plugins from JAI Image I/O Tools to JDK 9 Reviewed-by: prr, serb
This commit is contained in:
parent
d1c0c842fb
commit
17a615784e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,7 @@ import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
@ -47,64 +48,15 @@ import java.awt.image.SampleModel;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Arrays;
|
||||
|
||||
//import javax.imageio.ImageTypeSpecifier;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
|
||||
public class ImageUtil {
|
||||
/* XXX testing only
|
||||
public static void main(String[] args) {
|
||||
ImageTypeSpecifier bilevel =
|
||||
ImageTypeSpecifier.createIndexed(new byte[] {(byte)0, (byte)255},
|
||||
new byte[] {(byte)0, (byte)255},
|
||||
new byte[] {(byte)0, (byte)255},
|
||||
null, 1,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
ImageTypeSpecifier gray =
|
||||
ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false);
|
||||
ImageTypeSpecifier grayAlpha =
|
||||
ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false,
|
||||
false);
|
||||
ImageTypeSpecifier rgb =
|
||||
ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[] {0, 1, 2},
|
||||
DataBuffer.TYPE_BYTE,
|
||||
false,
|
||||
false);
|
||||
ImageTypeSpecifier rgba =
|
||||
ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[] {0, 1, 2, 3},
|
||||
DataBuffer.TYPE_BYTE,
|
||||
true,
|
||||
false);
|
||||
ImageTypeSpecifier packed =
|
||||
ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
0xff000000,
|
||||
0x00ff0000,
|
||||
0x0000ff00,
|
||||
0x000000ff,
|
||||
DataBuffer.TYPE_BYTE,
|
||||
false);
|
||||
|
||||
SampleModel bandedSM =
|
||||
new java.awt.image.BandedSampleModel(DataBuffer.TYPE_BYTE,
|
||||
1, 1, 15);
|
||||
|
||||
System.out.println(createColorModel(bilevel.getSampleModel()));
|
||||
System.out.println(createColorModel(gray.getSampleModel()));
|
||||
System.out.println(createColorModel(grayAlpha.getSampleModel()));
|
||||
System.out.println(createColorModel(rgb.getSampleModel()));
|
||||
System.out.println(createColorModel(rgba.getSampleModel()));
|
||||
System.out.println(createColorModel(packed.getSampleModel()));
|
||||
System.out.println(createColorModel(bandedSM));
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a <code>ColorModel</code> that may be used with the
|
||||
* specified <code>SampleModel</code>. If a suitable
|
||||
@ -1162,4 +1114,78 @@ public class ImageUtil {
|
||||
// pixel stride.
|
||||
return ImageUtil.isBinary(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destination image type.
|
||||
*/
|
||||
public static final ImageTypeSpecifier
|
||||
getDestinationType(ImageReadParam param,
|
||||
Iterator<ImageTypeSpecifier> imageTypes) throws IIOException {
|
||||
|
||||
if (imageTypes == null || !imageTypes.hasNext()) {
|
||||
throw new IllegalArgumentException("imageTypes null or empty!");
|
||||
}
|
||||
|
||||
ImageTypeSpecifier imageType = null;
|
||||
|
||||
// If param is non-null, use it
|
||||
if (param != null) {
|
||||
imageType = param.getDestinationType();
|
||||
}
|
||||
|
||||
// No info from param, use fallback image type
|
||||
if (imageType == null) {
|
||||
Object o = imageTypes.next();
|
||||
if (!(o instanceof ImageTypeSpecifier)) {
|
||||
throw new IllegalArgumentException
|
||||
("Non-ImageTypeSpecifier retrieved from imageTypes!");
|
||||
}
|
||||
imageType = (ImageTypeSpecifier)o;
|
||||
} else {
|
||||
boolean foundIt = false;
|
||||
while (imageTypes.hasNext()) {
|
||||
ImageTypeSpecifier type =
|
||||
imageTypes.next();
|
||||
if (type.equals(imageType)) {
|
||||
foundIt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundIt) {
|
||||
throw new IIOException
|
||||
("Destination type from ImageReadParam does not match!");
|
||||
}
|
||||
}
|
||||
|
||||
return imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the given <code>ColorSpace</code> object is
|
||||
* an instance of <code>ICC_ColorSpace</code> but is not one of the standard
|
||||
* <code>ColorSpace</code>s returned by <code>ColorSpace.getInstance()</code>.
|
||||
*
|
||||
* @param cs The <code>ColorSpace</code> to test.
|
||||
*/
|
||||
public static boolean isNonStandardICCColorSpace(ColorSpace cs) {
|
||||
boolean retval = false;
|
||||
|
||||
try {
|
||||
// Check the standard ColorSpaces in decreasing order of
|
||||
// likelihood except check CS_PYCC last as in some JREs
|
||||
// PYCC.pf used not to be installed.
|
||||
retval =
|
||||
(cs instanceof ICC_ColorSpace) &&
|
||||
!(cs.isCS_sRGB() ||
|
||||
cs.equals(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) ||
|
||||
cs.equals(ColorSpace.getInstance(ColorSpace.CS_GRAY)) ||
|
||||
cs.equals(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ)) ||
|
||||
cs.equals(ColorSpace.getInstance(ColorSpace.CS_PYCC)));
|
||||
} catch(IllegalArgumentException e) {
|
||||
// PYCC.pf not installed: ignore it - 'retval' is still 'false'.
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.common;
|
||||
|
||||
import java.awt.color.ColorSpace;
|
||||
|
||||
/**
|
||||
* Singleton class representing a simple, mathematically defined CMYK
|
||||
* color space.
|
||||
*/
|
||||
public final class SimpleCMYKColorSpace extends ColorSpace {
|
||||
private static final long serialVersionUID = 666L; // XXX Revise UID value
|
||||
|
||||
private static ColorSpace theInstance = null;
|
||||
private ColorSpace csRGB;
|
||||
|
||||
/** The exponent for gamma correction. */
|
||||
private static final double power1 = 1.0 / 2.4;
|
||||
|
||||
public static final synchronized ColorSpace getInstance() {
|
||||
if(theInstance == null) {
|
||||
theInstance = new SimpleCMYKColorSpace();
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
|
||||
private SimpleCMYKColorSpace() {
|
||||
super(TYPE_CMYK, 4);
|
||||
csRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o != null && o instanceof SimpleCMYKColorSpace;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return theInstance.hashCode();
|
||||
}
|
||||
|
||||
public float[] toRGB(float[] colorvalue) {
|
||||
float C = colorvalue[0];
|
||||
float M = colorvalue[1];
|
||||
float Y = colorvalue[2];
|
||||
float K = colorvalue[3];
|
||||
|
||||
float K1 = 1.0F - K;
|
||||
|
||||
// Convert from CMYK to linear RGB.
|
||||
float[] rgbvalue = new float[] {K1*(1.0F - C),
|
||||
K1*(1.0F - M),
|
||||
K1*(1.0F - Y)};
|
||||
|
||||
// Convert from linear RGB to sRGB.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float v = rgbvalue[i];
|
||||
|
||||
if (v < 0.0F) v = 0.0F;
|
||||
|
||||
if (v < 0.0031308F) {
|
||||
rgbvalue[i] = 12.92F * v;
|
||||
} else {
|
||||
if (v > 1.0F) v = 1.0F;
|
||||
|
||||
rgbvalue[i] = (float)(1.055 * Math.pow(v, power1) - 0.055);
|
||||
}
|
||||
}
|
||||
|
||||
return rgbvalue;
|
||||
}
|
||||
|
||||
public float[] fromRGB(float[] rgbvalue) {
|
||||
// Convert from sRGB to linear RGB.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (rgbvalue[i] < 0.040449936F) {
|
||||
rgbvalue[i] /= 12.92F;
|
||||
} else {
|
||||
rgbvalue[i] =
|
||||
(float)(Math.pow((rgbvalue[i] + 0.055)/1.055, 2.4));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert from linear RGB to CMYK.
|
||||
float C = 1.0F - rgbvalue[0];
|
||||
float M = 1.0F - rgbvalue[1];
|
||||
float Y = 1.0F - rgbvalue[2];
|
||||
float K = Math.min(C, Math.min(M, Y));
|
||||
|
||||
// If K == 1.0F, then C = M = Y = 1.0F.
|
||||
if(K != 1.0F) {
|
||||
float K1 = 1.0F - K;
|
||||
|
||||
C = (C - K)/K1;
|
||||
M = (M - K)/K1;
|
||||
Y = (Y - K)/K1;
|
||||
} else {
|
||||
C = M = Y = 0.0F;
|
||||
}
|
||||
|
||||
return new float[] {C, M, Y, K};
|
||||
}
|
||||
|
||||
public float[] toCIEXYZ(float[] colorvalue) {
|
||||
return csRGB.toCIEXYZ(toRGB(colorvalue));
|
||||
}
|
||||
|
||||
public float[] fromCIEXYZ(float[] xyzvalue) {
|
||||
return fromRGB(csRGB.fromCIEXYZ(xyzvalue));
|
||||
}
|
||||
}
|
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.common;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
public abstract class SimpleRenderedImage implements RenderedImage {
|
||||
/** The X coordinate of the image's upper-left pixel. */
|
||||
protected int minX;
|
||||
|
||||
/** The Y coordinate of the image's upper-left pixel. */
|
||||
protected int minY;
|
||||
|
||||
/** The image's width in pixels. */
|
||||
protected int width;
|
||||
|
||||
/** The image's height in pixels. */
|
||||
protected int height;
|
||||
|
||||
/** The width of a tile. */
|
||||
protected int tileWidth;
|
||||
|
||||
/** The height of a tile. */
|
||||
protected int tileHeight;
|
||||
|
||||
/** The X coordinate of the upper-left pixel of tile (0, 0). */
|
||||
protected int tileGridXOffset = 0;
|
||||
|
||||
/** The Y coordinate of the upper-left pixel of tile (0, 0). */
|
||||
protected int tileGridYOffset = 0;
|
||||
|
||||
/** The image's SampleModel. */
|
||||
protected SampleModel sampleModel;
|
||||
|
||||
/** The image's ColorModel. */
|
||||
protected ColorModel colorModel;
|
||||
|
||||
/** The image's sources, stored in a Vector. */
|
||||
protected Vector<RenderedImage> sources = new Vector<RenderedImage>();
|
||||
|
||||
/** A Hashtable containing the image properties. */
|
||||
protected Hashtable<String,Object> properties = new Hashtable<String,Object>();
|
||||
|
||||
/** Returns the X coordinate of the leftmost column of the image. */
|
||||
public int getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the X coordinate of the column immediatetely to the
|
||||
* right of the rightmost column of the image. getMaxX() is
|
||||
* implemented in terms of getMinX() and getWidth() and so does
|
||||
* not need to be implemented by subclasses.
|
||||
*/
|
||||
public final int getMaxX() {
|
||||
return getMinX() + getWidth();
|
||||
}
|
||||
|
||||
/** Returns the X coordinate of the uppermost row of the image. */
|
||||
public int getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y coordinate of the row immediately below the
|
||||
* bottom row of the image. getMaxY() is implemented in terms of
|
||||
* getMinY() and getHeight() and so does not need to be
|
||||
* implemented by subclasses.
|
||||
*/
|
||||
public final int getMaxY() {
|
||||
return getMinY() + getHeight();
|
||||
}
|
||||
|
||||
/** Returns the width of the image. */
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/** Returns the height of the image. */
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
/** Returns a Rectangle indicating the image bounds. */
|
||||
public Rectangle getBounds() {
|
||||
return new Rectangle(getMinX(), getMinY(), getWidth(), getHeight());
|
||||
}
|
||||
|
||||
/** Returns the width of a tile. */
|
||||
public int getTileWidth() {
|
||||
return tileWidth;
|
||||
}
|
||||
|
||||
/** Returns the height of a tile. */
|
||||
public int getTileHeight() {
|
||||
return tileHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the X coordinate of the upper-left pixel of tile (0, 0).
|
||||
*/
|
||||
public int getTileGridXOffset() {
|
||||
return tileGridXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y coordinate of the upper-left pixel of tile (0, 0).
|
||||
*/
|
||||
public int getTileGridYOffset() {
|
||||
return tileGridYOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal index of the leftmost column of tiles.
|
||||
* getMinTileX() is implemented in terms of getMinX()
|
||||
* and so does not need to be implemented by subclasses.
|
||||
*/
|
||||
public int getMinTileX() {
|
||||
return XToTileX(getMinX());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal index of the rightmost column of tiles.
|
||||
* getMaxTileX() is implemented in terms of getMaxX()
|
||||
* and so does not need to be implemented by subclasses.
|
||||
*/
|
||||
public int getMaxTileX() {
|
||||
return XToTileX(getMaxX() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tiles along the tile grid in the
|
||||
* horizontal direction. getNumXTiles() is implemented in terms
|
||||
* of getMinTileX() and getMaxTileX() and so does not need to be
|
||||
* implemented by subclasses.
|
||||
*/
|
||||
public int getNumXTiles() {
|
||||
return getMaxTileX() - getMinTileX() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical index of the uppermost row of tiles. getMinTileY()
|
||||
* is implemented in terms of getMinY() and so does not need to be
|
||||
* implemented by subclasses.
|
||||
*/
|
||||
public int getMinTileY() {
|
||||
return YToTileY(getMinY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical index of the bottom row of tiles. getMaxTileY()
|
||||
* is implemented in terms of getMaxY() and so does not need to
|
||||
* be implemented by subclasses.
|
||||
*/
|
||||
public int getMaxTileY() {
|
||||
return YToTileY(getMaxY() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tiles along the tile grid in the vertical
|
||||
* direction. getNumYTiles() is implemented in terms
|
||||
* of getMinTileY() and getMaxTileY() and so does not need to be
|
||||
* implemented by subclasses.
|
||||
*/
|
||||
public int getNumYTiles() {
|
||||
return getMaxTileY() - getMinTileY() + 1;
|
||||
}
|
||||
|
||||
/** Returns the SampleModel of the image. */
|
||||
public SampleModel getSampleModel() {
|
||||
return sampleModel;
|
||||
}
|
||||
|
||||
/** Returns the ColorModel of the image. */
|
||||
public ColorModel getColorModel() {
|
||||
return colorModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property from the property set of this image. If the
|
||||
* property name is not recognized,
|
||||
* <code>java.awt.Image.UndefinedProperty</code> will be returned.
|
||||
*
|
||||
* @param name the name of the property to get, as a
|
||||
* <code>String</code>. @return a reference to the property
|
||||
* <code>Object</code>, or the value
|
||||
* <code>java.awt.Image.UndefinedProperty.</code>
|
||||
*/
|
||||
public Object getProperty(String name) {
|
||||
name = name.toLowerCase();
|
||||
Object value = properties.get(name);
|
||||
return value != null ? value : java.awt.Image.UndefinedProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the properties recognized by this image. If
|
||||
* no properties are available, <code>null</code> will be
|
||||
* returned.
|
||||
*
|
||||
* @return an array of <code>String</code>s representing valid
|
||||
* property names.
|
||||
*/
|
||||
public String[] getPropertyNames() {
|
||||
String[] names = null;
|
||||
|
||||
if(properties.size() > 0) {
|
||||
names = new String[properties.size()];
|
||||
int index = 0;
|
||||
|
||||
Enumeration<String> e = properties.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
String name = e.nextElement();
|
||||
names[index++] = name;
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of <code>String</code>s recognized as names by
|
||||
* this property source that begin with the supplied prefix. If
|
||||
* no property names match, <code>null</code> will be returned.
|
||||
* The comparison is done in a case-independent manner.
|
||||
*
|
||||
* <p> The default implementation calls
|
||||
* <code>getPropertyNames()</code> and searches the list of names
|
||||
* for matches.
|
||||
*
|
||||
* @return an array of <code>String</code>s giving the valid
|
||||
* property names.
|
||||
*/
|
||||
public String[] getPropertyNames(String prefix) {
|
||||
String propertyNames[] = getPropertyNames();
|
||||
if (propertyNames == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
prefix = prefix.toLowerCase();
|
||||
|
||||
Vector<String> names = new Vector<String>();
|
||||
for (int i = 0; i < propertyNames.length; i++) {
|
||||
if (propertyNames[i].startsWith(prefix)) {
|
||||
names.addElement(propertyNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (names.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Copy the strings from the Vector over to a String array.
|
||||
String prefixNames[] = new String[names.size()];
|
||||
int count = 0;
|
||||
for (Iterator<String> it = names.iterator(); it.hasNext(); ) {
|
||||
prefixNames[count++] = it.next();
|
||||
}
|
||||
|
||||
return prefixNames;
|
||||
}
|
||||
|
||||
// Utility methods.
|
||||
|
||||
/**
|
||||
* Converts a pixel's X coordinate into a horizontal tile index
|
||||
* relative to a given tile grid layout specified by its X offset
|
||||
* and tile width.
|
||||
*/
|
||||
public static int XToTileX(int x, int tileGridXOffset, int tileWidth) {
|
||||
x -= tileGridXOffset;
|
||||
if (x < 0) {
|
||||
x += 1 - tileWidth; // Force round to -infinity
|
||||
}
|
||||
return x/tileWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a pixel's Y coordinate into a vertical tile index
|
||||
* relative to a given tile grid layout specified by its Y offset
|
||||
* and tile height.
|
||||
*/
|
||||
public static int YToTileY(int y, int tileGridYOffset, int tileHeight) {
|
||||
y -= tileGridYOffset;
|
||||
if (y < 0) {
|
||||
y += 1 - tileHeight; // Force round to -infinity
|
||||
}
|
||||
return y/tileHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a pixel's X coordinate into a horizontal tile index.
|
||||
* This is a convenience method. No attempt is made to detect
|
||||
* out-of-range coordinates.
|
||||
*
|
||||
* @param x the X coordinate of a pixel.
|
||||
* @return the X index of the tile containing the pixel.
|
||||
*/
|
||||
public int XToTileX(int x) {
|
||||
return XToTileX(x, getTileGridXOffset(), getTileWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a pixel's Y coordinate into a vertical tile index.
|
||||
* This is a convenience method. No attempt is made to detect
|
||||
* out-of-range coordinates.
|
||||
*
|
||||
* @param y the Y coordinate of a pixel.
|
||||
* @return the Y index of the tile containing the pixel.
|
||||
*/
|
||||
public int YToTileY(int y) {
|
||||
return YToTileY(y, getTileGridYOffset(), getTileHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a horizontal tile index into the X coordinate of its
|
||||
* upper left pixel relative to a given tile grid layout specified
|
||||
* by its X offset and tile width.
|
||||
*/
|
||||
public static int tileXToX(int tx, int tileGridXOffset, int tileWidth) {
|
||||
return tx*tileWidth + tileGridXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a vertical tile index into the Y coordinate of
|
||||
* its upper left pixel relative to a given tile grid layout
|
||||
* specified by its Y offset and tile height.
|
||||
*/
|
||||
public static int tileYToY(int ty, int tileGridYOffset, int tileHeight) {
|
||||
return ty*tileHeight + tileGridYOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a horizontal tile index into the X coordinate of its
|
||||
* upper left pixel. This is a convenience method. No attempt is made
|
||||
* to detect out-of-range indices.
|
||||
*
|
||||
* @param tx the horizontal index of a tile.
|
||||
* @return the X coordinate of the tile's upper left pixel.
|
||||
*/
|
||||
public int tileXToX(int tx) {
|
||||
return tx*tileWidth + tileGridXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a vertical tile index into the Y coordinate of its
|
||||
* upper left pixel. This is a convenience method. No attempt is made
|
||||
* to detect out-of-range indices.
|
||||
*
|
||||
* @param ty the vertical index of a tile.
|
||||
* @return the Y coordinate of the tile's upper left pixel.
|
||||
*/
|
||||
public int tileYToY(int ty) {
|
||||
return ty*tileHeight + tileGridYOffset;
|
||||
}
|
||||
|
||||
public Vector<RenderedImage> getSources() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entire image in a single Raster. For images with
|
||||
* multiple tiles this will require making a copy.
|
||||
*
|
||||
* <p> The returned Raster is semantically a copy. This means
|
||||
* that updates to the source image will not be reflected in the
|
||||
* returned Raster. For non-writable (immutable) source images,
|
||||
* the returned value may be a reference to the image's internal
|
||||
* data. The returned Raster should be considered non-writable;
|
||||
* any attempt to alter its pixel data (such as by casting it to
|
||||
* WritableRaster or obtaining and modifying its DataBuffer) may
|
||||
* result in undefined behavior. The copyData method should be
|
||||
* used if the returned Raster is to be modified.
|
||||
*
|
||||
* @return a Raster containing a copy of this image's data.
|
||||
*/
|
||||
public Raster getData() {
|
||||
Rectangle rect = new Rectangle(getMinX(), getMinY(),
|
||||
getWidth(), getHeight());
|
||||
return getData(rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an arbitrary rectangular region of the RenderedImage
|
||||
* in a Raster. The rectangle of interest will be clipped against
|
||||
* the image bounds.
|
||||
*
|
||||
* <p> The returned Raster is semantically a copy. This means
|
||||
* that updates to the source image will not be reflected in the
|
||||
* returned Raster. For non-writable (immutable) source images,
|
||||
* the returned value may be a reference to the image's internal
|
||||
* data. The returned Raster should be considered non-writable;
|
||||
* any attempt to alter its pixel data (such as by casting it to
|
||||
* WritableRaster or obtaining and modifying its DataBuffer) may
|
||||
* result in undefined behavior. The copyData method should be
|
||||
* used if the returned Raster is to be modified.
|
||||
*
|
||||
* @param bounds the region of the RenderedImage to be returned.
|
||||
*/
|
||||
public Raster getData(Rectangle bounds) {
|
||||
// Get the image bounds.
|
||||
Rectangle imageBounds = getBounds();
|
||||
|
||||
// Check for parameter validity.
|
||||
if(bounds == null) {
|
||||
bounds = imageBounds;
|
||||
} else if(!bounds.intersects(imageBounds)) {
|
||||
throw new IllegalArgumentException("The provided region doesn't intersect with the image bounds.");
|
||||
}
|
||||
|
||||
// Determine tile limits for the prescribed bounds.
|
||||
int startX = XToTileX(bounds.x);
|
||||
int startY = YToTileY(bounds.y);
|
||||
int endX = XToTileX(bounds.x + bounds.width - 1);
|
||||
int endY = YToTileY(bounds.y + bounds.height - 1);
|
||||
|
||||
// If the bounds are contained in a single tile, return a child
|
||||
// of that tile's Raster.
|
||||
if ((startX == endX) && (startY == endY)) {
|
||||
Raster tile = getTile(startX, startY);
|
||||
return tile.createChild(bounds.x, bounds.y,
|
||||
bounds.width, bounds.height,
|
||||
bounds.x, bounds.y, null);
|
||||
} else {
|
||||
// Recalculate the tile limits if the data bounds are not a
|
||||
// subset of the image bounds.
|
||||
if(!imageBounds.contains(bounds)) {
|
||||
Rectangle xsect = bounds.intersection(imageBounds);
|
||||
startX = XToTileX(xsect.x);
|
||||
startY = YToTileY(xsect.y);
|
||||
endX = XToTileX(xsect.x + xsect.width - 1);
|
||||
endY = YToTileY(xsect.y + xsect.height - 1);
|
||||
}
|
||||
|
||||
// Create a WritableRaster of the desired size
|
||||
SampleModel sm =
|
||||
sampleModel.createCompatibleSampleModel(bounds.width,
|
||||
bounds.height);
|
||||
|
||||
// Translate it
|
||||
WritableRaster dest =
|
||||
Raster.createWritableRaster(sm, bounds.getLocation());
|
||||
|
||||
// Loop over the tiles in the intersection.
|
||||
for (int j = startY; j <= endY; j++) {
|
||||
for (int i = startX; i <= endX; i++) {
|
||||
// Retrieve the tile.
|
||||
Raster tile = getTile(i, j);
|
||||
|
||||
// Create a child of the tile for the intersection of
|
||||
// the tile bounds and the bounds of the requested area.
|
||||
Rectangle tileRect = tile.getBounds();
|
||||
Rectangle intersectRect =
|
||||
bounds.intersection(tile.getBounds());
|
||||
Raster liveRaster = tile.createChild(intersectRect.x,
|
||||
intersectRect.y,
|
||||
intersectRect.width,
|
||||
intersectRect.height,
|
||||
intersectRect.x,
|
||||
intersectRect.y,
|
||||
null);
|
||||
|
||||
// Copy the data from the child.
|
||||
dest.setRect(liveRaster);
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies an arbitrary rectangular region of the RenderedImage
|
||||
* into a caller-supplied WritableRaster. The region to be
|
||||
* computed is determined by clipping the bounds of the supplied
|
||||
* WritableRaster against the bounds of the image. The supplied
|
||||
* WritableRaster must have a SampleModel that is compatible with
|
||||
* that of the image.
|
||||
*
|
||||
* <p> If the raster argument is null, the entire image will
|
||||
* be copied into a newly-created WritableRaster with a SampleModel
|
||||
* that is compatible with that of the image.
|
||||
*
|
||||
* @param dest a WritableRaster to hold the returned portion of
|
||||
* the image.
|
||||
* @return a reference to the supplied WritableRaster, or to a
|
||||
* new WritableRaster if the supplied one was null.
|
||||
*/
|
||||
public WritableRaster copyData(WritableRaster dest) {
|
||||
// Get the image bounds.
|
||||
Rectangle imageBounds = getBounds();
|
||||
|
||||
Rectangle bounds;
|
||||
if (dest == null) {
|
||||
// Create a WritableRaster for the entire image.
|
||||
bounds = imageBounds;
|
||||
Point p = new Point(minX, minY);
|
||||
SampleModel sm =
|
||||
sampleModel.createCompatibleSampleModel(width, height);
|
||||
dest = Raster.createWritableRaster(sm, p);
|
||||
} else {
|
||||
bounds = dest.getBounds();
|
||||
}
|
||||
|
||||
// Determine tile limits for the intersection of the prescribed
|
||||
// bounds with the image bounds.
|
||||
Rectangle xsect = imageBounds.contains(bounds) ?
|
||||
bounds : bounds.intersection(imageBounds);
|
||||
int startX = XToTileX(xsect.x);
|
||||
int startY = YToTileY(xsect.y);
|
||||
int endX = XToTileX(xsect.x + xsect.width - 1);
|
||||
int endY = YToTileY(xsect.y + xsect.height - 1);
|
||||
|
||||
// Loop over the tiles in the intersection.
|
||||
for (int j = startY; j <= endY; j++) {
|
||||
for (int i = startX; i <= endX; i++) {
|
||||
// Retrieve the tile.
|
||||
Raster tile = getTile(i, j);
|
||||
|
||||
// Create a child of the tile for the intersection of
|
||||
// the tile bounds and the bounds of the requested area.
|
||||
Rectangle tileRect = tile.getBounds();
|
||||
Rectangle intersectRect =
|
||||
bounds.intersection(tile.getBounds());
|
||||
Raster liveRaster = tile.createChild(intersectRect.x,
|
||||
intersectRect.y,
|
||||
intersectRect.width,
|
||||
intersectRect.height,
|
||||
intersectRect.x,
|
||||
intersectRect.y,
|
||||
null);
|
||||
|
||||
// Copy the data from the child.
|
||||
dest.setRect(liveRaster);
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.sun.imageio.plugins.common;
|
||||
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
|
||||
/**
|
||||
* A simple class that provides RenderedImage functionality
|
||||
* given a Raster and a ColorModel.
|
||||
*/
|
||||
public class SingleTileRenderedImage extends SimpleRenderedImage {
|
||||
|
||||
Raster ras;
|
||||
|
||||
/**
|
||||
* Constructs a SingleTileRenderedImage based on a Raster
|
||||
* and a ColorModel.
|
||||
*
|
||||
* @param ras A Raster that will define tile (0, 0) of the image.
|
||||
* @param cm A ColorModel that will serve as the image's
|
||||
* ColorModel.
|
||||
*/
|
||||
public SingleTileRenderedImage(Raster ras, ColorModel colorModel) {
|
||||
this.ras = ras;
|
||||
|
||||
this.tileGridXOffset = this.minX = ras.getMinX();
|
||||
this.tileGridYOffset = this.minY = ras.getMinY();
|
||||
this.tileWidth = this.width = ras.getWidth();
|
||||
this.tileHeight = this.height = ras.getHeight();
|
||||
this.sampleModel = ras.getSampleModel();
|
||||
this.colorModel = colorModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image's Raster as tile (0, 0).
|
||||
*/
|
||||
public Raster getTile(int tileX, int tileY) {
|
||||
if (tileX != 0 || tileY != 0) {
|
||||
throw new IllegalArgumentException("tileX != 0 || tileY != 0");
|
||||
}
|
||||
return ras;
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
# Common properties
|
||||
ImageUtil0=The supplied Raster does not represent a binary data set.
|
||||
ImageUtil1=The provided sample model is null.
|
||||
SimpleRenderedImage0=The provided region doesn't intersect with the image bounds.
|
||||
ImageUtil2=The provided image cannot be encoded using:
|
||||
GetNumImages0=Input has not been set.
|
||||
GetNumImages1=seekForwardOnly and allowSearch cannot both be true.
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
|
||||
public class TIFFAttrInfo {
|
||||
int valueType = IIOMetadataFormat.VALUE_ARBITRARY;
|
||||
int dataType;
|
||||
boolean isRequired = false;
|
||||
int listMinLength = 0;
|
||||
int listMaxLength = Integer.MAX_VALUE;
|
||||
|
||||
public TIFFAttrInfo() { }
|
||||
}
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.PixelInterleavedSampleModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Base class for all possible forms of JPEG compression in TIFF.
|
||||
*/
|
||||
public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor {
|
||||
|
||||
// Stream metadata format.
|
||||
protected static final String STREAM_METADATA_NAME =
|
||||
"javax_imageio_jpeg_stream_1.0";
|
||||
|
||||
// Image metadata format.
|
||||
protected static final String IMAGE_METADATA_NAME =
|
||||
"javax_imageio_jpeg_image_1.0";
|
||||
|
||||
// ImageWriteParam passed in.
|
||||
private ImageWriteParam param = null;
|
||||
|
||||
/**
|
||||
* ImageWriteParam for JPEG writer.
|
||||
* May be initialized by {@link #initJPEGWriter()}.
|
||||
*/
|
||||
protected JPEGImageWriteParam JPEGParam = null;
|
||||
|
||||
/**
|
||||
* The JPEG writer.
|
||||
* May be initialized by {@link #initJPEGWriter()}.
|
||||
*/
|
||||
protected ImageWriter JPEGWriter = null;
|
||||
|
||||
/**
|
||||
* Whether to write abbreviated JPEG streams (default == false).
|
||||
* A subclass which sets this to <code>true</code> should also
|
||||
* initialized {@link #JPEGStreamMetadata}.
|
||||
*/
|
||||
protected boolean writeAbbreviatedStream = false;
|
||||
|
||||
/**
|
||||
* Stream metadata equivalent to a tables-only stream such as in
|
||||
* the <code>JPEGTables</code>. Default value is <code>null</code>.
|
||||
* This should be set by any subclass which sets
|
||||
* {@link writeAbbreviatedStream} to <code>true</code>.
|
||||
*/
|
||||
protected IIOMetadata JPEGStreamMetadata = null;
|
||||
|
||||
// A pruned image metadata object containing only essential nodes.
|
||||
private IIOMetadata JPEGImageMetadata = null;
|
||||
|
||||
// Array-based output stream.
|
||||
private IIOByteArrayOutputStream baos;
|
||||
|
||||
/**
|
||||
* Removes nonessential nodes from a JPEG native image metadata tree.
|
||||
* All nodes derived from JPEG marker segments other than DHT, DQT,
|
||||
* SOF, SOS segments are removed unless <code>pruneTables</code> is
|
||||
* <code>true</code> in which case the nodes derived from the DHT and
|
||||
* DQT marker segments are also removed.
|
||||
*
|
||||
* @param tree A <tt>javax_imageio_jpeg_image_1.0</tt> tree.
|
||||
* @param pruneTables Whether to prune Huffman and quantization tables.
|
||||
* @throws NullPointerException if <code>tree</code> is
|
||||
* <code>null</code>.
|
||||
* @throws IllegalArgumentException if <code>tree</code> is not the root
|
||||
* of a JPEG native image metadata tree.
|
||||
*/
|
||||
private static void pruneNodes(Node tree, boolean pruneTables) {
|
||||
if(tree == null) {
|
||||
throw new NullPointerException("tree == null!");
|
||||
}
|
||||
if(!tree.getNodeName().equals(IMAGE_METADATA_NAME)) {
|
||||
throw new IllegalArgumentException
|
||||
("root node name is not "+IMAGE_METADATA_NAME+"!");
|
||||
}
|
||||
|
||||
// Create list of required nodes.
|
||||
List<String> wantedNodes = new ArrayList<String>();
|
||||
wantedNodes.addAll(Arrays.asList(new String[] {
|
||||
"JPEGvariety", "markerSequence",
|
||||
"sof", "componentSpec",
|
||||
"sos", "scanComponentSpec"
|
||||
}));
|
||||
|
||||
// Add Huffman and quantization table nodes if not pruning tables.
|
||||
if(!pruneTables) {
|
||||
wantedNodes.add("dht");
|
||||
wantedNodes.add("dhtable");
|
||||
wantedNodes.add("dqt");
|
||||
wantedNodes.add("dqtable");
|
||||
}
|
||||
|
||||
IIOMetadataNode iioTree = (IIOMetadataNode)tree;
|
||||
|
||||
List<Node> nodes = getAllNodes(iioTree, null);
|
||||
int numNodes = nodes.size();
|
||||
|
||||
for(int i = 0; i < numNodes; i++) {
|
||||
Node node = nodes.get(i);
|
||||
if(!wantedNodes.contains(node.getNodeName())) {
|
||||
node.getParentNode().removeChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Node> getAllNodes(IIOMetadataNode root, List<Node> nodes) {
|
||||
if(nodes == null) nodes = new ArrayList<Node>();
|
||||
|
||||
if(root.hasChildNodes()) {
|
||||
Node sibling = root.getFirstChild();
|
||||
while(sibling != null) {
|
||||
nodes.add(sibling);
|
||||
nodes = getAllNodes((IIOMetadataNode)sibling, nodes);
|
||||
sibling = sibling.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public TIFFBaseJPEGCompressor(String compressionType,
|
||||
int compressionTagValue,
|
||||
boolean isCompressionLossless,
|
||||
ImageWriteParam param) {
|
||||
super(compressionType, compressionTagValue, isCompressionLossless);
|
||||
|
||||
this.param = param;
|
||||
}
|
||||
|
||||
/**
|
||||
* A <code>ByteArrayOutputStream</code> which allows writing to an
|
||||
* <code>ImageOutputStream</code>.
|
||||
*/
|
||||
private static class IIOByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
IIOByteArrayOutputStream() {
|
||||
super();
|
||||
}
|
||||
|
||||
IIOByteArrayOutputStream(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
public synchronized void writeTo(ImageOutputStream ios)
|
||||
throws IOException {
|
||||
ios.write(buf, 0, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the JPEGWriter and JPEGParam instance variables.
|
||||
* This method must be called before encode() is invoked.
|
||||
*
|
||||
* @param supportsStreamMetadata Whether the JPEG writer must
|
||||
* support JPEG native stream metadata, i.e., be capable of writing
|
||||
* abbreviated streams.
|
||||
* @param supportsImageMetadata Whether the JPEG writer must
|
||||
* support JPEG native image metadata.
|
||||
*/
|
||||
protected void initJPEGWriter(boolean supportsStreamMetadata,
|
||||
boolean supportsImageMetadata) {
|
||||
// Reset the writer to null if it does not match preferences.
|
||||
if(this.JPEGWriter != null &&
|
||||
(supportsStreamMetadata || supportsImageMetadata)) {
|
||||
ImageWriterSpi spi = this.JPEGWriter.getOriginatingProvider();
|
||||
if(supportsStreamMetadata) {
|
||||
String smName = spi.getNativeStreamMetadataFormatName();
|
||||
if(smName == null || !smName.equals(STREAM_METADATA_NAME)) {
|
||||
this.JPEGWriter = null;
|
||||
}
|
||||
}
|
||||
if(this.JPEGWriter != null && supportsImageMetadata) {
|
||||
String imName = spi.getNativeImageMetadataFormatName();
|
||||
if(imName == null || !imName.equals(IMAGE_METADATA_NAME)) {
|
||||
this.JPEGWriter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the writer.
|
||||
if(this.JPEGWriter == null) {
|
||||
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");
|
||||
|
||||
while(iter.hasNext()) {
|
||||
// Get a writer.
|
||||
ImageWriter writer = iter.next();
|
||||
|
||||
// Verify its metadata support level.
|
||||
if(supportsStreamMetadata || supportsImageMetadata) {
|
||||
ImageWriterSpi spi = writer.getOriginatingProvider();
|
||||
if(supportsStreamMetadata) {
|
||||
String smName =
|
||||
spi.getNativeStreamMetadataFormatName();
|
||||
if(smName == null ||
|
||||
!smName.equals(STREAM_METADATA_NAME)) {
|
||||
// Try the next one.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(supportsImageMetadata) {
|
||||
String imName =
|
||||
spi.getNativeImageMetadataFormatName();
|
||||
if(imName == null ||
|
||||
!imName.equals(IMAGE_METADATA_NAME)) {
|
||||
// Try the next one.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the writer.
|
||||
this.JPEGWriter = writer;
|
||||
break;
|
||||
}
|
||||
|
||||
if(this.JPEGWriter == null) {
|
||||
throw new NullPointerException
|
||||
("No appropriate JPEG writers found!");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the ImageWriteParam.
|
||||
if(this.JPEGParam == null) {
|
||||
if(param != null && param instanceof JPEGImageWriteParam) {
|
||||
JPEGParam = (JPEGImageWriteParam)param;
|
||||
} else {
|
||||
JPEGParam =
|
||||
new JPEGImageWriteParam(writer != null ?
|
||||
writer.getLocale() : null);
|
||||
if (param != null && param.getCompressionMode()
|
||||
== ImageWriteParam.MODE_EXPLICIT) {
|
||||
JPEGParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
JPEGParam.setCompressionQuality(param.getCompressionQuality());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves image metadata with non-core nodes removed.
|
||||
*/
|
||||
private IIOMetadata getImageMetadata(boolean pruneTables)
|
||||
throws IIOException {
|
||||
if(JPEGImageMetadata == null &&
|
||||
IMAGE_METADATA_NAME.equals(JPEGWriter.getOriginatingProvider().getNativeImageMetadataFormatName())) {
|
||||
TIFFImageWriter tiffWriter = (TIFFImageWriter)this.writer;
|
||||
|
||||
// Get default image metadata.
|
||||
JPEGImageMetadata =
|
||||
JPEGWriter.getDefaultImageMetadata(tiffWriter.getImageType(),
|
||||
JPEGParam);
|
||||
|
||||
// Get the DOM tree.
|
||||
Node tree = JPEGImageMetadata.getAsTree(IMAGE_METADATA_NAME);
|
||||
|
||||
// Remove unwanted marker segments.
|
||||
try {
|
||||
pruneNodes(tree, pruneTables);
|
||||
} catch(IllegalArgumentException e) {
|
||||
throw new IIOException("Error pruning unwanted nodes", e);
|
||||
}
|
||||
|
||||
// Set the DOM back into the metadata.
|
||||
try {
|
||||
JPEGImageMetadata.setFromTree(IMAGE_METADATA_NAME, tree);
|
||||
} catch(IIOInvalidTreeException e) {
|
||||
throw new IIOException
|
||||
("Cannot set pruned image metadata!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return JPEGImageMetadata;
|
||||
}
|
||||
|
||||
public final int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
if (this.JPEGWriter == null) {
|
||||
throw new IIOException("JPEG writer has not been initialized!");
|
||||
}
|
||||
if (!((bitsPerSample.length == 3
|
||||
&& bitsPerSample[0] == 8
|
||||
&& bitsPerSample[1] == 8
|
||||
&& bitsPerSample[2] == 8)
|
||||
|| (bitsPerSample.length == 1
|
||||
&& bitsPerSample[0] == 8))) {
|
||||
throw new IIOException("Can only JPEG compress 8- and 24-bit images!");
|
||||
}
|
||||
|
||||
// Set the stream.
|
||||
// The stream has to be wrapped as the Java Image I/O JPEG
|
||||
// ImageWriter flushes the stream at the end of each write()
|
||||
// and this causes problems for the TIFF writer.
|
||||
if (baos == null) {
|
||||
baos = new IIOByteArrayOutputStream();
|
||||
} else {
|
||||
baos.reset();
|
||||
}
|
||||
ImageOutputStream ios = new MemoryCacheImageOutputStream(baos);
|
||||
JPEGWriter.setOutput(ios);
|
||||
|
||||
// Create a DataBuffer.
|
||||
DataBufferByte dbb;
|
||||
if (off == 0) {
|
||||
dbb = new DataBufferByte(b, b.length);
|
||||
} else {
|
||||
//
|
||||
// Workaround for bug in core Java Image I/O JPEG
|
||||
// ImageWriter which cannot handle non-zero offsets.
|
||||
//
|
||||
int bytesPerSegment = scanlineStride * height;
|
||||
byte[] btmp = new byte[bytesPerSegment];
|
||||
System.arraycopy(b, off, btmp, 0, bytesPerSegment);
|
||||
dbb = new DataBufferByte(btmp, bytesPerSegment);
|
||||
off = 0;
|
||||
}
|
||||
|
||||
// Set up the ColorSpace.
|
||||
int[] offsets;
|
||||
ColorSpace cs;
|
||||
if (bitsPerSample.length == 3) {
|
||||
offsets = new int[]{off, off + 1, off + 2};
|
||||
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
} else {
|
||||
offsets = new int[]{off};
|
||||
cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
}
|
||||
|
||||
// Create the ColorModel.
|
||||
ColorModel cm = new ComponentColorModel(cs,
|
||||
false,
|
||||
false,
|
||||
Transparency.OPAQUE,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
|
||||
// Create the SampleModel.
|
||||
SampleModel sm
|
||||
= new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
|
||||
width, height,
|
||||
bitsPerSample.length,
|
||||
scanlineStride,
|
||||
offsets);
|
||||
|
||||
// Create the WritableRaster.
|
||||
WritableRaster wras
|
||||
= Raster.createWritableRaster(sm, dbb, new Point(0, 0));
|
||||
|
||||
// Create the BufferedImage.
|
||||
BufferedImage bi = new BufferedImage(cm, wras, false, null);
|
||||
|
||||
// Get the pruned JPEG image metadata (may be null).
|
||||
IIOMetadata imageMetadata = getImageMetadata(writeAbbreviatedStream);
|
||||
|
||||
// Compress the image into the output stream.
|
||||
int compDataLength;
|
||||
if (writeAbbreviatedStream) {
|
||||
// Write abbreviated JPEG stream
|
||||
|
||||
// First write the tables-only data.
|
||||
JPEGWriter.prepareWriteSequence(JPEGStreamMetadata);
|
||||
ios.flush();
|
||||
|
||||
// Rewind to the beginning of the byte array.
|
||||
baos.reset();
|
||||
|
||||
// Write the abbreviated image data.
|
||||
IIOImage image = new IIOImage(bi, null, imageMetadata);
|
||||
JPEGWriter.writeToSequence(image, JPEGParam);
|
||||
JPEGWriter.endWriteSequence();
|
||||
} else {
|
||||
// Write complete JPEG stream
|
||||
JPEGWriter.write(null,
|
||||
new IIOImage(bi, null, imageMetadata),
|
||||
JPEGParam);
|
||||
}
|
||||
|
||||
compDataLength = baos.size();
|
||||
baos.writeTo(stream);
|
||||
baos.reset();
|
||||
|
||||
return compDataLength;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if(JPEGWriter != null) {
|
||||
JPEGWriter.dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
public class TIFFCIELabColorConverter extends TIFFColorConverter {
|
||||
|
||||
// XYZ coordinate or reference white (CIE D65)
|
||||
private static final float Xn = 95.047f;
|
||||
private static final float Yn = 100.0f;
|
||||
private static final float Zn = 108.883f;
|
||||
|
||||
private static final float THRESHOLD = (float)Math.pow(0.008856, 1.0/3.0);
|
||||
|
||||
public TIFFCIELabColorConverter() {}
|
||||
|
||||
|
||||
private float clamp(float x) {
|
||||
if (x < 0.0f) {
|
||||
return 0.0f;
|
||||
} else if (x > 100.0f) {
|
||||
return 255.0f;
|
||||
} else {
|
||||
return x*(255.0f/100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
private float clamp2(float x) {
|
||||
if (x < 0.0f) {
|
||||
return 0.0f;
|
||||
} else if (x > 255.0f) {
|
||||
return 255.0f;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
public void fromRGB(float r, float g, float b, float[] result) {
|
||||
float X = 0.412453f*r + 0.357580f*g + 0.180423f*b;
|
||||
float Y = 0.212671f*r + 0.715160f*g + 0.072169f*b;
|
||||
float Z = 0.019334f*r + 0.119193f*g + 0.950227f*b;
|
||||
|
||||
float YYn = Y/Yn;
|
||||
float XXn = X/Xn;
|
||||
float ZZn = Z/Zn;
|
||||
|
||||
if (YYn < 0.008856f) {
|
||||
YYn = 7.787f*YYn + 16.0f/116.0f;
|
||||
} else {
|
||||
YYn = (float)Math.pow(YYn, 1.0/3.0);
|
||||
}
|
||||
|
||||
if (XXn < 0.008856f) {
|
||||
XXn = 7.787f*XXn + 16.0f/116.0f;
|
||||
} else {
|
||||
XXn = (float)Math.pow(XXn, 1.0/3.0);
|
||||
}
|
||||
|
||||
if (ZZn < 0.008856f) {
|
||||
ZZn = 7.787f*ZZn + 16.0f/116.0f;
|
||||
} else {
|
||||
ZZn = (float)Math.pow(ZZn, 1.0/3.0);
|
||||
}
|
||||
|
||||
float LStar = 116.0f*YYn - 16.0f;
|
||||
float aStar = 500.0f*(XXn - YYn);
|
||||
float bStar = 200.0f*(YYn - ZZn);
|
||||
|
||||
LStar *= 255.0f/100.0f;
|
||||
if (aStar < 0.0f) {
|
||||
aStar += 256.0f;
|
||||
}
|
||||
if (bStar < 0.0f) {
|
||||
bStar += 256.0f;
|
||||
}
|
||||
|
||||
result[0] = clamp2(LStar);
|
||||
result[1] = clamp2(aStar);
|
||||
result[2] = clamp2(bStar);
|
||||
}
|
||||
|
||||
public void toRGB(float x0, float x1, float x2, float[] rgb) {
|
||||
float LStar = x0*100.0f/255.0f;
|
||||
float aStar = (x1 > 128.0f) ? (x1 - 256.0f) : x1;
|
||||
float bStar = (x2 > 128.0f) ? (x2 - 256.0f) : x2;
|
||||
|
||||
float YYn; // Y/Yn
|
||||
float fY; // 'F' value for Y
|
||||
|
||||
if (LStar < 8.0f) {
|
||||
YYn = LStar/903.3f;
|
||||
fY = 7.787f*YYn + 16.0f/116.0f;
|
||||
} else {
|
||||
float YYn_cubeRoot = (LStar + 16.0f)/116.0f;
|
||||
YYn = YYn_cubeRoot*YYn_cubeRoot*YYn_cubeRoot;
|
||||
fY = (float)Math.pow(YYn, 1.0/3.0);
|
||||
}
|
||||
float Y = YYn*Yn;
|
||||
|
||||
float fX = fY + (aStar/500.0f);
|
||||
float X;
|
||||
if (fX <= THRESHOLD) {
|
||||
X = Xn*(fX - 16.0f/116.0f)/7.787f;
|
||||
} else {
|
||||
X = Xn*fX*fX*fX;
|
||||
}
|
||||
|
||||
float fZ = fY - bStar/200.0f;
|
||||
float Z;
|
||||
if (fZ <= THRESHOLD) {
|
||||
Z = Zn*(fZ - 16.0f/116.0f)/7.787f;
|
||||
} else {
|
||||
Z = Zn*fZ*fZ*fZ;
|
||||
}
|
||||
|
||||
float R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z;
|
||||
float G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z;
|
||||
float B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z;
|
||||
|
||||
rgb[0] = clamp(R);
|
||||
rgb[1] = clamp(G);
|
||||
rgb[2] = clamp(B);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
/**
|
||||
* An abstract class that performs simple color conversion on 3-banded source
|
||||
* images, for use with the TIFF Image I/O plug-in.
|
||||
*/
|
||||
public abstract class TIFFColorConverter {
|
||||
|
||||
/**
|
||||
* Constructs an instance of a <code>TIFFColorConverter</code>.
|
||||
*/
|
||||
public TIFFColorConverter() {}
|
||||
|
||||
/**
|
||||
* Converts an RGB triple into the native color space of this
|
||||
* TIFFColorConverter, and stores the result in the first three
|
||||
* entries of the <code>result</code> array.
|
||||
*
|
||||
* @param r the red value.
|
||||
* @param g the green value.
|
||||
* @param b the blue value.
|
||||
* @param result an array of <code>float</code>s containing three elements.
|
||||
* @throws NullPointerException if <code>result</code> is
|
||||
* <code>null</code>.
|
||||
* @throws ArrayIndexOutOfBoundsException if
|
||||
* <code>result.length < 3</code>.
|
||||
*/
|
||||
public abstract void fromRGB(float r, float g, float b, float[] result);
|
||||
|
||||
/**
|
||||
* Converts a triple in the native color space of this
|
||||
* TIFFColorConverter into an RGB triple, and stores the result in
|
||||
* the first three entries of the <code>rgb</code> array.
|
||||
*
|
||||
* @param x0 the value of channel 0.
|
||||
* @param x1 the value of channel 1.
|
||||
* @param x2 the value of channel 2.
|
||||
* @param rgb an array of <code>float</code>s containing three elements.
|
||||
* @throws NullPointerException if <code>rgb</code> is
|
||||
* <code>null</code>.
|
||||
* @throws ArrayIndexOutOfBoundsException if
|
||||
* <code>rgb.length < 3</code>.
|
||||
*/
|
||||
public abstract void toRGB(float x0, float x1, float x2, float[] rgb);
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
|
||||
/**
|
||||
* An abstract superclass for pluggable TIFF compressors.
|
||||
*/
|
||||
public abstract class TIFFCompressor {
|
||||
|
||||
/**
|
||||
* The <code>ImageWriter</code> calling this
|
||||
* <code>TIFFCompressor</code>.
|
||||
*/
|
||||
protected ImageWriter writer;
|
||||
|
||||
/**
|
||||
* The <code>IIOMetadata</code> object containing metadata for the
|
||||
* current image.
|
||||
*/
|
||||
protected IIOMetadata metadata;
|
||||
|
||||
/**
|
||||
* The name of the compression type supported by this compressor.
|
||||
*/
|
||||
protected String compressionType;
|
||||
|
||||
/**
|
||||
* The value to be assigned to the TIFF <i>Compression</i> tag in the
|
||||
* TIFF image metadata.
|
||||
*/
|
||||
protected int compressionTagValue;
|
||||
|
||||
/**
|
||||
* Whether the compression is lossless.
|
||||
*/
|
||||
protected boolean isCompressionLossless;
|
||||
|
||||
/**
|
||||
* The <code>ImageOutputStream</code> to be written.
|
||||
*/
|
||||
protected ImageOutputStream stream;
|
||||
|
||||
/**
|
||||
* Creates a compressor object for use in compressing TIFF data. This
|
||||
* object may be passed to the
|
||||
* {@link TIFFImageWriteParam#setTIFFCompressor(TIFFCompressor)}
|
||||
* method to override the compressor of a supported compression type or
|
||||
* to provide the implementation of the compression algorithm of an
|
||||
* unsupported compression type.
|
||||
*
|
||||
* <p>The parameters <code>compressionTagValue</code> and
|
||||
* <code>isCompressionLossless</code> are provided to accomodate
|
||||
* compression types which are unknown. A compression type is
|
||||
* "known" if it is either among those already supported by the
|
||||
* TIFF writer (see {@link TIFFImageWriteParam}), or is listed in
|
||||
* the TIFF 6.0 specification but not supported. If the compression
|
||||
* type is unknown, the <code>compressionTagValue</code> and
|
||||
* <code>isCompressionLossless</code> parameters are ignored.</p>
|
||||
*
|
||||
* @param compressionType The name of the compression type.
|
||||
* @param compressionTagValue The value to be assigned to the TIFF
|
||||
* <i>Compression</i> tag in the TIFF image metadata; ignored if
|
||||
* <code>compressionType</code> is a known type.
|
||||
* @param isCompressionLossless Whether the compression is lossless;
|
||||
* ignored if <code>compressionType</code> is a known type.
|
||||
*
|
||||
* @throws NullPointerException if <code>compressionType</code> is
|
||||
* <code>null</code>.
|
||||
* @throws IllegalArgumentException if <code>compressionTagValue</code> is
|
||||
* less <code>1</code>.
|
||||
*/
|
||||
public TIFFCompressor(String compressionType,
|
||||
int compressionTagValue,
|
||||
boolean isCompressionLossless) {
|
||||
if(compressionType == null) {
|
||||
throw new NullPointerException("compressionType == null");
|
||||
} else if(compressionTagValue < 1) {
|
||||
throw new IllegalArgumentException("compressionTagValue < 1");
|
||||
}
|
||||
|
||||
// Set the compression type.
|
||||
this.compressionType = compressionType;
|
||||
|
||||
// Determine whether this type is either defined in the TIFF 6.0
|
||||
// specification or is already supported.
|
||||
int compressionIndex = -1;
|
||||
String[] compressionTypes = TIFFImageWriter.compressionTypes;
|
||||
int len = compressionTypes.length;
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(compressionTypes[i].equals(compressionType)) {
|
||||
// Save the index of the supported type.
|
||||
compressionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(compressionIndex != -1) {
|
||||
// Known compression type.
|
||||
this.compressionTagValue =
|
||||
TIFFImageWriter.compressionNumbers[compressionIndex];
|
||||
this.isCompressionLossless =
|
||||
TIFFImageWriter.isCompressionLossless[compressionIndex];
|
||||
} else {
|
||||
// Unknown compression type.
|
||||
this.compressionTagValue = compressionTagValue;
|
||||
this.isCompressionLossless = isCompressionLossless;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of the compression type supported by this compressor.
|
||||
*
|
||||
* @return The compression type name.
|
||||
*/
|
||||
public String getCompressionType() {
|
||||
return compressionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value to be assigned to the TIFF <i>Compression</i> tag
|
||||
* in the TIFF image metadata.
|
||||
*
|
||||
* @return The <i>Compression</i> tag value.
|
||||
*/
|
||||
public int getCompressionTagValue() {
|
||||
return compressionTagValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value indicating whether the compression is lossless.
|
||||
*
|
||||
* @return Whether the compression is lossless.
|
||||
*/
|
||||
public boolean isCompressionLossless() {
|
||||
return isCompressionLossless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>ImageOutputStream</code> to be written.
|
||||
*
|
||||
* @param stream an <code>ImageOutputStream</code> to be written.
|
||||
*
|
||||
* @see #getStream
|
||||
*/
|
||||
public void setStream(ImageOutputStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>ImageOutputStream</code> that will be written.
|
||||
*
|
||||
* @return an <code>ImageOutputStream</code>.
|
||||
*
|
||||
* @see #setStream(ImageOutputStream)
|
||||
*/
|
||||
public ImageOutputStream getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <code>writer</code> field.
|
||||
*
|
||||
* @param writer the current <code>ImageWriter</code>.
|
||||
*
|
||||
* @see #getWriter()
|
||||
*/
|
||||
public void setWriter(ImageWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current <code>ImageWriter</code>.
|
||||
*
|
||||
* @return an <code>ImageWriter</code>.
|
||||
*
|
||||
* @see #setWriter(ImageWriter)
|
||||
*/
|
||||
public ImageWriter getWriter() {
|
||||
return this.writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <code>metadata</code> field.
|
||||
*
|
||||
* @param metadata the <code>IIOMetadata</code> object for the
|
||||
* image being written.
|
||||
*
|
||||
* @see #getMetadata()
|
||||
*/
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current <code>IIOMetadata</code> object.
|
||||
*
|
||||
* @return the <code>IIOMetadata</code> object for the image being
|
||||
* written.
|
||||
*
|
||||
* @see #setMetadata(IIOMetadata)
|
||||
*/
|
||||
public IIOMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the supplied image data, writing to the currently set
|
||||
* <code>ImageOutputStream</code>.
|
||||
*
|
||||
* @param b an array of <code>byte</code>s containing the packed
|
||||
* but uncompressed image data.
|
||||
* @param off the starting offset of the data to be written in the
|
||||
* array <code>b</code>.
|
||||
* @param width the width of the rectangle of pixels to be written.
|
||||
* @param height the height of the rectangle of pixels to be written.
|
||||
* @param bitsPerSample an array of <code>int</code>s indicting
|
||||
* the number of bits used to represent each image sample within
|
||||
* a pixel.
|
||||
* @param scanlineStride the number of bytes separating each
|
||||
* row of the input data.
|
||||
*
|
||||
* @return the number of bytes written.
|
||||
*
|
||||
* @throws IOException if the supplied data cannot be encoded by
|
||||
* this <code>TIFFCompressor</code>, or if any I/O error occurs
|
||||
* during writing.
|
||||
*/
|
||||
public abstract int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
|
||||
/**
|
||||
* Compressor for Deflate compression.
|
||||
*/
|
||||
public class TIFFDeflateCompressor extends TIFFDeflater {
|
||||
public TIFFDeflateCompressor(ImageWriteParam param, int predictor) {
|
||||
super("Deflate", BaselineTIFFTagSet.COMPRESSION_DEFLATE, param,
|
||||
predictor);
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
|
||||
public class TIFFDeflateDecompressor extends TIFFDecompressor {
|
||||
|
||||
Inflater inflater = null;
|
||||
int predictor;
|
||||
|
||||
public TIFFDeflateDecompressor(int predictor) throws IIOException {
|
||||
inflater = new Inflater();
|
||||
|
||||
if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
|
||||
predictor !=
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
throw new IIOException("Illegal value for Predictor in " +
|
||||
"TIFF file");
|
||||
}
|
||||
|
||||
this.predictor = predictor;
|
||||
}
|
||||
|
||||
public synchronized void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
|
||||
// Check bitsPerSample.
|
||||
if (predictor ==
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
int len = bitsPerSample.length;
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(bitsPerSample[i] != 8) {
|
||||
throw new IIOException
|
||||
(bitsPerSample[i] + "-bit samples "+
|
||||
"are not supported for Horizontal "+
|
||||
"differencing Predictor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Seek to current tile data offset.
|
||||
stream.seek(offset);
|
||||
|
||||
// Read the deflated data.
|
||||
byte[] srcData = new byte[byteCount];
|
||||
stream.readFully(srcData);
|
||||
|
||||
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
|
||||
byte[] buf;
|
||||
int bufOffset;
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
buf = b;
|
||||
bufOffset = dstOffset;
|
||||
} else {
|
||||
buf = new byte[bytesPerRow*srcHeight];
|
||||
bufOffset = 0;
|
||||
}
|
||||
|
||||
// Set the input to the Inflater.
|
||||
inflater.setInput(srcData);
|
||||
|
||||
// Inflate the data.
|
||||
try {
|
||||
inflater.inflate(buf, bufOffset, bytesPerRow*srcHeight);
|
||||
} catch(DataFormatException dfe) {
|
||||
throw new IIOException("Error inflating data",
|
||||
dfe);
|
||||
}
|
||||
|
||||
// Reset the Inflater.
|
||||
inflater.reset();
|
||||
|
||||
if (predictor ==
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
|
||||
for (int j = 0; j < srcHeight; j++) {
|
||||
int count = bufOffset + samplesPerPixel * (j * srcWidth + 1);
|
||||
for (int i=samplesPerPixel; i<srcWidth*samplesPerPixel; i++) {
|
||||
buf[count] += buf[count - samplesPerPixel];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bytesPerRow != scanlineStride) {
|
||||
int off = 0;
|
||||
for (int y = 0; y < srcHeight; y++) {
|
||||
System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
|
||||
off += bytesPerRow;
|
||||
dstOffset += scanlineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.Deflater;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
|
||||
/**
|
||||
* Compressor superclass for Deflate and ZLib compression.
|
||||
*/
|
||||
public class TIFFDeflater extends TIFFCompressor {
|
||||
|
||||
Deflater deflater;
|
||||
int predictor;
|
||||
|
||||
public TIFFDeflater(String compressionType,
|
||||
int compressionTagValue,
|
||||
ImageWriteParam param,
|
||||
int predictorValue) {
|
||||
super(compressionType, compressionTagValue, true);
|
||||
|
||||
this.predictor = predictorValue;
|
||||
|
||||
// Set the deflate level.
|
||||
int deflateLevel;
|
||||
if(param != null &&
|
||||
param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) {
|
||||
float quality = param.getCompressionQuality();
|
||||
deflateLevel = (int)(1 + 8*quality);
|
||||
} else {
|
||||
deflateLevel = Deflater.DEFAULT_COMPRESSION;
|
||||
}
|
||||
|
||||
this.deflater = new Deflater(deflateLevel);
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
|
||||
int inputSize = height*scanlineStride;
|
||||
int blocks = (inputSize + 32767)/32768;
|
||||
|
||||
// Worst case for Zlib deflate is input size + 5 bytes per 32k
|
||||
// block, plus 6 header bytes
|
||||
byte[] compData = new byte[inputSize + 5*blocks + 6];
|
||||
|
||||
int numCompressedBytes = 0;
|
||||
if(predictor == BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
int samplesPerPixel = bitsPerSample.length;
|
||||
int bitsPerPixel = 0;
|
||||
for (int i = 0; i < samplesPerPixel; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
int bytesPerRow = (bitsPerPixel*width + 7)/8;
|
||||
byte[] rowBuf = new byte[bytesPerRow];
|
||||
|
||||
int maxRow = height - 1;
|
||||
for(int i = 0; i < height; i++) {
|
||||
// Cannot modify b[] in place as it might be a data
|
||||
// array from the image being written so make a copy.
|
||||
System.arraycopy(b, off, rowBuf, 0, bytesPerRow);
|
||||
for(int j = bytesPerRow - 1; j >= samplesPerPixel; j--) {
|
||||
rowBuf[j] -= rowBuf[j - samplesPerPixel];
|
||||
}
|
||||
|
||||
deflater.setInput(rowBuf);
|
||||
if(i == maxRow) {
|
||||
deflater.finish();
|
||||
}
|
||||
|
||||
int numBytes = 0;
|
||||
while((numBytes = deflater.deflate(compData,
|
||||
numCompressedBytes,
|
||||
compData.length -
|
||||
numCompressedBytes)) != 0) {
|
||||
numCompressedBytes += numBytes;
|
||||
}
|
||||
|
||||
off += scanlineStride;
|
||||
}
|
||||
} else {
|
||||
deflater.setInput(b, off, height*scanlineStride);
|
||||
deflater.finish();
|
||||
|
||||
numCompressedBytes = deflater.deflate(compData);
|
||||
}
|
||||
|
||||
deflater.reset();
|
||||
|
||||
stream.write(compData, 0, numCompressedBytes);
|
||||
|
||||
return numCompressedBytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
|
||||
class TIFFElementInfo {
|
||||
String[] childNames;
|
||||
String[] attributeNames;
|
||||
int childPolicy;
|
||||
|
||||
int minChildren = 0;
|
||||
int maxChildren = Integer.MAX_VALUE;
|
||||
|
||||
int objectValueType = IIOMetadataFormat.VALUE_NONE;
|
||||
Class<?> objectClass = null;
|
||||
Object objectDefaultValue = null;
|
||||
Object[] objectEnumerations = null;
|
||||
Comparable<Object> objectMinValue = null;
|
||||
Comparable<Object> objectMaxValue = null;
|
||||
int objectArrayMinLength = 0;
|
||||
int objectArrayMaxLength = 0;
|
||||
|
||||
public TIFFElementInfo(String[] childNames,
|
||||
String[] attributeNames,
|
||||
int childPolicy) {
|
||||
this.childNames = childNames;
|
||||
this.attributeNames = attributeNames;
|
||||
this.childPolicy = childPolicy;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
|
||||
/**
|
||||
* A <code>TIFFCompressor</code> for the JPEG variant of Exif.
|
||||
*/
|
||||
public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor {
|
||||
public TIFFExifJPEGCompressor(ImageWriteParam param) {
|
||||
super(TIFFImageWriter.EXIF_JPEG_COMPRESSION_TYPE,
|
||||
BaselineTIFFTagSet.COMPRESSION_OLD_JPEG,
|
||||
false,
|
||||
param);
|
||||
}
|
||||
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
// Set the metadata.
|
||||
super.setMetadata(metadata);
|
||||
|
||||
// Initialize the JPEG writer and writeparam.
|
||||
initJPEGWriter(false, // No stream metadata (not writing abbreviated)
|
||||
true); // Yes image metadata (remove APPn markers)
|
||||
}
|
||||
}
|
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract class TIFFFaxCompressor extends TIFFCompressor {
|
||||
|
||||
/**
|
||||
* The CCITT numerical definition of white.
|
||||
*/
|
||||
protected static final int WHITE = 0;
|
||||
|
||||
/**
|
||||
* The CCITT numerical definition of black.
|
||||
*/
|
||||
protected static final int BLACK = 1;
|
||||
|
||||
// --- Begin tables for CCITT compression ---
|
||||
|
||||
protected static final byte[] byteTable = new byte[] {
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, // 0 to 15
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16 to 31
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 32 to 47
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 48 to 63
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 to 79
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 to 95
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 to 111
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 112 to 127
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 to 143
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144 to 159
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 to 175
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176 to 191
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 to 207
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208 to 223
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224 to 239
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240 to 255
|
||||
};
|
||||
|
||||
/**
|
||||
* Terminating codes for black runs.
|
||||
*/
|
||||
protected static final int[] termCodesBlack = new int[] {
|
||||
/* 0 0x0000 */ 0x0dc0000a, 0x40000003, 0xc0000002, 0x80000002,
|
||||
/* 4 0x0004 */ 0x60000003, 0x30000004, 0x20000004, 0x18000005,
|
||||
/* 8 0x0008 */ 0x14000006, 0x10000006, 0x08000007, 0x0a000007,
|
||||
/* 12 0x000c */ 0x0e000007, 0x04000008, 0x07000008, 0x0c000009,
|
||||
/* 16 0x0010 */ 0x05c0000a, 0x0600000a, 0x0200000a, 0x0ce0000b,
|
||||
/* 20 0x0014 */ 0x0d00000b, 0x0d80000b, 0x06e0000b, 0x0500000b,
|
||||
/* 24 0x0018 */ 0x02e0000b, 0x0300000b, 0x0ca0000c, 0x0cb0000c,
|
||||
/* 28 0x001c */ 0x0cc0000c, 0x0cd0000c, 0x0680000c, 0x0690000c,
|
||||
/* 32 0x0020 */ 0x06a0000c, 0x06b0000c, 0x0d20000c, 0x0d30000c,
|
||||
/* 36 0x0024 */ 0x0d40000c, 0x0d50000c, 0x0d60000c, 0x0d70000c,
|
||||
/* 40 0x0028 */ 0x06c0000c, 0x06d0000c, 0x0da0000c, 0x0db0000c,
|
||||
/* 44 0x002c */ 0x0540000c, 0x0550000c, 0x0560000c, 0x0570000c,
|
||||
/* 48 0x0030 */ 0x0640000c, 0x0650000c, 0x0520000c, 0x0530000c,
|
||||
/* 52 0x0034 */ 0x0240000c, 0x0370000c, 0x0380000c, 0x0270000c,
|
||||
/* 56 0x0038 */ 0x0280000c, 0x0580000c, 0x0590000c, 0x02b0000c,
|
||||
/* 60 0x003c */ 0x02c0000c, 0x05a0000c, 0x0660000c, 0x0670000c
|
||||
};
|
||||
|
||||
/**
|
||||
* Terminating codes for white runs.
|
||||
*/
|
||||
protected static final int[] termCodesWhite = new int[] {
|
||||
/* 0 0x0000 */ 0x35000008, 0x1c000006, 0x70000004, 0x80000004,
|
||||
/* 4 0x0004 */ 0xb0000004, 0xc0000004, 0xe0000004, 0xf0000004,
|
||||
/* 8 0x0008 */ 0x98000005, 0xa0000005, 0x38000005, 0x40000005,
|
||||
/* 12 0x000c */ 0x20000006, 0x0c000006, 0xd0000006, 0xd4000006,
|
||||
/* 16 0x0010 */ 0xa8000006, 0xac000006, 0x4e000007, 0x18000007,
|
||||
/* 20 0x0014 */ 0x10000007, 0x2e000007, 0x06000007, 0x08000007,
|
||||
/* 24 0x0018 */ 0x50000007, 0x56000007, 0x26000007, 0x48000007,
|
||||
/* 28 0x001c */ 0x30000007, 0x02000008, 0x03000008, 0x1a000008,
|
||||
/* 32 0x0020 */ 0x1b000008, 0x12000008, 0x13000008, 0x14000008,
|
||||
/* 36 0x0024 */ 0x15000008, 0x16000008, 0x17000008, 0x28000008,
|
||||
/* 40 0x0028 */ 0x29000008, 0x2a000008, 0x2b000008, 0x2c000008,
|
||||
/* 44 0x002c */ 0x2d000008, 0x04000008, 0x05000008, 0x0a000008,
|
||||
/* 48 0x0030 */ 0x0b000008, 0x52000008, 0x53000008, 0x54000008,
|
||||
/* 52 0x0034 */ 0x55000008, 0x24000008, 0x25000008, 0x58000008,
|
||||
/* 56 0x0038 */ 0x59000008, 0x5a000008, 0x5b000008, 0x4a000008,
|
||||
/* 60 0x003c */ 0x4b000008, 0x32000008, 0x33000008, 0x34000008
|
||||
};
|
||||
|
||||
/**
|
||||
* Make-up codes for black runs.
|
||||
*/
|
||||
protected static final int[] makeupCodesBlack = new int[] {
|
||||
/* 0 0x0000 */ 0x00000000, 0x03c0000a, 0x0c80000c, 0x0c90000c,
|
||||
/* 4 0x0004 */ 0x05b0000c, 0x0330000c, 0x0340000c, 0x0350000c,
|
||||
/* 8 0x0008 */ 0x0360000d, 0x0368000d, 0x0250000d, 0x0258000d,
|
||||
/* 12 0x000c */ 0x0260000d, 0x0268000d, 0x0390000d, 0x0398000d,
|
||||
/* 16 0x0010 */ 0x03a0000d, 0x03a8000d, 0x03b0000d, 0x03b8000d,
|
||||
/* 20 0x0014 */ 0x0290000d, 0x0298000d, 0x02a0000d, 0x02a8000d,
|
||||
/* 24 0x0018 */ 0x02d0000d, 0x02d8000d, 0x0320000d, 0x0328000d,
|
||||
/* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c,
|
||||
/* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c,
|
||||
/* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c,
|
||||
/* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000
|
||||
};
|
||||
|
||||
/**
|
||||
* Make-up codes for white runs.
|
||||
*/
|
||||
protected static final int[] makeupCodesWhite = new int[] {
|
||||
/* 0 0x0000 */ 0x00000000, 0xd8000005, 0x90000005, 0x5c000006,
|
||||
/* 4 0x0004 */ 0x6e000007, 0x36000008, 0x37000008, 0x64000008,
|
||||
/* 8 0x0008 */ 0x65000008, 0x68000008, 0x67000008, 0x66000009,
|
||||
/* 12 0x000c */ 0x66800009, 0x69000009, 0x69800009, 0x6a000009,
|
||||
/* 16 0x0010 */ 0x6a800009, 0x6b000009, 0x6b800009, 0x6c000009,
|
||||
/* 20 0x0014 */ 0x6c800009, 0x6d000009, 0x6d800009, 0x4c000009,
|
||||
/* 24 0x0018 */ 0x4c800009, 0x4d000009, 0x60000006, 0x4d800009,
|
||||
/* 28 0x001c */ 0x0100000b, 0x0180000b, 0x01a0000b, 0x0120000c,
|
||||
/* 32 0x0020 */ 0x0130000c, 0x0140000c, 0x0150000c, 0x0160000c,
|
||||
/* 36 0x0024 */ 0x0170000c, 0x01c0000c, 0x01d0000c, 0x01e0000c,
|
||||
/* 40 0x0028 */ 0x01f0000c, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 44 0x002c */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 48 0x0030 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 52 0x0034 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/* 56 0x0038 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000
|
||||
};
|
||||
|
||||
/**
|
||||
* Pass mode table.
|
||||
*/
|
||||
protected static final int[] passMode = new int[] {
|
||||
0x10000004 // 0001
|
||||
};
|
||||
|
||||
/**
|
||||
* Vertical mode table.
|
||||
*/
|
||||
protected static final int[] vertMode = new int[] {
|
||||
0x06000007, // 0000011
|
||||
0x0c000006, // 000011
|
||||
0x60000003, // 011
|
||||
0x80000001, // 1
|
||||
0x40000003, // 010
|
||||
0x08000006, // 000010
|
||||
0x04000007 // 0000010
|
||||
};
|
||||
|
||||
/**
|
||||
* Horizontal mode table.
|
||||
*/
|
||||
protected static final int[] horzMode = new int[] {
|
||||
0x20000003 // 001
|
||||
};
|
||||
|
||||
/**
|
||||
* Black and white terminating code table.
|
||||
*/
|
||||
protected static final int[][] termCodes =
|
||||
new int[][] {termCodesWhite, termCodesBlack};
|
||||
|
||||
/**
|
||||
* Black and white make-up code table.
|
||||
*/
|
||||
protected static final int[][] makeupCodes =
|
||||
new int[][] {makeupCodesWhite, makeupCodesBlack};
|
||||
|
||||
/**
|
||||
* Black and white pass mode table.
|
||||
*/
|
||||
protected static final int[][] pass = new int[][] {passMode, passMode};
|
||||
|
||||
/**
|
||||
* Black and white vertical mode table.
|
||||
*/
|
||||
protected static final int[][] vert = new int[][] {vertMode, vertMode};
|
||||
|
||||
/**
|
||||
* Black and white horizontal mode table.
|
||||
*/
|
||||
protected static final int[][] horz = new int[][] {horzMode, horzMode};
|
||||
|
||||
// --- End tables for CCITT compression ---
|
||||
|
||||
/**
|
||||
* Whether bits are inserted in reverse order (TIFF FillOrder 2).
|
||||
*/
|
||||
protected boolean inverseFill = false;
|
||||
|
||||
/**
|
||||
* Output bit buffer.
|
||||
*/
|
||||
protected int bits;
|
||||
|
||||
/**
|
||||
* Number of bits in the output bit buffer.
|
||||
*/
|
||||
protected int ndex;
|
||||
|
||||
/**
|
||||
* Constructor. The superclass constructor is merely invoked with the
|
||||
* same parameters.
|
||||
*/
|
||||
protected TIFFFaxCompressor(String compressionType,
|
||||
int compressionTagValue,
|
||||
boolean isCompressionLossless) {
|
||||
super(compressionType, compressionTagValue, isCompressionLossless);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <code>metadata</code> field.
|
||||
*
|
||||
* <p> The implementation in this class also sets local options
|
||||
* from the FILL_ORDER field if it exists.</p>
|
||||
*
|
||||
* @param metadata the <code>IIOMetadata</code> object for the
|
||||
* image being written.
|
||||
*
|
||||
* @see #getMetadata()
|
||||
*/
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
super.setMetadata(metadata);
|
||||
|
||||
if (metadata instanceof TIFFImageMetadata) {
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
|
||||
inverseFill = (f != null && f.getAsInt(0) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return min of <code>maxOffset</code> or offset of first pixel
|
||||
* different from pixel at <code>bitOffset</code>.
|
||||
*/
|
||||
public int nextState(byte[] data,
|
||||
int base,
|
||||
int bitOffset,
|
||||
int maxOffset)
|
||||
{
|
||||
if(data == null) {
|
||||
return maxOffset;
|
||||
}
|
||||
|
||||
int next = base + (bitOffset>>>3);
|
||||
// If the offset is beyond the data already then the minimum of the
|
||||
// current offset and maxOffset must be maxOffset.
|
||||
if(next >= data.length) {
|
||||
return maxOffset;
|
||||
}
|
||||
int end = base + (maxOffset>>>3);
|
||||
if(end == data.length) { // Prevents out of bounds exception below
|
||||
end--;
|
||||
}
|
||||
int extra = bitOffset & 0x7;
|
||||
|
||||
int testbyte;
|
||||
|
||||
if((data[next] & (0x80 >>> extra)) != 0) { // look for "0"
|
||||
testbyte = ~(data[next]) & (0xff >>> extra);
|
||||
while (next < end) {
|
||||
if (testbyte != 0) {
|
||||
break;
|
||||
}
|
||||
testbyte = ~(data[++next]) & 0xff;
|
||||
}
|
||||
} else { // look for "1"
|
||||
if ((testbyte = (data[next] & (0xff >>> extra))) != 0) {
|
||||
bitOffset = (next-base)*8 + byteTable[testbyte];
|
||||
return ((bitOffset < maxOffset) ? bitOffset : maxOffset);
|
||||
}
|
||||
while (next < end) {
|
||||
if ((testbyte = data[++next]&0xff) != 0) {
|
||||
// "1" is in current byte
|
||||
bitOffset = (next-base)*8 + byteTable[testbyte];
|
||||
return ((bitOffset < maxOffset) ? bitOffset : maxOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
bitOffset = (next-base)*8 + byteTable[testbyte];
|
||||
return ((bitOffset < maxOffset) ? bitOffset : maxOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bit buffer machinery.
|
||||
*/
|
||||
public void initBitBuf()
|
||||
{
|
||||
ndex = 0;
|
||||
bits = 0x00000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get code for run and add to compressed bitstream.
|
||||
*/
|
||||
public int add1DBits(byte[] buf,
|
||||
int where, // byte offs
|
||||
int count, // #pixels in run
|
||||
int color) // color of run
|
||||
{
|
||||
int sixtyfours;
|
||||
int mask;
|
||||
int len = where;
|
||||
|
||||
sixtyfours = count >>> 6; // count / 64;
|
||||
count = count & 0x3f; // count % 64
|
||||
if (sixtyfours != 0) {
|
||||
for ( ; sixtyfours > 40; sixtyfours -= 40) {
|
||||
mask = makeupCodes[color][40];
|
||||
bits |= (mask & 0xfff80000) >>> ndex;
|
||||
ndex += (mask & 0x0000ffff);
|
||||
while (ndex > 7) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
mask = makeupCodes[color][sixtyfours];
|
||||
bits |= (mask & 0xfff80000) >>> ndex;
|
||||
ndex += (mask & 0x0000ffff);
|
||||
while (ndex > 7) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
mask = termCodes[color][count];
|
||||
bits |= (mask & 0xfff80000) >>> ndex;
|
||||
ndex += (mask & 0x0000ffff);
|
||||
while (ndex > 7) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
return(len - where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place entry from mode table into compressed bitstream.
|
||||
*/
|
||||
public int add2DBits(byte[] buf, // compressed buffer
|
||||
int where, // byte offset into compressed buffer
|
||||
int[][] mode, // 2-D mode to be encoded
|
||||
int entry) // mode entry (0 unless vertical)
|
||||
{
|
||||
int mask;
|
||||
int len = where;
|
||||
int color = 0;
|
||||
|
||||
mask = mode[color][entry];
|
||||
bits |= (mask & 0xfff80000) >>> ndex;
|
||||
ndex += (mask & 0x0000ffff);
|
||||
while (ndex > 7) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
return(len - where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an End-of-Line (EOL == 0x001) to the compressed bitstream
|
||||
* with optional byte alignment.
|
||||
*/
|
||||
public int addEOL(boolean is1DMode,// 1D encoding
|
||||
boolean addFill, // byte aligned EOLs
|
||||
boolean add1, // add1 ? EOL+1 : EOL+0
|
||||
byte[] buf, // compressed buffer address
|
||||
int where) // current byte offset into buffer
|
||||
{
|
||||
int len = where;
|
||||
|
||||
//
|
||||
// Add zero-valued fill bits such that the EOL is aligned as
|
||||
//
|
||||
// xxxx 0000 0000 0001
|
||||
//
|
||||
if(addFill) {
|
||||
//
|
||||
// Simply increment the bit count. No need to feed bits into
|
||||
// the output buffer at this point as there are at most 7 bits
|
||||
// in the bit buffer, at most 7 are added here, and at most
|
||||
// 13 below making the total 7+7+13 = 27 before the bit feed
|
||||
// at the end of this routine.
|
||||
//
|
||||
ndex += ((ndex <= 4) ? 4 - ndex : 12 - ndex);
|
||||
}
|
||||
|
||||
//
|
||||
// Write EOL into buffer
|
||||
//
|
||||
if(is1DMode) {
|
||||
bits |= 0x00100000 >>> ndex;
|
||||
ndex += 12;
|
||||
} else {
|
||||
bits |= (add1 ? 0x00180000 : 0x00100000) >>> ndex;
|
||||
ndex += 13;
|
||||
}
|
||||
|
||||
while (ndex > 7) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
return(len - where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an End-of-Facsimile-Block (EOFB == 0x001001) to the compressed
|
||||
* bitstream.
|
||||
*/
|
||||
public int addEOFB(byte[] buf, // compressed buffer
|
||||
int where) // byte offset into compressed buffer
|
||||
{
|
||||
int len = where;
|
||||
|
||||
//
|
||||
// eofb code
|
||||
//
|
||||
bits |= 0x00100100 >>> ndex;
|
||||
|
||||
//
|
||||
// eofb code length
|
||||
//
|
||||
ndex += 24;
|
||||
|
||||
//
|
||||
// flush all pending bits
|
||||
//
|
||||
while(ndex > 0) {
|
||||
buf[len++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
return(len - where);
|
||||
}
|
||||
|
||||
/**
|
||||
* One-dimensionally encode a row of data using CCITT Huffman compression.
|
||||
* The bit buffer should be initialized as required before invoking this
|
||||
* method and should be flushed after the method returns. The fill order
|
||||
* is always highest-order to lowest-order bit so the calling routine
|
||||
* should handle bit inversion.
|
||||
*/
|
||||
public int encode1D(byte[] data,
|
||||
int rowOffset,
|
||||
int colOffset,
|
||||
int rowLength,
|
||||
byte[] compData,
|
||||
int compOffset) {
|
||||
int lineAddr = rowOffset;
|
||||
int bitIndex = colOffset;
|
||||
|
||||
int last = bitIndex + rowLength;
|
||||
int outIndex = compOffset;
|
||||
|
||||
//
|
||||
// Is first pixel black
|
||||
//
|
||||
int testbit =
|
||||
((data[lineAddr + (bitIndex>>>3)]&0xff) >>>
|
||||
(7-(bitIndex & 0x7))) & 0x1;
|
||||
int currentColor = BLACK;
|
||||
if (testbit != 0) {
|
||||
outIndex += add1DBits(compData, outIndex, 0, WHITE);
|
||||
} else {
|
||||
currentColor = WHITE;
|
||||
}
|
||||
|
||||
//
|
||||
// Run-length encode line
|
||||
//
|
||||
while (bitIndex < last) {
|
||||
int bitCount =
|
||||
nextState(data, lineAddr, bitIndex, last) - bitIndex;
|
||||
outIndex +=
|
||||
add1DBits(compData, outIndex, bitCount, currentColor);
|
||||
bitIndex += bitCount;
|
||||
currentColor ^= 0x00000001;
|
||||
}
|
||||
|
||||
return outIndex - compOffset;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import org.w3c.dom.Node;
|
||||
import javax.imageio.plugins.tiff.TIFFDirectory;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
import javax.imageio.plugins.tiff.TIFFTag;
|
||||
import javax.imageio.plugins.tiff.TIFFTagSet;
|
||||
|
||||
/**
|
||||
* The <code>Node</code> representation of a <code>TIFFField</code>
|
||||
* wherein the child node is procedural rather than buffered.
|
||||
*/
|
||||
public class TIFFFieldNode extends IIOMetadataNode {
|
||||
private static String getNodeName(TIFFField f) {
|
||||
return f.getData() instanceof TIFFDirectory ?
|
||||
"TIFFIFD" : "TIFFField";
|
||||
}
|
||||
|
||||
private boolean isIFD;
|
||||
|
||||
private Boolean isInitialized = Boolean.FALSE;
|
||||
|
||||
private TIFFField field;
|
||||
|
||||
public TIFFFieldNode(TIFFField field) {
|
||||
super(getNodeName(field));
|
||||
|
||||
isIFD = field.getData() instanceof TIFFDirectory;
|
||||
|
||||
this.field = field;
|
||||
|
||||
TIFFTag tag = field.getTag();
|
||||
int tagNumber = tag.getNumber();
|
||||
String tagName = tag.getName();
|
||||
|
||||
if(isIFD) {
|
||||
if(tagNumber != 0) {
|
||||
setAttribute("parentTagNumber", Integer.toString(tagNumber));
|
||||
}
|
||||
if(tagName != null) {
|
||||
setAttribute("parentTagName", tagName);
|
||||
}
|
||||
|
||||
TIFFDirectory dir = (TIFFDirectory)field.getData();
|
||||
TIFFTagSet[] tagSets = dir.getTagSets();
|
||||
if(tagSets != null) {
|
||||
StringBuilder tagSetNames = new StringBuilder();
|
||||
for(int i = 0; i < tagSets.length; i++) {
|
||||
tagSetNames.append(tagSets[i].getClass().getName());
|
||||
if(i != tagSets.length - 1) {
|
||||
tagSetNames.append(",");
|
||||
}
|
||||
}
|
||||
setAttribute("tagSets", tagSetNames.toString());
|
||||
}
|
||||
} else {
|
||||
setAttribute("number", Integer.toString(tagNumber));
|
||||
setAttribute("name", tagName);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initialize() {
|
||||
if(isInitialized) return;
|
||||
|
||||
if(isIFD) {
|
||||
TIFFDirectory dir = (TIFFDirectory)field.getData();
|
||||
TIFFField[] fields = dir.getTIFFFields();
|
||||
if(fields != null) {
|
||||
TIFFTagSet[] tagSets = dir.getTagSets();
|
||||
List<TIFFTagSet> tagSetList = Arrays.asList(tagSets);
|
||||
int numFields = fields.length;
|
||||
for(int i = 0; i < numFields; i++) {
|
||||
TIFFField f = fields[i];
|
||||
int tagNumber = f.getTagNumber();
|
||||
TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSetList);
|
||||
|
||||
Node node = f.getAsNativeNode();
|
||||
|
||||
if (node != null) {
|
||||
appendChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IIOMetadataNode child;
|
||||
int count = field.getCount();
|
||||
if (field.getType() == TIFFTag.TIFF_UNDEFINED) {
|
||||
child = new IIOMetadataNode("TIFFUndefined");
|
||||
|
||||
byte[] data = field.getAsBytes();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append(Integer.toString(data[i] & 0xff));
|
||||
if (i < count - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
child.setAttribute("value", sb.toString());
|
||||
} else {
|
||||
child = new IIOMetadataNode("TIFF" +
|
||||
TIFFField.getTypeName(field.getType()) +
|
||||
"s");
|
||||
|
||||
TIFFTag tag = field.getTag();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
IIOMetadataNode cchild =
|
||||
new IIOMetadataNode("TIFF" +
|
||||
TIFFField.getTypeName(field.getType()));
|
||||
|
||||
cchild.setAttribute("value", field.getValueAsString(i));
|
||||
if (tag.hasValueNames() && field.isIntegral()) {
|
||||
int value = field.getAsInt(i);
|
||||
String name = tag.getValueName(value);
|
||||
if (name != null) {
|
||||
cchild.setAttribute("description", name);
|
||||
}
|
||||
}
|
||||
|
||||
child.appendChild(cchild);
|
||||
}
|
||||
}
|
||||
appendChild(child);
|
||||
}
|
||||
|
||||
isInitialized = Boolean.TRUE;
|
||||
}
|
||||
|
||||
// Need to override this method to avoid a stack overflow exception
|
||||
// which will occur if super.appendChild is called from initialize().
|
||||
public Node appendChild(Node newChild) {
|
||||
if (newChild == null) {
|
||||
throw new NullPointerException("newChild == null!");
|
||||
}
|
||||
|
||||
return super.insertBefore(newChild, null);
|
||||
}
|
||||
|
||||
// Override all methods which refer to child nodes.
|
||||
|
||||
public boolean hasChildNodes() {
|
||||
initialize();
|
||||
return super.hasChildNodes();
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
initialize();
|
||||
return super.getLength();
|
||||
}
|
||||
|
||||
public Node getFirstChild() {
|
||||
initialize();
|
||||
return super.getFirstChild();
|
||||
}
|
||||
|
||||
public Node getLastChild() {
|
||||
initialize();
|
||||
return super.getLastChild();
|
||||
}
|
||||
|
||||
public Node getPreviousSibling() {
|
||||
initialize();
|
||||
return super.getPreviousSibling();
|
||||
}
|
||||
|
||||
public Node getNextSibling() {
|
||||
initialize();
|
||||
return super.getNextSibling();
|
||||
}
|
||||
|
||||
public Node insertBefore(Node newChild,
|
||||
Node refChild) {
|
||||
initialize();
|
||||
return super.insertBefore(newChild, refChild);
|
||||
}
|
||||
|
||||
public Node replaceChild(Node newChild,
|
||||
Node oldChild) {
|
||||
initialize();
|
||||
return super.replaceChild(newChild, oldChild);
|
||||
}
|
||||
|
||||
public Node removeChild(Node oldChild) {
|
||||
initialize();
|
||||
return super.removeChild(oldChild);
|
||||
}
|
||||
|
||||
public Node cloneNode(boolean deep) {
|
||||
initialize();
|
||||
return super.cloneNode(deep);
|
||||
}
|
||||
}
|
@ -0,0 +1,837 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFDirectory;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
import javax.imageio.plugins.tiff.TIFFTag;
|
||||
import javax.imageio.plugins.tiff.TIFFTagSet;
|
||||
|
||||
public class TIFFIFD extends TIFFDirectory {
|
||||
private static final long MAX_SAMPLES_PER_PIXEL = 0xffff;
|
||||
private static final long MAX_ASCII_SIZE = 0xffff;
|
||||
|
||||
private long stripOrTileByteCountsPosition = -1;
|
||||
private long stripOrTileOffsetsPosition = -1;
|
||||
private long lastPosition = -1;
|
||||
|
||||
public static TIFFTag getTag(int tagNumber, List<TIFFTagSet> tagSets) {
|
||||
Iterator<TIFFTagSet> iter = tagSets.iterator();
|
||||
while (iter.hasNext()) {
|
||||
TIFFTagSet tagSet = iter.next();
|
||||
TIFFTag tag = tagSet.getTag(tagNumber);
|
||||
if (tag != null) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TIFFTag getTag(String tagName, List<TIFFTagSet> tagSets) {
|
||||
Iterator<TIFFTagSet> iter = tagSets.iterator();
|
||||
while (iter.hasNext()) {
|
||||
TIFFTagSet tagSet = iter.next();
|
||||
TIFFTag tag = tagSet.getTag(tagName);
|
||||
if (tag != null) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void writeTIFFFieldToStream(TIFFField field,
|
||||
ImageOutputStream stream)
|
||||
throws IOException {
|
||||
int count = field.getCount();
|
||||
Object data = field.getData();
|
||||
|
||||
switch (field.getType()) {
|
||||
case TIFFTag.TIFF_ASCII:
|
||||
for (int i = 0; i < count; i++) {
|
||||
String s = ((String[])data)[i];
|
||||
int length = s.length();
|
||||
for (int j = 0; j < length; j++) {
|
||||
stream.writeByte(s.charAt(j) & 0xff);
|
||||
}
|
||||
stream.writeByte(0);
|
||||
}
|
||||
break;
|
||||
case TIFFTag.TIFF_UNDEFINED:
|
||||
case TIFFTag.TIFF_BYTE:
|
||||
case TIFFTag.TIFF_SBYTE:
|
||||
stream.write((byte[])data);
|
||||
break;
|
||||
case TIFFTag.TIFF_SHORT:
|
||||
stream.writeChars((char[])data, 0, ((char[])data).length);
|
||||
break;
|
||||
case TIFFTag.TIFF_SSHORT:
|
||||
stream.writeShorts((short[])data, 0, ((short[])data).length);
|
||||
break;
|
||||
case TIFFTag.TIFF_SLONG:
|
||||
stream.writeInts((int[])data, 0, ((int[])data).length);
|
||||
break;
|
||||
case TIFFTag.TIFF_LONG:
|
||||
for (int i = 0; i < count; i++) {
|
||||
stream.writeInt((int)(((long[])data)[i]));
|
||||
}
|
||||
break;
|
||||
case TIFFTag.TIFF_IFD_POINTER:
|
||||
stream.writeInt(0); // will need to be backpatched
|
||||
break;
|
||||
case TIFFTag.TIFF_FLOAT:
|
||||
stream.writeFloats((float[])data, 0, ((float[])data).length);
|
||||
break;
|
||||
case TIFFTag.TIFF_DOUBLE:
|
||||
stream.writeDoubles((double[])data, 0, ((double[])data).length);
|
||||
break;
|
||||
case TIFFTag.TIFF_SRATIONAL:
|
||||
for (int i = 0; i < count; i++) {
|
||||
stream.writeInt(((int[][])data)[i][0]);
|
||||
stream.writeInt(((int[][])data)[i][1]);
|
||||
}
|
||||
break;
|
||||
case TIFFTag.TIFF_RATIONAL:
|
||||
for (int i = 0; i < count; i++) {
|
||||
long num = ((long[][])data)[i][0];
|
||||
long den = ((long[][])data)[i][1];
|
||||
stream.writeInt((int)num);
|
||||
stream.writeInt((int)den);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// error
|
||||
}
|
||||
}
|
||||
|
||||
public TIFFIFD(List<TIFFTagSet> tagSets, TIFFTag parentTag) {
|
||||
super(tagSets.toArray(new TIFFTagSet[tagSets.size()]),
|
||||
parentTag);
|
||||
}
|
||||
|
||||
public TIFFIFD(List<TIFFTagSet> tagSets) {
|
||||
this(tagSets, null);
|
||||
}
|
||||
|
||||
public List<TIFFTagSet> getTagSetList() {
|
||||
return Arrays.asList(getTagSets());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>Iterator</code> over the TIFF fields. The
|
||||
* traversal is in the order of increasing tag number.
|
||||
*/
|
||||
// Note: the sort is guaranteed for low fields by the use of an
|
||||
// array wherein the index corresponds to the tag number and for
|
||||
// the high fields by the use of a TreeMap with tag number keys.
|
||||
public Iterator<TIFFField> iterator() {
|
||||
return Arrays.asList(getTIFFFields()).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the value of a field. The <code>data</code> parameter should be
|
||||
* an array of length 1 of Object.
|
||||
*
|
||||
* @param stream the input stream
|
||||
* @param type the type as read from the stream
|
||||
* @param count the count read from the stream
|
||||
* @param data a container for the data
|
||||
* @return the updated count
|
||||
* @throws IOException
|
||||
*/
|
||||
private static int readFieldValue(ImageInputStream stream,
|
||||
int type, int count, Object[] data) throws IOException {
|
||||
Object obj;
|
||||
|
||||
switch (type) {
|
||||
case TIFFTag.TIFF_BYTE:
|
||||
case TIFFTag.TIFF_SBYTE:
|
||||
case TIFFTag.TIFF_UNDEFINED:
|
||||
case TIFFTag.TIFF_ASCII:
|
||||
byte[] bvalues = new byte[count];
|
||||
stream.readFully(bvalues, 0, count);
|
||||
|
||||
if (type == TIFFTag.TIFF_ASCII) {
|
||||
// Can be multiple strings
|
||||
ArrayList<String> v = new ArrayList<>();
|
||||
boolean inString = false;
|
||||
int prevIndex = 0;
|
||||
for (int index = 0; index <= count; index++) {
|
||||
if (index < count && bvalues[index] != 0) {
|
||||
if (!inString) {
|
||||
// start of string
|
||||
prevIndex = index;
|
||||
inString = true;
|
||||
}
|
||||
} else { // null or special case at end of string
|
||||
if (inString) {
|
||||
// end of string
|
||||
String s = new String(bvalues, prevIndex,
|
||||
index - prevIndex,
|
||||
StandardCharsets.US_ASCII);
|
||||
v.add(s);
|
||||
inString = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = v.size();
|
||||
String[] strings;
|
||||
if (count != 0) {
|
||||
strings = new String[count];
|
||||
for (int c = 0; c < count; c++) {
|
||||
strings[c] = v.get(c);
|
||||
}
|
||||
} else {
|
||||
// This case has been observed when the value of
|
||||
// 'count' recorded in the field is non-zero but
|
||||
// the value portion contains all nulls.
|
||||
count = 1;
|
||||
strings = new String[]{""};
|
||||
}
|
||||
|
||||
obj = strings;
|
||||
} else {
|
||||
obj = bvalues;
|
||||
}
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_SHORT:
|
||||
char[] cvalues = new char[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
cvalues[j] = (char) (stream.readUnsignedShort());
|
||||
}
|
||||
obj = cvalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_LONG:
|
||||
case TIFFTag.TIFF_IFD_POINTER:
|
||||
long[] lvalues = new long[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
lvalues[j] = stream.readUnsignedInt();
|
||||
}
|
||||
obj = lvalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_RATIONAL:
|
||||
long[][] llvalues = new long[count][2];
|
||||
for (int j = 0; j < count; j++) {
|
||||
llvalues[j][0] = stream.readUnsignedInt();
|
||||
llvalues[j][1] = stream.readUnsignedInt();
|
||||
}
|
||||
obj = llvalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_SSHORT:
|
||||
short[] svalues = new short[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
svalues[j] = stream.readShort();
|
||||
}
|
||||
obj = svalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_SLONG:
|
||||
int[] ivalues = new int[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
ivalues[j] = stream.readInt();
|
||||
}
|
||||
obj = ivalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_SRATIONAL:
|
||||
int[][] iivalues = new int[count][2];
|
||||
for (int j = 0; j < count; j++) {
|
||||
iivalues[j][0] = stream.readInt();
|
||||
iivalues[j][1] = stream.readInt();
|
||||
}
|
||||
obj = iivalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_FLOAT:
|
||||
float[] fvalues = new float[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
fvalues[j] = stream.readFloat();
|
||||
}
|
||||
obj = fvalues;
|
||||
break;
|
||||
|
||||
case TIFFTag.TIFF_DOUBLE:
|
||||
double[] dvalues = new double[count];
|
||||
for (int j = 0; j < count; j++) {
|
||||
dvalues[j] = stream.readDouble();
|
||||
}
|
||||
obj = dvalues;
|
||||
break;
|
||||
|
||||
default:
|
||||
obj = null;
|
||||
break;
|
||||
}
|
||||
|
||||
data[0] = obj;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//
|
||||
// Class to represent an IFD entry where the actual content is at an offset
|
||||
// in the stream somewhere outside the IFD itself. This occurs when the
|
||||
// value cannot be contained within four bytes. Seeking is required to read
|
||||
// such field values.
|
||||
//
|
||||
private static class TIFFIFDEntry {
|
||||
public final TIFFTag tag;
|
||||
public final int type;
|
||||
public final int count;
|
||||
public final long offset;
|
||||
|
||||
TIFFIFDEntry(TIFFTag tag, int type, int count, long offset) {
|
||||
this.tag = tag;
|
||||
this.type = type;
|
||||
this.count = count;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Verify that data pointed to outside of the IFD itself are within the
|
||||
// stream. To be called after all fields have been read and populated.
|
||||
//
|
||||
private void checkFieldOffsets(long streamLength) throws IIOException {
|
||||
if (streamLength < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// StripOffsets
|
||||
List<TIFFField> offsets = new ArrayList<>();
|
||||
TIFFField f = getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
|
||||
int count = 0;
|
||||
if (f != null) {
|
||||
count = f.getCount();
|
||||
offsets.add(f);
|
||||
}
|
||||
|
||||
// TileOffsets
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
|
||||
if (f != null) {
|
||||
int sz = offsets.size();
|
||||
int newCount = f.getCount();
|
||||
if (sz > 0 && newCount != count) {
|
||||
throw new IIOException
|
||||
("StripOffsets count != TileOffsets count");
|
||||
}
|
||||
|
||||
if (sz == 0) {
|
||||
count = newCount;
|
||||
}
|
||||
offsets.add(f);
|
||||
}
|
||||
|
||||
if (offsets.size() > 0) {
|
||||
// StripByteCounts
|
||||
List<TIFFField> byteCounts = new ArrayList<>();
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
|
||||
if (f != null) {
|
||||
if (f.getCount() != count) {
|
||||
throw new IIOException
|
||||
("StripByteCounts count != number of offsets");
|
||||
}
|
||||
byteCounts.add(f);
|
||||
}
|
||||
|
||||
// TileByteCounts
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS);
|
||||
if (f != null) {
|
||||
if (f.getCount() != count) {
|
||||
throw new IIOException
|
||||
("TileByteCounts count != number of offsets");
|
||||
}
|
||||
byteCounts.add(f);
|
||||
}
|
||||
|
||||
if (byteCounts.size() > 0) {
|
||||
for (TIFFField offset : offsets) {
|
||||
for (TIFFField byteCount : byteCounts) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
long dataOffset = offset.getAsLong(i);
|
||||
long dataByteCount = byteCount.getAsLong(i);
|
||||
if (dataOffset + dataByteCount > streamLength) {
|
||||
throw new IIOException
|
||||
("Data segment out of stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JPEGInterchangeFormat and JPEGInterchangeFormatLength
|
||||
TIFFField jpegOffset =
|
||||
getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||
if (jpegOffset != null) {
|
||||
TIFFField jpegLength =
|
||||
getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
if (jpegLength != null) {
|
||||
if (jpegOffset.getAsLong(0) + jpegLength.getAsLong(0)
|
||||
> streamLength) {
|
||||
throw new IIOException
|
||||
("JPEGInterchangeFormat data out of stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JPEGQTables - one 64-byte table for each offset.
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_JPEG_Q_TABLES);
|
||||
if (f != null) {
|
||||
long[] tableOffsets = f.getAsLongs();
|
||||
for (long off : tableOffsets) {
|
||||
if (off + 64 > streamLength) {
|
||||
throw new IIOException("JPEGQTables data out of stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JPEGDCTables
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_JPEG_DC_TABLES);
|
||||
if (f != null) {
|
||||
long[] tableOffsets = f.getAsLongs();
|
||||
for (long off : tableOffsets) {
|
||||
if (off + 16 > streamLength) {
|
||||
throw new IIOException("JPEGDCTables data out of stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JPEGACTables
|
||||
f = getTIFFField(BaselineTIFFTagSet.TAG_JPEG_AC_TABLES);
|
||||
if (f != null) {
|
||||
long[] tableOffsets = f.getAsLongs();
|
||||
for (long off : tableOffsets) {
|
||||
if (off + 16 > streamLength) {
|
||||
throw new IIOException("JPEGACTables data out of stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stream position initially at beginning, left at end
|
||||
// if ignoreUnknownFields is true, do not load fields for which
|
||||
// a tag cannot be found in an allowed TagSet.
|
||||
public void initialize(ImageInputStream stream, boolean isPrimaryIFD,
|
||||
boolean ignoreUnknownFields) throws IOException {
|
||||
|
||||
removeTIFFFields();
|
||||
|
||||
long streamLength = stream.length();
|
||||
boolean haveStreamLength = streamLength != -1;
|
||||
|
||||
List<TIFFTagSet> tagSetList = getTagSetList();
|
||||
|
||||
List<Object> entries = new ArrayList<>();
|
||||
Object[] entryData = new Object[1]; // allocate once for later reuse.
|
||||
|
||||
// Read the IFD entries, loading the field values which are no more than
|
||||
// four bytes long, and storing the 4-byte offsets for the others.
|
||||
int numEntries = stream.readUnsignedShort();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
// Read tag number, value type, and value count.
|
||||
int tagNumber = stream.readUnsignedShort();
|
||||
int type = stream.readUnsignedShort();
|
||||
int count = (int)stream.readUnsignedInt();
|
||||
|
||||
// Get the associated TIFFTag.
|
||||
TIFFTag tag = getTag(tagNumber, tagSetList);
|
||||
|
||||
// Ignore unknown fields.
|
||||
if((tag == null && ignoreUnknownFields)
|
||||
|| (tag != null && !tag.isDataTypeOK(type))) {
|
||||
// Skip the value/offset so as to leave the stream
|
||||
// position at the start of the next IFD entry.
|
||||
stream.skipBytes(4);
|
||||
|
||||
// Continue with the next IFD entry.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag == null) {
|
||||
tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, tagNumber,
|
||||
1 << type, count);
|
||||
} else {
|
||||
int expectedCount = tag.getCount();
|
||||
if (expectedCount > 0) {
|
||||
// If the tag count is positive then the tag defines a
|
||||
// specific, fixed count that the field must match.
|
||||
if (count != expectedCount) {
|
||||
throw new IIOException("Unexpected count "
|
||||
+ count + " for " + tag.getName() + " field");
|
||||
}
|
||||
} else if (type == TIFFTag.TIFF_ASCII) {
|
||||
// Clamp the size of ASCII fields of unspecified length
|
||||
// to a maximum value.
|
||||
int asciiSize = TIFFTag.getSizeOfType(TIFFTag.TIFF_ASCII);
|
||||
if (count*asciiSize > MAX_ASCII_SIZE) {
|
||||
count = (int)(MAX_ASCII_SIZE/asciiSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size = count*TIFFTag.getSizeOfType(type);
|
||||
if (size > 4 || tag.isIFDPointer()) {
|
||||
// The IFD entry value is a pointer to the actual field value.
|
||||
long offset = stream.readUnsignedInt();
|
||||
|
||||
// Check whether the the field value is within the stream.
|
||||
if (haveStreamLength && offset + size > streamLength) {
|
||||
throw new IIOException("Field data is past end-of-stream");
|
||||
}
|
||||
|
||||
// Add a TIFFIFDEntry as a placeholder. This avoids a mark,
|
||||
// seek to the data, and a reset.
|
||||
entries.add(new TIFFIFDEntry(tag, type, count, offset));
|
||||
} else {
|
||||
// The IFD entry value is the actual field value of no more than
|
||||
// four bytes.
|
||||
Object obj = null;
|
||||
try {
|
||||
// Read the field value and update the count.
|
||||
count = readFieldValue(stream, type, count, entryData);
|
||||
obj = entryData[0];
|
||||
} catch (EOFException eofe) {
|
||||
// The TIFF 6.0 fields have tag numbers less than or equal
|
||||
// to 532 (ReferenceBlackWhite) or equal to 33432 (Copyright).
|
||||
// If there is an error reading a baseline tag, then re-throw
|
||||
// the exception and fail; otherwise continue with the next
|
||||
// field.
|
||||
if (BaselineTIFFTagSet.getInstance().getTag(tagNumber) == null) {
|
||||
throw eofe;
|
||||
}
|
||||
}
|
||||
|
||||
// If the field value is smaller than four bytes then skip
|
||||
// the remaining, unused bytes.
|
||||
if (size < 4) {
|
||||
stream.skipBytes(4 - size);
|
||||
}
|
||||
|
||||
// Add the populated TIFFField to the list of entries.
|
||||
entries.add(new TIFFField(tag, type, count, obj));
|
||||
}
|
||||
}
|
||||
|
||||
// After reading the IFD entries the stream is positioned at an unsigned
|
||||
// four byte integer containing either the offset of the next IFD or
|
||||
// zero if this is the last IFD.
|
||||
long nextIFDOffset = stream.getStreamPosition();
|
||||
|
||||
Object[] fieldData = new Object[1];
|
||||
for (Object entry : entries) {
|
||||
if (entry instanceof TIFFField) {
|
||||
// Add the populated field directly.
|
||||
addTIFFField((TIFFField)entry);
|
||||
} else {
|
||||
TIFFIFDEntry e = (TIFFIFDEntry)entry;
|
||||
TIFFTag tag = e.tag;
|
||||
int tagNumber = tag.getNumber();
|
||||
int type = e.type;
|
||||
int count = e.count;
|
||||
|
||||
stream.seek(e.offset);
|
||||
|
||||
if (tag.isIFDPointer()) {
|
||||
List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(1);
|
||||
tagSets.add(tag.getTagSet());
|
||||
TIFFIFD subIFD = new TIFFIFD(tagSets);
|
||||
|
||||
subIFD.initialize(stream, false, ignoreUnknownFields);
|
||||
TIFFField f = new TIFFField(tag, type, e.offset, subIFD);
|
||||
addTIFFField(f);
|
||||
} else {
|
||||
if (tagNumber == BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS
|
||||
|| tagNumber == BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS
|
||||
|| tagNumber == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) {
|
||||
this.stripOrTileByteCountsPosition
|
||||
= stream.getStreamPosition();
|
||||
} else if (tagNumber == BaselineTIFFTagSet.TAG_STRIP_OFFSETS
|
||||
|| tagNumber == BaselineTIFFTagSet.TAG_TILE_OFFSETS
|
||||
|| tagNumber == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) {
|
||||
this.stripOrTileOffsetsPosition
|
||||
= stream.getStreamPosition();
|
||||
}
|
||||
|
||||
Object obj = null;
|
||||
try {
|
||||
count = readFieldValue(stream, type, count, fieldData);
|
||||
obj = fieldData[0];
|
||||
} catch (EOFException eofe) {
|
||||
// The TIFF 6.0 fields have tag numbers less than or equal
|
||||
// to 532 (ReferenceBlackWhite) or equal to 33432 (Copyright).
|
||||
// If there is an error reading a baseline tag, then re-throw
|
||||
// the exception and fail; otherwise continue with the next
|
||||
// field.
|
||||
if (BaselineTIFFTagSet.getInstance().getTag(tagNumber) == null) {
|
||||
throw eofe;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TIFFField f = new TIFFField(tag, type, count, obj);
|
||||
addTIFFField(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isPrimaryIFD && haveStreamLength) {
|
||||
checkFieldOffsets(streamLength);
|
||||
}
|
||||
|
||||
stream.seek(nextIFDOffset);
|
||||
this.lastPosition = stream.getStreamPosition();
|
||||
}
|
||||
|
||||
public void writeToStream(ImageOutputStream stream)
|
||||
throws IOException {
|
||||
|
||||
int numFields = getNumTIFFFields();
|
||||
stream.writeShort(numFields);
|
||||
|
||||
long nextSpace = stream.getStreamPosition() + 12*numFields + 4;
|
||||
|
||||
Iterator<TIFFField> iter = iterator();
|
||||
while (iter.hasNext()) {
|
||||
TIFFField f = iter.next();
|
||||
|
||||
TIFFTag tag = f.getTag();
|
||||
|
||||
int type = f.getType();
|
||||
int count = f.getCount();
|
||||
|
||||
// Deal with unknown tags
|
||||
if (type == 0) {
|
||||
type = TIFFTag.TIFF_UNDEFINED;
|
||||
}
|
||||
int size = count*TIFFTag.getSizeOfType(type);
|
||||
|
||||
if (type == TIFFTag.TIFF_ASCII) {
|
||||
int chars = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
chars += f.getAsString(i).length() + 1;
|
||||
}
|
||||
count = chars;
|
||||
size = count;
|
||||
}
|
||||
|
||||
int tagNumber = f.getTagNumber();
|
||||
stream.writeShort(tagNumber);
|
||||
stream.writeShort(type);
|
||||
stream.writeInt(count);
|
||||
|
||||
// Write a dummy value to fill space
|
||||
stream.writeInt(0);
|
||||
stream.mark(); // Mark beginning of next field
|
||||
stream.skipBytes(-4);
|
||||
|
||||
long pos;
|
||||
|
||||
if (size > 4 || tag.isIFDPointer()) {
|
||||
// Ensure IFD or value is written on a word boundary
|
||||
nextSpace = (nextSpace + 3) & ~0x3;
|
||||
|
||||
stream.writeInt((int)nextSpace);
|
||||
stream.seek(nextSpace);
|
||||
pos = nextSpace;
|
||||
|
||||
if (tag.isIFDPointer() && f.hasDirectory()) {
|
||||
TIFFIFD subIFD = (TIFFIFD)f.getDirectory();
|
||||
subIFD.writeToStream(stream);
|
||||
nextSpace = subIFD.lastPosition;
|
||||
} else {
|
||||
writeTIFFFieldToStream(f, stream);
|
||||
nextSpace = stream.getStreamPosition();
|
||||
}
|
||||
} else {
|
||||
pos = stream.getStreamPosition();
|
||||
writeTIFFFieldToStream(f, stream);
|
||||
}
|
||||
|
||||
// If we are writing the data for the
|
||||
// StripByteCounts, TileByteCounts, StripOffsets,
|
||||
// TileOffsets, JPEGInterchangeFormat, or
|
||||
// JPEGInterchangeFormatLength fields, record the current stream
|
||||
// position for backpatching
|
||||
if (tagNumber ==
|
||||
BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS ||
|
||||
tagNumber == BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS ||
|
||||
tagNumber == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) {
|
||||
this.stripOrTileByteCountsPosition = pos;
|
||||
} else if (tagNumber ==
|
||||
BaselineTIFFTagSet.TAG_STRIP_OFFSETS ||
|
||||
tagNumber ==
|
||||
BaselineTIFFTagSet.TAG_TILE_OFFSETS ||
|
||||
tagNumber ==
|
||||
BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) {
|
||||
this.stripOrTileOffsetsPosition = pos;
|
||||
}
|
||||
|
||||
stream.reset(); // Go to marked position of next field
|
||||
}
|
||||
|
||||
this.lastPosition = nextSpace;
|
||||
}
|
||||
|
||||
public long getStripOrTileByteCountsPosition() {
|
||||
return stripOrTileByteCountsPosition;
|
||||
}
|
||||
|
||||
public long getStripOrTileOffsetsPosition() {
|
||||
return stripOrTileOffsetsPosition;
|
||||
}
|
||||
|
||||
public long getLastPosition() {
|
||||
return lastPosition;
|
||||
}
|
||||
|
||||
void setPositions(long stripOrTileOffsetsPosition,
|
||||
long stripOrTileByteCountsPosition,
|
||||
long lastPosition) {
|
||||
this.stripOrTileOffsetsPosition = stripOrTileOffsetsPosition;
|
||||
this.stripOrTileByteCountsPosition = stripOrTileByteCountsPosition;
|
||||
this.lastPosition = lastPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>TIFFIFD</code> wherein all fields from the
|
||||
* <code>BaselineTIFFTagSet</code> are copied by value and all other
|
||||
* fields copied by reference.
|
||||
*/
|
||||
public TIFFIFD getShallowClone() {
|
||||
// Get the baseline TagSet.
|
||||
TIFFTagSet baselineTagSet = BaselineTIFFTagSet.getInstance();
|
||||
|
||||
// If the baseline TagSet is not included just return.
|
||||
List<TIFFTagSet> tagSetList = getTagSetList();
|
||||
if(!tagSetList.contains(baselineTagSet)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Create a new object.
|
||||
TIFFIFD shallowClone = new TIFFIFD(tagSetList, getParentTag());
|
||||
|
||||
// Get the tag numbers in the baseline set.
|
||||
Set<Integer> baselineTagNumbers = baselineTagSet.getTagNumbers();
|
||||
|
||||
// Iterate over the fields in this IFD.
|
||||
Iterator<TIFFField> fields = iterator();
|
||||
while(fields.hasNext()) {
|
||||
// Get the next field.
|
||||
TIFFField field = fields.next();
|
||||
|
||||
// Get its tag number.
|
||||
Integer tagNumber = Integer.valueOf(field.getTagNumber());
|
||||
|
||||
// Branch based on membership in baseline set.
|
||||
TIFFField fieldClone;
|
||||
if(baselineTagNumbers.contains(tagNumber)) {
|
||||
// Copy by value.
|
||||
Object fieldData = field.getData();
|
||||
|
||||
int fieldType = field.getType();
|
||||
|
||||
try {
|
||||
switch (fieldType) {
|
||||
case TIFFTag.TIFF_BYTE:
|
||||
case TIFFTag.TIFF_SBYTE:
|
||||
case TIFFTag.TIFF_UNDEFINED:
|
||||
fieldData = ((byte[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_ASCII:
|
||||
fieldData = ((String[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_SHORT:
|
||||
fieldData = ((char[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_LONG:
|
||||
case TIFFTag.TIFF_IFD_POINTER:
|
||||
fieldData = ((long[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_RATIONAL:
|
||||
fieldData = ((long[][])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_SSHORT:
|
||||
fieldData = ((short[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_SLONG:
|
||||
fieldData = ((int[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_SRATIONAL:
|
||||
fieldData = ((int[][])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_FLOAT:
|
||||
fieldData = ((float[])fieldData).clone();
|
||||
break;
|
||||
case TIFFTag.TIFF_DOUBLE:
|
||||
fieldData = ((double[])fieldData).clone();
|
||||
break;
|
||||
default:
|
||||
// Shouldn't happen but do nothing ...
|
||||
}
|
||||
} catch(Exception e) {
|
||||
// Ignore it and copy by reference ...
|
||||
}
|
||||
|
||||
fieldClone = new TIFFField(field.getTag(), fieldType,
|
||||
field.getCount(), fieldData);
|
||||
} else {
|
||||
// Copy by reference.
|
||||
fieldClone = field;
|
||||
}
|
||||
|
||||
// Add the field to the clone.
|
||||
shallowClone.addTIFFField(fieldClone);
|
||||
}
|
||||
|
||||
// Set positions.
|
||||
shallowClone.setPositions(stripOrTileOffsetsPosition,
|
||||
stripOrTileByteCountsPosition,
|
||||
lastPosition);
|
||||
|
||||
return shallowClone;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
|
||||
public class TIFFImageMetadataFormat extends TIFFMetadataFormat {
|
||||
|
||||
private static TIFFImageMetadataFormat theInstance = null;
|
||||
|
||||
static {
|
||||
}
|
||||
|
||||
public boolean canNodeAppear(String elementName,
|
||||
ImageTypeSpecifier imageType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private TIFFImageMetadataFormat() {
|
||||
this.resourceBaseName =
|
||||
"javax.imageio.plugins.tiff.TIFFImageMetadataFormatResources";
|
||||
this.rootName = TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME;
|
||||
|
||||
TIFFElementInfo einfo;
|
||||
TIFFAttrInfo ainfo;
|
||||
String[] empty = new String[0];
|
||||
String[] childNames;
|
||||
String[] attrNames;
|
||||
|
||||
childNames = new String[] { "TIFFIFD" };
|
||||
einfo = new TIFFElementInfo(childNames, empty, CHILD_POLICY_SEQUENCE);
|
||||
|
||||
elementInfoMap.put(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
einfo);
|
||||
|
||||
childNames = new String[] { "TIFFField", "TIFFIFD" };
|
||||
attrNames =
|
||||
new String[] { "tagSets", "parentTagNumber", "parentTagName" };
|
||||
einfo = new TIFFElementInfo(childNames, attrNames, CHILD_POLICY_SEQUENCE);
|
||||
elementInfoMap.put("TIFFIFD", einfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
ainfo.dataType = DATATYPE_STRING;
|
||||
ainfo.isRequired = true;
|
||||
attrInfoMap.put("TIFFIFD/tagSets", ainfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
ainfo.dataType = DATATYPE_INTEGER;
|
||||
ainfo.isRequired = false;
|
||||
attrInfoMap.put("TIFFIFD/parentTagNumber", ainfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
ainfo.dataType = DATATYPE_STRING;
|
||||
ainfo.isRequired = false;
|
||||
attrInfoMap.put("TIFFIFD/parentTagName", ainfo);
|
||||
|
||||
String[] types = {
|
||||
"TIFFByte",
|
||||
"TIFFAscii",
|
||||
"TIFFShort",
|
||||
"TIFFSShort",
|
||||
"TIFFLong",
|
||||
"TIFFSLong",
|
||||
"TIFFRational",
|
||||
"TIFFSRational",
|
||||
"TIFFFloat",
|
||||
"TIFFDouble",
|
||||
"TIFFUndefined"
|
||||
};
|
||||
|
||||
attrNames = new String[] { "value", "description" };
|
||||
String[] attrNamesValueOnly = new String[] { "value" };
|
||||
TIFFAttrInfo ainfoValue = new TIFFAttrInfo();
|
||||
TIFFAttrInfo ainfoDescription = new TIFFAttrInfo();
|
||||
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (!types[i].equals("TIFFUndefined")) {
|
||||
childNames = new String[1];
|
||||
childNames[0] = types[i];
|
||||
einfo =
|
||||
new TIFFElementInfo(childNames, empty, CHILD_POLICY_SEQUENCE);
|
||||
elementInfoMap.put(types[i] + "s", einfo);
|
||||
}
|
||||
|
||||
boolean hasDescription =
|
||||
!types[i].equals("TIFFUndefined") &&
|
||||
!types[i].equals("TIFFAscii") &&
|
||||
!types[i].equals("TIFFRational") &&
|
||||
!types[i].equals("TIFFSRational") &&
|
||||
!types[i].equals("TIFFFloat") &&
|
||||
!types[i].equals("TIFFDouble");
|
||||
|
||||
String[] anames = hasDescription ? attrNames : attrNamesValueOnly;
|
||||
einfo = new TIFFElementInfo(empty, anames, CHILD_POLICY_EMPTY);
|
||||
elementInfoMap.put(types[i], einfo);
|
||||
|
||||
attrInfoMap.put(types[i] + "/value", ainfoValue);
|
||||
if (hasDescription) {
|
||||
attrInfoMap.put(types[i] + "/description", ainfoDescription);
|
||||
}
|
||||
}
|
||||
|
||||
childNames = new String[2*types.length - 1];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
childNames[2*i] = types[i];
|
||||
if (!types[i].equals("TIFFUndefined")) {
|
||||
childNames[2*i + 1] = types[i] + "s";
|
||||
}
|
||||
}
|
||||
attrNames = new String[] { "number", "name" };
|
||||
einfo = new TIFFElementInfo(childNames, attrNames, CHILD_POLICY_CHOICE);
|
||||
elementInfoMap.put("TIFFField", einfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
ainfo.isRequired = true;
|
||||
attrInfoMap.put("TIFFField/number", ainfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
attrInfoMap.put("TIFFField/name", ainfo);
|
||||
}
|
||||
|
||||
public static synchronized IIOMetadataFormat getInstance() {
|
||||
if (theInstance == null) {
|
||||
theInstance = new TIFFImageMetadataFormat();
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ListResourceBundle;
|
||||
|
||||
public class TIFFImageMetadataFormatResources extends ListResourceBundle {
|
||||
|
||||
private static final Object[][] contents = {
|
||||
{ "TIFFIFD", "An IFD (directory) containing fields" },
|
||||
{ "TIFFIFD/parentTagNumber",
|
||||
"The tag number of the field pointing to this IFD" },
|
||||
{ "TIFFIFD/parentTagName",
|
||||
"A mnemonic name for the field pointing to this IFD, if known" },
|
||||
{ "TIFFField", "A field containing data" },
|
||||
{ "TIFFField/number", "The tag number asociated with the field" },
|
||||
{ "TIFFField/name",
|
||||
"A mnemonic name associated with the field, if known" },
|
||||
|
||||
{ "TIFFUndefined", "Uninterpreted byte data" },
|
||||
{ "TIFFUndefined/value", "A list of comma-separated byte values" },
|
||||
|
||||
{ "TIFFBytes", "A sequence of TIFFByte nodes" },
|
||||
{ "TIFFByte", "An integral value between 0 and 255" },
|
||||
{ "TIFFByte/value", "The value" },
|
||||
{ "TIFFByte/description", "A description, if available" },
|
||||
|
||||
{ "TIFFAsciis", "A sequence of TIFFAscii nodes" },
|
||||
{ "TIFFAscii", "A String value" },
|
||||
{ "TIFFAscii/value", "The value" },
|
||||
|
||||
{ "TIFFShorts", "A sequence of TIFFShort nodes" },
|
||||
{ "TIFFShort", "An integral value between 0 and 65535" },
|
||||
{ "TIFFShort/value", "The value" },
|
||||
{ "TIFFShort/description", "A description, if available" },
|
||||
|
||||
{ "TIFFSShorts", "A sequence of TIFFSShort nodes" },
|
||||
{ "TIFFSShort", "An integral value between -32768 and 32767" },
|
||||
{ "TIFFSShort/value", "The value" },
|
||||
{ "TIFFSShort/description", "A description, if available" },
|
||||
|
||||
{ "TIFFLongs", "A sequence of TIFFLong nodes" },
|
||||
{ "TIFFLong", "An integral value between 0 and 4294967295" },
|
||||
{ "TIFFLong/value", "The value" },
|
||||
{ "TIFFLong/description", "A description, if available" },
|
||||
|
||||
{ "TIFFSLongs", "A sequence of TIFFSLong nodes" },
|
||||
{ "TIFFSLong", "An integral value between -2147483648 and 2147483647" },
|
||||
{ "TIFFSLong/value", "The value" },
|
||||
{ "TIFFSLong/description", "A description, if available" },
|
||||
|
||||
{ "TIFFRationals", "A sequence of TIFFRational nodes" },
|
||||
{ "TIFFRational",
|
||||
"A rational value consisting of an unsigned numerator and denominator" },
|
||||
{ "TIFFRational/value",
|
||||
"The numerator and denominator, separated by a slash" },
|
||||
|
||||
{ "TIFFSRationals", "A sequence of TIFFSRational nodes" },
|
||||
{ "TIFFSRational",
|
||||
"A rational value consisting of a signed numerator and denominator" },
|
||||
{ "TIFFSRational/value",
|
||||
"The numerator and denominator, separated by a slash" },
|
||||
|
||||
{ "TIFFFloats", "A sequence of TIFFFloat nodes" },
|
||||
{ "TIFFFloat", "A single-precision floating-point value" },
|
||||
{ "TIFFFloat/value", "The value" },
|
||||
|
||||
{ "TIFFDoubles", "A sequence of TIFFDouble nodes" },
|
||||
{ "TIFFDouble", "A double-precision floating-point value" },
|
||||
{ "TIFFDouble/value", "The value" },
|
||||
|
||||
};
|
||||
|
||||
public TIFFImageMetadataFormatResources() {
|
||||
}
|
||||
|
||||
public Object[][] getContents() {
|
||||
return contents.clone();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
public class TIFFImageReaderSpi extends ImageReaderSpi {
|
||||
|
||||
private boolean registered = false;
|
||||
|
||||
public TIFFImageReaderSpi() {
|
||||
super("Oracle Corporation",
|
||||
"1.0",
|
||||
new String[] {"tif", "TIF", "tiff", "TIFF"},
|
||||
new String[] {"tif", "tiff"},
|
||||
new String[] {"image/tiff"},
|
||||
"com.sun.imageio.plugins.tiff.TIFFImageReader",
|
||||
new Class<?>[] { ImageInputStream.class },
|
||||
new String[] {"com.sun.imageio.plugins.tiff.TIFFImageWriterSpi"},
|
||||
false,
|
||||
TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
"com.sun.imageio.plugins.tiff.TIFFStreamMetadataFormat",
|
||||
null, null,
|
||||
true,
|
||||
TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
"com.sun.imageio.plugins.tiff.TIFFImageMetadataFormat",
|
||||
null, null
|
||||
);
|
||||
}
|
||||
|
||||
public String getDescription(Locale locale) {
|
||||
return "Standard TIFF image reader";
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(Object input) throws IOException {
|
||||
if (!(input instanceof ImageInputStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageInputStream stream = (ImageInputStream)input;
|
||||
byte[] b = new byte[4];
|
||||
stream.mark();
|
||||
stream.readFully(b);
|
||||
stream.reset();
|
||||
|
||||
return ((b[0] == (byte)0x49 && b[1] == (byte)0x49 &&
|
||||
b[2] == (byte)0x2a && b[3] == (byte)0x00) ||
|
||||
(b[0] == (byte)0x4d && b[1] == (byte)0x4d &&
|
||||
b[2] == (byte)0x00 && b[3] == (byte)0x2a));
|
||||
}
|
||||
|
||||
public ImageReader createReaderInstance(Object extension) {
|
||||
return new TIFFImageReader(this);
|
||||
}
|
||||
|
||||
public void onRegistration(ServiceRegistry registry,
|
||||
Class<?> category) {
|
||||
if (registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
registered = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.Locale;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
|
||||
/**
|
||||
* A subclass of {@link ImageWriteParam ImageWriteParam}
|
||||
* allowing control over the TIFF writing process. The set of innately
|
||||
* supported compression types is listed in the following table:
|
||||
*
|
||||
* <table border=1>
|
||||
* <caption><b>Supported Compression Types</b></caption>
|
||||
* <tr><th>Compression Type</th> <th>Description</th> <th>Reference</th></tr>
|
||||
* <tr>
|
||||
* <td>CCITT RLE</td>
|
||||
* <td>Modified Huffman compression</td>
|
||||
* <td>TIFF 6.0 Specification, Section 10</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>CCITT T.4</td>
|
||||
* <td>CCITT T.4 bilevel encoding/Group 3 facsimile compression</td>
|
||||
* <td>TIFF 6.0 Specification, Section 11</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>CCITT T.6</td>
|
||||
* <td>CCITT T.6 bilevel encoding/Group 4 facsimile compression</td>
|
||||
* <td>TIFF 6.0 Specification, Section 11</td></tr>
|
||||
* <tr>
|
||||
* <td>LZW</td>
|
||||
* <td>LZW compression</td>
|
||||
* <td>TIFF 6.0 Specification, Section 13</td></tr>
|
||||
* <tr>
|
||||
* <td>JPEG</td>
|
||||
* <td>"New" JPEG-in-TIFF compression</td>
|
||||
* <td><a href="ftp://ftp.sgi.com/graphics/tiff/TTN2.draft.txt">TIFF
|
||||
* Technical Note #2</a></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>ZLib</td>
|
||||
* <td>"Deflate/Inflate" compression (see note following this table)</td>
|
||||
* <td><a href="http://partners.adobe.com/asn/developer/pdfs/tn/TIFFphotoshop.pdf">
|
||||
* Adobe Photoshop® TIFF Technical Notes</a> (PDF)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>PackBits</td>
|
||||
* <td>Byte-oriented, run length compression</td>
|
||||
* <td>TIFF 6.0 Specification, Section 9</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Deflate</td>
|
||||
* <td>"Zip-in-TIFF" compression (see note following this table)</td>
|
||||
* <td><a href="http://www.isi.edu/in-notes/rfc1950.txt">
|
||||
* ZLIB Compressed Data Format Specification</a>,
|
||||
* <a href="http://www.isi.edu/in-notes/rfc1951.txt">
|
||||
* DEFLATE Compressed Data Format Specification</a></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Exif JPEG</td>
|
||||
* <td>Exif-specific JPEG compression (see note following this table)</td>
|
||||
* <td><a href="http://www.exif.org/Exif2-2.PDF">Exif 2.2 Specification</a>
|
||||
* (PDF), section 4.5.5, "Basic Structure of Thumbnail Data"</td>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* Old-style JPEG compression as described in section 22 of the TIFF 6.0
|
||||
* Specification is <i>not</i> supported.
|
||||
* </p>
|
||||
*
|
||||
* <p> The CCITT compression types are applicable to bilevel (1-bit)
|
||||
* images only. The JPEG compression type is applicable to byte
|
||||
* grayscale (1-band) and RGB (3-band) images only.</p>
|
||||
*
|
||||
* <p>
|
||||
* ZLib and Deflate compression are identical except for the value of the
|
||||
* TIFF Compression field: for ZLib the Compression field has value 8
|
||||
* whereas for Deflate it has value 32946 (0x80b2). In both cases each
|
||||
* image segment (strip or tile) is written as a single complete zlib data
|
||||
* stream.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* "Exif JPEG" is a compression type used when writing the contents of an
|
||||
* APP1 Exif marker segment for inclusion in a JPEG native image metadata
|
||||
* tree. The contents appended to the output when this compression type is
|
||||
* used are a function of whether an empty or non-empty image is written.
|
||||
* If the image is empty, then a TIFF IFD adhering to the specification of
|
||||
* a compressed Exif primary IFD is appended. If the image is non-empty,
|
||||
* then a complete IFD and image adhering to the specification of a
|
||||
* compressed Exif thumbnail IFD and image are appended. Note that the
|
||||
* data of the empty image may <i>not</i> later be appended using the pixel
|
||||
* replacement capability of the TIFF writer.
|
||||
* </p>
|
||||
*
|
||||
* <p> If ZLib/Deflate or JPEG compression is used, the compression quality
|
||||
* may be set. For ZLib/Deflate the supplied floating point quality value is
|
||||
* rescaled to the range <tt>[1, 9]</tt> and truncated to an integer
|
||||
* to derive the Deflate compression level. For JPEG the floating point
|
||||
* quality value is passed directly to the JPEG writer plug-in which
|
||||
* interprets it in the usual way.</p>
|
||||
*
|
||||
* <p> The <code>canWriteTiles</code> and
|
||||
* <code>canWriteCompressed</code> methods will return
|
||||
* <code>true</code>; the <code>canOffsetTiles</code> and
|
||||
* <code>canWriteProgressive</code> methods will return
|
||||
* <code>false</code>.</p>
|
||||
*
|
||||
* <p> If tiles are being written, then each of their dimensions will be
|
||||
* rounded to the nearest multiple of 16 per the TIFF specification. If
|
||||
* JPEG-in-TIFF compression is being used, and tiles are being written
|
||||
* each tile dimension will be rounded to the nearest multiple of 8 times
|
||||
* the JPEG minimum coded unit (MCU) in that dimension. If JPEG-in-TIFF
|
||||
* compression is being used and strips are being written, the number of
|
||||
* rows per strip is rounded to a multiple of 8 times the maximum MCU over
|
||||
* both dimensions.</p>
|
||||
*/
|
||||
public class TIFFImageWriteParam extends ImageWriteParam {
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFImageWriteParam</code> instance
|
||||
* for a given <code>Locale</code>.
|
||||
*
|
||||
* @param locale the <code>Locale</code> for which messages
|
||||
* should be localized.
|
||||
*/
|
||||
public TIFFImageWriteParam(Locale locale) {
|
||||
super(locale);
|
||||
this.canWriteCompressed = true;
|
||||
this.canWriteTiles = true;
|
||||
this.compressionTypes = TIFFImageWriter.TIFFCompressionTypes;
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.Locale;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
|
||||
public class TIFFImageWriterSpi extends ImageWriterSpi {
|
||||
|
||||
private boolean registered = false;
|
||||
|
||||
public TIFFImageWriterSpi() {
|
||||
super("Oracle Corporation",
|
||||
"1.0",
|
||||
new String[] {"tif", "TIF", "tiff", "TIFF"},
|
||||
new String[] {"tif", "tiff"},
|
||||
new String[] {"image/tiff"},
|
||||
"com.sun.imageio.plugins.tiff.TIFFImageWriter",
|
||||
new Class<?>[] {ImageOutputStream.class},
|
||||
new String[] {"com.sun.imageio.plugins.tiff.TIFFImageReaderSpi"},
|
||||
false,
|
||||
TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
"com.sun.imageio.plugins.tiff.TIFFStreamMetadataFormat",
|
||||
null, null,
|
||||
false,
|
||||
TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
"com.sun.imageio.plugins.tiff.TIFFImageMetadataFormat",
|
||||
null, null
|
||||
);
|
||||
}
|
||||
|
||||
public boolean canEncodeImage(ImageTypeSpecifier type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDescription(Locale locale) {
|
||||
return "Standard TIFF image writer";
|
||||
}
|
||||
|
||||
public ImageWriter createWriterInstance(Object extension) {
|
||||
return new TIFFImageWriter(this);
|
||||
}
|
||||
|
||||
public void onRegistration(ServiceRegistry registry,
|
||||
Class<?> category) {
|
||||
if (registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
registered = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
import javax.imageio.plugins.tiff.TIFFTag;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Iterator;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||
|
||||
/**
|
||||
* Compressor for encoding compression type 7, TTN2/Adobe JPEG-in-TIFF.
|
||||
*/
|
||||
public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor {
|
||||
|
||||
// Subsampling factor for chroma bands (Cb Cr).
|
||||
static final int CHROMA_SUBSAMPLING = 2;
|
||||
|
||||
/**
|
||||
* A filter which identifies the ImageReaderSpi of a JPEG reader
|
||||
* which supports JPEG native stream metadata.
|
||||
*/
|
||||
private static class JPEGSPIFilter implements ServiceRegistry.Filter {
|
||||
JPEGSPIFilter() {}
|
||||
|
||||
public boolean filter(Object provider) {
|
||||
ImageReaderSpi readerSPI = (ImageReaderSpi)provider;
|
||||
|
||||
if(readerSPI != null) {
|
||||
String streamMetadataName =
|
||||
readerSPI.getNativeStreamMetadataFormatName();
|
||||
if(streamMetadataName != null) {
|
||||
return streamMetadataName.equals(STREAM_METADATA_NAME);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a JPEG reader which supports native JPEG stream metadata.
|
||||
*/
|
||||
private static ImageReader getJPEGTablesReader() {
|
||||
ImageReader jpegReader = null;
|
||||
|
||||
try {
|
||||
IIORegistry registry = IIORegistry.getDefaultInstance();
|
||||
Class<?> imageReaderClass =
|
||||
Class.forName("javax.imageio.spi.ImageReaderSpi");
|
||||
Iterator<?> readerSPIs =
|
||||
registry.getServiceProviders(imageReaderClass,
|
||||
new JPEGSPIFilter(),
|
||||
true);
|
||||
if(readerSPIs.hasNext()) {
|
||||
ImageReaderSpi jpegReaderSPI =
|
||||
(ImageReaderSpi)readerSPIs.next();
|
||||
jpegReader = jpegReaderSPI.createReaderInstance();
|
||||
}
|
||||
} catch(Exception e) {
|
||||
// Ignore it ...
|
||||
}
|
||||
|
||||
return jpegReader;
|
||||
}
|
||||
|
||||
public TIFFJPEGCompressor(ImageWriteParam param) {
|
||||
super("JPEG", BaselineTIFFTagSet.COMPRESSION_JPEG, false, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <code>metadata</code> field.
|
||||
*
|
||||
* <p>The implementation in this class also adds the TIFF fields
|
||||
* JPEGTables, YCbCrSubSampling, YCbCrPositioning, and
|
||||
* ReferenceBlackWhite superseding any prior settings of those
|
||||
* fields.</p>
|
||||
*
|
||||
* @param metadata the <code>IIOMetadata</code> object for the
|
||||
* image being written.
|
||||
*
|
||||
* @see #getMetadata()
|
||||
*/
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
super.setMetadata(metadata);
|
||||
|
||||
if (metadata instanceof TIFFImageMetadata) {
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
TIFFIFD rootIFD = tim.getRootIFD();
|
||||
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
|
||||
|
||||
TIFFField f =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
|
||||
int numBands = f.getAsInt(0);
|
||||
|
||||
if(numBands == 1) {
|
||||
// Remove YCbCr fields not relevant for grayscale.
|
||||
|
||||
rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
|
||||
rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING);
|
||||
rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
|
||||
} else { // numBands == 3
|
||||
// Replace YCbCr fields.
|
||||
|
||||
// YCbCrSubSampling
|
||||
TIFFField YCbCrSubSamplingField = new TIFFField
|
||||
(base.getTag(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING),
|
||||
TIFFTag.TIFF_SHORT, 2,
|
||||
new char[] {CHROMA_SUBSAMPLING, CHROMA_SUBSAMPLING});
|
||||
rootIFD.addTIFFField(YCbCrSubSamplingField);
|
||||
|
||||
// YCbCrPositioning
|
||||
TIFFField YCbCrPositioningField = new TIFFField
|
||||
(base.getTag(BaselineTIFFTagSet.TAG_Y_CB_CR_POSITIONING),
|
||||
TIFFTag.TIFF_SHORT, 1,
|
||||
new char[]
|
||||
{BaselineTIFFTagSet.Y_CB_CR_POSITIONING_CENTERED});
|
||||
rootIFD.addTIFFField(YCbCrPositioningField);
|
||||
|
||||
// ReferenceBlackWhite
|
||||
TIFFField referenceBlackWhiteField = new TIFFField
|
||||
(base.getTag(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE),
|
||||
TIFFTag.TIFF_RATIONAL, 6,
|
||||
new long[][] { // no headroon/footroom
|
||||
{0, 1}, {255, 1},
|
||||
{128, 1}, {255, 1},
|
||||
{128, 1}, {255, 1}
|
||||
});
|
||||
rootIFD.addTIFFField(referenceBlackWhiteField);
|
||||
}
|
||||
|
||||
// JPEGTables field is written if and only if one is
|
||||
// already present in the metadata. If one is present
|
||||
// and has either zero length or does not represent a
|
||||
// valid tables-only stream, then a JPEGTables field
|
||||
// will be written initialized to the standard tables-
|
||||
// only stream written by the JPEG writer.
|
||||
|
||||
// Retrieve the JPEGTables field.
|
||||
TIFFField JPEGTablesField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
|
||||
|
||||
// Initialize JPEG writer to one supporting abbreviated streams.
|
||||
if(JPEGTablesField != null) {
|
||||
// Intialize the JPEG writer to one that supports stream
|
||||
// metadata, i.e., abbreviated streams, and may or may not
|
||||
// support image metadata.
|
||||
initJPEGWriter(true, false);
|
||||
}
|
||||
|
||||
// Write JPEGTables field if a writer supporting abbreviated
|
||||
// streams was available.
|
||||
if(JPEGTablesField != null && JPEGWriter != null) {
|
||||
// Set the abbreviated stream flag.
|
||||
this.writeAbbreviatedStream = true;
|
||||
|
||||
//Branch based on field value count.
|
||||
if(JPEGTablesField.getCount() > 0) {
|
||||
// Derive the stream metadata from the field.
|
||||
|
||||
// Get the field values.
|
||||
byte[] tables = JPEGTablesField.getAsBytes();
|
||||
|
||||
// Create an input stream for the tables.
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(tables);
|
||||
MemoryCacheImageInputStream iis =
|
||||
new MemoryCacheImageInputStream(bais);
|
||||
|
||||
// Read the tables stream using the JPEG reader.
|
||||
ImageReader jpegReader = getJPEGTablesReader();
|
||||
jpegReader.setInput(iis);
|
||||
|
||||
// Initialize the stream metadata object.
|
||||
try {
|
||||
JPEGStreamMetadata = jpegReader.getStreamMetadata();
|
||||
} catch(Exception e) {
|
||||
// Fall back to default tables.
|
||||
JPEGStreamMetadata = null;
|
||||
} finally {
|
||||
jpegReader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if(JPEGStreamMetadata == null) {
|
||||
// Derive the field from default stream metadata.
|
||||
|
||||
// Get default stream metadata.
|
||||
JPEGStreamMetadata =
|
||||
JPEGWriter.getDefaultStreamMetadata(JPEGParam);
|
||||
|
||||
// Create an output stream for the tables.
|
||||
ByteArrayOutputStream tableByteStream =
|
||||
new ByteArrayOutputStream();
|
||||
MemoryCacheImageOutputStream tableStream =
|
||||
new MemoryCacheImageOutputStream(tableByteStream);
|
||||
|
||||
// Write a tables-only stream.
|
||||
JPEGWriter.setOutput(tableStream);
|
||||
try {
|
||||
JPEGWriter.prepareWriteSequence(JPEGStreamMetadata);
|
||||
tableStream.flush();
|
||||
JPEGWriter.endWriteSequence();
|
||||
|
||||
// Get the tables-only stream content.
|
||||
byte[] tables = tableByteStream.toByteArray();
|
||||
|
||||
// Add the JPEGTables field.
|
||||
JPEGTablesField = new TIFFField
|
||||
(base.getTag(BaselineTIFFTagSet.TAG_JPEG_TABLES),
|
||||
TIFFTag.TIFF_UNDEFINED,
|
||||
tables.length,
|
||||
tables);
|
||||
rootIFD.addTIFFField(JPEGTablesField);
|
||||
} catch(Exception e) {
|
||||
// Do not write JPEGTables field.
|
||||
rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
|
||||
this.writeAbbreviatedStream = false;
|
||||
}
|
||||
}
|
||||
} else { // Do not write JPEGTables field.
|
||||
// Remove any field present.
|
||||
rootIFD.removeTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
|
||||
|
||||
// Initialize the writer preferring codecLib.
|
||||
initJPEGWriter(false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Iterator;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
|
||||
public class TIFFJPEGDecompressor extends TIFFDecompressor {
|
||||
// Start of Image
|
||||
protected static final int SOI = 0xD8;
|
||||
|
||||
// End of Image
|
||||
protected static final int EOI = 0xD9;
|
||||
|
||||
protected ImageReader JPEGReader = null;
|
||||
protected ImageReadParam JPEGParam;
|
||||
|
||||
protected boolean hasJPEGTables = false;
|
||||
protected byte[] tables = null;
|
||||
|
||||
private byte[] data = new byte[0];
|
||||
|
||||
public TIFFJPEGDecompressor() {}
|
||||
|
||||
public void beginDecoding() {
|
||||
// Initialize the JPEG reader if needed.
|
||||
if(this.JPEGReader == null) {
|
||||
// Get all JPEG readers.
|
||||
Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("jpeg");
|
||||
|
||||
if(!iter.hasNext()) {
|
||||
throw new IllegalStateException("No JPEG readers found!");
|
||||
}
|
||||
|
||||
// Initialize reader to the first one.
|
||||
this.JPEGReader = iter.next();
|
||||
|
||||
this.JPEGParam = JPEGReader.getDefaultReadParam();
|
||||
}
|
||||
|
||||
// Get the JPEGTables field.
|
||||
TIFFImageMetadata tmetadata = (TIFFImageMetadata)metadata;
|
||||
TIFFField f =
|
||||
tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_TABLES);
|
||||
|
||||
if (f != null) {
|
||||
this.hasJPEGTables = true;
|
||||
this.tables = f.getAsBytes();
|
||||
} else {
|
||||
this.hasJPEGTables = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
// Seek to the data position for this segment.
|
||||
stream.seek(offset);
|
||||
|
||||
// Set the stream variable depending on presence of JPEGTables.
|
||||
ImageInputStream is;
|
||||
if(this.hasJPEGTables) {
|
||||
// The current strip or tile is an abbreviated JPEG stream.
|
||||
|
||||
// Reallocate memory if there is not enough already.
|
||||
int dataLength = tables.length + byteCount;
|
||||
if(data.length < dataLength) {
|
||||
data = new byte[dataLength];
|
||||
}
|
||||
|
||||
// Copy the tables ignoring any EOI and subsequent bytes.
|
||||
int dataOffset = tables.length;
|
||||
for(int i = tables.length - 2; i > 0; i--) {
|
||||
if((tables[i] & 0xff) == 0xff &&
|
||||
(tables[i+1] & 0xff) == EOI) {
|
||||
dataOffset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.arraycopy(tables, 0, data, 0, dataOffset);
|
||||
|
||||
// Check for SOI and skip it if present.
|
||||
byte byte1 = (byte)stream.read();
|
||||
byte byte2 = (byte)stream.read();
|
||||
if(!((byte1 & 0xff) == 0xff && (byte2 & 0xff) == SOI)) {
|
||||
data[dataOffset++] = byte1;
|
||||
data[dataOffset++] = byte2;
|
||||
}
|
||||
|
||||
// Read remaining data.
|
||||
stream.readFully(data, dataOffset, byteCount - 2);
|
||||
|
||||
// Create ImageInputStream.
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
is = new MemoryCacheImageInputStream(bais);
|
||||
} else {
|
||||
// The current strip or tile is a complete JPEG stream.
|
||||
is = stream;
|
||||
}
|
||||
|
||||
// Set the stream on the reader.
|
||||
JPEGReader.setInput(is, false, true);
|
||||
|
||||
// Set the destination to the raw image ignoring the parameters.
|
||||
JPEGParam.setDestination(rawImage);
|
||||
|
||||
// Read the strip or tile.
|
||||
JPEGReader.read(0, JPEGParam);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
JPEGReader.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Uncompressed data with LSB-to-MSB fill order.
|
||||
*/
|
||||
public class TIFFLSBCompressor extends TIFFCompressor {
|
||||
|
||||
public TIFFLSBCompressor() {
|
||||
super("", BaselineTIFFTagSet.COMPRESSION_NONE, true);
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
int bitsPerPixel = 0;
|
||||
for (int i = 0; i < bitsPerSample.length; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
int bytesPerRow = (bitsPerPixel*width + 7)/8;
|
||||
byte[] compData = new byte[bytesPerRow];
|
||||
byte[] flipTable = TIFFFaxDecompressor.flipTable;
|
||||
for (int row = 0; row < height; row++) {
|
||||
System.arraycopy(b, off, compData, 0, bytesPerRow);
|
||||
for(int j = 0; j < bytesPerRow; j++) {
|
||||
compData[j] = flipTable[compData[j]&0xff];
|
||||
}
|
||||
stream.write(compData, 0, bytesPerRow);
|
||||
off += scanlineStride;
|
||||
}
|
||||
return height*bytesPerRow;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFLSBDecompressor extends TIFFDecompressor {
|
||||
|
||||
/**
|
||||
* Table for flipping bytes from LSB-to-MSB to MSB-to-LSB.
|
||||
*/
|
||||
private static final byte[] flipTable = TIFFFaxDecompressor.flipTable;
|
||||
|
||||
public TIFFLSBDecompressor() {}
|
||||
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
stream.seek(offset);
|
||||
|
||||
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
int numBytes = bytesPerRow*srcHeight;
|
||||
stream.readFully(b, dstOffset, numBytes);
|
||||
int xMax = dstOffset + numBytes;
|
||||
for (int x = dstOffset; x < xMax; x++) {
|
||||
b[x] = flipTable[b[x]&0xff];
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < srcHeight; y++) {
|
||||
stream.readFully(b, dstOffset, bytesPerRow);
|
||||
int xMax = dstOffset + bytesPerRow;
|
||||
for (int x = dstOffset; x < xMax; x++) {
|
||||
b[x] = flipTable[b[x]&0xff];
|
||||
}
|
||||
dstOffset += scanlineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import com.sun.imageio.plugins.common.LZWCompressor;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
|
||||
/**
|
||||
* LZW Compressor.
|
||||
*/
|
||||
public class TIFFLZWCompressor extends TIFFCompressor {
|
||||
|
||||
private final int predictor;
|
||||
|
||||
public TIFFLZWCompressor(int predictorValue) {
|
||||
super("LZW", BaselineTIFFTagSet.COMPRESSION_LZW, true);
|
||||
this.predictor = predictorValue;
|
||||
}
|
||||
|
||||
public void setStream(ImageOutputStream stream) {
|
||||
super.setStream(stream);
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
|
||||
LZWCompressor lzwCompressor = new LZWCompressor(stream, 8, true);
|
||||
|
||||
int samplesPerPixel = bitsPerSample.length;
|
||||
int bitsPerPixel = 0;
|
||||
for (int i = 0; i < samplesPerPixel; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
int bytesPerRow = (bitsPerPixel*width + 7)/8;
|
||||
|
||||
long initialStreamPosition = stream.getStreamPosition();
|
||||
|
||||
boolean usePredictor =
|
||||
predictor == BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING;
|
||||
|
||||
if(bytesPerRow == scanlineStride && !usePredictor) {
|
||||
lzwCompressor.compress(b, off, bytesPerRow*height);
|
||||
} else {
|
||||
byte[] rowBuf = usePredictor ? new byte[bytesPerRow] : null;
|
||||
for(int i = 0; i < height; i++) {
|
||||
if(usePredictor) {
|
||||
// Cannot modify b[] in place as it might be a data
|
||||
// array from the image being written so make a copy.
|
||||
System.arraycopy(b, off, rowBuf, 0, bytesPerRow);
|
||||
for(int j = bytesPerRow - 1; j >= samplesPerPixel; j--) {
|
||||
rowBuf[j] -= rowBuf[j - samplesPerPixel];
|
||||
}
|
||||
lzwCompressor.compress(rowBuf, 0, bytesPerRow);
|
||||
} else {
|
||||
lzwCompressor.compress(b, off, bytesPerRow);
|
||||
}
|
||||
off += scanlineStride;
|
||||
}
|
||||
}
|
||||
|
||||
lzwCompressor.flush();
|
||||
|
||||
int bytesWritten =
|
||||
(int)(stream.getStreamPosition() - initialStreamPosition);
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
}
|
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
|
||||
class TIFFLZWDecompressor extends TIFFDecompressor {
|
||||
|
||||
private static final int andTable[] = {
|
||||
511,
|
||||
1023,
|
||||
2047,
|
||||
4095
|
||||
};
|
||||
|
||||
private int predictor;
|
||||
|
||||
private byte[] srcData;
|
||||
private byte[] dstData;
|
||||
|
||||
private int srcIndex;
|
||||
private int dstIndex;
|
||||
|
||||
private byte stringTable[][];
|
||||
private int tableIndex, bitsToGet = 9;
|
||||
|
||||
private int nextData = 0;
|
||||
private int nextBits = 0;
|
||||
|
||||
public TIFFLZWDecompressor(int predictor) throws IIOException {
|
||||
super();
|
||||
|
||||
if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
|
||||
predictor !=
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
throw new IIOException("Illegal value for Predictor in " +
|
||||
"TIFF file");
|
||||
}
|
||||
|
||||
this.predictor = predictor;
|
||||
}
|
||||
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
|
||||
// Check bitsPerSample.
|
||||
if (predictor ==
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
int len = bitsPerSample.length;
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(bitsPerSample[i] != 8) {
|
||||
throw new IIOException
|
||||
(bitsPerSample[i] + "-bit samples "+
|
||||
"are not supported for Horizontal "+
|
||||
"differencing Predictor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream.seek(offset);
|
||||
|
||||
byte[] sdata = new byte[byteCount];
|
||||
stream.readFully(sdata);
|
||||
|
||||
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
|
||||
byte[] buf;
|
||||
int bufOffset;
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
buf = b;
|
||||
bufOffset = dstOffset;
|
||||
} else {
|
||||
buf = new byte[bytesPerRow*srcHeight];
|
||||
bufOffset = 0;
|
||||
}
|
||||
|
||||
int numBytesDecoded = decode(sdata, 0, buf, bufOffset);
|
||||
|
||||
if(bytesPerRow != scanlineStride) {
|
||||
int off = 0;
|
||||
for (int y = 0; y < srcHeight; y++) {
|
||||
System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
|
||||
off += bytesPerRow;
|
||||
dstOffset += scanlineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int decode(byte[] sdata, int srcOffset,
|
||||
byte[] ddata, int dstOffset)
|
||||
throws IOException {
|
||||
if (sdata[0] == (byte)0x00 && sdata[1] == (byte)0x01) {
|
||||
throw new IIOException
|
||||
("TIFF 5.0-style LZW compression is not supported!");
|
||||
}
|
||||
|
||||
this.srcData = sdata;
|
||||
this.dstData = ddata;
|
||||
|
||||
this.srcIndex = srcOffset;
|
||||
this.dstIndex = dstOffset;
|
||||
|
||||
this.nextData = 0;
|
||||
this.nextBits = 0;
|
||||
|
||||
initializeStringTable();
|
||||
|
||||
int code, oldCode = 0;
|
||||
byte[] string;
|
||||
|
||||
while ((code = getNextCode()) != 257) {
|
||||
if (code == 256) {
|
||||
initializeStringTable();
|
||||
code = getNextCode();
|
||||
if (code == 257) {
|
||||
break;
|
||||
}
|
||||
|
||||
writeString(stringTable[code]);
|
||||
oldCode = code;
|
||||
} else {
|
||||
if (code < tableIndex) {
|
||||
string = stringTable[code];
|
||||
|
||||
writeString(string);
|
||||
addStringToTable(stringTable[oldCode], string[0]);
|
||||
oldCode = code;
|
||||
} else {
|
||||
string = stringTable[oldCode];
|
||||
string = composeString(string, string[0]);
|
||||
writeString(string);
|
||||
addStringToTable(string);
|
||||
oldCode = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (predictor ==
|
||||
BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
|
||||
|
||||
for (int j = 0; j < srcHeight; j++) {
|
||||
|
||||
int count = dstOffset + samplesPerPixel * (j * srcWidth + 1);
|
||||
|
||||
for (int i = samplesPerPixel; i < srcWidth * samplesPerPixel; i++) {
|
||||
|
||||
dstData[count] += dstData[count - samplesPerPixel];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dstIndex - dstOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the string table.
|
||||
*/
|
||||
public void initializeStringTable() {
|
||||
stringTable = new byte[4096][];
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
stringTable[i] = new byte[1];
|
||||
stringTable[i][0] = (byte)i;
|
||||
}
|
||||
|
||||
tableIndex = 258;
|
||||
bitsToGet = 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the string just uncompressed.
|
||||
*/
|
||||
public void writeString(byte string[]) {
|
||||
if(dstIndex < dstData.length) {
|
||||
int maxIndex = Math.min(string.length,
|
||||
dstData.length - dstIndex);
|
||||
|
||||
for (int i=0; i < maxIndex; i++) {
|
||||
dstData[dstIndex++] = string[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new string to the string table.
|
||||
*/
|
||||
public void addStringToTable(byte oldString[], byte newString) {
|
||||
int length = oldString.length;
|
||||
byte string[] = new byte[length + 1];
|
||||
System.arraycopy(oldString, 0, string, 0, length);
|
||||
string[length] = newString;
|
||||
|
||||
// Add this new String to the table
|
||||
stringTable[tableIndex++] = string;
|
||||
|
||||
if (tableIndex == 511) {
|
||||
bitsToGet = 10;
|
||||
} else if (tableIndex == 1023) {
|
||||
bitsToGet = 11;
|
||||
} else if (tableIndex == 2047) {
|
||||
bitsToGet = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new string to the string table.
|
||||
*/
|
||||
public void addStringToTable(byte string[]) {
|
||||
// Add this new String to the table
|
||||
stringTable[tableIndex++] = string;
|
||||
|
||||
if (tableIndex == 511) {
|
||||
bitsToGet = 10;
|
||||
} else if (tableIndex == 1023) {
|
||||
bitsToGet = 11;
|
||||
} else if (tableIndex == 2047) {
|
||||
bitsToGet = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append <code>newString</code> to the end of <code>oldString</code>.
|
||||
*/
|
||||
public byte[] composeString(byte oldString[], byte newString) {
|
||||
int length = oldString.length;
|
||||
byte string[] = new byte[length + 1];
|
||||
System.arraycopy(oldString, 0, string, 0, length);
|
||||
string[length] = newString;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
// Returns the next 9, 10, 11 or 12 bits
|
||||
public int getNextCode() {
|
||||
// Attempt to get the next code. The exception is caught to make
|
||||
// this robust to cases wherein the EndOfInformation code has been
|
||||
// omitted from a strip. Examples of such cases have been observed
|
||||
// in practice.
|
||||
|
||||
try {
|
||||
nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
|
||||
nextBits += 8;
|
||||
|
||||
if (nextBits < bitsToGet) {
|
||||
nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
|
||||
nextBits += 8;
|
||||
}
|
||||
|
||||
int code =
|
||||
(nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9];
|
||||
nextBits -= bitsToGet;
|
||||
|
||||
return code;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
// Strip not terminated as expected: return EndOfInformation code.
|
||||
return 257;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
class TIFFLZWUtil {
|
||||
public TIFFLZWUtil() {
|
||||
}
|
||||
|
||||
byte[] srcData;
|
||||
int srcIndex;
|
||||
|
||||
byte[] dstData;
|
||||
int dstIndex = 0;
|
||||
|
||||
byte stringTable[][];
|
||||
int tableIndex, bitsToGet = 9;
|
||||
|
||||
int nextData = 0;
|
||||
int nextBits = 0;
|
||||
|
||||
private static final int andTable[] = {
|
||||
511,
|
||||
1023,
|
||||
2047,
|
||||
4095
|
||||
};
|
||||
|
||||
public byte[] decode(byte[] data, int predictor, int samplesPerPixel,
|
||||
int width, int height) throws IOException {
|
||||
if (data[0] == (byte)0x00 && data[1] == (byte)0x01) {
|
||||
throw new IIOException("TIFF 5.0-style LZW compression is not supported!");
|
||||
}
|
||||
|
||||
this.srcData = data;
|
||||
this.srcIndex = 0;
|
||||
this.nextData = 0;
|
||||
this.nextBits = 0;
|
||||
|
||||
this.dstData = new byte[8192];
|
||||
this.dstIndex = 0;
|
||||
|
||||
initializeStringTable();
|
||||
|
||||
int code, oldCode = 0;
|
||||
byte[] string;
|
||||
|
||||
while ((code = getNextCode()) != 257) {
|
||||
if (code == 256) {
|
||||
initializeStringTable();
|
||||
code = getNextCode();
|
||||
if (code == 257) {
|
||||
break;
|
||||
}
|
||||
|
||||
writeString(stringTable[code]);
|
||||
oldCode = code;
|
||||
} else {
|
||||
if (code < tableIndex) {
|
||||
string = stringTable[code];
|
||||
|
||||
writeString(string);
|
||||
addStringToTable(stringTable[oldCode], string[0]);
|
||||
oldCode = code;
|
||||
} else {
|
||||
string = stringTable[oldCode];
|
||||
string = composeString(string, string[0]);
|
||||
writeString(string);
|
||||
addStringToTable(string);
|
||||
oldCode = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (predictor == 2) {
|
||||
|
||||
int count;
|
||||
for (int j = 0; j < height; j++) {
|
||||
|
||||
count = samplesPerPixel * (j * width + 1);
|
||||
|
||||
for (int i = samplesPerPixel; i < width * samplesPerPixel; i++) {
|
||||
|
||||
dstData[count] += dstData[count - samplesPerPixel];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] newDstData = new byte[dstIndex];
|
||||
System.arraycopy(dstData, 0, newDstData, 0, dstIndex);
|
||||
return newDstData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the string table.
|
||||
*/
|
||||
public void initializeStringTable() {
|
||||
stringTable = new byte[4096][];
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
stringTable[i] = new byte[1];
|
||||
stringTable[i][0] = (byte)i;
|
||||
}
|
||||
|
||||
tableIndex = 258;
|
||||
bitsToGet = 9;
|
||||
}
|
||||
|
||||
private void ensureCapacity(int bytesToAdd) {
|
||||
if (dstIndex + bytesToAdd > dstData.length) {
|
||||
byte[] newDstData = new byte[Math.max((int)(dstData.length*1.2f),
|
||||
dstIndex + bytesToAdd)];
|
||||
System.arraycopy(dstData, 0, newDstData, 0, dstData.length);
|
||||
dstData = newDstData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the string just uncompressed.
|
||||
*/
|
||||
public void writeString(byte string[]) {
|
||||
ensureCapacity(string.length);
|
||||
for (int i = 0; i < string.length; i++) {
|
||||
dstData[dstIndex++] = string[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new string to the string table.
|
||||
*/
|
||||
public void addStringToTable(byte oldString[], byte newString) {
|
||||
int length = oldString.length;
|
||||
byte string[] = new byte[length + 1];
|
||||
System.arraycopy(oldString, 0, string, 0, length);
|
||||
string[length] = newString;
|
||||
|
||||
// Add this new String to the table
|
||||
stringTable[tableIndex++] = string;
|
||||
|
||||
if (tableIndex == 511) {
|
||||
bitsToGet = 10;
|
||||
} else if (tableIndex == 1023) {
|
||||
bitsToGet = 11;
|
||||
} else if (tableIndex == 2047) {
|
||||
bitsToGet = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new string to the string table.
|
||||
*/
|
||||
public void addStringToTable(byte string[]) {
|
||||
// Add this new String to the table
|
||||
stringTable[tableIndex++] = string;
|
||||
|
||||
if (tableIndex == 511) {
|
||||
bitsToGet = 10;
|
||||
} else if (tableIndex == 1023) {
|
||||
bitsToGet = 11;
|
||||
} else if (tableIndex == 2047) {
|
||||
bitsToGet = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append <code>newString</code> to the end of <code>oldString</code>.
|
||||
*/
|
||||
public byte[] composeString(byte oldString[], byte newString) {
|
||||
int length = oldString.length;
|
||||
byte string[] = new byte[length + 1];
|
||||
System.arraycopy(oldString, 0, string, 0, length);
|
||||
string[length] = newString;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
// Returns the next 9, 10, 11 or 12 bits
|
||||
public int getNextCode() {
|
||||
// Attempt to get the next code. The exception is caught to make
|
||||
// this robust to cases wherein the EndOfInformation code has been
|
||||
// omitted from a strip. Examples of such cases have been observed
|
||||
// in practice.
|
||||
|
||||
try {
|
||||
nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
|
||||
nextBits += 8;
|
||||
|
||||
if (nextBits < bitsToGet) {
|
||||
nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
|
||||
nextBits += 8;
|
||||
}
|
||||
|
||||
int code =
|
||||
(nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9];
|
||||
nextBits -= bitsToGet;
|
||||
|
||||
return code;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
// Strip not terminated as expected: return EndOfInformation code.
|
||||
return 257;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
|
||||
public abstract class TIFFMetadataFormat implements IIOMetadataFormat {
|
||||
|
||||
protected Map<String,TIFFElementInfo> elementInfoMap = new HashMap<String,TIFFElementInfo>();
|
||||
protected Map<String,TIFFAttrInfo> attrInfoMap = new HashMap<String,TIFFAttrInfo>();
|
||||
|
||||
protected String resourceBaseName;
|
||||
protected String rootName;
|
||||
|
||||
public String getRootName() {
|
||||
return rootName;
|
||||
}
|
||||
|
||||
private String getResource(String key, Locale locale) {
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
try {
|
||||
ResourceBundle bundle =
|
||||
ResourceBundle.getBundle(resourceBaseName, locale);
|
||||
return bundle.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TIFFElementInfo getElementInfo(String elementName) {
|
||||
if (elementName == null) {
|
||||
throw new NullPointerException("elementName == null!");
|
||||
}
|
||||
TIFFElementInfo info =
|
||||
elementInfoMap.get(elementName);
|
||||
if (info == null) {
|
||||
throw new IllegalArgumentException("No such element: " +
|
||||
elementName);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private TIFFAttrInfo getAttrInfo(String elementName, String attrName) {
|
||||
if (elementName == null) {
|
||||
throw new NullPointerException("elementName == null!");
|
||||
}
|
||||
if (attrName == null) {
|
||||
throw new NullPointerException("attrName == null!");
|
||||
}
|
||||
String key = elementName + "/" + attrName;
|
||||
TIFFAttrInfo info = attrInfoMap.get(key);
|
||||
if (info == null) {
|
||||
throw new IllegalArgumentException("No such attribute: " + key);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public int getElementMinChildren(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.minChildren;
|
||||
}
|
||||
|
||||
public int getElementMaxChildren(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.maxChildren;
|
||||
}
|
||||
|
||||
public String getElementDescription(String elementName, Locale locale) {
|
||||
if (!elementInfoMap.containsKey(elementName)) {
|
||||
throw new IllegalArgumentException("No such element: " +
|
||||
elementName);
|
||||
}
|
||||
return getResource(elementName, locale);
|
||||
}
|
||||
|
||||
public int getChildPolicy(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.childPolicy;
|
||||
}
|
||||
|
||||
public String[] getChildNames(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.childNames;
|
||||
}
|
||||
|
||||
public String[] getAttributeNames(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.attributeNames;
|
||||
}
|
||||
|
||||
public int getAttributeValueType(String elementName, String attrName) {
|
||||
TIFFAttrInfo info = getAttrInfo(elementName, attrName);
|
||||
return info.valueType;
|
||||
}
|
||||
|
||||
public int getAttributeDataType(String elementName, String attrName) {
|
||||
TIFFAttrInfo info = getAttrInfo(elementName, attrName);
|
||||
return info.dataType;
|
||||
}
|
||||
|
||||
public boolean isAttributeRequired(String elementName, String attrName) {
|
||||
TIFFAttrInfo info = getAttrInfo(elementName, attrName);
|
||||
return info.isRequired;
|
||||
}
|
||||
|
||||
public String getAttributeDefaultValue(String elementName,
|
||||
String attrName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getAttributeEnumerations(String elementName,
|
||||
String attrName) {
|
||||
throw new IllegalArgumentException("The attribute is not an enumeration.");
|
||||
}
|
||||
|
||||
public String getAttributeMinValue(String elementName, String attrName) {
|
||||
throw new IllegalArgumentException("The attribute is not a range.");
|
||||
}
|
||||
|
||||
public String getAttributeMaxValue(String elementName, String attrName) {
|
||||
throw new IllegalArgumentException("The attribute is not a range.");
|
||||
}
|
||||
|
||||
public int getAttributeListMinLength(String elementName, String attrName) {
|
||||
TIFFAttrInfo info = getAttrInfo(elementName, attrName);
|
||||
return info.listMinLength;
|
||||
}
|
||||
|
||||
public int getAttributeListMaxLength(String elementName, String attrName) {
|
||||
TIFFAttrInfo info = getAttrInfo(elementName, attrName);
|
||||
return info.listMaxLength;
|
||||
}
|
||||
|
||||
public String getAttributeDescription(String elementName, String attrName,
|
||||
Locale locale) {
|
||||
String key = elementName + "/" + attrName;
|
||||
if (!attrInfoMap.containsKey(key)) {
|
||||
throw new IllegalArgumentException("No such attribute: " + key);
|
||||
}
|
||||
return getResource(key, locale);
|
||||
}
|
||||
|
||||
public int getObjectValueType(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
return info.objectValueType;
|
||||
}
|
||||
|
||||
public Class<?> getObjectClass(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectClass;
|
||||
}
|
||||
|
||||
public Object getObjectDefaultValue(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectDefaultValue;
|
||||
}
|
||||
|
||||
public Object[] getObjectEnumerations(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectEnumerations;
|
||||
}
|
||||
|
||||
public Comparable<Object> getObjectMinValue(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectMinValue;
|
||||
}
|
||||
|
||||
public Comparable<Object> getObjectMaxValue(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectMaxValue;
|
||||
}
|
||||
|
||||
public int getObjectArrayMinLength(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectArrayMinLength;
|
||||
}
|
||||
|
||||
public int getObjectArrayMaxLength(String elementName) {
|
||||
TIFFElementInfo info = getElementInfo(elementName);
|
||||
if (info.objectValueType == VALUE_NONE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element cannot contain an object value: " + elementName);
|
||||
}
|
||||
return info.objectArrayMaxLength;
|
||||
}
|
||||
|
||||
public TIFFMetadataFormat() {}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFNullCompressor extends TIFFCompressor {
|
||||
|
||||
public TIFFNullCompressor() {
|
||||
super("", BaselineTIFFTagSet.COMPRESSION_NONE, true);
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
int bitsPerPixel = 0;
|
||||
for (int i = 0; i < bitsPerSample.length; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
|
||||
int bytesPerRow = (bitsPerPixel*width + 7)/8;
|
||||
int numBytes = height*bytesPerRow;
|
||||
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
stream.write(b, off, numBytes);
|
||||
} else {
|
||||
for (int row = 0; row < height; row++) {
|
||||
stream.write(b, off, bytesPerRow);
|
||||
off += scanlineStride;
|
||||
}
|
||||
}
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFNullDecompressor extends TIFFDecompressor {
|
||||
|
||||
/**
|
||||
* Whether to read the active source region only.
|
||||
*/
|
||||
private boolean isReadActiveOnly = false;
|
||||
|
||||
/** The original value of <code>srcMinX</code>. */
|
||||
private int originalSrcMinX;
|
||||
|
||||
/** The original value of <code>srcMinY</code>. */
|
||||
private int originalSrcMinY;
|
||||
|
||||
/** The original value of <code>srcWidth</code>. */
|
||||
private int originalSrcWidth;
|
||||
|
||||
/** The original value of <code>srcHeight</code>. */
|
||||
private int originalSrcHeight;
|
||||
|
||||
public TIFFNullDecompressor() {}
|
||||
|
||||
//
|
||||
// This approach to reading the active region is a not the best
|
||||
// as the original values of the entire source region are stored,
|
||||
// overwritten, and then restored. It would probably be better to
|
||||
// revise TIFFDecompressor such that this were not necessary, i.e.,
|
||||
// change beginDecoding() and decode() to use the active region values
|
||||
// when random access is easy and the entire region values otherwise.
|
||||
//
|
||||
public void beginDecoding() {
|
||||
// Determine number of bits per pixel.
|
||||
int bitsPerPixel = 0;
|
||||
for(int i = 0; i < bitsPerSample.length; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
|
||||
// Can read active region only if row starts on a byte boundary.
|
||||
if((activeSrcMinX != srcMinX || activeSrcMinY != srcMinY ||
|
||||
activeSrcWidth != srcWidth || activeSrcHeight != srcHeight) &&
|
||||
((activeSrcMinX - srcMinX)*bitsPerPixel) % 8 == 0) {
|
||||
// Set flag.
|
||||
isReadActiveOnly = true;
|
||||
|
||||
// Cache original region.
|
||||
originalSrcMinX = srcMinX;
|
||||
originalSrcMinY = srcMinY;
|
||||
originalSrcWidth = srcWidth;
|
||||
originalSrcHeight = srcHeight;
|
||||
|
||||
// Replace region with active region.
|
||||
srcMinX = activeSrcMinX;
|
||||
srcMinY = activeSrcMinY;
|
||||
srcWidth = activeSrcWidth;
|
||||
srcHeight = activeSrcHeight;
|
||||
} else {
|
||||
// Clear flag.
|
||||
isReadActiveOnly = false;
|
||||
}
|
||||
|
||||
super.beginDecoding();
|
||||
}
|
||||
|
||||
public void decode() throws IOException {
|
||||
super.decode();
|
||||
|
||||
// Reset state.
|
||||
if(isReadActiveOnly) {
|
||||
// Restore original source region values.
|
||||
srcMinX = originalSrcMinX;
|
||||
srcMinY = originalSrcMinY;
|
||||
srcWidth = originalSrcWidth;
|
||||
srcHeight = originalSrcHeight;
|
||||
|
||||
// Unset flag.
|
||||
isReadActiveOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
if(isReadActiveOnly) {
|
||||
// Read the active source region only.
|
||||
|
||||
int activeBytesPerRow = (activeSrcWidth*bitsPerPixel + 7)/8;
|
||||
int totalBytesPerRow = (originalSrcWidth*bitsPerPixel + 7)/8;
|
||||
int bytesToSkipPerRow = totalBytesPerRow - activeBytesPerRow;
|
||||
|
||||
//
|
||||
// Seek to the start of the active region:
|
||||
//
|
||||
// active offset = original offset +
|
||||
// number of bytes to start of first active row +
|
||||
// number of bytes to first active pixel within row
|
||||
//
|
||||
// Since the condition for reading from the active region only is
|
||||
//
|
||||
// ((activeSrcMinX - srcMinX)*bitsPerPixel) % 8 == 0
|
||||
//
|
||||
// the bit offset to the first active pixel within the first
|
||||
// active row is a multiple of 8.
|
||||
//
|
||||
stream.seek(offset +
|
||||
(activeSrcMinY - originalSrcMinY)*totalBytesPerRow +
|
||||
((activeSrcMinX - originalSrcMinX)*bitsPerPixel)/8);
|
||||
|
||||
int lastRow = activeSrcHeight - 1;
|
||||
for (int y = 0; y < activeSrcHeight; y++) {
|
||||
int bytesRead = stream.read(b, dstOffset, activeBytesPerRow);
|
||||
if (bytesRead < 0) {
|
||||
throw new EOFException();
|
||||
} else if (bytesRead != activeBytesPerRow) {
|
||||
break;
|
||||
}
|
||||
dstOffset += scanlineStride;
|
||||
|
||||
// Skip unneeded bytes (row suffix + row prefix).
|
||||
if(y != lastRow) {
|
||||
stream.skipBytes(bytesToSkipPerRow);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Read the entire source region.
|
||||
stream.seek(offset);
|
||||
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
if (stream.read(b, dstOffset, bytesPerRow*srcHeight) < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < srcHeight; y++) {
|
||||
int bytesRead = stream.read(b, dstOffset, bytesPerRow);
|
||||
if (bytesRead < 0) {
|
||||
throw new EOFException();
|
||||
} else if (bytesRead != bytesPerRow) {
|
||||
break;
|
||||
}
|
||||
dstOffset += scanlineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
|
||||
/**
|
||||
* <code>TIFFDecompressor</code> for "Old JPEG" compression.
|
||||
*/
|
||||
public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor {
|
||||
|
||||
// Define Huffman Tables
|
||||
private static final int DHT = 0xC4;
|
||||
|
||||
// Define Quantisation Tables
|
||||
private static final int DQT = 0xDB;
|
||||
|
||||
// Define Restart Interval
|
||||
private static final int DRI = 0xDD;
|
||||
|
||||
// Baseline DCT
|
||||
private static final int SOF0 = 0xC0;
|
||||
|
||||
// Start of Scan
|
||||
private static final int SOS = 0xDA;
|
||||
|
||||
// End of Image
|
||||
// private static final int EOI = 0xD9; // now defined in superclass
|
||||
|
||||
// Whether the decompressor has been initialized.
|
||||
private boolean isInitialized = false;
|
||||
|
||||
//
|
||||
// Instance variables set by the initialize() method.
|
||||
//
|
||||
// Offset to a complete, contiguous JPEG stream.
|
||||
private Long JPEGStreamOffset = null;
|
||||
// Offset to the SOF marker.
|
||||
private int SOFPosition = -1;
|
||||
// Value of the SOS marker.
|
||||
private byte[] SOSMarker = null;
|
||||
|
||||
// Horizontal chroma subsampling factor.
|
||||
private int subsamplingX = 2;
|
||||
|
||||
// Vertical chroma subsampling factor.
|
||||
private int subsamplingY = 2;
|
||||
|
||||
public TIFFOldJPEGDecompressor() {}
|
||||
|
||||
//
|
||||
// Intialize instance variables according to an analysis of the
|
||||
// TIFF field content. See bug 4929147 for test image information.
|
||||
//
|
||||
// Case 1: Image contains a single strip or tile and the offset to
|
||||
// that strip or tile points to an SOI marker.
|
||||
//
|
||||
// Example:
|
||||
// "Visionshape Inc. Compression Software, version 2.5"
|
||||
// ColorTiffWithBarcode.tif
|
||||
// Color2.tif (pages 2-5 (indexes 1-4)
|
||||
// color3.tif (pages 2-5 (indexes 1-4)
|
||||
//
|
||||
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
|
||||
// 01.tif (pages 1 and 3(indexes 0 and 2))
|
||||
//
|
||||
// Instance variables set: JPEGStreamOffset
|
||||
//
|
||||
// Case 2: Image contains a single strip or tile and a
|
||||
// JPEGInterchangeFormat field is present but the
|
||||
// JPEGInterchangeFormatLength is erroneously missing.
|
||||
//
|
||||
// Example:
|
||||
// "Kofax standard Multi-Page TIFF Storage Filter v2.01.000"
|
||||
// 01.tif (pages 1 and 3(indexes 0 and 2))
|
||||
// (but this example also satisfies case 1)
|
||||
//
|
||||
// Instance variables set: JPEGStreamOffset
|
||||
//
|
||||
// Case 3: Image contains a single strip or tile, the
|
||||
// JPEGInterchangeFormat and JPEGInterchangeFormatLength
|
||||
// fields are both present, the value of JPEGInterchangeFormat
|
||||
// is less than the offset to the strip or tile, and the sum
|
||||
// of the values of JPEGInterchangeFormat and
|
||||
// JPEGInterchangeFormatLength is greater than the offset to
|
||||
// the strip or tile.
|
||||
//
|
||||
// Instance variables set: JPEGStreamOffset
|
||||
//
|
||||
// Example:
|
||||
// "HP IL v1.1"
|
||||
// smallliz.tif from libtiff test data.
|
||||
//
|
||||
// Instance variables set: JPEGStreamOffset
|
||||
//
|
||||
// Cases 4-5 apply if none of cases 1-3 applies or the image has multiple
|
||||
// strips or tiles.
|
||||
//
|
||||
// Case 4: JPEGInterchangeFormat and JPEGInterchangeFormatLength are
|
||||
// present, the value of JPEGInterchangeFormatLength is at least 2,
|
||||
// and the sum of the values of these two fields is at most the
|
||||
// value of the offset to the first strip or tile.
|
||||
//
|
||||
// Instance variables set: tables, SOFPosition, SOSMarker
|
||||
//
|
||||
// Example:
|
||||
// "Oi/GFS, writer v00.06.00P, (c) Wang Labs, Inc. 1990, 1991"
|
||||
// 03.tif (pages 1 and 3(indexes 0 and 2))
|
||||
//
|
||||
// "Oi/GFS, writer v00.06.02"
|
||||
// Color2.tif (page 1 (index 0))
|
||||
// color3.tif (page 1 (index 0))
|
||||
//
|
||||
// Case 5: If none of the foregoing cases apply. For this case the
|
||||
// JPEGQTables, JPEGACTables, and JPEGDCTables must be valid.
|
||||
//
|
||||
// Instance variables set: tables, SOFPosition, SOSMarker
|
||||
//
|
||||
// Example:
|
||||
// "NeXT"
|
||||
// zackthecat.tif from libtiff test data.
|
||||
//
|
||||
private synchronized void initialize() throws IOException {
|
||||
if(isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the TIFF metadata object.
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
|
||||
// Get the JPEGInterchangeFormat field.
|
||||
TIFFField JPEGInterchangeFormatField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||
|
||||
// Get the tile or strip offsets.
|
||||
TIFFField segmentOffsetField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
|
||||
if(segmentOffsetField == null) {
|
||||
segmentOffsetField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
|
||||
if(segmentOffsetField == null) {
|
||||
segmentOffsetField = JPEGInterchangeFormatField;
|
||||
}
|
||||
}
|
||||
long[] segmentOffsets = segmentOffsetField.getAsLongs();
|
||||
|
||||
// Determine whether the image has more than one strip or tile.
|
||||
boolean isTiled = segmentOffsets.length > 1;
|
||||
|
||||
if(!isTiled) {
|
||||
//
|
||||
// If the image has only a single strip or tile and it looks
|
||||
// as if a complete JPEG stream is present then set the value
|
||||
// of JPEGStreamOffset to the offset of the JPEG stream;
|
||||
// otherwise leave JPEGStreamOffset set to null.
|
||||
//
|
||||
|
||||
stream.seek(offset);
|
||||
stream.mark();
|
||||
if(stream.read() == 0xff && stream.read() == SOI) {
|
||||
// Tile or strip offset points to SOI.
|
||||
JPEGStreamOffset = Long.valueOf(offset);
|
||||
|
||||
// Set initialization flag and return.
|
||||
((TIFFImageReader)reader).forwardWarningMessage("SOI marker detected at start of strip or tile.");
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
stream.reset();
|
||||
|
||||
if(JPEGInterchangeFormatField != null) {
|
||||
// Get the value of JPEGInterchangeFormat.
|
||||
long jpegInterchangeOffset =
|
||||
JPEGInterchangeFormatField.getAsLong(0);
|
||||
|
||||
// Get the JPEGInterchangeFormatLength field.
|
||||
TIFFField JPEGInterchangeFormatLengthField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
|
||||
if(JPEGInterchangeFormatLengthField == null) {
|
||||
// JPEGInterchangeFormat stream is of indeterminate
|
||||
// length so use it as a complete JPEG stream.
|
||||
JPEGStreamOffset = Long.valueOf(jpegInterchangeOffset);
|
||||
|
||||
// Set initialization flag and return.
|
||||
((TIFFImageReader)reader).forwardWarningMessage("JPEGInterchangeFormatLength field is missing");
|
||||
isInitialized = true;
|
||||
return;
|
||||
} else {
|
||||
// Get the JPEGInterchangeFormatLength field's value.
|
||||
long jpegInterchangeLength =
|
||||
JPEGInterchangeFormatLengthField.getAsLong(0);
|
||||
|
||||
if(jpegInterchangeOffset < segmentOffsets[0] &&
|
||||
(jpegInterchangeOffset + jpegInterchangeLength) >
|
||||
segmentOffsets[0]) {
|
||||
// JPEGInterchangeFormat points to a position
|
||||
// below the segment start position and ends at
|
||||
// a position after the segment start position.
|
||||
JPEGStreamOffset = Long.valueOf(jpegInterchangeOffset);
|
||||
|
||||
// Set initialization flag and return.
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the subsampling factors.
|
||||
TIFFField YCbCrSubsamplingField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
|
||||
if(YCbCrSubsamplingField != null) {
|
||||
subsamplingX = YCbCrSubsamplingField.getAsChars()[0];
|
||||
subsamplingY = YCbCrSubsamplingField.getAsChars()[1];
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the 'tables' instance variable either for later
|
||||
// use in prepending to individual abbreviated strips or tiles.
|
||||
//
|
||||
if(JPEGInterchangeFormatField != null) {
|
||||
// Get the value of JPEGInterchangeFormat.
|
||||
long jpegInterchangeOffset =
|
||||
JPEGInterchangeFormatField.getAsLong(0);
|
||||
|
||||
// Get the JPEGInterchangeFormatLength field.
|
||||
TIFFField JPEGInterchangeFormatLengthField =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
|
||||
if(JPEGInterchangeFormatLengthField != null) {
|
||||
// Get the JPEGInterchangeFormatLength field's value.
|
||||
long jpegInterchangeLength =
|
||||
JPEGInterchangeFormatLengthField.getAsLong(0);
|
||||
|
||||
if(jpegInterchangeLength >= 2 &&
|
||||
jpegInterchangeOffset + jpegInterchangeLength <=
|
||||
segmentOffsets[0]) {
|
||||
// Determine the length excluding any terminal EOI marker
|
||||
// and allocate table memory.
|
||||
stream.mark();
|
||||
stream.seek(jpegInterchangeOffset+jpegInterchangeLength-2);
|
||||
if(stream.read() == 0xff && stream.read() == EOI) {
|
||||
this.tables = new byte[(int)(jpegInterchangeLength-2)];
|
||||
} else {
|
||||
this.tables = new byte[(int)jpegInterchangeLength];
|
||||
}
|
||||
stream.reset();
|
||||
|
||||
// Read the tables.
|
||||
stream.mark();
|
||||
stream.seek(jpegInterchangeOffset);
|
||||
stream.readFully(tables);
|
||||
stream.reset();
|
||||
|
||||
((TIFFImageReader)reader).forwardWarningMessage("Incorrect JPEG interchange format: using JPEGInterchangeFormat offset to derive tables.");
|
||||
} else {
|
||||
((TIFFImageReader)reader).forwardWarningMessage("JPEGInterchangeFormat+JPEGInterchangeFormatLength > offset to first strip or tile.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this.tables == null) {
|
||||
//
|
||||
// Create tables-only stream in tables[] consisting of
|
||||
// SOI+DQTs+DHTs
|
||||
//
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
// Save stream length;
|
||||
long streamLength = stream.length();
|
||||
|
||||
// SOI
|
||||
baos.write(0xff);
|
||||
baos.write(SOI);
|
||||
|
||||
// Quantization Tables
|
||||
TIFFField f =
|
||||
tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_Q_TABLES);
|
||||
if(f == null) {
|
||||
throw new IIOException("JPEGQTables field missing!");
|
||||
}
|
||||
long[] off = f.getAsLongs();
|
||||
|
||||
for(int i = 0; i < off.length; i++) {
|
||||
baos.write(0xff); // Marker ID
|
||||
baos.write(DQT);
|
||||
|
||||
char markerLength = (char)67;
|
||||
baos.write((markerLength >>> 8) & 0xff); // Length
|
||||
baos.write(markerLength & 0xff);
|
||||
|
||||
baos.write(i); // Table ID and precision
|
||||
|
||||
byte[] qtable = new byte[64];
|
||||
if(streamLength != -1 && off[i] > streamLength) {
|
||||
throw new IIOException("JPEGQTables offset for index "+
|
||||
i+" is not in the stream!");
|
||||
}
|
||||
stream.seek(off[i]);
|
||||
stream.readFully(qtable);
|
||||
|
||||
baos.write(qtable); // Table data
|
||||
}
|
||||
|
||||
// Huffman Tables (k == 0 ? DC : AC).
|
||||
for(int k = 0; k < 2; k++) {
|
||||
int tableTagNumber = k == 0 ?
|
||||
BaselineTIFFTagSet.TAG_JPEG_DC_TABLES :
|
||||
BaselineTIFFTagSet.TAG_JPEG_AC_TABLES;
|
||||
f = tim.getTIFFField(tableTagNumber);
|
||||
String fieldName =
|
||||
tableTagNumber ==
|
||||
BaselineTIFFTagSet.TAG_JPEG_DC_TABLES ?
|
||||
"JPEGDCTables" : "JPEGACTables";
|
||||
|
||||
if(f == null) {
|
||||
throw new IIOException(fieldName+" field missing!");
|
||||
}
|
||||
off = f.getAsLongs();
|
||||
|
||||
for(int i = 0; i < off.length; i++) {
|
||||
baos.write(0xff); // Marker ID
|
||||
baos.write(DHT);
|
||||
|
||||
byte[] blengths = new byte[16];
|
||||
if(streamLength != -1 && off[i] > streamLength) {
|
||||
throw new IIOException(fieldName+" offset for index "+
|
||||
i+" is not in the stream!");
|
||||
}
|
||||
stream.seek(off[i]);
|
||||
stream.readFully(blengths);
|
||||
int numCodes = 0;
|
||||
for(int j = 0; j < 16; j++) {
|
||||
numCodes += blengths[j]&0xff;
|
||||
}
|
||||
|
||||
char markerLength = (char)(19 + numCodes);
|
||||
|
||||
baos.write((markerLength >>> 8) & 0xff); // Length
|
||||
baos.write(markerLength & 0xff);
|
||||
|
||||
baos.write(i | (k << 4)); // Table ID and type
|
||||
|
||||
baos.write(blengths); // Number of codes
|
||||
|
||||
byte[] bcodes = new byte[numCodes];
|
||||
stream.readFully(bcodes);
|
||||
baos.write(bcodes); // Codes
|
||||
}
|
||||
}
|
||||
|
||||
// SOF0
|
||||
baos.write((byte)0xff); // Marker identifier
|
||||
baos.write((byte)SOF0);
|
||||
short sval = (short)(8 + 3*samplesPerPixel); // Length
|
||||
baos.write((byte)((sval >>> 8) & 0xff));
|
||||
baos.write((byte)(sval & 0xff));
|
||||
baos.write((byte)8); // Data precision
|
||||
sval = (short)srcHeight; // Tile/strip height
|
||||
baos.write((byte)((sval >>> 8) & 0xff));
|
||||
baos.write((byte)(sval & 0xff));
|
||||
sval = (short)srcWidth; // Tile/strip width
|
||||
baos.write((byte)((sval >>> 8) & 0xff));
|
||||
baos.write((byte)(sval & 0xff));
|
||||
baos.write((byte)samplesPerPixel); // Number of components
|
||||
if(samplesPerPixel == 1) {
|
||||
baos.write((byte)1); // Component ID
|
||||
baos.write((byte)0x11); // Subsampling factor
|
||||
baos.write((byte)0); // Quantization table ID
|
||||
} else { // 3
|
||||
for(int i = 0; i < 3; i++) {
|
||||
baos.write((byte)(i + 1)); // Component ID
|
||||
baos.write((i != 0) ?
|
||||
(byte)0x11 :
|
||||
(byte)(((subsamplingX & 0x0f) << 4) |
|
||||
(subsamplingY & 0x0f)));
|
||||
|
||||
baos.write((byte)i); // Quantization table ID
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// DRI (optional).
|
||||
f = tim.getTIFFField(BaselineTIFFTagSet.TAG_JPEG_RESTART_INTERVAL);
|
||||
if(f != null) {
|
||||
char restartInterval = f.getAsChars()[0];
|
||||
|
||||
if(restartInterval != 0) {
|
||||
baos.write((byte)0xff); // Marker identifier
|
||||
baos.write((byte)DRI);
|
||||
|
||||
sval = 4;
|
||||
baos.write((byte)((sval >>> 8) & 0xff)); // Length
|
||||
baos.write((byte)(sval & 0xff));
|
||||
|
||||
// RestartInterval
|
||||
baos.write((byte)((restartInterval >>> 8) & 0xff));
|
||||
baos.write((byte)(restartInterval & 0xff));
|
||||
}
|
||||
}
|
||||
|
||||
tables = baos.toByteArray();
|
||||
}
|
||||
|
||||
//
|
||||
// Check for presence of SOF marker and save its position.
|
||||
//
|
||||
int idx = 0;
|
||||
int idxMax = tables.length - 1;
|
||||
while(idx < idxMax) {
|
||||
if((tables[idx]&0xff) == 0xff &&
|
||||
(tables[idx+1]&0xff) == SOF0) {
|
||||
SOFPosition = idx;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
//
|
||||
// If no SOF marker, add one.
|
||||
//
|
||||
if(SOFPosition == -1) {
|
||||
byte[] tmpTables =
|
||||
new byte[tables.length + 10 + 3*samplesPerPixel];
|
||||
System.arraycopy(tables, 0, tmpTables, 0, tables.length);
|
||||
int tmpOffset = tables.length;
|
||||
SOFPosition = tables.length;
|
||||
tables = tmpTables;
|
||||
|
||||
tables[tmpOffset++] = (byte)0xff; // Marker identifier
|
||||
tables[tmpOffset++] = (byte)SOF0;
|
||||
short sval = (short)(8 + 3*samplesPerPixel); // Length
|
||||
tables[tmpOffset++] = (byte)((sval >>> 8) & 0xff);
|
||||
tables[tmpOffset++] = (byte)(sval & 0xff);
|
||||
tables[tmpOffset++] = (byte)8; // Data precision
|
||||
sval = (short)srcHeight; // Tile/strip height
|
||||
tables[tmpOffset++] = (byte)((sval >>> 8) & 0xff);
|
||||
tables[tmpOffset++] = (byte)(sval & 0xff);
|
||||
sval = (short)srcWidth; // Tile/strip width
|
||||
tables[tmpOffset++] = (byte)((sval >>> 8) & 0xff);
|
||||
tables[tmpOffset++] = (byte)(sval & 0xff);
|
||||
tables[tmpOffset++] = (byte)samplesPerPixel; // Number of components
|
||||
if(samplesPerPixel == 1) {
|
||||
tables[tmpOffset++] = (byte)1; // Component ID
|
||||
tables[tmpOffset++] = (byte)0x11; // Subsampling factor
|
||||
tables[tmpOffset++] = (byte)0; // Quantization table ID
|
||||
} else { // 3
|
||||
for(int i = 0; i < 3; i++) {
|
||||
tables[tmpOffset++] = (byte)(i + 1); // Component ID
|
||||
tables[tmpOffset++] = (i != 0) ?
|
||||
(byte)0x11 :
|
||||
(byte)(((subsamplingX & 0x0f) << 4) |
|
||||
(subsamplingY & 0x0f));
|
||||
|
||||
tables[tmpOffset++] = (byte)i; // Quantization table ID
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize SOSMarker.
|
||||
//
|
||||
stream.mark();
|
||||
stream.seek(segmentOffsets[0]);
|
||||
if(stream.read() == 0xff && stream.read() == SOS) {
|
||||
//
|
||||
// If the first segment starts with an SOS marker save it.
|
||||
//
|
||||
int SOSLength = (stream.read()<<8)|stream.read();
|
||||
SOSMarker = new byte[SOSLength+2];
|
||||
SOSMarker[0] = (byte)0xff;
|
||||
SOSMarker[1] = (byte)SOS;
|
||||
SOSMarker[2] = (byte)((SOSLength & 0xff00) >> 8);
|
||||
SOSMarker[3] = (byte)(SOSLength & 0xff);
|
||||
stream.readFully(SOSMarker, 4, SOSLength - 2);
|
||||
} else {
|
||||
//
|
||||
// Manufacture an SOS marker.
|
||||
//
|
||||
SOSMarker = new byte[2 + 6 + 2*samplesPerPixel];
|
||||
int SOSMarkerIndex = 0;
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)0xff; // Marker identifier
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)SOS;
|
||||
short sval = (short)(6 + 2*samplesPerPixel); // Length
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)((sval >>> 8) & 0xff);
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)(sval & 0xff);
|
||||
// Number of components in scan
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)samplesPerPixel;
|
||||
if(samplesPerPixel == 1) {
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)1; // Component ID
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)0; // Huffman table ID
|
||||
} else { // 3
|
||||
for(int i = 0; i < 3; i++) {
|
||||
SOSMarker[SOSMarkerIndex++] =
|
||||
(byte)(i + 1); // Component ID
|
||||
SOSMarker[SOSMarkerIndex++] =
|
||||
(byte)((i << 4) | i); // Huffman table IDs
|
||||
}
|
||||
};
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)0;
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)0x3f;
|
||||
SOSMarker[SOSMarkerIndex++] = (byte)0;
|
||||
}
|
||||
stream.reset();
|
||||
|
||||
// Set initialization flag.
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
//
|
||||
// The strategy for reading cases 1-3 is to treat the data as a complete
|
||||
// JPEG interchange stream located at JPEGStreamOffset.
|
||||
//
|
||||
// The strategy for cases 4-5 is to concatenate a tables stream created
|
||||
// in initialize() with the entropy coded data in each strip or tile.
|
||||
//
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
|
||||
initialize();
|
||||
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
|
||||
if(JPEGStreamOffset != null) {
|
||||
stream.seek(JPEGStreamOffset.longValue());
|
||||
JPEGReader.setInput(stream, false, true);
|
||||
} else {
|
||||
// Determine buffer length and allocate.
|
||||
int tableLength = tables.length;
|
||||
int bufLength =
|
||||
tableLength + SOSMarker.length + byteCount + 2; // 2 for EOI.
|
||||
byte[] buf = new byte[bufLength];
|
||||
System.arraycopy(tables, 0, buf, 0, tableLength);
|
||||
int bufOffset = tableLength;
|
||||
|
||||
// Update the SOF dimensions.
|
||||
short sval = (short)srcHeight; // Tile/strip height
|
||||
buf[SOFPosition + 5] = (byte)((sval >>> 8) & 0xff);
|
||||
buf[SOFPosition + 6] = (byte)(sval & 0xff);
|
||||
sval = (short)srcWidth; // Tile/strip width
|
||||
buf[SOFPosition + 7] = (byte)((sval >>> 8) & 0xff);
|
||||
buf[SOFPosition + 8] = (byte)(sval & 0xff);
|
||||
|
||||
// Seek to data.
|
||||
stream.seek(offset);
|
||||
|
||||
// Add SOS marker if data segment does not start with one.
|
||||
byte[] twoBytes = new byte[2];
|
||||
stream.readFully(twoBytes);
|
||||
if(!((twoBytes[0]&0xff) == 0xff && (twoBytes[1]&0xff) == SOS)) {
|
||||
// Segment does not start with SOS marker;
|
||||
// use the pre-calculated SOS marker.
|
||||
System.arraycopy(SOSMarker, 0, buf, bufOffset,
|
||||
SOSMarker.length);
|
||||
bufOffset += SOSMarker.length;
|
||||
}
|
||||
|
||||
// Copy the segment data into the buffer.
|
||||
buf[bufOffset++] = twoBytes[0];
|
||||
buf[bufOffset++] = twoBytes[1];
|
||||
stream.readFully(buf, bufOffset, byteCount - 2);
|
||||
bufOffset += byteCount - 2;
|
||||
|
||||
// EOI.
|
||||
buf[bufOffset++] = (byte)0xff; // Marker identifier
|
||||
buf[bufOffset++] = (byte)EOI;
|
||||
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(buf, 0, bufOffset);
|
||||
ImageInputStream is = new MemoryCacheImageInputStream(bais);
|
||||
|
||||
JPEGReader.setInput(is, true, true);
|
||||
}
|
||||
|
||||
// Read real image
|
||||
JPEGParam.setDestination(rawImage);
|
||||
JPEGReader.read(0, JPEGParam);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
JPEGReader.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFPackBitsCompressor extends TIFFCompressor {
|
||||
|
||||
public TIFFPackBitsCompressor() {
|
||||
super("PackBits", BaselineTIFFTagSet.COMPRESSION_PACKBITS, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs PackBits compression for a single buffer of data.
|
||||
* This should be called for each row of each tile. The returned
|
||||
* value is the offset into the output buffer after compression.
|
||||
*/
|
||||
private static int packBits(byte[] input, int inOffset, int inCount,
|
||||
byte[] output, int outOffset) {
|
||||
int inMax = inOffset + inCount - 1;
|
||||
int inMaxMinus1 = inMax - 1;
|
||||
|
||||
while(inOffset <= inMax) {
|
||||
int run = 1;
|
||||
byte replicate = input[inOffset];
|
||||
while(run < 127 && inOffset < inMax &&
|
||||
input[inOffset] == input[inOffset+1]) {
|
||||
run++;
|
||||
inOffset++;
|
||||
}
|
||||
if(run > 1) {
|
||||
inOffset++;
|
||||
output[outOffset++] = (byte)(-(run - 1));
|
||||
output[outOffset++] = replicate;
|
||||
}
|
||||
|
||||
run = 0;
|
||||
int saveOffset = outOffset;
|
||||
while(run < 128 &&
|
||||
((inOffset < inMax &&
|
||||
input[inOffset] != input[inOffset+1]) ||
|
||||
(inOffset < inMaxMinus1 &&
|
||||
input[inOffset] != input[inOffset+2]))) {
|
||||
run++;
|
||||
output[++outOffset] = input[inOffset++];
|
||||
}
|
||||
if(run > 0) {
|
||||
output[saveOffset] = (byte)(run - 1);
|
||||
outOffset++;
|
||||
}
|
||||
|
||||
if(inOffset == inMax) {
|
||||
if(run > 0 && run < 128) {
|
||||
output[saveOffset]++;
|
||||
output[outOffset++] = input[inOffset++];
|
||||
} else {
|
||||
output[outOffset++] = (byte)0;
|
||||
output[outOffset++] = input[inOffset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outOffset;
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
int bitsPerPixel = 0;
|
||||
for (int i = 0; i < bitsPerSample.length; i++) {
|
||||
bitsPerPixel += bitsPerSample[i];
|
||||
}
|
||||
int bytesPerRow = (bitsPerPixel*width + 7)/8;
|
||||
int bufSize = (bytesPerRow + (bytesPerRow + 127)/128);
|
||||
byte[] compData = new byte[bufSize];
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
for(int i = 0; i < height; i++) {
|
||||
int bytes = packBits(b, off, scanlineStride, compData, 0);
|
||||
off += scanlineStride;
|
||||
bytesWritten += bytes;
|
||||
stream.write(compData, 0, bytes);
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFPackBitsDecompressor extends TIFFDecompressor {
|
||||
|
||||
public TIFFPackBitsDecompressor() {
|
||||
}
|
||||
|
||||
public int decode(byte[] srcData, int srcOffset,
|
||||
byte[] dstData, int dstOffset)
|
||||
throws IOException {
|
||||
|
||||
int srcIndex = srcOffset;
|
||||
int dstIndex = dstOffset;
|
||||
|
||||
int dstArraySize = dstData.length;
|
||||
int srcArraySize = srcData.length;
|
||||
try {
|
||||
while (dstIndex < dstArraySize && srcIndex < srcArraySize) {
|
||||
byte b = srcData[srcIndex++];
|
||||
|
||||
if (b >= 0 && b <= 127) {
|
||||
// Literal run packet
|
||||
|
||||
for (int i = 0; i < b + 1; i++) {
|
||||
dstData[dstIndex++] = srcData[srcIndex++];
|
||||
}
|
||||
} else if (b <= -1 && b >= -127) {
|
||||
// 2-byte encoded run packet
|
||||
byte repeat = srcData[srcIndex++];
|
||||
for (int i = 0; i < (-b + 1); i++) {
|
||||
dstData[dstIndex++] = repeat;
|
||||
}
|
||||
} else {
|
||||
// No-op packet, do nothing
|
||||
++srcIndex;
|
||||
}
|
||||
}
|
||||
} catch(ArrayIndexOutOfBoundsException e) {
|
||||
if(reader instanceof TIFFImageReader) {
|
||||
((TIFFImageReader)reader).forwardWarningMessage
|
||||
("ArrayIndexOutOfBoundsException ignored in TIFFPackBitsDecompressor.decode()");
|
||||
}
|
||||
}
|
||||
|
||||
return dstIndex - dstOffset;
|
||||
}
|
||||
|
||||
public void decodeRaw(byte[] b,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
stream.seek(offset);
|
||||
|
||||
byte[] srcData = new byte[byteCount];
|
||||
stream.readFully(srcData);
|
||||
|
||||
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
|
||||
byte[] buf;
|
||||
int bufOffset;
|
||||
if(bytesPerRow == scanlineStride) {
|
||||
buf = b;
|
||||
bufOffset = dstOffset;
|
||||
} else {
|
||||
buf = new byte[bytesPerRow*srcHeight];
|
||||
bufOffset = 0;
|
||||
}
|
||||
|
||||
decode(srcData, 0, buf, bufOffset);
|
||||
|
||||
if(bytesPerRow != scanlineStride) {
|
||||
int off = 0;
|
||||
for (int y = 0; y < srcHeight; y++) {
|
||||
System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
|
||||
off += bytesPerRow;
|
||||
dstOffset += scanlineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TIFFPackBitsUtil {
|
||||
|
||||
byte[] dstData = new byte[8192];
|
||||
int dstIndex = 0;
|
||||
|
||||
public TIFFPackBitsUtil() {
|
||||
}
|
||||
|
||||
private void ensureCapacity(int bytesToAdd) {
|
||||
if (dstIndex + bytesToAdd > dstData.length) {
|
||||
byte[] newDstData = new byte[Math.max((int)(dstData.length*1.2f),
|
||||
dstIndex + bytesToAdd)];
|
||||
System.arraycopy(dstData, 0, newDstData, 0, dstData.length);
|
||||
dstData = newDstData;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] decode(byte[] srcData) throws IOException {
|
||||
int inIndex = 0;
|
||||
while (inIndex < srcData.length) {
|
||||
byte b = srcData[inIndex++];
|
||||
|
||||
if (b >= 0 && b <= 127) {
|
||||
// Literal run packet
|
||||
|
||||
ensureCapacity(b + 1);
|
||||
for (int i = 0; i < b + 1; i++) {
|
||||
dstData[dstIndex++] = srcData[inIndex++];
|
||||
}
|
||||
} else if (b <= -1 && b >= -127) {
|
||||
// 2-byte encoded run packet
|
||||
byte repeat = srcData[inIndex++];
|
||||
ensureCapacity(-b + 1);
|
||||
for (int i = 0; i < (-b + 1); i++) {
|
||||
dstData[dstIndex++] = repeat;
|
||||
}
|
||||
} else {
|
||||
// No-op packet, do nothing
|
||||
++inIndex;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] newDstData = new byte[dstIndex];
|
||||
System.arraycopy(dstData, 0, newDstData, 0, dstIndex);
|
||||
return newDstData;
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TIFFRLECompressor extends TIFFFaxCompressor {
|
||||
|
||||
public TIFFRLECompressor() {
|
||||
super("CCITT RLE", BaselineTIFFTagSet.COMPRESSION_CCITT_RLE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a row of data using Modified Huffman Compression also known as
|
||||
* CCITT RLE (Run Lenth Encoding).
|
||||
*
|
||||
* @param data The row of data to compress.
|
||||
* @param rowOffset Starting index in <code>data</code>.
|
||||
* @param colOffset Bit offset within first <code>data[rowOffset]</code>.
|
||||
* @param rowLength Number of bits in the row.
|
||||
* @param compData The compressed data.
|
||||
*
|
||||
* @return The number of bytes saved in the compressed data array.
|
||||
*/
|
||||
public int encodeRLE(byte[] data,
|
||||
int rowOffset,
|
||||
int colOffset,
|
||||
int rowLength,
|
||||
byte[] compData) {
|
||||
//
|
||||
// Initialize bit buffer machinery.
|
||||
//
|
||||
initBitBuf();
|
||||
|
||||
//
|
||||
// Run-length encode line.
|
||||
//
|
||||
int outIndex =
|
||||
encode1D(data, rowOffset, colOffset, rowLength, compData, 0);
|
||||
|
||||
//
|
||||
// Flush pending bits
|
||||
//
|
||||
while (ndex > 0) {
|
||||
compData[outIndex++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
//
|
||||
// Flip the bytes if inverse fill was requested.
|
||||
//
|
||||
if (inverseFill) {
|
||||
byte[] flipTable = TIFFFaxDecompressor.flipTable;
|
||||
for(int i = 0; i < outIndex; i++) {
|
||||
compData[i] = flipTable[compData[i] & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
return outIndex;
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
|
||||
throw new IIOException(
|
||||
"Bits per sample must be 1 for RLE compression!");
|
||||
}
|
||||
|
||||
// In the worst case, 2 bits of input will result in 9 bits of output,
|
||||
// plus 2 extra bits if the row starts with black.
|
||||
int maxBits = 9*((width + 1)/2) + 2;
|
||||
byte[] compData = new byte[(maxBits + 7)/8];
|
||||
|
||||
int bytes = 0;
|
||||
int rowOffset = off;
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
int rowBytes = encodeRLE(b, rowOffset, 0, width, compData);
|
||||
stream.write(compData, 0, rowBytes);
|
||||
|
||||
rowOffset += scanlineStride;
|
||||
bytes += rowBytes;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.plugins.tiff.TIFFImageReadParam;
|
||||
import javax.imageio.plugins.tiff.TIFFTagSet;
|
||||
|
||||
public class TIFFRenderedImage implements RenderedImage {
|
||||
|
||||
private TIFFImageReader reader;
|
||||
private int imageIndex;
|
||||
private ImageReadParam tileParam;
|
||||
|
||||
private int subsampleX;
|
||||
private int subsampleY;
|
||||
|
||||
private boolean isSubsampling;
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private int tileWidth;
|
||||
private int tileHeight;
|
||||
|
||||
private ImageTypeSpecifier its;
|
||||
|
||||
public TIFFRenderedImage(TIFFImageReader reader,
|
||||
int imageIndex,
|
||||
ImageReadParam readParam,
|
||||
int width, int height) throws IOException {
|
||||
this.reader = reader;
|
||||
this.imageIndex = imageIndex;
|
||||
this.tileParam = cloneImageReadParam(readParam, false);
|
||||
|
||||
this.subsampleX = tileParam.getSourceXSubsampling();
|
||||
this.subsampleY = tileParam.getSourceYSubsampling();
|
||||
|
||||
this.isSubsampling = this.subsampleX != 1 || this.subsampleY != 1;
|
||||
|
||||
this.width = width/subsampleX;
|
||||
this.height = height/subsampleY;
|
||||
|
||||
// If subsampling is being used, we may not match the
|
||||
// true tile grid exactly, but everything should still work
|
||||
this.tileWidth = reader.getTileWidth(imageIndex)/subsampleX;
|
||||
this.tileHeight = reader.getTileHeight(imageIndex)/subsampleY;
|
||||
|
||||
Iterator<ImageTypeSpecifier> iter = reader.getImageTypes(imageIndex);
|
||||
this.its = iter.next();
|
||||
tileParam.setDestinationType(its);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of <code>param</code>. The source subsampling and
|
||||
* and bands settings and the destination bands and offset settings
|
||||
* are copied. If <code>param</code> is a <code>TIFFImageReadParam</code>
|
||||
* then the <code>TIFFDecompressor</code> and
|
||||
* <code>TIFFColorConverter</code> settings are also copied; otherwise
|
||||
* they are explicitly set to <code>null</code>.
|
||||
*
|
||||
* @param param the parameters to be copied.
|
||||
* @param copyTagSets whether the <code>TIFFTagSet</code> settings
|
||||
* should be copied if set.
|
||||
* @return copied parameters.
|
||||
*/
|
||||
private ImageReadParam cloneImageReadParam(ImageReadParam param,
|
||||
boolean copyTagSets) {
|
||||
// Create a new TIFFImageReadParam.
|
||||
TIFFImageReadParam newParam = new TIFFImageReadParam();
|
||||
|
||||
// Copy the basic settings.
|
||||
newParam.setSourceSubsampling(param.getSourceXSubsampling(),
|
||||
param.getSourceYSubsampling(),
|
||||
param.getSubsamplingXOffset(),
|
||||
param.getSubsamplingYOffset());
|
||||
newParam.setSourceBands(param.getSourceBands());
|
||||
newParam.setDestinationBands(param.getDestinationBands());
|
||||
newParam.setDestinationOffset(param.getDestinationOffset());
|
||||
|
||||
if (param instanceof TIFFImageReadParam && copyTagSets) {
|
||||
// Copy the settings from the input parameter.
|
||||
TIFFImageReadParam tparam = (TIFFImageReadParam) param;
|
||||
|
||||
List<TIFFTagSet> tagSets = tparam.getAllowedTagSets();
|
||||
if (tagSets != null) {
|
||||
Iterator<TIFFTagSet> tagSetIter = tagSets.iterator();
|
||||
if (tagSetIter != null) {
|
||||
while (tagSetIter.hasNext()) {
|
||||
TIFFTagSet tagSet = tagSetIter.next();
|
||||
newParam.addAllowedTagSet(tagSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newParam;
|
||||
}
|
||||
|
||||
public Vector<RenderedImage> getSources() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getProperty(String name) {
|
||||
return java.awt.Image.UndefinedProperty;
|
||||
}
|
||||
|
||||
public String[] getPropertyNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ColorModel getColorModel() {
|
||||
return its.getColorModel();
|
||||
}
|
||||
|
||||
public SampleModel getSampleModel() {
|
||||
return its.getSampleModel();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getMinX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getMinY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getNumXTiles() {
|
||||
return (width + tileWidth - 1)/tileWidth;
|
||||
}
|
||||
|
||||
public int getNumYTiles() {
|
||||
return (height + tileHeight - 1)/tileHeight;
|
||||
}
|
||||
|
||||
public int getMinTileX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getMinTileY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getTileWidth() {
|
||||
return tileWidth;
|
||||
}
|
||||
|
||||
public int getTileHeight() {
|
||||
return tileHeight;
|
||||
}
|
||||
|
||||
public int getTileGridXOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getTileGridYOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Raster getTile(int tileX, int tileY) {
|
||||
Rectangle tileRect = new Rectangle(tileX*tileWidth,
|
||||
tileY*tileHeight,
|
||||
tileWidth,
|
||||
tileHeight);
|
||||
return getData(tileRect);
|
||||
}
|
||||
|
||||
public Raster getData() {
|
||||
return read(new Rectangle(0, 0, getWidth(), getHeight()));
|
||||
}
|
||||
|
||||
public Raster getData(Rectangle rect) {
|
||||
return read(rect);
|
||||
}
|
||||
|
||||
// This method needs to be synchronized as it updates the instance
|
||||
// variable 'tileParam'.
|
||||
public synchronized WritableRaster read(Rectangle rect) {
|
||||
tileParam.setSourceRegion(isSubsampling ?
|
||||
new Rectangle(subsampleX*rect.x,
|
||||
subsampleY*rect.y,
|
||||
subsampleX*rect.width,
|
||||
subsampleY*rect.height) :
|
||||
rect);
|
||||
|
||||
try {
|
||||
BufferedImage bi = reader.read(imageIndex, tileParam);
|
||||
WritableRaster ras = bi.getRaster();
|
||||
return ras.createWritableChild(0, 0,
|
||||
ras.getWidth(), ras.getHeight(),
|
||||
rect.x, rect.y,
|
||||
null);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public WritableRaster copyData(WritableRaster raster) {
|
||||
if (raster == null) {
|
||||
return read(new Rectangle(0, 0, getWidth(), getHeight()));
|
||||
} else {
|
||||
Raster src = read(raster.getBounds());
|
||||
raster.setRect(src);
|
||||
return raster;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
public class TIFFStreamMetadata extends IIOMetadata {
|
||||
|
||||
// package scope
|
||||
static final String NATIVE_METADATA_FORMAT_NAME =
|
||||
"javax_imageio_tiff_stream_1.0";
|
||||
|
||||
static final String NATIVE_METADATA_FORMAT_CLASS_NAME =
|
||||
"javax.imageio.plugins.tiff.TIFFStreamMetadataFormat";
|
||||
|
||||
private static final String bigEndianString =
|
||||
ByteOrder.BIG_ENDIAN.toString();
|
||||
private static final String littleEndianString =
|
||||
ByteOrder.LITTLE_ENDIAN.toString();
|
||||
|
||||
public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
|
||||
public TIFFStreamMetadata() {
|
||||
super(false,
|
||||
NATIVE_METADATA_FORMAT_NAME,
|
||||
NATIVE_METADATA_FORMAT_CLASS_NAME,
|
||||
null, null);
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shorthand for throwing an IIOInvalidTreeException
|
||||
private static void fatal(Node node, String reason)
|
||||
throws IIOInvalidTreeException {
|
||||
throw new IIOInvalidTreeException(reason, node);
|
||||
}
|
||||
|
||||
public Node getAsTree(String formatName) {
|
||||
IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName);
|
||||
|
||||
IIOMetadataNode byteOrderNode = new IIOMetadataNode("ByteOrder");
|
||||
byteOrderNode.setAttribute("value", byteOrder.toString());
|
||||
|
||||
root.appendChild(byteOrderNode);
|
||||
return root;
|
||||
}
|
||||
|
||||
// public void setFromTree(String formatName, Node root) {
|
||||
// }
|
||||
|
||||
private void mergeNativeTree(Node root) throws IIOInvalidTreeException {
|
||||
Node node = root;
|
||||
if (!node.getNodeName().equals(nativeMetadataFormatName)) {
|
||||
fatal(node, "Root must be " + nativeMetadataFormatName);
|
||||
}
|
||||
|
||||
node = node.getFirstChild();
|
||||
if (node == null || !node.getNodeName().equals("ByteOrder")) {
|
||||
fatal(node, "Root must have \"ByteOrder\" child");
|
||||
}
|
||||
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
String order = attrs.getNamedItem("value").getNodeValue();
|
||||
|
||||
if (order == null) {
|
||||
fatal(node, "ByteOrder node must have a \"value\" attribute");
|
||||
}
|
||||
if (order.equals(bigEndianString)) {
|
||||
this.byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
} else if (order.equals(littleEndianString)) {
|
||||
this.byteOrder = ByteOrder.LITTLE_ENDIAN;
|
||||
} else {
|
||||
fatal(node, "Incorrect value for ByteOrder \"value\" attribute");
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeTree(String formatName, Node root)
|
||||
throws IIOInvalidTreeException {
|
||||
if (formatName.equals(nativeMetadataFormatName)) {
|
||||
if (root == null) {
|
||||
throw new NullPointerException("root == null!");
|
||||
}
|
||||
mergeNativeTree(root);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not a recognized format!");
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
|
||||
public class TIFFStreamMetadataFormat extends TIFFMetadataFormat {
|
||||
|
||||
private static TIFFStreamMetadataFormat theInstance = null;
|
||||
|
||||
public boolean canNodeAppear(String elementName,
|
||||
ImageTypeSpecifier imageType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private TIFFStreamMetadataFormat() {
|
||||
this.resourceBaseName =
|
||||
"javax.imageio.plugins.tiff.TIFFStreamMetadataFormatResources";
|
||||
this.rootName = TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME;
|
||||
|
||||
TIFFElementInfo einfo;
|
||||
TIFFAttrInfo ainfo;
|
||||
String[] empty = new String[0];
|
||||
String[] childNames;
|
||||
String[] attrNames;
|
||||
|
||||
childNames = new String[] { "ByteOrder" };
|
||||
einfo = new TIFFElementInfo(childNames, empty, CHILD_POLICY_ALL);
|
||||
|
||||
elementInfoMap.put(TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME,
|
||||
einfo);
|
||||
|
||||
childNames = empty;
|
||||
attrNames = new String[] { "value" };
|
||||
einfo = new TIFFElementInfo(childNames, attrNames, CHILD_POLICY_EMPTY);
|
||||
elementInfoMap.put("ByteOrder", einfo);
|
||||
|
||||
ainfo = new TIFFAttrInfo();
|
||||
ainfo.dataType = DATATYPE_STRING;
|
||||
ainfo.isRequired = true;
|
||||
attrInfoMap.put("ByteOrder/value", ainfo);
|
||||
}
|
||||
|
||||
public static synchronized IIOMetadataFormat getInstance() {
|
||||
if (theInstance == null) {
|
||||
theInstance = new TIFFStreamMetadataFormat();
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ListResourceBundle;
|
||||
|
||||
public class TIFFStreamMetadataFormatResources extends ListResourceBundle {
|
||||
|
||||
private static final Object[][] contents = {
|
||||
{ "ByteOrder", "The stream byte order" },
|
||||
{ "ByteOrder/value", "One of \"BIG_ENDIAN\" or \"LITTLE_ENDIAN\"" }
|
||||
};
|
||||
|
||||
public TIFFStreamMetadataFormatResources() {
|
||||
}
|
||||
|
||||
public Object[][] getContents() {
|
||||
return contents.clone();
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
import javax.imageio.plugins.tiff.TIFFTag;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
|
||||
public class TIFFT4Compressor extends TIFFFaxCompressor {
|
||||
|
||||
private boolean is1DMode = false;
|
||||
private boolean isEOLAligned = false;
|
||||
|
||||
public TIFFT4Compressor() {
|
||||
super("CCITT T.4", BaselineTIFFTagSet.COMPRESSION_CCITT_T_4, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <code>metadata</code> field.
|
||||
*
|
||||
* <p> The implementation in this class also sets local options
|
||||
* from the T4_OPTIONS field if it exists, and if it doesn't, adds
|
||||
* it with default values.</p>
|
||||
*
|
||||
* @param metadata the <code>IIOMetadata</code> object for the
|
||||
* image being written.
|
||||
*
|
||||
* @see #getMetadata()
|
||||
*/
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
super.setMetadata(metadata);
|
||||
|
||||
if (metadata instanceof TIFFImageMetadata) {
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
TIFFField f = tim.getTIFFField(BaselineTIFFTagSet.TAG_T4_OPTIONS);
|
||||
if (f != null) {
|
||||
int options = f.getAsInt(0);
|
||||
is1DMode = (options & 0x1) == 0;
|
||||
isEOLAligned = (options & 0x4) == 0x4;
|
||||
} else {
|
||||
long[] oarray = new long[1];
|
||||
oarray[0] = (isEOLAligned ? 0x4 : 0x0) |
|
||||
(is1DMode ? 0x0 : 0x1);
|
||||
|
||||
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
|
||||
TIFFField T4Options =
|
||||
new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_T4_OPTIONS),
|
||||
TIFFTag.TIFF_LONG,
|
||||
1,
|
||||
oarray);
|
||||
tim.rootIFD.addTIFFField(T4Options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a buffer of data using CCITT T.4 Compression also known as
|
||||
* Group 3 facsimile compression.
|
||||
*
|
||||
* @param is1DMode Whether to perform one-dimensional encoding.
|
||||
* @param isEOLAligned Whether EOL bit sequences should be padded.
|
||||
* @param data The row of data to compress.
|
||||
* @param lineStride Byte step between the same sample in different rows.
|
||||
* @param colOffset Bit offset within first <code>data[rowOffset]</code>.
|
||||
* @param width Number of bits in the row.
|
||||
* @param height Number of rows in the buffer.
|
||||
* @param compData The compressed data.
|
||||
*
|
||||
* @return The number of bytes saved in the compressed data array.
|
||||
*/
|
||||
public int encodeT4(boolean is1DMode,
|
||||
boolean isEOLAligned,
|
||||
byte[] data,
|
||||
int lineStride,
|
||||
int colOffset,
|
||||
int width,
|
||||
int height,
|
||||
byte[] compData)
|
||||
{
|
||||
//
|
||||
// ao, a1, a2 are bit indices in the current line
|
||||
// b1 and b2 are bit indices in the reference line (line above)
|
||||
// color is the current color (WHITE or BLACK)
|
||||
//
|
||||
byte[] refData = data;
|
||||
int lineAddr = 0;
|
||||
int outIndex = 0;
|
||||
|
||||
initBitBuf();
|
||||
|
||||
int KParameter = 2;
|
||||
for(int numRows = 0; numRows < height; numRows++) {
|
||||
if(is1DMode || (numRows % KParameter) == 0) { // 1D encoding
|
||||
// Write EOL+1
|
||||
outIndex += addEOL(is1DMode, isEOLAligned, true,
|
||||
compData, outIndex);
|
||||
|
||||
// Encode row
|
||||
outIndex += encode1D(data, lineAddr, colOffset, width,
|
||||
compData, outIndex);
|
||||
} else { // 2D encoding.
|
||||
// Write EOL+0
|
||||
outIndex += addEOL(is1DMode, isEOLAligned, false,
|
||||
compData, outIndex);
|
||||
|
||||
// Set reference to previous line
|
||||
int refAddr = lineAddr - lineStride;
|
||||
|
||||
// Encode row
|
||||
int a0 = colOffset;
|
||||
int last = a0 + width;
|
||||
|
||||
int testbit =
|
||||
((data[lineAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
int a1 = testbit != 0 ?
|
||||
a0 : nextState(data, lineAddr, a0, last);
|
||||
|
||||
testbit = ((refData[refAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
int b1 = testbit != 0 ?
|
||||
a0 : nextState(refData, refAddr, a0, last);
|
||||
|
||||
// The current color is set to WHITE at line start
|
||||
int color = WHITE;
|
||||
|
||||
while(true) {
|
||||
int b2 = nextState(refData, refAddr, b1, last);
|
||||
if(b2 < a1) { // pass mode
|
||||
outIndex += add2DBits(compData, outIndex, pass, 0);
|
||||
a0 = b2;
|
||||
} else {
|
||||
int tmp = b1 - a1 + 3;
|
||||
if((tmp <= 6) && (tmp >= 0)) { // vertical mode
|
||||
outIndex +=
|
||||
add2DBits(compData, outIndex, vert, tmp);
|
||||
a0 = a1;
|
||||
} else { // horizontal mode
|
||||
int a2 = nextState(data, lineAddr, a1, last);
|
||||
outIndex +=
|
||||
add2DBits(compData, outIndex, horz, 0);
|
||||
outIndex +=
|
||||
add1DBits(compData, outIndex, a1-a0, color);
|
||||
outIndex +=
|
||||
add1DBits(compData, outIndex, a2-a1, color^1);
|
||||
a0 = a2;
|
||||
}
|
||||
}
|
||||
if(a0 >= last) {
|
||||
break;
|
||||
}
|
||||
color = ((data[lineAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
a1 = nextState(data, lineAddr, a0, last);
|
||||
b1 = nextState(refData, refAddr, a0, last);
|
||||
testbit = ((refData[refAddr + (b1>>>3)]&0xff) >>>
|
||||
(7-(b1 & 0x7))) & 0x1;
|
||||
if(testbit == color) {
|
||||
b1 = nextState(refData, refAddr, b1, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to next line.
|
||||
lineAddr += lineStride;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++) {
|
||||
outIndex += addEOL(is1DMode, isEOLAligned, true,
|
||||
compData, outIndex);
|
||||
}
|
||||
|
||||
//
|
||||
// flush all pending bits
|
||||
//
|
||||
while(ndex > 0) {
|
||||
compData[outIndex++] = (byte)(bits >>> 24);
|
||||
bits <<= 8;
|
||||
ndex -= 8;
|
||||
}
|
||||
|
||||
// Flip the bytes if inverse fill was requested.
|
||||
if(inverseFill) {
|
||||
for(int i = 0; i < outIndex; i++) {
|
||||
compData[i] = TIFFFaxDecompressor.flipTable[compData[i]&0xff];
|
||||
}
|
||||
}
|
||||
|
||||
return outIndex;
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
|
||||
throw new IIOException(
|
||||
"Bits per sample must be 1 for T4 compression!");
|
||||
}
|
||||
|
||||
// This initial buffer size is based on an alternating 1-0
|
||||
// pattern generating the most bits when converted to code
|
||||
// words: 9 bits out for each pair of bits in. So the number
|
||||
// of bit pairs is determined, multiplied by 9, converted to
|
||||
// bytes, and a ceil() is taken to account for fill bits at the
|
||||
// end of each line. The "2" addend accounts for the case
|
||||
// of the pattern beginning with black. The buffer is intended
|
||||
// to hold only a single row.
|
||||
|
||||
int maxBits = 9*((width + 1)/2) + 2;
|
||||
int bufSize = (maxBits + 7)/8;
|
||||
|
||||
// Calculate the maximum row as the G3-1D size plus the EOL,
|
||||
// multiply this by the number of rows in the tile, and add
|
||||
// 6 EOLs for the RTC (return to control).
|
||||
bufSize = height*(bufSize + 2) + 12;
|
||||
|
||||
byte[] compData = new byte[bufSize];
|
||||
|
||||
int bytes = encodeT4(is1DMode,
|
||||
isEOLAligned,
|
||||
b, scanlineStride, 8*off,
|
||||
width, height,
|
||||
compData);
|
||||
|
||||
stream.write(compData, 0, bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
import javax.imageio.plugins.tiff.TIFFTag;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
public class TIFFT6Compressor extends TIFFFaxCompressor {
|
||||
|
||||
public TIFFT6Compressor() {
|
||||
super("CCITT T.6", BaselineTIFFTagSet.COMPRESSION_CCITT_T_6, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a buffer of data using CCITT T.6 Compression also known as
|
||||
* Group 4 facsimile compression.
|
||||
*
|
||||
* @param data The row of data to compress.
|
||||
* @param lineStride Byte step between the same sample in different rows.
|
||||
* @param colOffset Bit offset within first <code>data[rowOffset]</code>.
|
||||
* @param width Number of bits in the row.
|
||||
* @param height Number of rows in the buffer.
|
||||
* @param compData The compressed data.
|
||||
*
|
||||
* @return The number of bytes saved in the compressed data array.
|
||||
*/
|
||||
public synchronized int encodeT6(byte[] data,
|
||||
int lineStride,
|
||||
int colOffset,
|
||||
int width,
|
||||
int height,
|
||||
byte[] compData)
|
||||
{
|
||||
//
|
||||
// ao, a1, a2 are bit indices in the current line
|
||||
// b1 and b2 are bit indices in the reference line (line above)
|
||||
// color is the current color (WHITE or BLACK)
|
||||
//
|
||||
byte[] refData = null;
|
||||
int refAddr = 0;
|
||||
int lineAddr = 0;
|
||||
int outIndex = 0;
|
||||
|
||||
initBitBuf();
|
||||
|
||||
//
|
||||
// Iterate over all lines
|
||||
//
|
||||
while(height-- != 0) {
|
||||
int a0 = colOffset;
|
||||
int last = a0 + width;
|
||||
|
||||
int testbit =
|
||||
((data[lineAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
int a1 = testbit != 0 ?
|
||||
a0 : nextState(data, lineAddr, a0, last);
|
||||
|
||||
testbit = refData == null ?
|
||||
0: ((refData[refAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
int b1 = testbit != 0 ?
|
||||
a0 : nextState(refData, refAddr, a0, last);
|
||||
|
||||
//
|
||||
// The current color is set to WHITE at line start
|
||||
//
|
||||
int color = WHITE;
|
||||
|
||||
while(true) {
|
||||
int b2 = nextState(refData, refAddr, b1, last);
|
||||
if(b2 < a1) { // pass mode
|
||||
outIndex += add2DBits(compData, outIndex, pass, 0);
|
||||
a0 = b2;
|
||||
} else {
|
||||
int tmp = b1 - a1 + 3;
|
||||
if((tmp <= 6) && (tmp >= 0)) { // vertical mode
|
||||
outIndex += add2DBits(compData, outIndex, vert, tmp);
|
||||
a0 = a1;
|
||||
} else { // horizontal mode
|
||||
int a2 = nextState(data, lineAddr, a1, last);
|
||||
outIndex += add2DBits(compData, outIndex, horz, 0);
|
||||
outIndex += add1DBits(compData, outIndex, a1-a0, color);
|
||||
outIndex += add1DBits(compData, outIndex, a2-a1, color^1);
|
||||
a0 = a2;
|
||||
}
|
||||
}
|
||||
if(a0 >= last) {
|
||||
break;
|
||||
}
|
||||
color = ((data[lineAddr + (a0>>>3)]&0xff) >>>
|
||||
(7-(a0 & 0x7))) & 0x1;
|
||||
a1 = nextState(data, lineAddr, a0, last);
|
||||
b1 = nextState(refData, refAddr, a0, last);
|
||||
testbit = refData == null ?
|
||||
0: ((refData[refAddr + (b1>>>3)]&0xff) >>>
|
||||
(7-(b1 & 0x7))) & 0x1;
|
||||
if(testbit == color) {
|
||||
b1 = nextState(refData, refAddr, b1, last);
|
||||
}
|
||||
}
|
||||
|
||||
refData = data;
|
||||
refAddr = lineAddr;
|
||||
lineAddr += lineStride;
|
||||
|
||||
} // End while(height--)
|
||||
|
||||
//
|
||||
// append eofb
|
||||
//
|
||||
outIndex += addEOFB(compData, outIndex);
|
||||
|
||||
// Flip the bytes if inverse fill was requested.
|
||||
if(inverseFill) {
|
||||
for(int i = 0; i < outIndex; i++) {
|
||||
compData[i] = TIFFFaxDecompressor.flipTable[compData[i]&0xff];
|
||||
}
|
||||
}
|
||||
|
||||
return outIndex;
|
||||
}
|
||||
|
||||
public int encode(byte[] b, int off,
|
||||
int width, int height,
|
||||
int[] bitsPerSample,
|
||||
int scanlineStride) throws IOException {
|
||||
if (bitsPerSample.length != 1 || bitsPerSample[0] != 1) {
|
||||
throw new IIOException(
|
||||
"Bits per sample must be 1 for T6 compression!");
|
||||
}
|
||||
|
||||
|
||||
if (metadata instanceof TIFFImageMetadata) {
|
||||
TIFFImageMetadata tim = (TIFFImageMetadata)metadata;
|
||||
|
||||
long[] options = new long[1];
|
||||
options[0] = 0;
|
||||
|
||||
BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
|
||||
TIFFField T6Options =
|
||||
new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_T6_OPTIONS),
|
||||
TIFFTag.TIFF_LONG,
|
||||
1,
|
||||
options);
|
||||
tim.rootIFD.addTIFFField(T6Options);
|
||||
}
|
||||
|
||||
// See comment in TIFFT4Compressor
|
||||
int maxBits = 9*((width + 1)/2) + 2;
|
||||
int bufSize = (maxBits + 7)/8;
|
||||
bufSize = height*(bufSize + 2) + 12;
|
||||
|
||||
byte[] compData = new byte[bufSize];
|
||||
int bytes = encodeT6(b, scanlineStride, 8*off, width, height,
|
||||
compData);
|
||||
stream.write(compData, 0, bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
|
||||
public class TIFFYCbCrColorConverter extends TIFFColorConverter {
|
||||
|
||||
private static final float CODING_RANGE_Y = 255.0f;
|
||||
private static final float CODING_RANGE_CB_CR = 127.0f;
|
||||
|
||||
private float lumaRed = 0.299f;
|
||||
private float lumaGreen = 0.587f;
|
||||
private float lumaBlue = 0.114f;
|
||||
|
||||
private float referenceBlackY = 0.0f;
|
||||
private float referenceWhiteY = 255.0f;
|
||||
|
||||
private float referenceBlackCb = 128.0f;
|
||||
private float referenceWhiteCb = 255.0f;
|
||||
|
||||
private float referenceBlackCr = 128.0f;
|
||||
private float referenceWhiteCr = 255.0f;
|
||||
|
||||
public TIFFYCbCrColorConverter(TIFFImageMetadata metadata) {
|
||||
TIFFImageMetadata tmetadata = metadata;
|
||||
|
||||
TIFFField f =
|
||||
tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
|
||||
if (f != null && f.getCount() == 3) {
|
||||
this.lumaRed = f.getAsFloat(0);
|
||||
this.lumaGreen = f.getAsFloat(1);
|
||||
this.lumaBlue = f.getAsFloat(2);
|
||||
}
|
||||
|
||||
f =
|
||||
tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
|
||||
if (f != null && f.getCount() == 6) {
|
||||
this.referenceBlackY = f.getAsFloat(0);
|
||||
this.referenceWhiteY = f.getAsFloat(1);
|
||||
this.referenceBlackCb = f.getAsFloat(2);
|
||||
this.referenceWhiteCb = f.getAsFloat(3);
|
||||
this.referenceBlackCr = f.getAsFloat(4);
|
||||
this.referenceWhiteCr = f.getAsFloat(5);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The full range component value is converted from the code by:
|
||||
|
||||
FullRangeValue = (code - ReferenceBlack) * CodingRange
|
||||
/ (ReferenceWhite - ReferenceBlack);
|
||||
|
||||
The code is converted from the full-range component value by:
|
||||
|
||||
code = (FullRangeValue * (ReferenceWhite - ReferenceBlack)
|
||||
/ CodingRange) + ReferenceBlack;
|
||||
|
||||
*/
|
||||
public void fromRGB(float r, float g, float b, float[] result) {
|
||||
// Convert RGB to full-range YCbCr.
|
||||
float Y = (lumaRed*r + lumaGreen*g + lumaBlue*b);
|
||||
float Cb = (b - Y)/(2 - 2*lumaBlue);
|
||||
float Cr = (r - Y)/(2 - 2*lumaRed);
|
||||
|
||||
// Convert full-range YCbCr to code.
|
||||
result[0] = Y*(referenceWhiteY - referenceBlackY)/CODING_RANGE_Y +
|
||||
referenceBlackY;
|
||||
result[1] = Cb*(referenceWhiteCb - referenceBlackCb)/CODING_RANGE_CB_CR +
|
||||
referenceBlackCb;
|
||||
result[2] = Cr*(referenceWhiteCr - referenceBlackCr)/CODING_RANGE_CB_CR +
|
||||
referenceBlackCr;
|
||||
}
|
||||
|
||||
public void toRGB(float x0, float x1, float x2, float[] rgb) {
|
||||
// Convert YCbCr code to full-range YCbCr.
|
||||
float Y = (x0 - referenceBlackY)*CODING_RANGE_Y/
|
||||
(referenceWhiteY - referenceBlackY);
|
||||
float Cb = (x1 - referenceBlackCb)*CODING_RANGE_CB_CR/
|
||||
(referenceWhiteCb - referenceBlackCb);
|
||||
float Cr = (x2 - referenceBlackCr)*CODING_RANGE_CB_CR/
|
||||
(referenceWhiteCr - referenceBlackCr);
|
||||
|
||||
// Convert YCbCr to RGB.
|
||||
rgb[0] = Cr*(2 - 2*lumaRed) + Y;
|
||||
rgb[2] = Cb*(2 - 2*lumaBlue) + Y;
|
||||
rgb[1] = (Y - lumaBlue*rgb[2] - lumaRed*rgb[0])/lumaGreen;
|
||||
}
|
||||
}
|
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.plugins.tiff.TIFFField;
|
||||
|
||||
public class TIFFYCbCrDecompressor extends TIFFDecompressor {
|
||||
// Store constants in S15.16 format
|
||||
private static final int FRAC_BITS = 16;
|
||||
private static final float FRAC_SCALE = (float)(1 << FRAC_BITS);
|
||||
|
||||
private float lumaRed = 0.299f;
|
||||
private float lumaGreen = 0.587f;
|
||||
private float lumaBlue = 0.114f;
|
||||
|
||||
private float referenceBlackY = 0.0f;
|
||||
private float referenceWhiteY = 255.0f;
|
||||
|
||||
private float referenceBlackCb = 128.0f;
|
||||
private float referenceWhiteCb = 255.0f;
|
||||
|
||||
private float referenceBlackCr = 128.0f;
|
||||
private float referenceWhiteCr = 255.0f;
|
||||
|
||||
private float codingRangeY = 255.0f;
|
||||
|
||||
private int[] iYTab = new int[256];
|
||||
private int[] iCbTab = new int[256];
|
||||
private int[] iCrTab = new int[256];
|
||||
|
||||
private int[] iGYTab = new int[256];
|
||||
private int[] iGCbTab = new int[256];
|
||||
private int[] iGCrTab = new int[256];
|
||||
|
||||
private int chromaSubsampleH = 2;
|
||||
private int chromaSubsampleV = 2;
|
||||
|
||||
private boolean colorConvert;
|
||||
|
||||
private TIFFDecompressor decompressor;
|
||||
|
||||
private BufferedImage tmpImage;
|
||||
|
||||
//
|
||||
// If 'decompressor' is not null then it reads the data from the
|
||||
// actual stream first and passes the result on to YCrCr decompression
|
||||
// and possibly color conversion.
|
||||
//
|
||||
|
||||
public TIFFYCbCrDecompressor(TIFFDecompressor decompressor,
|
||||
boolean colorConvert) {
|
||||
this.decompressor = decompressor;
|
||||
this.colorConvert = colorConvert;
|
||||
}
|
||||
|
||||
private void warning(String message) {
|
||||
if(this.reader instanceof TIFFImageReader) {
|
||||
((TIFFImageReader)reader).forwardWarningMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// "Chained" decompressor methods.
|
||||
//
|
||||
|
||||
public void setReader(ImageReader reader) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setReader(reader);
|
||||
}
|
||||
super.setReader(reader);
|
||||
}
|
||||
|
||||
public void setMetadata(IIOMetadata metadata) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setMetadata(metadata);
|
||||
}
|
||||
super.setMetadata(metadata);
|
||||
}
|
||||
|
||||
public void setPhotometricInterpretation(int photometricInterpretation) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setPhotometricInterpretation(photometricInterpretation);
|
||||
}
|
||||
super.setPhotometricInterpretation(photometricInterpretation);
|
||||
}
|
||||
|
||||
public void setCompression(int compression) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setCompression(compression);
|
||||
}
|
||||
super.setCompression(compression);
|
||||
}
|
||||
|
||||
public void setPlanar(boolean planar) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setPlanar(planar);
|
||||
}
|
||||
super.setPlanar(planar);
|
||||
}
|
||||
|
||||
public void setSamplesPerPixel(int samplesPerPixel) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSamplesPerPixel(samplesPerPixel);
|
||||
}
|
||||
super.setSamplesPerPixel(samplesPerPixel);
|
||||
}
|
||||
|
||||
public void setBitsPerSample(int[] bitsPerSample) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setBitsPerSample(bitsPerSample);
|
||||
}
|
||||
super.setBitsPerSample(bitsPerSample);
|
||||
}
|
||||
|
||||
public void setSampleFormat(int[] sampleFormat) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSampleFormat(sampleFormat);
|
||||
}
|
||||
super.setSampleFormat(sampleFormat);
|
||||
}
|
||||
|
||||
public void setExtraSamples(int[] extraSamples) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setExtraSamples(extraSamples);
|
||||
}
|
||||
super.setExtraSamples(extraSamples);
|
||||
}
|
||||
|
||||
public void setColorMap(char[] colorMap) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setColorMap(colorMap);
|
||||
}
|
||||
super.setColorMap(colorMap);
|
||||
}
|
||||
|
||||
public void setStream(ImageInputStream stream) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setStream(stream);
|
||||
} else {
|
||||
super.setStream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOffset(long offset) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setOffset(offset);
|
||||
}
|
||||
super.setOffset(offset);
|
||||
}
|
||||
|
||||
public void setByteCount(int byteCount) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setByteCount(byteCount);
|
||||
}
|
||||
super.setByteCount(byteCount);
|
||||
}
|
||||
|
||||
public void setSrcMinX(int srcMinX) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSrcMinX(srcMinX);
|
||||
}
|
||||
super.setSrcMinX(srcMinX);
|
||||
}
|
||||
|
||||
public void setSrcMinY(int srcMinY) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSrcMinY(srcMinY);
|
||||
}
|
||||
super.setSrcMinY(srcMinY);
|
||||
}
|
||||
|
||||
public void setSrcWidth(int srcWidth) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSrcWidth(srcWidth);
|
||||
}
|
||||
super.setSrcWidth(srcWidth);
|
||||
}
|
||||
|
||||
public void setSrcHeight(int srcHeight) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSrcHeight(srcHeight);
|
||||
}
|
||||
super.setSrcHeight(srcHeight);
|
||||
}
|
||||
|
||||
public void setSourceXOffset(int sourceXOffset) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSourceXOffset(sourceXOffset);
|
||||
}
|
||||
super.setSourceXOffset(sourceXOffset);
|
||||
}
|
||||
|
||||
public void setDstXOffset(int dstXOffset) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstXOffset(dstXOffset);
|
||||
}
|
||||
super.setDstXOffset(dstXOffset);
|
||||
}
|
||||
|
||||
public void setSourceYOffset(int sourceYOffset) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSourceYOffset(sourceYOffset);
|
||||
}
|
||||
super.setSourceYOffset(sourceYOffset);
|
||||
}
|
||||
|
||||
public void setDstYOffset(int dstYOffset) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstYOffset(dstYOffset);
|
||||
}
|
||||
super.setDstYOffset(dstYOffset);
|
||||
}
|
||||
|
||||
/* Should not need to override these mutators as subsampling
|
||||
should not be done by the wrapped decompressor.
|
||||
public void setSubsampleX(int subsampleX) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSubsampleX(subsampleX);
|
||||
}
|
||||
super.setSubsampleX(subsampleX);
|
||||
}
|
||||
|
||||
public void setSubsampleY(int subsampleY) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSubsampleY(subsampleY);
|
||||
}
|
||||
super.setSubsampleY(subsampleY);
|
||||
}
|
||||
*/
|
||||
|
||||
public void setSourceBands(int[] sourceBands) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setSourceBands(sourceBands);
|
||||
}
|
||||
super.setSourceBands(sourceBands);
|
||||
}
|
||||
|
||||
public void setDestinationBands(int[] destinationBands) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDestinationBands(destinationBands);
|
||||
}
|
||||
super.setDestinationBands(destinationBands);
|
||||
}
|
||||
|
||||
public void setImage(BufferedImage image) {
|
||||
if(decompressor != null) {
|
||||
ColorModel cm = image.getColorModel();
|
||||
tmpImage =
|
||||
new BufferedImage(cm,
|
||||
image.getRaster().createCompatibleWritableRaster(1, 1),
|
||||
cm.isAlphaPremultiplied(),
|
||||
null);
|
||||
decompressor.setImage(tmpImage);
|
||||
}
|
||||
super.setImage(image);
|
||||
}
|
||||
|
||||
public void setDstMinX(int dstMinX) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstMinX(dstMinX);
|
||||
}
|
||||
super.setDstMinX(dstMinX);
|
||||
}
|
||||
|
||||
public void setDstMinY(int dstMinY) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstMinY(dstMinY);
|
||||
}
|
||||
super.setDstMinY(dstMinY);
|
||||
}
|
||||
|
||||
public void setDstWidth(int dstWidth) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstWidth(dstWidth);
|
||||
}
|
||||
super.setDstWidth(dstWidth);
|
||||
}
|
||||
|
||||
public void setDstHeight(int dstHeight) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setDstHeight(dstHeight);
|
||||
}
|
||||
super.setDstHeight(dstHeight);
|
||||
}
|
||||
|
||||
public void setActiveSrcMinX(int activeSrcMinX) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setActiveSrcMinX(activeSrcMinX);
|
||||
}
|
||||
super.setActiveSrcMinX(activeSrcMinX);
|
||||
}
|
||||
|
||||
public void setActiveSrcMinY(int activeSrcMinY) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setActiveSrcMinY(activeSrcMinY);
|
||||
}
|
||||
super.setActiveSrcMinY(activeSrcMinY);
|
||||
}
|
||||
|
||||
public void setActiveSrcWidth(int activeSrcWidth) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setActiveSrcWidth(activeSrcWidth);
|
||||
}
|
||||
super.setActiveSrcWidth(activeSrcWidth);
|
||||
}
|
||||
|
||||
public void setActiveSrcHeight(int activeSrcHeight) {
|
||||
if(decompressor != null) {
|
||||
decompressor.setActiveSrcHeight(activeSrcHeight);
|
||||
}
|
||||
super.setActiveSrcHeight(activeSrcHeight);
|
||||
}
|
||||
|
||||
private byte clamp(int f) {
|
||||
if (f < 0) {
|
||||
return (byte)0;
|
||||
} else if (f > 255*65536) {
|
||||
return (byte)255;
|
||||
} else {
|
||||
return (byte)(f >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginDecoding() {
|
||||
if(decompressor != null) {
|
||||
decompressor.beginDecoding();
|
||||
}
|
||||
|
||||
TIFFImageMetadata tmetadata = (TIFFImageMetadata)metadata;
|
||||
TIFFField f;
|
||||
|
||||
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_SUBSAMPLING);
|
||||
if (f != null) {
|
||||
if (f.getCount() == 2) {
|
||||
this.chromaSubsampleH = f.getAsInt(0);
|
||||
this.chromaSubsampleV = f.getAsInt(1);
|
||||
|
||||
if (chromaSubsampleH != 1 && chromaSubsampleH != 2 &&
|
||||
chromaSubsampleH != 4) {
|
||||
warning("Y_CB_CR_SUBSAMPLING[0] has illegal value " +
|
||||
chromaSubsampleH +
|
||||
" (should be 1, 2, or 4), setting to 1");
|
||||
chromaSubsampleH = 1;
|
||||
}
|
||||
|
||||
if (chromaSubsampleV != 1 && chromaSubsampleV != 2 &&
|
||||
chromaSubsampleV != 4) {
|
||||
warning("Y_CB_CR_SUBSAMPLING[1] has illegal value " +
|
||||
chromaSubsampleV +
|
||||
" (should be 1, 2, or 4), setting to 1");
|
||||
chromaSubsampleV = 1;
|
||||
}
|
||||
} else {
|
||||
warning("Y_CB_CR_SUBSAMPLING count != 2, " +
|
||||
"assuming no subsampling");
|
||||
}
|
||||
}
|
||||
|
||||
f =
|
||||
tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_Y_CB_CR_COEFFICIENTS);
|
||||
if (f != null) {
|
||||
if (f.getCount() == 3) {
|
||||
this.lumaRed = f.getAsFloat(0);
|
||||
this.lumaGreen = f.getAsFloat(1);
|
||||
this.lumaBlue = f.getAsFloat(2);
|
||||
} else {
|
||||
warning("Y_CB_CR_COEFFICIENTS count != 3, " +
|
||||
"assuming default values for CCIR 601-1");
|
||||
}
|
||||
}
|
||||
|
||||
f =
|
||||
tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE);
|
||||
if (f != null) {
|
||||
if (f.getCount() == 6) {
|
||||
this.referenceBlackY = f.getAsFloat(0);
|
||||
this.referenceWhiteY = f.getAsFloat(1);
|
||||
this.referenceBlackCb = f.getAsFloat(2);
|
||||
this.referenceWhiteCb = f.getAsFloat(3);
|
||||
this.referenceBlackCr = f.getAsFloat(4);
|
||||
this.referenceWhiteCr = f.getAsFloat(5);
|
||||
} else {
|
||||
warning("REFERENCE_BLACK_WHITE count != 6, ignoring it");
|
||||
}
|
||||
} else {
|
||||
warning("REFERENCE_BLACK_WHITE not found, assuming 0-255/128-255/128-255");
|
||||
}
|
||||
|
||||
this.colorConvert = true;
|
||||
|
||||
float BCb = (2.0f - 2.0f*lumaBlue);
|
||||
float RCr = (2.0f - 2.0f*lumaRed);
|
||||
|
||||
float GY = (1.0f - lumaBlue - lumaRed)/lumaGreen;
|
||||
float GCb = 2.0f*lumaBlue*(lumaBlue - 1.0f)/lumaGreen;
|
||||
float GCr = 2.0f*lumaRed*(lumaRed - 1.0f)/lumaGreen;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
float fY = (i - referenceBlackY)*codingRangeY/
|
||||
(referenceWhiteY - referenceBlackY);
|
||||
float fCb = (i - referenceBlackCb)*127.0f/
|
||||
(referenceWhiteCb - referenceBlackCb);
|
||||
float fCr = (i - referenceBlackCr)*127.0f/
|
||||
(referenceWhiteCr - referenceBlackCr);
|
||||
|
||||
iYTab[i] = (int)(fY*FRAC_SCALE);
|
||||
iCbTab[i] = (int)(fCb*BCb*FRAC_SCALE);
|
||||
iCrTab[i] = (int)(fCr*RCr*FRAC_SCALE);
|
||||
|
||||
iGYTab[i] = (int)(fY*GY*FRAC_SCALE);
|
||||
iGCbTab[i] = (int)(fCb*GCb*FRAC_SCALE);
|
||||
iGCrTab[i] = (int)(fCr*GCr*FRAC_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeRaw(byte[] buf,
|
||||
int dstOffset,
|
||||
int bitsPerPixel,
|
||||
int scanlineStride) throws IOException {
|
||||
int elementsPerPacket = chromaSubsampleH*chromaSubsampleV + 2;
|
||||
byte[] packet = new byte[elementsPerPacket];
|
||||
|
||||
if(decompressor != null) {
|
||||
int bytesPerRow = 3*srcWidth;
|
||||
byte[] tmpBuf = new byte[bytesPerRow*srcHeight];
|
||||
decompressor.decodeRaw(tmpBuf, dstOffset, bitsPerPixel,
|
||||
bytesPerRow);
|
||||
ByteArrayInputStream byteStream =
|
||||
new ByteArrayInputStream(tmpBuf);
|
||||
stream = new MemoryCacheImageInputStream(byteStream);
|
||||
} else {
|
||||
stream.seek(offset);
|
||||
}
|
||||
|
||||
for (int y = srcMinY; y < srcMinY + srcHeight; y += chromaSubsampleV) {
|
||||
// Decode chromaSubsampleV rows
|
||||
for (int x = srcMinX; x < srcMinX + srcWidth;
|
||||
x += chromaSubsampleH) {
|
||||
try {
|
||||
stream.readFully(packet);
|
||||
} catch (EOFException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte Cb = packet[elementsPerPacket - 2];
|
||||
byte Cr = packet[elementsPerPacket - 1];
|
||||
|
||||
int iCb = 0, iCr = 0, iGCb = 0, iGCr = 0;
|
||||
|
||||
if (colorConvert) {
|
||||
int Cbp = Cb & 0xff;
|
||||
int Crp = Cr & 0xff;
|
||||
|
||||
iCb = iCbTab[Cbp];
|
||||
iCr = iCrTab[Crp];
|
||||
|
||||
iGCb = iGCbTab[Cbp];
|
||||
iGCr = iGCrTab[Crp];
|
||||
}
|
||||
|
||||
int yIndex = 0;
|
||||
for (int v = 0; v < chromaSubsampleV; v++) {
|
||||
int idx = dstOffset + 3*(x - srcMinX) +
|
||||
scanlineStride*(y - srcMinY + v);
|
||||
|
||||
// Check if we reached the last scanline
|
||||
if (y + v >= srcMinY + srcHeight) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int h = 0; h < chromaSubsampleH; h++) {
|
||||
if (x + h >= srcMinX + srcWidth) {
|
||||
break;
|
||||
}
|
||||
|
||||
byte Y = packet[yIndex++];
|
||||
|
||||
if (colorConvert) {
|
||||
int Yp = Y & 0xff;
|
||||
int iY = iYTab[Yp];
|
||||
int iGY = iGYTab[Yp];
|
||||
|
||||
int iR = iY + iCr;
|
||||
int iG = iGY + iGCb + iGCr;
|
||||
int iB = iY + iCb;
|
||||
|
||||
byte r = clamp(iR);
|
||||
byte g = clamp(iG);
|
||||
byte b = clamp(iB);
|
||||
|
||||
buf[idx] = r;
|
||||
buf[idx + 1] = g;
|
||||
buf[idx + 2] = b;
|
||||
} else {
|
||||
buf[idx] = Y;
|
||||
buf[idx + 1] = Cb;
|
||||
buf[idx + 2] = Cr;
|
||||
}
|
||||
|
||||
idx += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.imageio.plugins.tiff;
|
||||
|
||||
import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
|
||||
/**
|
||||
* Compressor for ZLib compression.
|
||||
*/
|
||||
public class TIFFZLibCompressor extends TIFFDeflater {
|
||||
public TIFFZLibCompressor(ImageWriteParam param, int predictor) {
|
||||
super("ZLib", BaselineTIFFTagSet.COMPRESSION_ZLIB, param, predictor);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
@ -81,6 +81,11 @@ Each of the standard plug-ins supports a so-called "native" metadata
|
||||
format, which encodes its metadata losslessly:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<A HREF="doc-files/bmp_metadata.html">
|
||||
BMP metadata
|
||||
</A>
|
||||
|
||||
<li>
|
||||
<A HREF="doc-files/gif_metadata.html">
|
||||
GIF metadata
|
||||
@ -97,8 +102,8 @@ PNG metadata
|
||||
</A>
|
||||
|
||||
<li>
|
||||
<A HREF="doc-files/bmp_metadata.html">
|
||||
BMP metadata
|
||||
<A HREF="doc-files/tiff_metadata.html#StreamMetadata">
|
||||
TIFF metadata
|
||||
</A>
|
||||
|
||||
<li>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,724 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing the tags found in an Exif GPS Info IFD.
|
||||
*
|
||||
* <p> The definitions of the data types referenced by the field
|
||||
* definitions may be found in the {@link TIFFTag TIFFTag} class.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see ExifTIFFTagSet
|
||||
*/
|
||||
public class ExifGPSTagSet extends TIFFTagSet {
|
||||
private static ExifGPSTagSet theInstance = null;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS tag version (type BYTE, count = 4).
|
||||
*
|
||||
* @see #GPS_VERSION_2_2
|
||||
*/
|
||||
public static final int TAG_GPS_VERSION_ID = 0;
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSVersionID" tag to indicate GPS version
|
||||
* 2.2. The value equals the US-ASCII encoding of the byte array
|
||||
* <code>{'2', '2', '0', '0'}</code>.
|
||||
*
|
||||
* @see #TAG_GPS_VERSION_ID
|
||||
*/
|
||||
public static final String GPS_VERSION_2_2 =
|
||||
new String(new byte[] { '2', '2', '0', '0' },
|
||||
StandardCharsets.US_ASCII);
|
||||
|
||||
/**
|
||||
* A tag indicating the North or South latitude (type ASCII, count = 2).
|
||||
*
|
||||
* @see #LATITUDE_REF_NORTH
|
||||
* @see #LATITUDE_REF_SOUTH
|
||||
*/
|
||||
public static final int TAG_GPS_LATITUDE_REF = 1;
|
||||
|
||||
/**
|
||||
* A tag indicating the Latitude (type RATIONAL, count = 3).
|
||||
*/
|
||||
public static final int TAG_GPS_LATITUDE = 2;
|
||||
|
||||
/**
|
||||
* A tag indicating the East or West Longitude (type ASCII, count = 2).
|
||||
*
|
||||
* @see #LONGITUDE_REF_EAST
|
||||
* @see #LONGITUDE_REF_WEST
|
||||
*/
|
||||
public static final int TAG_GPS_LONGITUDE_REF = 3;
|
||||
|
||||
/**
|
||||
* A tag indicating the Longitude (type RATIONAL, count = 3).
|
||||
*/
|
||||
public static final int TAG_GPS_LONGITUDE = 4;
|
||||
|
||||
/**
|
||||
* A tag indicating the Altitude reference (type BYTE, count = 1);
|
||||
*
|
||||
* @see #ALTITUDE_REF_SEA_LEVEL
|
||||
* @see #ALTITUDE_REF_SEA_LEVEL_REFERENCE
|
||||
*/
|
||||
public static final int TAG_GPS_ALTITUDE_REF = 5;
|
||||
|
||||
/**
|
||||
* A tag indicating the Altitude (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_ALTITUDE = 6;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS time (atomic clock) (type RATIONAL, count = 3).
|
||||
*/
|
||||
public static final int TAG_GPS_TIME_STAMP = 7;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS satellites used for measurement (type ASCII).
|
||||
*/
|
||||
public static final int TAG_GPS_SATELLITES = 8;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS receiver status (type ASCII, count = 2).
|
||||
*
|
||||
* @see #STATUS_MEASUREMENT_IN_PROGRESS
|
||||
* @see #STATUS_MEASUREMENT_INTEROPERABILITY
|
||||
*/
|
||||
public static final int TAG_GPS_STATUS = 9;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS measurement mode (type ASCII, count = 2).
|
||||
*
|
||||
* @see #MEASURE_MODE_2D
|
||||
* @see #MEASURE_MODE_3D
|
||||
*/
|
||||
public static final int TAG_GPS_MEASURE_MODE = 10;
|
||||
|
||||
/**
|
||||
* A tag indicating the Measurement precision (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_DOP = 11;
|
||||
|
||||
/**
|
||||
* A tag indicating the Speed unit (type ASCII, count = 2).
|
||||
*
|
||||
* @see #SPEED_REF_KILOMETERS_PER_HOUR
|
||||
* @see #SPEED_REF_MILES_PER_HOUR
|
||||
* @see #SPEED_REF_KNOTS
|
||||
*/
|
||||
public static final int TAG_GPS_SPEED_REF = 12;
|
||||
|
||||
/**
|
||||
* A tag indicating the Speed of GPS receiver (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_SPEED = 13;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for direction of movement (type ASCII,
|
||||
* count = 2).
|
||||
*
|
||||
* @see #DIRECTION_REF_TRUE
|
||||
* @see #DIRECTION_REF_MAGNETIC
|
||||
*/
|
||||
public static final int TAG_GPS_TRACK_REF = 14;
|
||||
|
||||
/**
|
||||
* A tag indicating the Direction of movement (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_TRACK = 15;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for direction of image (type ASCII,
|
||||
* count = 2).
|
||||
*
|
||||
* @see #DIRECTION_REF_TRUE
|
||||
* @see #DIRECTION_REF_MAGNETIC
|
||||
*/
|
||||
public static final int TAG_GPS_IMG_DIRECTION_REF = 16;
|
||||
|
||||
/**
|
||||
* A tag indicating the Direction of image (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_IMG_DIRECTION = 17;
|
||||
|
||||
/**
|
||||
* A tag indicating the Geodetic survey data used (type ASCII).
|
||||
*/
|
||||
public static final int TAG_GPS_MAP_DATUM = 18;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for latitude of destination (type
|
||||
* ASCII, count = 2).
|
||||
*
|
||||
* @see #LATITUDE_REF_NORTH
|
||||
* @see #LATITUDE_REF_SOUTH
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_LATITUDE_REF = 19;
|
||||
|
||||
/**
|
||||
* A tag indicating the Latitude of destination (type RATIONAL, count = 3).
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_LATITUDE = 20;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for longitude of destination (type
|
||||
* ASCII, count = 2).
|
||||
*
|
||||
* @see #LONGITUDE_REF_EAST
|
||||
* @see #LONGITUDE_REF_WEST
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_LONGITUDE_REF = 21;
|
||||
|
||||
/**
|
||||
* A tag indicating the Longitude of destination (type RATIONAL,
|
||||
* count = 3).
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_LONGITUDE = 22;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for bearing of destination (type ASCII,
|
||||
* count = 2).
|
||||
*
|
||||
* @see #DIRECTION_REF_TRUE
|
||||
* @see #DIRECTION_REF_MAGNETIC
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_BEARING_REF = 23;
|
||||
|
||||
/**
|
||||
* A tag indicating the Bearing of destination (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_BEARING = 24;
|
||||
|
||||
/**
|
||||
* A tag indicating the Reference for distance to destination (type ASCII,
|
||||
* count = 2).
|
||||
*
|
||||
* @see #DEST_DISTANCE_REF_KILOMETERS
|
||||
* @see #DEST_DISTANCE_REF_MILES
|
||||
* @see #DEST_DISTANCE_REF_KNOTS
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_DISTANCE_REF = 25;
|
||||
|
||||
/**
|
||||
* A tag indicating the Distance to destination (type RATIONAL, count = 1).
|
||||
*/
|
||||
public static final int TAG_GPS_DEST_DISTANCE = 26;
|
||||
|
||||
/**
|
||||
* A tag indicating the Name of GPS processing method (type UNDEFINED).
|
||||
*/
|
||||
public static final int TAG_GPS_PROCESSING_METHOD = 27;
|
||||
|
||||
/**
|
||||
* A tag indicating the Name of GPS area (type UNDEFINED).
|
||||
*/
|
||||
public static final int TAG_GPS_AREA_INFORMATION = 28;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS date (type ASCII, count 11).
|
||||
*/
|
||||
public static final int TAG_GPS_DATE_STAMP = 29;
|
||||
|
||||
/**
|
||||
* A tag indicating the GPS differential correction (type SHORT,
|
||||
* count = 1).
|
||||
*
|
||||
* @see #DIFFERENTIAL_CORRECTION_NONE
|
||||
* @see #DIFFERENTIAL_CORRECTION_APPLIED
|
||||
*/
|
||||
public static final int TAG_GPS_DIFFERENTIAL = 30;
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSLatitudeRef" and
|
||||
* "GPSDestLatitudeRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_LATITUDE_REF
|
||||
* @see #TAG_GPS_DEST_LATITUDE_REF
|
||||
*/
|
||||
public static final String LATITUDE_REF_NORTH = "N";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSLatitudeRef" and
|
||||
* "GPSDestLatitudeRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_LATITUDE_REF
|
||||
* @see #TAG_GPS_DEST_LATITUDE_REF
|
||||
*/
|
||||
public static final String LATITUDE_REF_SOUTH = "S";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSLongitudeRef" and
|
||||
* "GPSDestLongitudeRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_LONGITUDE_REF
|
||||
* @see #TAG_GPS_DEST_LONGITUDE_REF
|
||||
*/
|
||||
public static final String LONGITUDE_REF_EAST = "E";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSLongitudeRef" and
|
||||
* "GPSDestLongitudeRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_LONGITUDE_REF
|
||||
* @see #TAG_GPS_DEST_LONGITUDE_REF
|
||||
*/
|
||||
public static final String LONGITUDE_REF_WEST = "W";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSAltitudeRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_ALTITUDE_REF
|
||||
*/
|
||||
public static final int ALTITUDE_REF_SEA_LEVEL = 0;
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSAltitudeRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_ALTITUDE_REF
|
||||
*/
|
||||
public static final int ALTITUDE_REF_SEA_LEVEL_REFERENCE = 1;
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSStatus" tag.
|
||||
*
|
||||
* @see #TAG_GPS_STATUS
|
||||
*/
|
||||
public static final String STATUS_MEASUREMENT_IN_PROGRESS = "A";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSStatus" tag.
|
||||
*
|
||||
* @see #TAG_GPS_STATUS
|
||||
*/
|
||||
public static final String STATUS_MEASUREMENT_INTEROPERABILITY = "V";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSMeasureMode" tag.
|
||||
*
|
||||
* @see #TAG_GPS_MEASURE_MODE
|
||||
*/
|
||||
public static final String MEASURE_MODE_2D = "2";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSMeasureMode" tag.
|
||||
*
|
||||
* @see #TAG_GPS_MEASURE_MODE
|
||||
*/
|
||||
public static final String MEASURE_MODE_3D = "3";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSSpeedRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_SPEED_REF
|
||||
*/
|
||||
public static final String SPEED_REF_KILOMETERS_PER_HOUR = "K";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSSpeedRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_SPEED_REF
|
||||
*/
|
||||
public static final String SPEED_REF_MILES_PER_HOUR = "M";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSSpeedRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_SPEED_REF
|
||||
*/
|
||||
public static final String SPEED_REF_KNOTS = "N";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSTrackRef", "GPSImgDirectionRef",
|
||||
* and "GPSDestBearingRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_TRACK_REF
|
||||
* @see #TAG_GPS_IMG_DIRECTION_REF
|
||||
* @see #TAG_GPS_DEST_BEARING_REF
|
||||
*/
|
||||
public static final String DIRECTION_REF_TRUE = "T";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSTrackRef", "GPSImgDirectionRef",
|
||||
* and "GPSDestBearingRef" tags.
|
||||
*
|
||||
* @see #TAG_GPS_TRACK_REF
|
||||
* @see #TAG_GPS_IMG_DIRECTION_REF
|
||||
* @see #TAG_GPS_DEST_BEARING_REF
|
||||
*/
|
||||
public static final String DIRECTION_REF_MAGNETIC = "M";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSDestDistanceRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_DEST_DISTANCE_REF
|
||||
*/
|
||||
public static final String DEST_DISTANCE_REF_KILOMETERS = "K";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSDestDistanceRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_DEST_DISTANCE_REF
|
||||
*/
|
||||
public static final String DEST_DISTANCE_REF_MILES = "M";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSDestDistanceRef" tag.
|
||||
*
|
||||
* @see #TAG_GPS_DEST_DISTANCE_REF
|
||||
*/
|
||||
public static final String DEST_DISTANCE_REF_KNOTS = "N";
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSDifferential" tag.
|
||||
*
|
||||
* @see #TAG_GPS_DIFFERENTIAL
|
||||
*/
|
||||
public static final int DIFFERENTIAL_CORRECTION_NONE = 0;
|
||||
|
||||
/**
|
||||
* A value to be used with the "GPSDifferential" tag.
|
||||
*
|
||||
* @see #TAG_GPS_DIFFERENTIAL
|
||||
*/
|
||||
public static final int DIFFERENTIAL_CORRECTION_APPLIED = 1;
|
||||
|
||||
static class GPSVersionID extends TIFFTag {
|
||||
public GPSVersionID() {
|
||||
super("GPSVersionID",
|
||||
TAG_GPS_VERSION_ID,
|
||||
1 << TIFFTag.TIFF_BYTE);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSLatitudeRef extends TIFFTag {
|
||||
public GPSLatitudeRef() {
|
||||
super("GPSLatitudeRef",
|
||||
TAG_GPS_LATITUDE_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSLatitude extends TIFFTag {
|
||||
public GPSLatitude() {
|
||||
super("GPSLatitude",
|
||||
TAG_GPS_LATITUDE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSLongitudeRef extends TIFFTag {
|
||||
public GPSLongitudeRef() {
|
||||
super("GPSLongitudeRef",
|
||||
TAG_GPS_LONGITUDE_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSLongitude extends TIFFTag {
|
||||
public GPSLongitude() {
|
||||
super("GPSLongitude",
|
||||
TAG_GPS_LONGITUDE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSAltitudeRef extends TIFFTag {
|
||||
public GPSAltitudeRef() {
|
||||
super("GPSAltitudeRef",
|
||||
TAG_GPS_ALTITUDE_REF,
|
||||
1 << TIFFTag.TIFF_BYTE);
|
||||
|
||||
addValueName(ALTITUDE_REF_SEA_LEVEL, "Sea level");
|
||||
addValueName(ALTITUDE_REF_SEA_LEVEL_REFERENCE,
|
||||
"Sea level reference (negative value)");
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSAltitude extends TIFFTag {
|
||||
public GPSAltitude() {
|
||||
super("GPSAltitude",
|
||||
TAG_GPS_ALTITUDE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSTimeStamp extends TIFFTag {
|
||||
public GPSTimeStamp() {
|
||||
super("GPSTimeStamp",
|
||||
TAG_GPS_TIME_STAMP,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSSatellites extends TIFFTag {
|
||||
public GPSSatellites() {
|
||||
super("GPSSatellites",
|
||||
TAG_GPS_SATELLITES,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSStatus extends TIFFTag {
|
||||
public GPSStatus() {
|
||||
super("GPSStatus",
|
||||
TAG_GPS_STATUS,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSMeasureMode extends TIFFTag {
|
||||
public GPSMeasureMode() {
|
||||
super("GPSMeasureMode",
|
||||
TAG_GPS_MEASURE_MODE,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDOP extends TIFFTag {
|
||||
public GPSDOP() {
|
||||
super("GPSDOP",
|
||||
TAG_GPS_DOP,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSSpeedRef extends TIFFTag {
|
||||
public GPSSpeedRef() {
|
||||
super("GPSSpeedRef",
|
||||
TAG_GPS_SPEED_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSSpeed extends TIFFTag {
|
||||
public GPSSpeed() {
|
||||
super("GPSSpeed",
|
||||
TAG_GPS_SPEED,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSTrackRef extends TIFFTag {
|
||||
public GPSTrackRef() {
|
||||
super("GPSTrackRef",
|
||||
TAG_GPS_TRACK_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSTrack extends TIFFTag {
|
||||
public GPSTrack() {
|
||||
super("GPSTrack",
|
||||
TAG_GPS_TRACK,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSImgDirectionRef extends TIFFTag {
|
||||
public GPSImgDirectionRef() {
|
||||
super("GPSImgDirectionRef",
|
||||
TAG_GPS_IMG_DIRECTION_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSImgDirection extends TIFFTag {
|
||||
public GPSImgDirection() {
|
||||
super("GPSImgDirection",
|
||||
TAG_GPS_IMG_DIRECTION,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSMapDatum extends TIFFTag {
|
||||
public GPSMapDatum() {
|
||||
super("GPSMapDatum",
|
||||
TAG_GPS_MAP_DATUM,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestLatitudeRef extends TIFFTag {
|
||||
public GPSDestLatitudeRef() {
|
||||
super("GPSDestLatitudeRef",
|
||||
TAG_GPS_DEST_LATITUDE_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestLatitude extends TIFFTag {
|
||||
public GPSDestLatitude() {
|
||||
super("GPSDestLatitude",
|
||||
TAG_GPS_DEST_LATITUDE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestLongitudeRef extends TIFFTag {
|
||||
public GPSDestLongitudeRef() {
|
||||
super("GPSDestLongitudeRef",
|
||||
TAG_GPS_DEST_LONGITUDE_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestLongitude extends TIFFTag {
|
||||
public GPSDestLongitude() {
|
||||
super("GPSDestLongitude",
|
||||
TAG_GPS_DEST_LONGITUDE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestBearingRef extends TIFFTag {
|
||||
public GPSDestBearingRef() {
|
||||
super("GPSDestBearingRef",
|
||||
TAG_GPS_DEST_BEARING_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestBearing extends TIFFTag {
|
||||
public GPSDestBearing() {
|
||||
super("GPSDestBearing",
|
||||
TAG_GPS_DEST_BEARING,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestDistanceRef extends TIFFTag {
|
||||
public GPSDestDistanceRef() {
|
||||
super("GPSDestDistanceRef",
|
||||
TAG_GPS_DEST_DISTANCE_REF,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDestDistance extends TIFFTag {
|
||||
public GPSDestDistance() {
|
||||
super("GPSDestDistance",
|
||||
TAG_GPS_DEST_DISTANCE,
|
||||
1 << TIFFTag.TIFF_RATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSProcessingMethod extends TIFFTag {
|
||||
public GPSProcessingMethod() {
|
||||
super("GPSProcessingMethod",
|
||||
TAG_GPS_PROCESSING_METHOD,
|
||||
1 << TIFFTag.TIFF_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSAreaInformation extends TIFFTag {
|
||||
public GPSAreaInformation() {
|
||||
super("GPSAreaInformation",
|
||||
TAG_GPS_AREA_INFORMATION,
|
||||
1 << TIFFTag.TIFF_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDateStamp extends TIFFTag {
|
||||
public GPSDateStamp() {
|
||||
super("GPSDateStamp",
|
||||
TAG_GPS_DATE_STAMP,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
static class GPSDifferential extends TIFFTag {
|
||||
public GPSDifferential() {
|
||||
super("GPSDifferential",
|
||||
TAG_GPS_DIFFERENTIAL,
|
||||
1 << TIFFTag.TIFF_SHORT);
|
||||
addValueName(DIFFERENTIAL_CORRECTION_NONE,
|
||||
"Measurement without differential correction");
|
||||
addValueName(DIFFERENTIAL_CORRECTION_APPLIED,
|
||||
"Differential correction applied");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TIFFTag> initTags() {
|
||||
ArrayList<TIFFTag> tags = new ArrayList<TIFFTag>(31);
|
||||
|
||||
tags.add(new GPSVersionID());
|
||||
tags.add(new GPSLatitudeRef());
|
||||
tags.add(new GPSLatitude());
|
||||
tags.add(new GPSLongitudeRef());
|
||||
tags.add(new GPSLongitude());
|
||||
tags.add(new GPSAltitudeRef());
|
||||
tags.add(new GPSAltitude());
|
||||
tags.add(new GPSTimeStamp());
|
||||
tags.add(new GPSSatellites());
|
||||
tags.add(new GPSStatus());
|
||||
tags.add(new GPSMeasureMode());
|
||||
tags.add(new GPSDOP());
|
||||
tags.add(new GPSSpeedRef());
|
||||
tags.add(new GPSSpeed());
|
||||
tags.add(new GPSTrackRef());
|
||||
tags.add(new GPSTrack());
|
||||
tags.add(new GPSImgDirectionRef());
|
||||
tags.add(new GPSImgDirection());
|
||||
tags.add(new GPSMapDatum());
|
||||
tags.add(new GPSDestLatitudeRef());
|
||||
tags.add(new GPSDestLatitude());
|
||||
tags.add(new GPSDestLongitudeRef());
|
||||
tags.add(new GPSDestLongitude());
|
||||
tags.add(new GPSDestBearingRef());
|
||||
tags.add(new GPSDestBearing());
|
||||
tags.add(new GPSDestDistanceRef());
|
||||
tags.add(new GPSDestDistance());
|
||||
tags.add(new GPSProcessingMethod());
|
||||
tags.add(new GPSAreaInformation());
|
||||
tags.add(new GPSDateStamp());
|
||||
tags.add(new GPSDifferential());
|
||||
return tags;
|
||||
}
|
||||
|
||||
private ExifGPSTagSet() {
|
||||
super(initTags());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of an <code>ExifGPSTagSet</code>.
|
||||
*
|
||||
* @return an <code>ExifGPSTagSet</code> instance.
|
||||
*/
|
||||
public synchronized static ExifGPSTagSet getInstance() {
|
||||
if (theInstance == null) {
|
||||
theInstance = new ExifGPSTagSet();
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing the tags found in an Exif Interoperability IFD.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see ExifTIFFTagSet
|
||||
*/
|
||||
public class ExifInteroperabilityTagSet extends TIFFTagSet {
|
||||
/**
|
||||
* A tag indicating the identification of the Interoperability rule
|
||||
* (type ASCII).
|
||||
*
|
||||
* @see #INTEROPERABILITY_INDEX_R98
|
||||
* @see #INTEROPERABILITY_INDEX_THM
|
||||
*/
|
||||
public static final int TAG_INTEROPERABILITY_INDEX = 1;
|
||||
|
||||
/**
|
||||
* A value to be used with the "InteroperabilityIndex" tag. Indicates
|
||||
* a file conforming to the R98 file specification of Recommended Exif
|
||||
* Interoperability Rules (ExifR98) or to the DCF basic file stipulated
|
||||
* by the Design Rule for Camera File System (type ASCII).
|
||||
*
|
||||
* @see #TAG_INTEROPERABILITY_INDEX
|
||||
*/
|
||||
public static final String INTEROPERABILITY_INDEX_R98 = "R98";
|
||||
|
||||
/**
|
||||
* A value to be used with the "InteroperabilityIndex" tag. Indicates
|
||||
* a file conforming to the DCF thumbnail file stipulated by the Design
|
||||
* rule for Camera File System (type ASCII).
|
||||
*
|
||||
* @see #TAG_INTEROPERABILITY_INDEX
|
||||
*/
|
||||
public static final String INTEROPERABILITY_INDEX_THM = "THM";
|
||||
|
||||
private static ExifInteroperabilityTagSet theInstance = null;
|
||||
|
||||
static class InteroperabilityIndex extends TIFFTag {
|
||||
|
||||
public InteroperabilityIndex() {
|
||||
super("InteroperabilityIndex",
|
||||
TAG_INTEROPERABILITY_INDEX,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TIFFTag> tags;
|
||||
|
||||
private static void initTags() {
|
||||
tags = new ArrayList<TIFFTag>(42);
|
||||
|
||||
tags.add(new ExifInteroperabilityTagSet.InteroperabilityIndex());
|
||||
}
|
||||
|
||||
private ExifInteroperabilityTagSet() {
|
||||
super(tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared instance of
|
||||
* <code>ExifInteroperabilityTagSet</code>.
|
||||
*
|
||||
* @return the <code>ExifInteroperabilityTagSet</code> instance.
|
||||
*/
|
||||
public synchronized static ExifInteroperabilityTagSet getInstance() {
|
||||
if (theInstance == null) {
|
||||
initTags();
|
||||
theInstance = new ExifInteroperabilityTagSet();
|
||||
tags = null;
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class containing the TIFF tags used to reference the Exif and GPS IFDs.
|
||||
* This tag set should be added to the root tag set by means of the
|
||||
* {@link TIFFImageReadParam#addAllowedTagSet(TIFFTagSet)
|
||||
* TIFFImageReadParam.addAllowedTagSet} method if Exif
|
||||
* support is desired.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public class ExifParentTIFFTagSet extends TIFFTagSet {
|
||||
|
||||
private static ExifParentTIFFTagSet theInstance = null;
|
||||
|
||||
// 34665 - Exif IFD Pointer (LONG/1)
|
||||
/** Tag pointing to the Exif IFD (type LONG). */
|
||||
public static final int TAG_EXIF_IFD_POINTER = 34665;
|
||||
|
||||
/** Tag pointing to a GPS info IFD (type LONG). */
|
||||
public static final int TAG_GPS_INFO_IFD_POINTER = 34853;
|
||||
|
||||
// To be inserted into parent (root) TIFFTagSet
|
||||
static class ExifIFDPointer extends TIFFTag {
|
||||
|
||||
public ExifIFDPointer() {
|
||||
super("ExifIFDPointer",
|
||||
TAG_EXIF_IFD_POINTER,
|
||||
ExifTIFFTagSet.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
// To be inserted into parent (root) TIFFTagSet
|
||||
static class GPSInfoIFDPointer extends TIFFTag {
|
||||
|
||||
public GPSInfoIFDPointer() {
|
||||
super("GPSInfoIFDPointer",
|
||||
TAG_GPS_INFO_IFD_POINTER,
|
||||
ExifGPSTagSet.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TIFFTag> tags;
|
||||
|
||||
private static void initTags() {
|
||||
tags = new ArrayList<TIFFTag>(1);
|
||||
tags.add(new ExifParentTIFFTagSet.ExifIFDPointer());
|
||||
tags.add(new ExifParentTIFFTagSet.GPSInfoIFDPointer());
|
||||
}
|
||||
|
||||
private ExifParentTIFFTagSet() {
|
||||
super(tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of an <code>ExifParentTIFFTagSet</code>.
|
||||
*
|
||||
* @return an <code>ExifParentTIFFTagSet</code> instance.
|
||||
*/
|
||||
public synchronized static ExifParentTIFFTagSet getInstance() {
|
||||
if (theInstance == null) {
|
||||
initTags();
|
||||
theInstance = new ExifParentTIFFTagSet();
|
||||
tags = null;
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing the extra tags found in a
|
||||
* <a href="http://tools.ietf.org/html/rfc2306"> TIFF-F</a> (RFC 2036) file.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public class FaxTIFFTagSet extends TIFFTagSet {
|
||||
|
||||
private static FaxTIFFTagSet theInstance = null;
|
||||
|
||||
/** Tag indicating the number of bad fax lines (type SHORT or LONG). */
|
||||
public static final int TAG_BAD_FAX_LINES = 326;
|
||||
|
||||
/**
|
||||
* Tag indicating the number of lines of clean fax data (type
|
||||
* SHORT).
|
||||
*
|
||||
* @see #CLEAN_FAX_DATA_NO_ERRORS
|
||||
* @see #CLEAN_FAX_DATA_ERRORS_CORRECTED
|
||||
* @see #CLEAN_FAX_DATA_ERRORS_UNCORRECTED
|
||||
*/
|
||||
public static final int TAG_CLEAN_FAX_DATA = 327;
|
||||
|
||||
/**
|
||||
* A value to be used with the "CleanFaxData" tag.
|
||||
*
|
||||
* @see #TAG_CLEAN_FAX_DATA
|
||||
*/
|
||||
public static final int CLEAN_FAX_DATA_NO_ERRORS = 0;
|
||||
|
||||
/**
|
||||
* A value to be used with the "CleanFaxData" tag.
|
||||
*
|
||||
* @see #TAG_CLEAN_FAX_DATA
|
||||
*/
|
||||
public static final int CLEAN_FAX_DATA_ERRORS_CORRECTED = 1;
|
||||
|
||||
/**
|
||||
* A value to be used with the "CleanFaxData" tag.
|
||||
*
|
||||
* @see #TAG_CLEAN_FAX_DATA
|
||||
*/
|
||||
public static final int CLEAN_FAX_DATA_ERRORS_UNCORRECTED = 2;
|
||||
|
||||
/**
|
||||
* Tag indicating the number of consecutive bad lines (type
|
||||
* SHORT or LONG).
|
||||
*/
|
||||
public static final int TAG_CONSECUTIVE_BAD_LINES = 328;
|
||||
|
||||
static class BadFaxLines extends TIFFTag {
|
||||
|
||||
public BadFaxLines() {
|
||||
super("BadFaxLines",
|
||||
TAG_BAD_FAX_LINES,
|
||||
1 << TIFF_SHORT |
|
||||
1 << TIFF_LONG,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
static class CleanFaxData extends TIFFTag {
|
||||
|
||||
public CleanFaxData() {
|
||||
super("CleanFaxData",
|
||||
TAG_CLEAN_FAX_DATA,
|
||||
1 << TIFF_SHORT,
|
||||
1);
|
||||
|
||||
addValueName(CLEAN_FAX_DATA_NO_ERRORS,
|
||||
"No errors");
|
||||
addValueName(CLEAN_FAX_DATA_ERRORS_CORRECTED,
|
||||
"Errors corrected");
|
||||
addValueName(CLEAN_FAX_DATA_ERRORS_UNCORRECTED,
|
||||
"Errors uncorrected");
|
||||
}
|
||||
}
|
||||
|
||||
static class ConsecutiveBadFaxLines extends TIFFTag {
|
||||
|
||||
public ConsecutiveBadFaxLines() {
|
||||
super("ConsecutiveBadFaxLines",
|
||||
TAG_CONSECUTIVE_BAD_LINES,
|
||||
1 << TIFF_SHORT |
|
||||
1 << TIFF_LONG,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TIFFTag> tags;
|
||||
|
||||
private static void initTags() {
|
||||
tags = new ArrayList<TIFFTag>(42);
|
||||
|
||||
tags.add(new FaxTIFFTagSet.BadFaxLines());
|
||||
tags.add(new FaxTIFFTagSet.CleanFaxData());
|
||||
tags.add(new FaxTIFFTagSet.ConsecutiveBadFaxLines());
|
||||
}
|
||||
|
||||
private FaxTIFFTagSet() {
|
||||
super(tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of a <code>FaxTIFFTagSet</code>.
|
||||
*
|
||||
* @return a <code>FaxTIFFTagSet</code> instance.
|
||||
*/
|
||||
public synchronized static FaxTIFFTagSet getInstance() {
|
||||
if (theInstance == null) {
|
||||
initTags();
|
||||
theInstance = new FaxTIFFTagSet();
|
||||
tags = null;
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing the tags found in a GeoTIFF IFD. GeoTIFF is a
|
||||
* standard for annotating georeferenced or geocoded raster imagery.
|
||||
* The GeoTIFF specification may be found at <a
|
||||
* href="http://www.remotesensing.org/geotiff/spec/geotiffhome.html">
|
||||
* <code>http://www.remotesensing.org/geotiff/spec/geotiffhome.html</code>
|
||||
* </a>. This class does <i>not</i> handle the <i>GeoKey</i>s referenced
|
||||
* from a <i>GeoKeyDirectoryTag</i> as those are not TIFF tags per se.
|
||||
*
|
||||
* <p>The definitions of the data types referenced by the field
|
||||
* definitions may be found in the {@link TIFFTag TIFFTag} class.</p>
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public class GeoTIFFTagSet extends TIFFTagSet {
|
||||
|
||||
private static GeoTIFFTagSet theInstance = null;
|
||||
|
||||
/**
|
||||
* A tag used to specify the size of raster pixel spacing in
|
||||
* model space units.
|
||||
*/
|
||||
public static final int TAG_MODEL_PIXEL_SCALE = 33550;
|
||||
|
||||
/**
|
||||
* A tag used to specify the transformation matrix between the raster
|
||||
* space and the model space.
|
||||
*/
|
||||
public static final int TAG_MODEL_TRANSFORMATION = 34264;
|
||||
|
||||
/** A tag used to store raster-to-model tiepoint pairs. */
|
||||
public static final int TAG_MODEL_TIE_POINT = 33922;
|
||||
|
||||
/** A tag used to store the <i>GeoKey</i> directory. */
|
||||
public static final int TAG_GEO_KEY_DIRECTORY = 34735;
|
||||
|
||||
/** A tag used to store all <code>double</code>-values <i>GeoKey</i>s. */
|
||||
public static final int TAG_GEO_DOUBLE_PARAMS = 34736;
|
||||
|
||||
/** A tag used to store all ASCII-values <i>GeoKey</i>s. */
|
||||
public static final int TAG_GEO_ASCII_PARAMS = 34737;
|
||||
|
||||
// GeoTIFF tags
|
||||
|
||||
static class ModelPixelScale extends TIFFTag {
|
||||
public ModelPixelScale() {
|
||||
super("ModelPixelScaleTag",
|
||||
TAG_MODEL_PIXEL_SCALE,
|
||||
1 << TIFFTag.TIFF_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class ModelTransformation extends TIFFTag {
|
||||
public ModelTransformation() {
|
||||
super("ModelTransformationTag",
|
||||
TAG_MODEL_TRANSFORMATION,
|
||||
1 << TIFFTag.TIFF_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class ModelTiePoint extends TIFFTag {
|
||||
public ModelTiePoint() {
|
||||
super("ModelTiePointTag",
|
||||
TAG_MODEL_TIE_POINT,
|
||||
1 << TIFFTag.TIFF_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class GeoKeyDirectory extends TIFFTag {
|
||||
public GeoKeyDirectory() {
|
||||
super("GeoKeyDirectory",
|
||||
TAG_GEO_KEY_DIRECTORY,
|
||||
1 << TIFFTag.TIFF_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
static class GeoDoubleParams extends TIFFTag {
|
||||
public GeoDoubleParams() {
|
||||
super("GeoDoubleParams",
|
||||
TAG_GEO_DOUBLE_PARAMS,
|
||||
1 << TIFFTag.TIFF_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class GeoAsciiParams extends TIFFTag {
|
||||
public GeoAsciiParams() {
|
||||
super("GeoAsciiParams",
|
||||
TAG_GEO_ASCII_PARAMS,
|
||||
1 << TIFFTag.TIFF_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TIFFTag> tags;
|
||||
|
||||
private static void initTags() {
|
||||
tags = new ArrayList<TIFFTag>(42);
|
||||
|
||||
tags.add(new GeoTIFFTagSet.ModelPixelScale());
|
||||
tags.add(new GeoTIFFTagSet.ModelTransformation());
|
||||
tags.add(new GeoTIFFTagSet.ModelTiePoint());
|
||||
tags.add(new GeoTIFFTagSet.GeoKeyDirectory());
|
||||
tags.add(new GeoTIFFTagSet.GeoDoubleParams());
|
||||
tags.add(new GeoTIFFTagSet.GeoAsciiParams());
|
||||
}
|
||||
|
||||
private GeoTIFFTagSet() {
|
||||
super(tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared instance of a <code>GeoTIFFTagSet</code>.
|
||||
*
|
||||
* @return a <code>GeoTIFFTagSet</code> instance.
|
||||
*/
|
||||
public synchronized static GeoTIFFTagSet getInstance() {
|
||||
if (theInstance == null) {
|
||||
initTags();
|
||||
theInstance = new GeoTIFFTagSet();
|
||||
tags = null;
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import com.sun.imageio.plugins.tiff.TIFFIFD;
|
||||
import com.sun.imageio.plugins.tiff.TIFFImageMetadata;
|
||||
|
||||
/**
|
||||
* A convenience class for simplifying interaction with TIFF native
|
||||
* image metadata. A TIFF image metadata tree represents an Image File
|
||||
* Directory (IFD) from a TIFF 6.0 stream. An IFD consists of a number of
|
||||
* IFD Entries each of which associates an identifying tag number with
|
||||
* a compatible value. A <code>TIFFDirectory</code> instance corresponds
|
||||
* to an IFD and contains a set of {@link TIFFField}s each of which
|
||||
* corresponds to an IFD Entry in the IFD.
|
||||
*
|
||||
* <p>When reading, a <code>TIFFDirectory</code> may be created by passing
|
||||
* the value returned by {@link javax.imageio.ImageReader#getImageMetadata
|
||||
* ImageReader.getImageMetadata()} to {@link #createFromMetadata
|
||||
* createFromMetadata()}. The {@link TIFFField}s in the directory may then
|
||||
* be obtained using the accessor methods provided in this class.</p>
|
||||
*
|
||||
* <p>When writing, an {@link IIOMetadata} object for use by one of the
|
||||
* <code>write()</code> methods of {@link javax.imageio.ImageWriter} may be
|
||||
* created from a <code>TIFFDirectory</code> by {@link #getAsMetadata()}.
|
||||
* The <code>TIFFDirectory</code> itself may be created by construction or
|
||||
* from the <code>IIOMetadata</code> object returned by
|
||||
* {@link javax.imageio.ImageWriter#getDefaultImageMetadata
|
||||
* ImageWriter.getDefaultImageMetadata()}. The <code>TIFFField</code>s in the
|
||||
* directory may be set using the mutator methods provided in this class.</p>
|
||||
*
|
||||
* <p>A <code>TIFFDirectory</code> is aware of the tag numbers in the
|
||||
* group of {@link TIFFTagSet}s associated with it. When
|
||||
* a <code>TIFFDirectory</code> is created from a native image metadata
|
||||
* object, these tag sets are derived from the <tt>tagSets</tt> attribute
|
||||
* of the <tt>TIFFIFD</tt> node.</p>
|
||||
*
|
||||
* <p>A <code>TIFFDirectory</code> might also have a parent {@link TIFFTag}.
|
||||
* This will occur if the directory represents an IFD other than the root
|
||||
* IFD of the image. The parent tag is the tag of the IFD Entry which is a
|
||||
* pointer to the IFD represented by this <code>TIFFDirectory</code>. The
|
||||
* {@link TIFFTag#isIFDPointer} method of this parent <code>TIFFTag</code>
|
||||
* must return <code>true</code>. When a <code>TIFFDirectory</code> is
|
||||
* created from a native image metadata object, the parent tag set is set
|
||||
* from the <tt>parentTagName</tt> attribute of the corresponding
|
||||
* <tt>TIFFIFD</tt> node. Note that a <code>TIFFDirectory</code> instance
|
||||
* which has a non-<code>null</code> parent tag will be contained in the
|
||||
* data field of a <code>TIFFField</code> instance which has a tag field
|
||||
* equal to the contained directory's parent tag.</p>
|
||||
*
|
||||
* <p>As an example consider an Exif image. The <code>TIFFDirectory</code>
|
||||
* instance corresponding to the Exif IFD in the Exif stream would have parent
|
||||
* tag {@link ExifParentTIFFTagSet#TAG_EXIF_IFD_POINTER TAG_EXIF_IFD_POINTER}
|
||||
* and would include {@link ExifTIFFTagSet} in its group of known tag sets.
|
||||
* The <code>TIFFDirectory</code> corresponding to this Exif IFD will be
|
||||
* contained in the data field of a <code>TIFFField</code> which will in turn
|
||||
* be contained in the <code>TIFFDirectory</code> corresponding to the primary
|
||||
* IFD of the Exif image which will itself have a <code>null</code>-valued
|
||||
* parent tag.</p>
|
||||
*
|
||||
* <p><b>Note that this implementation is not synchronized. </b>If multiple
|
||||
* threads use a <code>TIFFDirectory</code> instance concurrently, and at
|
||||
* least one of the threads modifies the directory, for example, by adding
|
||||
* or removing <code>TIFFField</code>s or <code>TIFFTagSet</code>s, it
|
||||
* <i>must</i> be synchronized externally.</p>
|
||||
*
|
||||
* @since 1.9
|
||||
* @see IIOMetadata
|
||||
* @see TIFFField
|
||||
* @see TIFFTag
|
||||
* @see TIFFTagSet
|
||||
*/
|
||||
public class TIFFDirectory implements Cloneable {
|
||||
|
||||
/** The largest low-valued tag number in the TIFF 6.0 specification. */
|
||||
private static final int MAX_LOW_FIELD_TAG_NUM =
|
||||
BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE;
|
||||
|
||||
/** The <code>TIFFTagSets</code> associated with this directory. */
|
||||
private List<TIFFTagSet> tagSets;
|
||||
|
||||
/** The parent <code>TIFFTag</code> of this directory. */
|
||||
private TIFFTag parentTag;
|
||||
|
||||
/**
|
||||
* The fields in this directory which have a low tag number. These are
|
||||
* managed as an array for efficiency as they are the most common fields.
|
||||
*/
|
||||
private TIFFField[] lowFields = new TIFFField[MAX_LOW_FIELD_TAG_NUM + 1];
|
||||
|
||||
/** The number of low tag numbered fields in the directory. */
|
||||
private int numLowFields = 0;
|
||||
|
||||
/**
|
||||
* A mapping of <code>Integer</code> tag numbers to <code>TIFFField</code>s
|
||||
* for fields which are not low tag numbered.
|
||||
*/
|
||||
private Map<Integer,TIFFField> highFields = new TreeMap<Integer,TIFFField>();
|
||||
|
||||
/**
|
||||
* Creates a <code>TIFFDirectory</code> instance from the contents of
|
||||
* an image metadata object. The supplied object must support an image
|
||||
* metadata format supported by the TIFF {@link javax.imageio.ImageWriter}
|
||||
* plug-in. This will usually be either the TIFF native image metadata
|
||||
* format <tt>javax_imageio_tiff_image_1.0</tt> or the Java
|
||||
* Image I/O standard metadata format <tt>javax_imageio_1.0</tt>.
|
||||
*
|
||||
* @param tiffImageMetadata A metadata object which supports a compatible
|
||||
* image metadata format.
|
||||
*
|
||||
* @return A <code>TIFFDirectory</code> populated from the contents of
|
||||
* the supplied metadata object.
|
||||
*
|
||||
* @throws NullPointerException if <code>tiffImageMetadata</code>
|
||||
* is <code>null</code>.
|
||||
* @throws IllegalArgumentException if <code>tiffImageMetadata</code>
|
||||
* does not support a compatible image metadata format.
|
||||
* @throws IIOInvalidTreeException if the supplied metadata object
|
||||
* cannot be parsed.
|
||||
*/
|
||||
public static TIFFDirectory
|
||||
createFromMetadata(IIOMetadata tiffImageMetadata)
|
||||
throws IIOInvalidTreeException {
|
||||
|
||||
if(tiffImageMetadata == null) {
|
||||
throw new NullPointerException("tiffImageMetadata == null");
|
||||
}
|
||||
|
||||
TIFFImageMetadata tim;
|
||||
if(tiffImageMetadata instanceof TIFFImageMetadata) {
|
||||
tim = (TIFFImageMetadata)tiffImageMetadata;
|
||||
} else {
|
||||
// Create a native metadata object.
|
||||
ArrayList<TIFFTagSet> l = new ArrayList<TIFFTagSet>(1);
|
||||
l.add(BaselineTIFFTagSet.getInstance());
|
||||
tim = new TIFFImageMetadata(l);
|
||||
|
||||
// Determine the format name to use.
|
||||
String formatName = null;
|
||||
if(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME.equals
|
||||
(tiffImageMetadata.getNativeMetadataFormatName())) {
|
||||
formatName = TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME;
|
||||
} else {
|
||||
String[] extraNames =
|
||||
tiffImageMetadata.getExtraMetadataFormatNames();
|
||||
if(extraNames != null) {
|
||||
for(int i = 0; i < extraNames.length; i++) {
|
||||
if(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME.equals
|
||||
(extraNames[i])) {
|
||||
formatName = extraNames[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(formatName == null) {
|
||||
if(tiffImageMetadata.isStandardMetadataFormatSupported()) {
|
||||
formatName =
|
||||
IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
} else {
|
||||
throw new IllegalArgumentException
|
||||
("Parameter does not support required metadata format!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the native metadata object from the tree.
|
||||
tim.setFromTree(formatName,
|
||||
tiffImageMetadata.getAsTree(formatName));
|
||||
}
|
||||
|
||||
return tim.getRootIFD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a <code>TIFFDirectory</code> to a <code>TIFFIFD</code>.
|
||||
*/
|
||||
private static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) {
|
||||
if(dir instanceof TIFFIFD) {
|
||||
return (TIFFIFD)dir;
|
||||
}
|
||||
|
||||
TIFFIFD ifd = new TIFFIFD(Arrays.asList(dir.getTagSets()),
|
||||
dir.getParentTag());
|
||||
TIFFField[] fields = dir.getTIFFFields();
|
||||
int numFields = fields.length;
|
||||
for(int i = 0; i < numFields; i++) {
|
||||
TIFFField f = fields[i];
|
||||
TIFFTag tag = f.getTag();
|
||||
if(tag.isIFDPointer()) {
|
||||
TIFFDirectory subIFD =
|
||||
getDirectoryAsIFD((TIFFDirectory)f.getData());
|
||||
f = new TIFFField(tag, f.getType(), (long)f.getCount(), subIFD);
|
||||
}
|
||||
ifd.addTIFFField(f);
|
||||
}
|
||||
|
||||
return ifd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFDirectory</code> which is aware of a given
|
||||
* group of {@link TIFFTagSet}s. An optional parent {@link TIFFTag}
|
||||
* may also be specified.
|
||||
*
|
||||
* @param tagSets The <code>TIFFTagSets</code> associated with this
|
||||
* directory.
|
||||
* @param parentTag The parent <code>TIFFTag</code> of this directory;
|
||||
* may be <code>null</code>.
|
||||
* @throws NullPointerException if <code>tagSets</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public TIFFDirectory(TIFFTagSet[] tagSets, TIFFTag parentTag) {
|
||||
if(tagSets == null) {
|
||||
throw new NullPointerException("tagSets == null!");
|
||||
}
|
||||
this.tagSets = new ArrayList<TIFFTagSet>(tagSets.length);
|
||||
int numTagSets = tagSets.length;
|
||||
for(int i = 0; i < numTagSets; i++) {
|
||||
this.tagSets.add(tagSets[i]);
|
||||
}
|
||||
this.parentTag = parentTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TIFFTagSet}s of which this directory is aware.
|
||||
*
|
||||
* @return The <code>TIFFTagSet</code>s associated with this
|
||||
* <code>TIFFDirectory</code>.
|
||||
*/
|
||||
public TIFFTagSet[] getTagSets() {
|
||||
return tagSets.toArray(new TIFFTagSet[tagSets.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the group of {@link TIFFTagSet}s of which this
|
||||
* directory is aware.
|
||||
*
|
||||
* @param tagSet The <code>TIFFTagSet</code> to add.
|
||||
* @throws NullPointerException if <code>tagSet</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public void addTagSet(TIFFTagSet tagSet) {
|
||||
if(tagSet == null) {
|
||||
throw new NullPointerException("tagSet == null");
|
||||
}
|
||||
|
||||
if(!tagSets.contains(tagSet)) {
|
||||
tagSets.add(tagSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from the group of {@link TIFFTagSet}s of which this
|
||||
* directory is aware.
|
||||
*
|
||||
* @param tagSet The <code>TIFFTagSet</code> to remove.
|
||||
* @throws NullPointerException if <code>tagSet</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public void removeTagSet(TIFFTagSet tagSet) {
|
||||
if(tagSet == null) {
|
||||
throw new NullPointerException("tagSet == null");
|
||||
}
|
||||
|
||||
if(tagSets.contains(tagSet)) {
|
||||
tagSets.remove(tagSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent {@link TIFFTag} of this directory if one
|
||||
* has been defined or <code>null</code> otherwise.
|
||||
*
|
||||
* @return The parent <code>TIFFTag</code> of this
|
||||
* <code>TIFFDiectory</code> or <code>null</code>.
|
||||
*/
|
||||
public TIFFTag getParentTag() {
|
||||
return parentTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TIFFTag} which has tag number equal to
|
||||
* <code>tagNumber</code> or <code>null</code> if no such tag
|
||||
* exists in the {@link TIFFTagSet}s associated with this
|
||||
* directory.
|
||||
*
|
||||
* @param tagNumber The tag number of interest.
|
||||
* @return The corresponding <code>TIFFTag</code> or <code>null</code>.
|
||||
*/
|
||||
public TIFFTag getTag(int tagNumber) {
|
||||
return TIFFIFD.getTag(tagNumber, tagSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link TIFFField}s in this directory.
|
||||
*
|
||||
* @return The number of <code>TIFFField</code>s in this
|
||||
* <code>TIFFDirectory</code>.
|
||||
*/
|
||||
public int getNumTIFFFields() {
|
||||
return numLowFields + highFields.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a TIFF field with the given tag number is
|
||||
* contained in this directory.
|
||||
*
|
||||
* @param tagNumber The tag number.
|
||||
* @return Whether a {@link TIFFTag} with tag number equal to
|
||||
* <code>tagNumber</code> is present in this <code>TIFFDirectory</code>.
|
||||
*/
|
||||
public boolean containsTIFFField(int tagNumber) {
|
||||
return (tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM &&
|
||||
lowFields[tagNumber] != null) ||
|
||||
highFields.containsKey(Integer.valueOf(tagNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a TIFF field to the directory.
|
||||
*
|
||||
* @param f The field to add.
|
||||
* @throws NullPointerException if <code>f</code> is <code>null</code>.
|
||||
*/
|
||||
public void addTIFFField(TIFFField f) {
|
||||
if(f == null) {
|
||||
throw new NullPointerException("f == null");
|
||||
}
|
||||
int tagNumber = f.getTagNumber();
|
||||
if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) {
|
||||
if(lowFields[tagNumber] == null) {
|
||||
numLowFields++;
|
||||
}
|
||||
lowFields[tagNumber] = f;
|
||||
} else {
|
||||
highFields.put(Integer.valueOf(tagNumber), f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a TIFF field from the directory.
|
||||
*
|
||||
* @param tagNumber The tag number of the tag associated with the field.
|
||||
* @return A <code>TIFFField</code> with the requested tag number of
|
||||
* <code>null</code> if no such field is present.
|
||||
*/
|
||||
public TIFFField getTIFFField(int tagNumber) {
|
||||
TIFFField f;
|
||||
if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) {
|
||||
f = lowFields[tagNumber];
|
||||
} else {
|
||||
f = highFields.get(Integer.valueOf(tagNumber));
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a TIFF field from the directory.
|
||||
*
|
||||
* @param tagNumber The tag number of the tag associated with the field.
|
||||
*/
|
||||
public void removeTIFFField(int tagNumber) {
|
||||
if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) {
|
||||
if(lowFields[tagNumber] != null) {
|
||||
numLowFields--;
|
||||
lowFields[tagNumber] = null;
|
||||
}
|
||||
} else {
|
||||
highFields.remove(Integer.valueOf(tagNumber));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all TIFF fields from the directory.
|
||||
*
|
||||
* @return An array of all TIFF fields in order of numerically increasing
|
||||
* tag number.
|
||||
*/
|
||||
public TIFFField[] getTIFFFields() {
|
||||
// Allocate return value.
|
||||
TIFFField[] fields = new TIFFField[numLowFields + highFields.size()];
|
||||
|
||||
// Copy any low-index fields.
|
||||
int nextIndex = 0;
|
||||
for(int i = 0; i <= MAX_LOW_FIELD_TAG_NUM; i++) {
|
||||
if(lowFields[i] != null) {
|
||||
fields[nextIndex++] = lowFields[i];
|
||||
if(nextIndex == numLowFields) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any high-index fields.
|
||||
if(!highFields.isEmpty()) {
|
||||
Iterator<Integer> keys = highFields.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
fields[nextIndex++] = highFields.get(keys.next());
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all TIFF fields from the directory.
|
||||
*/
|
||||
public void removeTIFFFields() {
|
||||
Arrays.fill(lowFields, (Object)null);
|
||||
numLowFields = 0;
|
||||
highFields.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the directory to a metadata object.
|
||||
*
|
||||
* @return A metadata instance initialized from the contents of this
|
||||
* <code>TIFFDirectory</code>.
|
||||
*/
|
||||
public IIOMetadata getAsMetadata() {
|
||||
return new TIFFImageMetadata(getDirectoryAsIFD(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the directory and all the fields contained therein.
|
||||
*
|
||||
* @return A clone of this <code>TIFFDirectory</code>.
|
||||
* @throws CloneNotSupportedException if the instance cannot be cloned.
|
||||
*/
|
||||
@Override
|
||||
public TIFFDirectory clone() throws CloneNotSupportedException {
|
||||
TIFFDirectory dir = (TIFFDirectory) super.clone();
|
||||
dir.tagSets = new ArrayList<TIFFTagSet>(tagSets);
|
||||
dir.parentTag = getParentTag();
|
||||
TIFFField[] fields = getTIFFFields();
|
||||
for(TIFFField field : fields) {
|
||||
dir.addTIFFField(field.clone());
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.imageio.ImageReadParam;
|
||||
|
||||
/**
|
||||
* A subclass of {@link ImageReadParam} allowing control over
|
||||
* the TIFF reading process.
|
||||
*
|
||||
* <p> Because TIFF is an extensible format, the reader requires
|
||||
* information about any tags used by TIFF extensions in order to emit
|
||||
* meaningful metadata. Also, TIFF extensions may define new
|
||||
* compression types. Both types of information about extensions may
|
||||
* be provided by this interface.
|
||||
*
|
||||
* <p> Additional TIFF tags must be organized into
|
||||
* <code>TIFFTagSet</code>s. A <code>TIFFTagSet</code> may be
|
||||
* provided to the reader by means of the
|
||||
* <code>addAllowedTagSet</code> method. By default, the tag sets
|
||||
* <code>BaselineTIFFTagSet</code>, <code>FaxTIFFTagSet</code>,
|
||||
* <code>ExifParentTIFFTagSet</code>, and <code>GeoTIFFTagSet</code>
|
||||
* are included.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public class TIFFImageReadParam extends ImageReadParam {
|
||||
|
||||
private List<TIFFTagSet> allowedTagSets = new ArrayList<TIFFTagSet>(4);
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFImageReadParam</code>. Tags defined by
|
||||
* the <code>TIFFTagSet</code>s <code>BaselineTIFFTagSet</code>,
|
||||
* <code>FaxTIFFTagSet</code>, <code>ExifParentTIFFTagSet</code>, and
|
||||
* <code>GeoTIFFTagSet</code> will be supported.
|
||||
*
|
||||
* @see BaselineTIFFTagSet
|
||||
* @see FaxTIFFTagSet
|
||||
* @see ExifParentTIFFTagSet
|
||||
* @see GeoTIFFTagSet
|
||||
*/
|
||||
public TIFFImageReadParam() {
|
||||
addAllowedTagSet(BaselineTIFFTagSet.getInstance());
|
||||
addAllowedTagSet(FaxTIFFTagSet.getInstance());
|
||||
addAllowedTagSet(ExifParentTIFFTagSet.getInstance());
|
||||
addAllowedTagSet(GeoTIFFTagSet.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a <code>TIFFTagSet</code> object to the list of allowed
|
||||
* tag sets.
|
||||
*
|
||||
* @param tagSet a <code>TIFFTagSet</code>.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>tagSet</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public void addAllowedTagSet(TIFFTagSet tagSet) {
|
||||
if (tagSet == null) {
|
||||
throw new IllegalArgumentException("tagSet == null!");
|
||||
}
|
||||
allowedTagSets.add(tagSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a <code>TIFFTagSet</code> object from the list of
|
||||
* allowed tag sets. Removal is based on the <code>equals</code>
|
||||
* method of the <code>TIFFTagSet</code>, which is normally
|
||||
* defined as reference equality.
|
||||
*
|
||||
* @param tagSet a <code>TIFFTagSet</code>.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>tagSet</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public void removeAllowedTagSet(TIFFTagSet tagSet) {
|
||||
if (tagSet == null) {
|
||||
throw new IllegalArgumentException("tagSet == null!");
|
||||
}
|
||||
allowedTagSets.remove(tagSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>List</code> containing the allowed
|
||||
* <code>TIFFTagSet</code> objects.
|
||||
*
|
||||
* @return a <code>List</code> of <code>TIFFTagSet</code>s.
|
||||
*/
|
||||
public List<TIFFTagSet> getAllowedTagSets() {
|
||||
return allowedTagSets;
|
||||
}
|
||||
}
|
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A class defining the notion of a TIFF tag. A TIFF tag is a key
|
||||
* that may appear in an Image File Directory (IFD). In the IFD
|
||||
* each tag has some data associated with it, which may consist of zero
|
||||
* or more values of a given data type. The combination of a tag and a
|
||||
* value is known as an IFD Entry or TIFF Field.
|
||||
*
|
||||
* <p> The actual tag values used in the root IFD of a standard ("baseline")
|
||||
* tiff stream are defined in the {@link BaselineTIFFTagSet
|
||||
* BaselineTIFFTagSet} class.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see BaselineTIFFTagSet
|
||||
* @see TIFFField
|
||||
* @see TIFFTagSet
|
||||
*/
|
||||
public class TIFFTag {
|
||||
|
||||
// TIFF 6.0 + Adobe PageMaker(R) 6.0 TIFF Technical Notes 1 IFD data type
|
||||
|
||||
/** Flag for 8 bit unsigned integers. */
|
||||
public static final int TIFF_BYTE = 1;
|
||||
|
||||
/** Flag for null-terminated ASCII strings. */
|
||||
public static final int TIFF_ASCII = 2;
|
||||
|
||||
/** Flag for 16 bit unsigned integers. */
|
||||
public static final int TIFF_SHORT = 3;
|
||||
|
||||
/** Flag for 32 bit unsigned integers. */
|
||||
public static final int TIFF_LONG = 4;
|
||||
|
||||
/** Flag for pairs of 32 bit unsigned integers. */
|
||||
public static final int TIFF_RATIONAL = 5;
|
||||
|
||||
/** Flag for 8 bit signed integers. */
|
||||
public static final int TIFF_SBYTE = 6;
|
||||
|
||||
/** Flag for 8 bit uninterpreted bytes. */
|
||||
public static final int TIFF_UNDEFINED = 7;
|
||||
|
||||
/** Flag for 16 bit signed integers. */
|
||||
public static final int TIFF_SSHORT = 8;
|
||||
|
||||
/** Flag for 32 bit signed integers. */
|
||||
public static final int TIFF_SLONG = 9;
|
||||
|
||||
/** Flag for pairs of 32 bit signed integers. */
|
||||
public static final int TIFF_SRATIONAL = 10;
|
||||
|
||||
/** Flag for 32 bit IEEE floats. */
|
||||
public static final int TIFF_FLOAT = 11;
|
||||
|
||||
/** Flag for 64 bit IEEE doubles. */
|
||||
public static final int TIFF_DOUBLE = 12;
|
||||
|
||||
/**
|
||||
* Flag for IFD pointer defined in TIFF Tech Note 1 in
|
||||
* TIFF Specification Supplement 1.
|
||||
*/
|
||||
public static final int TIFF_IFD_POINTER = 13;
|
||||
|
||||
/**
|
||||
* The numerically smallest constant representing a TIFF data type.
|
||||
*/
|
||||
public static final int MIN_DATATYPE = TIFF_BYTE;
|
||||
|
||||
/**
|
||||
* The numerically largest constant representing a TIFF data type.
|
||||
*/
|
||||
public static final int MAX_DATATYPE = TIFF_IFD_POINTER;
|
||||
|
||||
/**
|
||||
* The name assigned to a tag with an unknown tag number. Such
|
||||
* a tag may be created for example when reading an IFD and a
|
||||
* tag number is encountered which is not in any of the
|
||||
* <code>TIFFTagSet</code>s known to the reader.
|
||||
*/
|
||||
public static final String UNKNOWN_TAG_NAME = "UnknownTag";
|
||||
|
||||
/**
|
||||
* Disallowed data type mask.
|
||||
*/
|
||||
private static final int DISALLOWED_DATATYPES_MASK = ~0x3fff;
|
||||
|
||||
private static final int[] SIZE_OF_TYPE = {
|
||||
0, // 0 = n/a
|
||||
1, // 1 = byte
|
||||
1, // 2 = ascii
|
||||
2, // 3 = short
|
||||
4, // 4 = long
|
||||
8, // 5 = rational
|
||||
1, // 6 = sbyte
|
||||
1, // 7 = undefined
|
||||
2, // 8 = sshort
|
||||
4, // 9 = slong
|
||||
8, // 10 = srational
|
||||
4, // 11 = float
|
||||
8, // 12 = double
|
||||
4, // 13 = IFD_POINTER
|
||||
};
|
||||
|
||||
private int number;
|
||||
private String name;
|
||||
private int dataTypes;
|
||||
private int count;
|
||||
private TIFFTagSet tagSet = null;
|
||||
|
||||
// Mnemonic names for integral enumerated constants
|
||||
private SortedMap<Integer,String> valueNames = null;
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFTag</code> with a given name, tag number, set
|
||||
* of legal data types, and value count. A negative value count signifies
|
||||
* that either an arbitrary number of values is legal or the required count
|
||||
* is determined by the values of other fields in the IFD. A non-negative
|
||||
* count specifies the number of values which an associated field must
|
||||
* contain. The tag will have no associated <code>TIFFTagSet</code>.
|
||||
*
|
||||
* <p> If there are mnemonic names to be associated with the legal
|
||||
* data values for the tag, {@link #addValueName(int, String)
|
||||
* addValueName()} should be called on the new instance for each name.
|
||||
* Mnemonic names apply only to tags which have integral data type.</p>
|
||||
*
|
||||
* <p> See the documentation for {@link #getDataTypes()
|
||||
* getDataTypes()} for an explanation of how the set
|
||||
* of data types is to be converted into a bit mask.</p>
|
||||
*
|
||||
* @param name the name of the tag.
|
||||
* @param number the number used to represent the tag.
|
||||
* @param dataTypes a bit mask indicating the set of legal data
|
||||
* types for this tag.
|
||||
* @param count the value count for this tag.
|
||||
* @throws NullPointerException if name is null.
|
||||
* @throws IllegalArgumentException if number is negative or dataTypes
|
||||
* is negative or specifies an out of range type.
|
||||
*/
|
||||
public TIFFTag(String name, int number, int dataTypes, int count) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name == null");
|
||||
} else if (number < 0) {
|
||||
throw new IllegalArgumentException("number (" + number + ") < 0");
|
||||
} else if (dataTypes < 0
|
||||
|| (dataTypes & DISALLOWED_DATATYPES_MASK) != 0) {
|
||||
throw new IllegalArgumentException("dataTypes out of range");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.number = number;
|
||||
this.dataTypes = dataTypes;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFTag</code> with a given name, tag number and
|
||||
* <code>TIFFTagSet</code> to which it refers. The legal data types are
|
||||
* set to include {@link #TIFF_LONG} and {@link #TIFF_IFD_POINTER} and the
|
||||
* value count is unity. The <code>TIFFTagSet</code> will
|
||||
* represent the set of <code>TIFFTag</code>s which appear in the IFD
|
||||
* pointed to. A <code>TIFFTag</code> represents an IFD pointer if and
|
||||
* only if <code>tagSet</code> is non-<code>null</code> or the data
|
||||
* type <code>TIFF_IFD_POINTER</code> is legal.
|
||||
*
|
||||
* @param name the name of the tag.
|
||||
* @param number the number used to represent the tag.
|
||||
* @param tagSet the <code>TIFFTagSet</code> to which this tag belongs.
|
||||
* @throws NullPointerException if name or tagSet is null.
|
||||
* @throws IllegalArgumentException if number is negative.
|
||||
*
|
||||
* @see #TIFFTag(String, int, int, int)
|
||||
*/
|
||||
public TIFFTag(String name, int number, TIFFTagSet tagSet) {
|
||||
this(name, number,
|
||||
1 << TIFFTag.TIFF_LONG | 1 << TIFFTag.TIFF_IFD_POINTER, 1);
|
||||
if (tagSet == null) {
|
||||
throw new NullPointerException("tagSet == null");
|
||||
}
|
||||
this.tagSet = tagSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFTag</code> with a given name, tag number,
|
||||
* and set of legal data types. The value count of the tag will be
|
||||
* undefined and it will have no associated <code>TIFFTagSet</code>.
|
||||
*
|
||||
* @param name the name of the tag.
|
||||
* @param number the number used to represent the tag.
|
||||
* @param dataTypes a bit mask indicating the set of legal data
|
||||
* types for this tag.
|
||||
* @throws NullPointerException if name is null.
|
||||
* @throws IllegalArgumentException if number is negative or dataTypes
|
||||
* is negative or specifies an out of range type.
|
||||
*
|
||||
* @see #TIFFTag(String, int, int, int)
|
||||
*/
|
||||
public TIFFTag(String name, int number, int dataTypes) {
|
||||
this(name, number, dataTypes, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes used to store a value of the given
|
||||
* data type.
|
||||
*
|
||||
* @param dataType the data type to be queried.
|
||||
*
|
||||
* @return the number of bytes used to store the given data type.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>datatype</code> is
|
||||
* less than <code>MIN_DATATYPE</code> or greater than
|
||||
* <code>MAX_DATATYPE</code>.
|
||||
*/
|
||||
public static int getSizeOfType(int dataType) {
|
||||
if (dataType < MIN_DATATYPE ||dataType > MAX_DATATYPE) {
|
||||
throw new IllegalArgumentException("dataType out of range!");
|
||||
}
|
||||
|
||||
return SIZE_OF_TYPE[dataType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the tag, as it will appear in image metadata.
|
||||
*
|
||||
* @return the tag name, as a <code>String</code>.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer used to represent the tag.
|
||||
*
|
||||
* @return the tag number, as an <code>int</code>.
|
||||
*/
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bit mask indicating the set of data types that may
|
||||
* be used to store the data associated with the tag.
|
||||
* For example, a tag that can store both SHORT and LONG values
|
||||
* would return a value of:
|
||||
*
|
||||
* <pre>
|
||||
* (1 << TIFFTag.TIFF_SHORT) | (1 << TIFFTag.TIFF_LONG)
|
||||
* </pre>
|
||||
*
|
||||
* @return an <code>int</code> containing a bitmask encoding the
|
||||
* set of valid data types.
|
||||
*/
|
||||
public int getDataTypes() {
|
||||
return dataTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value count of this tag. If this value is positive, it
|
||||
* represents the required number of values for a <code>TIFFField</code>
|
||||
* which has this tag. If the value is negative, the count is undefined.
|
||||
* In the latter case the count may be derived, e.g., the number of values
|
||||
* of the <code>BitsPerSample</code> field is <code>SamplesPerPixel</code>,
|
||||
* or it may be variable as in the case of most <code>US-ASCII</code>
|
||||
* fields.
|
||||
*
|
||||
* @return the value count of this tag.
|
||||
*/
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the given data type
|
||||
* may be used for the data associated with this tag.
|
||||
*
|
||||
* @param dataType the data type to be queried, one of
|
||||
* <code>TIFF_BYTE</code>, <code>TIFF_SHORT</code>, etc.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether the given
|
||||
* data type may be used with this tag.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>datatype</code> is
|
||||
* less than <code>MIN_DATATYPE</code> or greater than
|
||||
* <code>MAX_DATATYPE</code>.
|
||||
*/
|
||||
public boolean isDataTypeOK(int dataType) {
|
||||
if (dataType < MIN_DATATYPE || dataType > MAX_DATATYPE) {
|
||||
throw new IllegalArgumentException("datatype not in range!");
|
||||
}
|
||||
return (dataTypes & (1 << dataType)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>TIFFTagSet</code> of which this tag is a part.
|
||||
*
|
||||
* @return the containing <code>TIFFTagSet</code>.
|
||||
*/
|
||||
public TIFFTagSet getTagSet() {
|
||||
return tagSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this tag is used to point to an IFD
|
||||
* structure containing additional tags. A <code>TIFFTag</code> represents
|
||||
* an IFD pointer if and only if its <code>TIFFTagSet</code> is
|
||||
* non-<code>null</code> or the data type <code>TIFF_IFD_POINTER</code> is
|
||||
* legal. This condition will be satisfied if and only if either
|
||||
* <code>getTagSet() != null</code> or
|
||||
* <code>isDataTypeOK(TIFF_IFD_POINTER) == true</code>.
|
||||
*
|
||||
* <p>Many TIFF extensions use the IFD mechanism in order to limit the
|
||||
* number of new tags that may appear in the root IFD.</p>
|
||||
*
|
||||
* @return <code>true</code> if this tag points to an IFD.
|
||||
*/
|
||||
public boolean isIFDPointer() {
|
||||
return tagSet != null || isDataTypeOK(TIFF_IFD_POINTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if there are mnemonic names associated with
|
||||
* the set of legal values for the data associated with this tag. Mnemonic
|
||||
* names apply only to tags which have integral data type.
|
||||
*
|
||||
* @return <code>true</code> if mnemonic value names are available.
|
||||
*/
|
||||
public boolean hasValueNames() {
|
||||
return valueNames != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mnemonic name for a particular value that this tag's data may take
|
||||
* on. Mnemonic names apply only to tags which have integral data type.
|
||||
*
|
||||
* @param value the data value.
|
||||
* @param name the name to associate with the value.
|
||||
*/
|
||||
protected void addValueName(int value, String name) {
|
||||
if (valueNames == null) {
|
||||
valueNames = new TreeMap<Integer,String>();
|
||||
}
|
||||
valueNames.put(Integer.valueOf(value), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mnemonic name associated with a particular value
|
||||
* that this tag's data may take on, or <code>null</code> if
|
||||
* no name is present. Mnemonic names apply only to tags which have
|
||||
* integral data type.
|
||||
*
|
||||
* @param value the data value.
|
||||
*
|
||||
* @return the mnemonic name associated with the value, as a
|
||||
* <code>String</code>.
|
||||
*/
|
||||
public String getValueName(int value) {
|
||||
if (valueNames == null) {
|
||||
return null;
|
||||
}
|
||||
return valueNames.get(Integer.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of values for which mnemonic names are defined. The
|
||||
* method {@link #getValueName(int) getValueName()} will return
|
||||
* non-{@code null} only for values contained in the returned array.
|
||||
* Mnemonic names apply only to tags which have integral data type.
|
||||
*
|
||||
* @return the values for which there is a mnemonic name.
|
||||
*/
|
||||
public int[] getNamedValues() {
|
||||
int[] intValues = null;
|
||||
if (valueNames != null) {
|
||||
Set<Integer> values = valueNames.keySet();
|
||||
Iterator<Integer> iter = values.iterator();
|
||||
intValues = new int[values.size()];
|
||||
int i = 0;
|
||||
while (iter.hasNext()) {
|
||||
intValues[i++] = iter.next();
|
||||
}
|
||||
}
|
||||
return intValues;
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*/
|
||||
package javax.imageio.plugins.tiff;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A class representing a set of TIFF tags. Each tag in the set must
|
||||
* have a unique number (this is a limitation of the TIFF
|
||||
* specification itself).
|
||||
*
|
||||
* <p> This class and its subclasses are responsible for mapping
|
||||
* between raw tag numbers and <code>TIFFTag</code> objects, which
|
||||
* contain additional information about each tag, such as the tag's
|
||||
* name, legal data types, and mnemonic names for some or all of ts
|
||||
* data values.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see TIFFTag
|
||||
*/
|
||||
public class TIFFTagSet {
|
||||
|
||||
private SortedMap<Integer,TIFFTag> allowedTagsByNumber = new TreeMap<Integer,TIFFTag>();
|
||||
|
||||
private SortedMap<String,TIFFTag> allowedTagsByName = new TreeMap<String,TIFFTag>();
|
||||
|
||||
/**
|
||||
* Constructs a TIFFTagSet.
|
||||
*/
|
||||
private TIFFTagSet() {}
|
||||
|
||||
/**
|
||||
* Constructs a <code>TIFFTagSet</code>, given a <code>List</code>
|
||||
* of <code>TIFFTag</code> objects.
|
||||
*
|
||||
* @param tags a <code>List</code> object containing
|
||||
* <code>TIFFTag</code> objects to be added to this tag set.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>tags</code> is
|
||||
* <code>null</code>, or contains objects that are not instances
|
||||
* of the <code>TIFFTag</code> class.
|
||||
*/
|
||||
public TIFFTagSet(List<TIFFTag> tags) {
|
||||
if (tags == null) {
|
||||
throw new IllegalArgumentException("tags == null!");
|
||||
}
|
||||
Iterator<TIFFTag> iter = tags.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Object o = iter.next();
|
||||
if (!(o instanceof TIFFTag)) {
|
||||
throw new IllegalArgumentException(
|
||||
"tags contains a non-TIFFTag!");
|
||||
}
|
||||
TIFFTag tag = (TIFFTag)o;
|
||||
|
||||
allowedTagsByNumber.put(Integer.valueOf(tag.getNumber()), tag);
|
||||
allowedTagsByName.put(tag.getName(), tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>TIFFTag</code> from this set that is
|
||||
* associated with the given tag number, or <code>null</code> if
|
||||
* no tag exists for that number.
|
||||
*
|
||||
* @param tagNumber the number of the tag to be retrieved.
|
||||
*
|
||||
* @return the numbered <code>TIFFTag</code>, or <code>null</code>.
|
||||
*/
|
||||
public TIFFTag getTag(int tagNumber) {
|
||||
return allowedTagsByNumber.get(Integer.valueOf(tagNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>TIFFTag</code> having the given tag name, or
|
||||
* <code>null</code> if the named tag does not belong to this tag set.
|
||||
*
|
||||
* @param tagName the name of the tag to be retrieved, as a
|
||||
* <code>String</code>.
|
||||
*
|
||||
* @return the named <code>TIFFTag</code>, or <code>null</code>.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>tagName</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public TIFFTag getTag(String tagName) {
|
||||
if (tagName == null) {
|
||||
throw new IllegalArgumentException("tagName == null!");
|
||||
}
|
||||
return allowedTagsByName.get(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an unmodifiable numerically increasing set of tag numbers.
|
||||
*
|
||||
* <p>The returned object is unmodifiable and contains the tag
|
||||
* numbers of all <code>TIFFTag</code>s in this <code>TIFFTagSet</code>
|
||||
* sorted into ascending order according to
|
||||
* {@link Integer#compareTo(Object)}.</p>
|
||||
*
|
||||
* @return All tag numbers in this set.
|
||||
*/
|
||||
public SortedSet<Integer> getTagNumbers() {
|
||||
Set<Integer> tagNumbers = allowedTagsByNumber.keySet();
|
||||
SortedSet<Integer> sortedTagNumbers;
|
||||
if(tagNumbers instanceof SortedSet) {
|
||||
sortedTagNumbers = (SortedSet<Integer>)tagNumbers;
|
||||
} else {
|
||||
sortedTagNumbers = new TreeSet<Integer>(tagNumbers);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSortedSet(sortedTagNumbers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an unmodifiable lexicographically increasing set of tag names.
|
||||
*
|
||||
* <p>The returned object is unmodifiable and contains the tag
|
||||
* names of all <code>TIFFTag</code>s in this <code>TIFFTagSet</code>
|
||||
* sorted into ascending order according to
|
||||
* {@link String#compareTo(Object)}.</p>
|
||||
*
|
||||
* @return All tag names in this set.
|
||||
*/
|
||||
public SortedSet<String> getTagNames() {
|
||||
Set<String> tagNames = allowedTagsByName.keySet();
|
||||
SortedSet<String> sortedTagNames;
|
||||
if(tagNames instanceof SortedSet) {
|
||||
sortedTagNames = (SortedSet<String>)tagNames;
|
||||
} else {
|
||||
sortedTagNames = new TreeSet<String>(tagNames);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSortedSet(sortedTagNames);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
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.
|
||||
-->
|
||||
</head>
|
||||
|
||||
<body bgcolor="white">
|
||||
|
||||
<body>
|
||||
Public classes used by the built-in TIFF plug-ins.
|
||||
|
||||
<p>
|
||||
This package contains classes supporting the built-in TIFF reader and writer
|
||||
plug-ins. Classes are provided for simplifying interaction with metadata,
|
||||
including Exif metadata common in digital photography, and an extension of
|
||||
{@link javax.imageio.ImageReadParam} which permits specifying which metadata
|
||||
tags are allowed to be read. For more information about the operation of the
|
||||
built-in TIFF plug-ins, see the
|
||||
<a HREF="../../metadata/doc-files/tiff_metadata.html">TIFF metadata format
|
||||
specification and usage notes</a>.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@since 1.9
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -49,6 +49,8 @@ import com.sun.imageio.plugins.bmp.BMPImageReaderSpi;
|
||||
import com.sun.imageio.plugins.bmp.BMPImageWriterSpi;
|
||||
import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
|
||||
import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
|
||||
import com.sun.imageio.plugins.tiff.TIFFImageReaderSpi;
|
||||
import com.sun.imageio.plugins.tiff.TIFFImageWriterSpi;
|
||||
import sun.awt.AppContext;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
@ -168,6 +170,8 @@ public final class IIORegistry extends ServiceRegistry {
|
||||
registerServiceProvider(new BMPImageWriterSpi());
|
||||
registerServiceProvider(new WBMPImageReaderSpi());
|
||||
registerServiceProvider(new WBMPImageWriterSpi());
|
||||
registerServiceProvider(new TIFFImageReaderSpi());
|
||||
registerServiceProvider(new TIFFImageWriterSpi());
|
||||
registerServiceProvider(new PNGImageReaderSpi());
|
||||
registerServiceProvider(new PNGImageWriterSpi());
|
||||
registerServiceProvider(new JPEGImageReaderSpi());
|
||||
|
Loading…
x
Reference in New Issue
Block a user