picrate 2.0.1-java → 2.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
  }