diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index ffe0e53a7..301c28e5b 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -652,7 +652,7 @@ public class PGraphicsJava2D extends PGraphics { who.modified = false; } - g2.drawImage(((ImageCache) who.cache).image, + g2.drawImage(((ImageCache) who.cache).image, (int) x1, (int) y1, (int) x2, (int) y2, u1, v1, u2, v2, null); } @@ -662,18 +662,122 @@ public class PGraphicsJava2D extends PGraphics { PImage source; boolean tinted; int tintedColor; - int tintedPixels[]; + int tintedPixels[]; // one row of tinted pixels BufferedImage image; public ImageCache(PImage source) { this.source = source; // even if RGB, set the image type to ARGB, because the // image may have an alpha value for its tint(). - int type = BufferedImage.TYPE_INT_ARGB; +// int type = BufferedImage.TYPE_INT_ARGB; //System.out.println("making new buffered image"); - image = new BufferedImage(source.width, source.height, type); +// image = new BufferedImage(source.width, source.height, type); } + /** + * Update the pixels of the cache image. Already determined that the tint + * has changed, or the pixels have changed, so should just go through + * with the update without further checks. + */ + public void update(boolean tint, int tintColor) { + int bufferType = BufferedImage.TYPE_INT_ARGB; + boolean opaque = (tintColor & 0xFF000000) == 0xFF000000; + if (source.format == RGB) { + if (!tint || (tint && opaque)) { + bufferType = BufferedImage.TYPE_INT_RGB; + } + } + boolean wrongType = (image != null) && (image.getType() != bufferType); + if ((image == null) || wrongType) { + image = new BufferedImage(source.width, source.height, bufferType); + } + + WritableRaster wr = image.getRaster(); + if (tint) { + if (tintedPixels == null || tintedPixels.length != source.width) { + tintedPixels = new int[source.width]; + } + int a2 = (tintColor >> 24) & 0xff; + int r2 = (tintColor >> 16) & 0xff; + int g2 = (tintColor >> 8) & 0xff; + int b2 = (tintColor) & 0xff; + + if (bufferType == BufferedImage.TYPE_INT_RGB) { + //int alpha = tintColor & 0xFF000000; + int index = 0; + for (int y = 0; y < source.height; y++) { + for (int x = 0; x < source.width; x++) { + int argb1 = source.pixels[index++]; + int r1 = (argb1 >> 16) & 0xff; + int g1 = (argb1 >> 8) & 0xff; + int b1 = (argb1) & 0xff; + + tintedPixels[x] = //0xFF000000 | + (((r2 * r1) & 0xff00) << 8) | + ((g2 * g1) & 0xff00) | + (((b2 * b1) & 0xff00) >> 8); + } + wr.setDataElements(0, y, source.width, 1, tintedPixels); + } + // could this be any slower? +// float[] scales = { tintR, tintG, tintB }; +// float[] offsets = new float[3]; +// RescaleOp op = new RescaleOp(scales, offsets, null); +// op.filter(image, image); + + } else if (bufferType == BufferedImage.TYPE_INT_ARGB) { + int index = 0; + for (int y = 0; y < source.height; y++) { + if (source.format == RGB) { + int alpha = tintColor & 0xFF000000; + for (int x = 0; x < source.width; x++) { + int argb1 = source.pixels[index++]; + int r1 = (argb1 >> 16) & 0xff; + int g1 = (argb1 >> 8) & 0xff; + int b1 = (argb1) & 0xff; + tintedPixels[x] = alpha | + (((r2 * r1) & 0xff00) << 8) | + ((g2 * g1) & 0xff00) | + (((b2 * b1) & 0xff00) >> 8); + } + } else if (source.format == ARGB) { + for (int x = 0; x < source.width; x++) { + int argb1 = source.pixels[index++]; + int a1 = (argb1 >> 24) & 0xff; + int r1 = (argb1 >> 16) & 0xff; + int g1 = (argb1 >> 8) & 0xff; + int b1 = (argb1) & 0xff; + tintedPixels[x] = + (((a2 * a1) & 0xff00) << 16) | + (((r2 * r1) & 0xff00) << 8) | + ((g2 * g1) & 0xff00) | + (((b2 * b1) & 0xff00) >> 8); + } + } else if (source.format == ALPHA) { + int lower = tintColor & 0xFFFFFF; + for (int x = 0; x < source.width; x++) { + int a1 = source.pixels[index++]; + tintedPixels[x] = + (((a2 * a1) & 0xff00) << 16) | lower; + } + } + wr.setDataElements(0, y, source.width, 1, tintedPixels); + } + // Not sure why ARGB images take the scales in this order... +// float[] scales = { tintR, tintG, tintB, tintA }; +// float[] offsets = new float[4]; +// RescaleOp op = new RescaleOp(scales, offsets, null); +// op.filter(image, image); + } + } else { + wr.setDataElements(0, 0, source.width, source.height, source.pixels); + } + this.tinted = tint; + this.tintedColor = tintColor; + } + } + + /* // for rev 0124, passing the tintColor in here. the problem is that // the 'parent' PGraphics object of this inner class may not be // the same one that's used when drawing. for instance, if this @@ -785,7 +889,7 @@ public class PGraphicsJava2D extends PGraphics { raster.setDataElements(0, 0, source.width, source.height, tintedPixels); } } - } + */ ////////////////////////////////////////////////////////////// diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index a4a67fb28..f9fe8d0c4 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -24,9 +24,10 @@ package processing.core; +import java.awt.Image; import java.awt.image.*; import java.io.*; -import java.lang.reflect.*; +import javax.imageio.ImageIO; /** @@ -60,8 +61,8 @@ public class PImage implements PConstants, Cloneable { public int imageMode = CORNER; public boolean smooth = false; - /** native storage for java 1.3 image object */ - //public Object image; + /** Native Java image object */ + //public Image image; /** for subclasses that need to store info about the image */ public Object cache; @@ -230,6 +231,7 @@ public class PImage implements PConstants, Cloneable { * this should copy all data into the pixels[] array */ public void loadPixels() { // ignore + } @@ -2445,10 +2447,11 @@ public class PImage implements PConstants, Cloneable { */ protected void saveImageIO(String path) throws IOException { try { - //BufferedImage bimage = - // new BufferedImage(width, height, (format == ARGB) ? - // BufferedImage.TYPE_INT_ARGB : - // BufferedImage.TYPE_INT_RGB); + BufferedImage bimage = + new BufferedImage(width, height, (format == ARGB) ? + BufferedImage.TYPE_INT_ARGB : + BufferedImage.TYPE_INT_RGB); + /* Class bufferedImageClass = Class.forName("java.awt.image.BufferedImage"); Constructor bufferedImageConstructor = @@ -2466,8 +2469,10 @@ public class PImage implements PConstants, Cloneable { new Integer(height), new Integer((format == ARGB) ? typeIntArgb : typeIntRgb) }); + */ - //bimage.setRGB(0, 0, width, height, pixels, 0, width); + bimage.setRGB(0, 0, width, height, pixels, 0, width); + /* Method setRgbMethod = bufferedImageClass.getMethod("setRGB", new Class[] { Integer.TYPE, Integer.TYPE, @@ -2480,11 +2485,13 @@ public class PImage implements PConstants, Cloneable { new Integer(width), new Integer(height), pixels, new Integer(0), new Integer(width) }); + */ File file = new File(path); String extension = path.substring(path.lastIndexOf('.') + 1); - //ImageIO.write(bimage, extension, file); + ImageIO.write(bimage, extension, file); + /* Class renderedImageClass = Class.forName("java.awt.image.RenderedImage"); Class ioClass = Class.forName("javax.imageio.ImageIO"); @@ -2493,6 +2500,7 @@ public class PImage implements PConstants, Cloneable { renderedImageClass, String.class, File.class }); writeMethod.invoke(null, new Object[] { bimage, extension, file }); + */ } catch (Exception e) { e.printStackTrace(); @@ -2509,6 +2517,9 @@ public class PImage implements PConstants, Cloneable { * As of revision 0100, this function requires an absolute path, * in order to avoid confusion. To save inside the sketch folder, * use the function savePath() from PApplet, or use saveFrame() instead. + * As of revision 0116, savePath() is not needed if this object has been + * created (as recommended) via createImage() or createGraphics() or + * one of its neighbors. *

* 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 @@ -2517,16 +2528,13 @@ public class PImage implements PConstants, Cloneable { * 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. + * To use the original built-in image writers, use .tga or .tif as the + * extension, or don't include an extension. When no extension is used, + * the extension .tif will be added to the file name. *

* 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. - *

- * As of revision 0116, savePath() is not needed if this object has been - * created (as recommended) via createImage() or createGraphics() or - * one of its neighbors. */ public void save(String path) { // ignore boolean success = false; @@ -2548,16 +2556,16 @@ public class PImage implements PConstants, Cloneable { 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(); - } + 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++) { diff --git a/core/todo.txt b/core/todo.txt index 7fd0df68e..3374e2f0e 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,5 +1,11 @@ 0132 core - +X an image marked RGB but with 0s for the alpha won't draw in JAVA2D +X images with 0x00 in their high bits being drawn transparent +X also if transparency set but RGB is setting, still honors transparency +X http://dev.processing.org/bugs/show_bug.cgi?id=351 +X tint() and noTint() switching problem in P2D +X this should be a quick fix +X http://dev.processing.org/bugs/show_bug.cgi?id=222 _ fix svg caps/joins for opengl with svg library _ http://dev.processing.org/bugs/show_bug.cgi?id=628 @@ -26,6 +32,7 @@ _ and that java2d should complain if people try it _ add hint() and unhint() _ also add unhint() to the keywords file _ and maybe remove hint() from keywords_base? +_ method to go from function name to the included examples where used? createGraphics() mess _ text characters showing up as opaque rectangles in tga files @@ -61,13 +68,6 @@ _ make a note that updatePixels() only sets a flag in PImage _ (but not PGraphics, which does it immediately) tint/textures -_ an image marked RGB but with 0s for the alpha won't draw in JAVA2D -_ images with 0x00 in their high bits being drawn transparent -_ also if transparency set but RGB is setting, still honors transparency -_ http://dev.processing.org/bugs/show_bug.cgi?id=351 -_ tint() and noTint() switching problem in P2D -_ this should be a quick fix -_ http://dev.processing.org/bugs/show_bug.cgi?id=222 _ related to the fill bugs: when fill is identical, no fill applied _ actually tint() should take over for fill as per-vertex color _ when textured images are being used