import java.io.FileInputStream; import java.io.BufferedReader; import java.io.FileReader; import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * Class to handle reading and writing grayscale Sun Raster Format * (.sun, .ras, .sunras) and PBM P1 (.pbm) bitmap files. * The methods in this class are all static, so no instantiation is * necessary. This class sends/receives image data in the form of a * 2D array of ints (int[x][y]). It uses the Input class in the * (input/output)(Grayscale/Bitmap) methods to prompt the user for * file names. If you wish to supply a filename by another method, * use the (readFrom/writeTo)(Grayscale/Bitmap) methods instead. * @author Glenn Matthews */ public class RasterIO { /** * Converts an (unsigned) byte to an unsigned int. * Since Java doesn't have an unsigned * byte type, this requires some foolery. * This solution based on information and code from * http://www.rgagnon.com/javadetails/java-0026.html * @param b The unsigned byte to convert * @return the unsigned int equivalent */ public static int unsignedByteToInt(byte b) { return (int) b & 0xFF; } /** * Converts a set of four consecutive bytes into a single int. * @param data An array of bytes * @param offset The array index to begin with * @return The resulting int */ public static int bytesToInt(byte[] data, int offset) { int i = 0; i += unsignedByteToInt(data[offset]) << 24; i += unsignedByteToInt(data[offset + 1]) << 16; i += unsignedByteToInt(data[offset + 2]) << 8; i += unsignedByteToInt(data[offset + 3]); return i; } /** * Reads image from an external raster file (name supplied by the user). * Calls readFromRasterFile() after receiving the user input. * @return Array representing grayscale pixel data. */ public static int[][] inputGrayscale() { String filename = Input.getString("Load what image file? "); int[][] pixels; if (filename == null) return null; pixels = readFromRasterFile(filename); if (pixels == null) { //must have been an error - try again! return inputGrayscale(); } return pixels; } /** * Read the provided grayscale Sun Raster Format file and return an array * representing its pixels. * @param name The name of the raster file to read. * @return a 2d array with values 0-255 representing pixel values. */ public static int[][] readFromRasterFile(String name) { try { FileInputStream input = new FileInputStream(name); byte header[] = new byte[32]; if (input.read(header) != 32) { System.out.println("Unable to read file header!"); return null; } //check to make sure this is really raster file format if (header[0] != 0x59 || header[1] != (byte)0xa6 || header[2] != 0x6a || header[3] != (byte)0x95) { System.out.println("Magic cookie # is invalid - are you " + "sure that this is a Raster file?"); return null; } int w = bytesToInt(header,4); int h = bytesToInt(header,8); System.out.println("Image w = " + w + " and h = " + h); int depth = bytesToInt(header,12); if (depth != 8) { System.out.println("Expected 8-bit depth, found "+depth); return null; } int dataLength = bytesToInt(header,16); if (dataLength != w*h) { System.out.println("Data length doesn't match expected."); return null; } int fileType = bytesToInt(header,20); if (fileType != 1) { System.out.println("Expected file type 1, found"+ fileType); return null; } int colorType = bytesToInt(header,24); if (colorType != 1) { System.out.println("Expected color type 1, found"+ colorType); return null; } int colorLength = bytesToInt(header,28); System.out.println("Color palette has " + colorLength/3 + " colors"); //Now that we've checked the header, we can read the data //First, the color map. byte[] colorData = new byte[colorLength]; if (input.read(colorData) != colorLength) { System.out.println("Unexpected EOF while reading colors!"); return null; } //Second, the pixel data. byte[] data = new byte[dataLength]; if (input.read(data) != dataLength) { System.out.println("Unexpected EOF!"); return null; } int [][] pixels = new int[w][h]; int i; //We convert the image to grayscale in case it isn't already //or in case the grayscale mapping used isn't what we expect. //If not already grayscale, we get gray by just averaging the //RGB components of each color. int[] colors = new int[colorLength / 3]; for (i=0; i> 8), (byte)(w & 0x00FF), //image width 0x00, 0x00, (byte)(h >> 8), (byte)(h & 0x00FF), //image height 0x00, 0x00, 0x00, 0x08, //8-bit color (byte)(size >> 24), (byte)((size & 0x00FF0000) >> 16), (byte)((size & 0x0000FF00) >> 8), (byte)(size & 0xFF), //# of px 0x00, 0x00, 0x00, 0x01, //standard format type 01 0x00, 0x00, 0x00, 0x01, //using colormap 0x00, 0x00, 0x03, 0x00 //colormap length }; FileOutputStream output = null; try { output = new FileOutputStream(name); output.write(header); //output color scheme (grayscale) for (int i=0; i<3; i++) { //r, g, b for (int j=0; j<256; j++) { //256 values output.write(j&0xFF); } } //output pixels for (int y=0; y