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.
329 lines
12 KiB
329 lines
12 KiB
package com.fr.third.JAI; |
|
/* |
|
* 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. |
|
*/ |
|
import java.awt.Point; |
|
import java.awt.Rectangle; |
|
import java.awt.Transparency; |
|
import java.awt.color.ColorSpace; |
|
import java.awt.image.ComponentColorModel; |
|
import java.awt.image.DataBuffer; |
|
import java.awt.image.DataBufferByte; |
|
import java.awt.image.DataBufferInt; |
|
import java.awt.image.DataBufferUShort; |
|
import java.awt.image.IndexColorModel; |
|
import java.awt.image.MultiPixelPackedSampleModel; |
|
import java.awt.image.Raster; |
|
import java.awt.image.RenderedImage; |
|
import java.awt.image.SampleModel; |
|
import java.awt.image.WritableRaster; |
|
import java.io.IOException; |
|
|
|
/** |
|
*/ |
|
public class PNMImageDecoder extends ImageDecoderImpl { |
|
|
|
public PNMImageDecoder(SeekableStream input, |
|
ImageDecodeParam param) { |
|
super(input, param); |
|
} |
|
|
|
public RenderedImage decodeAsRenderedImage(int page) throws IOException { |
|
if (page != 0) { |
|
throw new IOException(JaiI18N.getString("PNMImageDecoder5")); |
|
} |
|
return new PNMImage(input); |
|
} |
|
} |
|
|
|
class PNMImage extends SimpleRenderedImage { |
|
|
|
private static final int PBM_ASCII = '1'; |
|
private static final int PGM_ASCII = '2'; |
|
private static final int PPM_ASCII = '3'; |
|
private static final int PBM_RAW = '4'; |
|
private static final int PGM_RAW = '5'; |
|
private static final int PPM_RAW = '6'; |
|
|
|
private static final int LINE_FEED = 0x0A; |
|
|
|
private SeekableStream input; |
|
|
|
private byte[] lineSeparator; |
|
|
|
/** File variant: PBM/PGM/PPM, ASCII/RAW. */ |
|
private int variant; |
|
|
|
/** Maximum pixel value. */ |
|
private int maxValue; |
|
|
|
/** Raster that is the entire image. */ |
|
private Raster theTile; |
|
|
|
private int numBands; |
|
|
|
private int dataType; |
|
|
|
/** |
|
* Construct a PNMImage. |
|
* |
|
* @param input The SeekableStream for the PNM file. |
|
*/ |
|
public PNMImage(SeekableStream input) { |
|
theTile = null; |
|
|
|
this.input = input; |
|
|
|
String ls = (String)java.security.AccessController.doPrivileged( |
|
new sun.security.action.GetPropertyAction("line.separator")); |
|
lineSeparator = ls.getBytes(); |
|
|
|
// Read file header. |
|
try { |
|
if (this.input.read() != 'P') { // magic number |
|
throw new RuntimeException(JaiI18N.getString("PNMImageDecoder0")); |
|
} |
|
|
|
variant = this.input.read(); // file variant |
|
if ((variant < PBM_ASCII) || (variant > PPM_RAW)) { |
|
throw new RuntimeException(JaiI18N.getString("PNMImageDecoder1")); |
|
} |
|
|
|
width = readInteger(this.input); // width |
|
height = readInteger(this.input); // height |
|
|
|
if (variant == PBM_ASCII || variant == PBM_RAW) { |
|
maxValue = 1; |
|
} else { |
|
maxValue = readInteger(this.input); // maximum value |
|
} |
|
} catch (IOException e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(JaiI18N.getString("PNMImageDecoder2")); |
|
} |
|
|
|
// The RAWBITS format can only support byte image data, which means |
|
// maxValue should be less than 0x100. In case there's a conflict, |
|
// base the maxValue on variant. |
|
if (isRaw(variant) && maxValue >= 0x100) { |
|
maxValue = 0xFF; |
|
} |
|
|
|
// Reset image layout so there's only one tile. |
|
tileWidth = width; |
|
tileHeight = height; |
|
|
|
// Determine number of bands: pixmap (PPM) is 3 bands, |
|
// bitmap (PBM) and greymap (PGM) are 1 band. |
|
if (variant == PPM_ASCII || variant == PPM_RAW) { |
|
this.numBands = 3; |
|
} else { |
|
this.numBands = 1; |
|
} |
|
|
|
// Determine data type based on maxValue. |
|
if (maxValue < 0x100) { |
|
this.dataType = DataBuffer.TYPE_BYTE; |
|
} else if (maxValue < 0x10000) { |
|
this.dataType = DataBuffer.TYPE_USHORT; |
|
} else { |
|
this.dataType = DataBuffer.TYPE_INT; |
|
} |
|
|
|
// Choose an appropriate SampleModel. |
|
if ((variant == PBM_ASCII) || (variant == PBM_RAW)) { |
|
// Each pixel takes 1 bit, pack 8 pixels into a byte. |
|
sampleModel = new MultiPixelPackedSampleModel( |
|
DataBuffer.TYPE_BYTE, width, height, 1); |
|
colorModel = |
|
ImageCodec.createGrayIndexColorModel(sampleModel, false); |
|
} else { |
|
int[] bandOffsets = numBands == 1 ? |
|
new int[] {0} : new int[] {0, 1, 2}; |
|
sampleModel = RasterFactory.createPixelInterleavedSampleModel( |
|
dataType, tileWidth, tileHeight, |
|
numBands, tileWidth*numBands, |
|
bandOffsets); |
|
|
|
colorModel = |
|
ImageCodec.createComponentColorModel(sampleModel); |
|
} |
|
} |
|
|
|
/** Returns true if file variant is raw format, false if ASCII. */ |
|
private boolean isRaw(int v) { |
|
return (v >= PBM_RAW); |
|
} |
|
|
|
/** Reads the next integer. */ |
|
private int readInteger(SeekableStream in) throws IOException { |
|
int ret = 0; |
|
boolean foundDigit = false; |
|
|
|
int b; |
|
while ((b = in.read()) != -1) { |
|
char c = (char)b; |
|
if (Character.isDigit(c)) { |
|
ret = ret * 10 + Character.digit(c, 10); |
|
foundDigit = true; |
|
} else { |
|
if (c == '#') { // skip to the end of comment line |
|
int length = lineSeparator.length; |
|
|
|
while ((b = in.read()) != -1) { |
|
boolean eol = false; |
|
for (int i = 0; i < length; i++) { |
|
if (b == lineSeparator[i]) { |
|
eol = true; |
|
break; |
|
} |
|
} |
|
if (eol) { |
|
break; |
|
} |
|
} |
|
if (b == -1) { |
|
break; |
|
} |
|
} |
|
if (foundDigit) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
private Raster computeTile(int tileX, int tileY) { |
|
// Create a new tile. |
|
Point org = new Point(tileXToX(tileX), tileYToY(tileY)); |
|
WritableRaster tile = Raster.createWritableRaster(sampleModel, org); |
|
Rectangle tileRect = tile.getBounds(); |
|
|
|
// There should only be one tile. |
|
try { |
|
switch (variant) { |
|
case PBM_ASCII: |
|
case PBM_RAW: |
|
// SampleModel for these cases should be MultiPixelPacked. |
|
|
|
DataBuffer dataBuffer = tile.getDataBuffer(); |
|
if (isRaw(variant)) { |
|
// Read the entire image. |
|
byte[] buf = ((DataBufferByte)dataBuffer).getData(); |
|
input.readFully(buf, 0, buf.length); |
|
} else { |
|
// Read 8 rows at a time |
|
byte[] pixels = new byte[8*width]; |
|
int offset = 0; |
|
for (int row = 0; row < tileHeight; row += 8) { |
|
int rows = Math.min(8, tileHeight - row); |
|
int len = (rows*width + 7)/8; |
|
|
|
for (int i = 0; i < rows*width; i++) { |
|
pixels[i] = (byte)readInteger(input); |
|
} |
|
sampleModel.setDataElements(tileRect.x, |
|
row, |
|
tileRect.width, |
|
rows, |
|
pixels, |
|
dataBuffer); |
|
} |
|
} |
|
break; |
|
|
|
case PGM_ASCII: |
|
case PGM_RAW: |
|
case PPM_ASCII: |
|
case PPM_RAW: |
|
// SampleModel for these cases should be PixelInterleaved. |
|
int size = width*height*numBands; |
|
|
|
switch (dataType) { |
|
case DataBuffer.TYPE_BYTE: |
|
DataBufferByte bbuf = |
|
(DataBufferByte)tile.getDataBuffer(); |
|
byte[] byteArray = bbuf.getData(); |
|
if (isRaw(variant)) { |
|
input.readFully(byteArray); |
|
} else { |
|
for (int i = 0; i < size; i++) { |
|
byteArray[i] = (byte)readInteger(input); |
|
} |
|
} |
|
break; |
|
|
|
case DataBuffer.TYPE_USHORT: |
|
DataBufferUShort sbuf = |
|
(DataBufferUShort)tile.getDataBuffer(); |
|
short[] shortArray = sbuf.getData(); |
|
for (int i = 0; i < size; i++) { |
|
shortArray[i] = (short)readInteger(input); |
|
} |
|
break; |
|
|
|
case DataBuffer.TYPE_INT: |
|
DataBufferInt ibuf = |
|
(DataBufferInt)tile.getDataBuffer(); |
|
int[] intArray = ibuf.getData(); |
|
for (int i = 0; i < size; i++) { |
|
intArray[i] = readInteger(input); |
|
} |
|
break; |
|
} |
|
break; |
|
} |
|
|
|
// Close the PNM stream and release system resources. |
|
input.close(); |
|
} catch (IOException e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(JaiI18N.getString("PNMImageDecoder3")); |
|
} |
|
|
|
return tile; |
|
} |
|
|
|
public synchronized Raster getTile(int tileX, int tileY) { |
|
if ((tileX != 0) || (tileY != 0)) { |
|
throw new IllegalArgumentException(JaiI18N.getString("PNMImageDecoder4")); |
|
} |
|
|
|
if (theTile == null) { |
|
theTile = computeTile(tileX, tileY); |
|
} |
|
|
|
return theTile; |
|
} |
|
}
|
|
|