diff --git a/build/macosx/make.sh b/build/macosx/make.sh index 0c2149361..92e72110d 100755 --- a/build/macosx/make.sh +++ b/build/macosx/make.sh @@ -80,6 +80,7 @@ export CLASSPATH perl preproc.pl ../build/macosx/work/jikes -d . +D -target 1.1 *.java +#javac -d . -source 1.3 -target 1.1 *.java zip -r0q ../build/macosx/work/lib/core.jar processing # head back to root "processing" dir diff --git a/core/PApplet.java b/core/PApplet.java index 5d496cad4..01fb0d115 100644 --- a/core/PApplet.java +++ b/core/PApplet.java @@ -3014,6 +3014,9 @@ public class PApplet extends Applet // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + protected String[] loadImageFormats; + + /** * Load an image from the data folder or a local directory. * Supports .gif (including transparency), .tga, and .jpg images. @@ -3028,6 +3031,28 @@ public class PApplet extends Applet * As of 0096, returns null if no image of that name is found. */ public PImage loadImage(String filename) { + if (PApplet.javaVersion >= 1.4f) { + if (loadImageFormats == null) { + //loadImageFormats = javax.imageio.ImageIO.getReaderFormatNames(); + try { + Class ioClass = Class.forName("javax.imageio.ImageIO"); + Method getFormatNamesMethod = + ioClass.getMethod("getReaderFormatNames", (Class[]) null); + loadImageFormats = (String[]) + getFormatNamesMethod.invoke((Class[]) null, (Object[]) null); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (loadImageFormats != null) { + for (int i = 0; i < loadImageFormats.length; i++) { + if (filename.endsWith("." + loadImageFormats[i])) { + return loadImageIO(filename); + } + } + } + } + if (filename.toLowerCase().endsWith(".tga")) { return loadImageTGA(filename); } @@ -3035,6 +3060,11 @@ public class PApplet extends Applet byte bytes[] = loadBytes(filename); if (bytes == null) return null; + if (filename.toLowerCase().endsWith(".tif") || + filename.toLowerCase().endsWith(".tiff")) { + return PImage.loadTIFF(bytes); + } + Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes); MediaTracker tracker = new MediaTracker(this); @@ -3065,6 +3095,61 @@ public class PApplet extends Applet } + /** + * + */ + protected PImage loadImageIO(String filename) { + InputStream stream = openStream(filename); + if (stream == null) { + System.err.println("The image " + filename + " could not be found."); + return null; + } + + try { + Class ioClass = Class.forName("javax.imageio.ImageIO"); + Method readMethod = + ioClass.getMethod("read", new Class[] { InputStream.class }); + Object bimage = readMethod.invoke(null, new Object[] { stream }); + + // need to get width and height, then create pixels[] at that size + int px[] = null; + + Class biClass = + Class.forName("java.awt.image.BufferedImage"); + + Method getHeightMethod = + biClass.getMethod("getHeight", (Class[]) null); + Integer hi = (Integer) getHeightMethod.invoke(bimage, (Object[]) null); + //int h = hi.intValue(); + + Method getWidthMethod = + biClass.getMethod("getWidth", (Class[]) null); + Integer wi = (Integer) getWidthMethod.invoke(bimage, (Object[]) null); + //int w = wi.intValue(); + + // need to call getType() on the image to see if RGB or ARGB + + PImage outgoing = new PImage(wi.intValue(), hi.intValue()); + + Method getRgbMethod = + biClass.getMethod("getRGB", new Class[] { + Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE, + outgoing.pixels.getClass(), Integer.TYPE, Integer.TYPE + }); + getRgbMethod.invoke(bimage, new Object[] { + new Integer(0), new Integer(0), + new Integer(outgoing.width), new Integer(outgoing.height), + outgoing.pixels, new Integer(0), new Integer(outgoing.width) + }); + return outgoing; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** * Targa bitmap loader for 24/32bit RGB(A) [toxi 040304] *
@@ -6228,24 +6313,6 @@ public class PApplet extends Applet } - static public boolean saveHeaderTIFF(OutputStream output, - int width, int height) { - return PGraphics.saveHeaderTIFF(output, width, height); - } - - - static public boolean saveTIFF(OutputStream output, int pixels[], - int width, int height) { - return PGraphics.saveTIFF(output, pixels, width, height); - } - - - static public boolean saveTGA(OutputStream output, int pixels[], - int width, int height, int format) { - return PGraphics.saveTGA(output, pixels, width, height, format); - } - - public void hint(int which) { if (recorder != null) recorder.hint(which); g.hint(which); diff --git a/core/PImage.java b/core/PImage.java index 3cc54a6e5..cd4d06c50 100644 --- a/core/PImage.java +++ b/core/PImage.java @@ -26,6 +26,9 @@ package processing.core; import java.awt.image.*; import java.io.*; +import java.lang.reflect.*; + +import javax.imageio.*; /** @@ -118,8 +121,8 @@ public class PImage implements PConstants, Cloneable { public PImage(int width, int height, int format) { init(width, height, format); } - - + + public PImage(int pixels[], int width, int height, int format) { this.pixels = pixels; this.width = width; @@ -844,7 +847,7 @@ public class PImage implements PConstants, Cloneable { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //cb = cg = cr = sum = 0; - cb = sum = 0; + cb = sum = 0; read = x - blurRadius; if (read<0) { bk0=-read; @@ -876,7 +879,7 @@ public class PImage implements PConstants, Cloneable { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //cb = cg = cr = sum = 0; - cb = sum = 0; + cb = sum = 0; if (ym<0) { bk0 = ri = -ym; read = x; @@ -1782,7 +1785,7 @@ public class PImage implements PConstants, Cloneable { // FILE I/O - static byte tiff_header[] = { + static byte TIFF_HEADER[] = { 77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0, @@ -1792,8 +1795,8 @@ public class PImage implements PConstants, Cloneable { }; - static public boolean saveHeaderTIFF(OutputStream output, - int width, int height) { + /* + protected boolean saveHeaderTIFF(OutputStream output) { try { byte tiff[] = new byte[768]; System.arraycopy(tiff_header, 0, tiff, 0, tiff_header.length); @@ -1817,14 +1820,83 @@ public class PImage implements PConstants, Cloneable { } return false; } + */ - static public boolean saveTIFF(OutputStream output, int pixels[], - int width, int height) { - try { - if (!saveHeaderTIFF(output, width, height)) { - return false; + static final String TIFF_ERROR = + "Error: Processing can only read its own TIFF files."; + + static protected PImage loadTIFF(byte tiff[]) { + if ((tiff[42] != tiff[102]) || // width/height in both places + (tiff[43] != tiff[103])) { + System.err.println(TIFF_ERROR); + return null; + } + + int width = + ((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff); + int height = + ((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff); + + int count = + ((tiff[114] & 0xff) << 24) | + ((tiff[115] & 0xff) << 16) | + ((tiff[116] & 0xff) << 8) | + (tiff[117] & 0xff); + if (count != width * height * 3) { + System.err.println(TIFF_ERROR + " (" + width + ", " + height +")"); + return null; + } + + // check the rest of the header + for (int i = 0; i < TIFF_HEADER.length; i++) { + if ((i == 30) || (i == 31) || (i == 42) || (i == 43) || + (i == 102) || (i == 103) || + (i == 114) || (i == 115) || (i == 116) || (i == 117)) continue; + + if (tiff[i] != TIFF_HEADER[i]) { + System.err.println(TIFF_ERROR + " (" + i + ")"); + return null; } + } + + PImage outgoing = new PImage(width, height, RGB); + int index = 768; + count /= 3; + for (int i = 0; i < count; i++) { + outgoing.pixels[i] = + 0xFF000000 | + (tiff[index++] & 0xff) << 16 | + (tiff[index++] & 0xff) << 8 | + (tiff[index++] & 0xff); + } + return outgoing; + } + + + protected boolean saveTIFF(OutputStream output) { + if (format != RGB) { + System.out.println("Warning: only RGB information is saved with " + + ".tif files. Use .tga or .png if you want alpha."); + } + try { + byte tiff[] = new byte[768]; + System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length); + + tiff[30] = (byte) ((width >> 8) & 0xff); + tiff[31] = (byte) ((width) & 0xff); + tiff[42] = tiff[102] = (byte) ((height >> 8) & 0xff); + tiff[43] = tiff[103] = (byte) ((height) & 0xff); + + int count = width*height*3; + tiff[114] = (byte) ((count >> 24) & 0xff); + tiff[115] = (byte) ((count >> 16) & 0xff); + tiff[116] = (byte) ((count >> 8) & 0xff); + tiff[117] = (byte) ((count) & 0xff); + + //if (!saveHeaderTIFF(output)) { //, width, height)) { + //return false; + //} for (int i = 0; i < pixels.length; i++) { output.write((pixels[i] >> 16) & 0xff); output.write((pixels[i] >> 8) & 0xff); @@ -1856,8 +1928,7 @@ public class PImage implements PConstants, Cloneable { * Contributed by toxi 8-10 May 2005, based on this RLE * specification */ - static public boolean saveTGA(OutputStream output, int pixels[], - int width, int height, int format) { + protected boolean saveTGA(OutputStream output) { byte header[] = new byte[18]; if (format == ALPHA) { // save ALPHA images as 8bit grayscale @@ -1993,6 +2064,72 @@ public class PImage implements PConstants, Cloneable { } + /** + * Use ImageIO functions from Java 1.4 and later to handle image save. + * Various formats are supported, typically jpeg, png, bmp, and wbmp. + * To get a list of the supported formats for writing, use:@@ -2000,10 +2137,19 @@ public class PImage implements PConstants, Cloneable { * in order to avoid confusion. To save inside the sketch folder, * use the function savePath() from PApplet, or use saveFrame() instead. *
- * TODO write reflection code here to use java 1.4 imageio
- * methods for writing out images that might be much better.
- * won't want to use them in all cases.. how to determine?
- * boolean ImageIO.write(RenderedImage im, String formatName, File output)
+ * As of revision 0115, when using Java 1.4 and later, you can write
+ * to several formats besides tga and tiff. If Java 1.4 is installed
+ * and the extension used is supported (usually png, jpg, jpeg, bmp,
+ * and tiff), then those methods will be used to write the image.
+ * To get a list of the supported formats for writing, use:
+ * println(javax.imageio.ImageIO.getReaderFormatNames())
+ *
+ * To use the original built-in image writers, use .tga as the extension, + * or don't include an extension, in which case .tif will be added. + *
+ * The ImageIO API claims to support wbmp files, however they probably + * require a black and white image. Basic testing produced a zero-length + * file with no error. */ public void save(String filename) { // ignore boolean success = false; @@ -2018,9 +2164,33 @@ public class PImage implements PConstants, Cloneable { try { OutputStream os = null; + if (PApplet.javaVersion >= 1.4f) { + if (saveImageFormats == null) { + //saveImageFormats = javax.imageio.ImageIO.getWriterFormatNames(); + try { + Class ioClass = Class.forName("javax.imageio.ImageIO"); + Method getFormatNamesMethod = + ioClass.getMethod("getWriterFormatNames", (Class[]) null); + saveImageFormats = (String[]) + getFormatNamesMethod.invoke((Class[]) null, (Object[]) null); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (saveImageFormats != null) { + for (int i = 0; i < saveImageFormats.length; i++) { + System.out.println(saveImageFormats[i]); + if (filename.endsWith("." + saveImageFormats[i])) { + saveImageIO(filename); + return; + } + } + } + } + if (filename.toLowerCase().endsWith(".tga")) { os = new BufferedOutputStream(new FileOutputStream(filename), 32768); - success = saveTGA(os, pixels, width, height, format); + success = saveTGA(os); //, pixels, width, height, format); } else { if (!filename.toLowerCase().endsWith(".tif") && @@ -2029,7 +2199,7 @@ public class PImage implements PConstants, Cloneable { filename += ".tif"; } os = new BufferedOutputStream(new FileOutputStream(filename), 32768); - success = saveTIFF(os, pixels, width, height); + success = saveTIFF(os); //, pixels, width, height); } os.flush(); os.close(); diff --git a/core/todo.txt b/core/todo.txt index 5147b8469..e9a76fd8b 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -6,6 +6,31 @@ X if file is missing for reader() X return null and println an error rather than failing X add arraycopy(from, to, count); X fix fill/stroke issues in bugs db (bug 339) +X saveTIFF, saveHeaderTIFF, saveTGA no longer public/static in PImage +X this was a mistake to expose the api this way + +_ an image marked RGB but with 0s for the alpha won't draw in JAVA2D + +_ illegal jpeg images are what happens whenever the image cannot be read +_ java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot be <= 0 +_ for instance, trying to load a tiff image with the jpg loader + +_ test support for reading and writing images that have alpha and imageio +_ get tiff exporter for p5 to support argb + +_ more image file i/o in java 1.4 +X add dynamic loading of the jpeg, png, and gif(?) encoder classes +_ http://dev.processing.org/bugs/show_bug.cgi?id=165 +_ http://java.sun.com/products/java-media/jai/index.jsp +_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1120174647 +_ P5 cannot read files generated by saveFrame() +_ need to update docs re: tga +_ and add support for reading its own uncompressed TIFs +_ http://dev.processing.org/bugs/show_bug.cgi?id=271 + +_ this produces a dark blue background: +colorMode(RGB, 100); +background(128); _ endRaw() should force depth sorted triangles to flush _ fix dxf export bug @@ -139,16 +164,6 @@ _ maybe background() should do this automatically? _ lookat is now camera(), but not fixed in the docs _ add notes to the faq about the camera changes on the changes page -_ more image file i/o in java 1.4 -_ add dynamic loading of the jpeg, png, and gif(?) encoder classes -_ http://dev.processing.org/bugs/show_bug.cgi?id=165 -_ http://java.sun.com/products/java-media/jai/index.jsp -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1120174647 -_ P5 cannot read files generated by saveFrame() -_ need to update docs re: tga -_ and add support for reading its own uncompressed TIFs -_ http://dev.processing.org/bugs/show_bug.cgi?id=271 - _ on osx, System.err isn't writing in things like createGraphics() _ but doing a printStackTrace(System.out) works _ something weird happening with one of the streams shutting down? diff --git a/todo.txt b/todo.txt index bcbf54b7c..d63a6bd1e 100644 --- a/todo.txt +++ b/todo.txt @@ -4,6 +4,13 @@ o the first time, it's very slow.. presumably an awt problem X renaming a sketch should rebuild the sketch menu X http://dev.processing.org/bugs/show_bug.cgi?id=332 +_ toInt() needs to go away in time for the book.. fix parser bugs +_ make expand() et al work on objects + +_ notes about setting key=0 to catch ESC +_ also size(screen.width, screen.height); +_ maybe make a section in installations with p5 + _ would be nice to have macosx packaged up as a single .app file _ should recommend that people install libraries into their sketchbook