picrate 2.0.0.pre-java → 2.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -1
  3. data/.mvn/wrapper/MavenWrapperDownloader.java +1 -1
  4. data/.mvn/wrapper/maven-wrapper.properties +2 -2
  5. data/CHANGELOG.md +10 -0
  6. data/README.md +11 -9
  7. data/Rakefile +9 -8
  8. data/docs/_config.yml +1 -1
  9. data/docs/_editors/geany.md +1 -0
  10. data/docs/_gems/gems/gems.md +1 -1
  11. data/docs/_methods/alternative_methods.md +2 -1
  12. data/docs/_posts/2018-05-06-getting_started.md +4 -4
  13. data/docs/_posts/2018-05-06-install_jruby.md +5 -11
  14. data/docs/_posts/2018-05-11-arch-linux-arm.md +1 -11
  15. data/docs/_posts/2018-11-18-building-gem.md +4 -2
  16. data/docs/_posts/2018-11-27-getting_started_geany.md +1 -1
  17. data/docs/_posts/2019-11-11-getting_started_buster.md +4 -7
  18. data/docs/_posts/{2018-06-26-auto_install_picrate.md → 2020-03-09-auto_install_picrate.md} +9 -6
  19. data/docs/_posts/2020-05-11-getting_started_manjaro.md +106 -0
  20. data/docs/about.md +1 -1
  21. data/lib/picrate.rb +2 -1
  22. data/lib/picrate/app.rb +1 -0
  23. data/lib/picrate/helper_methods.rb +1 -1
  24. data/lib/picrate/native_folder.rb +6 -7
  25. data/lib/picrate/runner.rb +4 -4
  26. data/lib/picrate/version.rb +1 -1
  27. data/library/jcomplex/jcomplex.rb +1 -0
  28. data/mvnw +2 -2
  29. data/mvnw.cmd +2 -2
  30. data/picrate.gemspec +3 -5
  31. data/pom.rb +18 -15
  32. data/pom.xml +20 -8
  33. data/src/main/java/monkstone/complex/JComplex.java +252 -0
  34. data/src/main/java/processing/awt/PGraphicsJava2D.java +22 -23
  35. data/src/main/java/processing/awt/PImageAWT.java +377 -0
  36. data/src/main/java/processing/awt/ShimAWT.java +545 -0
  37. data/src/main/java/processing/core/PApplet.java +2030 -2556
  38. data/src/main/java/processing/core/PGraphics.java +138 -124
  39. data/src/main/java/processing/core/PImage.java +1517 -1702
  40. data/src/main/java/processing/core/PSurface.java +105 -139
  41. data/src/main/java/processing/core/PSurfaceNone.java +29 -0
  42. data/src/main/java/processing/opengl/PGL.java +649 -3699
  43. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +223 -184
  44. data/src/main/java/processing/opengl/PJOGL.java +374 -1526
  45. data/src/main/java/processing/opengl/PShapeOpenGL.java +5 -6
  46. data/src/main/java/processing/opengl/PSurfaceJOGL.java +220 -86
  47. data/vendors/Rakefile +33 -21
  48. data/vendors/{picrate_sketches.geany → geany.rb} +32 -7
  49. metadata +17 -48
  50. data/src/main/java/processing/opengl/shaders/LightVert-brcm.glsl +0 -154
  51. data/src/main/java/processing/opengl/shaders/LightVert-vc4.glsl +0 -154
  52. data/src/main/java/processing/opengl/shaders/TexLightVert-brcm.glsl +0 -160
  53. data/src/main/java/processing/opengl/shaders/TexLightVert-vc4.glsl +0 -160
@@ -29,7 +29,6 @@ import java.awt.font.TextAttribute;
29
29
  import java.awt.geom.*;
30
30
  import java.awt.image.*;
31
31
  import java.util.Arrays;
32
- import java.util.HashMap;
33
32
  import java.util.Map;
34
33
 
35
34
  import processing.core.*;
