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