new, improved and shiny version, courtesy of Jos Hirth
This commit is contained in:
parent
e34ce0f20c
commit
0c539252b4
|
@ -1,12 +1,13 @@
|
||||||
package org.lwjgl.util;
|
package org.lwjgl.util;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.LineNumberReader;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
@ -15,7 +16,9 @@ import java.util.StringTokenizer;
|
||||||
* <p>
|
* <p>
|
||||||
* NOTE: This simple XPM reader does not support extensions nor hotspots
|
* NOTE: This simple XPM reader does not support extensions nor hotspots
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
* @author Brian Matzon <brian@matzon.dk>
|
* @author Brian Matzon <brian@matzon.dk>
|
||||||
|
* @author Jos Hirth
|
||||||
* @version $Revision$
|
* @version $Revision$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -24,23 +27,30 @@ public class XPMFile {
|
||||||
/** Array of bytes (RGBA) */
|
/** Array of bytes (RGBA) */
|
||||||
private byte bytes[] = null;
|
private byte bytes[] = null;
|
||||||
|
|
||||||
/** Height of image */
|
private final static int WIDTH = 0;
|
||||||
private int height = 0;
|
|
||||||
|
|
||||||
/** Width of image */
|
private final static int HEIGHT = 1;
|
||||||
private int width = 0;
|
|
||||||
|
private final static int NUMBER_OF_COLORS = 2;
|
||||||
|
|
||||||
|
private final static int CHARACTERS_PER_PIXEL = 3;
|
||||||
|
|
||||||
|
private static int[] format = new int[4];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private constructor, use load(String filename)
|
* Private constructor, use load(String filename)
|
||||||
*/
|
*/
|
||||||
private XPMFile() { }
|
private XPMFile() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the XPM file
|
* Loads the XPM file
|
||||||
*
|
*
|
||||||
* @param file path to file
|
* @param file
|
||||||
|
* path to file
|
||||||
* @return XPMFile loaded, or exception
|
* @return XPMFile loaded, or exception
|
||||||
* @throws IOException If any IO exceptions occurs while reading file
|
* @throws IOException
|
||||||
|
* If any IO exceptions occurs while reading file
|
||||||
*/
|
*/
|
||||||
public static XPMFile load(String file) throws IOException {
|
public static XPMFile load(String file) throws IOException {
|
||||||
return load(new FileInputStream(new File(file)));
|
return load(new FileInputStream(new File(file)));
|
||||||
|
@ -49,9 +59,11 @@ public class XPMFile {
|
||||||
/**
|
/**
|
||||||
* Loads the XPM file
|
* Loads the XPM file
|
||||||
*
|
*
|
||||||
* @param is InputStream to read file from
|
* @param is
|
||||||
|
* InputStream to read file from
|
||||||
* @return XPMFile loaded, or exception
|
* @return XPMFile loaded, or exception
|
||||||
* @throws IOException If any IO exceptions occurs while reading file
|
* @throws IOException
|
||||||
|
* If any IO exceptions occurs while reading file
|
||||||
*/
|
*/
|
||||||
public static XPMFile load(InputStream is) throws IOException {
|
public static XPMFile load(InputStream is) throws IOException {
|
||||||
XPMFile xFile = new XPMFile();
|
XPMFile xFile = new XPMFile();
|
||||||
|
@ -63,14 +75,14 @@ public class XPMFile {
|
||||||
* @return the height of the image.
|
* @return the height of the image.
|
||||||
*/
|
*/
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
return height;
|
return format[HEIGHT];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the width of the image.
|
* @return the width of the image.
|
||||||
*/
|
*/
|
||||||
public int getWidth() {
|
public int getWidth() {
|
||||||
return width;
|
return format[WIDTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,52 +95,68 @@ public class XPMFile {
|
||||||
/**
|
/**
|
||||||
* Read the image from the specified file.
|
* Read the image from the specified file.
|
||||||
*
|
*
|
||||||
* @throws IOException If any IO exceptions occurs while reading file
|
* @throws IOException
|
||||||
|
* If any IO exceptions occurs while reading file
|
||||||
*/
|
*/
|
||||||
private void readImage(InputStream is) throws IOException {
|
private void readImage(InputStream is) throws IOException {
|
||||||
try {
|
try {
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
LineNumberReader reader = new LineNumberReader(
|
||||||
|
new InputStreamReader(is));
|
||||||
HashMap colors = new HashMap();
|
HashMap colors = new HashMap();
|
||||||
|
|
||||||
String comment = br.readLine();
|
format = parseFormat(nextLineOfInterest(reader));
|
||||||
String typedef = br.readLine();
|
|
||||||
int[] format = parseFormat(br.readLine());
|
|
||||||
|
|
||||||
// setup color mapping
|
// setup color mapping
|
||||||
for (int i = 0; i < format[2]; i++) {
|
for (int i = 0; i < format[NUMBER_OF_COLORS]; i++) {
|
||||||
Object[] colorDefinition = parseColor(br.readLine());
|
Object[] colorDefinition = parseColor(nextLineOfInterest(reader));
|
||||||
colors.put(colorDefinition[0], colorDefinition[1]);
|
colors.put(colorDefinition[0], colorDefinition[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read actual image (convert to RGBA)
|
// read actual image (convert to RGBA)
|
||||||
bytes = new byte[format[0] * format[1] * 4];
|
bytes = new byte[format[WIDTH] * format[HEIGHT] * 4];
|
||||||
for (int i = 0; i < format[1]; i++) {
|
for (int i = 0; i < format[HEIGHT]; i++) {
|
||||||
parseImageLine(br.readLine(), format, colors, i);
|
parseImageLine(nextLineOfInterest(reader), format, colors, i);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
throw new IllegalArgumentException("Unable to parse XPM File");
|
throw new IllegalArgumentException("Unable to parse XPM File");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the next interesting line of text.
|
||||||
|
*
|
||||||
|
* @param reader
|
||||||
|
* The LineNumberReader to read from
|
||||||
|
* @return The next interesting String (with stripped quotes)
|
||||||
|
* @throws IOException
|
||||||
|
* If any IO exceptions occurs while reading file
|
||||||
|
*/
|
||||||
|
private String nextLineOfInterest(LineNumberReader reader)
|
||||||
|
throws IOException {
|
||||||
|
String ret;
|
||||||
|
do {
|
||||||
|
ret = reader.readLine();
|
||||||
|
} while (!ret.startsWith("\""));
|
||||||
|
// lacks sanity check
|
||||||
|
return ret.substring(1, ret.lastIndexOf('\"'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the format of the xpm file given a format string
|
* Parses the format of the xpm file given a format string
|
||||||
*
|
*
|
||||||
* @param format String to parse
|
* @param format
|
||||||
|
* String to parse
|
||||||
* @return Array specifying width, height, colors, characters per pixel
|
* @return Array specifying width, height, colors, characters per pixel
|
||||||
*/
|
*/
|
||||||
private int[] parseFormat(String format) {
|
private int[] parseFormat(String format) {
|
||||||
|
|
||||||
// format should look like this:
|
// format should look like this:
|
||||||
// "16 16 122 2",
|
// 16 16 122 2
|
||||||
|
|
||||||
// nuke first and last " and last ,
|
|
||||||
format = format.substring(1, format.length() - 2);
|
|
||||||
|
|
||||||
// tokenize it
|
// tokenize it
|
||||||
StringTokenizer st = new StringTokenizer(format);
|
StringTokenizer st = new StringTokenizer(format);
|
||||||
|
|
||||||
return new int[] {
|
return new int[] { Integer.parseInt(st.nextToken()), /* width */
|
||||||
Integer.parseInt(st.nextToken()), /* width */
|
|
||||||
Integer.parseInt(st.nextToken()), /* height */
|
Integer.parseInt(st.nextToken()), /* height */
|
||||||
Integer.parseInt(st.nextToken()), /* colors */
|
Integer.parseInt(st.nextToken()), /* colors */
|
||||||
Integer.parseInt(st.nextToken()) /* chars per pixel */
|
Integer.parseInt(st.nextToken()) /* chars per pixel */
|
||||||
|
@ -138,19 +166,23 @@ public class XPMFile {
|
||||||
/**
|
/**
|
||||||
* Given a line defining a color/pixel, parses this into an array containing
|
* Given a line defining a color/pixel, parses this into an array containing
|
||||||
* a key and a color
|
* a key and a color
|
||||||
* @param line Line to parse
|
*
|
||||||
|
* @param line
|
||||||
|
* Line to parse
|
||||||
* @return Array containing a key (String) and a color (Integer)
|
* @return Array containing a key (String) and a color (Integer)
|
||||||
*/
|
*/
|
||||||
private Object[] parseColor(String line) {
|
private Object[] parseColor(String line) {
|
||||||
// line should look like this
|
// line should look like this:
|
||||||
// "# c #0A0A0A",
|
// # c #0A0A0A
|
||||||
|
|
||||||
// nuke first and last "
|
// NOTE: will break if the color is something like "black" or "gray50"
|
||||||
line = line.substring(1, line.length() - 2);
|
// etc (instead of #rrggbb).
|
||||||
|
|
||||||
String key = line.substring(0, 2);
|
String key = line.substring(0, format[CHARACTERS_PER_PIXEL]);
|
||||||
String type = line.substring(3, 4);
|
// since we always assume color as type we dont need to read it
|
||||||
String color = line.substring(6);
|
// String type = line.substring(format[CHARACTERS_PER_PIXEL] + 1,
|
||||||
|
// format[CHARACTERS_PER_PIXEL] + 2);
|
||||||
|
String color = line.substring(format[CHARACTERS_PER_PIXEL] + 4);
|
||||||
|
|
||||||
// we always assume type is color, and supplied as #<r><g><b>
|
// we always assume type is color, and supplied as #<r><g><b>
|
||||||
return new Object[] { key, new Integer(Integer.parseInt(color, 16)) };
|
return new Object[] { key, new Integer(Integer.parseInt(color, 16)) };
|
||||||
|
@ -158,25 +190,34 @@ public class XPMFile {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an Image line into its byte values
|
* Parses an Image line into its byte values
|
||||||
* @param line Line of chars to parse
|
*
|
||||||
* @param format Format to expext it in
|
* @param line
|
||||||
* @param colors Colors to lookup
|
* Line of chars to parse
|
||||||
* @param index current index into lines, we've reached
|
* @param format
|
||||||
|
* Format to expext it in
|
||||||
|
* @param colors
|
||||||
|
* Colors to lookup
|
||||||
|
* @param index
|
||||||
|
* current index into lines, we've reached
|
||||||
*/
|
*/
|
||||||
private void parseImageLine(String line, int[] format, HashMap colors, int index) {
|
private void parseImageLine(String line, int[] format, HashMap colors,
|
||||||
|
int index) {
|
||||||
// offset for next line
|
// offset for next line
|
||||||
int offset = index * 4 * format[0];
|
int offset = index * 4 * format[WIDTH];
|
||||||
|
|
||||||
// nuke first "
|
// read <format[CHARACTERS_PER_PIXEL]> characters <format[WIDTH]> times,
|
||||||
line = line.substring(1, line.length());
|
// each iteration equals one pixel
|
||||||
|
for (int i = 0; i < format[WIDTH]; i++) {
|
||||||
// read format[3] characters format[0] times, each iteration is one color
|
String key = line
|
||||||
for (int i = 0; i < format[0]; i++) {
|
.substring(
|
||||||
String key = line.substring(i * 2, (i * 2 + 2));
|
i * format[CHARACTERS_PER_PIXEL],
|
||||||
|
(i * format[CHARACTERS_PER_PIXEL] + format[CHARACTERS_PER_PIXEL]));
|
||||||
Integer color = (Integer) colors.get(key);
|
Integer color = (Integer) colors.get(key);
|
||||||
bytes[offset + (i * 4)] = (byte) ((color.intValue() & 0x00ff0000) >> 16);
|
bytes[offset + (i * 4)] = (byte) ((color.intValue() & 0x00ff0000) >> 16);
|
||||||
bytes[offset + ((i * 4) + 1)] = (byte) ((color.intValue() & 0x0000ff00) >> 8);
|
bytes[offset + ((i * 4) + 1)] = (byte) ((color.intValue() & 0x0000ff00) >> 8);
|
||||||
bytes[offset + ((i * 4) + 2)] = (byte) ((color.intValue() & 0x000000ff) >> 0); // looks better :)
|
bytes[offset + ((i * 4) + 2)] = (byte) ((color.intValue() & 0x000000ff) >> 0); // looks
|
||||||
|
// better
|
||||||
|
// :)
|
||||||
bytes[offset + ((i * 4) + 3)] = (byte) 0xff; // always 0xff alpha
|
bytes[offset + ((i * 4) + 3)] = (byte) 0xff; // always 0xff alpha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +233,8 @@ public class XPMFile {
|
||||||
try {
|
try {
|
||||||
String out = args[0].substring(0, args[0].indexOf(".")) + ".raw";
|
String out = args[0].substring(0, args[0].indexOf(".")) + ".raw";
|
||||||
XPMFile file = XPMFile.load(args[0]);
|
XPMFile file = XPMFile.load(args[0]);
|
||||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(out)));
|
BufferedOutputStream bos = new BufferedOutputStream(
|
||||||
|
new FileOutputStream(new File(out)));
|
||||||
bos.write(file.getBytes());
|
bos.write(file.getBytes());
|
||||||
bos.close();
|
bos.close();
|
||||||
|
|
||||||
|
@ -201,7 +243,6 @@ public class XPMFile {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private static void showResult(byte[] bytes) {
|
private static void showResult(byte[] bytes) {
|
||||||
final BufferedImage i = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
final BufferedImage i = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
Loading…
Reference in New Issue