package ij.plugin;
import ij.*;
import ij.io.*;
import ij.process.*;
import java.io.*;
public class PGM_Reader extends ImagePlus implements PlugIn {
private int width, height;
private boolean rawBits;
private boolean sixteenBits;
private boolean isColor;
private boolean isBlackWhite;
private int maxValue;
public void run(String arg) {
OpenDialog od = new OpenDialog("PBM/PGM/PPM Reader...", arg);
String directory = od.getDirectory();
String name = od.getFileName();
if (name == null)
return;
String path = directory + name;
IJ.showStatus("Opening: " + path);
ImageStack stack;
try {
stack = openFile(path);
}
catch (IOException e) {
String msg = e.getMessage();
IJ.showMessage("PBM/PGM/PPM Reader", msg.equals("") ? "" + e : msg);
return;
}
setStack(name, stack);
FileInfo fi = new FileInfo();
fi.fileFormat = FileInfo.PGM;
fi.directory = directory;
fi.fileName = name;
setFileInfo(fi);
if (arg.equals("")) show();
}
public ImageStack openFile(String path) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(path));
try {
StreamTokenizer tok = new StreamTokenizer(is); tok.resetSyntax();
tok.wordChars(33, 255);
tok.whitespaceChars(0, ' ');
tok.parseNumbers();
tok.eolIsSignificant(true);
tok.commentChar('#');
openHeader(tok);
if (!isColor && sixteenBits) { if (rawBits) {
ImageProcessor ip = open16bitRawImage(is, width, height);
ImageStack stack = new ImageStack(width, height);
stack.addSlice("", ip);
return stack;
} else {
ImageProcessor ip = open16bitAsciiImage(tok, width, height);
ImageStack stack = new ImageStack(width, height);
stack.addSlice("", ip);
return stack;
}
}
if (!isColor) { byte[] pixels = new byte[width * height];
ImageProcessor ip = new ByteProcessor(width, height, pixels, null);
if (rawBits)
openRawImage(is, width * height, pixels);
else
openAsciiImage(tok, width * height, pixels);
for (int i = pixels.length - 1; i >= 0; i--) {
if (isBlackWhite) {
if (rawBits) {
if (i < (pixels.length / 8)) {
for (int bit = 7; bit >= 0; bit--) {
pixels[8 * i + 7 - bit] = (byte) ((pixels[i] & ((int) Math.pow(2, bit))) == 0 ? 255 : 0);
}
}
} else
pixels[i] = (byte) (pixels[i] == 0 ? 255 : 0);
} else
pixels[i] = (byte) (0xff & (255 * (int) (0xff & pixels[i]) / maxValue));
}
ImageStack stack = new ImageStack(width, height);
stack.addSlice("", ip);
return stack;
}
if (!sixteenBits) { int[] pixels = new int[width * height];
byte[] bytePixels = new byte[3 * width * height];
ImageProcessor ip = new ColorProcessor(width, height, pixels);
if (rawBits)
openRawImage(is, 3 * width * height, bytePixels);
else
openAsciiImage(tok, 3 * width * height, bytePixels);
for (int i = 0; i < width * height; i++) {
int r = (int) (0xff & bytePixels[i * 3]);
int g = (int) (0xff & bytePixels[i * 3 + 1]);
int b = (int) (0xff & bytePixels[i * 3 + 2]);
r = (r * 255 / maxValue) << 16;
g = (g * 255 / maxValue) << 8;
b = (b * 255 / maxValue);
pixels[i] = 0xFF000000 | r | g | b;
}
ImageStack stack = new ImageStack(width, height);
stack.addSlice("", ip);
return stack;
}
short[] red = new short[width*height];
short[] green = new short[width*height];
short[] blue = new short[width*height];
if (rawBits) {
byte[] bytePixels = new byte[6*width*height];
openRawImage(is, 6*width*height, bytePixels);
for (int i=0; i<width*height; i++) {
int r1 = 0xff & bytePixels[i*6];
int r2 = 0xff & bytePixels[i*6+1];
int g1 = 0xff & bytePixels[i*6+2];
int g2 = 0xff & bytePixels[i*6+3];
int b1 = 0xff & bytePixels[i*6+ 4];
int b2 = 0xff & bytePixels[i*6+5];
red[i] = (short) (0xffff & (r1*256+r2));
green[i] = (short) (0xffff & (g1*256+g2));
blue[i] = (short) (0xffff & (b1*256+b2));
}
} else {
ImageProcessor ip = open16bitAsciiImage(tok, 3*width, height);
short[] pixels = (short[])ip.getPixels();
for (int i=0; i<width*height; i++) {
red[i] = (short)(pixels[i*3]&0xffffff);
green[i] = (short)(pixels[i*3+1]&0xffffff);
blue[i] = (short)(pixels[i*3+2]&0xffffff);
}
}
ImageStack stack = new ImageStack(width, height);
stack.addSlice("red", new ShortProcessor(width, height, red, null));
stack.addSlice("green", new ShortProcessor(width, height, green, null));
stack.addSlice("blue", new ShortProcessor(width, height, blue, null));
return stack;
} finally {
if (is!=null) is.close();
}
}
public void openHeader(StreamTokenizer tok) throws IOException {
String magicNumber = getWord(tok);
if (magicNumber.equals("P1")) {
rawBits = false;
isColor = false;
isBlackWhite = true;
} else if (magicNumber.equals("P4")) {
rawBits = true;
isColor = false;
isBlackWhite = true;
} else if (magicNumber.equals("P2")) {
rawBits = false;
isColor = false;
isBlackWhite = false;
} else if (magicNumber.equals("P5")) {
rawBits = true;
isColor = false;
isBlackWhite = false;
} else if (magicNumber.equals("P3")) {
rawBits = false;
isColor = true;
isBlackWhite = false;
} else if (magicNumber.equals("P6")) {
rawBits = true;
isColor = true;
isBlackWhite = false;
} else
throw new IOException("PxM files must start with \"P1\" or \"P2\" or \"P3\" or \"P4\" or \"P5\" or \"P6\"");
width = getInt(tok);
height = getInt(tok);
if (width == -1 || height == -1)
throw new IOException("Error opening PxM header..");
if (! isBlackWhite) {
maxValue = getInt(tok);
if (maxValue == -1)
throw new IOException("Error opening PxM header..");
sixteenBits = maxValue > 255;
} else
maxValue = 255;
if (sixteenBits && maxValue > 65535)
throw new IOException("The maximum gray value is larger than 65535.");
}
public void openAsciiImage(StreamTokenizer tok, int size, byte[] pixels) throws IOException {
int i = 0;
int inc = size/20;
if (inc==0) inc = 1;
while (tok.nextToken() != tok.TT_EOF) {
if (tok.ttype == tok.TT_NUMBER) {
pixels[i++] = (byte) (((int) tok.nval) & 255);
if (i%inc==0)
IJ.showProgress(0.5 + ((double) i / size) / 2.0);
}
}
IJ.showProgress(1.0);
}
public void openRawImage(InputStream is, int size, byte[] pixels) throws IOException {
int count = 0;
while (count < size && count >= 0)
count = is.read(pixels, count, size - count);
}
public ImageProcessor open16bitRawImage(InputStream is, int width, int height) throws IOException {
int size = width * height * 2;
byte[] bytes = new byte[size];
int count = 0;
while (count < size && count >= 0)
count = is.read(bytes, count, size - count);
short[] pixels = new short[size / 2];
for (int i = 0, j = 0; i < size / 2; i++, j += 2)
pixels[i] = (short) (((bytes[j] & 0xff) << 8) | (bytes[j + 1] & 0xff)); return new ShortProcessor(width, height, pixels, null);
}
public ImageProcessor open16bitAsciiImage(StreamTokenizer tok, int width, int height) throws IOException {
int i = 0;
int size = width * height;
int inc = size/20; if (inc==0) inc = 1;
short[] pixels = new short[size];
while (tok.nextToken() != tok.TT_EOF) {
if (tok.ttype == tok.TT_NUMBER) {
pixels[i++] = (short) (((int) tok.nval) & 65535);
if (i%inc==0)
IJ.showProgress(0.5 + ((double) i / size) / 2.0);
}
}
IJ.showProgress(1.0);
return new ShortProcessor(width, height, pixels, null);
}
String getWord(StreamTokenizer tok) throws IOException {
while (tok.nextToken() != tok.TT_EOF) {
if (tok.ttype == tok.TT_WORD)
return tok.sval;
}
return null;
}
int getInt(StreamTokenizer tok) throws IOException {
while (tok.nextToken() != tok.TT_EOF) {
if (tok.ttype == tok.TT_NUMBER)
return (int) tok.nval;
}
return -1;
}
}