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