picrate 2.0.1-java → 2.3.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) 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 +6 -3
  7. data/Rakefile +2 -1
  8. data/docs/_includes/footer.html +1 -1
  9. data/docs/_layouts/post.html +1 -1
  10. data/docs/_methods/alternative_methods.md +2 -1
  11. data/docs/_methods/noise_mode.md +88 -0
  12. data/docs/_posts/2018-05-06-install_jruby.md +3 -3
  13. data/docs/_posts/2018-11-18-building-gem.md +3 -1
  14. data/docs/_posts/2020-03-09-auto_install_picrate.md +2 -3
  15. data/docs/_posts/2020-05-11-getting_started_manjaro.md +20 -8
  16. data/docs/classes.md +2 -2
  17. data/docs/editors.md +2 -2
  18. data/docs/gems.md +3 -3
  19. data/docs/index.html +1 -1
  20. data/docs/libraries.md +2 -2
  21. data/docs/live.md +2 -2
  22. data/docs/magic.md +2 -2
  23. data/docs/methods.md +2 -2
  24. data/docs/modules.md +3 -3
  25. data/docs/objects.md +2 -2
  26. data/lib/picrate.rb +2 -1
  27. data/lib/picrate/app.rb +7 -2
  28. data/lib/picrate/helper_methods.rb +1 -1
  29. data/lib/picrate/native_folder.rb +1 -3
  30. data/lib/picrate/runner.rb +4 -4
  31. data/lib/picrate/version.rb +1 -1
  32. data/library/jcomplex/jcomplex.rb +1 -0
  33. data/library/pdf/pdf.rb +6 -0
  34. data/mvnw +2 -2
  35. data/mvnw.cmd +2 -2
  36. data/picrate.gemspec +3 -2
  37. data/pom.rb +22 -8
  38. data/pom.xml +27 -5
  39. data/src/main/java/monkstone/PicrateLibrary.java +1 -1
  40. data/src/main/java/monkstone/complex/JComplex.java +252 -0
  41. data/src/main/java/monkstone/fastmath/DegLutTables.java +111 -0
  42. data/src/main/java/monkstone/fastmath/Deglut.java +41 -93
  43. data/src/main/java/monkstone/noise/FastTerrain.java +874 -0
  44. data/src/main/java/monkstone/noise/Noise.java +90 -0
  45. data/src/main/java/monkstone/noise/NoiseGenerator.java +75 -0
  46. data/src/main/java/monkstone/noise/NoiseMode.java +28 -0
  47. data/src/main/java/monkstone/noise/OpenSimplex2F.java +881 -0
  48. data/src/main/java/monkstone/noise/OpenSimplex2S.java +1106 -0
  49. data/src/main/java/monkstone/noise/SmoothTerrain.java +1099 -0
  50. data/src/main/java/monkstone/vecmath/package-info.java +1 -1
  51. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +1 -1
  52. data/src/main/java/monkstone/videoevent/package-info.java +1 -1
  53. data/src/main/java/processing/awt/PGraphicsJava2D.java +22 -23
  54. data/src/main/java/processing/awt/PImageAWT.java +377 -0
  55. data/src/main/java/processing/awt/ShimAWT.java +711 -0
  56. data/src/main/java/processing/core/PApplet.java +14880 -14101
  57. data/src/main/java/processing/core/PConstants.java +5 -5
  58. data/src/main/java/processing/core/PFont.java +1 -1
  59. data/src/main/java/processing/core/PGraphics.java +284 -271
  60. data/src/main/java/processing/core/PImage.java +1620 -1815
  61. data/src/main/java/processing/core/PShape.java +18 -18
  62. data/src/main/java/processing/core/PSurface.java +105 -139
  63. data/src/main/java/processing/core/PSurfaceNone.java +29 -0
  64. data/src/main/java/processing/core/PVector.java +23 -23
  65. data/src/main/java/processing/data/Table.java +4 -4
  66. data/src/main/java/processing/net/Client.java +13 -13
  67. data/src/main/java/processing/net/Server.java +5 -5
  68. data/src/main/java/processing/opengl/PGL.java +649 -3699
  69. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +2503 -2278
  70. data/src/main/java/processing/opengl/PJOGL.java +374 -1526
  71. data/src/main/java/processing/opengl/PSurfaceJOGL.java +220 -86
  72. data/src/main/java/processing/pdf/PGraphicsPDF.java +607 -0
  73. data/test/deglut_spec_test.rb +2 -2
  74. data/test/respond_to_test.rb +0 -1
  75. data/vendors/Rakefile +33 -21
  76. data/vendors/{picrate_sketches.geany → geany.rb} +32 -7
  77. metadata +24 -9
  78. data/src/main/java/monkstone/noise/SimplexNoise.java +0 -465
@@ -1,6 +1,6 @@
1
1
  /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
2
 
3
- /*
3
+ /*
4
4
  Part of the Processing project - http://processing.org
5
5
 
6
6
  Copyright (c) 2004-14 Ben Fry and Casey Reas
@@ -20,37 +20,41 @@
20
20
  Public License along with this library; if not, write to the
21
21
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
22
  Boston, MA 02111-1307 USA
23
- */
23
+ */
24
+
24
25
  package processing.core;
25
26
 
26
- import java.awt.*;
27
- import java.awt.image.*;
28
- import java.io.*;
29
- import java.util.Iterator;
27
+ import java.io.BufferedOutputStream;
28
+ import java.io.File;
29
+ import java.io.FileOutputStream;
30
+ import java.io.IOException;
31
+ import java.io.InputStream;
32
+ import java.io.OutputStream;
33
+
34
+ import processing.awt.ShimAWT;
30
35
 
31
- import javax.imageio.*;
32
- import javax.imageio.metadata.*;
33
36
 
34
37
  /**
35
- * ( begin auto-generated from PImage.xml )
36
38
  *
37
- * Datatype for storing images. Processing can display <b>.gif</b>,
38
- * <b>.jpg</b>, <b>.tga</b>, and <b>.png</b> images. Images may be displayed in
39
- * 2D and 3D space. Before an image is used, it must be loaded with the
40
- * <b>loadImage()</b> function. The <b>PImage</b> class contains fields for the
41
- * <b>width</b> and <b>height</b> of the image, as well as an array called
42
- * <b>pixels[]</b> that contains the values for every pixel in the image. The
43
- * methods described below allow easy access to the image's pixels and alpha
44
- * channel and simplify the process of compositing.
45
- * using the <b>pixels[]</b> array, be sure to use the
39
+ * Datatype for storing images. Processing can display <b>.gif</b>, <b>.jpg</b>,
40
+ * <b>.tga</b>, and <b>.png</b> images. Images may be displayed in 2D and 3D
41
+ * space. Before an image is used, it must be loaded with the <b>loadImage()</b>
42
+ * function. The <b>PImage</b> class contains fields for the <b>width</b> and
43
+ * <b>height</b> of the image, as well as an array called <b>pixels[]</b> that
44
+ * contains the values for every pixel in the image. The methods described below
45
+ * allow easy access to the image's pixels and alpha channel and simplify the
46
+ * process of compositing.<br />
47
+ * <br />
48
+ * Before using the <b>pixels[]</b> array, be sure to use the
46
49
  * <b>loadPixels()</b> method on the image to make sure that the pixel data is
47
- * properly loaded.
48
- * create a new image, use the <b>createImage()</b> function. Do not use
49
- * the syntax <b>new PImage()</b>.
50
+ * properly loaded.<br />
51
+ * <br />
52
+ * To create a new image, use the <b>createImage()</b> function. Do not use the
53
+ * syntax <b>new PImage()</b>.
50
54
  *
51
- * ( end auto-generated )
52
55
  *
53
56
  * @webref image
57
+ * @webBrief Datatype for storing images.
54
58
  * @usage Web &amp; Application
55
59
  * @instanceName pimg any object of type PImage
56
60
  * @see PApplet#loadImage(String)
@@ -59,127 +63,101 @@ import javax.imageio.metadata.*;
59
63
  */
