帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

809 lines
31 KiB

/*
* Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduct the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
package com.fr.third.JAI;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGDecodeParam;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
public class FPXImage extends SimpleRenderedImage {
private static final int SUBIMAGE_COLOR_SPACE_COLORLESS = 0;
private static final int SUBIMAGE_COLOR_SPACE_MONOCHROME = 0;
private static final int SUBIMAGE_COLOR_SPACE_PHOTOYCC = 0;
private static final int SUBIMAGE_COLOR_SPACE_NIFRGB = 0;
private static final String[] COLORSPACE_NAME = {
"Colorless", "Monochrome", "PhotoYCC", "NIF RGB"
};
StructuredStorage storage;
int numResolutions;
int highestResWidth;
int highestResHeight;
float defaultDisplayHeight;
float defaultDisplayWidth;
int displayHeightWidthUnits;
boolean[] subimageValid;
int[] subimageWidth;
int[] subimageHeight;
int[][] subimageColor;
// subimageNumericalFormat
int[] decimationMethod;
float[] decimationPrefilterWidth;
// subimage ICC profile
int highestResolution = -1;
int maxJPEGTableIndex;
byte[][] JPEGTable;
// Values from "Subimage 0000 Header" stream
int numChannels;
int tileHeaderTableOffset;
int tileHeaderEntryLength;
// int[] tileOffset;
// int[] tileSize;
// int[] compressionType;
// int[] compressionSubtype;
// The "Subimage 0000 Header" stream
SeekableStream subimageHeaderStream;
// The "Subimage 0000 Data" stream
SeekableStream subimageDataStream;
int resolution;
// Derived values
int tilesAcross;
int[] bandOffsets = { 0, 1, 2 };
private static final int[] RGBBits8 = { 8, 8, 8 };
private static final ComponentColorModel colorModelRGB8 =
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
RGBBits8, false, false,
Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);
public FPXImage(SeekableStream stream, FPXDecodeParam param)
throws IOException {
this.storage = new StructuredStorage(stream);
readImageContents();
if (param == null) {
param = new FPXDecodeParam();
}
this.resolution = param.getResolution();
readResolution();
bandOffsets = new int[numChannels];
for (int i = 0; i < numChannels; i++) {
bandOffsets[i] = i;
}
this.minX = 0;
this.minY = 0;
this.sampleModel =
RasterFactory.createPixelInterleavedSampleModel(
DataBuffer.TYPE_BYTE,
tileWidth,
tileHeight,
numChannels,
numChannels*tileWidth,
bandOffsets);
this.colorModel = ImageCodec.createComponentColorModel(sampleModel);
}
private void readImageContents() throws IOException {
storage.changeDirectoryToRoot();
storage.changeDirectory("Data Object Store 000001");
SeekableStream imageContents =
storage.getStream("Image Contents");
PropertySet icps = new PropertySet(imageContents);
this.numResolutions = (int)icps.getUI4(0x01000000);
this.highestResWidth = (int)icps.getUI4(0x01000002);
this.highestResHeight = (int)icps.getUI4(0x01000003);
// this.defaultDisplayHeight = icps.getR4(0x01000004);
// this.defaultDisplayWidth = icps.getR4(0x01000005);
this.displayHeightWidthUnits = (int)icps.getUI4(0x01000006, 0L);
/*
System.out.println("\nImage Contents Property Set:\n");
System.out.println(" numResolutions = " + numResolutions);
System.out.println(" highestResWidth = " + highestResWidth);
System.out.println(" highestResHeight = " + highestResHeight);
System.out.println();
*/
this.subimageValid = new boolean[numResolutions];
this.subimageWidth = new int[numResolutions];
this.subimageHeight = new int[numResolutions];
this.subimageColor = new int[numResolutions][];
// subimageNumericalFormat
this.decimationMethod = new int[numResolutions];
this.decimationPrefilterWidth = new float[numResolutions];
// subimage ICC profile
for (int i = 0; i < numResolutions; i++) {
int index = i << 16;
if (!icps.hasProperty(0x02000000 | index)) {
break;
}
this.highestResolution = i;
subimageValid[i] = true;
subimageWidth[i] = (int)icps.getUI4(0x02000000 | index);
subimageHeight[i] = (int)icps.getUI4(0x02000001 | index);
byte[] subimageColorBlob = icps.getBlob(0x02000002 | index);
decimationMethod[i] = icps.getI4(0x02000004 | index);
// decimationPrefilterWidth[i] = icps.getR4(0x02000005 | index);
int numSubImages = FPXUtils.getIntLE(subimageColorBlob, 0);
int numChannels = FPXUtils.getIntLE(subimageColorBlob, 4);
// System.out.println(" subimageWidth[" + i + "] = " +
// subimageWidth[i]);
// System.out.println(" subimageHeight[" + i + "] = " +
// subimageHeight[i]);
// System.out.println(" subimageColor[" + i + "] = ");
// System.out.println(" numSubimages = " + numSubImages);
subimageColor[i] = new int[numChannels];
for (int c = 0; c < numChannels; c++) {
int color = FPXUtils.getIntLE(subimageColorBlob, 8 + 4*c);
subimageColor[i][c] = color;
// System.out.println(" channel " + c + " color space " +
// (color >> 16) +
// " (" + COLORSPACE_NAME[color >> 16] +")");
// System.out.println(" channel " + c + " color type " +
// (color & 0x7fff));
// if ((color & 0x8000) != 0) {
// System.out.println(" channel " + c + " has premultiplied opacity");
// }
}
// System.out.println(" decimationMethod[" + i + "] = " +
// decimationMethod[i]);
// System.out.println();
}
this.maxJPEGTableIndex = (int)icps.getUI4(0x03000002, -1L);
// System.out.println("maxJPEGTableIndex = " + maxJPEGTableIndex);
this.JPEGTable = new byte[maxJPEGTableIndex + 1][];
for (int i = 0; i <= maxJPEGTableIndex; i++) {
int index = i << 16;
if (icps.hasProperty(0x03000001 | index)) {
// System.out.println("Found a table at index " + i);
this.JPEGTable[i] = icps.getBlob(0x03000001 | index);
} else {
// System.out.println("No table at index " + i);
this.JPEGTable[i] = null;
}
}
}
private void readResolution() throws IOException {
if (resolution == -1) {
resolution = this.highestResolution;
}
// System.out.println("Reading resolution " + resolution);
storage.changeDirectoryToRoot();
storage.changeDirectory("Data Object Store 000001");
storage.changeDirectory("Resolution 000" + resolution); // FIX
this.subimageHeaderStream = storage.getStream("Subimage 0000 Header");
subimageHeaderStream.skip(28);
int headerLength = subimageHeaderStream.readIntLE();
this.width = subimageHeaderStream.readIntLE();
this.height = subimageHeaderStream.readIntLE();
int numTiles = subimageHeaderStream.readIntLE();
this.tileWidth = subimageHeaderStream.readIntLE();
this.tileHeight = subimageHeaderStream.readIntLE();
this.numChannels = subimageHeaderStream.readIntLE();
this.tileHeaderTableOffset = subimageHeaderStream.readIntLE() + 28;
this.tileHeaderEntryLength = subimageHeaderStream.readIntLE();
// System.out.println("\nResolution 000" + resolution + "\n");
// System.out.println("Subimage 0000 Header:\n");
// System.out.println(" headerLength = " + headerLength);
// System.out.println(" width = " + width);
// System.out.println(" height = " + height);
// System.out.println(" numTiles = " + numTiles);
// System.out.println(" tileWidth = " + tileWidth);
// System.out.println(" tileHeight = " + tileHeight);
// System.out.println(" numChannels = " + numChannels);
// System.out.println(" tileHeaderTableOffset = " +
// tileHeaderTableOffset);
// System.out.println(" tileHeaderEntryLength = " +
// tileHeaderEntryLength);
this.subimageDataStream = storage.getStream("Subimage 0000 Data");
// Compute derived values
tilesAcross = (width + tileWidth - 1)/tileWidth;
}
private int getTileOffset(int tileIndex) throws IOException {
// return tileOffset[tileIndex];
subimageHeaderStream.seek(tileHeaderTableOffset +
16*tileIndex);
return subimageHeaderStream.readIntLE() + 28;
}
private int getTileSize(int tileIndex) throws IOException {
// return tileSize[tileIndex];
subimageHeaderStream.seek(tileHeaderTableOffset +
16*tileIndex + 4);
return subimageHeaderStream.readIntLE();
}
private int getCompressionType(int tileIndex) throws IOException {
// return compressionType[tileIndex];
subimageHeaderStream.seek(tileHeaderTableOffset +
16*tileIndex + 8);
return subimageHeaderStream.readIntLE();
}
private int getCompressionSubtype(int tileIndex) throws IOException {
// return compressionSubtype[tileIndex];
subimageHeaderStream.seek(tileHeaderTableOffset +
16*tileIndex + 12);
return subimageHeaderStream.readIntLE();
}
private static final byte[] PhotoYCCToRGBLUT = {
(byte)0, (byte)1, (byte)1, (byte)2, (byte)2, (byte)3, (byte)4,
(byte)5, (byte)6, (byte)7, (byte)8, (byte)9, (byte)10, (byte)11,
(byte)12, (byte)13, (byte)14, (byte)15, (byte)16, (byte)17, (byte)18,
(byte)19, (byte)20, (byte)22, (byte)23, (byte)24, (byte)25, (byte)26,
(byte)28, (byte)29, (byte)30, (byte)31,
(byte)33, (byte)34, (byte)35, (byte)36, (byte)38, (byte)39,
(byte)40, (byte)41, (byte)43, (byte)44, (byte)45, (byte)47, (byte)48,
(byte)49, (byte)51, (byte)52, (byte)53, (byte)55, (byte)56, (byte)57,
(byte)59, (byte)60, (byte)61, (byte)63, (byte)64, (byte)65, (byte)67,
(byte)68, (byte)70, (byte)71, (byte)72, (byte)74,
(byte)75, (byte)76, (byte)78, (byte)79, (byte)81, (byte)82, (byte)83,
(byte)85, (byte)86, (byte)88, (byte)89, (byte)91, (byte)92, (byte)93,
(byte)95, (byte)96, (byte)98, (byte)99, (byte)101, (byte)102,
(byte)103, (byte)105, (byte)106, (byte)108, (byte)109, (byte)111,
(byte)112, (byte)113, (byte)115, (byte)116, (byte)118, (byte)119,
(byte)121, (byte)122, (byte)123, (byte)125, (byte)126, (byte)128,
(byte)129, (byte)130, (byte)132, (byte)133, (byte)134, (byte)136,
(byte)137, (byte)138, (byte)140, (byte)141, (byte)142, (byte)144,
(byte)145, (byte)146, (byte)148, (byte)149, (byte)150, (byte)152,
(byte)153, (byte)154, (byte)155, (byte)157, (byte)158, (byte)159,
(byte)160, (byte)162,
(byte)163, (byte)164, (byte)165, (byte)166, (byte)168, (byte)169,
(byte)170, (byte)171, (byte)172, (byte)174, (byte)175, (byte)176,
(byte)177, (byte)178, (byte)179, (byte)180, (byte)182, (byte)183,
(byte)184, (byte)185, (byte)186, (byte)187, (byte)188, (byte)189,
(byte)190, (byte)191, (byte)192, (byte)194, (byte)195, (byte)196,
(byte)197, (byte)198,
(byte)199, (byte)200, (byte)201, (byte)202, (byte)203, (byte)204,
(byte)204, (byte)205, (byte)206, (byte)207, (byte)208, (byte)209,
(byte)210, (byte)211, (byte)212, (byte)213, (byte)213, (byte)214,
(byte)215, (byte)216, (byte)217, (byte)217, (byte)218, (byte)219,
(byte)220, (byte)221, (byte)221, (byte)222, (byte)223, (byte)223,
(byte)224, (byte)225,
(byte)225, (byte)226, (byte)227, (byte)227, (byte)228, (byte)229,
(byte)229, (byte)230, (byte)230, (byte)231, (byte)231, (byte)232,
(byte)233, (byte)233, (byte)234, (byte)234, (byte)235, (byte)235,
(byte)236, (byte)236, (byte)236, (byte)237, (byte)237, (byte)238,
(byte)238, (byte)238, (byte)239, (byte)239, (byte)240, (byte)240,
(byte)240, (byte)241,
(byte)241, (byte)241, (byte)242, (byte)242, (byte)242, (byte)242,
(byte)243, (byte)243, (byte)243, (byte)244, (byte)244, (byte)244,
(byte)244, (byte)245, (byte)245, (byte)245, (byte)245, (byte)245,
(byte)246, (byte)246, (byte)246, (byte)246, (byte)246, (byte)247,
(byte)247, (byte)247, (byte)247, (byte)247, (byte)247, (byte)248,
(byte)248, (byte)248,
(byte)248, (byte)248, (byte)248, (byte)249, (byte)249, (byte)249,
(byte)249, (byte)249, (byte)249, (byte)249, (byte)249, (byte)249,
(byte)250, (byte)250, (byte)250, (byte)250, (byte)250, (byte)250,
(byte)250, (byte)250, (byte)250, (byte)250, (byte)251, (byte)251,
(byte)251, (byte)251, (byte)251, (byte)251, (byte)251, (byte)251,
(byte)251, (byte)251,
(byte)251, (byte)251, (byte)251, (byte)251, (byte)252, (byte)252,
(byte)252, (byte)252, (byte)252, (byte)252, (byte)252, (byte)252,
(byte)252, (byte)252, (byte)252, (byte)252, (byte)252, (byte)252,
(byte)252, (byte)252, (byte)252, (byte)253, (byte)253, (byte)253,
(byte)253, (byte)253, (byte)253, (byte)253, (byte)253, (byte)253,
(byte)253, (byte)253,
(byte)253, (byte)253, (byte)253, (byte)253, (byte)253, (byte)253,
(byte)253, (byte)254, (byte)254, (byte)254, (byte)254, (byte)254,
(byte)254, (byte)254, (byte)254, (byte)254, (byte)254, (byte)254,
(byte)254, (byte)254, (byte)254, (byte)254, (byte)255, (byte)255,
(byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255,
(byte)255, (byte)255,
(byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255,
(byte)255, (byte)255, (byte)255
};
private final byte PhotoYCCToNIFRed(float scaledY, float Cb, float Cr) {
float red = scaledY + 1.8215F*Cr - 249.55F;
if (red < 0.0F) {
return (byte)0;
} else if (red > 360.0F) {
return (byte)255;
} else {
byte r = PhotoYCCToRGBLUT[(int)red];
return r;
}
}
private final byte PhotoYCCToNIFGreen(float scaledY, float Cb, float Cr) {
float green = scaledY - .43031F*Cb - .9271F*Cr + 194.14F;
if (green < 0.0F) {
return (byte)0;
} else if (green > 360.0F) {
return (byte)255;
} else {
byte g = PhotoYCCToRGBLUT[(int)green];
return g;
}
}
private final byte PhotoYCCToNIFBlue(float scaledY, float Cb, float Cr) {
float blue = scaledY + 2.2179F*Cb - 345.99F;
if (blue < 0.0F) {
return (byte)0;
} else if (blue > 360.0F) {
return (byte)255;
} else {
byte b = PhotoYCCToRGBLUT[(int)blue];
return b;
}
}
private final byte YCCToNIFRed(float Y, float Cb, float Cr) {
float red = Y + 1.402F*Cr - (255.0F*.701F);
if (red < 0.0F) {
return (byte)0;
} else if (red > 255.0F) {
return (byte)255;
} else {
return (byte)red;
}
}
private final byte YCCToNIFGreen(float Y, float Cb, float Cr) {
float green = Y - .34414F*Cb - .71414F*Cr + (255.0F*.52914F);
if (green < 0.0F) {
return (byte)0;
} else if (green > 255.0F) {
return (byte)255;
} else {
return (byte)green;
}
}
private final byte YCCToNIFBlue(float Y, float Cb, float Cr) {
float blue = Y + 1.772F*Cb - (255.0F*.886F);
if (blue < 0.0F) {
return (byte)0;
} else if (blue > 255.0F) {
return (byte)255;
} else {
return (byte)blue;
}
}
private Raster getUncompressedTile(int tileX, int tileY)
throws IOException {
int tx = tileXToX(tileX);
int ty = tileYToY(tileY);
Raster ras =
RasterFactory.createInterleavedRaster(DataBuffer.TYPE_BYTE,
tileWidth,
tileHeight,
numChannels*tileWidth,
numChannels,
bandOffsets,
new Point(tx, ty));
// System.out.println("Uncompressed tile.");
DataBufferByte dataBuffer = (DataBufferByte)ras.getDataBuffer();
byte[] data = dataBuffer.getData();
int tileIndex = tileY*tilesAcross + tileX;
subimageDataStream.seek(getTileOffset(tileIndex));
subimageDataStream.readFully(data, 0,
numChannels*tileWidth*tileHeight);
// Color convert if subimage is in PhotoYCC format
if (subimageColor[resolution][0] >> 16 == 2) {
int size = tileWidth*tileHeight;
for (int i = 0; i < size; i++) {
float Y = data[3*i] & 0xff;
float Cb = data[3*i + 1] & 0xff;
float Cr = data[3*i + 2] & 0xff;
float scaledY = Y*1.3584F;
byte red = PhotoYCCToNIFRed(scaledY, Cb, Cr);
byte green = PhotoYCCToNIFGreen(scaledY, Cb, Cr);
byte blue = PhotoYCCToNIFBlue(scaledY, Cb, Cr);
data[3*i] = red;
data[3*i + 1] = green;
data[3*i + 2] = blue;
}
}
return ras;
}
private Raster getSingleColorCompressedTile(int tileX, int tileY)
throws IOException {
// System.out.println("Single color compressed tile.");
int tx = tileXToX(tileX);
int ty = tileYToY(tileY);
Raster ras =
RasterFactory.createInterleavedRaster(DataBuffer.TYPE_BYTE,
tileWidth,
tileHeight,
numChannels*tileWidth,
numChannels,
bandOffsets,
new Point(tx, ty));
int subimageColorType = subimageColor[resolution][0] >> 16;
DataBufferByte dataBuffer = (DataBufferByte)ras.getDataBuffer();
byte[] data = dataBuffer.getData();
int tileIndex = tileY*tilesAcross + tileX;
int color = getCompressionSubtype(tileIndex);
byte c0 = (byte)((color >> 0) & 0xff);
byte c1 = (byte)((color >> 8) & 0xff);
byte c2 = (byte)((color >> 16) & 0xff);
byte alpha = (byte)((color >> 24) & 0xff);
byte red, green, blue;
// Color convert if subimage is in PhotoYCC format
if (subimageColor[resolution][0] >> 16 == 2) {
float Y = c0 & 0xff;
float Cb = c1 & 0xff;
float Cr = c2 & 0xff;
float scaledY = Y*1.3584F;
red = PhotoYCCToNIFRed(scaledY, Cb, Cr);
green = PhotoYCCToNIFGreen(scaledY, Cb, Cr);
blue = PhotoYCCToNIFBlue(scaledY, Cb, Cr);
} else {
red = c0;
green = c1;
blue = c2;
}
int index = 0;
int pixels = tileWidth*tileHeight;
if (numChannels == 1) {
} else if (numChannels == 2) {
} else if (numChannels == 3) {
for (int i = 0; i < pixels; i++) {
data[index + 0] = red;
data[index + 1] = green;
data[index + 2] = blue;
index += 3;
}
} else if (numChannels == 4) {
for (int i = 0; i < pixels; i++) {
data[index + 0] = red;
data[index + 1] = green;
data[index + 2] = blue;
data[index + 3] = alpha;
index += 4;
}
}
return ras;
}
private Raster getJPEGCompressedTile(int tileX, int tileY)
throws IOException {
// System.out.println("JPEG compressed tile.");
int tileIndex = tileY*tilesAcross + tileX;
int tx = tileXToX(tileX);
int ty = tileYToY(tileY);
int subtype = getCompressionSubtype(tileIndex);
int interleave = (subtype >> 0) & 0xff;
int chroma = (subtype >> 8) & 0xff;
int conversion = (subtype >> 16) & 0xff;
int table = (subtype >> 24) & 0xff;
JPEGImageDecoder dec;
JPEGDecodeParam param = null;
if (table != 0) {
InputStream tableStream =
new ByteArrayInputStream(JPEGTable[table]);
dec = JPEGCodec.createJPEGDecoder(tableStream);
Raster junk = dec.decodeAsRaster();
param = dec.getJPEGDecodeParam();
}
subimageDataStream.seek(getTileOffset(tileIndex));
if (param != null) {
dec = JPEGCodec.createJPEGDecoder(subimageDataStream, param);
} else {
dec = JPEGCodec.createJPEGDecoder(subimageDataStream);
}
Raster ras = dec.decodeAsRaster().createTranslatedChild(tx, ty);
DataBufferByte dataBuffer = (DataBufferByte)ras.getDataBuffer();
byte[] data = dataBuffer.getData();
int subimageColorType = subimageColor[resolution][0] >> 16;
int size = tileWidth*tileHeight;
if ((conversion == 0) && (subimageColorType == 2)) {
// System.out.println("Converting PhotoYCC to NIFRGB");
int offset = 0;
for (int i = 0; i < size; i++) {
float Y = data[offset] & 0xff;
float Cb = data[offset + 1] & 0xff;
float Cr = data[offset + 2] & 0xff;
float scaledY = Y*1.3584F;
byte red = PhotoYCCToNIFRed(scaledY, Cb, Cr);
byte green = PhotoYCCToNIFGreen(scaledY, Cb, Cr);
byte blue = PhotoYCCToNIFBlue(scaledY, Cb, Cr);
data[offset] = red;
data[offset + 1] = green;
data[offset + 2] = blue;
offset += numChannels;
}
} else if ((conversion == 1) && (subimageColorType == 3)) {
// System.out.println("Converting YCC to NIFRGB");
int offset = 0;
for (int i = 0; i < size; i++) {
float Y = data[offset] & 0xff;
float Cb = data[offset + 1] & 0xff;
float Cr = data[offset + 2] & 0xff;
byte red = YCCToNIFRed(Y, Cb, Cr);
byte green = YCCToNIFGreen(Y, Cb, Cr);
byte blue = YCCToNIFBlue(Y, Cb, Cr);
data[offset] = red;
data[offset + 1] = green;
data[offset + 2] = blue;
offset += numChannels;
}
}
// Perform special inversion step when output space is
// NIF RGB (subimageColorType == 3) with premultiplied opacity
// (numChannels == 4).
if ((conversion == 1) &&
(subimageColorType == 3) && (numChannels == 4)) {
// System.out.println("Flipping NIFRGB");
int offset = 0;
for (int i = 0; i < size; i++) {
data[offset + 0] = (byte)(255 - data[offset + 0]);
data[offset + 1] = (byte)(255 - data[offset + 1]);
data[offset + 2] = (byte)(255 - data[offset + 2]);
offset += 4;
}
}
return ras;
}
public synchronized Raster getTile(int tileX, int tileY) {
int tileIndex = tileY*tilesAcross + tileX;
try {
int ctype = getCompressionType(tileIndex);
if (ctype == 0) {
return getUncompressedTile(tileX, tileY);
} else if (ctype == 1) {
return getSingleColorCompressedTile(tileX, tileY);
} else if (ctype == 2) {
return getJPEGCompressedTile(tileX, tileY);
}
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Hashtable properties = null;
private void addLPSTRProperty(String name, PropertySet ps, int id) {
String s = ps.getLPSTR(id);
if (s != null) {
properties.put(name.toLowerCase(), s);
}
}
private void addLPWSTRProperty(String name, PropertySet ps, int id) {
String s = ps.getLPWSTR(id);
if (s != null) {
properties.put(name.toLowerCase(), s);
}
}
private void addUI4Property(String name, PropertySet ps, int id) {
if (ps.hasProperty(id)) {
long i = ps.getUI4(id);
properties.put(name.toLowerCase(), new Integer((int)i));
}
}
private void getSummaryInformation() {
SeekableStream summaryInformation = null;
PropertySet sips = null;
try {
storage.changeDirectoryToRoot();
summaryInformation = storage.getStream("SummaryInformation");
sips = new PropertySet(summaryInformation);
} catch (IOException e) {
e.printStackTrace();
return;
}
addLPSTRProperty("title", sips, 0x000000002);
addLPSTRProperty("subject", sips, 0x000000003);
addLPSTRProperty("author", sips, 0x000000004);
addLPSTRProperty("keywords", sips, 0x000000005);
addLPSTRProperty("comments", sips, 0x000000006);
addLPSTRProperty("template", sips, 0x000000007);
addLPSTRProperty("last saved by", sips, 0x000000008);
addLPSTRProperty("revision number", sips, 0x000000009);
}
private void getImageInfo() {
SeekableStream imageInfo = null;
PropertySet iips = null;
try {
storage.changeDirectoryToRoot();
imageInfo = storage.getStream("Image Info");
if (imageInfo == null) {
return;
}
iips = new PropertySet(imageInfo);
} catch (IOException e) {
e.printStackTrace();
return;
}
addUI4Property("file source", iips, 0x21000000);
addUI4Property("scene type", iips, 0x21000001);
// creation path vector
addLPWSTRProperty("software name/manufacturer/release",
iips, 0x21000003);
addLPWSTRProperty("user defined id",
iips, 0x21000004);
addLPWSTRProperty("copyright message",
iips, 0x22000000);
addLPWSTRProperty("legal broker for the original image",
iips, 0x22000001);
addLPWSTRProperty("legal broker for the digital image",
iips, 0x22000002);
addLPWSTRProperty("authorship", iips, 0x22000003);
addLPWSTRProperty("intellectual property notes", iips, 0x22000004);
}
private synchronized void getProperties() {
if (properties != null) {
return;
}
properties = new Hashtable();
getSummaryInformation();
getImageInfo();
// Ad hoc properties
properties.put("max_resolution", new Integer(highestResolution));
}
public String[] getPropertyNames() {
getProperties();
int len = properties.size();
String[] names = new String[len];
Enumeration enum1 = properties.keys();
int count = 0;
while (enum1.hasMoreElements()) {
names[count++] = (String)enum1.nextElement();
}
return names;
}
public Object getProperty(String name) {
getProperties();
return properties.get(name.toLowerCase());
}
}