Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* $RCSfile: PNMImageReader.java,v $
*
*
* Copyright (c) 2005 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:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce 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 MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for
* use in the design, construction, operation or maintenance of any
* nuclear facility.
*
* $Revision: 1.1 $
* $Date: 2005/02/11 05:01:40 $
* $State: Exp $
*/
package com.github.jaiimageio.impl.plugins.pnm;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
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.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import com.github.jaiimageio.impl.common.ImageUtil;
/** This class is the Java Image IO plugin reader for PNM images.
* It may subsample the image, clip the image, select sub-bands,
* and shift the decoded image origin if the proper decoding parameter
* are set in the provided PNMImageReadParam.
*/
public class PNMImageReader extends ImageReader {
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 static byte[] lineSeparator;
static {
if (lineSeparator == null) {
lineSeparator = System.getProperty("line.separator").getBytes();
}
}
/** File variant: PBM/PGM/PPM, ASCII/RAW. */
private int variant;
/** Maximum pixel value. */
private int maxValue;
/** The input stream where reads from */
private ImageInputStream iis = null;
/** Indicates whether the header is read. */
private boolean gotHeader = false;
/** The stream position where the image data starts. */
private long imageDataOffset;
/** The original image width. */
private int width;
/** The original image height. */
private int height;
private String aLine;
private StringTokenizer token;
private PNMMetadata metadata;
/** Constructs PNMImageReader from the provided
* ImageReaderSpi.
*/
public PNMImageReader(ImageReaderSpi originator) {
super(originator);
}
/** Overrides the method defined in the superclass. */
public void setInput(Object input,
boolean seekForwardOnly,
boolean ignoreMetadata) {
super.setInput(input, seekForwardOnly, ignoreMetadata);
iis = (ImageInputStream) input; // Always works
}
/** Overrides the method defined in the superclass. */
public int getNumImages(boolean allowSearch) throws IOException {
return 1;
}
public int getWidth(int imageIndex) throws IOException {
checkIndex(imageIndex);
readHeader();
return width;
}
public int getHeight(int imageIndex) throws IOException {
checkIndex(imageIndex);
readHeader();
return height;
}
public int getVariant() {
return variant;
}
public int getMaxValue() {
return maxValue;
}
private void checkIndex(int imageIndex) {
if (imageIndex != 0) {
throw new IndexOutOfBoundsException(I18N.getString("PNMImageReader1"));
}
}
public synchronized void readHeader() throws IOException {
if (gotHeader) {
// Seek to where the image data starts, since that is where
// the stream pointer should be after header is read
iis.seek(imageDataOffset);
return;
}
if (iis != null) {
if (iis.readByte() != 'P') { // magic number
throw new RuntimeException(I18N.getString("PNMImageReader0"));
}
variant = iis.readByte(); // file variant
if ((variant < PBM_ASCII) || (variant > PPM_RAW)) {
throw new RuntimeException(I18N.getString("PNMImageReader0"));
}
// Create the metadata object.
metadata = new PNMMetadata();
// Set the variant.
metadata.setVariant(variant);
// Read the line separator.
iis.readLine();
readComments(iis, metadata);
width = readInteger(iis); // width
height = readInteger(iis); // height
if (variant == PBM_ASCII || variant == PBM_RAW) {
maxValue = 1;
} else {
maxValue = readInteger(iis); // maximum value
}
metadata.setWidth(width);
metadata.setHeight(height);
metadata.setMaxBitDepth(maxValue);
gotHeader = true;
// Store the stream position where the image data starts
imageDataOffset = iis.getStreamPosition();
}
}
public Iterator getImageTypes(int imageIndex)
throws IOException {
checkIndex(imageIndex);
readHeader();
int tmp = (variant - '1') % 3 ;
ArrayList list = new ArrayList(1);
int dataType = DataBuffer.TYPE_INT;
// Determine data type based on maxValue.
if (maxValue < 0x100) {
dataType = DataBuffer.TYPE_BYTE;
} else if (maxValue < 0x10000) {
dataType = DataBuffer.TYPE_USHORT;
}
// Choose an appropriate SampleModel.
SampleModel sampleModel = null;
ColorModel colorModel = null;
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);
byte[] color = {(byte)0xFF, (byte)0};
colorModel = new IndexColorModel(1, 2, color, color, color);
} else {
sampleModel =
new PixelInterleavedSampleModel(dataType,
width,
height,
tmp == 1 ? 1 : 3,
width * (tmp == 1 ? 1 : 3),
tmp == 1 ? new int[]{0} : new int[]{0, 1, 2});
colorModel = ImageUtil.createColorModel(null, sampleModel);
}
list.add(new ImageTypeSpecifier(colorModel, sampleModel));
return list.iterator();
}
public ImageReadParam getDefaultReadParam() {
return new ImageReadParam();
}
public IIOMetadata getImageMetadata(int imageIndex)
throws IOException {
checkIndex(imageIndex);
readHeader();
return metadata;
}
public IIOMetadata getStreamMetadata() throws IOException {
return null;
}
public boolean isRandomAccessEasy(int imageIndex) throws IOException {
checkIndex(imageIndex);
return true;
}
public BufferedImage read(int imageIndex, ImageReadParam param)
throws IOException {
checkIndex(imageIndex);
clearAbortRequest();
processImageStarted(imageIndex);
if (param == null)
param = getDefaultReadParam();
//read header
readHeader();
Rectangle sourceRegion = new Rectangle(0, 0, 0, 0);
Rectangle destinationRegion = new Rectangle(0, 0, 0, 0);
computeRegions(param, this.width, this.height,
param.getDestination(),
sourceRegion,
destinationRegion);
int scaleX = param.getSourceXSubsampling();
int scaleY = param.getSourceYSubsampling();
// If the destination band is set used it
int[] sourceBands = param.getSourceBands();
int[] destBands = param.getDestinationBands();
boolean seleBand = (sourceBands != null) && (destBands != null);
boolean noTransform =
destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
seleBand;
// 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;
}
int numBands = 1;
// Determine number of bands: pixmap (PPM) is 3 bands,
// bitmap (PBM) and greymap (PGM) are 1 band.
if (variant == PPM_ASCII || variant == PPM_RAW) {
numBands = 3;
}
if (!seleBand) {
sourceBands = new int[numBands];
destBands = new int[numBands];
for (int i = 0; i < numBands; i++)
destBands[i] = sourceBands[i] = i;
}
int dataType = DataBuffer.TYPE_INT;
// Determine data type based on maxValue.
if (maxValue < 0x100) {
dataType = DataBuffer.TYPE_BYTE;
} else if (maxValue < 0x10000) {
dataType = DataBuffer.TYPE_USHORT;
}
// Choose an appropriate SampleModel.
SampleModel sampleModel = null;
ColorModel colorModel = null;
if ((variant == PBM_ASCII) || (variant == PBM_RAW)) {
// Each pixel takes 1 bit, pack 8 pixels into a byte.
sampleModel = new MultiPixelPackedSampleModel(
DataBuffer.TYPE_BYTE,
destinationRegion.width,
destinationRegion.height,
1);
byte[] color = {(byte)0xFF, (byte)0};
colorModel = new IndexColorModel(1, 2, color, color, color);
} else {
sampleModel =
new PixelInterleavedSampleModel(dataType,
destinationRegion.width,
destinationRegion.height,
sourceBands.length,
destinationRegion.width *
sourceBands.length,
destBands);
colorModel = ImageUtil.createColorModel(null, sampleModel);
}
// If the destination is provided, then use it. Otherwise, create new
// one
BufferedImage bi = param.getDestination();
// Get the image data.
WritableRaster raster = null;
if (bi == null) {
sampleModel = sampleModel.createCompatibleSampleModel(
destinationRegion.x + destinationRegion.width,
destinationRegion.y + destinationRegion.height);
if (seleBand)
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
raster = Raster.createWritableRaster(sampleModel, new Point());
bi = new BufferedImage(colorModel, raster, false, null);
} else {
raster = bi.getWritableTile(0, 0);
sampleModel = bi.getSampleModel();
colorModel = bi.getColorModel();
noTransform &= destinationRegion.equals(raster.getBounds());
}
switch (variant) {
case PBM_RAW:
{
// SampleModel for these cases should be MultiPixelPacked.
DataBuffer dataBuffer = raster.getDataBuffer();
// Read the entire image.
byte[] buf = ((DataBufferByte)dataBuffer).getData();
if (noTransform) {
iis.readFully(buf, 0, buf.length);
processImageUpdate(bi,
0, 0,
width, height, 1, 1,
destBands);
processImageProgress(100.0F);
} else if (scaleX == 1 && sourceRegion.x % 8 == 0) {
int skip = sourceRegion.x >> 3;
int originalLS = width + 7 >> 3;
int destLS = raster.getWidth() + 7 >> 3;
int readLength = sourceRegion.width + 7 >> 3;
int offset = sourceRegion.y * originalLS;
iis.skipBytes(offset + skip);
offset = originalLS * (scaleY - 1) + originalLS - readLength;
byte[] lineData = new byte[readLength];
int bitoff = destinationRegion.x & 7;
boolean reformat = !(bitoff == 0);
for (int i = 0, j = 0,
k = destinationRegion.y * destLS + (destinationRegion.x >> 3);
i < destinationRegion.height; i++, j += scaleY) {
if (reformat) {
iis.read(lineData, 0, readLength);
int mask1 = (255 << bitoff) & 255;
int mask2 = ~mask1 & 255;
int shift = 8 - bitoff;
int n = 0;
int m = k;
for (; n < readLength -1; n++, m++)
buf[m] = (byte)(((lineData[n] & mask2) << shift) |
(lineData[n + 1] & mask1) >>bitoff);
buf[m] = (byte)((lineData[n] & mask2) << shift);
} else {
iis.read(buf, k, readLength);
}
iis.skipBytes(offset);
k += destLS;
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
} else {
int originalLS = width + 7 >> 3;
byte[] data = new byte[originalLS];
iis.skipBytes(sourceRegion.y * originalLS);
int destLS = bi.getWidth() + 7 >> 3;
int offset = originalLS * (scaleY - 1);
int dsx = destLS * destinationRegion.y +
(destinationRegion.x >> 3);
for (int i = 0, j = 0, n = dsx;
i < destinationRegion.height; i++, j += scaleY) {
iis.read(data, 0, originalLS);
iis.skipBytes(offset);
int b = 0;
int pos = 7 - (destinationRegion.x & 7);
for (int m = sourceRegion.x;
m < sourceRegion.x + sourceRegion.width;
m += scaleX) {
b |= (data[m >> 3] >> (7 - (m & 7)) & 1) << pos;
pos--;
if (pos == -1) {
buf[n++] = (byte)b;
b = 0;
pos = 7;
}
}
if (pos != 7)
buf[n++] = (byte)b;
n += destinationRegion.x >> 3;
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
}
break;
}
case PBM_ASCII:
{
DataBuffer dataBuffer = raster.getDataBuffer();
byte[] buf = ((DataBufferByte)dataBuffer).getData();
if (noTransform)
for (int i = 0, n = 0; i < height; i++) {
int b = 0;
int pos = 7;
for (int j = 0; j < width; j++) {
b |= (readInteger(iis) & 1) << pos;
pos--;
if (pos == -1 ) {
buf[n++] = (byte)b;
b = 0;
pos = 7;
}
}
if (pos != 7)
buf[n++] = (byte)b;
processImageUpdate(bi,
0, i,
width, 1, 1, 1,
destBands);
processImageProgress(100.0F * i / height);
}
else {
skipInteger(iis, sourceRegion.y * width + sourceRegion.x);
int skipX = scaleX - 1;
int skipY = (scaleY - 1) * width +
width - destinationRegion.width * scaleX;
int dsx = (bi.getWidth() + 7 >> 3) *
destinationRegion.y + (destinationRegion.x >> 3);
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
int b = 0;
int pos = 7 - (destinationRegion.x & 7);
for (int j = 0; j < destinationRegion.width; j++) {
b |= (readInteger(iis) & 1) << pos;
pos--;
if (pos == -1 ) {
buf[n++] = (byte)b;
b = 0;
pos = 7;
}
skipInteger(iis, skipX);
}
if (pos != 7)
buf[n++] = (byte)b;
n += destinationRegion.x >> 3;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
}
break;
}
case PGM_ASCII:
case PGM_RAW:
case PPM_ASCII:
case PPM_RAW:
// SampleModel for these cases should be PixelInterleaved.
int skipX = (scaleX - 1) * numBands;
int skipY = (scaleY * width -
destinationRegion.width * scaleX) * numBands;
int dsx = (bi.getWidth() * destinationRegion. y +
destinationRegion.x) * numBands;
switch (dataType) {
case DataBuffer.TYPE_BYTE:
DataBufferByte bbuf =
(DataBufferByte)raster.getDataBuffer();
byte[] byteArray = bbuf.getData();
if (isRaw(variant)) {
if (noTransform) {
iis.readFully(byteArray);
processImageUpdate(bi,
0, 0,
width, height, 1, 1,
destBands);
processImageProgress(100.0F);
} else {
iis.skipBytes(sourceRegion.y * width * numBands);
int skip = (scaleY - 1) * width * numBands;
byte[] data = new byte[width * numBands];
int pixelStride = scaleX * numBands;
int sx = sourceRegion.x * numBands;
int ex = width;
for (int i = 0, n = dsx ; i < destinationRegion.height; i++) {
iis.read(data);
for (int j = sourceRegion.x, k = sx;
j < sourceRegion.x + sourceRegion.width;
j+= scaleX, k += pixelStride) {
for (int m = 0; m < sourceBands.length; m++)
byteArray[n+ destBands[m]] = data[k + sourceBands[m]];
n += sourceBands.length;
}
n += destinationRegion.x * numBands;
iis.skipBytes(skip);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
}
} else {
skipInteger(iis,
(sourceRegion.y * width + sourceRegion.x) *
numBands);
if (seleBand) {
byte[] data = new byte[numBands];
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
data[k] = (byte)readInteger(iis);
for (int k = 0; k < sourceBands.length; k++)
byteArray[n+destBands[k]] = data[sourceBands[k]];
n += sourceBands.length;
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
} else
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
byteArray[n++] = (byte)readInteger(iis);
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
}
break;
case DataBuffer.TYPE_USHORT:
DataBufferUShort sbuf =
(DataBufferUShort)raster.getDataBuffer();
short[] shortArray = sbuf.getData();
skipInteger(iis, sourceRegion.y * width * numBands + sourceRegion.x);
if (seleBand) {
short[] data = new short[numBands];
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
data[k] = (short)readInteger(iis);
for (int k = 0; k < sourceBands.length; k++)
shortArray[n+destBands[k]] = data[sourceBands[k]];
n += sourceBands.length;
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
} else
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
shortArray[n++] = (short)readInteger(iis);
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
break;
case DataBuffer.TYPE_INT:
DataBufferInt ibuf =
(DataBufferInt)raster.getDataBuffer();
int[] intArray = ibuf.getData();
skipInteger(iis, sourceRegion.y * width * numBands + sourceRegion.x);
if (seleBand) {
int[] data = new int[numBands];
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
data[k] = readInteger(iis);
for (int k = 0; k < sourceBands.length; k++)
intArray[n+destBands[k]] = data[sourceBands[k]];
n += sourceBands.length;
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
} else
for (int i = 0, n = dsx; i < destinationRegion.height; i++) {
for (int j = 0; j < destinationRegion.width; j++) {
for (int k = 0; k < numBands; k++)
intArray[n++] = readInteger(iis);
skipInteger(iis, skipX);
}
n += destinationRegion.x * sourceBands.length;
skipInteger(iis, skipY);
processImageUpdate(bi,
0, i,
destinationRegion.width, 1, 1, 1,
destBands);
processImageProgress(100.0F*i/destinationRegion.height);
}
break;
}
break;
}
if (abortRequested())
processReadAborted();
else
processImageComplete();
return bi;
}
public boolean canReadRaster() {
return true;
}
public Raster readRaster(int imageIndex,
ImageReadParam param) throws IOException {
BufferedImage bi = read(imageIndex, param);
return bi.getData();
}
public void reset() {
super.reset();
iis = null;
gotHeader = false;
System.gc();
}
/** Returns true if file variant is raw format, false if ASCII. */
private boolean isRaw(int v) {
return (v >= PBM_RAW);
}
/** Reads the comments. */
private void readComments(ImageInputStream stream,
PNMMetadata metadata) throws IOException {
String line = null;
int pos = -1;
stream.mark();
while ((line = stream.readLine()) != null &&
(pos = line.indexOf("#")) >= 0) {
metadata.addComment(line.substring(pos + 1).trim());
}
stream.reset();
}
/** Reads the next integer. */
private int readInteger(ImageInputStream stream) throws IOException {
boolean foundDigit = false;
while (aLine == null) {
aLine = stream.readLine();
if (aLine == null)
return 0;
int pos = aLine.indexOf("#");
if (pos == 0)
aLine = null;
else if (pos > 0)
aLine = aLine.substring(0, pos - 1);
if (aLine != null)
token = new StringTokenizer(aLine);
}
while (token.hasMoreTokens()) {
String s = token.nextToken();
try {
return new Integer(s).intValue();
} catch (NumberFormatException e) {
continue;
}
}
if (!foundDigit) {
aLine = null;
return readInteger(stream);
}
return 0;
}
private void skipInteger(ImageInputStream stream, int num) throws IOException {
for (int i = 0; i < num; i++)
readInteger(stream);
}
}