60
64
  public class PImage implements PConstants, Cloneable {
61
65
 
66
+ private static final byte[] TIFF_HEADER = {
67
+ 77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0,
68
+ 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1,
69
+ 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0,
70
+ 0, 0, 1, 0, 2, 0, 0, 1, 17, 0, 4, 0, 0, 0, 1, 0, 0, 3, 0, 1, 21,
71
+ 0, 3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 22, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0,
72
+ 1, 23, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8
73
+ };
74
+
75
+ private static final String TIFF_ERROR = "Error: Processing can only read its own TIFF files.";
76
+
62
77
  /**
63
- * Format for this image, one of RGB, ARGB or ALPHA. note that RGB images
64
- * still require 0xff in the high byte because of how they'll be manipulated
65
- * by other functions
78
+ * Format for this image, one of RGB, ARGB or ALPHA.
79
+ * note that RGB images still require 0xff in the high byte
80
+ * because of how they'll be manipulated by other functions
66
81
  */
67
82
  public int format;
68
83
 
69
84
  /**
70
- * ( begin auto-generated from pixels.xml )
71
- *
72
- * Array containing the values for all the pixels in the display window. These
73
- * values are of the color datatype. This array is the size of the display
74
- * window. For example, if the image is 100x100 pixels, there will be 10000
75
- * values and if the window is 200x300 pixels, there will be 60000 values. The
76
- * <b>index</b> value defines the position of a value within the array. For
77
- * example, the statement <b>color b = pixels[230]</b> will set the variable
78
- * <b>b</b> to be equal to the value at that location in the array.
79
- *
85
+ *
86
+ * The pixels[] array contains the values for all the pixels in the image. These
87
+ * values are of the color datatype. This array is the size of the image,
88
+ * meaning if the image is 100 x 100 pixels, there will be 10,000 values and if
89
+ * the window is 200 x 300 pixels, there will be 60,000 values. <br />
90
+ * <br />
80
91
  * Before accessing this array, the data must loaded with the
81
- * <b>loadPixels()</b> function. After the array data has been modified, the
82
- * <b>updatePixels()</b> function must be run to update the changes. Without
83
- * <b>loadPixels()</b>, running the code may (or will in future releases)
84
- * result in a NullPointerException.
92
+ * <b>loadPixels()</b> method. Failure to do so may result in a
93
+ * NullPointerException. After the array data has been modified, the
94
+ * <b>updatePixels()</b> method must be run to update the content of the display
95
+ * window.
85
96
  *
86
- * ( end auto-generated )
87
97
  *
88
98
  * @webref image:pixels
99
+ * @webBrief Array containing the color of every pixel in the image.
89
100
  * @usage web_application
90
- * @brief Array containing the color of every pixel in the image
91
101
  */
92
102
  public int[] pixels;
93
103
 
94
- /**
95
- * 1 for most images, 2 for hi-dpi/retina
96
- */
104
+ /** 1 for most images, 2 for hi-dpi/retina */
97
105
  public int pixelDensity = 1;
98
106
 
99
- /**
100
- * Actual dimensions of pixels array, taking into account the 2x setting.
101
- */
107
+ /** Actual dimensions of pixels array, taking into account the 2x setting. */
102
108
  public int pixelWidth;
103
-
104
- /**
105
- *
106
- */
107
109
  public int pixelHeight;
108
110
 
109
111
  /**
110
- * ( begin auto-generated from PImage_width.xml )
111
112
  *
112
113
  * The width of the image in units of pixels.
113
114
  *
114
- * ( end auto-generated )
115
- *
116
115
  * @webref pimage:field
116
+ * @webBrief The width of the image in units of pixels.
117
117
  * @usage web_application
118
- * @brief Image width
119
118
  */
120
119
  public int width;
121
120
 
122
121
  /**
123
- * ( begin auto-generated from PImage_height.xml )
124
122
  *
125
123
  * The height of the image in units of pixels.
126
124
  *
127
- * ( end auto-generated )
128
- *
129
125
  * @webref pimage:field
126
+ * @webBrief The height of the image in units of pixels.
130
127
  * @usage web_application
131
- * @brief Image height
132
128
  */
133
129
  public int height;
134
130
 
135
131
  /**
136
- * Path to parent object that will be used with save(). This prevents users
137
- * from needing savePath() to use PImage.save().
132
+ * Path to parent object that will be used with save().
133
+ * This prevents users from needing savePath() to use PImage.save().
138
134
  */
139
135
  public PApplet parent;
140
136
 
137
+
141
138
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
142
- /**
143
- * modified portion of the image
144
- */
145
- protected boolean modified;
146
139
 
147
- /**
148
- *
149
- */
150
- protected int mx1,
151
- /**
152
- *
153
- */
154
- my1,
155
- /**
156
- *
157
- */
158
- mx2,
159
- /**
160
- *
161
- */
162
- my2;
163
140
 
164
- /**
165
- * Loaded pixels flag
166
- */
141
+ /** modified portion of the image */
142
+ protected boolean modified;
143
+ protected int mx1, my1, mx2, my2;
144
+
145
+ /** Loaded pixels flag */
167
146
  public boolean loaded = false;
168
147
 
169
148
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
170
- // private fields
171
- private int fracU, ifU, fracV, ifV, u1, u2, v1, v2, sX, sY, iw, iw1, ih1;
172
- private int ul, ll, ur, lr, cUL, cLL, cUR, cLR;
149
+
150
+
151
+ private int ifV, sX, v1, v2, iw, iw1, ih1;
173
152
  private int srcXOffset, srcYOffset;
174
- private int r, g, b, a;
175
153
  private int[] srcBuffer;
176
154
 
177
- // fixed point precision is limited to 15 bits!!
155
+ // fixed point precision is limited to 15 bits
178
156
  static final int PRECISIONB = 15;
179
157
  static final int PRECISIONF = 1 << PRECISIONB;
180
- static final int PREC_MAXVAL = PRECISIONF - 1;
181
- static final int PREC_ALPHA_SHIFT = 24 - PRECISIONB;
182
- static final int PREC_RED_SHIFT = 16 - PRECISIONB;
158
+ static final int PREC_MAXVAL = PRECISIONF-1;
159
+ static final int PREC_ALPHA_SHIFT = 24-PRECISIONB;
160
+ static final int PREC_RED_SHIFT = 16-PRECISIONB;
183
161
 
184
162
  // internal kernel stuff for the gaussian blur filter
185
163
  private int blurRadius;
@@ -188,46 +166,34 @@ public class PImage implements PConstants, Cloneable {
188
166
  private int[][] blurMult;
189
167
 
190
168
  // colour component bitmasks (moved from PConstants in 2.0b7)
191
- /**
192
- *
193
- */
194
169
  public static final int ALPHA_MASK = 0xff000000;
195
-
196
- /**
197
- *
198
- */
199
- public static final int RED_MASK = 0x00ff0000;
200
-
201
- /**
202
- *
203
- */
170
+ public static final int RED_MASK = 0x00ff0000;
204
171
  public static final int GREEN_MASK = 0x0000ff00;
172
+ public static final int BLUE_MASK = 0x000000ff;
205
173
 
206
- /**
207
- *
208
- */
209
- public static final int BLUE_MASK = 0x000000ff;
210
174
 
211
175
  //////////////////////////////////////////////////////////////
176
+
177
+
212
178
  /**
213
179
  * ( begin auto-generated from PImage.xml )
214
180
  *
215
181
  * Datatype for storing images. Processing can display <b>.gif</b>,
216
- * <b>.jpg</b>, <b>.tga</b>, and <b>.png</b> images. Images may be displayed
217
- * in 2D and 3D space. Before an image is used, it must be loaded with the
218
- * <b>loadImage()</b> function. The <b>PImage</b> object contains fields for
219
- * the <b>width</b> and <b>height</b> of the image, as well as an array called
220
- * <b>pixels[]</b> which contains the values for every pixel in the image. A
221
- * group of methods, described below, allow easy access to the image's pixels
222
- * and alpha channel and simplify the process of compositing.
223
- *
182
+ * <b>.jpg</b>, <b>.tga</b>, and <b>.png</b> images. Images may be
183
+ * displayed in 2D and 3D space. Before an image is used, it must be loaded
184
+ * with the <b>loadImage()</b> function. The <b>PImage</b> object contains
185
+ * fields for the <b>width</b> and <b>height</b> of the image, as well as
186
+ * an array called <b>pixels[]</b> which contains the values for every
187
+ * pixel in the image. A group of methods, described below, allow easy
188
+ * access to the image's pixels and alpha channel and simplify the process
189
+ * of compositing.
190
+ * <br/> <br/>
224
191
  * Before using the <b>pixels[]</b> array, be sure to use the
225
- * <b>loadPixels()</b> method on the image to make sure that the pixel data is
226
- * properly loaded.
227
- *
192
+ * <b>loadPixels()</b> method on the image to make sure that the pixel data
193
+ * is properly loaded.
194
+ * <br/> <br/>
228
195
  * To create a new image, use the <b>createImage()</b> function (do not use
229
- * <b>new PImage()</b>). ( end auto-generated )
230
- *
196
+ * <b>new PImage()</b>).
231
197
  * @nowebref
232
198
  * @usage web_application
233
199
  * @see PApplet#loadImage(String, String)
@@ -236,11 +202,12 @@ public class PImage implements PConstants, Cloneable {
236
202
  */
237
203
  public PImage() {
238
204
  format = ARGB; // default to ARGB images for release 0116
239
- pixelDensity = 1;
240
205
  }
241
206
 
207
+
242
208
  /**
243
- * @nowebref @param width image width
209
+ * @nowebref
210
+ * @param width image width
244
211
  * @param height image height
245
212
  */
246
213
  public PImage(int width, int height) {
@@ -249,16 +216,15 @@ public class PImage implements PConstants, Cloneable {
249
216
  // toxi: is it maybe better to init the image with max alpha enabled?
250
217
  //for(int i=0; i<pixels.length; i++) pixels[i]=0xffffffff;
251
218
  // fry: i'm opting for the full transparent image, which is how
252
- // photoshop works, and our audience oughta be familiar with.
219
+ // photoshop works, and our audience will likely be familiar with.
253
220
  // also, i want to avoid having to set all those pixels since
254
221
  // in java it's super slow, and most using this fxn will be
255
222
  // setting all the pixels anyway.
256
223
  // toxi: agreed and same reasons why i left it out ;)
257
224
  }
258
225
 
226
+
259
227
  /**
260
- * @param width
261
- * @param height
262
228
  * @nowebref
263
229
  * @param format Either RGB, ARGB, ALPHA (grayscale alpha channel)
264
230
  */
@@ -266,39 +232,26 @@ public class PImage implements PConstants, Cloneable {
266
232
  init(width, height, format, 1);
267
233
  }
268
234
 
269
- /**
270
- *
271
- * @param width
272
- * @param height
273
- * @param format
274
- * @param factor
275
- */
235
+
276
236
  public PImage(int width, int height, int format, int factor) {
277
237
  init(width, height, format, factor);
278
238
  }
279
239
 
240
+
280
241
  /**
281
242
  * Do not remove, see notes in the other variant.
282
- *
283
- * @param width
284
- * @param height
285
- * @param format
286
243
  */
287
244
  public void init(int width, int height, int format) { // ignore
288
245
  init(width, height, format, 1);
289
246
  }
290
247
 
248
+
291
249
  /**
292
- * Function to be used by subclasses of PImage to init later than at the
293
- * constructor, or re-init later when things changes. Used by Capture and
294
- * Movie classes (and perhaps others), because the width/height will not be
295
- * known when super() is called. (Leave this public so that other libraries
296
- * can do the same.)
297
- *
298
- * @param width
299
- * @param factor
300
- * @param height
301
- * @param format
250
+ * Function to be used by subclasses of PImage to init later than
251
+ * at the constructor, or re-init later when things changes.
252
+ * Used by Capture and Movie classes (and perhaps others),
253
+ * because the width/height will not be known when super() is called.
254
+ * (Leave this public so that other libraries can do the same.)
302
255
  */
303
256
  public void init(int width, int height, int format, int factor) { // ignore
304
257
  this.width = width;
@@ -311,13 +264,12 @@ public class PImage implements PConstants, Cloneable {
311
264
  this.pixels = new int[pixelWidth * pixelHeight];
312
265
  }
313
266
 
267
+
314
268
  /**
315
269
  * Check the alpha on an image, using a really primitive loop.
316
270
  */
317
- protected void checkAlpha() {
318
- if (pixels == null) {
319
- return;
320
- }
271
+ public void checkAlpha() {
272
+ if (pixels == null) return;
321
273
 
322
274
  for (int i = 0; i < pixels.length; i++) {
323
275
  // since transparency is often at corners, hopefully this
@@ -329,101 +281,56 @@ public class PImage implements PConstants, Cloneable {
329
281
  }
330
282
  }
331
283
 
284
+
332
285
  //////////////////////////////////////////////////////////////
333
- /**
334
- * Construct a new PImage from a java.awt.Image. This constructor assumes that
335
- * you've done the work of making sure a MediaTracker has been used to fully
336
- * download the data and that the img is valid.
337
- *
338
- * @nowebref
339
- * @param img assumes a MediaTracker has been used to fully download the data
340
- * and the img is valid
341
- */
342
- public PImage(Image img) {
343
- format = RGB;
344
- if (img instanceof BufferedImage) {
345
- BufferedImage bi = (BufferedImage) img;
346
- width = bi.getWidth();
347
- height = bi.getHeight();
348
- int type = bi.getType();
349
- if (type == BufferedImage.TYPE_3BYTE_BGR
350
- || type == BufferedImage.TYPE_4BYTE_ABGR) {
351
- pixels = new int[width * height];
352
- bi.getRGB(0, 0, width, height, pixels, 0, width);
353
- if (type == BufferedImage.TYPE_4BYTE_ABGR) {
354
- format = ARGB;
355
- } else {
356
- opaque();
357
- }
358
- } else {
359
- DataBuffer db = bi.getRaster().getDataBuffer();
360
- if (db instanceof DataBufferInt) {
361
- pixels = ((DataBufferInt) db).getData();
362
- if (type == BufferedImage.TYPE_INT_ARGB) {
363
- format = ARGB;
364
- } else if (type == BufferedImage.TYPE_INT_RGB) {
365
- opaque();
366
- }
367
- }
368
- }
286
+
287
+
288
+ public PImage(int width, int height, int[] pixels,
289
+ boolean requiresCheckAlpha, PApplet parent) {
290
+ initFromPixels(width, height, pixels, RGB,1);
291
+ this.parent = parent;
292
+
293
+ if (requiresCheckAlpha) {
294
+ checkAlpha();
369
295
  }
370
- // Implements fall-through if not DataBufferInt above, or not a
371
- // known type, or not DataBufferInt for the data itself.
372
- if (pixels == null) { // go the old school Java 1.0 route
373
- width = img.getWidth(null);
374
- height = img.getHeight(null);
375
- pixels = new int[width * height];
376
- PixelGrabber pg
377
- = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
378
- try {
379
- pg.grabPixels();
380
- } catch (InterruptedException e) {
381
- }
296
+ }
297
+
298
+ public PImage(int width, int height, int[] pixels,
299
+ boolean requiresCheckAlpha, PApplet parent,
300
+ int format, int factor) {
301
+
302
+ initFromPixels(width, height, pixels, format, factor);
303
+ this.parent = parent;
304
+
305
+ if (requiresCheckAlpha) {
306
+ checkAlpha();
382
307
  }
383
- pixelDensity = 1;
384
- pixelWidth = width;
385
- pixelHeight = height;
386
308
  }
387
309
 
388
- /**
389
- * Use the getNative() method instead, which allows library interfaces to be
390
- * written in a cross-platform fashion for desktop, Android, and others. This
391
- * is still included for PGraphics objects, which may need the image.
392
- *
393
- * @return
394
- */
395
- public Image getImage() { // ignore
396
- return (Image) getNative();
310
+ private void initFromPixels(int width, int height, int[] pixels, int format, int factor) {
311
+ this.width = width;
312
+ this.height = height;
313
+ this.format = format;
314
+ this.pixelDensity = factor;
315
+ this.pixels = pixels;
397
316
  }
398
317
 
399
- /**
400
- * Returns a native BufferedImage from this PImage.
401
- *
402
- * @return
403
- */
318
+
404
319
  public Object getNative() { // ignore
405
- loadPixels();
406
- int type = (format == RGB)
407
- ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
408
- BufferedImage image = new BufferedImage(pixelWidth, pixelHeight, type);
409
- WritableRaster wr = image.getRaster();
410
- wr.setDataElements(0, 0, pixelWidth, pixelHeight, pixels);
411
- return image;
320
+ return null;
412
321
  }
413
322
 
323
+
414
324
  //////////////////////////////////////////////////////////////
325
+
415
326
  // MARKING IMAGE AS MODIFIED / FOR USE w/ GET/SET
416
- /**
417
- *
418
- * @return
419
- */
327
+
328
+
420
329
  public boolean isModified() { // ignore
421
330
  return modified;
422
331
  }
423
332
 
424
- /**
425
- *
426
- */
333
+
427
334
  public void setModified() { // ignore
428
335
  modified = true;
429
336
  mx1 = 0;
@@ -432,111 +339,76 @@ public class PImage implements PConstants, Cloneable {
432
339
  my2 = pixelHeight;
433
340
  }
434
341
 
435
- /**
436
- *
437
- * @param m
438
- */
342
+
439
343
  public void setModified(boolean m) { // ignore
440
344
  modified = m;
441
345
  }
442
346
 
443
- /**
444
- *
445
- * @return
446
- */
347
+
447
348
  public int getModifiedX1() { // ignore
448
349
  return mx1;
449
350
  }
450
351
 
451
- /**
452
- *
453
- * @return
454
- */
352
+
455
353
  public int getModifiedX2() { // ignore
456
354
  return mx2;
457
355
  }
458
356
 
459
- /**
460
- *
461
- * @return
462
- */
357
+
463
358
  public int getModifiedY1() { // ignore
464
359
  return my1;
465
360
  }
466
361
 
467
- /**
468
- *
469
- * @return
470
- */
362
+
471
363
  public int getModifiedY2() { // ignore
472
364
  return my2;
473
365
  }
474
366
 
367
+
475
368
  /**
476
- * ( begin auto-generated from PImage_loadPixels.xml )
477
- *
478
- * Loads the pixel data for the image into its <b>pixels[]</b> array. This
479
- * function must always be called before reading from or writing to
480
- * <b>pixels[]</b>.
481
- * renderers may or may not seem to require <b>loadPixels()</b>
482
- * or <b>updatePixels()</b>. However, the rule is that any time you want to
483
- * manipulate the <b>pixels[]</b> array, you must first call
484
- * <b>loadPixels()</b>, and after changes have been made, call
485
- * <b>updatePixels()</b>. Even if the renderer may not seem to use this
486
- * function in the current Processing release, this will always be subject to
487
- * change.
488
369
  *
489
- * ( end auto-generated )
370
+ * Loads the pixel data of the current display window into the <b>pixels[]</b>
371
+ * array. This function must always be called before reading from or writing to
372
+ * <b>pixels[]</b>. Subsequent changes to the display window will not be
373
+ * reflected in <b>pixels</b> until <b>loadPixels()</b> is called again.
490
374
  *
491
- * <h3>Advanced</h3>
492
- * Call this when you want to mess with the pixels[] array.
493
375
  *
376
+ * <h3>Advanced</h3> Call this when you want to mess with the pixels[] array.
377
+ * <p/>
494
378
  * For subclasses where the pixels[] buffer isn't set by default, this should
495
379
  * copy all data into the pixels[] array
496
380
  *
497
381
  * @webref pimage:pixels
498
- * @brief Loads the pixel data for the image into its pixels[] array
382
+ * @webBrief Loads the pixel data for the image into its <b>pixels[]</b> array.
499
383
  * @usage web_application
500
384
  */
501
385
  public void loadPixels() { // ignore
502
- if (pixels == null || pixels.length != pixelWidth * pixelHeight) {
503
- pixels = new int[pixelWidth * pixelHeight];
386
+ if (pixels == null || pixels.length != pixelWidth*pixelHeight) {
387
+ pixels = new int[pixelWidth*pixelHeight];
504
388
  }
505
389
  setLoaded();
506
390
  }
507
391
 
508
- /**
509
- *
510
- */
392
+
511
393
  public void updatePixels() { // ignore
512
394
  updatePixels(0, 0, pixelWidth, pixelHeight);
513
395
  }
514
396
 
397
+
515
398
  /**
516
- * ( begin auto-generated from PImage_updatePixels.xml )
517
- *
518
- * Updates the image with the data in its <b>pixels[]</b> array. Use in
519
- * conjunction with <b>loadPixels()</b>. If you're only reading pixels from
520
- * the array, there's no need to call <b>updatePixels()</b>.
521
- * renderers may or may not seem to require <b>loadPixels()</b>
522
- * or <b>updatePixels()</b>. However, the rule is that any time you want to
523
- * manipulate the <b>pixels[]</b> array, you must first call
524
- * <b>loadPixels()</b>, and after changes have been made, call
525
- * <b>updatePixels()</b>. Even if the renderer may not seem to use this
526
- * function in the current Processing release, this will always be subject to
527
- * change.
528
- *
529
- * Currently, none of the renderers use the additional parameters to
530
- * <b>updatePixels()</b>, however this may be implemented in the future.
531
- *
532
- * ( end auto-generated )
533
- * <h3>Advanced</h3>
534
- * Mark the pixels in this region as needing an update. This is not currently
535
- * used by any of the renderers, however the api is structured this way in the
536
- * hope of being able to use this to speed things up in the future.
399
+ *
400
+ * Updates the display window with the data in the <b>pixels[]</b> array. Use in
401
+ * conjunction with <b>loadPixels()</b>. If you're only reading pixels from the
402
+ * array, there's no need to call <b>updatePixels()</b> &mdash; updating is only
403
+ * necessary to apply changes.
404
+ *
405
+ * <h3>Advanced</h3> Mark the pixels in this region as needing an update. This
406
+ * is not currently used by any of the renderers, however the api is structured
407
+ * this way in the hope of being able to use this to speed things up in the
408
+ * future.
537
409
  *
538
410
  * @webref pimage:pixels
539
- * @brief Updates the image with the data in its pixels[] array
411
+ * @webBrief Updates the image with the data in its <b>pixels[]</b> array.
540
412
  * @usage web_application
541
413
  * @param x x-coordinate of the upper-left corner
542
414
  * @param y y-coordinate of the upper-left corner
@@ -555,246 +427,131 @@ public class PImage implements PConstants, Cloneable {
555
427
  modified = true;
556
428
 
557
429
  } else {
558
- if (x < mx1) {
559
- mx1 = PApplet.max(0, x);
560
- }
561
- if (x > mx2) {
562
- mx2 = PApplet.min(pixelWidth, x);
563
- }
564
- if (y < my1) {
565
- my1 = PApplet.max(0, y);
566
- }
567
- if (y > my2) {
568
- my2 = PApplet.min(pixelHeight, y);
569
- }
430
+ if (x < mx1) mx1 = PApplet.max(0, x);
431
+ if (x > mx2) mx2 = PApplet.min(pixelWidth, x);
432
+ if (y < my1) my1 = PApplet.max(0, y);
433
+ if (y > my2) my2 = PApplet.min(pixelHeight, y);
570
434
 
571
- if (x2 < mx1) {
572
- mx1 = PApplet.max(0, x2);
573
- }
574
- if (x2 > mx2) {
575
- mx2 = PApplet.min(pixelWidth, x2);
576
- }
577
- if (y2 < my1) {
578
- my1 = PApplet.max(0, y2);
579
- }
580
- if (y2 > my2) {
581
- my2 = PApplet.min(pixelHeight, y2);
582
- }
435
+ if (x2 < mx1) mx1 = PApplet.max(0, x2);
436
+ if (x2 > mx2) mx2 = PApplet.min(pixelWidth, x2);
437
+ if (y2 < my1) my1 = PApplet.max(0, y2);
438
+ if (y2 > my2) my2 = PApplet.min(pixelHeight, y2);
583
439
  }
584
440
  }
585
441
 
442
+
586
443
  //////////////////////////////////////////////////////////////
444
+
587
445
  // COPYING IMAGE DATA
446
+
447
+
588
448
  /**
589
- * Duplicate an image, returns new PImage object. The pixels[] array for the
590
- * new object will be unique and recopied from the source image. This is
591
- * implemented as an override of Object.clone(). We recommend using get()
592
- * instead, because it prevents you from needing to catch the
449
+ * Duplicate an image, returns new PImage object.
450
+ * The pixels[] array for the new object will be unique
451
+ * and recopied from the source image. This is implemented as an
452
+ * override of Object.clone(). We recommend using get() instead,
453
+ * because it prevents you from needing to catch the
593
454
  * CloneNotSupportedException, and from doing a cast from the result.
594
- *
595
- * @return
596
- * @throws java.lang.CloneNotSupportedException
597
455
  */
598
456
  @Override
599
457
  public Object clone() throws CloneNotSupportedException { // ignore
600
458
  return get();
601
459
  }
602
460
 
461
+
603
462
  /**
604
- * ( begin auto-generated from PImage_resize.xml )
605
463
  *
606
464
  * Resize the image to a new width and height. To make the image scale
607
465
  * proportionally, use 0 as the value for the <b>wide</b> or <b>high</b>
608
466
  * parameter. For instance, to make the width of an image 150 pixels, and
609
- * change the height using the same proportion, use resize(150, 0).
610
- *
467
+ * change the height using the same proportion, use resize(150, 0).<br />
468
+ * <br />
611
469
  * Even though a PGraphics is technically a PImage, it is not possible to
612
- * rescale the image data found in a PGraphics. (It's simply not possible to
613
- * do this consistently across renderers: technically infeasible with P3D, or
614
- * what would it even do with PDF?) If you want to resize PGraphics content,
615
- * first get a copy of its image data using the <b>get()</b>
470
+ * rescale the image data found in a PGraphics. (It's simply not possible
471
+ * to do this consistently across renderers: technically infeasible with
472
+ * P3D, or what would it even do with PDF?) If you want to resize PGraphics
473
+ * content, first get a copy of its image data using the <b>get()</b>
616
474
  * method, and call <b>resize()</b> on the PImage that is returned.
617
475
  *
618
- * ( end auto-generated )
619
- *
620
476
  * @webref pimage:method
621
- * @brief Changes the size of an image to a new width and height
477
+ * @webBrief Resize the image to a new width and height.
622
478
  * @usage web_application
623
479
  * @param w the resized image width
624
480
  * @param h the resized image height
625
481
  * @see PImage#get(int, int, int, int)
626
482
  */
627
483
  public void resize(int w, int h) { // ignore
628
- if (w <= 0 && h <= 0) {
629
- throw new IllegalArgumentException("width or height must be > 0 for resize");
630
- }
631
-
632
- if (w == 0) { // Use height to determine relative size
633
- float diff = (float) h / (float) height;
634
- w = (int) (width * diff);
635
- } else if (h == 0) { // Use the width to determine relative size
636
- float diff = (float) w / (float) width;
637
- h = (int) (height * diff);
638
- }
639
-
640
- BufferedImage img
641
- = shrinkImage((BufferedImage) getNative(), w * pixelDensity, h * pixelDensity);
642
-
643
- PImage temp = new PImage(img);
644
- this.pixelWidth = temp.width;
645
- this.pixelHeight = temp.height;
646
-
647
- // Get the resized pixel array
648
- this.pixels = temp.pixels;
649
-
650
- this.width = pixelWidth / pixelDensity;
651
- this.height = pixelHeight / pixelDensity;
652
-
653
- // Mark the pixels array as altered
654
- updatePixels();
484
+ throw new RuntimeException("resize() not implemented for this PImage type");
655
485
  }
656
486
 
657
- // Adapted from getFasterScaledInstance() method from page 111 of
658
- // "Filthy Rich Clients" by Chet Haase and Romain Guy
659
- // Additional modifications and simplifications have been added,
660
- // plus a fix to deal with an infinite loop if images are expanded.
661
- // http://code.google.com/p/processing/issues/detail?id=1463
662
- static private BufferedImage shrinkImage(BufferedImage img,
663
- int targetWidth, int targetHeight) {
664
- int type = (img.getTransparency() == Transparency.OPAQUE)
665
- ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
666
- BufferedImage outgoing = img;
667
- BufferedImage scratchImage = null;
668
- Graphics2D g2 = null;
669
- int prevW = outgoing.getWidth();
670
- int prevH = outgoing.getHeight();
671
- boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;
672
-
673
- // Use multi-step technique: start with original size, then scale down in
674
- // multiple passes with drawImage() until the target size is reached
675
- int w = img.getWidth();
676
- int h = img.getHeight();
677
-
678
- do {
679
- if (w > targetWidth) {
680
- w /= 2;
681
- // if this is the last step, do the exact size
682
- if (w < targetWidth) {
683
- w = targetWidth;
684
- }
685
- } else if (targetWidth >= w) {
686
- w = targetWidth;
687
- }
688
- if (h > targetHeight) {
689
- h /= 2;
690
- if (h < targetHeight) {
691
- h = targetHeight;
692
- }
693
- } else if (targetHeight >= h) {
694
- h = targetHeight;
695
- }
696
- if (scratchImage == null || isTranslucent) {
697
- // Use a single scratch buffer for all iterations and then copy
698
- // to the final, correctly-sized image before returning
699
- scratchImage = new BufferedImage(w, h, type);
700
- g2 = scratchImage.createGraphics();
701
- }
702
- g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
703
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
704
- g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null);
705
- prevW = w;
706
- prevH = h;
707
- outgoing = scratchImage;
708
- } while (w != targetWidth || h != targetHeight);
709
-
710
- if (g2 != null) {
711
- g2.dispose();
712
- }
713
-
714
- // If we used a scratch buffer that is larger than our target size,
715
- // create an image of the right size and copy the results into it
716
- if (targetWidth != outgoing.getWidth()
717
- || targetHeight != outgoing.getHeight()) {
718
- scratchImage = new BufferedImage(targetWidth, targetHeight, type);
719
- g2 = scratchImage.createGraphics();
720
- g2.drawImage(outgoing, 0, 0, null);
721
- g2.dispose();
722
- outgoing = scratchImage;
723
- }
724
- return outgoing;
725
- }
726
487
 
727
488
  //////////////////////////////////////////////////////////////
489
+
728
490
  // MARKING IMAGE AS LOADED / FOR USE IN RENDERERS
729
- /**
730
- *
731
- * @return
732
- */
491
+
492
+
733
493
  public boolean isLoaded() { // ignore
734
494
  return loaded;
735
495
  }
736
496
 
737
- /**
738
- *
739
- */
497
+
740
498
  public void setLoaded() { // ignore
741
499
  loaded = true;
742
500
  }
743
501
 
744
- /**
745
- *
746
- * @param l
747
- */
502
+
748
503
  public void setLoaded(boolean l) { // ignore
749
504
  loaded = l;
750
505
  }
751
506
 
507
+
752
508
  //////////////////////////////////////////////////////////////
509
+
753
510
  // GET/SET PIXELS
511
+
512
+
754
513
  /**
755
- * ( begin auto-generated from PImage_get.xml )
756
514
  *
757
515
  * Reads the color of any pixel or grabs a section of an image. If no
758
516
  * parameters are specified, the entire image is returned. Use the <b>x</b>
759
- * and <b>y</b> parameters to get the value of one pixel. Get a section of the
760
- * display window by specifying an additional <b>width</b> and
517
+ * and <b>y</b> parameters to get the value of one pixel. Get a section of
518
+ * the display window by specifying an additional <b>width</b> and
761
519
  * <b>height</b> parameter. When getting an image, the <b>x</b> and
762
- * <b>y</b> parameters define the coordinates for the upper-left corner of the
763
- * image, regardless of the current <b>imageMode()</b>.
764
- *
765
- * If the pixel requested is outside of the image window, black is returned.
766
- * The numbers returned are scaled according to the current color ranges, but
767
- * only RGB values are returned by this function. For example, even though you
768
- * may have drawn a shape with <b>colorMode(HSB)</b>, the numbers returned
769
- * will be in RGB format.
770
- *
771
- * Getting the color of a single pixel with <b>get(x, y)</b> is easy, but not
772
- * as fast as grabbing the data directly from <b>pixels[]</b>. The equivalent
773
- * statement to <b>get(x, y)</b> using <b>pixels[]</b> is
774
- * <b>pixels[y*width+x]</b>. See the reference for <b>pixels[]</b> for more
775
- * information.
776
- *
777
- * ( end auto-generated )
520
+ * <b>y</b> parameters define the coordinates for the upper-left corner of
521
+ * the image, regardless of the current <b>imageMode()</b>.<br />
522
+ * <br />
523
+ * If the pixel requested is outside of the image window, black is
524
+ * returned. The numbers returned are scaled according to the current color
525
+ * ranges, but only RGB values are returned by this function. For example,
526
+ * even though you may have drawn a shape with <b>colorMode(HSB)</b>, the
527
+ * numbers returned will be in RGB format.<br />
528
+ * <br />
529
+ * Getting the color of a single pixel with <b>get(x, y)</b> is easy, but
530
+ * not as fast as grabbing the data directly from <b>pixels[]</b>. The
531
+ * equivalent statement to <b>get(x, y)</b> using <b>pixels[]</b> is
532
+ * <b>pixels[y*width+x]</b>. See the reference for <b>pixels[]</b> for more information.
533
+ *
778
534
  *
779
535
  * <h3>Advanced</h3>
780
- * Returns an ARGB "color" type (a packed 32 bit int with the color. If the
781
- * coordinate is outside the image, zero is returned (black, but completely
782
- * transparent).
536
+ * Returns an ARGB "color" type (a packed 32 bit int with the color.
537
+ * If the coordinate is outside the image, zero is returned
538
+ * (black, but completely transparent).
783
539
  * <P>
784
- * If the image is in RGB format (i.e. on a PVideo object), the value will get
785
- * its high bits set, just to avoid cases where they haven't been set already.
540
+ * If the image is in RGB format (i.e. on a PVideo object),
541
+ * the value will get its high bits set, just to avoid cases where
542
+ * they haven't been set already.
786
543
  * <P>
787
- * If the image is in ALPHA format, this returns a white with its alpha value
788
- * set.
544
+ * If the image is in ALPHA format, this returns a white with its
545
+ * alpha value set.
789
546
  * <P>
790
- * This function is included primarily for beginners. It is quite slow because
791
- * it has to check to see if the x, y that was provided is inside the bounds,
792
- * and then has to check to see what image type it is. If you want things to
793
- * be more efficient, access the pixels[] array directly.
547
+ * This function is included primarily for beginners. It is quite
548
+ * slow because it has to check to see if the x, y that was provided
549
+ * is inside the bounds, and then has to check to see what image
550
+ * type it is. If you want things to be more efficient, access the
551
+ * pixels[] array directly.
794
552
  *
795
- * @return
796
553
  * @webref image:pixels
797
- * @brief Reads the color of any pixel or grabs a rectangle of pixels
554
+ * @webBrief Reads the color of any pixel or grabs a rectangle of pixels.
798
555
  * @usage web_application
799
556
  * @param x x-coordinate of the pixel
800
557
  * @param y y-coordinate of the pixel
@@ -803,29 +560,25 @@ public class PImage implements PConstants, Cloneable {
803
560
  * @see PApplet#copy(PImage, int, int, int, int, int, int, int, int)
804
561
  */
805
562
  public int get(int x, int y) {
806
- if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) {
807
- return 0;
808
- }
563
+ if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return 0;
809
564
 
810
565
  switch (format) {
811
566
  case RGB:
812
- return pixels[y * pixelWidth + x] | 0xff000000;
567
+ return pixels[y*pixelWidth + x] | 0xff000000;
813
568
 
814
569
  case ARGB:
815
- return pixels[y * pixelWidth + x];
570
+ return pixels[y*pixelWidth + x];
816
571
 
817
572
  case ALPHA:
818
- return (pixels[y * pixelWidth + x] << 24) | 0xffffff;
573
+ return (pixels[y*pixelWidth + x] << 24) | 0xffffff;
819
574
  }
820
575
  return 0;
821
576
  }
822
577
 
578
+
823
579
  /**
824
- * @param x
825
- * @param y
826
580
  * @param w width of pixel rectangle to get
827
581
  * @param h height of pixel rectangle to get
828
- * @return
829
582
  */
830
583
  public PImage get(int x, int y, int w, int h) {
831
584
  int targetX = 0;
@@ -869,8 +622,8 @@ public class PImage implements PConstants, Cloneable {
869
622
  }
870
623
 
871
624
  PImage target = new PImage(targetWidth / pixelDensity,
872
- targetHeight / pixelDensity,
873
- targetFormat, pixelDensity);
625
+ targetHeight / pixelDensity,
626
+ targetFormat, pixelDensity);
874
627
  target.parent = parent; // parent may be null so can't use createImage()
875
628
  if (w > 0 && h > 0) {
876
629
  getImpl(x, y, w, h, target, targetX, targetY);
@@ -878,11 +631,10 @@ public class PImage implements PConstants, Cloneable {
878
631
  return target;
879
632
  }
880
633
 
634
+
881
635
  /**
882
636
  * Returns a copy of this PImage. Equivalent to get(0, 0, width, height).
883
637
  * Deprecated, just use copy() instead.
884
- *
885
- * @return
886
638
  */
887
639
  public PImage get() {
888
640
  // Formerly this used clone(), which caused memory problems.
@@ -890,33 +642,23 @@ public class PImage implements PConstants, Cloneable {
890
642
  return get(0, 0, pixelWidth, pixelHeight);
891
643
  }
892
644
 
893
- /**
894
- *
895
- * @return
896
- */
645
+
897
646
  public PImage copy() {
898
647
  return get(0, 0, pixelWidth, pixelHeight);
899
648
  }
900
649
 
650
+
901
651
  /**
902
- * Internal function to actually handle getting a block of pixels that has
903
- * already been properly cropped to a valid region. That is, x/y/w/h are
904
- * guaranteed to be inside the image space, so the implementation can use the
905
- * fastest possible pixel copying method.
906
- *
907
- * @param sourceX
908
- * @param sourceY
909
- * @param sourceWidth
910
- * @param target
911
- * @param sourceHeight
912
- * @param targetX
913
- * @param targetY
652
+ * Internal function to actually handle getting a block of pixels that
653
+ * has already been properly cropped to a valid region. That is, x/y/w/h
654
+ * are guaranteed to be inside the image space, so the implementation can
655
+ * use the fastest possible pixel copying method.
914
656
  */
915
657
  protected void getImpl(int sourceX, int sourceY,
916
- int sourceWidth, int sourceHeight,
917
- PImage target, int targetX, int targetY) {
918
- int sourceIndex = sourceY * pixelWidth + sourceX;
919
- int targetIndex = targetY * target.pixelWidth + targetX;
658
+ int sourceWidth, int sourceHeight,
659
+ PImage target, int targetX, int targetY) {
660
+ int sourceIndex = sourceY*pixelWidth + sourceX;
661
+ int targetIndex = targetY*target.pixelWidth + targetX;
920
662
  for (int row = 0; row < sourceHeight; row++) {
921
663
  System.arraycopy(pixels, sourceIndex, target.pixels, targetIndex, sourceWidth);
922
664
  sourceIndex += pixelWidth;
@@ -924,29 +666,28 @@ public class PImage implements PConstants, Cloneable {
924
666
  }
925
667
  }
926
668
 
669
+
927
670
  /**
928
- * ( begin auto-generated from PImage_set.xml )
929
671
  *
930
- * Changes the color of any pixel or writes an image directly into the display
931
- * window.
932
- *
672
+ * Changes the color of any pixel or writes an image directly into the
673
+ * display window.<br />
674
+ * <br />
933
675
  * The <b>x</b> and <b>y</b> parameters specify the pixel to change and the
934
676
  * <b>color</b> parameter specifies the color value. The color parameter is
935
677
  * affected by the current color mode (the default is RGB values from 0 to
936
678
  * 255). When setting an image, the <b>x</b> and <b>y</b> parameters define
937
- * the coordinates for the upper-left corner of the image, regardless of the
938
- * current <b>imageMode()</b>.
939
- *
940
- * Setting the color of a single pixel with <b>set(x, y)</b> is easy, but not
941
- * as fast as putting the data directly into <b>pixels[]</b>. The equivalent
942
- * statement to <b>set(x, y, #000000)</b> using <b>pixels[]</b>
679
+ * the coordinates for the upper-left corner of the image, regardless of
680
+ * the current <b>imageMode()</b>.
681
+ * <br /><br />
682
+ * Setting the color of a single pixel with <b>set(x, y)</b> is easy, but
683
+ * not as fast as putting the data directly into <b>pixels[]</b>. The
684
+ * equivalent statement to <b>set(x, y, #000000)</b> using <b>pixels[]</b>
943
685
  * is <b>pixels[y*width+x] = #000000</b>. See the reference for
944
686
  * <b>pixels[]</b> for more information.
945
687
  *
946
- * ( end auto-generated )
947
688
  *
948
689
  * @webref image:pixels
949
- * @brief writes a color to any pixel or writes an image into another
690
+ * @webBrief Writes a color to any pixel or writes an image into another
950
691
  * @usage web_application
951
692
  * @param x x-coordinate of the pixel
952
693
  * @param y y-coordinate of the pixel
@@ -956,22 +697,19 @@ public class PImage implements PConstants, Cloneable {
956
697
  * @see PImage#copy(PImage, int, int, int, int, int, int, int, int)
957
698
  */
958
699
  public void set(int x, int y, int c) {
959
- if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) {
960
- return;
961
- }
962
- pixels[y * pixelWidth + x] = c;
700
+ if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return;
701
+ pixels[y*pixelWidth + x] = c;
963
702
  updatePixels(x, y, 1, 1); // slow...
964
703
  }
965
704
 
705
+
966
706
  /**
967
707
  * <h3>Advanced</h3>
968
- * Efficient method of drawing an image's pixels directly to this surface. No
969
- * variations are employed, meaning that any scale, tint, or imageMode
708
+ * Efficient method of drawing an image's pixels directly to this surface.
709
+ * No variations are employed, meaning that any scale, tint, or imageMode
970
710
  * settings will be ignored.
971
711
  *
972
- * @param x
973
712
  * @param img image to copy into the original image
974
- * @param y
975
713
  */
976
714
  public void set(int x, int y, PImage img) {
977
715
  int sx = 0;
@@ -997,29 +735,20 @@ public class PImage implements PConstants, Cloneable {
997
735
  }
998
736
 
999
737
  // this could be nonexistent
1000
- if ((sw <= 0) || (sh <= 0)) {
1001
- return;
1002
- }
738
+ if ((sw <= 0) || (sh <= 0)) return;
1003
739
 
1004
740
  setImpl(img, sx, sy, sw, sh, x, y);
1005
741
  }
1006
742
 
743
+
1007
744
  /**
1008
- * Internal function to actually handle setting a block of pixels that has
1009
- * already been properly cropped from the image to a valid region.
1010
- *
1011
- * @param sourceImage
1012
- * @param sourceX
1013
- * @param targetY
1014
- * @param sourceHeight
1015
- * @param sourceY
1016
- * @param sourceWidth
1017
- * @param targetX
745
+ * Internal function to actually handle setting a block of pixels that
746
+ * has already been properly cropped from the image to a valid region.
1018
747
  */
1019
748
  protected void setImpl(PImage sourceImage,
1020
- int sourceX, int sourceY,
1021
- int sourceWidth, int sourceHeight,
1022
- int targetX, int targetY) {
749
+ int sourceX, int sourceY,
750
+ int sourceWidth, int sourceHeight,
751
+ int targetX, int targetY) {
1023
752
  int sourceOffset = sourceY * sourceImage.pixelWidth + sourceX;
1024
753
  int targetOffset = targetY * pixelWidth + targetX;
1025
754
 
@@ -1033,13 +762,18 @@ public class PImage implements PConstants, Cloneable {
1033
762
  updatePixels(targetX, targetY, sourceWidth, sourceHeight);
1034
763
  }
1035
764
 
765
+
766
+
1036
767
  //////////////////////////////////////////////////////////////
768
+
1037
769
  // ALPHA CHANNEL
770
+
771
+
1038
772
  /**
1039
773
  * @param maskArray array of integers used as the alpha channel, needs to be
1040
774
  * the same length as the image's pixel array.
1041
775
  */
1042
- public void mask(int maskArray[]) { // ignore
776
+ public void mask(int[] maskArray) { // ignore
1043
777
  loadPixels();
1044
778
  // don't execute if mask image is different size
1045
779
  if (maskArray.length != pixels.length) {
@@ -1052,50 +786,52 @@ public class PImage implements PConstants, Cloneable {
1052
786
  updatePixels();
1053
787
  }
1054
788
 
789
+
1055
790
  /**
1056
- * ( begin auto-generated from PImage_mask.xml )
1057
791
  *
1058
- * Masks part of an image from displaying by loading another image and using
1059
- * it as an alpha channel. This mask image should only contain grayscale data,
1060
- * but only the blue color channel is used. The mask image needs to be the
1061
- * same size as the image to which it is applied.
1062
- *
792
+ * Masks part of an image from displaying by loading another image and
793
+ * using it as an alpha channel. This mask image should only contain
794
+ * grayscale data, but only the blue color channel is used. The mask image
795
+ * needs to be the same size as the image to which it is applied.<br />
796
+ * <br />
1063
797
  * In addition to using a mask image, an integer array containing the alpha
1064
- * channel data can be specified directly. This method is useful for creating
1065
- * dynamically generated alpha masks. This array must be of the same length as
1066
- * the target image's pixels array and should contain only grayscale data of
1067
- * values between 0-255.
798
+ * channel data can be specified directly. This method is useful for
799
+ * creating dynamically generated alpha masks. This array must be of the
800
+ * same length as the target image's pixels array and should contain only
801
+ * grayscale data of values between 0-255.
1068
802
  *
1069
- * ( end auto-generated )
1070
803
  *
1071
804
  * <h3>Advanced</h3>
1072
805
  *
1073
- * Set alpha channel for an image. Black colors in the source image will make
1074
- * the destination image completely transparent, and white will make things
1075
- * fully opaque. Gray values will be in-between steps.
806
+ * Set alpha channel for an image. Black colors in the source
807
+ * image will make the destination image completely transparent,
808
+ * and white will make things fully opaque. Gray values will
809
+ * be in-between steps.
1076
810
  * <P>
1077
- * Strictly speaking the "blue" value from the source image is used as the
1078
- * alpha color. For a fully grayscale image, this is correct, but for a color
1079
- * image it's not 100% accurate. For a more accurate conversion, first use
1080
- * filter(GRAY) which will make the image into a "correct" grayscale by
811
+ * Strictly speaking the "blue" value from the source image is
812
+ * used as the alpha color. For a fully grayscale image, this
813
+ * is correct, but for a color image it's not 100% accurate.
814
+ * For a more accurate conversion, first use filter(GRAY)
815
+ * which will make the image into a "correct" grayscale by
1081
816
  * performing a proper luminance-based conversion.
1082
817
  *
1083
818
  * @webref pimage:method
819
+ * @webBrief Masks part of an image with another image as an alpha channel
1084
820
  * @usage web_application
1085
821
  * @param img image to use as the mask
1086
- * @brief Masks part of an image with another image as an alpha channel
1087
822
  */
1088
823
  public void mask(PImage img) {
1089
824
  img.loadPixels();
1090
825
  mask(img.pixels);
1091
826
  }
1092
827
 
828
+
829
+
1093
830
  //////////////////////////////////////////////////////////////
831
+
1094
832
  // IMAGE FILTERS
1095
- /**
1096
- *
1097
- * @param kind
1098
- */
833
+
834
+
1099
835
  public void filter(int kind) {
1100
836
  loadPixels();
1101
837
 
@@ -1126,8 +862,8 @@ public class PImage implements PConstants, Cloneable {
1126
862
  // 0.30 * 256 = 77
1127
863
  // 0.59 * 256 = 151
1128
864
  // 0.11 * 256 = 28
1129
- int lum = (77 * (col >> 16 & 0xff) + 151 * (col >> 8 & 0xff) + 28 * (col & 0xff)) >> 8;
1130
- pixels[i] = (col & ALPHA_MASK) | lum << 16 | lum << 8 | lum;
865
+ int lum = (77*(col>>16&0xff) + 151*(col>>8&0xff) + 28*(col&0xff))>>8;
866
+ pixels[i] = (col & ALPHA_MASK) | lum<<16 | lum<<8 | lum;
1131
867
  }
1132
868
  }
1133
869
  break;
@@ -1140,8 +876,8 @@ public class PImage implements PConstants, Cloneable {
1140
876
  break;
1141
877
 
1142
878
  case POSTERIZE:
1143
- throw new RuntimeException("Use filter(POSTERIZE, int levels) "
1144
- + "instead of filter(POSTERIZE)");
879
+ throw new RuntimeException("Use filter(POSTERIZE, int levels) " +
880
+ "instead of filter(POSTERIZE)");
1145
881
 
1146
882
  case OPAQUE:
1147
883
  for (int i = 0; i < pixels.length; i++) {
@@ -1154,7 +890,7 @@ public class PImage implements PConstants, Cloneable {
1154
890
  filter(THRESHOLD, 0.5f);
1155
891
  break;
1156
892
 
1157
- // [toxi 050728] added new filters
893
+ // [toxi 050728] added new filters
1158
894
  case ERODE:
1159
895
  erode(); // former dilate(true);
1160
896
  break;
@@ -1166,38 +902,45 @@ public class PImage implements PConstants, Cloneable {
1166
902
  updatePixels(); // mark as modified
1167
903
  }
1168
904
 
905
+
1169
906
  /**
1170
- * ( begin auto-generated from PImage_filter.xml )
1171
- *
1172
- * Filters an image as defined by one of the following modes:<br
1173
- * />THRESHOLD - converts the image to black and white pixels depending if
1174
- * they are above or below the threshold defined by the level parameter. The
1175
- * level must be between 0.0 (black) and 1.0(white). If no level is specified,
1176
- * 0.5 is used.
1177
- *
1178
- * GRAY - converts any colors in the image to grayscale equivalents
1179
- *
1180
- * INVERT - sets each pixel to its inverse value
1181
- *
1182
- * POSTERIZE - limits each channel of the image to the number of colors
1183
- * specified as the level parameter
1184
- *
1185
- * BLUR - executes a Guassian blur with the level parameter specifying the
1186
- * extent of the blurring. If no level parameter is used, the blur is
1187
- * equivalent to Guassian blur of radius 1
1188
- *
1189
- * OPAQUE - sets the alpha channel to entirely opaque
1190
- *
1191
- * ERODE - reduces the light areas with the amount defined by the level
1192
- * parameter
1193
- *
1194
- * DILATE - increases the light areas with the amount defined by the level
1195
- * parameter
1196
- *
1197
- * ( end auto-generated )
1198
907
  *
1199
- * <h3>Advanced</h3>
1200
- * Method to apply a variety of basic filters to this image.
908
+ * Filters the image as defined by one of the following modes:<br />
909
+ * <br />
910
+ * THRESHOLD<br />
911
+ * Converts the image to black and white pixels depending if they are above or
912
+ * below the threshold defined by the level parameter. The parameter must be
913
+ * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is
914
+ * used.<br />
915
+ * <br />
916
+ * GRAY<br />
917
+ * Converts any colors in the image to grayscale equivalents. No parameter is
918
+ * used.<br />
919
+ * <br />
920
+ * OPAQUE<br />
921
+ * Sets the alpha channel to entirely opaque. No parameter is used.<br />
922
+ * <br />
923
+ * INVERT<br />
924
+ * Sets each pixel to its inverse value. No parameter is used.<br />
925
+ * <br />
926
+ * POSTERIZE<br />
927
+ * Limits each channel of the image to the number of colors specified as the
928
+ * parameter. The parameter can be set to values between 2 and 255, but results
929
+ * are most noticeable in the lower ranges.<br />
930
+ * <br />
931
+ * BLUR<br />
932
+ * Executes a Gaussian blur with the level parameter specifying the extent of
933
+ * the blurring. If no parameter is used, the blur is equivalent to Gaussian
934
+ * blur of radius 1. Larger values increase the blur.<br />
935
+ * <br />
936
+ * ERODE<br />
937
+ * Reduces the light areas. No parameter is used.<br />
938
+ * <br />
939
+ * DILATE<br />
940
+ * Increases the light areas. No parameter is used.
941
+ *
942
+ *
943
+ * <h3>Advanced</h3> Method to apply a variety of basic filters to this image.
1201
944
  * <P>
1202
945
  * <UL>
1203
946
  * <LI>filter(BLUR) provides a basic blur.
@@ -1210,15 +953,15 @@ public class PImage implements PConstants, Cloneable {
1210
953
  * </UL>
1211
954
  * Luminance conversion code contributed by
1212
955
  * <A HREF="http://www.toxi.co.uk">toxi</A>
1213
- *
956
+ * <P/>
1214
957
  * Gaussian blur code contributed by
1215
958
  * <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A>
1216
959
  *
1217
960
  * @webref image:pixels
1218
- * @brief Converts the image to grayscale or black and white
961
+ * @webBrief Converts the image to grayscale or black and white
1219
962
  * @usage web_application
1220
- * @param kind Either THRESHOLD, GRAY, OPAQUE, INVERT, POSTERIZE, BLUR, ERODE,
1221
- * or DILATE
963
+ * @param kind Either THRESHOLD, GRAY, OPAQUE, INVERT, POSTERIZE, BLUR, ERODE,
964
+ * or DILATE
1222
965
  * @param param unique for each, see above
1223
966
  */
1224
967
  public void filter(int kind, float param) {
@@ -1226,32 +969,31 @@ public class PImage implements PConstants, Cloneable {
1226
969
 
1227
970
  switch (kind) {
1228
971
  case BLUR:
1229
- if (format == ALPHA) {
972
+ if (format == ALPHA)
1230
973
  blurAlpha(param);
1231
- } else if (format == ARGB) {
974
+ else if (format == ARGB)
1232
975
  blurARGB(param);
1233
- } else {
976
+ else
1234
977
  blurRGB(param);
1235
- }
1236
978
  break;
1237
979
 
1238
980
  case GRAY:
1239
- throw new RuntimeException("Use filter(GRAY) instead of "
1240
- + "filter(GRAY, param)");
981
+ throw new RuntimeException("Use filter(GRAY) instead of " +
982
+ "filter(GRAY, param)");
1241
983
 
1242
984
  case INVERT:
1243
- throw new RuntimeException("Use filter(INVERT) instead of "
1244
- + "filter(INVERT, param)");
985
+ throw new RuntimeException("Use filter(INVERT) instead of " +
986
+ "filter(INVERT, param)");
1245
987
 
1246
988
  case OPAQUE:
1247
- throw new RuntimeException("Use filter(OPAQUE) instead of "
1248
- + "filter(OPAQUE, param)");
989
+ throw new RuntimeException("Use filter(OPAQUE) instead of " +
990
+ "filter(OPAQUE, param)");
1249
991
 
1250
992
  case POSTERIZE:
1251
- int levels = (int) param;
993
+ int levels = (int)param;
1252
994
  if ((levels < 2) || (levels > 255)) {
1253
- throw new RuntimeException("Levels must be between 2 and 255 for "
1254
- + "filter(POSTERIZE, levels)");
995
+ throw new RuntimeException("Levels must be between 2 and 255 for " +
996
+ "filter(POSTERIZE, levels)");
1255
997
  }
1256
998
  int levels1 = levels - 1;
1257
999
  for (int i = 0; i < pixels.length; i++) {
@@ -1261,10 +1003,10 @@ public class PImage implements PConstants, Cloneable {
1261
1003
  rlevel = (((rlevel * levels) >> 8) * 255) / levels1;
1262
1004
  glevel = (((glevel * levels) >> 8) * 255) / levels1;
1263
1005
  blevel = (((blevel * levels) >> 8) * 255) / levels1;
1264
- pixels[i] = ((0xff000000 & pixels[i])
1265
- | (rlevel << 16)
1266
- | (glevel << 8)
1267
- | blevel);
1006
+ pixels[i] = ((0xff000000 & pixels[i]) |
1007
+ (rlevel << 16) |
1008
+ (glevel << 8) |
1009
+ blevel);
1268
1010
  }
1269
1011
  break;
1270
1012
 
@@ -1272,76 +1014,72 @@ public class PImage implements PConstants, Cloneable {
1272
1014
  int thresh = (int) (param * 255);
1273
1015
  for (int i = 0; i < pixels.length; i++) {
1274
1016
  int max = Math.max((pixels[i] & RED_MASK) >> 16,
1275
- Math.max((pixels[i] & GREEN_MASK) >> 8,
1276
- (pixels[i] & BLUE_MASK)));
1277
- pixels[i] = (pixels[i] & ALPHA_MASK)
1278
- | ((max < thresh) ? 0x000000 : 0xffffff);
1017
+ Math.max((pixels[i] & GREEN_MASK) >> 8,
1018
+ (pixels[i] & BLUE_MASK)));
1019
+ pixels[i] = (pixels[i] & ALPHA_MASK) |
1020
+ ((max < thresh) ? 0x000000 : 0xffffff);
1279
1021
  }
1280
1022
  break;
1281
1023
 
1282
- // [toxi20050728] added new filters
1283
- case ERODE:
1284
- throw new RuntimeException("Use filter(ERODE) instead of "
1285
- + "filter(ERODE, param)");
1286
- case DILATE:
1287
- throw new RuntimeException("Use filter(DILATE) instead of "
1288
- + "filter(DILATE, param)");
1024
+ // [toxi20050728] added new filters
1025
+ case ERODE:
1026
+ throw new RuntimeException("Use filter(ERODE) instead of " +
1027
+ "filter(ERODE, param)");
1028
+ case DILATE:
1029
+ throw new RuntimeException("Use filter(DILATE) instead of " +
1030
+ "filter(DILATE, param)");
1289
1031
  }
1290
1032
  updatePixels(); // mark as modified
1291
1033
  }
1292
1034
 
1293
- /**
1294
- * Set the high bits of all pixels to opaque.
1295
- */
1035
+
1036
+ /** Set the high bits of all pixels to opaque. */
1296
1037
  protected void opaque() {
1297
1038
  for (int i = 0; i < pixels.length; i++) {
1298
1039
  pixels[i] = 0xFF000000 | pixels[i];
1299
1040
  }
1300
1041
  }
1301
1042
 
1043
+
1302
1044
  /**
1303
- * Optimized code for building the blur kernel. further optimized blur code
1304
- * (approx. 15% for radius=20) bigger speed gains for larger radii (~30%)
1305
- * added support for various image types (ALPHA, RGB, ARGB) [toxi 050728]
1306
- *
1307
- * @param r
1045
+ * Optimized code for building the blur kernel.
1046
+ * further optimized blur code (approx. 15% for radius=20)
1047
+ * bigger speed gains for larger radii (~30%)
1048
+ * added support for various image types (ALPHA, RGB, ARGB)
1049
+ * [toxi 050728]
1308
1050
  */
1309
1051
  protected void buildBlurKernel(float r) {
1310
1052
  int radius = (int) (r * 3.5f);
1311
- radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248);
1053
+ if (radius < 1) radius = 1;
1054
+ if (radius > 248) radius = 248;
1312
1055
  if (blurRadius != radius) {
1313
1056
  blurRadius = radius;
1314
- blurKernelSize = 1 + blurRadius << 1;
1057
+ blurKernelSize = 1 + blurRadius<<1;
1315
1058
  blurKernel = new int[blurKernelSize];
1316
1059
  blurMult = new int[blurKernelSize][256];
1317
1060
 
1318
- int bk, bki;
1319
- int[] bm, bmi;
1061
+ int bk,bki;
1062
+ int[] bm,bmi;
1320
1063
 
1321
1064
  for (int i = 1, radiusi = radius - 1; i < radius; i++) {
1322
- blurKernel[radius + i] = blurKernel[radiusi] = bki = radiusi * radiusi;
1323
- bm = blurMult[radius + i];
1324
- bmi = blurMult[radiusi--];
1325
- for (int j = 0; j < 256; j++) {
1326
- bm[j] = bmi[j] = bki * j;
1327
- }
1065
+ blurKernel[radius+i] = blurKernel[radiusi] = bki = radiusi * radiusi;
1066
+ bm=blurMult[radius+i];
1067
+ bmi=blurMult[radiusi--];
1068
+ for (int j = 0; j < 256; j++)
1069
+ bm[j] = bmi[j] = bki*j;
1328
1070
  }
1329
1071
  bk = blurKernel[radius] = radius * radius;
1330
1072
  bm = blurMult[radius];
1331
- for (int j = 0; j < 256; j++) {
1332
- bm[j] = bk * j;
1333
- }
1073
+ for (int j = 0; j < 256; j++)
1074
+ bm[j] = bk*j;
1334
1075
  }
1335
1076
  }
1336
1077
 
1337
- /**
1338
- *
1339
- * @param r
1340
- */
1078
+
1341
1079
  protected void blurAlpha(float r) {
1342
1080
  int sum, cb;
1343
1081
  int read, ri, ym, ymi, bk0;
1344
- int b2[] = new int[pixels.length];
1082
+ int[] b2 = new int[pixels.length];
1345
1083
  int yi = 0;
1346
1084
 
1347
1085
  buildBlurKernel(r);
@@ -1351,19 +1089,17 @@ public class PImage implements PConstants, Cloneable {
1351
1089
  //cb = cg = cr = sum = 0;
1352
1090
  cb = sum = 0;
1353
1091
  read = x - blurRadius;
1354
- if (read < 0) {
1355
- bk0 = -read;
1356
- read = 0;
1092
+ if (read<0) {
1093
+ bk0=-read;
1094
+ read=0;
1357
1095
  } else {
1358
- if (read >= pixelWidth) {
1096
+ if (read >= pixelWidth)
1359
1097
  break;
1360
- }
1361
- bk0 = 0;
1098
+ bk0=0;
1362
1099
  }
1363
1100
  for (int i = bk0; i < blurKernelSize; i++) {
1364
- if (read >= pixelWidth) {
1101
+ if (read >= pixelWidth)
1365
1102
  break;
1366
- }
1367
1103
  int c = pixels[read + yi];
1368
1104
  int[] bm = blurMult[i];
1369
1105
  cb += bm[c & BLUE_MASK];
@@ -1387,24 +1123,22 @@ public class PImage implements PConstants, Cloneable {
1387
1123
  bk0 = ri = -ym;
1388
1124
  read = x;
1389
1125
  } else {
1390
- if (ym >= pixelHeight) {
1126
+ if (ym >= pixelHeight)
1391
1127
  break;
1392
- }
1393
1128
  bk0 = 0;
1394
1129
  ri = ym;
1395
1130
  read = x + ymi;
1396
1131
  }
1397
1132
  for (int i = bk0; i < blurKernelSize; i++) {
1398
- if (ri >= pixelHeight) {
1133
+ if (ri >= pixelHeight)
1399
1134
  break;
1400
- }
1401
1135
  int[] bm = blurMult[i];
1402
1136
  cb += bm[b2[read]];
1403
1137
  sum += blurKernel[i];
1404
1138
  ri++;
1405
1139
  read += pixelWidth;
1406
1140
  }
1407
- pixels[x + yi] = (cb / sum);
1141
+ pixels[x+yi] = (cb/sum);
1408
1142
  }
1409
1143
  yi += pixelWidth;
1410
1144
  ymi += pixelWidth;
@@ -1412,16 +1146,13 @@ public class PImage implements PConstants, Cloneable {
1412
1146
  }
1413
1147
  }
1414
1148
 
1415
- /**
1416
- *
1417
- * @param r
1418
- */
1149
+
1419
1150
  protected void blurRGB(float r) {
1420
- int sum, cr, cg, cb; //, k;
1421
- int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
1422
- int r2[] = new int[pixels.length];
1423
- int g2[] = new int[pixels.length];
1424
- int b2[] = new int[pixels.length];
1151
+ int sum, cr, cg, cb;
1152
+ int read, ri, ym, ymi, bk0;
1153
+ int[] r2 = new int[pixels.length];
1154
+ int[] g2 = new int[pixels.length];
1155
+ int[] b2 = new int[pixels.length];
1425
1156
  int yi = 0;
1426
1157
 
1427
1158
  buildBlurKernel(r);
@@ -1489,7 +1220,7 @@ public class PImage implements PConstants, Cloneable {
1489
1220
  ri++;
1490
1221
  read += pixelWidth;
1491
1222
  }
1492
- pixels[x + yi] = 0xff000000 | (cr / sum) << 16 | (cg / sum) << 8 | (cb / sum);
1223
+ pixels[x+yi] = 0xff000000 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum);
1493
1224
  }
1494
1225
  yi += pixelWidth;
1495
1226
  ymi += pixelWidth;
@@ -1497,18 +1228,15 @@ public class PImage implements PConstants, Cloneable {
1497
1228
  }
1498
1229
  }
1499
1230
 
1500
- /**
1501
- *
1502
- * @param r
1503
- */
1231
+
1504
1232
  protected void blurARGB(float r) {
1505
1233
  int sum, cr, cg, cb, ca;
1506
1234
  int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
1507
1235
  int wh = pixels.length;
1508
- int r2[] = new int[wh];
1509
- int g2[] = new int[wh];
1510
- int b2[] = new int[wh];
1511
- int a2[] = new int[wh];
1236
+ int[] r2 = new int[wh];
1237
+ int[] g2 = new int[wh];
1238
+ int[] b2 = new int[wh];
1239
+ int[] a2 = new int[wh];
1512
1240
  int yi = 0;
1513
1241
 
1514
1242
  buildBlurKernel(r);
@@ -1524,14 +1252,14 @@ public class PImage implements PConstants, Cloneable {
1524
1252
  if (read >= pixelWidth) {
1525
1253
  break;
1526
1254
  }
1527
- bk0 = 0;
1255
+ bk0=0;
1528
1256
  }
1529
1257
  for (int i = bk0; i < blurKernelSize; i++) {
1530
1258
  if (read >= pixelWidth) {
1531
1259
  break;
1532
1260
  }
1533
1261
  int c = pixels[read + yi];
1534
- int[] bm = blurMult[i];
1262
+ int[] bm=blurMult[i];
1535
1263
  ca += bm[(c & ALPHA_MASK) >>> 24];
1536
1264
  cr += bm[(c & RED_MASK) >> 16];
1537
1265
  cg += bm[(c & GREEN_MASK) >> 8];
@@ -1570,7 +1298,7 @@ public class PImage implements PConstants, Cloneable {
1570
1298
  if (ri >= pixelHeight) {
1571
1299
  break;
1572
1300
  }
1573
- int[] bm = blurMult[i];
1301
+ int[] bm=blurMult[i];
1574
1302
  ca += bm[a2[read]];
1575
1303
  cr += bm[r2[read]];
1576
1304
  cg += bm[g2[read]];
@@ -1579,7 +1307,7 @@ public class PImage implements PConstants, Cloneable {
1579
1307
  ri++;
1580
1308
  read += pixelWidth;
1581
1309
  }
1582
- pixels[x + yi] = (ca / sum) << 24 | (cr / sum) << 16 | (cg / sum) << 8 | (cb / sum);
1310
+ pixels[x+yi] = (ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum);
1583
1311
  }
1584
1312
  yi += pixelWidth;
1585
1313
  ymi += pixelWidth;
@@ -1587,9 +1315,10 @@ public class PImage implements PConstants, Cloneable {
1587
1315
  }
1588
1316
  }
1589
1317
 
1318
+
1590
1319
  /**
1591
- * Generic dilate/erode filter using luminance values as decision factor.
1592
- * [toxi 050728]
1320
+ * Generic dilate/erode filter using luminance values
1321
+ * as decision factor. [toxi 050728]
1593
1322
  */
1594
1323
  protected void dilate() { // formerly dilate(false)
1595
1324
  int index = 0;
@@ -1626,16 +1355,16 @@ public class PImage implements PConstants, Cloneable {
1626
1355
  int colRight = pixels[idxRight];
1627
1356
 
1628
1357
  // compute luminance
1629
- int currLum
1630
- = 77 * (orig >> 16 & 0xff) + 151 * (orig >> 8 & 0xff) + 28 * (orig & 0xff);
1631
- int lumLeft
1632
- = 77 * (colLeft >> 16 & 0xff) + 151 * (colLeft >> 8 & 0xff) + 28 * (colLeft & 0xff);
1633
- int lumRight
1634
- = 77 * (colRight >> 16 & 0xff) + 151 * (colRight >> 8 & 0xff) + 28 * (colRight & 0xff);
1635
- int lumUp
1636
- = 77 * (colUp >> 16 & 0xff) + 151 * (colUp >> 8 & 0xff) + 28 * (colUp & 0xff);
1637
- int lumDown
1638
- = 77 * (colDown >> 16 & 0xff) + 151 * (colDown >> 8 & 0xff) + 28 * (colDown & 0xff);
1358
+ int currLum =
1359
+ 77*(orig>>16&0xff) + 151*(orig>>8&0xff) + 28*(orig&0xff);
1360
+ int lumLeft =
1361
+ 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff);
1362
+ int lumRight =
1363
+ 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff);
1364
+ int lumUp =
1365
+ 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff);
1366
+ int lumDown =
1367
+ 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff);
1639
1368
 
1640
1369
  if (lumLeft > currLum) {
1641
1370
  result = colLeft;
@@ -1651,7 +1380,7 @@ public class PImage implements PConstants, Cloneable {
1651
1380
  }
1652
1381
  if (lumDown > currLum) {
1653
1382
  result = colDown;
1654
- currLum = lumDown;
1383
+ // currLum = lumDown; // removed, unused assignment
1655
1384
  }
1656
1385
  outgoing[index++] = result;
1657
1386
  }
@@ -1659,9 +1388,7 @@ public class PImage implements PConstants, Cloneable {
1659
1388
  System.arraycopy(outgoing, 0, pixels, 0, maxIndex);
1660
1389
  }
1661
1390
 
1662
- /**
1663
- *
1664
- */
1391
+
1665
1392
  protected void erode() { // formerly dilate(true)
1666
1393
  int index = 0;
1667
1394
  int maxIndex = pixels.length;
@@ -1697,16 +1424,16 @@ public class PImage implements PConstants, Cloneable {
1697
1424
  int colRight = pixels[idxRight];
1698
1425
 
1699
1426
  // compute luminance
1700
- int currLum
1701
- = 77 * (orig >> 16 & 0xff) + 151 * (orig >> 8 & 0xff) + 28 * (orig & 0xff);
1702
- int lumLeft
1703
- = 77 * (colLeft >> 16 & 0xff) + 151 * (colLeft >> 8 & 0xff) + 28 * (colLeft & 0xff);
1704
- int lumRight
1705
- = 77 * (colRight >> 16 & 0xff) + 151 * (colRight >> 8 & 0xff) + 28 * (colRight & 0xff);
1706
- int lumUp
1707
- = 77 * (colUp >> 16 & 0xff) + 151 * (colUp >> 8 & 0xff) + 28 * (colUp & 0xff);
1708
- int lumDown
1709
- = 77 * (colDown >> 16 & 0xff) + 151 * (colDown >> 8 & 0xff) + 28 * (colDown & 0xff);
1427
+ int currLum =
1428
+ 77*(orig>>16&0xff) + 151*(orig>>8&0xff) + 28*(orig&0xff);
1429
+ int lumLeft =
1430
+ 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff);
1431
+ int lumRight =
1432
+ 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff);
1433
+ int lumUp =
1434
+ 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff);
1435
+ int lumDown =
1436
+ 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff);
1710
1437
 
1711
1438
  if (lumLeft < currLum) {
1712
1439
  result = colLeft;
@@ -1722,7 +1449,7 @@ public class PImage implements PConstants, Cloneable {
1722
1449
  }
1723
1450
  if (lumDown < currLum) {
1724
1451
  result = colDown;
1725
- currLum = lumDown;
1452
+ // currLum = lumDown; // removed, unused assignment
1726
1453
  }
1727
1454
  outgoing[index++] = result;
1728
1455
  }
@@ -1730,23 +1457,26 @@ public class PImage implements PConstants, Cloneable {
1730
1457
  System.arraycopy(outgoing, 0, pixels, 0, maxIndex);
1731
1458
  }
1732
1459
 
1460
+
1461
+
1733
1462
  //////////////////////////////////////////////////////////////
1463
+
1734
1464
  // COPY
1465
+
1466
+
1735
1467
  /**
1736
- * ( begin auto-generated from PImage_copy.xml )
1737
1468
  *
1738
1469
  * Copies a region of pixels from one image into another. If the source and
1739
1470
  * destination regions aren't the same size, it will automatically resize
1740
- * source pixels to fit the specified target region. No alpha information is
1741
- * used in the process, however if the source image has an alpha channel set,
1742
- * it will be copied as well.
1743
- *
1471
+ * source pixels to fit the specified target region. No alpha information
1472
+ * is used in the process, however if the source image has an alpha channel
1473
+ * set, it will be copied as well.
1474
+ * <br /><br />
1744
1475
  * As of release 0149, this function ignores <b>imageMode()</b>.
1745
1476
  *
1746
- * ( end auto-generated )
1747
1477
  *
1748
1478
  * @webref image:pixels
1749
- * @brief Copies the entire image
1479
+ * @webBrief Copies the entire image
1750
1480
  * @usage web_application
1751
1481
  * @param sx X coordinate of the source's upper left corner
1752
1482
  * @param sy Y coordinate of the source's upper left corner
@@ -1760,58 +1490,58 @@ public class PImage implements PConstants, Cloneable {
1760
1490
  * @see PImage#blend(PImage, int, int, int, int, int, int, int, int, int)
1761
1491
  */
1762
1492
  public void copy(int sx, int sy, int sw, int sh,
1763
- int dx, int dy, int dw, int dh) {
1493
+ int dx, int dy, int dw, int dh) {
1764
1494
  blend(this, sx, sy, sw, sh, dx, dy, dw, dh, REPLACE);
1765
1495
  }
1766
1496
 
1767
- /**
1768
- * @param src an image variable referring to the source image.
1769
- * @param sx
1770
- * @param sy
1771
- * @param dh
1772
- * @param sw
1773
- * @param dx
1774
- * @param sh
1775
- * @param dy
1776
- * @param dw
1777
- */
1497
+
1498
+ /**
1499
+ * @param src an image variable referring to the source image.
1500
+ */
1778
1501
  public void copy(PImage src,
1779
- int sx, int sy, int sw, int sh,
1780
- int dx, int dy, int dw, int dh) {
1502
+ int sx, int sy, int sw, int sh,
1503
+ int dx, int dy, int dw, int dh) {
1781
1504
  blend(src, sx, sy, sw, sh, dx, dy, dw, dh, REPLACE);
1782
1505
  }
1783
1506
 
1507
+
1508
+
1784
1509
  //////////////////////////////////////////////////////////////
1510
+
1785
1511
  // BLEND
1512
+
1513
+
1786
1514
  /**
1787
- * ( begin auto-generated from blendColor.xml )
1788
1515
  *
1789
1516
  * Blends two color values together based on the blending mode given as the
1790
1517
  * <b>MODE</b> parameter. The possible modes are described in the reference
1791
1518
  * for the <b>blend()</b> function.
1792
1519
  *
1793
- * ( end auto-generated )
1794
1520
  * <h3>Advanced</h3>
1795
1521
  * <UL>
1796
1522
  * <LI>REPLACE - destination colour equals colour of source pixel: C = A.
1797
- * Sometimes called "Normal" or "Copy" in other software.
1523
+ * Sometimes called "Normal" or "Copy" in other software.
1798
1524
  *
1799
1525
  * <LI>BLEND - linear interpolation of colours:
1800
- * <TT>C = A*factor + B</TT>
1526
+ * <TT>C = A*factor + B</TT>
1801
1527
  *
1802
1528
  * <LI>ADD - additive blending with white clip:
1803
- * <TT>C = min(A*factor + B, 255)</TT>. Clipped to 0..255, Photoshop calls
1804
- * this "Linear Burn", and Director calls it "Add Pin".
1529
+ * <TT>C = min(A*factor + B, 255)</TT>.
1530
+ * Clipped to 0..255, Photoshop calls this "Linear Burn",
1531
+ * and Director calls it "Add Pin".
1805
1532
  *
1806
- * <LI>SUBTRACT - substractive blend with black clip:
1807
- * <TT>C = max(B - A*factor, 0)</TT>. Clipped to 0..255, Photoshop calls this
1808
- * "Linear Dodge", and Director calls it "Subtract Pin".
1533
+ * <LI>SUBTRACT - subtractive blend with black clip:
1534
+ * <TT>C = max(B - A*factor, 0)</TT>.
1535
+ * Clipped to 0..255, Photoshop calls this "Linear Dodge",
1536
+ * and Director calls it "Subtract Pin".
1809
1537
  *
1810
1538
  * <LI>DARKEST - only the darkest colour succeeds:
1811
- * <TT>C = min(A*factor, B)</TT>. Illustrator calls this "Darken".
1539
+ * <TT>C = min(A*factor, B)</TT>.
1540
+ * Illustrator calls this "Darken".
1812
1541
  *
1813
1542
  * <LI>LIGHTEST - only the lightest colour succeeds:
1814
- * <TT>C = max(A*factor, B)</TT>. Illustrator calls this "Lighten".
1543
+ * <TT>C = max(A*factor, B)</TT>.
1544
+ * Illustrator calls this "Lighten".
1815
1545
  *
1816
1546
  * <LI>DIFFERENCE - subtract colors from underlying image.
1817
1547
  *
@@ -1821,180 +1551,148 @@ public class PImage implements PConstants, Cloneable {
1821
1551
  *
1822
1552
  * <LI>SCREEN - Opposite multiply, uses inverse values of the colors.
1823
1553
  *
1824
- * <LI>OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and
1825
- * screens light values.
1554
+ * <LI>OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
1555
+ * and screens light values.
1826
1556
  *
1827
1557
  * <LI>HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
1828
1558
  *
1829
- * <LI>SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not
1830
- * as harsh.
1559
+ * <LI>SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
1560
+ * Works like OVERLAY, but not as harsh.
1831
1561
  *
1832
1562
  * <LI>DODGE - Lightens light tones and increases contrast, ignores darks.
1833
- * Called "Color Dodge" in Illustrator and Photoshop.
1563
+ * Called "Color Dodge" in Illustrator and Photoshop.
1834
1564
  *
1835
1565
  * <LI>BURN - Darker areas are applied, increasing contrast, ignores lights.
1836
- * Called "Color Burn" in Illustrator and Photoshop.
1566
+ * Called "Color Burn" in Illustrator and Photoshop.
1837
1567
  * </UL>
1838
- * <P>
1839
- * A useful reference for blending modes and their algorithms can be found in
1840
- * the <A HREF="http://www.w3.org/TR/SVG12/rendering.html">SVG</A>
1568
+ * <P>A useful reference for blending modes and their algorithms can be
1569
+ * found in the <A HREF="http://www.w3.org/TR/SVG12/rendering.html">SVG</A>
1841
1570
  * specification.</P>
1842
- * <P>
1843
- * It is important to note that Processing uses "fast" code, not necessarily
1844
- * "correct" code. No biggie, most software does. A nitpicker can find
1845
- * numerous "off by 1 division" problems in the blend code where
1571
+ * <P>It is important to note that Processing uses "fast" code, not
1572
+ * necessarily "correct" code. No biggie, most software does. A nitpicker
1573
+ * can find numerous "off by 1 division" problems in the blend code where
1846
1574
  * <TT>&gt;&gt;8</TT> or <TT>&gt;&gt;7</TT> is used when strictly speaking
1847
1575
  * <TT>/255.0</T> or <TT>/127.0</TT> should have been used.</P>
1848
- * <P>
1849
- * For instance, exclusion (not intended for real-time use) reads
1576
+ * <P>For instance, exclusion (not intended for real-time use) reads
1850
1577
  * <TT>r1 + r2 - ((2 * r1 * r2) / 255)</TT> because <TT>255 == 1.0</TT>
1851
- * not <TT>256 == 1.0</TT>. In other words, <TT>(255*255)>>8</TT> is not the
1852
- * same as <TT>(255*255)/255</TT>. But for real-time use the shifts are
1853
- * preferrable, and the difference is insignificant for applications built
1854
- * with Processing.</P>
1578
+ * not <TT>256 == 1.0</TT>. In other words, <TT>(255*255)>>8</TT> is not
1579
+ * the same as <TT>(255*255)/255</TT>. But for real-time use the shifts
1580
+ * are preferable, and the difference is insignificant for applications
1581
+ * built with Processing.</P>
1855
1582
  *
1856
- * @return
1857
1583
  * @webref color:creating_reading
1584
+ * @webBrief Blends two color values together based on the blending mode given as the
1585
+ * <b>MODE</b> parameter.
1858
1586
  * @usage web_application
1859
1587
  * @param c1 the first color to blend
1860
1588
  * @param c2 the second color to blend
1861
- * @param mode either BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE,
1862
- * EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, or
1863
- * BURN
1589
+ * @param mode either BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, or BURN
1864
1590
  * @see PImage#blend(PImage, int, int, int, int, int, int, int, int, int)
1865
1591
  * @see PApplet#color(float, float, float, float)
1866
1592
  */
1867
1593
  static public int blendColor(int c1, int c2, int mode) { // ignore
1868
1594
  switch (mode) {
1869
- case REPLACE:
1870
- return c2;
1871
- case BLEND:
1872
- return blend_blend(c1, c2);
1595
+ case REPLACE: return c2;
1596
+ case BLEND: return blend_blend(c1, c2);
1873
1597
 
1874
- case ADD:
1875
- return blend_add_pin(c1, c2);
1876
- case SUBTRACT:
1877
- return blend_sub_pin(c1, c2);
1598
+ case ADD: return blend_add_pin(c1, c2);
1599
+ case SUBTRACT: return blend_sub_pin(c1, c2);
1878
1600
 
1879
- case LIGHTEST:
1880
- return blend_lightest(c1, c2);
1881
- case DARKEST:
1882
- return blend_darkest(c1, c2);
1601
+ case LIGHTEST: return blend_lightest(c1, c2);
1602
+ case DARKEST: return blend_darkest(c1, c2);
1883
1603
 
1884
- case DIFFERENCE:
1885
- return blend_difference(c1, c2);
1886
- case EXCLUSION:
1887
- return blend_exclusion(c1, c2);
1604
+ case DIFFERENCE: return blend_difference(c1, c2);
1605
+ case EXCLUSION: return blend_exclusion(c1, c2);
1888
1606
 
1889
- case MULTIPLY:
1890
- return blend_multiply(c1, c2);
1891
- case SCREEN:
1892
- return blend_screen(c1, c2);
1607
+ case MULTIPLY: return blend_multiply(c1, c2);
1608
+ case SCREEN: return blend_screen(c1, c2);
1893
1609
 
1894
- case HARD_LIGHT:
1895
- return blend_hard_light(c1, c2);
1896
- case SOFT_LIGHT:
1897
- return blend_soft_light(c1, c2);
1898
- case OVERLAY:
1899
- return blend_overlay(c1, c2);
1610
+ case HARD_LIGHT: return blend_hard_light(c1, c2);
1611
+ case SOFT_LIGHT: return blend_soft_light(c1, c2);
1612
+ case OVERLAY: return blend_overlay(c1, c2);
1900
1613
 
1901
- case DODGE:
1902
- return blend_dodge(c1, c2);
1903
- case BURN:
1904
- return blend_burn(c1, c2);
1614
+ case DODGE: return blend_dodge(c1, c2);
1615
+ case BURN: return blend_burn(c1, c2);
1905
1616
  }
1906
1617
  return 0;
1907
1618
  }
1908
1619
 
1909
- /**
1910
- *
1911
- * @param sx
1912
- * @param sy
1913
- * @param sw
1914
- * @param sh
1915
- * @param dx
1916
- * @param dy
1917
- * @param dw
1918
- * @param dh
1919
- * @param mode
1920
- */
1620
+
1921
1621
  public void blend(int sx, int sy, int sw, int sh,
1922
- int dx, int dy, int dw, int dh, int mode) {
1622
+ int dx, int dy, int dw, int dh, int mode) {
1923
1623
  blend(this, sx, sy, sw, sh, dx, dy, dw, dh, mode);
1924
1624
  }
1925
1625
 
1626
+
1926
1627
  /**
1927
- * ( begin auto-generated from PImage_blend.xml )
1928
1628
  *
1929
1629
  * Blends a region of pixels into the image specified by the <b>img</b>
1930
- * parameter. These copies utilize full alpha channel support and a choice of
1931
- * the following modes to blend the colors of source pixels (A) with the ones
1932
- * of pixels in the destination image (B):
1933
- *
1934
- * BLEND - linear interpolation of colours: C = A*factor + B
1935
- *
1936
- * ADD - additive blending with white clip: C = min(A*factor + B, 255)
1937
- *
1630
+ * parameter. These copies utilize full alpha channel support and a choice
1631
+ * of the following modes to blend the colors of source pixels (A) with the
1632
+ * ones of pixels in the destination image (B):<br />
1633
+ * <br />
1634
+ * BLEND - linear interpolation of colours: C = A*factor + B<br />
1635
+ * <br />
1636
+ * ADD - additive blending with white clip: C = min(A*factor + B, 255)<br />
1637
+ * <br />
1938
1638
  * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor,
1939
- * 0)
1940
- *
1941
- * DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
1942
- *
1943
- * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
1944
- *
1945
- * DIFFERENCE - subtract colors from underlying image.
1946
- *
1947
- * EXCLUSION - similar to DIFFERENCE, but less extreme.
1948
- *
1949
- * MULTIPLY - Multiply the colors, result will always be darker.
1950
- *
1951
- * SCREEN - Opposite multiply, uses inverse values of the colors.
1952
- *
1953
- * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens
1954
- * light values.
1955
- *
1956
- * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
1957
- *
1958
- * SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as
1959
- * harsh.
1960
- *
1961
- * DODGE - Lightens light tones and increases contrast, ignores darks. Called
1962
- * "Color Dodge" in Illustrator and Photoshop.
1963
- *
1639
+ * 0)<br />
1640
+ * <br />
1641
+ * DARKEST - only the darkest colour succeeds: C = min(A*factor, B)<br />
1642
+ * <br />
1643
+ * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)<br />
1644
+ * <br />
1645
+ * DIFFERENCE - subtract colors from underlying image.<br />
1646
+ * <br />
1647
+ * EXCLUSION - similar to DIFFERENCE, but less extreme.<br />
1648
+ * <br />
1649
+ * MULTIPLY - Multiply the colors, result will always be darker.<br />
1650
+ * <br />
1651
+ * SCREEN - Opposite multiply, uses inverse values of the colors.<br />
1652
+ * <br />
1653
+ * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
1654
+ * and screens light values.<br />
1655
+ * <br />
1656
+ * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.<br />
1657
+ * <br />
1658
+ * SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
1659
+ * Works like OVERLAY, but not as harsh.<br />
1660
+ * <br />
1661
+ * DODGE - Lightens light tones and increases contrast, ignores darks.
1662
+ * Called "Color Dodge" in Illustrator and Photoshop.<br />
1663
+ * <br />
1964
1664
  * BURN - Darker areas are applied, increasing contrast, ignores lights.
1965
- * Called "Color Burn" in Illustrator and Photoshop.
1966
- *
1967
- * All modes use the alpha information (highest byte) of source image pixels
1968
- * as the blending factor. If the source and destination regions are different
1969
- * sizes, the image will be automatically resized to match the destination
1970
- * size. If the <b>srcImg</b> parameter is not used, the display window is
1971
- * used as the source image.
1972
- *
1665
+ * Called "Color Burn" in Illustrator and Photoshop.<br />
1666
+ * <br />
1667
+ * All modes use the alpha information (highest byte) of source image
1668
+ * pixels as the blending factor. If the source and destination regions are
1669
+ * different sizes, the image will be automatically resized to match the
1670
+ * destination size. If the <b>srcImg</b> parameter is not used, the
1671
+ * display window is used as the source image.<br />
1672
+ * <br />
1973
1673
  * As of release 0149, this function ignores <b>imageMode()</b>.
1974
1674
  *
1975
- * ( end auto-generated )
1976
1675
  *
1977
1676
  * @webref image:pixels
1978
- * @brief Copies a pixel or rectangle of pixels using different blending modes
1677
+ * @webBrief Copies a pixel or rectangle of pixels using different blending modes.
1979
1678
  * @param src an image variable referring to the source image
1980
1679
  * @param sx X coordinate of the source's upper left corner
1981
1680
  * @param sy Y coordinate of the source's upper left corner
1982
1681
  * @param sw source image width
1983
1682
  * @param sh source image height
1984
- * @param dx X coordinate of the destinations's upper left corner
1985
- * @param dy Y coordinate of the destinations's upper left corner
1683
+ * @param dx X coordinate of the destination's upper left corner
1684
+ * @param dy Y coordinate of the destination's upper left corner
1986
1685
  * @param dw destination image width
1987
1686
  * @param dh destination image height
1988
- * @param mode Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE,
1989
- * EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
1687
+ * @param mode Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
1990
1688
  *
1991
1689
  * @see PApplet#alpha(int)
1992
1690
  * @see PImage#copy(PImage, int, int, int, int, int, int, int, int)
1993
1691
  * @see PImage#blendColor(int,int,int)
1994
1692
  */
1995
1693
  public void blend(PImage src,
1996
- int sx, int sy, int sw, int sh,
1997
- int dx, int dy, int dw, int dh, int mode) {
1694
+ int sx, int sy, int sw, int sh,
1695
+ int dx, int dy, int dw, int dh, int mode) {
1998
1696
  int sx2 = sx + sw;
1999
1697
  int sy2 = sy + sh;
2000
1698
  int dx2 = dx + dw;
@@ -2003,28 +1701,29 @@ public class PImage implements PConstants, Cloneable {
2003
1701
  loadPixels();
2004
1702
  if (src == this) {
2005
1703
  if (intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) {
2006
- blit_resize(get(sx, sy, sw, sh),
2007
- 0, 0, sw, sh,
2008
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1704
+ blitResize(get(sx, sy, sw, sh),
1705
+ 0, 0, sw, sh,
1706
+ pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode, true);
2009
1707
  } else {
2010
1708
  // same as below, except skip the loadPixels() because it'd be redundant
2011
- blit_resize(src, sx, sy, sx2, sy2,
2012
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1709
+ blitResize(src, sx, sy, sx2, sy2,
1710
+ pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode, true);
2013
1711
  }
2014
1712
  } else {
2015
1713
  src.loadPixels();
2016
- blit_resize(src, sx, sy, sx2, sy2,
2017
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1714
+ blitResize(src, sx, sy, sx2, sy2,
1715
+ pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode, true);
2018
1716
  //src.updatePixels();
2019
1717
  }
2020
1718
  updatePixels();
2021
1719
  }
2022
1720
 
1721
+
2023
1722
  /**
2024
1723
  * Check to see if two rectangles intersect one another
2025
1724
  */
2026
1725
  private boolean intersect(int sx1, int sy1, int sx2, int sy2,
2027
- int dx1, int dy1, int dx2, int dy2) {
1726
+ int dx1, int dy1, int dx2, int dy2) {
2028
1727
  int sw = sx2 - sx1 + 1;
2029
1728
  int sh = sy2 - sy1 + 1;
2030
1729
  int dw = dx2 - dx1 + 1;
@@ -2055,46 +1754,39 @@ public class PImage implements PConstants, Cloneable {
2055
1754
  return !(dw <= 0 || dh <= 0);
2056
1755
  }
2057
1756
 
1757
+
2058
1758
  //////////////////////////////////////////////////////////////
1759
+
1760
+
2059
1761
  /**
2060
- * Internal blitter/resizer/copier from toxi. Uses bilinear filtering if
2061
- * smooth() has been enabled 'mode' determines the blending mode used in the
2062
- * process.
1762
+ * Internal blitter/resizer/copier from toxi.
1763
+ * Uses bilinear filtering if smooth() has been enabled
1764
+ * 'mode' determines the blending mode used in the process.
2063
1765
  */
2064
- private void blit_resize(PImage img,
2065
- int srcX1, int srcY1, int srcX2, int srcY2,
2066
- int[] destPixels, int screenW, int screenH,
2067
- int destX1, int destY1, int destX2, int destY2,
2068
- int mode) {
2069
- if (srcX1 < 0) {
2070
- srcX1 = 0;
2071
- }
2072
- if (srcY1 < 0) {
2073
- srcY1 = 0;
2074
- }
2075
- if (srcX2 > img.pixelWidth) {
2076
- srcX2 = img.pixelWidth;
2077
- }
2078
- if (srcY2 > img.pixelHeight) {
2079
- srcY2 = img.pixelHeight;
2080
- }
1766
+ private void blitResize(PImage img,
1767
+ int srcX1, int srcY1, int srcX2, int srcY2,
1768
+ int[] destPixels, int screenW, int screenH,
1769
+ int destX1, int destY1, int destX2, int destY2,
1770
+ int mode, boolean smooth) {
1771
+ if (srcX1 < 0) srcX1 = 0;
1772
+ if (srcY1 < 0) srcY1 = 0;
1773
+ if (srcX2 > img.pixelWidth) srcX2 = img.pixelWidth;
1774
+ if (srcY2 > img.pixelHeight) srcY2 = img.pixelHeight;
2081
1775
 
2082
1776
  int srcW = srcX2 - srcX1;
2083
1777
  int srcH = srcY2 - srcY1;
2084
1778
  int destW = destX2 - destX1;
2085
1779
  int destH = destY2 - destY1;
2086
1780
 
2087
- boolean smooth = true; // may as well go with the smoothing these days
2088
-
2089
1781
  if (!smooth) {
2090
1782
  srcW++;
2091
1783
  srcH++;
2092
1784
  }
2093
1785
 
2094
- if (destW <= 0 || destH <= 0
2095
- || srcW <= 0 || srcH <= 0
2096
- || destX1 >= screenW || destY1 >= screenH
2097
- || srcX1 >= img.pixelWidth || srcY1 >= img.pixelHeight) {
1786
+ if (destW <= 0 || destH <= 0 ||
1787
+ srcW <= 0 || srcH <= 0 ||
1788
+ destX1 >= screenW || destY1 >= screenH ||
1789
+ srcX1 >= img.pixelWidth || srcY1 >= img.pixelHeight) {
2098
1790
  return;
2099
1791
  }
2100
1792
 
@@ -2120,461 +1812,482 @@ public class PImage implements PConstants, Cloneable {
2120
1812
  srcBuffer = img.pixels;
2121
1813
 
2122
1814
  if (smooth) {
2123
- // use bilinear filtering
2124
- iw = img.pixelWidth;
2125
- iw1 = img.pixelWidth - 1;
2126
- ih1 = img.pixelHeight - 1;
2127
-
2128
- switch (mode) {
2129
-
2130
- case BLEND:
2131
- for (int y = 0; y < destH; y++) {
2132
- filter_new_scanline();
2133
- for (int x = 0; x < destW; x++) {
2134
- // davbol - renamed old blend_multiply to blend_blend
2135
- destPixels[destOffset + x]
2136
- = blend_blend(destPixels[destOffset + x], filter_bilinear());
2137
- sX += dx;
2138
- }
2139
- destOffset += screenW;
2140
- srcYOffset += dy;
2141
- }
2142
- break;
2143
-
2144
- case ADD:
2145
- for (int y = 0; y < destH; y++) {
2146
- filter_new_scanline();
2147
- for (int x = 0; x < destW; x++) {
2148
- destPixels[destOffset + x]
2149
- = blend_add_pin(destPixels[destOffset + x], filter_bilinear());
2150
- sX += dx;
2151
- }
2152
- destOffset += screenW;
2153
- srcYOffset += dy;
2154
- }
2155
- break;
2156
-
2157
- case SUBTRACT:
2158
- for (int y = 0; y < destH; y++) {
2159
- filter_new_scanline();
2160
- for (int x = 0; x < destW; x++) {
2161
- destPixels[destOffset + x]
2162
- = blend_sub_pin(destPixels[destOffset + x], filter_bilinear());
2163
- sX += dx;
2164
- }
2165
- destOffset += screenW;
2166
- srcYOffset += dy;
2167
- }
2168
- break;
2169
-
2170
- case LIGHTEST:
2171
- for (int y = 0; y < destH; y++) {
2172
- filter_new_scanline();
2173
- for (int x = 0; x < destW; x++) {
2174
- destPixels[destOffset + x]
2175
- = blend_lightest(destPixels[destOffset + x], filter_bilinear());
2176
- sX += dx;
2177
- }
2178
- destOffset += screenW;
2179
- srcYOffset += dy;
2180
- }
2181
- break;
2182
-
2183
- case DARKEST:
2184
- for (int y = 0; y < destH; y++) {
2185
- filter_new_scanline();
2186
- for (int x = 0; x < destW; x++) {
2187
- destPixels[destOffset + x]
2188
- = blend_darkest(destPixels[destOffset + x], filter_bilinear());
2189
- sX += dx;
2190
- }
2191
- destOffset += screenW;
2192
- srcYOffset += dy;
2193
- }
2194
- break;
2195
-
2196
- case REPLACE:
2197
- for (int y = 0; y < destH; y++) {
2198
- filter_new_scanline();
2199
- for (int x = 0; x < destW; x++) {
2200
- destPixels[destOffset + x] = filter_bilinear();
2201
- sX += dx;
2202
- }
2203
- destOffset += screenW;
2204
- srcYOffset += dy;
2205
- }
2206
- break;
2207
-
2208
- case DIFFERENCE:
2209
- for (int y = 0; y < destH; y++) {
2210
- filter_new_scanline();
2211
- for (int x = 0; x < destW; x++) {
2212
- destPixels[destOffset + x]
2213
- = blend_difference(destPixels[destOffset + x], filter_bilinear());
2214
- sX += dx;
2215
- }
2216
- destOffset += screenW;
2217
- srcYOffset += dy;
2218
- }
2219
- break;
2220
-
2221
- case EXCLUSION:
2222
- for (int y = 0; y < destH; y++) {
2223
- filter_new_scanline();
2224
- for (int x = 0; x < destW; x++) {
2225
- destPixels[destOffset + x]
2226
- = blend_exclusion(destPixels[destOffset + x], filter_bilinear());
2227
- sX += dx;
2228
- }
2229
- destOffset += screenW;
2230
- srcYOffset += dy;
2231
- }
2232
- break;
2233
-
2234
- case MULTIPLY:
2235
- for (int y = 0; y < destH; y++) {
2236
- filter_new_scanline();
2237
- for (int x = 0; x < destW; x++) {
2238
- destPixels[destOffset + x]
2239
- = blend_multiply(destPixels[destOffset + x], filter_bilinear());
2240
- sX += dx;
2241
- }
2242
- destOffset += screenW;
2243
- srcYOffset += dy;
2244
- }
2245
- break;
2246
-
2247
- case SCREEN:
2248
- for (int y = 0; y < destH; y++) {
2249
- filter_new_scanline();
2250
- for (int x = 0; x < destW; x++) {
2251
- destPixels[destOffset + x]
2252
- = blend_screen(destPixels[destOffset + x], filter_bilinear());
2253
- sX += dx;
2254
- }
2255
- destOffset += screenW;
2256
- srcYOffset += dy;
2257
- }
2258
- break;
2259
-
2260
- case OVERLAY:
2261
- for (int y = 0; y < destH; y++) {
2262
- filter_new_scanline();
2263
- for (int x = 0; x < destW; x++) {
2264
- destPixels[destOffset + x]
2265
- = blend_overlay(destPixels[destOffset + x], filter_bilinear());
2266
- sX += dx;
2267
- }
2268
- destOffset += screenW;
2269
- srcYOffset += dy;
2270
- }
2271
- break;
1815
+ blitResizeBilinear(img, destPixels, destOffset, screenW, destW, destH, dx, dy, mode);
1816
+ } else {
1817
+ blitResizeNearest(img, destPixels, destOffset, screenW, destW, destH, dx, dy, mode);
1818
+ }
1819
+ }
2272
1820
 
2273
- case HARD_LIGHT:
2274
- for (int y = 0; y < destH; y++) {
2275
- filter_new_scanline();
2276
- for (int x = 0; x < destW; x++) {
2277
- destPixels[destOffset + x]
2278
- = blend_hard_light(destPixels[destOffset + x], filter_bilinear());
2279
- sX += dx;
2280
- }
2281
- destOffset += screenW;
2282
- srcYOffset += dy;
2283
- }
2284
- break;
1821
+ private void blitResizeBilinear(PImage img,
1822
+ int[] destPixels, int destOffset, int screenW,
1823
+ int destW, int destH,
1824
+ int dx, int dy,
1825
+ int mode) {
1826
+ // use bilinear filtering
1827
+ iw = img.pixelWidth;
1828
+ iw1 = img.pixelWidth - 1;
1829
+ ih1 = img.pixelHeight - 1;
2285
1830
 
2286
- case SOFT_LIGHT:
2287
- for (int y = 0; y < destH; y++) {
2288
- filter_new_scanline();
2289
- for (int x = 0; x < destW; x++) {
2290
- destPixels[destOffset + x]
2291
- = blend_soft_light(destPixels[destOffset + x], filter_bilinear());
2292
- sX += dx;
2293
- }
2294
- destOffset += screenW;
2295
- srcYOffset += dy;
2296
- }
2297
- break;
1831
+ switch (mode) {
2298
1832
 
2299
- // davbol - proposed 2007-01-09
2300
- case DODGE:
2301
- for (int y = 0; y < destH; y++) {
2302
- filter_new_scanline();
2303
- for (int x = 0; x < destW; x++) {
2304
- destPixels[destOffset + x]
2305
- = blend_dodge(destPixels[destOffset + x], filter_bilinear());
2306
- sX += dx;
2307
- }
2308
- destOffset += screenW;
2309
- srcYOffset += dy;
1833
+ case BLEND:
1834
+ for (int y = 0; y < destH; y++) {
1835
+ filter_new_scanline();
1836
+ for (int x = 0; x < destW; x++) {
1837
+ // davbol - renamed old blend_multiply to blend_blend
1838
+ destPixels[destOffset + x] =
1839
+ blend_blend(destPixels[destOffset + x], filter_bilinear());
1840
+ sX += dx;
2310
1841
  }
2311
- break;
1842
+ destOffset += screenW;
1843
+ srcYOffset += dy;
1844
+ }
1845
+ break;
2312
1846
 
2313
- case BURN:
2314
- for (int y = 0; y < destH; y++) {
2315
- filter_new_scanline();
2316
- for (int x = 0; x < destW; x++) {
2317
- destPixels[destOffset + x]
2318
- = blend_burn(destPixels[destOffset + x], filter_bilinear());
2319
- sX += dx;
2320
- }
2321
- destOffset += screenW;
2322
- srcYOffset += dy;
1847
+ case ADD:
1848
+ for (int y = 0; y < destH; y++) {
1849
+ filter_new_scanline();
1850
+ for (int x = 0; x < destW; x++) {
1851
+ destPixels[destOffset + x] =
1852
+ blend_add_pin(destPixels[destOffset + x], filter_bilinear());
1853
+ sX += dx;
2323
1854
  }
2324
- break;
2325
-
2326
- }
1855
+ destOffset += screenW;
1856
+ srcYOffset += dy;
1857
+ }
1858
+ break;
2327
1859
 
2328
- } else {
2329
- // nearest neighbour scaling (++fast!)
2330
- switch (mode) {
2331
-
2332
- case BLEND:
2333
- for (int y = 0; y < destH; y++) {
2334
- sX = srcXOffset;
2335
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2336
- for (int x = 0; x < destW; x++) {
2337
- // davbol - renamed old blend_multiply to blend_blend
2338
- destPixels[destOffset + x]
2339
- = blend_blend(destPixels[destOffset + x],
2340
- srcBuffer[sY + (sX >> PRECISIONB)]);
2341
- sX += dx;
2342
- }
2343
- destOffset += screenW;
2344
- srcYOffset += dy;
1860
+ case SUBTRACT:
1861
+ for (int y = 0; y < destH; y++) {
1862
+ filter_new_scanline();
1863
+ for (int x = 0; x < destW; x++) {
1864
+ destPixels[destOffset + x] =
1865
+ blend_sub_pin(destPixels[destOffset + x], filter_bilinear());
1866
+ sX += dx;
2345
1867
  }
2346
- break;
1868
+ destOffset += screenW;
1869
+ srcYOffset += dy;
1870
+ }
1871
+ break;
2347
1872
 
2348
- case ADD:
2349
- for (int y = 0; y < destH; y++) {
2350
- sX = srcXOffset;
2351
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2352
- for (int x = 0; x < destW; x++) {
2353
- destPixels[destOffset + x]
2354
- = blend_add_pin(destPixels[destOffset + x],
2355
- srcBuffer[sY + (sX >> PRECISIONB)]);
2356
- sX += dx;
2357
- }
2358
- destOffset += screenW;
2359
- srcYOffset += dy;
1873
+ case LIGHTEST:
1874
+ for (int y = 0; y < destH; y++) {
1875
+ filter_new_scanline();
1876
+ for (int x = 0; x < destW; x++) {
1877
+ destPixels[destOffset + x] =
1878
+ blend_lightest(destPixels[destOffset + x], filter_bilinear());
1879
+ sX += dx;
2360
1880
  }
2361
- break;
1881
+ destOffset += screenW;
1882
+ srcYOffset += dy;
1883
+ }
1884
+ break;
2362
1885
 
2363
- case SUBTRACT:
2364
- for (int y = 0; y < destH; y++) {
2365
- sX = srcXOffset;
2366
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2367
- for (int x = 0; x < destW; x++) {
2368
- destPixels[destOffset + x]
2369
- = blend_sub_pin(destPixels[destOffset + x],
2370
- srcBuffer[sY + (sX >> PRECISIONB)]);
2371
- sX += dx;
2372
- }
2373
- destOffset += screenW;
2374
- srcYOffset += dy;
1886
+ case DARKEST:
1887
+ for (int y = 0; y < destH; y++) {
1888
+ filter_new_scanline();
1889
+ for (int x = 0; x < destW; x++) {
1890
+ destPixels[destOffset + x] =
1891
+ blend_darkest(destPixels[destOffset + x], filter_bilinear());
1892
+ sX += dx;
2375
1893
  }
2376
- break;
1894
+ destOffset += screenW;
1895
+ srcYOffset += dy;
1896
+ }
1897
+ break;
2377
1898
 
2378
- case LIGHTEST:
2379
- for (int y = 0; y < destH; y++) {
2380
- sX = srcXOffset;
2381
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2382
- for (int x = 0; x < destW; x++) {
2383
- destPixels[destOffset + x]
2384
- = blend_lightest(destPixels[destOffset + x],
2385
- srcBuffer[sY + (sX >> PRECISIONB)]);
2386
- sX += dx;
2387
- }
2388
- destOffset += screenW;
2389
- srcYOffset += dy;
1899
+ case REPLACE:
1900
+ for (int y = 0; y < destH; y++) {
1901
+ filter_new_scanline();
1902
+ for (int x = 0; x < destW; x++) {
1903
+ destPixels[destOffset + x] = filter_bilinear();
1904
+ sX += dx;
2390
1905
  }
2391
- break;
1906
+ destOffset += screenW;
1907
+ srcYOffset += dy;
1908
+ }
1909
+ break;
2392
1910
 
2393
- case DARKEST:
2394
- for (int y = 0; y < destH; y++) {
2395
- sX = srcXOffset;
2396
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2397
- for (int x = 0; x < destW; x++) {
2398
- destPixels[destOffset + x]
2399
- = blend_darkest(destPixels[destOffset + x],
2400
- srcBuffer[sY + (sX >> PRECISIONB)]);
2401
- sX += dx;
2402
- }
2403
- destOffset += screenW;
2404
- srcYOffset += dy;
1911
+ case DIFFERENCE:
1912
+ for (int y = 0; y < destH; y++) {
1913
+ filter_new_scanline();
1914
+ for (int x = 0; x < destW; x++) {
1915
+ destPixels[destOffset + x] =
1916
+ blend_difference(destPixels[destOffset + x], filter_bilinear());
1917
+ sX += dx;
2405
1918
  }
2406
- break;
1919
+ destOffset += screenW;
1920
+ srcYOffset += dy;
1921
+ }
1922
+ break;
2407
1923
 
2408
- case REPLACE:
2409
- for (int y = 0; y < destH; y++) {
2410
- sX = srcXOffset;
2411
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2412
- for (int x = 0; x < destW; x++) {
2413
- destPixels[destOffset + x] = srcBuffer[sY + (sX >> PRECISIONB)];
2414
- sX += dx;
2415
- }
2416
- destOffset += screenW;
2417
- srcYOffset += dy;
1924
+ case EXCLUSION:
1925
+ for (int y = 0; y < destH; y++) {
1926
+ filter_new_scanline();
1927
+ for (int x = 0; x < destW; x++) {
1928
+ destPixels[destOffset + x] =
1929
+ blend_exclusion(destPixels[destOffset + x], filter_bilinear());
1930
+ sX += dx;
2418
1931
  }
2419
- break;
1932
+ destOffset += screenW;
1933
+ srcYOffset += dy;
1934
+ }
1935
+ break;
2420
1936
 
2421
- case DIFFERENCE:
2422
- for (int y = 0; y < destH; y++) {
2423
- sX = srcXOffset;
2424
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2425
- for (int x = 0; x < destW; x++) {
2426
- destPixels[destOffset + x]
2427
- = blend_difference(destPixels[destOffset + x],
2428
- srcBuffer[sY + (sX >> PRECISIONB)]);
2429
- sX += dx;
2430
- }
2431
- destOffset += screenW;
2432
- srcYOffset += dy;
1937
+ case MULTIPLY:
1938
+ for (int y = 0; y < destH; y++) {
1939
+ filter_new_scanline();
1940
+ for (int x = 0; x < destW; x++) {
1941
+ destPixels[destOffset + x] =
1942
+ blend_multiply(destPixels[destOffset + x], filter_bilinear());
1943
+ sX += dx;
2433
1944
  }
2434
- break;
1945
+ destOffset += screenW;
1946
+ srcYOffset += dy;
1947
+ }
1948
+ break;
2435
1949
 
2436
- case EXCLUSION:
2437
- for (int y = 0; y < destH; y++) {
2438
- sX = srcXOffset;
2439
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2440
- for (int x = 0; x < destW; x++) {
2441
- destPixels[destOffset + x]
2442
- = blend_exclusion(destPixels[destOffset + x],
2443
- srcBuffer[sY + (sX >> PRECISIONB)]);
2444
- sX += dx;
2445
- }
2446
- destOffset += screenW;
2447
- srcYOffset += dy;
1950
+ case SCREEN:
1951
+ for (int y = 0; y < destH; y++) {
1952
+ filter_new_scanline();
1953
+ for (int x = 0; x < destW; x++) {
1954
+ destPixels[destOffset + x] =
1955
+ blend_screen(destPixels[destOffset + x], filter_bilinear());
1956
+ sX += dx;
2448
1957
  }
2449
- break;
1958
+ destOffset += screenW;
1959
+ srcYOffset += dy;
1960
+ }
1961
+ break;
2450
1962
 
2451
- case MULTIPLY:
2452
- for (int y = 0; y < destH; y++) {
2453
- sX = srcXOffset;
2454
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2455
- for (int x = 0; x < destW; x++) {
2456
- destPixels[destOffset + x]
2457
- = blend_multiply(destPixels[destOffset + x],
2458
- srcBuffer[sY + (sX >> PRECISIONB)]);
2459
- sX += dx;
2460
- }
2461
- destOffset += screenW;
2462
- srcYOffset += dy;
1963
+ case OVERLAY:
1964
+ for (int y = 0; y < destH; y++) {
1965
+ filter_new_scanline();
1966
+ for (int x = 0; x < destW; x++) {
1967
+ destPixels[destOffset + x] =
1968
+ blend_overlay(destPixels[destOffset + x], filter_bilinear());
1969
+ sX += dx;
2463
1970
  }
2464
- break;
1971
+ destOffset += screenW;
1972
+ srcYOffset += dy;
1973
+ }
1974
+ break;
2465
1975
 
2466
- case SCREEN:
2467
- for (int y = 0; y < destH; y++) {
2468
- sX = srcXOffset;
2469
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2470
- for (int x = 0; x < destW; x++) {
2471
- destPixels[destOffset + x]
2472
- = blend_screen(destPixels[destOffset + x],
2473
- srcBuffer[sY + (sX >> PRECISIONB)]);
2474
- sX += dx;
2475
- }
2476
- destOffset += screenW;
2477
- srcYOffset += dy;
1976
+ case HARD_LIGHT:
1977
+ for (int y = 0; y < destH; y++) {
1978
+ filter_new_scanline();
1979
+ for (int x = 0; x < destW; x++) {
1980
+ destPixels[destOffset + x] =
1981
+ blend_hard_light(destPixels[destOffset + x], filter_bilinear());
1982
+ sX += dx;
2478
1983
  }
2479
- break;
1984
+ destOffset += screenW;
1985
+ srcYOffset += dy;
1986
+ }
1987
+ break;
2480
1988
 
2481
- case OVERLAY:
2482
- for (int y = 0; y < destH; y++) {
2483
- sX = srcXOffset;
2484
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2485
- for (int x = 0; x < destW; x++) {
2486
- destPixels[destOffset + x]
2487
- = blend_overlay(destPixels[destOffset + x],
2488
- srcBuffer[sY + (sX >> PRECISIONB)]);
2489
- sX += dx;
2490
- }
2491
- destOffset += screenW;
2492
- srcYOffset += dy;
1989
+ case SOFT_LIGHT:
1990
+ for (int y = 0; y < destH; y++) {
1991
+ filter_new_scanline();
1992
+ for (int x = 0; x < destW; x++) {
1993
+ destPixels[destOffset + x] =
1994
+ blend_soft_light(destPixels[destOffset + x], filter_bilinear());
1995
+ sX += dx;
2493
1996
  }
2494
- break;
1997
+ destOffset += screenW;
1998
+ srcYOffset += dy;
1999
+ }
2000
+ break;
2495
2001
 
2496
- case HARD_LIGHT:
2497
- for (int y = 0; y < destH; y++) {
2498
- sX = srcXOffset;
2499
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2500
- for (int x = 0; x < destW; x++) {
2501
- destPixels[destOffset + x]
2502
- = blend_hard_light(destPixels[destOffset + x],
2503
- srcBuffer[sY + (sX >> PRECISIONB)]);
2504
- sX += dx;
2505
- }
2506
- destOffset += screenW;
2507
- srcYOffset += dy;
2002
+ // davbol - proposed 2007-01-09
2003
+ case DODGE:
2004
+ for (int y = 0; y < destH; y++) {
2005
+ filter_new_scanline();
2006
+ for (int x = 0; x < destW; x++) {
2007
+ destPixels[destOffset + x] =
2008
+ blend_dodge(destPixels[destOffset + x], filter_bilinear());
2009
+ sX += dx;
2508
2010
  }
2509
- break;
2011
+ destOffset += screenW;
2012
+ srcYOffset += dy;
2013
+ }
2014
+ break;
2510
2015
 
2511
- case SOFT_LIGHT:
2512
- for (int y = 0; y < destH; y++) {
2513
- sX = srcXOffset;
2514
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2515
- for (int x = 0; x < destW; x++) {
2516
- destPixels[destOffset + x]
2517
- = blend_soft_light(destPixels[destOffset + x],
2518
- srcBuffer[sY + (sX >> PRECISIONB)]);
2519
- sX += dx;
2520
- }
2521
- destOffset += screenW;
2522
- srcYOffset += dy;
2016
+ case BURN:
2017
+ for (int y = 0; y < destH; y++) {
2018
+ filter_new_scanline();
2019
+ for (int x = 0; x < destW; x++) {
2020
+ destPixels[destOffset + x] =
2021
+ blend_burn(destPixels[destOffset + x], filter_bilinear());
2022
+ sX += dx;
2523
2023
  }
2524
- break;
2024
+ destOffset += screenW;
2025
+ srcYOffset += dy;
2026
+ }
2027
+ break;
2525
2028
 
2526
- // davbol - proposed 2007-01-09
2527
- case DODGE:
2528
- for (int y = 0; y < destH; y++) {
2529
- sX = srcXOffset;
2530
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2531
- for (int x = 0; x < destW; x++) {
2532
- destPixels[destOffset + x]
2533
- = blend_dodge(destPixels[destOffset + x],
2534
- srcBuffer[sY + (sX >> PRECISIONB)]);
2535
- sX += dx;
2536
- }
2537
- destOffset += screenW;
2538
- srcYOffset += dy;
2539
- }
2540
- break;
2029
+ }
2030
+ }
2541
2031
 
2542
- case BURN:
2543
- for (int y = 0; y < destH; y++) {
2544
- sX = srcXOffset;
2545
- sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2546
- for (int x = 0; x < destW; x++) {
2547
- destPixels[destOffset + x]
2548
- = blend_burn(destPixels[destOffset + x],
2549
- srcBuffer[sY + (sX >> PRECISIONB)]);
2550
- sX += dx;
2551
- }
2552
- destOffset += screenW;
2553
- srcYOffset += dy;
2554
- }
2555
- break;
2032
+ private void blitResizeNearest(PImage img,
2033
+ int[] destPixels, int destOffset, int screenW,
2034
+ int destW, int destH,
2035
+ int dx, int dy,
2036
+ int mode) {
2037
+ // nearest neighbour scaling (++fast!)
2038
+ int sY;
2039
+ switch (mode) {
2556
2040
 
2041
+ case BLEND:
2042
+ for (int y = 0; y < destH; y++) {
2043
+ sX = srcXOffset;
2044
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2045
+ for (int x = 0; x < destW; x++) {
2046
+ // davbol - renamed old blend_multiply to blend_blend
2047
+ destPixels[destOffset + x] =
2048
+ blend_blend(destPixels[destOffset + x],
2049
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2050
+ sX += dx;
2051
+ }
2052
+ destOffset += screenW;
2053
+ srcYOffset += dy;
2054
+ }
2055
+ break;
2056
+
2057
+ case ADD:
2058
+ for (int y = 0; y < destH; y++) {
2059
+ sX = srcXOffset;
2060
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2061
+ for (int x = 0; x < destW; x++) {
2062
+ destPixels[destOffset + x] =
2063
+ blend_add_pin(destPixels[destOffset + x],
2064
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2065
+ sX += dx;
2066
+ }
2067
+ destOffset += screenW;
2068
+ srcYOffset += dy;
2069
+ }
2070
+ break;
2071
+
2072
+ case SUBTRACT:
2073
+ for (int y = 0; y < destH; y++) {
2074
+ sX = srcXOffset;
2075
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2076
+ for (int x = 0; x < destW; x++) {
2077
+ destPixels[destOffset + x] =
2078
+ blend_sub_pin(destPixels[destOffset + x],
2079
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2080
+ sX += dx;
2081
+ }
2082
+ destOffset += screenW;
2083
+ srcYOffset += dy;
2084
+ }
2085
+ break;
2086
+
2087
+ case LIGHTEST:
2088
+ for (int y = 0; y < destH; y++) {
2089
+ sX = srcXOffset;
2090
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2091
+ for (int x = 0; x < destW; x++) {
2092
+ destPixels[destOffset + x] =
2093
+ blend_lightest(destPixels[destOffset + x],
2094
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2095
+ sX += dx;
2096
+ }
2097
+ destOffset += screenW;
2098
+ srcYOffset += dy;
2099
+ }
2100
+ break;
2101
+
2102
+ case DARKEST:
2103
+ for (int y = 0; y < destH; y++) {
2104
+ sX = srcXOffset;
2105
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2106
+ for (int x = 0; x < destW; x++) {
2107
+ destPixels[destOffset + x] =
2108
+ blend_darkest(destPixels[destOffset + x],
2109
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2110
+ sX += dx;
2111
+ }
2112
+ destOffset += screenW;
2113
+ srcYOffset += dy;
2114
+ }
2115
+ break;
2116
+
2117
+ case REPLACE:
2118
+ for (int y = 0; y < destH; y++) {
2119
+ sX = srcXOffset;
2120
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2121
+ for (int x = 0; x < destW; x++) {
2122
+ destPixels[destOffset + x] = srcBuffer[sY + (sX >> PRECISIONB)];
2123
+ sX += dx;
2124
+ }
2125
+ destOffset += screenW;
2126
+ srcYOffset += dy;
2127
+ }
2128
+ break;
2129
+
2130
+ case DIFFERENCE:
2131
+ for (int y = 0; y < destH; y++) {
2132
+ sX = srcXOffset;
2133
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2134
+ for (int x = 0; x < destW; x++) {
2135
+ destPixels[destOffset + x] =
2136
+ blend_difference(destPixels[destOffset + x],
2137
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2138
+ sX += dx;
2139
+ }
2140
+ destOffset += screenW;
2141
+ srcYOffset += dy;
2142
+ }
2143
+ break;
2144
+
2145
+ case EXCLUSION:
2146
+ for (int y = 0; y < destH; y++) {
2147
+ sX = srcXOffset;
2148
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2149
+ for (int x = 0; x < destW; x++) {
2150
+ destPixels[destOffset + x] =
2151
+ blend_exclusion(destPixels[destOffset + x],
2152
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2153
+ sX += dx;
2154
+ }
2155
+ destOffset += screenW;
2156
+ srcYOffset += dy;
2157
+ }
2158
+ break;
2159
+
2160
+ case MULTIPLY:
2161
+ for (int y = 0; y < destH; y++) {
2162
+ sX = srcXOffset;
2163
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2164
+ for (int x = 0; x < destW; x++) {
2165
+ destPixels[destOffset + x] =
2166
+ blend_multiply(destPixels[destOffset + x],
2167
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2168
+ sX += dx;
2169
+ }
2170
+ destOffset += screenW;
2171
+ srcYOffset += dy;
2172
+ }
2173
+ break;
2174
+
2175
+ case SCREEN:
2176
+ for (int y = 0; y < destH; y++) {
2177
+ sX = srcXOffset;
2178
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2179
+ for (int x = 0; x < destW; x++) {
2180
+ destPixels[destOffset + x] =
2181
+ blend_screen(destPixels[destOffset + x],
2182
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2183
+ sX += dx;
2184
+ }
2185
+ destOffset += screenW;
2186
+ srcYOffset += dy;
2187
+ }
2188
+ break;
2189
+
2190
+ case OVERLAY:
2191
+ for (int y = 0; y < destH; y++) {
2192
+ sX = srcXOffset;
2193
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2194
+ for (int x = 0; x < destW; x++) {
2195
+ destPixels[destOffset + x] =
2196
+ blend_overlay(destPixels[destOffset + x],
2197
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2198
+ sX += dx;
2199
+ }
2200
+ destOffset += screenW;
2201
+ srcYOffset += dy;
2557
2202
  }
2203
+ break;
2204
+
2205
+ case HARD_LIGHT:
2206
+ for (int y = 0; y < destH; y++) {
2207
+ sX = srcXOffset;
2208
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2209
+ for (int x = 0; x < destW; x++) {
2210
+ destPixels[destOffset + x] =
2211
+ blend_hard_light(destPixels[destOffset + x],
2212
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2213
+ sX += dx;
2214
+ }
2215
+ destOffset += screenW;
2216
+ srcYOffset += dy;
2217
+ }
2218
+ break;
2219
+
2220
+ case SOFT_LIGHT:
2221
+ for (int y = 0; y < destH; y++) {
2222
+ sX = srcXOffset;
2223
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2224
+ for (int x = 0; x < destW; x++) {
2225
+ destPixels[destOffset + x] =
2226
+ blend_soft_light(destPixels[destOffset + x],
2227
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2228
+ sX += dx;
2229
+ }
2230
+ destOffset += screenW;
2231
+ srcYOffset += dy;
2232
+ }
2233
+ break;
2234
+
2235
+ // davbol - proposed 2007-01-09
2236
+ case DODGE:
2237
+ for (int y = 0; y < destH; y++) {
2238
+ sX = srcXOffset;
2239
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2240
+ for (int x = 0; x < destW; x++) {
2241
+ destPixels[destOffset + x] =
2242
+ blend_dodge(destPixels[destOffset + x],
2243
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2244
+ sX += dx;
2245
+ }
2246
+ destOffset += screenW;
2247
+ srcYOffset += dy;
2248
+ }
2249
+ break;
2250
+
2251
+ case BURN:
2252
+ for (int y = 0; y < destH; y++) {
2253
+ sX = srcXOffset;
2254
+ sY = (srcYOffset >> PRECISIONB) * img.pixelWidth;
2255
+ for (int x = 0; x < destW; x++) {
2256
+ destPixels[destOffset + x] =
2257
+ blend_burn(destPixels[destOffset + x],
2258
+ srcBuffer[sY + (sX >> PRECISIONB)]);
2259
+ sX += dx;
2260
+ }
2261
+ destOffset += screenW;
2262
+ srcYOffset += dy;
2263
+ }
2264
+ break;
2558
2265
  }
2559
2266
  }
2560
2267
 
2268
+
2561
2269
  private void filter_new_scanline() {
2562
2270
  sX = srcXOffset;
2563
- fracV = srcYOffset & PREC_MAXVAL;
2271
+ int fracV = srcYOffset & PREC_MAXVAL;
2564
2272
  ifV = PREC_MAXVAL - fracV + 1;
2565
2273
  v1 = (srcYOffset >> PRECISIONB) * iw;
2566
2274
  v2 = min((srcYOffset >> PRECISIONB) + 1, ih1) * iw;
2567
2275
  }
2568
2276
 
2277
+
2569
2278
  private int filter_bilinear() {
2570
- fracU = sX & PREC_MAXVAL;
2571
- ifU = PREC_MAXVAL - fracU + 1;
2572
- ul = (ifU * ifV) >> PRECISIONB;
2573
- ll = ifU - ul;
2574
- ur = ifV - ul;
2575
- lr = PREC_MAXVAL + 1 - ul - ll - ur;
2576
- u1 = (sX >> PRECISIONB);
2577
- u2 = min(u1 + 1, iw1);
2279
+ int cUL, cLL, cUR, cLR;
2280
+ int r, g, b, a;
2281
+
2282
+ // private fields
2283
+ int fracU = sX & PREC_MAXVAL;
2284
+ int ifU = PREC_MAXVAL - fracU + 1;
2285
+ int ul = (ifU * ifV) >> PRECISIONB;
2286
+ int ll = ifU - ul;
2287
+ int ur = ifV - ul;
2288
+ int lr = PREC_MAXVAL + 1 - ul - ll - ur;
2289
+ int u1 = (sX >> PRECISIONB);
2290
+ int u2 = min(u1 + 1, iw1);
2578
2291
 
2579
2292
  // get color values of the 4 neighbouring texels
2580
2293
  cUL = srcBuffer[v1 + u1];
@@ -2582,36 +2295,44 @@ public class PImage implements PConstants, Cloneable {
2582
2295
  cLL = srcBuffer[v2 + u1];
2583
2296
  cLR = srcBuffer[v2 + u2];
2584
2297
 
2585
- r = ((ul * ((cUL & RED_MASK) >> 16) + ll * ((cLL & RED_MASK) >> 16)
2586
- + ur * ((cUR & RED_MASK) >> 16) + lr * ((cLR & RED_MASK) >> 16))
2587
- << PREC_RED_SHIFT) & RED_MASK;
2298
+ r = ((ul*((cUL&RED_MASK)>>16) + ll*((cLL&RED_MASK)>>16) +
2299
+ ur*((cUR&RED_MASK)>>16) + lr*((cLR&RED_MASK)>>16))
2300
+ << PREC_RED_SHIFT) & RED_MASK;
2588
2301
 
2589
- g = ((ul * (cUL & GREEN_MASK) + ll * (cLL & GREEN_MASK)
2590
- + ur * (cUR & GREEN_MASK) + lr * (cLR & GREEN_MASK))
2591
- >>> PRECISIONB) & GREEN_MASK;
2302
+ g = ((ul*(cUL&GREEN_MASK) + ll*(cLL&GREEN_MASK) +
2303
+ ur*(cUR&GREEN_MASK) + lr*(cLR&GREEN_MASK))
2304
+ >>> PRECISIONB) & GREEN_MASK;
2592
2305
 
2593
- b = (ul * (cUL & BLUE_MASK) + ll * (cLL & BLUE_MASK)
2594
- + ur * (cUR & BLUE_MASK) + lr * (cLR & BLUE_MASK))
2595
- >>> PRECISIONB;
2306
+ b = (ul*(cUL&BLUE_MASK) + ll*(cLL&BLUE_MASK) +
2307
+ ur*(cUR&BLUE_MASK) + lr*(cLR&BLUE_MASK))
2308
+ >>> PRECISIONB;
2596
2309
 
2597
- a = ((ul * ((cUL & ALPHA_MASK) >>> 24) + ll * ((cLL & ALPHA_MASK) >>> 24)
2598
- + ur * ((cUR & ALPHA_MASK) >>> 24) + lr * ((cLR & ALPHA_MASK) >>> 24))
2599
- << PREC_ALPHA_SHIFT) & ALPHA_MASK;
2310
+ a = ((ul*((cUL&ALPHA_MASK)>>>24) + ll*((cLL&ALPHA_MASK)>>>24) +
2311
+ ur*((cUR&ALPHA_MASK)>>>24) + lr*((cLR&ALPHA_MASK)>>>24))
2312
+ << PREC_ALPHA_SHIFT) & ALPHA_MASK;
2600
2313
 
2601
2314
  return a | r | g | b;
2602
2315
  }
2603
2316
 
2317
+
2318
+
2604
2319
  //////////////////////////////////////////////////////////////
2320
+
2605
2321
  // internal blending methods
2322
+
2323
+
2606
2324
  private static int min(int a, int b) {
2607
2325
  return (a < b) ? a : b;
2608
2326
  }
2609
2327
 
2328
+
2610
2329
  private static int max(int a, int b) {
2611
2330
  return (a > b) ? a : b;
2612
2331
  }
2613
2332
 
2333
+
2614
2334
  /////////////////////////////////////////////////////////////
2335
+
2615
2336
  // BLEND MODE IMPLEMENTATIONS
2616
2337
 
2617
2338
  /*
@@ -2700,11 +2421,13 @@ int testFunction(int dst, int src) {
2700
2421
  *
2701
2422
  *
2702
2423
  */
2424
+
2703
2425
  private static final int RB_MASK = 0x00FF00FF;
2704
2426
  private static final int GN_MASK = 0x0000FF00;
2705
2427
 
2706
2428
  /**
2707
- * Blend O = S
2429
+ * Blend
2430
+ * O = S
2708
2431
  */
2709
2432
  private static int blend_blend(int dst, int src) {
2710
2433
  int a = src >>> 24;
@@ -2712,13 +2435,15 @@ int testFunction(int dst, int src) {
2712
2435
  int s_a = a + (a >= 0x7F ? 1 : 0);
2713
2436
  int d_a = 0x100 - s_a;
2714
2437
 
2715
- return min((dst >>> 24) + a, 0xFF) << 24
2716
- | ((dst & RB_MASK) * d_a + (src & RB_MASK) * s_a) >>> 8 & RB_MASK
2717
- | ((dst & GN_MASK) * d_a + (src & GN_MASK) * s_a) >>> 8 & GN_MASK;
2438
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2439
+ ((dst & RB_MASK) * d_a + (src & RB_MASK) * s_a) >>> 8 & RB_MASK |
2440
+ ((dst & GN_MASK) * d_a + (src & GN_MASK) * s_a) >>> 8 & GN_MASK;
2718
2441
  }
2719
2442
 
2443
+
2720
2444
  /**
2721
- * Add O = MIN(D + S, 1)
2445
+ * Add
2446
+ * O = MIN(D + S, 1)
2722
2447
  */
2723
2448
  private static int blend_add_pin(int dst, int src) {
2724
2449
  int a = src >>> 24;
@@ -2728,31 +2453,35 @@ int testFunction(int dst, int src) {
2728
2453
  int rb = (dst & RB_MASK) + ((src & RB_MASK) * s_a >>> 8 & RB_MASK);
2729
2454
  int gn = (dst & GN_MASK) + ((src & GN_MASK) * s_a >>> 8);
2730
2455
 
2731
- return min((dst >>> 24) + a, 0xFF) << 24
2732
- | min(rb & 0xFFFF0000, RED_MASK)
2733
- | min(gn & 0x00FFFF00, GREEN_MASK)
2734
- | min(rb & 0x0000FFFF, BLUE_MASK);
2456
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2457
+ min(rb & 0xFFFF0000, RED_MASK) |
2458
+ min(gn & 0x00FFFF00, GREEN_MASK) |
2459
+ min(rb & 0x0000FFFF, BLUE_MASK);
2735
2460
  }
2736
2461
 
2462
+
2737
2463
  /**
2738
- * Subtract O = MAX(0, D - S)
2464
+ * Subtract
2465
+ * O = MAX(0, D - S)
2739
2466
  */
2740
2467
  private static int blend_sub_pin(int dst, int src) {
2741
2468
  int a = src >>> 24;
2742
2469
 
2743
2470
  int s_a = a + (a >= 0x7F ? 1 : 0);
2744
2471
 
2745
- int rb = ((src & RB_MASK) * s_a >>> 8);
2472
+ int rb = ((src & RB_MASK) * s_a >>> 8);
2746
2473
  int gn = ((src & GREEN_MASK) * s_a >>> 8);
2747
2474
 
2748
- return min((dst >>> 24) + a, 0xFF) << 24
2749
- | max((dst & RED_MASK) - (rb & RED_MASK), 0)
2750
- | max((dst & GREEN_MASK) - (gn & GREEN_MASK), 0)
2751
- | max((dst & BLUE_MASK) - (rb & BLUE_MASK), 0);
2475
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2476
+ max((dst & RED_MASK) - (rb & RED_MASK), 0) |
2477
+ max((dst & GREEN_MASK) - (gn & GREEN_MASK), 0) |
2478
+ max((dst & BLUE_MASK) - (rb & BLUE_MASK), 0);
2752
2479
  }
2753
2480
 
2481
+
2754
2482
  /**
2755
- * Lightest O = MAX(D, S)
2483
+ * Lightest
2484
+ * O = MAX(D, S)
2756
2485
  */
2757
2486
  private static int blend_lightest(int dst, int src) {
2758
2487
  int a = src >>> 24;
@@ -2760,17 +2489,19 @@ int testFunction(int dst, int src) {
2760
2489
  int s_a = a + (a >= 0x7F ? 1 : 0);
2761
2490
  int d_a = 0x100 - s_a;
2762
2491
 
2763
- int rb = max(src & RED_MASK, dst & RED_MASK)
2764
- | max(src & BLUE_MASK, dst & BLUE_MASK);
2492
+ int rb = max(src & RED_MASK, dst & RED_MASK) |
2493
+ max(src & BLUE_MASK, dst & BLUE_MASK);
2765
2494
  int gn = max(src & GREEN_MASK, dst & GREEN_MASK);
2766
2495
 
2767
- return min((dst >>> 24) + a, 0xFF) << 24
2768
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
2769
- | ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2496
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2497
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2498
+ ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2770
2499
  }
2771
2500
 
2501
+
2772
2502
  /**
2773
- * Darkest O = MIN(D, S)
2503
+ * Darkest
2504
+ * O = MIN(D, S)
2774
2505
  */
2775
2506
  private static int blend_darkest(int dst, int src) {
2776
2507
  int a = src >>> 24;
@@ -2778,17 +2509,19 @@ int testFunction(int dst, int src) {
2778
2509
  int s_a = a + (a >= 0x7F ? 1 : 0);
2779
2510
  int d_a = 0x100 - s_a;
2780
2511
 
2781
- int rb = min(src & RED_MASK, dst & RED_MASK)
2782
- | min(src & BLUE_MASK, dst & BLUE_MASK);
2512
+ int rb = min(src & RED_MASK, dst & RED_MASK) |
2513
+ min(src & BLUE_MASK, dst & BLUE_MASK);
2783
2514
  int gn = min(src & GREEN_MASK, dst & GREEN_MASK);
2784
2515
 
2785
- return min((dst >>> 24) + a, 0xFF) << 24
2786
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
2787
- | ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2516
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2517
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2518
+ ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2788
2519
  }
2789
2520
 
2521
+
2790
2522
  /**
2791
- * Difference O = ABS(D - S)
2523
+ * Difference
2524
+ * O = ABS(D - S)
2792
2525
  */
2793
2526
  private static int blend_difference(int dst, int src) {
2794
2527
  int a = src >>> 24;
@@ -2796,21 +2529,24 @@ int testFunction(int dst, int src) {
2796
2529
  int s_a = a + (a >= 0x7F ? 1 : 0);
2797
2530
  int d_a = 0x100 - s_a;
2798
2531
 
2799
- int r = (dst & RED_MASK) - (src & RED_MASK);
2800
- int b = (dst & BLUE_MASK) - (src & BLUE_MASK);
2532
+ int r = (dst & RED_MASK) - (src & RED_MASK);
2533
+ int b = (dst & BLUE_MASK) - (src & BLUE_MASK);
2801
2534
  int g = (dst & GREEN_MASK) - (src & GREEN_MASK);
2802
2535
 
2803
- int rb = (r < 0 ? -r : r)
2804
- | (b < 0 ? -b : b);
2536
+ int rb = (r < 0 ? -r : r) |
2537
+ (b < 0 ? -b : b);
2805
2538
  int gn = (g < 0 ? -g : g);
2806
2539
 
2807
- return min((dst >>> 24) + a, 0xFF) << 24
2808
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
2809
- | ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2540
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2541
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2542
+ ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2810
2543
  }
2811
2544
 
2545
+
2812
2546
  /**
2813
- * Exclusion O = (1 - S)D + S(1 - D) O = D + S - 2DS
2547
+ * Exclusion
2548
+ * O = (1 - S)D + S(1 - D)
2549
+ * O = D + S - 2DS
2814
2550
  */
2815
2551
  private static int blend_exclusion(int dst, int src) {
2816
2552
  int a = src >>> 24;
@@ -2826,16 +2562,16 @@ int testFunction(int dst, int src) {
2826
2562
  int f_r = (dst & RED_MASK) >> 16;
2827
2563
  int f_b = (dst & BLUE_MASK);
2828
2564
 
2829
- int rb_sub
2830
- = ((src & RED_MASK) * (f_r + (f_r >= 0x7F ? 1 : 0))
2831
- | (src & BLUE_MASK) * (f_b + (f_b >= 0x7F ? 1 : 0)))
2832
- >>> 7 & 0x01FF01FF;
2565
+ int rb_sub =
2566
+ ((src & RED_MASK) * (f_r + (f_r >= 0x7F ? 1 : 0)) |
2567
+ (src & BLUE_MASK) * (f_b + (f_b >= 0x7F ? 1 : 0)))
2568
+ >>> 7 & 0x01FF01FF;
2833
2569
  int gn_sub = s_gn * (d_gn + (d_gn >= 0x7F00 ? 0x100 : 0))
2834
- >>> 15 & 0x0001FF00;
2570
+ >>> 15 & 0x0001FF00;
2835
2571
 
2836
- return min((dst >>> 24) + a, 0xFF) << 24
2837
- | (d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK
2838
- | (d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
2572
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2573
+ (d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK |
2574
+ (d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
2839
2575
  }
2840
2576
 
2841
2577
 
@@ -2854,21 +2590,24 @@ int testFunction(int dst, int src) {
2854
2590
  int f_r = (dst & RED_MASK) >> 16;
2855
2591
  int f_b = (dst & BLUE_MASK);
2856
2592
 
2857
- int rb
2858
- = ((src & RED_MASK) * (f_r + 1)
2859
- | (src & BLUE_MASK) * (f_b + 1))
2860
- >>> 8 & RB_MASK;
2861
- int gn
2862
- = (src & GREEN_MASK) * (d_gn + 0x100)
2863
- >>> 16 & GN_MASK;
2593
+ int rb =
2594
+ ((src & RED_MASK) * (f_r + 1) |
2595
+ (src & BLUE_MASK) * (f_b + 1))
2596
+ >>> 8 & RB_MASK;
2597
+ int gn =
2598
+ (src & GREEN_MASK) * (d_gn + 0x100)
2599
+ >>> 16 & GN_MASK;
2864
2600
 
2865
- return min((dst >>> 24) + a, 0xFF) << 24
2866
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
2867
- | (d_gn * d_a + gn * s_a) >>> 8 & GN_MASK;
2601
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2602
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2603
+ (d_gn * d_a + gn * s_a) >>> 8 & GN_MASK;
2868
2604
  }
2869
2605
 
2606
+
2870
2607
  /**
2871
- * Screen O = 1 - (1 - D)(1 - S) O = D + S - DS
2608
+ * Screen
2609
+ * O = 1 - (1 - D)(1 - S)
2610
+ * O = D + S - DS
2872
2611
  */
2873
2612
  private static int blend_screen(int dst, int src) {
2874
2613
  int a = src >>> 24;
@@ -2884,21 +2623,23 @@ int testFunction(int dst, int src) {
2884
2623
  int f_r = (dst & RED_MASK) >> 16;
2885
2624
  int f_b = (dst & BLUE_MASK);
2886
2625
 
2887
- int rb_sub
2888
- = ((src & RED_MASK) * (f_r + 1)
2889
- | (src & BLUE_MASK) * (f_b + 1))
2890
- >>> 8 & RB_MASK;
2626
+ int rb_sub =
2627
+ ((src & RED_MASK) * (f_r + 1) |
2628
+ (src & BLUE_MASK) * (f_b + 1))
2629
+ >>> 8 & RB_MASK;
2891
2630
  int gn_sub = s_gn * (d_gn + 0x100)
2892
- >>> 16 & GN_MASK;
2631
+ >>> 16 & GN_MASK;
2893
2632
 
2894
- return min((dst >>> 24) + a, 0xFF) << 24
2895
- | (d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK
2896
- | (d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
2633
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2634
+ (d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK |
2635
+ (d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
2897
2636
  }
2898
2637
 
2638
+
2899
2639
  /**
2900
- * Overlay O = 2 * MULTIPLY(D, S) = 2DS for D < 0.5 O = 2 * SCREEN(D, S) - 1 =
2901
- * 2(S + D - DS) - 1 otherwise
2640
+ * Overlay
2641
+ * O = 2 * MULTIPLY(D, S) = 2DS for D < 0.5
2642
+ * O = 2 * SCREEN(D, S) - 1 = 2(S + D - DS) - 1 otherwise
2902
2643
  */
2903
2644
  private static int blend_overlay(int dst, int src) {
2904
2645
  int a = src >>> 24;
@@ -2914,26 +2655,28 @@ int testFunction(int dst, int src) {
2914
2655
  int s_g = src & GREEN_MASK;
2915
2656
  int s_b = src & BLUE_MASK;
2916
2657
 
2917
- int r = (d_r < 0x800000)
2918
- ? d_r * ((s_r >>> 16) + 1) >>> 7
2919
- : 0xFF0000 - ((0x100 - (s_r >>> 16)) * (RED_MASK - d_r) >>> 7);
2920
- int g = (d_g < 0x8000)
2921
- ? d_g * (s_g + 0x100) >>> 15
2922
- : (0xFF00 - ((0x10000 - s_g) * (GREEN_MASK - d_g) >>> 15));
2923
- int b = (d_b < 0x80)
2924
- ? d_b * (s_b + 1) >>> 7
2925
- : (0xFF00 - ((0x100 - s_b) * (BLUE_MASK - d_b) << 1)) >>> 8;
2658
+ int r = (d_r < 0x800000) ?
2659
+ d_r * ((s_r >>> 16) + 1) >>> 7 :
2660
+ 0xFF0000 - ((0x100 - (s_r >>> 16)) * (RED_MASK - d_r) >>> 7);
2661
+ int g = (d_g < 0x8000) ?
2662
+ d_g * (s_g + 0x100) >>> 15 :
2663
+ (0xFF00 - ((0x10000 - s_g) * (GREEN_MASK - d_g) >>> 15));
2664
+ int b = (d_b < 0x80) ?
2665
+ d_b * (s_b + 1) >>> 7 :
2666
+ (0xFF00 - ((0x100 - s_b) * (BLUE_MASK - d_b) << 1)) >>> 8;
2926
2667
 
2927
- return min((dst >>> 24) + a, 0xFF) << 24
2928
- | ((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK
2929
- | ((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
2668
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2669
+ ((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK |
2670
+ ((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
2930
2671
  }
2931
2672
 
2673
+
2932
2674
  /**
2933
- * Hard Light O = OVERLAY(S, D)
2675
+ * Hard Light
2676
+ * O = OVERLAY(S, D)
2934
2677
  *
2935
- * O = 2 * MULTIPLY(D, S) = 2DS for S < 0.5 O = 2 * SCREEN(D, S) - 1 = 2(S + D
2936
- * - DS) - 1 otherwise
2678
+ * O = 2 * MULTIPLY(D, S) = 2DS for S < 0.5
2679
+ * O = 2 * SCREEN(D, S) - 1 = 2(S + D - DS) - 1 otherwise
2937
2680
  */
2938
2681
  private static int blend_hard_light(int dst, int src) {
2939
2682
  int a = src >>> 24;
@@ -2949,24 +2692,27 @@ int testFunction(int dst, int src) {
2949
2692
  int s_g = src & GREEN_MASK;
2950
2693
  int s_b = src & BLUE_MASK;
2951
2694
 
2952
- int r = (s_r < 0x800000)
2953
- ? s_r * ((d_r >>> 16) + 1) >>> 7
2954
- : 0xFF0000 - ((0x100 - (d_r >>> 16)) * (RED_MASK - s_r) >>> 7);
2955
- int g = (s_g < 0x8000)
2956
- ? s_g * (d_g + 0x100) >>> 15
2957
- : (0xFF00 - ((0x10000 - d_g) * (GREEN_MASK - s_g) >>> 15));
2958
- int b = (s_b < 0x80)
2959
- ? s_b * (d_b + 1) >>> 7
2960
- : (0xFF00 - ((0x100 - d_b) * (BLUE_MASK - s_b) << 1)) >>> 8;
2695
+ int r = (s_r < 0x800000) ?
2696
+ s_r * ((d_r >>> 16) + 1) >>> 7 :
2697
+ 0xFF0000 - ((0x100 - (d_r >>> 16)) * (RED_MASK - s_r) >>> 7);
2698
+ int g = (s_g < 0x8000) ?
2699
+ s_g * (d_g + 0x100) >>> 15 :
2700
+ (0xFF00 - ((0x10000 - d_g) * (GREEN_MASK - s_g) >>> 15));
2701
+ int b = (s_b < 0x80) ?
2702
+ s_b * (d_b + 1) >>> 7 :
2703
+ (0xFF00 - ((0x100 - d_b) * (BLUE_MASK - s_b) << 1)) >>> 8;
2961
2704
 
2962
- return min((dst >>> 24) + a, 0xFF) << 24
2963
- | ((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK
2964
- | ((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
2705
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2706
+ ((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK |
2707
+ ((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
2965
2708
  }
2966
2709
 
2710
+
2967
2711
  /**
2968
- * Soft Light (Pegtop) O = (1 - D) * MULTIPLY(D, S) + D * SCREEN(D, S) O = (1
2969
- * - D) * DS + D * (1 - (1 - D)(1 - S)) O = 2DS + DD - 2DDS
2712
+ * Soft Light (peg top)
2713
+ * O = (1 - D) * MULTIPLY(D, S) + D * SCREEN(D, S)
2714
+ * O = (1 - D) * DS + D * (1 - (1 - D)(1 - S))
2715
+ * O = 2DS + DD - 2DDS
2970
2716
  */
2971
2717
  private static int blend_soft_light(int dst, int src) {
2972
2718
  int a = src >>> 24;
@@ -2983,23 +2729,25 @@ int testFunction(int dst, int src) {
2983
2729
  int s_b1 = src & BLUE_MASK;
2984
2730
 
2985
2731
  int d_r1 = (d_r >> 16) + (s_r1 < 7F ? 1 : 0);
2986
- int d_g1 = (d_g >> 8) + (s_g1 < 7F ? 1 : 0);
2987
- int d_b1 = d_b + (s_b1 < 7F ? 1 : 0);
2732
+ int d_g1 = (d_g >> 8) + (s_g1 < 7F ? 1 : 0);
2733
+ int d_b1 = d_b + (s_b1 < 7F ? 1 : 0);
2988
2734
 
2989
- int r = (s_r1 * d_r >> 7) + 0xFF * d_r1 * (d_r1 + 1)
2990
- - ((s_r1 * d_r1 * d_r1) << 1) & RED_MASK;
2991
- int g = (s_g1 * d_g << 1) + 0xFF * d_g1 * (d_g1 + 1)
2992
- - ((s_g1 * d_g1 * d_g1) << 1) >>> 8 & GREEN_MASK;
2993
- int b = (s_b1 * d_b << 9) + 0xFF * d_b1 * (d_b1 + 1)
2994
- - ((s_b1 * d_b1 * d_b1) << 1) >>> 16;
2735
+ int r = (s_r1 * d_r >> 7) + 0xFF * d_r1 * (d_r1 + 1) -
2736
+ ((s_r1 * d_r1 * d_r1) << 1) & RED_MASK;
2737
+ int g = (s_g1 * d_g << 1) + 0xFF * d_g1 * (d_g1 + 1) -
2738
+ ((s_g1 * d_g1 * d_g1) << 1) >>> 8 & GREEN_MASK;
2739
+ int b = (s_b1 * d_b << 9) + 0xFF * d_b1 * (d_b1 + 1) -
2740
+ ((s_b1 * d_b1 * d_b1) << 1) >>> 16;
2995
2741
 
2996
- return min((dst >>> 24) + a, 0xFF) << 24
2997
- | ((dst & RB_MASK) * d_a + (r | b) * s_a) >>> 8 & RB_MASK
2998
- | ((dst & GN_MASK) * d_a + g * s_a) >>> 8 & GN_MASK;
2742
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2743
+ ((dst & RB_MASK) * d_a + (r | b) * s_a) >>> 8 & RB_MASK |
2744
+ ((dst & GN_MASK) * d_a + g * s_a) >>> 8 & GN_MASK;
2999
2745
  }
3000
2746
 
2747
+
3001
2748
  /**
3002
- * Dodge O = D / (1 - S)
2749
+ * Dodge
2750
+ * O = D / (1 - S)
3003
2751
  */
3004
2752
  private static int blend_dodge(int dst, int src) {
3005
2753
  int a = src >>> 24;
@@ -3007,23 +2755,25 @@ int testFunction(int dst, int src) {
3007
2755
  int s_a = a + (a >= 0x7F ? 1 : 0);
3008
2756
  int d_a = 0x100 - s_a;
3009
2757
 
3010
- int r = (dst & RED_MASK) / (256 - ((src & RED_MASK) >> 16));
2758
+ int r = (dst & RED_MASK) / (256 - ((src & RED_MASK) >> 16));
3011
2759
  int g = ((dst & GREEN_MASK) << 8) / (256 - ((src & GREEN_MASK) >> 8));
3012
- int b = ((dst & BLUE_MASK) << 8) / (256 - (src & BLUE_MASK));
2760
+ int b = ((dst & BLUE_MASK) << 8) / (256 - (src & BLUE_MASK));
3013
2761
 
3014
- int rb
3015
- = (r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK))
3016
- | (b > 0x00FF ? 0x0000FF : b);
3017
- int gn
3018
- = (g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
2762
+ int rb =
2763
+ (r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK)) |
2764
+ (b > 0x00FF ? 0x0000FF : b);
2765
+ int gn =
2766
+ (g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
3019
2767
 
3020
- return min((dst >>> 24) + a, 0xFF) << 24
3021
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
3022
- | ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2768
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2769
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2770
+ ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
3023
2771
  }
3024
2772
 
2773
+
3025
2774
  /**
3026
- * Burn O = 1 - (1 - A) / B
2775
+ * Burn
2776
+ * O = 1 - (1 - A) / B
3027
2777
  */
3028
2778
  private static int blend_burn(int dst, int src) {
3029
2779
  int a = src >>> 24;
@@ -3031,70 +2781,60 @@ int testFunction(int dst, int src) {
3031
2781
  int s_a = a + (a >= 0x7F ? 1 : 0);
3032
2782
  int d_a = 0x100 - s_a;
3033
2783
 
3034
- int r = ((0xFF0000 - (dst & RED_MASK))) / (1 + (src & RED_MASK >> 16));
2784
+ int r = ((0xFF0000 - (dst & RED_MASK))) / (1 + (src & RED_MASK >> 16));
3035
2785
  int g = ((0x00FF00 - (dst & GREEN_MASK)) << 8) / (1 + (src & GREEN_MASK >> 8));
3036
- int b = ((0x0000FF - (dst & BLUE_MASK)) << 8) / (1 + (src & BLUE_MASK));
2786
+ int b = ((0x0000FF - (dst & BLUE_MASK)) << 8) / (1 + (src & BLUE_MASK));
3037
2787
 
3038
- int rb = RB_MASK
3039
- - (r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK))
3040
- - (b > 0x00FF ? 0x0000FF : b);
3041
- int gn = GN_MASK
3042
- - (g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
2788
+ int rb = RB_MASK -
2789
+ (r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK)) -
2790
+ (b > 0x00FF ? 0x0000FF : b);
2791
+ int gn = GN_MASK -
2792
+ (g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
3043
2793
 
3044
- return min((dst >>> 24) + a, 0xFF) << 24
3045
- | ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK
3046
- | ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
2794
+ return min((dst >>> 24) + a, 0xFF) << 24 |
2795
+ ((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
2796
+ ((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
3047
2797
  }
3048
2798
 
2799
+
2800
+
3049
2801
  //////////////////////////////////////////////////////////////
2802
+
3050
2803
  // FILE I/O
3051
- static byte TIFF_HEADER[] = {
3052
- 77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0,
3053
- 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1,
3054
- 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0,
3055
- 0, 0, 1, 0, 2, 0, 0, 1, 17, 0, 4, 0, 0, 0, 1, 0, 0, 3, 0, 1, 21,
3056
- 0, 3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 22, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0,
3057
- 1, 23, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8
3058
- };
3059
2804
 
3060
- static final String TIFF_ERROR
3061
- = "Error: Processing can only read its own TIFF files.";
3062
2805
 
3063
- /**
3064
- *
3065
- * @param tiff
3066
- * @return
3067
- */
3068
- static protected PImage loadTIFF(byte tiff[]) {
3069
- if ((tiff[42] != tiff[102])
3070
- || // width/height in both places
3071
- (tiff[43] != tiff[103])) {
2806
+ static public PImage loadTIFF(InputStream input) { // ignore
2807
+ byte[] tiff = PApplet.loadBytes(input);
2808
+ if (tiff == null) {
2809
+ return null;
2810
+ }
2811
+
2812
+ if ((tiff[42] != tiff[102]) || // width/height in both places
2813
+ (tiff[43] != tiff[103])) {
3072
2814
  System.err.println(TIFF_ERROR);
3073
2815
  return null;
3074
2816
  }
3075
2817
 
3076
- int width
3077
- = ((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff);
3078
- int height
3079
- = ((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff);
2818
+ int width =
2819
+ ((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff);
2820
+ int height =
2821
+ ((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff);
3080
2822
 
3081
- int count
3082
- = ((tiff[114] & 0xff) << 24)
3083
- | ((tiff[115] & 0xff) << 16)
3084
- | ((tiff[116] & 0xff) << 8)
3085
- | (tiff[117] & 0xff);
2823
+ int count =
2824
+ ((tiff[114] & 0xff) << 24) |
2825
+ ((tiff[115] & 0xff) << 16) |
2826
+ ((tiff[116] & 0xff) << 8) |
2827
+ (tiff[117] & 0xff);
3086
2828
  if (count != width * height * 3) {
3087
- System.err.println(TIFF_ERROR + " (" + width + ", " + height + ")");
2829
+ System.err.println(TIFF_ERROR + " (" + width + ", " + height +")");
3088
2830
  return null;
3089
2831
  }
3090
2832
 
3091
2833
  // check the rest of the header
3092
2834
  for (int i = 0; i < TIFF_HEADER.length; i++) {
3093
- if ((i == 30) || (i == 31) || (i == 42) || (i == 43)
3094
- || (i == 102) || (i == 103)
3095
- || (i == 114) || (i == 115) || (i == 116) || (i == 117)) {
3096
- continue;
3097
- }
2835
+ if ((i == 30) || (i == 31) || (i == 42) || (i == 43) ||
2836
+ (i == 102) || (i == 103) ||
2837
+ (i == 114) || (i == 115) || (i == 116) || (i == 117)) continue;
3098
2838
 
3099
2839
  if (tiff[i] != TIFF_HEADER[i]) {
3100
2840
  System.err.println(TIFF_ERROR + " (" + i + ")");
@@ -3106,30 +2846,25 @@ int testFunction(int dst, int src) {
3106
2846
  int index = 768;
3107
2847
  count /= 3;
3108
2848
  for (int i = 0; i < count; i++) {
3109
- outgoing.pixels[i]
3110
- = 0xFF000000
3111
- | (tiff[index++] & 0xff) << 16
3112
- | (tiff[index++] & 0xff) << 8
3113
- | (tiff[index++] & 0xff);
2849
+ outgoing.pixels[i] =
2850
+ 0xFF000000 |
2851
+ (tiff[index++] & 0xff) << 16 |
2852
+ (tiff[index++] & 0xff) << 8 |
2853
+ (tiff[index++] & 0xff);
3114
2854
  }
3115
2855
  return outgoing;
3116
2856
  }
3117
2857
 
3118
- /**
3119
- *
3120
- * @param output
3121
- * @return
3122
- */
3123
2858
  protected boolean saveTIFF(OutputStream output) {
3124
- // shutting off the warning, people can figure this out themselves
3125
2859
  /*
2860
+ // shutting off this warning, people can figure this out themselves
3126
2861
  if (format != RGB) {
3127
2862
  System.err.println("Warning: only RGB information is saved with " +
3128
2863
  ".tif files. Use .tga or .png for ARGB images and others.");
3129
2864
  }
3130
- */
2865
+ */
3131
2866
  try {
3132
- byte tiff[] = new byte[768];
2867
+ byte[] tiff = new byte[768];
3133
2868
  System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length);
3134
2869
 
3135
2870
  tiff[30] = (byte) ((pixelWidth >> 8) & 0xff);
@@ -3137,7 +2872,7 @@ int testFunction(int dst, int src) {
3137
2872
  tiff[42] = tiff[102] = (byte) ((pixelHeight >> 8) & 0xff);
3138
2873
  tiff[43] = tiff[103] = (byte) ((pixelHeight) & 0xff);
3139
2874
 
3140
- int count = pixelWidth * pixelHeight * 3;
2875
+ int count = pixelWidth*pixelHeight*3;
3141
2876
  tiff[114] = (byte) ((count >> 24) & 0xff);
3142
2877
  tiff[115] = (byte) ((count >> 16) & 0xff);
3143
2878
  tiff[116] = (byte) ((count >> 8) & 0xff);
@@ -3160,343 +2895,406 @@ int testFunction(int dst, int src) {
3160
2895
  return false;
3161
2896
  }
3162
2897
 
2898
+
3163
2899
  /**
3164
- * Creates a Targa32 formatted byte sequence of specified pixel buffer using
3165
- * RLE compression.
3166
- * </p>
3167
- * Also figured out how to avoid parsing the image upside-down (there's a
3168
- * header flag to set the image origin to top-left)
3169
- * </p>
3170
- * Starting with revision 0092, the format setting is taken into account:
3171
- * <UL>
3172
- * <LI><TT>ALPHA</TT> images written as 8bit grayscale (uses lowest byte)
3173
- * <LI><TT>RGB</TT> &rarr; 24 bits
3174
- * <LI><TT>ARGB</TT> &rarr; 32 bits
3175
- * </UL>
3176
- * All versions are RLE compressed.
3177
- * </p>
3178
- * Contributed by toxi 8-10 May 2005, based on this RLE
3179
- * <A HREF="http://www.wotsit.org/download.asp?f=tga">specification</A>
3180
- *
3181
- * @param output
3182
- * @return
2900
+ * Targa image loader for RLE-compressed TGA files.
2901
+ * <p>
2902
+ * Rewritten for 0115 to read/write RLE-encoded targa images.
2903
+ * For 0125, non-RLE encoded images are now supported, along with
2904
+ * images whose y-order is reversed (which is standard for TGA files).
2905
+ * <p>
2906
+ * A version of this function is in MovieMaker.java. Any fixes here
2907
+ * should be applied over in MovieMaker as well.
2908
+ * <p>
2909
+ * Known issue with RLE encoding and odd behavior in some apps:
2910
+ * https://github.com/processing/processing/issues/2096
2911
+ * Please help!
3183
2912
  */
3184
- protected boolean saveTGA(OutputStream output) {
3185
- byte header[] = new byte[18];
2913
+ static public PImage loadTGA(InputStream input) throws IOException { // ignore
2914
+ byte[] header = new byte[18];
2915
+ int offset = 0;
2916
+ do {
2917
+ int count = input.read(header, offset, header.length - offset);
2918
+ if (count == -1) return null;
2919
+ offset += count;
2920
+ } while (offset < 18);
3186
2921
 
3187
- if (format == ALPHA) { // save ALPHA images as 8bit grayscale
3188
- header[2] = 0x0B;
3189
- header[16] = 0x08;
3190
- header[17] = 0x28;
2922
+ /*
2923
+ header[2] image type code
2924
+ 2 (0x02) - Uncompressed, RGB images.
2925
+ 3 (0x03) - Uncompressed, black and white images.
2926
+ 10 (0x0A) - Run-length encoded RGB images.
2927
+ 11 (0x0B) - Compressed, black and white images. (grayscale?)
3191
2928
 
3192
- } else if (format == RGB) {
3193
- header[2] = 0x0A;
3194
- header[16] = 24;
3195
- header[17] = 0x20;
2929
+ header[16] is the bit depth (8, 24, 32)
3196
2930
 
3197
- } else if (format == ARGB) {
3198
- header[2] = 0x0A;
3199
- header[16] = 32;
3200
- header[17] = 0x28;
2931
+ header[17] image descriptor (packed bits)
2932
+ 0x20 is 32 = origin upper-left
2933
+ 0x28 is 32 + 8 = origin upper-left + 32 bits
3201
2934
 
3202
- } else {
3203
- throw new RuntimeException("Image format not recognized inside save()");
2935
+ 7 6 5 4 3 2 1 0
2936
+ 128 64 32 16 8 4 2 1
2937
+ */
2938
+
2939
+ int format = 0;
2940
+
2941
+ if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not
2942
+ (header[16] == 8) && // 8 bits
2943
+ ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit
2944
+ format = ALPHA;
2945
+
2946
+ } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not
2947
+ (header[16] == 24) && // 24 bits
2948
+ ((header[17] == 0x20) || (header[17] == 0))) { // origin
2949
+ format = RGB;
2950
+
2951
+ } else if (((header[2] == 2) || (header[2] == 10)) &&
2952
+ (header[16] == 32) &&
2953
+ ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32
2954
+ format = ARGB;
3204
2955
  }
3205
- // set image dimensions lo-hi byte order
3206
- header[12] = (byte) (pixelWidth & 0xff);
3207
- header[13] = (byte) (pixelWidth >> 8);
3208
- header[14] = (byte) (pixelHeight & 0xff);
3209
- header[15] = (byte) (pixelHeight >> 8);
3210
2956
 
3211
- try {
3212
- output.write(header);
2957
+ if (format == 0) {
2958
+ System.err.println("Unknown .tga file format");
2959
+ return null;
2960
+ }
3213
2961
 
3214
- int maxLen = pixelHeight * pixelWidth;
3215
- int index = 0;
3216
- int col; //, prevCol;
3217
- int[] currChunk = new int[128];
3218
-
3219
- // 8bit image exporter is in separate loop
3220
- // to avoid excessive conditionals...
3221
- if (format == ALPHA) {
3222
- while (index < maxLen) {
3223
- boolean isRLE = false;
3224
- int rle = 1;
3225
- currChunk[0] = col = pixels[index] & 0xff;
3226
- while (index + rle < maxLen) {
3227
- if (col != (pixels[index + rle] & 0xff) || rle == 128) {
3228
- isRLE = (rle > 1);
3229
- break;
3230
- }
3231
- rle++;
3232
- }
3233
- if (isRLE) {
3234
- output.write(0x80 | (rle - 1));
3235
- output.write(col);
3236
-
3237
- } else {
3238
- rle = 1;
3239
- while (index + rle < maxLen) {
3240
- int cscan = pixels[index + rle] & 0xff;
3241
- if ((col != cscan && rle < 128) || rle < 3) {
3242
- currChunk[rle] = col = cscan;
3243
- } else {
3244
- if (col == cscan) {
3245
- rle -= 2;
3246
- }
3247
- break;
3248
- }
3249
- rle++;
3250
- }
3251
- output.write(rle - 1);
3252
- for (int i = 0; i < rle; i++) {
3253
- output.write(currChunk[i]);
2962
+ int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
2963
+ int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
2964
+ PImage outgoing = new PImage(w, h, format);
2965
+
2966
+ // where "reversed" means upper-left corner (normal for most of
2967
+ // the modernized world, but "reversed" for the tga spec)
2968
+ //boolean reversed = (header[17] & 0x20) != 0;
2969
+ // https://github.com/processing/processing/issues/1682
2970
+ boolean reversed = (header[17] & 0x20) == 0;
2971
+
2972
+ if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded
2973
+ if (reversed) {
2974
+ int index = (h-1) * w;
2975
+ switch (format) {
2976
+ case ALPHA:
2977
+ for (int y = h-1; y >= 0; y--) {
2978
+ for (int x = 0; x < w; x++) {
2979
+ outgoing.pixels[index + x] = input.read();
3254
2980
  }
2981
+ index -= w;
3255
2982
  }
3256
- index += rle;
3257
- }
3258
- } else { // export 24/32 bit TARGA
3259
- while (index < maxLen) {
3260
- boolean isRLE = false;
3261
- currChunk[0] = col = pixels[index];
3262
- int rle = 1;
3263
- // try to find repeating bytes (min. len = 2 pixels)
3264
- // maximum chunk size is 128 pixels
3265
- while (index + rle < maxLen) {
3266
- if (col != pixels[index + rle] || rle == 128) {
3267
- isRLE = (rle > 1); // set flag for RLE chunk
3268
- break;
2983
+ break;
2984
+ case RGB:
2985
+ for (int y = h-1; y >= 0; y--) {
2986
+ for (int x = 0; x < w; x++) {
2987
+ outgoing.pixels[index + x] =
2988
+ input.read() | (input.read() << 8) | (input.read() << 16) |
2989
+ 0xff000000;
3269
2990
  }
3270
- rle++;
2991
+ index -= w;
3271
2992
  }
3272
- if (isRLE) {
3273
- output.write(128 | (rle - 1));
3274
- output.write(col & 0xff);
3275
- output.write(col >> 8 & 0xff);
3276
- output.write(col >> 16 & 0xff);
3277
- if (format == ARGB) {
3278
- output.write(col >>> 24 & 0xff);
3279
- }
3280
-
3281
- } else { // not RLE
3282
- rle = 1;
3283
- while (index + rle < maxLen) {
3284
- if ((col != pixels[index + rle] && rle < 128) || rle < 3) {
3285
- currChunk[rle] = col = pixels[index + rle];
3286
- } else {
3287
- // check if the exit condition was the start of
3288
- // a repeating colour
3289
- if (col == pixels[index + rle]) {
3290
- rle -= 2;
3291
- }
3292
- break;
3293
- }
3294
- rle++;
3295
- }
3296
- // write uncompressed chunk
3297
- output.write(rle - 1);
3298
- if (format == ARGB) {
3299
- for (int i = 0; i < rle; i++) {
3300
- col = currChunk[i];
3301
- output.write(col & 0xff);
3302
- output.write(col >> 8 & 0xff);
3303
- output.write(col >> 16 & 0xff);
3304
- output.write(col >>> 24 & 0xff);
3305
- }
3306
- } else {
3307
- for (int i = 0; i < rle; i++) {
3308
- col = currChunk[i];
3309
- output.write(col & 0xff);
3310
- output.write(col >> 8 & 0xff);
3311
- output.write(col >> 16 & 0xff);
3312
- }
2993
+ break;
2994
+ case ARGB:
2995
+ for (int y = h-1; y >= 0; y--) {
2996
+ for (int x = 0; x < w; x++) {
2997
+ outgoing.pixels[index + x] =
2998
+ input.read() | (input.read() << 8) | (input.read() << 16) |
2999
+ (input.read() << 24);
3313
3000
  }
3001
+ index -= w;
3314
3002
  }
3315
- index += rle;
3316
3003
  }
3317
- }
3318
- output.flush();
3319
- return true;
3320
-
3321
- } catch (IOException e) {
3322
- e.printStackTrace();
3323
- return false;
3324
- }
3325
- }
3326
-
3327
- /**
3328
- * Use ImageIO functions from Java 1.4 and later to handle image save. Various
3329
- * formats are supported, typically jpeg, png, bmp, and wbmp. To get a list of
3330
- * the supported formats for writing, use: <BR>
3331
- * <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
3332
- *
3333
- * @param path
3334
- * @return
3335
- * @throws java.io.IOException
3336
- */
3337
- protected boolean saveImageIO(String path) throws IOException {
3338
- try {
3339
- int outputFormat = (format == ARGB)
3340
- ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
3341
-
3342
- String extension
3343
- = path.substring(path.lastIndexOf('.') + 1).toLowerCase();
3344
-
3345
- // JPEG and BMP images that have an alpha channel set get pretty unhappy.
3346
- // BMP just doesn't write, and JPEG writes it as a CMYK image.
3347
- // http://code.google.com/p/processing/issues/detail?id=415
3348
- if (extension.equals("bmp") || extension.equals("jpg") || extension.equals("jpeg")) {
3349
- outputFormat = BufferedImage.TYPE_INT_RGB;
3350
- }
3351
-
3352
- BufferedImage bimage = new BufferedImage(pixelWidth, pixelHeight, outputFormat);
3353
- bimage.setRGB(0, 0, pixelWidth, pixelHeight, pixels, 0, pixelWidth);
3354
-
3355
- File file = new File(path);
3356
-
3357
- ImageWriter writer = null;
3358
- ImageWriteParam param = null;
3359
- IIOMetadata metadata = null;
3360
-
3361
- if (extension.equals("jpg") || extension.equals("jpeg")) {
3362
- if ((writer = imageioWriter("jpeg")) != null) {
3363
- // Set JPEG quality to 90% with baseline optimization. Setting this
3364
- // to 1 was a huge jump (about triple the size), so this seems good.
3365
- // Oddly, a smaller file size than Photoshop at 90%, but I suppose
3366
- // it's a completely different algorithm.
3367
- param = writer.getDefaultWriteParam();
3368
- param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
3369
- param.setCompressionQuality(0.9f);
3004
+ } else { // not reversed
3005
+ int count = w * h;
3006
+ switch (format) {
3007
+ case ALPHA:
3008
+ for (int i = 0; i < count; i++) {
3009
+ outgoing.pixels[i] = input.read();
3010
+ }
3011
+ break;
3012
+ case RGB:
3013
+ for (int i = 0; i < count; i++) {
3014
+ outgoing.pixels[i] =
3015
+ input.read() | (input.read() << 8) | (input.read() << 16) |
3016
+ 0xff000000;
3017
+ }
3018
+ break;
3019
+ case ARGB:
3020
+ for (int i = 0; i < count; i++) {
3021
+ outgoing.pixels[i] =
3022
+ input.read() | (input.read() << 8) | (input.read() << 16) |
3023
+ (input.read() << 24);
3024
+ }
3025
+ break;
3370
3026
  }
3371
3027
  }
3372
3028
 
3373
- if (extension.equals("png")) {
3374
- if ((writer = imageioWriter("png")) != null) {
3375
- param = writer.getDefaultWriteParam();
3376
- if (false) {
3377
- metadata = imageioDPI(writer, param, 100);
3029
+ } else { // header[2] is 10 or 11
3030
+ int index = 0;
3031
+ int[] px = outgoing.pixels;
3032
+
3033
+ while (index < px.length) {
3034
+ int num = input.read();
3035
+ boolean isRLE = (num & 0x80) != 0;
3036
+ if (isRLE) {
3037
+ num -= 127; // (num & 0x7F) + 1
3038
+ int pixel = 0;
3039
+ switch (format) {
3040
+ case ALPHA:
3041
+ pixel = input.read();
3042
+ break;
3043
+ case RGB:
3044
+ pixel = 0xFF000000 |
3045
+ input.read() | (input.read() << 8) | (input.read() << 16);
3046
+ //(is.read() << 16) | (is.read() << 8) | is.read();
3047
+ break;
3048
+ case ARGB:
3049
+ pixel = input.read() |
3050
+ (input.read() << 8) | (input.read() << 16) | (input.read() << 24);
3051
+ break;
3052
+ }
3053
+ for (int i = 0; i < num; i++) {
3054
+ px[index++] = pixel;
3055
+ if (index == px.length) break;
3056
+ }
3057
+ } else { // write up to 127 bytes as uncompressed
3058
+ num += 1;
3059
+ switch (format) {
3060
+ case ALPHA:
3061
+ for (int i = 0; i < num; i++) {
3062
+ px[index++] = input.read();
3063
+ }
3064
+ break;
3065
+ case RGB:
3066
+ for (int i = 0; i < num; i++) {
3067
+ px[index++] = 0xFF000000 |
3068
+ input.read() | (input.read() << 8) | (input.read() << 16);
3069
+ //(is.read() << 16) | (is.read() << 8) | is.read();
3070
+ }
3071
+ break;
3072
+ case ARGB:
3073
+ for (int i = 0; i < num; i++) {
3074
+ px[index++] = input.read() | //(is.read() << 24) |
3075
+ (input.read() << 8) | (input.read() << 16) | (input.read() << 24);
3076
+ //(is.read() << 16) | (is.read() << 8) | is.read();
3077
+ }
3078
+ break;
3378
3079
  }
3379
3080
  }
3380
3081
  }
3381
3082
 
3382
- if (writer != null) {
3383
- BufferedOutputStream output
3384
- = new BufferedOutputStream(PApplet.createOutput(file));
3385
- writer.setOutput(ImageIO.createImageOutputStream(output));
3386
- // writer.write(null, new IIOImage(bimage, null, null), param);
3387
- writer.write(metadata, new IIOImage(bimage, null, metadata), param);
3388
- writer.dispose();
3389
-
3390
- output.flush();
3391
- output.close();
3392
- return true;
3083
+ if (!reversed) {
3084
+ int[] temp = new int[w];
3085
+ for (int y = 0; y < h/2; y++) {
3086
+ int z = (h-1) - y;
3087
+ System.arraycopy(px, y*w, temp, 0, w);
3088
+ System.arraycopy(px, z*w, px, y*w, w);
3089
+ System.arraycopy(temp, 0, px, z*w, w);
3090
+ }
3393
3091
  }
3394
- // If iter.hasNext() somehow fails up top, it falls through to here
3395
- return javax.imageio.ImageIO.write(bimage, extension, file);
3396
-
3397
- } catch (Exception e) {
3398
- e.printStackTrace();
3399
- throw new IOException("image save failed.");
3400
3092
  }
3093
+ input.close();
3094
+ return outgoing;
3401
3095
  }
3402
3096
 
3403
- private ImageWriter imageioWriter(String extension) {
3404
- Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(extension);
3405
- if (iter.hasNext()) {
3406
- return iter.next();
3407
- }
3408
- return null;
3409
- }
3410
-
3411
- private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double dpi) {
3412
- // http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
3413
- ImageTypeSpecifier typeSpecifier
3414
- = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
3415
- IIOMetadata metadata
3416
- = writer.getDefaultImageMetadata(typeSpecifier, param);
3417
-
3418
- if (!metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) {
3419
- // for PNG, it's dots per millimeter
3420
- double dotsPerMilli = dpi / 25.4;
3421
-
3422
- IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
3423
- horiz.setAttribute("value", Double.toString(dotsPerMilli));
3424
-
3425
- IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
3426
- vert.setAttribute("value", Double.toString(dotsPerMilli));
3427
-
3428
- IIOMetadataNode dim = new IIOMetadataNode("Dimension");
3429
- dim.appendChild(horiz);
3430
- dim.appendChild(vert);
3431
-
3432
- IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
3433
- root.appendChild(dim);
3434
-
3435
- try {
3436
- metadata.mergeTree("javax_imageio_1.0", root);
3437
- return metadata;
3438
-
3439
- } catch (IIOInvalidTreeException e) {
3440
- System.err.println("Could not set the DPI of the output image");
3441
- e.printStackTrace();
3442
- }
3443
- }
3444
- return null;
3445
- }
3446
3097
 
3447
3098
  /**
3448
- *
3099
+ * Creates a Targa32 formatted byte sequence of specified
3100
+ * pixel buffer using RLE compression.
3101
+ * </p>
3102
+ * Also figured out how to avoid parsing the image upside-down
3103
+ * (there's a header flag to set the image origin to top-left)
3104
+ * </p>
3105
+ * Starting with revision 0092, the format setting is taken into account:
3106
+ * <UL>
3107
+ * <LI><TT>ALPHA</TT> images written as 8bit grayscale (uses lowest byte)
3108
+ * <LI><TT>RGB</TT> &rarr; 24 bits
3109
+ * <LI><TT>ARGB</TT> &rarr; 32 bits
3110
+ * </UL>
3111
+ * All versions are RLE compressed.
3112
+ * </p>
3113
+ * Contributed by toxi 8-10 May 2005, based on this RLE
3114
+ * <A HREF="http://www.wotsit.org/download.asp?f=tga">specification</A>
3449
3115
  */
3450
- protected String[] saveImageFormats;
3451
-
3452
- /**
3453
- * ( begin auto-generated from PImage_save.xml )
3454
- *
3455
- * Saves the image into a file. Append a file extension to the name of the
3456
- * file, to indicate the file format to be used: either TIFF (.tif), TARGA
3457
- * (.tga), JPEG (.jpg), or PNG (.png). If no extension is included in the
3458
- * filename, the image will save in TIFF format and .tif will be added to the
3459
- * name. These files are saved to the sketch's folder, which may be opened by
3460
- * selecting "Show sketch folder" from the "Sketch" menu.
3461
- * To save an image created within the code, rather than through
3462
- * loading, it's necessary to make the image with the
3463
- * <b>createImage()</b> function so it is aware of the location of the program
3464
- * and can therefore save the file to the right place. See the
3116
+ protected boolean saveTGA(OutputStream output) {
3117
+ byte[] header = new byte[18];
3118
+
3119
+ if (format == ALPHA) { // save ALPHA images as 8bit grayscale
3120
+ header[2] = 0x0B;
3121
+ header[16] = 0x08;
3122
+ header[17] = 0x28;
3123
+
3124
+ } else if (format == RGB) {
3125
+ header[2] = 0x0A;
3126
+ header[16] = 24;
3127
+ header[17] = 0x20;
3128
+
3129
+ } else if (format == ARGB) {
3130
+ header[2] = 0x0A;
3131
+ header[16] = 32;
3132
+ header[17] = 0x28;
3133
+
3134
+ } else {
3135
+ throw new RuntimeException("Image format not recognized inside save()");
3136
+ }
3137
+ // set image dimensions lo-hi byte order
3138
+ header[12] = (byte) (pixelWidth & 0xff);
3139
+ header[13] = (byte) (pixelWidth >> 8);
3140
+ header[14] = (byte) (pixelHeight & 0xff);
3141
+ header[15] = (byte) (pixelHeight >> 8);
3142
+
3143
+ try {
3144
+ output.write(header);
3145
+
3146
+ int maxLen = pixelHeight * pixelWidth;
3147
+ int index = 0;
3148
+ int col; //, prevCol;
3149
+ int[] currChunk = new int[128];
3150
+
3151
+ // 8bit image exporter is in separate loop
3152
+ // to avoid excessive conditionals...
3153
+ if (format == ALPHA) {
3154
+ while (index < maxLen) {
3155
+ boolean isRLE = false;
3156
+ int rle = 1;
3157
+ currChunk[0] = col = pixels[index] & 0xff;
3158
+ while (index + rle < maxLen) {
3159
+ if (col != (pixels[index + rle]&0xff) || rle == 128) {
3160
+ isRLE = (rle > 1);
3161
+ break;
3162
+ }
3163
+ rle++;
3164
+ }
3165
+ if (isRLE) {
3166
+ output.write(0x80 | (rle - 1));
3167
+ output.write(col);
3168
+
3169
+ } else {
3170
+ rle = 1;
3171
+ while (index + rle < maxLen) {
3172
+ int cscan = pixels[index + rle] & 0xff;
3173
+ if ((col != cscan && rle < 128) || rle < 3) {
3174
+ currChunk[rle] = col = cscan;
3175
+ } else {
3176
+ if (col == cscan) rle -= 2;
3177
+ break;
3178
+ }
3179
+ rle++;
3180
+ }
3181
+ output.write(rle - 1);
3182
+ for (int i = 0; i < rle; i++) output.write(currChunk[i]);
3183
+ }
3184
+ index += rle;
3185
+ }
3186
+ } else { // export 24/32 bit TARGA
3187
+ while (index < maxLen) {
3188
+ boolean isRLE = false;
3189
+ currChunk[0] = col = pixels[index];
3190
+ int rle = 1;
3191
+ // try to find repeating bytes (min. len = 2 pixels)
3192
+ // maximum chunk size is 128 pixels
3193
+ while (index + rle < maxLen) {
3194
+ if (col != pixels[index + rle] || rle == 128) {
3195
+ isRLE = (rle > 1); // set flag for RLE chunk
3196
+ break;
3197
+ }
3198
+ rle++;
3199
+ }
3200
+ if (isRLE) {
3201
+ output.write(128 | (rle - 1));
3202
+ output.write(col & 0xff);
3203
+ output.write(col >> 8 & 0xff);
3204
+ output.write(col >> 16 & 0xff);
3205
+ if (format == ARGB) output.write(col >>> 24 & 0xff);
3206
+
3207
+ } else { // not RLE
3208
+ rle = 1;
3209
+ while (index + rle < maxLen) {
3210
+ if ((col != pixels[index + rle] && rle < 128) || rle < 3) {
3211
+ currChunk[rle] = col = pixels[index + rle];
3212
+ } else {
3213
+ // check if the exit condition was the start of
3214
+ // a repeating colour
3215
+ if (col == pixels[index + rle]) rle -= 2;
3216
+ break;
3217
+ }
3218
+ rle++;
3219
+ }
3220
+ // write uncompressed chunk
3221
+ output.write(rle - 1);
3222
+ if (format == ARGB) {
3223
+ for (int i = 0; i < rle; i++) {
3224
+ col = currChunk[i];
3225
+ output.write(col & 0xff);
3226
+ output.write(col >> 8 & 0xff);
3227
+ output.write(col >> 16 & 0xff);
3228
+ output.write(col >>> 24 & 0xff);
3229
+ }
3230
+ } else {
3231
+ for (int i = 0; i < rle; i++) {
3232
+ col = currChunk[i];
3233
+ output.write(col & 0xff);
3234
+ output.write(col >> 8 & 0xff);
3235
+ output.write(col >> 16 & 0xff);
3236
+ }
3237
+ }
3238
+ }
3239
+ index += rle;
3240
+ }
3241
+ }
3242
+ output.flush();
3243
+ return true;
3244
+
3245
+ } catch (IOException e) {
3246
+ e.printStackTrace();
3247
+ return false;
3248
+ }
3249
+ }
3250
+
3251
+
3252
+ /**
3253
+ *
3254
+ * Saves the image into a file. Append a file extension to the name of
3255
+ * the file, to indicate the file format to be used: either TIFF (.tif),
3256
+ * TARGA (.tga), JPEG (.jpg), or PNG (.png). If no extension is included
3257
+ * in the filename, the image will save in TIFF format and .tif will be
3258
+ * added to the name. These files are saved to the sketch's folder, which
3259
+ * may be opened by selecting "Show sketch folder" from the "Sketch" menu.
3260
+ * <br /><br />To save an image created within the code, rather
3261
+ * than through loading, it's necessary to make the image with the
3262
+ * <b>createImage()</b> function so it is aware of the location of the
3263
+ * program and can therefore save the file to the right place. See the
3465
3264
  * <b>createImage()</b> reference for more information.
3466
3265
  *
3467
- * ( end auto-generated )
3468
3266
  * <h3>Advanced</h3>
3469
3267
  * Save this image to disk.
3470
3268
  * <p>
3471
- * As of revision 0100, this function requires an absolute path, in order to
3472
- * avoid confusion. To save inside the sketch folder, use the function
3473
- * savePath() from PApplet, or use saveFrame() instead. As of revision 0116,
3474
- * savePath() is not needed if this object has been created (as recommended)
3475
- * via createImage() or createGraphics() or one of its neighbors.
3269
+ * As of revision 0100, this function requires an absolute path,
3270
+ * in order to avoid confusion. To save inside the sketch folder,
3271
+ * use the function savePath() from PApplet, or use saveFrame() instead.
3272
+ * As of revision 0116, savePath() is not needed if this object has been
3273
+ * created (as recommended) via createImage() or createGraphics() or
3274
+ * one of its neighbors.
3476
3275
  * <p>
3477
- * As of revision 0115, when using Java 1.4 and later, you can write to
3478
- * several formats besides tga and tiff. If Java 1.4 is installed and the
3479
- * extension used is supported (usually png, jpg, jpeg, bmp, and tiff), then
3480
- * those methods will be used to write the image. To get a list of the
3481
- * supported formats for writing, use: <BR>
3276
+ * As of revision 0115, when using Java 1.4 and later, you can write
3277
+ * to several formats besides tga and tiff. If Java 1.4 is installed
3278
+ * and the extension used is supported (usually png, jpg, jpeg, bmp,
3279
+ * and tiff), then those methods will be used to write the image.
3280
+ * To get a list of the supported formats for writing, use: <BR>
3482
3281
  * <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
3483
3282
  * <p>
3484
3283
  * To use the original built-in image writers, use .tga or .tif as the
3485
- * extension, or don't include an extension. When no extension is used, the
3486
- * extension .tif will be added to the file name.
3284
+ * extension, or don't include an extension. When no extension is used,
3285
+ * the extension .tif will be added to the file name.
3487
3286
  * <p>
3488
- * The ImageIO API claims to support wbmp files, however they probably require
3489
- * a black and white image. Basic testing produced a zero-length file with no
3490
- * error.
3287
+ * The ImageIO API claims to support wbmp files, however they probably
3288
+ * require a black and white image. Basic testing produced a zero-length
3289
+ * file with no error.
3491
3290
  *
3492
- * @return
3493
3291
  * @webref pimage:method
3494
- * @brief Saves the image to a TIFF, TARGA, PNG, or JPEG file
3292
+ * @webBrief Saves the image to a TIFF, TARGA, PNG, or JPEG file.
3495
3293
  * @usage application
3496
3294
  * @param filename a sequence of letters and numbers
3497
3295
  */
3498
3296
  public boolean save(String filename) { // ignore
3499
- boolean success = false;
3297
+ boolean success;
3500
3298
 
3501
3299
  if (parent != null) {
3502
3300
  // use savePath(), so that the intermediate directories are created
@@ -3508,9 +3306,9 @@ int testFunction(int dst, int src) {
3508
3306
  // make sure that the intermediate folders have been created
3509
3307
  PApplet.createPath(file);
3510
3308
  } else {
3511
- String msg
3512
- = "PImage.save() requires an absolute path. "
3513
- + "Use createImage(), or pass savePath() to save().";
3309
+ String msg =
3310
+ "PImage.save() requires an absolute path. " +
3311
+ "Use createImage(), or pass savePath() to save().";
3514
3312
  PGraphics.showException(msg);
3515
3313
  }
3516
3314
  }
@@ -3519,38 +3317,28 @@ int testFunction(int dst, int src) {
3519
3317
  loadPixels();
3520
3318
 
3521
3319
  try {
3522
- OutputStream os = null;
3320
+ final String lower = filename.toLowerCase();
3523
3321
 
3524
- if (saveImageFormats == null) {
3525
- saveImageFormats = javax.imageio.ImageIO.getWriterFormatNames();
3526
- }
3527
- if (saveImageFormats != null) {
3528
- for (int i = 0; i < saveImageFormats.length; i++) {
3529
- if (filename.endsWith("." + saveImageFormats[i])) {
3530
- if (!saveImageIO(filename)) {
3531
- System.err.println("Error while saving image.");
3532
- return false;
3533
- }
3534
- return true;
3535
- }
3536
- }
3322
+ if (saveImpl(filename)) {
3323
+ return true;
3537
3324
  }
3538
3325
 
3539
- if (filename.toLowerCase().endsWith(".tga")) {
3540
- os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
3326
+ if (lower.endsWith(".tga")) {
3327
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
3541
3328
  success = saveTGA(os); //, pixels, width, height, format);
3329
+ os.close();
3542
3330
 
3543
- } else {
3544
- if (!filename.toLowerCase().endsWith(".tif")
3545
- && !filename.toLowerCase().endsWith(".tiff")) {
3546
- // if no .tif extension, add it..
3331
+ } else { // fall-through case is TIFF
3332
+ // add a default extension and save uncompressed
3333
+ // TODO this is the only place in the api that we mess w/ file names,
3334
+ // and while arguably useful, seems like a weird precedent [fry 200816]
3335
+ if (!lower.endsWith(".tif") && !lower.endsWith(".tiff")) {
3547
3336
  filename += ".tif";
3548
3337
  }
3549
- os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
3338
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
3550
3339
  success = saveTIFF(os); //, pixels, width, height);
3340
+ os.close();
3551
3341
  }
3552
- os.flush();
3553
- os.close();
3554
3342
 
3555
3343
  } catch (IOException e) {
3556
3344
  System.err.println("Error while saving image.");
@@ -3559,4 +3347,21 @@ int testFunction(int dst, int src) {
3559
3347
  }
3560
3348
  return success;
3561
3349
  }
3350
+
3351
+
3352
+ /**
3353
+ * Override this in subclasses to intercept save calls for other formats
3354
+ * or higher-performance implementations. When reaching this code, pixels
3355
+ * must be loaded and that path should be absolute.
3356
+ *
3357
+ * @param path must be a full path (not relative or simply a filename)
3358
+ */
3359
+ protected boolean saveImpl(String path) {
3360
+ // TODO Imperfect/temporary solution for alpha 2.
3361
+ // https://github.com/processing/processing4/wiki/Exorcising-AWT
3362
+ if (!PApplet.disableAWT) {
3363
+ return ShimAWT.saveImage(this, path);
3364
+ }
3365
+ return false;
3366
+ }
3562
3367
  }