@@ -295,10 +294,10 @@ public class PGraphicsJava2D extends PGraphics {
295
294
  * is going to return the {@link Graphics2D} object.
296
295
  * @return
297
296
  */
298
- @Override
299
- public Image getImage() {
300
- return image;
301
- }
297
+ // @Override
298
+ // public Image getImage() {
299
+ // return image;
300
+ // }
302
301
 
303
302
 
304
303
  /** Returns the java.awt.Graphics2D object used by this renderer.
@@ -346,30 +345,30 @@ public class PGraphicsJava2D extends PGraphics {
346
345
  // image = new BufferedImage(width * pixelFactor, height * pixelFactor
347
346
  // format == RGB ? BufferedImage.TYPE_INT_ARGB);
348
347
 
349
- GraphicsConfiguration gc = null;
350
- if (surface != null) {
351
- Component comp = null; //surface.getComponent();
352
- if (comp == null) {
353
- // System.out.println("component null, but parent.frame is " + parent.frame);
354
- comp = parent.frame;
355
- }
356
- if (comp != null) {
357
- gc = comp.getGraphicsConfiguration();
358
- }
359
- }
360
- // If not realized (off-screen, i.e the Color Selector Tool), gc will be null.
361
- if (gc == null) {
362
- //System.err.println("GraphicsConfiguration null in initImage()");
363
- GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
364
- gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
365
- }
348
+ // GraphicsConfiguration gc = null;
349
+ // if (surface != null) {
350
+ // Component comp = null; //surface.getComponent();
351
+ // if (comp == null) {
352
+ //// System.out.println("component null, but parent.frame is " + parent.frame);
353
+ // comp = parent.frame;
354
+ // }
355
+ // if (comp != null) {
356
+ // gc = comp.getGraphicsConfiguration();
357
+ // }
358
+ // }
359
+ // // If not realized (off-screen, i.e the Color Selector Tool), gc will be null.
360
+ // if (gc == null) {
361
+ // //System.err.println("GraphicsConfiguration null in initImage()");
362
+ // GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
363
+ // gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
364
+ // }
366
365
 
367
366
  // Formerly this was broken into separate versions based on offscreen or
368
367
  // not, but we may as well create a compatible image; it won't hurt, right?
369
368
  int wide = width * pixelDensity;
370
369
  int high = height * pixelDensity;
371
370
  // System.out.println("re-creating image");
372
- image = gc.createCompatibleImage(wide, high, Transparency.TRANSLUCENT);
371
+ image = new BufferedImage(wide, high, BufferedImage.TYPE_INT_ARGB);
373
372
  // image = gc.createCompatibleVolatileImage(wide, high);
374
373
  //image = surface.getComponent().createImage(width, height);
375
374
  }
@@ -0,0 +1,377 @@
1
+ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
+
3
+ /*
4
+ Part of the Processing project - http://processing.org
5
+
6
+ Copyright (c) 2015 The Processing Foundation
7
+
8
+ This library is free software; you can redistribute it and/or
9
+ modify it under the terms of the GNU Lesser General Public
10
+ License version 2.1 as published by the Free Software Foundation.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General
18
+ Public License along with this library; if not, write to the
19
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20
+ Boston, MA 02111-1307 USA
21
+ */
22
+
23
+ package processing.awt;
24
+
25
+ import java.awt.Graphics2D;
26
+ import java.awt.Image;
27
+ import java.awt.RenderingHints;
28
+ import java.awt.Transparency;
29
+ import java.awt.image.BufferedImage;
30
+ import java.awt.image.DataBuffer;
31
+ import java.awt.image.DataBufferInt;
32
+ import java.awt.image.PixelGrabber;
33
+ import java.awt.image.WritableRaster;
34
+ import java.io.BufferedOutputStream;
35
+ import java.io.File;
36
+ import java.io.IOException;
37
+ import java.util.Iterator;
38
+
39
+ import javax.imageio.IIOImage;
40
+ import javax.imageio.ImageIO;
41
+ import javax.imageio.ImageTypeSpecifier;
42
+ import javax.imageio.ImageWriteParam;
43
+ import javax.imageio.ImageWriter;
44
+ import javax.imageio.metadata.IIOInvalidTreeException;
45
+ import javax.imageio.metadata.IIOMetadata;
46
+ import javax.imageio.metadata.IIOMetadataNode;
47
+
48
+ import processing.core.PApplet;
49
+ import processing.core.PImage;
50
+
51
+
52
+ public class PImageAWT extends PImage {
53
+
54
+ /**
55
+ * Construct a new PImage from a java.awt.Image. This constructor assumes
56
+ * that you've done the work of making sure a MediaTracker has been used
57
+ * to fully download the data and that the img is valid.
58
+ *
59
+ * @nowebref
60
+ * @param img assumes a MediaTracker has been used to fully download
61
+ * the data and the img is valid
62
+ */
63
+ public PImageAWT(Image img) {
64
+ format = RGB;
65
+ if (img instanceof BufferedImage) {
66
+ BufferedImage bi = (BufferedImage) img;
67
+ width = bi.getWidth();
68
+ height = bi.getHeight();
69
+ int type = bi.getType();
70
+ if (type == BufferedImage.TYPE_3BYTE_BGR ||
71
+ type == BufferedImage.TYPE_4BYTE_ABGR) {
72
+ pixels = new int[width * height];
73
+ bi.getRGB(0, 0, width, height, pixels, 0, width);
74
+ if (type == BufferedImage.TYPE_4BYTE_ABGR) {
75
+ format = ARGB;
76
+ } else {
77
+ opaque();
78
+ }
79
+ } else {
80
+ DataBuffer db = bi.getRaster().getDataBuffer();
81
+ if (db instanceof DataBufferInt) {
82
+ pixels = ((DataBufferInt) db).getData();
83
+ if (type == BufferedImage.TYPE_INT_ARGB) {
84
+ format = ARGB;
85
+ } else if (type == BufferedImage.TYPE_INT_RGB) {
86
+ opaque();
87
+ }
88
+ }
89
+ }
90
+ }
91
+ // Implements fall-through if not DataBufferInt above, or not a
92
+ // known type, or not DataBufferInt for the data itself.
93
+ if (pixels == null) { // go the old school Java 1.0 route
94
+ width = img.getWidth(null);
95
+ height = img.getHeight(null);
96
+ pixels = new int[width * height];
97
+ PixelGrabber pg =
98
+ new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
99
+ try {
100
+ pg.grabPixels();
101
+ } catch (InterruptedException e) { }
102
+ }
103
+ pixelDensity = 1;
104
+ pixelWidth = width;
105
+ pixelHeight = height;
106
+ }
107
+
108
+
109
+ /**
110
+ * Use the getNative() method instead, which allows library interfaces to be
111
+ * written in a cross-platform fashion for desktop, Android, and others.
112
+ * This is still included for PGraphics objects, which may need the image.
113
+ */
114
+ public Image getImage() { // ignore
115
+ return (Image) getNative();
116
+ }
117
+
118
+
119
+ /**
120
+ * Returns a native BufferedImage from this PImage.
121
+ */
122
+ @Override
123
+ public Object getNative() { // ignore
124
+ loadPixels();
125
+ int type = (format == RGB) ?
126
+ BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
127
+ BufferedImage image = new BufferedImage(pixelWidth, pixelHeight, type);
128
+ WritableRaster wr = image.getRaster();
129
+ wr.setDataElements(0, 0, pixelWidth, pixelHeight, pixels);
130
+ return image;
131
+ }
132
+
133
+
134
+ @Override
135
+ public void resize(int w, int h) { // ignore
136
+ if (w <= 0 && h <= 0) {
137
+ throw new IllegalArgumentException("width or height must be > 0 for resize");
138
+ }
139
+
140
+ if (w == 0) { // Use height to determine relative size
141
+ float diff = (float) h / (float) height;
142
+ w = (int) (width * diff);
143
+ } else if (h == 0) { // Use the width to determine relative size
144
+ float diff = (float) w / (float) width;
145
+ h = (int) (height * diff);
146
+ }
147
+
148
+ BufferedImage img =
149
+ shrinkImage((BufferedImage) getNative(), w*pixelDensity, h*pixelDensity);
150
+
151
+ PImage temp = new PImageAWT(img);
152
+ this.pixelWidth = temp.width;
153
+ this.pixelHeight = temp.height;
154
+
155
+ // Get the resized pixel array
156
+ this.pixels = temp.pixels;
157
+
158
+ this.width = pixelWidth / pixelDensity;
159
+ this.height = pixelHeight / pixelDensity;
160
+
161
+ // Mark the pixels array as altered
162
+ updatePixels();
163
+ }
164
+
165
+
166
+ // Adapted from getFasterScaledInstance() method from page 111 of
167
+ // "Filthy Rich Clients" by Chet Haase and Romain Guy
168
+ // Additional modifications and simplifications have been added,
169
+ // plus a fix to deal with an infinite loop if images are expanded.
170
+ // http://code.google.com/p/processing/issues/detail?id=1463
171
+ static private BufferedImage shrinkImage(BufferedImage img,
172
+ int targetWidth, int targetHeight) {
173
+ int type = (img.getTransparency() == Transparency.OPAQUE) ?
174
+ BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
175
+ BufferedImage outgoing = img;
176
+ BufferedImage scratchImage = null;
177
+ Graphics2D g2 = null;
178
+ int prevW = outgoing.getWidth();
179
+ int prevH = outgoing.getHeight();
180
+ boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;
181
+
182
+ // Use multi-step technique: start with original size, then scale down in
183
+ // multiple passes with drawImage() until the target size is reached
184
+ int w = img.getWidth();
185
+ int h = img.getHeight();
186
+
187
+ do {
188
+ if (w > targetWidth) {
189
+ w /= 2;
190
+ // if this is the last step, do the exact size
191
+ if (w < targetWidth) {
192
+ w = targetWidth;
193
+ }
194
+ } else if (targetWidth >= w) {
195
+ w = targetWidth;
196
+ }
197
+ if (h > targetHeight) {
198
+ h /= 2;
199
+ if (h < targetHeight) {
200
+ h = targetHeight;
201
+ }
202
+ } else if (targetHeight >= h) {
203
+ h = targetHeight;
204
+ }
205
+ if (scratchImage == null || isTranslucent) {
206
+ // Use a single scratch buffer for all iterations and then copy
207
+ // to the final, correctly-sized image before returning
208
+ scratchImage = new BufferedImage(w, h, type);
209
+ g2 = scratchImage.createGraphics();
210
+ }
211
+ g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
212
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
213
+ g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null);
214
+ prevW = w;
215
+ prevH = h;
216
+ outgoing = scratchImage;
217
+ } while (w != targetWidth || h != targetHeight);
218
+ g2.dispose();
219
+
220
+
221
+ // If we used a scratch buffer that is larger than our target size,
222
+ // create an image of the right size and copy the results into it
223
+ if (targetWidth != outgoing.getWidth() ||
224
+ targetHeight != outgoing.getHeight()) {
225
+ scratchImage = new BufferedImage(targetWidth, targetHeight, type);
226
+ g2 = scratchImage.createGraphics();
227
+ g2.drawImage(outgoing, 0, 0, null);
228
+ g2.dispose();
229
+ outgoing = scratchImage;
230
+ }
231
+ return outgoing;
232
+ }
233
+
234
+
235
+ @Override
236
+ protected boolean saveImpl(String filename) {
237
+ if (saveImageFormats == null) {
238
+ saveImageFormats = javax.imageio.ImageIO.getWriterFormatNames();
239
+ }
240
+ try {
241
+ if (saveImageFormats != null) {
242
+ for (String saveImageFormat : saveImageFormats) {
243
+ if (filename.endsWith("." + saveImageFormat)) {
244
+ if (!saveImageIO(filename)) {
245
+ System.err.println("Error while saving image.");
246
+ return false;
247
+ }
248
+ return true;
249
+ }
250
+ }
251
+ }
252
+ } catch (IOException e) {
253
+ }
254
+ return false;
255
+ }
256
+
257
+
258
+ protected String[] saveImageFormats;
259
+
260
+
261
+ /**
262
+ * Use ImageIO functions from Java 1.4 and later to handle image save.
263
+ * Various formats are supported, typically jpeg, png, bmp, and wbmp.
264
+ * To get a list of the supported formats for writing, use: <BR>
265
+ * <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
266
+ *
267
+ * @path The path to which the file should be written.
268
+ */
269
+ protected boolean saveImageIO(String path) throws IOException {
270
+ try {
271
+ int outputFormat = (format == ARGB) ?
272
+ BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
273
+
274
+ String extension =
275
+ path.substring(path.lastIndexOf('.') + 1).toLowerCase();
276
+
277
+ // JPEG and BMP images that have an alpha channel set get pretty unhappy.
278
+ // BMP just doesn't write, and JPEG writes it as a CMYK image.
279
+ // http://code.google.com/p/processing/issues/detail?id=415
280
+ if (extension.equals("bmp") || extension.equals("jpg") || extension.equals("jpeg")) {
281
+ outputFormat = BufferedImage.TYPE_INT_RGB;
282
+ }
283
+
284
+ BufferedImage bimage = new BufferedImage(pixelWidth, pixelHeight, outputFormat);
285
+ bimage.setRGB(0, 0, pixelWidth, pixelHeight, pixels, 0, pixelWidth);
286
+
287
+ File file = new File(path);
288
+
289
+ ImageWriter writer = null;
290
+ ImageWriteParam param = null;
291
+ IIOMetadata metadata = null;
292
+
293
+ if (extension.equals("jpg") || extension.equals("jpeg")) {
294
+ if ((writer = imageioWriter("jpeg")) != null) {
295
+ // Set JPEG quality to 90% with baseline optimization. Setting this
296
+ // to 1 was a huge jump (about triple the size), so this seems good.
297
+ // Oddly, a smaller file size than Photoshop at 90%, but I suppose
298
+ // it's a completely different algorithm.
299
+ param = writer.getDefaultWriteParam();
300
+ param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
301
+ param.setCompressionQuality(0.9f);
302
+ }
303
+ }
304
+
305
+ if (extension.equals("png")) {
306
+ if ((writer = imageioWriter("png")) != null) {
307
+ param = writer.getDefaultWriteParam();
308
+ if (false) {
309
+ metadata = imageioDPI(writer, param, 100);
310
+ }
311
+ }
312
+ }
313
+
314
+ if (writer != null) {
315
+ try (BufferedOutputStream output = new BufferedOutputStream(PApplet.createOutput(file))) {
316
+ writer.setOutput(ImageIO.createImageOutputStream(output));
317
+ // writer.write(null, new IIOImage(bimage, null, null), param);
318
+ writer.write(metadata, new IIOImage(bimage, null, metadata), param);
319
+ writer.dispose();
320
+
321
+ output.flush();
322
+ }
323
+ return true;
324
+ }
325
+ // If iter.hasNext() somehow fails up top, it falls through to here
326
+ return javax.imageio.ImageIO.write(bimage, extension, file);
327
+
328
+ } catch (IOException e) {
329
+ throw new IOException("image save failed.");
330
+ }
331
+ }
332
+
333
+
334
+ private ImageWriter imageioWriter(String extension) {
335
+ Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(extension);
336
+ if (iter.hasNext()) {
337
+ return iter.next();
338
+ }
339
+ return null;
340
+ }
341
+
342
+
343
+ private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double dpi) {
344
+ // http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
345
+ ImageTypeSpecifier typeSpecifier =
346
+ ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
347
+ IIOMetadata metadata =
348
+ writer.getDefaultImageMetadata(typeSpecifier, param);
349
+
350
+ if (!metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) {
351
+ // for PNG, it's dots per millimeter
352
+ double dotsPerMilli = dpi / 25.4;
353
+
354
+ IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
355
+ horiz.setAttribute("value", Double.toString(dotsPerMilli));
356
+
357
+ IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
358
+ vert.setAttribute("value", Double.toString(dotsPerMilli));
359
+
360
+ IIOMetadataNode dim = new IIOMetadataNode("Dimension");
361
+ dim.appendChild(horiz);
362
+ dim.appendChild(vert);
363
+
364
+ IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
365
+ root.appendChild(dim);
366
+
367
+ try {
368
+ metadata.mergeTree("javax_imageio_1.0", root);
369
+ return metadata;
370
+
371
+ } catch (IIOInvalidTreeException e) {
372
+ System.err.println("Could not set the DPI of the output image");
373
+ }
374
+ }
375
+ return null;
376
+ }
377
+ }
@@ -0,0 +1,545 @@
1
+ package processing.awt;
2
+
3
+ import java.awt.Desktop;
4
+ import java.awt.EventQueue;
5
+ import java.awt.FileDialog;
6
+ import java.awt.Frame;
7
+ import java.awt.HeadlessException;
8
+ import java.awt.Image;
9
+ import java.awt.Toolkit;
10
+ import java.awt.color.ColorSpace;
11
+ import java.awt.image.BufferedImage;
12
+ import java.io.File;
13
+ import java.io.IOException;
14
+ import java.io.InputStream;
15
+ import java.net.URI;
16
+ import java.net.URISyntaxException;
17
+
18
+ import java.awt.DisplayMode;
19
+ import java.awt.GraphicsConfiguration;
20
+ import java.awt.GraphicsDevice;
21
+ import java.awt.GraphicsEnvironment;
22
+ import java.awt.geom.AffineTransform;
23
+
24
+ import javax.imageio.ImageIO;
25
+ import javax.swing.ImageIcon;
26
+ import javax.swing.JFileChooser;
27
+ import javax.swing.UIManager;
28
+ import javax.swing.UnsupportedLookAndFeelException;
29
+
30
+ // used by desktopFile() method
31
+ import javax.swing.filechooser.FileSystemView;
32
+
33
+ import processing.core.PApplet;
34
+ import processing.core.PConstants;
35
+ import processing.core.PImage;
36
+
37
+ /**
38
+ * This class exists as an abstraction layer to remove AWT from PApplet. It is a
39
+ * staging area for AWT-specific code that's shared by the Java2D, JavaFX, and
40
+ * JOGL renderers. Once PSurfaceFX and PSurfaceJOGL have their own
41
+ * implementations, these methods will move to PSurfaceAWT.
42
+ */
43
+ public class ShimAWT implements PConstants {
44
+
45
+ /*
46
+ PGraphics graphics;
47
+ PApplet sketch;
48
+
49
+
50
+ public ShimAWT(PApplet sketch) {
51
+ this.graphics = graphics;
52
+ this.sketch = sketch;
53
+ }
54
+ */
55
+ static private ShimAWT instance;
56
+
57
+ private GraphicsDevice[] displayDevices;
58
+
59
+ private final int displayWidth;
60
+ private final int displayHeight;
61
+
62
+ /**
63
+ * Only needed for display functions
64
+ */
65
+ static private ShimAWT getInstance() {
66
+ if (instance == null) {
67
+ instance = new ShimAWT();
68
+ }
69
+ return instance;
70
+ }
71
+
72
+ private ShimAWT() {
73
+ // Need the list of display devices to be queried already for usage below.
74
+ // https://github.com/processing/processing/issues/3295
75
+ // https://github.com/processing/processing/issues/3296
76
+ // Not doing this from a static initializer because it may cause
77
+ // PApplet to cache and the values to stick through subsequent runs.
78
+ // Instead make it a runtime thing and a local variable.
79
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
80
+ GraphicsDevice device = ge.getDefaultScreenDevice();
81
+ displayDevices = ge.getScreenDevices();
82
+
83
+ // // Default or unparsed will be -1, spanning will be 0, actual displays will
84
+ // // be numbered from 1 because it's too weird to say "display 0" in prefs.
85
+ // if (display > 0 && display <= displayDevices.length) {
86
+ // device = displayDevices[display-1];
87
+ // }
88
+ // When this was called, display will always be unset (even in 3.x),
89
+ // since this happens before settings() is called.
90
+ // Set displayWidth and displayHeight for people still using those.
91
+ DisplayMode displayMode = device.getDisplayMode();
92
+ displayWidth = displayMode.getWidth();
93
+ displayHeight = displayMode.getHeight();
94
+ }
95
+
96
+ static public int getDisplayWidth() {
97
+ return getInstance().displayWidth;
98
+ }
99
+
100
+ static public int getDisplayHeight() {
101
+ return getInstance().displayHeight;
102
+ }
103
+
104
+ static public int getDisplayCount() {
105
+ return getInstance().displayDevices.length;
106
+ }
107
+
108
+ static public int getDisplayDensity(int num) {
109
+ return getInstance().displayDensityImpl(num);
110
+ }
111
+
112
+
113
+ /*
114
+ private int displayDensityImpl() {
115
+ if (display != SPAN && (fullScreen || present)) {
116
+ return displayDensity(display);
117
+ }
118
+ // walk through all displays, use 2 if any display is 2
119
+ for (int i = 0; i < displayDevices.length; i++) {
120
+ if (displayDensity(i+1) == 2) {
121
+ return 2;
122
+ }
123
+ }
124
+ // If nobody's density is 2 then everyone is 1
125
+ return 1;
126
+ }
127
+ */
128
+ private int displayDensityImpl(int display) {
129
+ if (display > 0 && display <= displayDevices.length) {
130
+ GraphicsConfiguration graphicsConfig
131
+ = displayDevices[display - 1].getDefaultConfiguration();
132
+ AffineTransform tx = graphicsConfig.getDefaultTransform();
133
+ return (int) Math.round(tx.getScaleX());
134
+ }
135
+
136
+ System.err.println("Display " + display + " does not exist, "
137
+ + "returning 1 for displayDensity(" + display + ")");
138
+ return 1; // not the end of the world, so don't throw a RuntimeException
139
+ }
140
+
141
+ static public PImage loadImage(PApplet sketch, String filename, Object... args) {
142
+ String extension = null;
143
+ if (args != null && args.length > 0) {
144
+ // the only one that's supported for now
145
+ extension = (String) args[0];
146
+ }
147
+
148
+ if (extension == null) {
149
+ String lower = filename.toLowerCase();
150
+ int dot = filename.lastIndexOf('.');
151
+ if (dot == -1) {
152
+ extension = "unknown"; // no extension found
153
+
154
+ } else {
155
+ extension = lower.substring(dot + 1);
156
+
157
+ // check for, and strip any parameters on the url, i.e.
158
+ // filename.jpg?blah=blah&something=that
159
+ int question = extension.indexOf('?');
160
+ if (question != -1) {
161
+ extension = extension.substring(0, question);
162
+ }
163
+ }
164
+ }
165
+
166
+ // just in case. them users will try anything!
167
+ extension = extension.toLowerCase();
168
+
169
+ if (extension.equals("tga")) {
170
+ try {
171
+ InputStream input = sketch.createInput(filename);
172
+ if (input == null) {
173
+ return null;
174
+ }
175
+
176
+ PImage image = PImage.loadTGA(input);
177
+ image.parent = sketch;
178
+ return image;
179
+
180
+ } catch (IOException e) {
181
+ return null;
182
+ }
183
+ }
184
+
185
+ if (extension.equals("tif") || extension.equals("tiff")) {
186
+ InputStream input = sketch.createInput(filename);
187
+ PImage image = (input == null) ? null : PImage.loadTIFF(input);
188
+ return image;
189
+ }
190
+
191
+ // For jpeg, gif, and png, load them using createImage(),
192
+ // because the javax.imageio code was found to be much slower.
193
+ // http://dev.processing.org/bugs/show_bug.cgi?id=392
194
+ try {
195
+ if (extension.equals("jpg") || extension.equals("jpeg")
196
+ || extension.equals("gif") || extension.equals("png")
197
+ || extension.equals("unknown")) {
198
+ byte[] bytes = sketch.loadBytes(filename);
199
+ if (bytes == null) {
200
+ return null;
201
+ } else {
202
+ //Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes);
203
+ Image awtImage = new ImageIcon(bytes).getImage();
204
+
205
+ if (awtImage instanceof BufferedImage) {
206
+ BufferedImage buffImage = (BufferedImage) awtImage;
207
+ int space = buffImage.getColorModel().getColorSpace().getType();
208
+ if (space == ColorSpace.TYPE_CMYK) {
209
+ System.err.println(filename + " is a CMYK image, "
210
+ + "only RGB images are supported.");
211
+ return null;
212
+ /*
213
+ // wishful thinking, appears to not be supported
214
+ // https://community.oracle.com/thread/1272045?start=0&tstart=0
215
+ BufferedImage destImage =
216
+ new BufferedImage(buffImage.getWidth(),
217
+ buffImage.getHeight(),
218
+ BufferedImage.TYPE_3BYTE_BGR);
219
+ ColorConvertOp op = new ColorConvertOp(null);
220
+ op.filter(buffImage, destImage);
221
+ image = new PImage(destImage);
222
+ */
223
+ }
224
+ }
225
+
226
+ PImage image = new PImageAWT(awtImage);
227
+ if (image.width == -1) {
228
+ System.err.println("The file " + filename
229
+ + " contains bad image data, or may not be an image.");
230
+ }
231
+
232
+ // if it's a .gif image, test to see if it has transparency
233
+ if (extension.equals("gif") || extension.equals("png")
234
+ || extension.equals("unknown")) {
235
+ image.checkAlpha();
236
+ }
237
+
238
+ image.parent = sketch;
239
+ return image;
240
+ }
241
+ }
242
+ } catch (Exception e) {
243
+ // show error, but move on to the stuff below, see if it'll work
244
+
245
+ }
246
+
247
+ if (loadImageFormats == null) {
248
+ loadImageFormats = ImageIO.getReaderFormatNames();
249
+ }
250
+ if (loadImageFormats != null) {
251
+ for (String loadImageFormat : loadImageFormats) {
252
+ if (extension.equals(loadImageFormat)) {
253
+ return loadImageIO(sketch, filename);
254
+ }
255
+ }
256
+ }
257
+
258
+ // failed, could not load image after all those attempts
259
+ System.err.println("Could not find a method to load " + filename);
260
+ return null;
261
+ }
262
+
263
+ static protected String[] loadImageFormats;
264
+
265
+ /**
266
+ * Use Java 1.4 ImageIO methods to load an image.
267
+ */
268
+ static protected PImage loadImageIO(PApplet sketch, String filename) {
269
+ InputStream stream = sketch.createInput(filename);
270
+ if (stream == null) {
271
+ System.err.println("The image " + filename + " could not be found.");
272
+ return null;
273
+ }
274
+
275
+ try {
276
+ BufferedImage bi = ImageIO.read(stream);
277
+ //PImage outgoing = new PImage(bi.getWidth(), bi.getHeight());
278
+ PImage outgoing = new PImageAWT(bi);
279
+ outgoing.parent = sketch;
280
+
281
+ //bi.getRGB(0, 0, outgoing.width, outgoing.height,
282
+ // outgoing.pixels, 0, outgoing.width);
283
+ // check the alpha for this image
284
+ // was gonna call getType() on the image to see if RGB or ARGB,
285
+ // but it's not actually useful, since gif images will come through
286
+ // as TYPE_BYTE_INDEXED, which means it'll still have to check for
287
+ // the transparency. also, would have to iterate through all the other
288
+ // types and guess whether alpha was in there, so.. just gonna stick
289
+ // with the old method.
290
+ outgoing.checkAlpha();
291
+
292
+ stream.close();
293
+ // return the image
294
+ return outgoing;
295
+
296
+ } catch (IOException e) {
297
+ return null;
298
+ }
299
+ }
300
+
301
+ static public void initRun() {
302
+ // Supposed to help with flicker, but no effect on OS X.
303
+ // TODO IIRC this helped on Windows, but need to double check.
304
+ System.setProperty("sun.awt.noerasebackground", "true");
305
+
306
+ // Remove 60fps limit on the JavaFX "pulse" timer
307
+ System.setProperty("javafx.animation.fullspeed", "true");
308
+
309
+ // Catch any HeadlessException to provide more useful feedback
310
+ try {
311
+ // Call validate() while resize events are in progress
312
+ Toolkit.getDefaultToolkit().setDynamicLayout(true);
313
+ } catch (HeadlessException e) {
314
+ System.err.println("Cannot run sketch without a display. Read this for possible solutions:");
315
+ System.err.println("https://github.com/processing/processing/wiki/Running-without-a-Display");
316
+ System.exit(1);
317
+ }
318
+ }
319
+
320
+
321
+ /*
322
+ public int displayDensity() {
323
+ if (sketch.display != PConstants.SPAN && (sketch.fullScreen || sketch.present)) {
324
+ return displayDensity(sketch.display);
325
+ }
326
+ // walk through all displays, use 2 if any display is 2
327
+ for (int i = 0; i < displayDevices.length; i++) {
328
+ if (displayDensity(i+1) == 2) {
329
+ return 2;
330
+ }
331
+ }
332
+ // If nobody's density is 2 then everyone is 1
333
+ return 1;
334
+ }
335
+ */
336
+ /**
337
+ * @param display the display number to check (1-indexed to match the
338
+ * Preferences dialog box)
339
+ */
340
+ /*
341
+ public int displayDensity(int display) {
342
+ if (display > 0 && display <= displayDevices.length) {
343
+ GraphicsConfiguration graphicsConfig =
344
+ displayDevices[display - 1].getDefaultConfiguration();
345
+ AffineTransform tx = graphicsConfig.getDefaultTransform();
346
+ return (int) Math.round(tx.getScaleX());
347
+ }
348
+
349
+ System.err.println("Display " + display + " does not exist, returning ");
350
+ return 1; // not the end of the world, so don't throw a RuntimeException
351
+ }
352
+ */
353
+ static public void selectInput(String prompt, String callbackMethod,
354
+ File file, Object callbackObject) {
355
+ EventQueue.invokeLater(() -> {
356
+ selectImpl(prompt, callbackMethod, file,
357
+ callbackObject, null, FileDialog.LOAD);
358
+ });
359
+ }
360
+
361
+
362
+ /*
363
+ static public void selectOutput(String prompt, String callbackMethod,
364
+ File file, Object callbackObject, Frame parent) {
365
+ selectImpl(prompt, callbackMethod, file, callbackObject, parent, FileDialog.SAVE, null);
366
+ }
367
+
368
+
369
+ static public void selectOutput(String prompt, String callbackMethod,
370
+ File file, Object callbackObject, Frame parent,
371
+ PApplet sketch) {
372
+ selectImpl(prompt, callbackMethod, file, callbackObject, parent, FileDialog.SAVE, sketch);
373
+ }
374
+ */
375
+ static public void selectOutput(String prompt, String callbackMethod,
376
+ File file, Object callbackObject) {
377
+ EventQueue.invokeLater(() -> {
378
+ selectImpl(prompt, callbackMethod, file,
379
+ callbackObject, null, FileDialog.SAVE);
380
+ });
381
+ }
382
+
383
+
384
+ /*
385
+ // Will remove the 'sketch' parameter once we get an upstream JOGL fix
386
+ // https://github.com/processing/processing/issues/3831
387
+ static protected void selectEvent(final String prompt,
388
+ final String callbackMethod,
389
+ final File defaultSelection,
390
+ final Object callbackObject,
391
+ final Frame parentFrame,
392
+ final int mode,
393
+ final PApplet sketch) {
394
+ EventQueue.invokeLater(new Runnable() {
395
+ public void run() {
396
+ boolean hide = (sketch != null) &&
397
+ (sketch.g instanceof PGraphicsOpenGL) &&
398
+ (PApplet.platform == PConstants.WINDOWS);
399
+ if (hide) sketch.getSurface().setVisible(false);
400
+
401
+ selectImpl(prompt, callbackMethod, defaultSelection, callbackObject,
402
+ parentFrame, mode, sketch);
403
+
404
+ if (hide) sketch.getSurface().setVisible(true);
405
+ }
406
+ });
407
+ }
408
+ */
409
+ static public void selectImpl(final String prompt,
410
+ final String callbackMethod,
411
+ final File defaultSelection,
412
+ final Object callbackObject,
413
+ final Frame parentFrame,
414
+ final int mode) {
415
+ File selectedFile = null;
416
+
417
+ if (PApplet.useNativeSelect) {
418
+ FileDialog dialog = new FileDialog(parentFrame, prompt, mode);
419
+ if (defaultSelection != null) {
420
+ dialog.setDirectory(defaultSelection.getParent());
421
+ dialog.setFile(defaultSelection.getName());
422
+ }
423
+
424
+ dialog.setVisible(true);
425
+ String directory = dialog.getDirectory();
426
+ String filename = dialog.getFile();
427
+ if (filename != null) {
428
+ selectedFile = new File(directory, filename);
429
+ }
430
+
431
+ } else {
432
+ JFileChooser chooser = new JFileChooser();
433
+ chooser.setDialogTitle(prompt);
434
+ if (defaultSelection != null) {
435
+ chooser.setSelectedFile(defaultSelection);
436
+ }
437
+
438
+ int result = -1;
439
+ if (mode == FileDialog.SAVE) {
440
+ result = chooser.showSaveDialog(parentFrame);
441
+ } else if (mode == FileDialog.LOAD) {
442
+ result = chooser.showOpenDialog(parentFrame);
443
+ }
444
+ if (result == JFileChooser.APPROVE_OPTION) {
445
+ selectedFile = chooser.getSelectedFile();
446
+ }
447
+ }
448
+ PApplet.selectCallback(selectedFile, callbackMethod, callbackObject);
449
+ }
450
+
451
+ static public void selectFolder(final String prompt,
452
+ final String callbackMethod,
453
+ final File defaultSelection,
454
+ final Object callbackObject) {
455
+ EventQueue.invokeLater(() -> {
456
+ selectFolderImpl(prompt, callbackMethod, defaultSelection,
457
+ callbackObject, null);
458
+ });
459
+ }
460
+
461
+
462
+ /*
463
+ static public void selectFolder(final String prompt,
464
+ final String callbackMethod,
465
+ final File defaultSelection,
466
+ final Object callbackObject,
467
+ final Frame parentFrame) {
468
+ selectFolderEvent(prompt, callbackMethod, defaultSelection, callbackObject, parentFrame, null);
469
+ }
470
+
471
+
472
+ // Will remove the 'sketch' parameter once we get an upstream JOGL fix
473
+ // https://github.com/processing/processing/issues/3831
474
+ static public void selectFolderEvent(final String prompt,
475
+ final String callbackMethod,
476
+ final File defaultSelection,
477
+ final Object callbackObject,
478
+ final Frame parentFrame,
479
+ final PApplet sketch) {
480
+ EventQueue.invokeLater(() -> {
481
+ selectFolderImpl(prompt, callbackMethod, defaultSelection,
482
+ callbackObject, parentFrame, sketch);
483
+ });
484
+ }
485
+ */
486
+ static public void selectFolderImpl(final String prompt,
487
+ final String callbackMethod,
488
+ final File defaultSelection,
489
+ final Object callbackObject,
490
+ final Frame parentFrame) {
491
+ File selectedFile = null;
492
+
493
+ checkLookAndFeel();
494
+ JFileChooser fileChooser = new JFileChooser();
495
+ fileChooser.setDialogTitle(prompt);
496
+ fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
497
+ if (defaultSelection != null) {
498
+ fileChooser.setCurrentDirectory(defaultSelection);
499
+ }
500
+
501
+ int result = fileChooser.showOpenDialog(parentFrame);
502
+ if (result == JFileChooser.APPROVE_OPTION) {
503
+ selectedFile = fileChooser.getSelectedFile();
504
+ }
505
+
506
+ PApplet.selectCallback(selectedFile, callbackMethod, callbackObject);
507
+ }
508
+
509
+ static private boolean lookAndFeelCheck;
510
+
511
+ /**
512
+ * Initialize the Look & Feel if it hasn't been already. Call this before
513
+ * using any Swing-related code in PApplet methods.
514
+ */
515
+ static private void checkLookAndFeel() {
516
+ if (!lookAndFeelCheck) {
517
+ if (PApplet.platform == PConstants.WINDOWS) {
518
+ // Windows is defaulting to Metal or something else awful.
519
+ // Which also is not scaled properly with HiDPI interfaces.
520
+ try {
521
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
522
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | UnsupportedLookAndFeelException e) {
523
+ }
524
+ }
525
+ lookAndFeelCheck = true;
526
+ }
527
+ }
528
+
529
+ // TODO maybe call this with reflection from inside PApplet?
530
+ // longer term, develop a more general method for other platforms
531
+ static public File getWindowsDesktop() {
532
+ return FileSystemView.getFileSystemView().getHomeDirectory();
533
+ }
534
+
535
+ static public boolean openLink(String url) {
536
+ try {
537
+ if (Desktop.isDesktopSupported()) {
538
+ Desktop.getDesktop().browse(new URI(url));
539
+ return true;
540
+ }
541
+ } catch (IOException | URISyntaxException e) {
542
+ }
543
+ return false;
544
+ }
545
+ }