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