diff --git a/core/src/processing/awt/PImageAWT.java b/core/src/processing/awt/PImageAWT.java index b226fc4c6..a01b65742 100644 --- a/core/src/processing/awt/PImageAWT.java +++ b/core/src/processing/awt/PImageAWT.java @@ -92,6 +92,14 @@ public class PImageAWT extends PImage { } + /** Set the high bits of all pixels to opaque. */ + protected void opaque() { + for (int i = 0; i < pixels.length; i++) { + pixels[i] = 0xFF000000 | pixels[i]; + } + } + + /** * Use the getNative() method instead, which allows library interfaces to be * written in a cross-platform fashion for desktop, Android, and others. @@ -153,7 +161,7 @@ public class PImageAWT extends PImage { // "Filthy Rich Clients" by Chet Haase and Romain Guy // Additional modifications and simplifications have been added, // plus a fix to deal with an infinite loop if images are expanded. - // http://code.google.com/p/processing/issues/detail?id=1463 + // https://github.com/processing/processing/issues/1501 static private BufferedImage shrinkImage(BufferedImage img, int targetWidth, int targetHeight) { int type = (img.getTransparency() == Transparency.OPAQUE) ? diff --git a/core/src/processing/awt/ShimAWT.java b/core/src/processing/awt/ShimAWT.java index 17a9d72aa..3b9582c34 100644 --- a/core/src/processing/awt/ShimAWT.java +++ b/core/src/processing/awt/ShimAWT.java @@ -1,14 +1,8 @@ package processing.awt; -import java.awt.Desktop; -import java.awt.EventQueue; -import java.awt.FileDialog; -import java.awt.Frame; -import java.awt.HeadlessException; -import java.awt.Image; -import java.awt.Toolkit; +import java.awt.*; import java.awt.color.ColorSpace; -import java.awt.image.BufferedImage; +import java.awt.image.*; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; @@ -16,10 +10,6 @@ import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; -import java.awt.DisplayMode; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; import java.awt.geom.AffineTransform; import javax.imageio.IIOImage; @@ -156,6 +146,182 @@ public class ShimAWT implements PConstants { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + static public void fromNativeImage(Image img, PImage out) { + out.format = RGB; + out.pixels = null; + + if (img instanceof BufferedImage) { + BufferedImage bi = (BufferedImage) img; + out.width = bi.getWidth(); + out.height = bi.getHeight(); + + int type = bi.getType(); + if (type == BufferedImage.TYPE_3BYTE_BGR || + type == BufferedImage.TYPE_4BYTE_ABGR) { + out.pixels = new int[out.width * out.height]; + bi.getRGB(0, 0, out.width, out.height, out.pixels, 0, out.width); + if (type == BufferedImage.TYPE_4BYTE_ABGR) { + out.format = ARGB; +// } else { +// opaque(); + } + } else { + DataBuffer db = bi.getRaster().getDataBuffer(); + if (db instanceof DataBufferInt) { + out.pixels = ((DataBufferInt) db).getData(); + if (type == BufferedImage.TYPE_INT_ARGB) { + out.format = ARGB; +// } else if (type == BufferedImage.TYPE_INT_RGB) { +// opaque(); + } + } + } + } + if ((out.pixels != null) && (out.format == RGB)) { + for (int i = 0; i < out.pixels.length; i++) { + out.pixels[i] |= 0xFF000000; + } + } + // Implements fall-through if not DataBufferInt above, or not a + // known type, or not DataBufferInt for the data itself. + if (out.pixels == null) { // go the old school Java 1.0 route + out.width = img.getWidth(null); + out.height = img.getHeight(null); + out.pixels = new int[out.width * out.height]; + PixelGrabber pg = + new PixelGrabber(img, 0, 0, out.width, out.height, out.pixels, 0, out.width); + try { + pg.grabPixels(); + } catch (InterruptedException e) { } + } + out.pixelDensity = 1; + out.pixelWidth = out.width; + out.pixelHeight = out.height; + } + + +// /** Set the high bits of all pixels to opaque. */ +// protected void opaque() { +// for (int i = 0; i < pixels.length; i++) { +// pixels[i] = 0xFF000000 | pixels[i]; +// } +// } + + + static public Object getNativeImage(PImage img) { + img.loadPixels(); + int type = (img.format == RGB) ? + BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; + BufferedImage image = + new BufferedImage(img.pixelWidth, img.pixelHeight, type); + WritableRaster wr = image.getRaster(); + wr.setDataElements(0, 0, img.pixelWidth, img.pixelHeight, img.pixels); + return image; + } + + + static public void resizeImage(PImage img, int w, int h) { // ignore + if (w <= 0 && h <= 0) { + throw new IllegalArgumentException("width or height must be > 0 for resize"); + } + + if (w == 0) { // Use height to determine relative size + float diff = (float) h / (float) img.height; + w = (int) (img.width * diff); + } else if (h == 0) { // Use the width to determine relative size + float diff = (float) w / (float) img.width; + h = (int) (img.height * diff); + } + + BufferedImage bimg = + shrinkImage((BufferedImage) img.getNative(), w*img.pixelDensity, h*img.pixelDensity); + + PImage temp = new PImageAWT(bimg); + img.pixelWidth = temp.width; + img.pixelHeight = temp.height; + + // Get the resized pixel array + img.pixels = temp.pixels; + + img.width = img.pixelWidth / img.pixelDensity; + img.height = img.pixelHeight / img.pixelDensity; + + // Mark the pixels array as altered + img.updatePixels(); + } + + + // Adapted from getFasterScaledInstance() method from page 111 of + // "Filthy Rich Clients" by Chet Haase and Romain Guy + // Additional modifications and simplifications have been added, + // plus a fix to deal with an infinite loop if images are expanded. + // https://github.com/processing/processing/issues/1501 + static private BufferedImage shrinkImage(BufferedImage img, + int targetWidth, int targetHeight) { + int type = (img.getTransparency() == Transparency.OPAQUE) ? + BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; + BufferedImage outgoing = img; + BufferedImage scratchImage = null; + Graphics2D g2 = null; + int prevW = outgoing.getWidth(); + int prevH = outgoing.getHeight(); + boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE; + + // Use multi-step technique: start with original size, then scale down in + // multiple passes with drawImage() until the target size is reached + int w = img.getWidth(); + int h = img.getHeight(); + + do { + if (w > targetWidth) { + w /= 2; + // if this is the last step, do the exact size + if (w < targetWidth) { + w = targetWidth; + } + } else if (targetWidth >= w) { + w = targetWidth; + } + if (h > targetHeight) { + h /= 2; + if (h < targetHeight) { + h = targetHeight; + } + } else if (targetHeight >= h) { + h = targetHeight; + } + if (scratchImage == null || isTranslucent) { + // Use a single scratch buffer for all iterations and then copy + // to the final, correctly-sized image before returning + scratchImage = new BufferedImage(w, h, type); + g2 = scratchImage.createGraphics(); + } + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null); + prevW = w; + prevH = h; + outgoing = scratchImage; + } while (w != targetWidth || h != targetHeight); + + if (g2 != null) { + g2.dispose(); + } + + // If we used a scratch buffer that is larger than our target size, + // create an image of the right size and copy the results into it + if (targetWidth != outgoing.getWidth() || + targetHeight != outgoing.getHeight()) { + scratchImage = new BufferedImage(targetWidth, targetHeight, type); + g2 = scratchImage.createGraphics(); + g2.drawImage(outgoing, 0, 0, null); + g2.dispose(); + outgoing = scratchImage; + } + return outgoing; + } + + static protected String[] loadImageFormats; // list of ImageIO formats @@ -509,7 +675,7 @@ public class ShimAWT implements PConstants { /** - * @param display the display number to check + * display - the display number to check * (1-indexed to match the Preferences dialog box) */ /* diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index 487ebd880..840a65e58 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -24,6 +24,7 @@ package processing.core; +import java.awt.Image; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -257,11 +258,27 @@ public class PImage implements PConstants, Cloneable { this.width = width; this.height = height; this.format = format; - this.pixelDensity = factor; + pixelDensity = factor; pixelWidth = width * pixelDensity; pixelHeight = height * pixelDensity; - this.pixels = new int[pixelWidth * pixelHeight]; + + pixels = new int[pixelWidth * pixelHeight]; + } + + + private void init(int width, int height, int format, int factor, + int[] pixels) { // ignore + this.width = width; + this.height = height; + this.format = format; + + pixelDensity = factor; + // these weren't being set in 4.0a3, why? [fry 210615] + pixelWidth = width * pixelDensity; + pixelHeight = height * pixelDensity; + + this.pixels = pixels; } @@ -287,7 +304,7 @@ public class PImage implements PConstants, Cloneable { public PImage(int width, int height, int[] pixels, boolean requiresCheckAlpha, PApplet parent) { - initFromPixels(width, height, pixels, RGB,1); + init(width, height, RGB,1, pixels); this.parent = parent; if (requiresCheckAlpha) { @@ -298,8 +315,7 @@ public class PImage implements PConstants, Cloneable { public PImage(int width, int height, int[] pixels, boolean requiresCheckAlpha, PApplet parent, int format, int factor) { - - initFromPixels(width, height, pixels, format, factor); + init(width, height, format, factor, pixels); this.parent = parent; if (requiresCheckAlpha) { @@ -307,17 +323,27 @@ public class PImage implements PConstants, Cloneable { } } - private void initFromPixels(int width, int height, int[] pixels, int format, int factor) { - this.width = width; - this.height = height; - this.format = format; - this.pixelDensity = factor; - this.pixels = pixels; + + @Deprecated + public PImage(Image img) { + ShimAWT.fromNativeImage(img, this); + } + + + /** + * Use the getNative() method instead, which allows library interfaces to be + * written in a cross-platform fashion for desktop, Android, and others. + * This is still included for PGraphics objects, which may need the image. + */ + @Deprecated + public Image getImage() { // ignore + return (Image) getNative(); } public Object getNative() { // ignore - return null; + // TODO temporary solution for maximum backwards compatibility + return ShimAWT.getNativeImage(this); } @@ -481,7 +507,8 @@ public class PImage implements PConstants, Cloneable { * @see PImage#get(int, int, int, int) */ public void resize(int w, int h) { // ignore - throw new RuntimeException("resize() not implemented for this PImage type"); + //throw new RuntimeException("resize() not implemented for this PImage type"); + ShimAWT.resizeImage(this, w, h); } @@ -1033,14 +1060,6 @@ public class PImage implements PConstants, Cloneable { } - /** Set the high bits of all pixels to opaque. */ - protected void opaque() { - for (int i = 0; i < pixels.length; i++) { - pixels[i] = 0xFF000000 | pixels[i]; - } - } - - /** * Optimized code for building the blur kernel. * further optimized blur code (approx. 15% for radius=20) @@ -3357,11 +3376,11 @@ int testFunction(int dst, int src) { * @param path must be a full path (not relative or simply a filename) */ protected boolean saveImpl(String path) { - // TODO Imperfect/temporary solution for alpha 2. + // TODO Imperfect/temporary solution for current 4.x releases // https://github.com/processing/processing4/wiki/Exorcising-AWT - if (!PApplet.disableAWT) { - return ShimAWT.saveImage(this, path); - } - return false; + //if (!PApplet.disableAWT) { // TODO necessary? will this trigger NEWT? + return ShimAWT.saveImage(this, path); + //} + //return false; } } diff --git a/core/todo.txt b/core/todo.txt index 82fd4c224..94ae464a9 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -16,27 +16,29 @@ X https://github.com/processing/processing4/issues/202 X formerly https://github.com/processing/processing/issues/6169 X add PVector.setHeading() for parity with p5.js X https://github.com/processing/processing4/issues/193 -X .setAngle() for PVector? +o .setAngle() for PVector? X https://github.com/processing/processing-docs/issues/744 o Math for BLEND incorrect in the reference? o https://github.com/processing/processing-docs/issues/762 o How much of the attrib*() functions should be documented? o https://github.com/processing/processing-docs/issues/172 +get less ambitious with PImage +X cursor(PImage) broken everywhere because PImage.getNative() returns null +X https://github.com/processing/processing4/issues/180 +X PImage.resize() not working +X https://github.com/processing/processing4/issues/200 +X two simple examples added to the issue that can be used for tests +X copy() not working correctly +X https://github.com/processing/processing4/issues/169 + regressions _ (unconfirmed) setting which display to use does not work _ https://github.com/processing/processing4/issues/187 -_ cursor(PImage) broken everywhere because PImage.getNative() returns null -_ https://github.com/processing/processing4/issues/180 -_ PImage.resize() not working -_ https://github.com/processing/processing4/issues/200 -_ two simple examples added to the issue that can be used for tests _ mouseButton not set correctly on mouseReleased() with Java2D _ https://github.com/processing/processing4/issues/181 _ https://github.com/processing/processing4/pull/188 -_ copy() not working correctly -_ https://github.com/processing/processing4/issues/169 _ setting surface size needs to happen outside draw() diff --git a/todo.txt b/todo.txt index a03481c6e..e9c670b48 100755 --- a/todo.txt +++ b/todo.txt @@ -22,6 +22,7 @@ X https://github.com/processing/processing4/issues/197 X https://github.com/processing/processing4/pull/198 X automatically lock closed issues X https://github.com/apps/lock +X https://github.com/dessant/lock-threads-app X Display Window doesn't remember its position X seems that --external not getting passed X https://github.com/processing/processing4/issues/158 @@ -112,6 +113,9 @@ _ Some 3.x Tools not working because JavaFX isn't on the classpath _ https://github.com/processing/processing4/issues/110 _ Friendly Names for new Sketches (includes UI for switching it back) _ https://github.com/processing/processing/pull/6048 +_ add language support to Modes (request from Andres) +_ https://github.com/processing/processing4/pull/14 +_ this was a small change; rebase not really needed since needs rewrite anyway discuss with Sam @@ -132,15 +136,12 @@ _ launch/psk files/import from web editor (more details below) _ ability to switch mode in p5 w/o saving/closing/etc _ trying to save the user from themselves here is just messier than needed _ https://github.com/processing/processing4/issues/189 -_ 'show sketch folder' weird when in temp folder -_ ask to save first (sketch has not been saved yet) -_ or make the temp folder part of the sketchbook -_ same with adding files to an unsaved sketch, do we block that? - - -_ add language support to Modes (request from Andres) -_ https://github.com/processing/processing4/pull/14 -_ this was a small change; rebase not really needed since needs rewrite anyway +_ cleaning up the temp file handling +_ 'show sketch folder' weird when in temp folder +_ ask to save first (sketch has not been saved yet) +_ or make the temp folder part of the sketchbook +_ same with adding files to an unsaved sketch, do we block that? +_ remove code.google.com URLs with Github URLs (numbers are in sync) macos