propane 3.10.0-java → 3.11.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/wrapper/maven-wrapper.properties +1 -1
  3. data/CHANGELOG.md +2 -0
  4. data/README.md +7 -7
  5. data/lib/propane/app.rb +2 -5
  6. data/lib/propane/helper_methods.rb +6 -6
  7. data/lib/propane/version.rb +1 -1
  8. data/lib/{propane-3.10.0.jar → propane-3.11.0.jar} +0 -0
  9. data/pom.rb +6 -6
  10. data/pom.xml +6 -6
  11. data/propane.gemspec +3 -3
  12. data/src/main/java/monkstone/noise/OpenSimplex2F.java +838 -737
  13. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +8 -13
  14. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +14 -28
  15. data/src/main/java/processing/awt/PImageAWT.java +6 -4
  16. data/src/main/java/processing/core/PApplet.java +71 -59
  17. data/src/main/java/processing/core/PImage.java +14 -14
  18. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +13 -13
  19. data/src/main/java/processing/opengl/PShader.java +1 -6
  20. data/src/main/java/processing/opengl/PSurfaceJOGL.java +6 -6
  21. data/{lib/java/processing/opengl → src/main/resources}/cursors/arrow.png +0 -0
  22. data/{lib/java/processing/opengl → src/main/resources}/cursors/cross.png +0 -0
  23. data/{lib/java/processing/opengl → src/main/resources}/cursors/hand.png +0 -0
  24. data/{lib/java/processing/opengl → src/main/resources}/cursors/license.txt +0 -0
  25. data/{lib/java/processing/opengl → src/main/resources}/cursors/move.png +0 -0
  26. data/{lib/java/processing/opengl → src/main/resources}/cursors/text.png +0 -0
  27. data/{lib/java/processing/opengl → src/main/resources}/cursors/wait.png +0 -0
  28. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorFrag.glsl +0 -0
  29. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorVert.glsl +0 -0
  30. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightFrag.glsl +0 -0
  31. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightVert.glsl +0 -0
  32. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineFrag.glsl +0 -0
  33. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineVert.glsl +0 -0
  34. data/{lib/java/processing/opengl → src/main/resources}/shaders/MaskFrag.glsl +0 -0
  35. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointFrag.glsl +0 -0
  36. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointVert.glsl +0 -0
  37. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexFrag.glsl +0 -0
  38. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightFrag.glsl +0 -0
  39. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightVert.glsl +0 -0
  40. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexVert.glsl +0 -0
  41. data/test/test_helper.rb +1 -0
  42. data/vendors/Rakefile +1 -1
  43. metadata +29 -155
  44. data/lib/java/japplemenubar/JAppleMenuBar.java +0 -88
  45. data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
  46. data/lib/java/monkstone/ColorUtil.java +0 -127
  47. data/lib/java/monkstone/MathToolModule.java +0 -287
  48. data/lib/java/monkstone/PropaneLibrary.java +0 -46
  49. data/lib/java/monkstone/core/LibraryProxy.java +0 -136
  50. data/lib/java/monkstone/fastmath/DegLutTables.java +0 -111
  51. data/lib/java/monkstone/fastmath/Deglut.java +0 -71
  52. data/lib/java/monkstone/fastmath/package-info.java +0 -6
  53. data/lib/java/monkstone/filechooser/Chooser.java +0 -39
  54. data/lib/java/monkstone/noise/FastTerrain.java +0 -874
  55. data/lib/java/monkstone/noise/Noise.java +0 -90
  56. data/lib/java/monkstone/noise/NoiseGenerator.java +0 -75
  57. data/lib/java/monkstone/noise/NoiseMode.java +0 -28
  58. data/lib/java/monkstone/noise/OpenSimplex2F.java +0 -881
  59. data/lib/java/monkstone/noise/OpenSimplex2S.java +0 -1106
  60. data/lib/java/monkstone/noise/SmoothTerrain.java +0 -1099
  61. data/lib/java/monkstone/slider/CustomHorizontalSlider.java +0 -164
  62. data/lib/java/monkstone/slider/CustomVerticalSlider.java +0 -178
  63. data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +0 -145
  64. data/lib/java/monkstone/slider/SimpleSlider.java +0 -166
  65. data/lib/java/monkstone/slider/SimpleVerticalSlider.java +0 -157
  66. data/lib/java/monkstone/slider/Slider.java +0 -61
  67. data/lib/java/monkstone/slider/SliderBar.java +0 -245
  68. data/lib/java/monkstone/slider/SliderGroup.java +0 -56
  69. data/lib/java/monkstone/slider/WheelHandler.java +0 -35
  70. data/lib/java/monkstone/vecmath/GfxRender.java +0 -86
  71. data/lib/java/monkstone/vecmath/JRender.java +0 -56
  72. data/lib/java/monkstone/vecmath/ShapeRender.java +0 -87
  73. data/lib/java/monkstone/vecmath/package-info.java +0 -20
  74. data/lib/java/monkstone/vecmath/vec2/Vec2.java +0 -802
  75. data/lib/java/monkstone/vecmath/vec2/package-info.java +0 -6
  76. data/lib/java/monkstone/vecmath/vec3/Vec3.java +0 -727
  77. data/lib/java/monkstone/vecmath/vec3/package-info.java +0 -6
  78. data/lib/java/monkstone/videoevent/CaptureEvent.java +0 -27
  79. data/lib/java/monkstone/videoevent/MovieEvent.java +0 -32
  80. data/lib/java/monkstone/videoevent/package-info.java +0 -20
  81. data/lib/java/processing/awt/PGraphicsJava2D.java +0 -3040
  82. data/lib/java/processing/awt/PImageAWT.java +0 -377
  83. data/lib/java/processing/awt/PShapeJava2D.java +0 -387
  84. data/lib/java/processing/awt/PSurfaceAWT.java +0 -1581
  85. data/lib/java/processing/awt/ShimAWT.java +0 -581
  86. data/lib/java/processing/core/PApplet.java +0 -15156
  87. data/lib/java/processing/core/PConstants.java +0 -523
  88. data/lib/java/processing/core/PFont.java +0 -1126
  89. data/lib/java/processing/core/PGraphics.java +0 -8600
  90. data/lib/java/processing/core/PImage.java +0 -3377
  91. data/lib/java/processing/core/PMatrix.java +0 -208
  92. data/lib/java/processing/core/PMatrix2D.java +0 -562
  93. data/lib/java/processing/core/PMatrix3D.java +0 -890
  94. data/lib/java/processing/core/PShape.java +0 -3561
  95. data/lib/java/processing/core/PShapeOBJ.java +0 -483
  96. data/lib/java/processing/core/PShapeSVG.java +0 -2016
  97. data/lib/java/processing/core/PStyle.java +0 -63
  98. data/lib/java/processing/core/PSurface.java +0 -198
  99. data/lib/java/processing/core/PSurfaceNone.java +0 -431
  100. data/lib/java/processing/core/PVector.java +0 -1066
  101. data/lib/java/processing/core/ThinkDifferent.java +0 -115
  102. data/lib/java/processing/data/DoubleDict.java +0 -850
  103. data/lib/java/processing/data/DoubleList.java +0 -928
  104. data/lib/java/processing/data/FloatDict.java +0 -847
  105. data/lib/java/processing/data/FloatList.java +0 -936
  106. data/lib/java/processing/data/IntDict.java +0 -807
  107. data/lib/java/processing/data/IntList.java +0 -936
  108. data/lib/java/processing/data/JSONArray.java +0 -1260
  109. data/lib/java/processing/data/JSONObject.java +0 -2282
  110. data/lib/java/processing/data/JSONTokener.java +0 -435
  111. data/lib/java/processing/data/LongDict.java +0 -802
  112. data/lib/java/processing/data/LongList.java +0 -937
  113. data/lib/java/processing/data/Sort.java +0 -46
  114. data/lib/java/processing/data/StringDict.java +0 -613
  115. data/lib/java/processing/data/StringList.java +0 -800
  116. data/lib/java/processing/data/Table.java +0 -4936
  117. data/lib/java/processing/data/TableRow.java +0 -198
  118. data/lib/java/processing/data/XML.java +0 -1156
  119. data/lib/java/processing/dxf/RawDXF.java +0 -404
  120. data/lib/java/processing/event/Event.java +0 -125
  121. data/lib/java/processing/event/KeyEvent.java +0 -70
  122. data/lib/java/processing/event/MouseEvent.java +0 -114
  123. data/lib/java/processing/event/TouchEvent.java +0 -57
  124. data/lib/java/processing/javafx/PGraphicsFX2D.java +0 -32
  125. data/lib/java/processing/javafx/PSurfaceFX.java +0 -173
  126. data/lib/java/processing/net/Client.java +0 -744
  127. data/lib/java/processing/net/Server.java +0 -388
  128. data/lib/java/processing/opengl/FontTexture.java +0 -378
  129. data/lib/java/processing/opengl/FrameBuffer.java +0 -513
  130. data/lib/java/processing/opengl/LinePath.java +0 -627
  131. data/lib/java/processing/opengl/LineStroker.java +0 -681
  132. data/lib/java/processing/opengl/PGL.java +0 -3483
  133. data/lib/java/processing/opengl/PGraphics2D.java +0 -615
  134. data/lib/java/processing/opengl/PGraphics3D.java +0 -281
  135. data/lib/java/processing/opengl/PGraphicsOpenGL.java +0 -13753
  136. data/lib/java/processing/opengl/PJOGL.java +0 -2008
  137. data/lib/java/processing/opengl/PShader.java +0 -1484
  138. data/lib/java/processing/opengl/PShapeOpenGL.java +0 -5269
  139. data/lib/java/processing/opengl/PSurfaceJOGL.java +0 -1385
  140. data/lib/java/processing/opengl/Texture.java +0 -1696
  141. data/lib/java/processing/opengl/VertexBuffer.java +0 -88
  142. data/lib/java/processing/pdf/PGraphicsPDF.java +0 -581
  143. data/lib/java/processing/svg/PGraphicsSVG.java +0 -378
  144. data/src/main/java/processing/opengl/cursors/arrow.png +0 -0
  145. data/src/main/java/processing/opengl/cursors/cross.png +0 -0
  146. data/src/main/java/processing/opengl/cursors/hand.png +0 -0
  147. data/src/main/java/processing/opengl/cursors/license.txt +0 -27
  148. data/src/main/java/processing/opengl/cursors/move.png +0 -0
  149. data/src/main/java/processing/opengl/cursors/text.png +0 -0
  150. data/src/main/java/processing/opengl/cursors/wait.png +0 -0
  151. data/src/main/java/processing/opengl/shaders/ColorFrag.glsl +0 -32
  152. data/src/main/java/processing/opengl/shaders/ColorVert.glsl +0 -34
  153. data/src/main/java/processing/opengl/shaders/LightFrag.glsl +0 -33
  154. data/src/main/java/processing/opengl/shaders/LightVert.glsl +0 -151
  155. data/src/main/java/processing/opengl/shaders/LineFrag.glsl +0 -32
  156. data/src/main/java/processing/opengl/shaders/LineVert.glsl +0 -100
  157. data/src/main/java/processing/opengl/shaders/MaskFrag.glsl +0 -40
  158. data/src/main/java/processing/opengl/shaders/PointFrag.glsl +0 -32
  159. data/src/main/java/processing/opengl/shaders/PointVert.glsl +0 -56
  160. data/src/main/java/processing/opengl/shaders/TexFrag.glsl +0 -37
  161. data/src/main/java/processing/opengl/shaders/TexLightFrag.glsl +0 -37
  162. data/src/main/java/processing/opengl/shaders/TexLightVert.glsl +0 -157
  163. data/src/main/java/processing/opengl/shaders/TexVert.glsl +0 -38
@@ -1,3377 +0,0 @@
1
- /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
-
3
- /*
4
- Part of the Processing project - http://processing.org
5
-
6
- Copyright (c) 2004-14 Ben Fry and Casey Reas
7
- Copyright (c) 2001-04 Massachusetts Institute of Technology
8
-
9
- This library is free software; you can redistribute it and/or
10
- modify it under the terms of the GNU Lesser General Public
11
- License as published by the Free Software Foundation; either
12
- version 2.1 of the License, or (at your option) any later version.
13
-
14
- This library is distributed in the hope that it will be useful,
15
- but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
- Lesser General Public License for more details.
18
-
19
- You should have received a copy of the GNU Lesser General
20
- Public License along with this library; if not, write to the
21
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
- Boston, MA 02111-1307 USA
23
- */
24
-
25
- package processing.core;
26
-
27
- import java.io.BufferedOutputStream;
28
- import java.io.File;
29
- import java.io.FileOutputStream;
30
- import java.io.IOException;
31
- import java.io.InputStream;
32
- import java.io.OutputStream;
33
-
34
-
35
- /**
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
- *
54
- * @webref image
55
- * @usage Web &amp; Application
56
- * @instanceName pimg any object of type PImage
57
- * @see PApplet#loadImage(String)
58
- * @see PApplet#imageMode(int)
59
- * @see PApplet#createImage(int, int, int)
60
- */
61
- public class PImage implements PConstants, Cloneable {
62
-
63
- private static final byte TIFF_HEADER[] = {
64
- 77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0,
65
- 0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1,
66
- 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0,
67
- 0, 0, 1, 0, 2, 0, 0, 1, 17, 0, 4, 0, 0, 0, 1, 0, 0, 3, 0, 1, 21,
68
- 0, 3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 22, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0,
69
- 1, 23, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8
70
- };
71
-
72
- private static final String TIFF_ERROR = "Error: Processing can only read its own TIFF files.";
73
-
74
- /**
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
78
- */
79
- public int format;
80
-
81
- /**
82
- * ( begin auto-generated from pixels.xml )
83
- *
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
- *
93
- * Before accessing this array, the data must loaded with the
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.
98
- *
99
- * ( end auto-generated )
100
- *
101
- * @webref image:pixels
102
- * @usage web_application
103
- * @brief Array containing the color of every pixel in the image
104
- */
105
- public int[] pixels;
106
-
107
- /** 1 for most images, 2 for hi-dpi/retina */
108
- public int pixelDensity = 1;
109
-
110
- /** Actual dimensions of pixels array, taking into account the 2x setting. */
111
- public int pixelWidth;
112
- public int pixelHeight;
113
-
114
- /**
115
- * ( begin auto-generated from PImage_width.xml )
116
- *
117
- * The width of the image in units of pixels.
118
- *
119
- * ( end auto-generated )
120
- * @webref pimage:field
121
- * @usage web_application
122
- * @brief Image width
123
- */
124
- public int width;
125
-
126
- /**
127
- * ( begin auto-generated from PImage_height.xml )
128
- *
129
- * The height of the image in units of pixels.
130
- *
131
- * ( end auto-generated )
132
- * @webref pimage:field
133
- * @usage web_application
134
- * @brief Image height
135
- */
136
- public int height;
137
-
138
- /**
139
- * Path to parent object that will be used with save().
140
- * This prevents users from needing savePath() to use PImage.save().
141
- */
142
- public PApplet parent;
143
-
144
-
145
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
146
-
147
-
148
- /** modified portion of the image */
149
- protected boolean modified;
150
- protected int mx1, my1, mx2, my2;
151
-
152
- /** Loaded pixels flag */
153
- public boolean loaded = false;
154
-
155
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
156
-
157
-
158
- // private fields
159
- private int fracU, ifU, fracV, ifV, u1, u2, v1, v2, sX, sY, iw, iw1, ih1;
160
- private int ul, ll, ur, lr, cUL, cLL, cUR, cLR;
161
- private int srcXOffset, srcYOffset;
162
- private int r, g, b, a;
163
- private int[] srcBuffer;
164
-
165
- // fixed point precision is limited to 15 bits!!
166
- static final int PRECISIONB = 15;
167
- static final int PRECISIONF = 1 << PRECISIONB;
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;
171
-
172
- // internal kernel stuff for the gaussian blur filter
173
- private int blurRadius;
174
- private int blurKernelSize;
175
- private int[] blurKernel;
176
- private int[][] blurMult;
177
-
178
- // colour component bitmasks (moved from PConstants in 2.0b7)
179
- public static final int ALPHA_MASK = 0xff000000;
180
- public static final int RED_MASK = 0x00ff0000;
181
- public static final int GREEN_MASK = 0x0000ff00;
182
- public static final int BLUE_MASK = 0x000000ff;
183
-
184
-
185
- //////////////////////////////////////////////////////////////
186
-
187
-
188
- /**
189
- * ( begin auto-generated from PImage.xml )
190
- *
191
- * Datatype for storing images. Processing can display <b>.gif</b>,
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
- *
201
- * Before using the <b>pixels[]</b> array, be sure to use the
202
- * <b>loadPixels()</b> method on the image to make sure that the pixel data
203
- * is properly loaded.
204
- *
205
- * To create a new image, use the <b>createImage()</b> function (do not use
206
- * <b>new PImage()</b>).
207
- * ( end auto-generated )
208
- * @nowebref
209
- * @usage web_application
210
- * @see PApplet#loadImage(String, String)
211
- * @see PApplet#imageMode(int)
212
- * @see PApplet#createImage(int, int, int)
213
- */
214
- public PImage() {
215
- format = ARGB; // default to ARGB images for release 0116
216
- pixelDensity = 1;
217
- }
218
-
219
-
220
- /**
221
- * @nowebref
222
- * @param width image width
223
- * @param height image height
224
- */
225
- public PImage(int width, int height) {
226
- init(width, height, RGB, 1);
227
-
228
- // toxi: is it maybe better to init the image with max alpha enabled?
229
- //for(int i=0; i<pixels.length; i++) pixels[i]=0xffffffff;
230
- // fry: i'm opting for the full transparent image, which is how
231
- // photoshop works, and our audience oughta be familiar with.
232
- // also, i want to avoid having to set all those pixels since
233
- // in java it's super slow, and most using this fxn will be
234
- // setting all the pixels anyway.
235
- // toxi: agreed and same reasons why i left it out ;)
236
- }
237
-
238
-
239
- /**
240
- * @nowebref
241
- * @param format Either RGB, ARGB, ALPHA (grayscale alpha channel)
242
- */
243
- public PImage(int width, int height, int format) {
244
- init(width, height, format, 1);
245
- }
246
-
247
-
248
- public PImage(int width, int height, int format, int factor) {
249
- init(width, height, format, factor);
250
- }
251
-
252
-
253
- /**
254
- * Do not remove, see notes in the other variant.
255
- */
256
- public void init(int width, int height, int format) { // ignore
257
- init(width, height, format, 1);
258
- }
259
-
260
-
261
- /**
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.)
267
- */
268
- public void init(int width, int height, int format, int factor) { // ignore
269
- this.width = width;
270
- this.height = height;
271
- this.format = format;
272
- this.pixelDensity = factor;
273
-
274
- pixelWidth = width * pixelDensity;
275
- pixelHeight = height * pixelDensity;
276
- this.pixels = new int[pixelWidth * pixelHeight];
277
- }
278
-
279
-
280
- /**
281
- * Check the alpha on an image, using a really primitive loop.
282
- */
283
- public void checkAlpha() {
284
- if (pixels == null) return;
285
-
286
- for (int i = 0; i < pixels.length; i++) {
287
- // since transparency is often at corners, hopefully this
288
- // will find a non-transparent pixel quickly and exit
289
- if ((pixels[i] & 0xff000000) != 0xff000000) {
290
- format = ARGB;
291
- break;
292
- }
293
- }
294
- }
295
-
296
-
297
- //////////////////////////////////////////////////////////////
298
-
299
- public PImage(int width, int height, int[] pixels, boolean requiresCheckAlpha, PApplet parent) {
300
- initFromPixels(
301
- width,
302
- height,
303
- pixels,
304
- RGB,
305
- 1
306
- );
307
-
308
- this.parent = parent;
309
-
310
- if (requiresCheckAlpha) {
311
- checkAlpha();
312
- }
313
- }
314
-
315
- public PImage(int width, int height, int[] pixels, boolean requiresCheckAlpha, PApplet parent,
316
- int format, int factor) {
317
-
318
- initFromPixels(width, height, pixels, format, factor);
319
- this.parent = parent;
320
-
321
- if (requiresCheckAlpha) {
322
- checkAlpha();
323
- }
324
- }
325
-
326
- private void initFromPixels(int width, int height, int[] pixels, int format, int factor) {
327
- this.width = width;
328
- this.height = height;
329
- this.format = format;
330
- this.pixelDensity = factor;
331
- this.pixels = pixels;
332
- }
333
-
334
-
335
- public Object getNative() { // ignore
336
- return null;
337
- }
338
-
339
-
340
- //////////////////////////////////////////////////////////////
341
-
342
- // MARKING IMAGE AS MODIFIED / FOR USE w/ GET/SET
343
-
344
-
345
- public boolean isModified() { // ignore
346
- return modified;
347
- }
348
-
349
-
350
- public void setModified() { // ignore
351
- modified = true;
352
- mx1 = 0;
353
- my1 = 0;
354
- mx2 = pixelWidth;
355
- my2 = pixelHeight;
356
- }
357
-
358
-
359
- public void setModified(boolean m) { // ignore
360
- modified = m;
361
- }
362
-
363
-
364
- public int getModifiedX1() { // ignore
365
- return mx1;
366
- }
367
-
368
-
369
- public int getModifiedX2() { // ignore
370
- return mx2;
371
- }
372
-
373
-
374
- public int getModifiedY1() { // ignore
375
- return my1;
376
- }
377
-
378
-
379
- public int getModifiedY2() { // ignore
380
- return my2;
381
- }
382
-
383
-
384
- /**
385
- * ( begin auto-generated from PImage_loadPixels.xml )
386
- *
387
- * Loads the pixel data for the image into its <b>pixels[]</b> array. This
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>
390
- * or <b>updatePixels()</b>. However, the rule is that any time you want to
391
- * manipulate the <b>pixels[]</b> array, you must first call
392
- * <b>loadPixels()</b>, and after changes have been made, call
393
- * <b>updatePixels()</b>. Even if the renderer may not seem to use this
394
- * function in the current Processing release, this will always be subject
395
- * to change.
396
- *
397
- * ( end auto-generated )
398
- *
399
- * <h3>Advanced</h3>
400
- * Call this when you want to mess with 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
404
- *
405
- * @webref pimage:pixels
406
- * @brief Loads the pixel data for the image into its pixels[] array
407
- * @usage web_application
408
- */
409
- public void loadPixels() { // ignore
410
- if (pixels == null || pixels.length != pixelWidth*pixelHeight) {
411
- pixels = new int[pixelWidth*pixelHeight];
412
- }
413
- setLoaded();
414
- }
415
-
416
-
417
- public void updatePixels() { // ignore
418
- updatePixels(0, 0, pixelWidth, pixelHeight);
419
- }
420
-
421
-
422
- /**
423
- * ( begin auto-generated from PImage_updatePixels.xml )
424
- *
425
- * Updates the image with the data in its <b>pixels[]</b> array. Use in
426
- * conjunction with <b>loadPixels()</b>. If you're only reading pixels from
427
- * the array, there's no need to call <b>updatePixels()</b>.
428
- * renderers may or may not seem to require <b>loadPixels()</b>
429
- * or <b>updatePixels()</b>. However, the rule is that any time you want to
430
- * manipulate the <b>pixels[]</b> array, you must first call
431
- * <b>loadPixels()</b>, and after changes have been made, call
432
- * <b>updatePixels()</b>. Even if the renderer may not seem to use this
433
- * function in the current Processing release, this will always be subject
434
- * to change.
435
- *
436
- * Currently, none of the renderers use the additional parameters to
437
- * <b>updatePixels()</b>, however this may be implemented in the future.
438
- *
439
- * ( end auto-generated )
440
- * <h3>Advanced</h3>
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.
445
- * @webref pimage:pixels
446
- * @brief Updates the image with the data in its pixels[] array
447
- * @usage web_application
448
- * @param x x-coordinate of the upper-left corner
449
- * @param y y-coordinate of the upper-left corner
450
- * @param w width
451
- * @param h height
452
- */
453
- public void updatePixels(int x, int y, int w, int h) { // ignore
454
- int x2 = x + w;
455
- int y2 = y + h;
456
-
457
- if (!modified) {
458
- mx1 = PApplet.max(0, x);
459
- mx2 = PApplet.min(pixelWidth, x2);
460
- my1 = PApplet.max(0, y);
461
- my2 = PApplet.min(pixelHeight, y2);
462
- modified = true;
463
-
464
- } else {
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);
469
-
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);
474
- }
475
- }
476
-
477
-
478
- //////////////////////////////////////////////////////////////
479
-
480
- // COPYING IMAGE DATA
481
-
482
-
483
- /**
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
489
- * CloneNotSupportedException, and from doing a cast from the result.
490
- */
491
- @Override
492
- public Object clone() throws CloneNotSupportedException { // ignore
493
- return get();
494
- }
495
-
496
-
497
- /**
498
- * ( begin auto-generated from PImage_resize.xml )
499
- *
500
- * Resize the image to a new width and height. To make the image scale
501
- * proportionally, use 0 as the value for the <b>wide</b> or <b>high</b>
502
- * parameter. For instance, to make the width of an image 150 pixels, and
503
- * change the height using the same proportion, use resize(150, 0).
504
- *
505
- * Even though a PGraphics is technically a PImage, it is not possible to
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>
510
- * method, and call <b>resize()</b> on the PImage that is returned.
511
- *
512
- * ( end auto-generated )
513
- * @webref pimage:method
514
- * @brief Changes the size of an image to a new width and height
515
- * @usage web_application
516
- * @param w the resized image width
517
- * @param h the resized image height
518
- * @see PImage#get(int, int, int, int)
519
- */
520
- public void resize(int w, int h) { // ignore
521
- throw new RuntimeException("resize() not implemented for this PImage type");
522
- }
523
-
524
-
525
- //////////////////////////////////////////////////////////////
526
-
527
- // MARKING IMAGE AS LOADED / FOR USE IN RENDERERS
528
-
529
-
530
- public boolean isLoaded() { // ignore
531
- return loaded;
532
- }
533
-
534
-
535
- public void setLoaded() { // ignore
536
- loaded = true;
537
- }
538
-
539
-
540
- public void setLoaded(boolean l) { // ignore
541
- loaded = l;
542
- }
543
-
544
-
545
- //////////////////////////////////////////////////////////////
546
-
547
- // GET/SET PIXELS
548
-
549
-
550
- /**
551
- * ( begin auto-generated from PImage_get.xml )
552
- *
553
- * Reads the color of any pixel or grabs a section of an image. If no
554
- * parameters are specified, the entire image is returned. Use the <b>x</b>
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
557
- * <b>height</b> parameter. When getting an image, the <b>x</b> and
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.
571
- *
572
- * ( end auto-generated )
573
- *
574
- * <h3>Advanced</h3>
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).
578
- * <P>
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.
582
- * <P>
583
- * If the image is in ALPHA format, this returns a white with its
584
- * alpha value set.
585
- * <P>
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.
591
- *
592
- * @webref image:pixels
593
- * @brief Reads the color of any pixel or grabs a rectangle of pixels
594
- * @usage web_application
595
- * @param x x-coordinate of the pixel
596
- * @param y y-coordinate of the pixel
597
- * @see PApplet#set(int, int, int)
598
- * @see PApplet#pixels
599
- * @see PApplet#copy(PImage, int, int, int, int, int, int, int, int)
600
- */
601
- public int get(int x, int y) {
602
- if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return 0;
603
-
604
- switch (format) {
605
- case RGB:
606
- return pixels[y*pixelWidth + x] | 0xff000000;
607
-
608
- case ARGB:
609
- return pixels[y*pixelWidth + x];
610
-
611
- case ALPHA:
612
- return (pixels[y*pixelWidth + x] << 24) | 0xffffff;
613
- }
614
- return 0;
615
- }
616
-
617
-
618
- /**
619
- * @param w width of pixel rectangle to get
620
- * @param h height of pixel rectangle to get
621
- */
622
- public PImage get(int x, int y, int w, int h) {
623
- int targetX = 0;
624
- int targetY = 0;
625
- int targetWidth = w;
626
- int targetHeight = h;
627
- boolean cropped = false;
628
-
629
- if (x < 0) {
630
- w += x; // x is negative, removes the left edge from the width
631
- targetX = -x;
632
- cropped = true;
633
- x = 0;
634
- }
635
- if (y < 0) {
636
- h += y; // y is negative, clip the number of rows
637
- targetY = -y;
638
- cropped = true;
639
- y = 0;
640
- }
641
-
642
- if (x + w > pixelWidth) {
643
- w = pixelWidth - x;
644
- cropped = true;
645
- }
646
- if (y + h > pixelHeight) {
647
- h = pixelHeight - y;
648
- cropped = true;
649
- }
650
-
651
- if (w < 0) {
652
- w = 0;
653
- }
654
- if (h < 0) {
655
- h = 0;
656
- }
657
-
658
- int targetFormat = format;
659
- if (cropped && format == RGB) {
660
- targetFormat = ARGB;
661
- }
662
-
663
- PImage target = new PImage(targetWidth / pixelDensity,
664
- targetHeight / pixelDensity,
665
- targetFormat, pixelDensity);
666
- target.parent = parent; // parent may be null so can't use createImage()
667
- if (w > 0 && h > 0) {
668
- getImpl(x, y, w, h, target, targetX, targetY);
669
- }
670
- return target;
671
- }
672
-
673
-
674
- /**
675
- * Returns a copy of this PImage. Equivalent to get(0, 0, width, height).
676
- * Deprecated, just use copy() instead.
677
- */
678
- public PImage get() {
679
- // Formerly this used clone(), which caused memory problems.
680
- // http://code.google.com/p/processing/issues/detail?id=42
681
- return get(0, 0, pixelWidth, pixelHeight);
682
- }
683
-
684
-
685
- public PImage copy() {
686
- return get(0, 0, pixelWidth, pixelHeight);
687
- }
688
-
689
-
690
- /**
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.
695
- */
696
- protected void getImpl(int sourceX, int sourceY,
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;
701
- for (int row = 0; row < sourceHeight; row++) {
702
- System.arraycopy(pixels, sourceIndex, target.pixels, targetIndex, sourceWidth);
703
- sourceIndex += pixelWidth;
704
- targetIndex += target.pixelWidth;
705
- }
706
- }
707
-
708
-
709
- /**
710
- * ( begin auto-generated from PImage_set.xml )
711
- *
712
- * Changes the color of any pixel or writes an image directly into the
713
- * display window.
714
- *
715
- * The <b>x</b> and <b>y</b> parameters specify the pixel to change and the
716
- * <b>color</b> parameter specifies the color value. The color parameter is
717
- * affected by the current color mode (the default is RGB values from 0 to
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>
725
- * is <b>pixels[y*width+x] = #000000</b>. See the reference for
726
- * <b>pixels[]</b> for more information.
727
- *
728
- * ( end auto-generated )
729
- *
730
- * @webref image:pixels
731
- * @brief writes a color to any pixel or writes an image into another
732
- * @usage web_application
733
- * @param x x-coordinate of the pixel
734
- * @param y y-coordinate of the pixel
735
- * @param c any value of the color datatype
736
- * @see PImage#get(int, int, int, int)
737
- * @see PImage#pixels
738
- * @see PImage#copy(PImage, int, int, int, int, int, int, int, int)
739
- */
740
- public void set(int x, int y, int c) {
741
- if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return;
742
- pixels[y*pixelWidth + x] = c;
743
- updatePixels(x, y, 1, 1); // slow...
744
- }
745
-
746
-
747
- /**
748
- * <h3>Advanced</h3>
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.
752
- *
753
- * @param img image to copy into the original image
754
- */
755
- public void set(int x, int y, PImage img) {
756
- int sx = 0;
757
- int sy = 0;
758
- int sw = img.pixelWidth;
759
- int sh = img.pixelHeight;
760
-
761
- if (x < 0) { // off left edge
762
- sx -= x;
763
- sw += x;
764
- x = 0;
765
- }
766
- if (y < 0) { // off top edge
767
- sy -= y;
768
- sh += y;
769
- y = 0;
770
- }
771
- if (x + sw > pixelWidth) { // off right edge
772
- sw = pixelWidth - x;
773
- }
774
- if (y + sh > pixelHeight) { // off bottom edge
775
- sh = pixelHeight - y;
776
- }
777
-
778
- // this could be nonexistent
779
- if ((sw <= 0) || (sh <= 0)) return;
780
-
781
- setImpl(img, sx, sy, sw, sh, x, y);
782
- }
783
-
784
-
785
- /**
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.
788
- */
789
- protected void setImpl(PImage sourceImage,
790
- int sourceX, int sourceY,
791
- int sourceWidth, int sourceHeight,
792
- int targetX, int targetY) {
793
- int sourceOffset = sourceY * sourceImage.pixelWidth + sourceX;
794
- int targetOffset = targetY * pixelWidth + targetX;
795
-
796
- for (int y = sourceY; y < sourceY + sourceHeight; y++) {
797
- System.arraycopy(sourceImage.pixels, sourceOffset, pixels, targetOffset, sourceWidth);
798
- sourceOffset += sourceImage.pixelWidth;
799
- targetOffset += pixelWidth;
800
- }
801
-
802
- //updatePixelsImpl(targetX, targetY, sourceWidth, sourceHeight);
803
- updatePixels(targetX, targetY, sourceWidth, sourceHeight);
804
- }
805
-
806
-
807
-
808
- //////////////////////////////////////////////////////////////
809
-
810
- // ALPHA CHANNEL
811
-
812
-
813
- /**
814
- * @param maskArray array of integers used as the alpha channel, needs to be
815
- * the same length as the image's pixel array.
816
- */
817
- public void mask(int[] maskArray) { // ignore
818
- loadPixels();
819
- // don't execute if mask image is different size
820
- if (maskArray.length != pixels.length) {
821
- throw new IllegalArgumentException("mask() can only be used with an image that's the same size.");
822
- }
823
- for (int i = 0; i < pixels.length; i++) {
824
- pixels[i] = ((maskArray[i] & 0xff) << 24) | (pixels[i] & 0xffffff);
825
- }
826
- format = ARGB;
827
- updatePixels();
828
- }
829
-
830
-
831
- /**
832
- * ( begin auto-generated from PImage_mask.xml )
833
- *
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
- *
839
- * In addition to using a mask image, an integer array containing the alpha
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.
844
- *
845
- * ( end auto-generated )
846
- *
847
- * <h3>Advanced</h3>
848
- *
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.
853
- * <P>
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
859
- * performing a proper luminance-based conversion.
860
- *
861
- * @webref pimage:method
862
- * @usage web_application
863
- * @param img image to use as the mask
864
- * @brief Masks part of an image with another image as an alpha channel
865
- */
866
- public void mask(PImage img) {
867
- img.loadPixels();
868
- mask(img.pixels);
869
- }
870
-
871
-
872
-
873
- //////////////////////////////////////////////////////////////
874
-
875
- // IMAGE FILTERS
876
-
877
-
878
- public void filter(int kind) {
879
- loadPixels();
880
-
881
- switch (kind) {
882
- case BLUR:
883
- // TODO write basic low-pass filter blur here
884
- // what does photoshop do on the edges with this guy?
885
- // better yet.. why bother? just use gaussian with radius 1
886
- filter(BLUR, 1);
887
- break;
888
-
889
- case GRAY:
890
- if (format == ALPHA) {
891
- // for an alpha image, convert it to an opaque grayscale
892
- for (int i = 0; i < pixels.length; i++) {
893
- int col = 255 - pixels[i];
894
- pixels[i] = 0xff000000 | (col << 16) | (col << 8) | col;
895
- }
896
- format = RGB;
897
-
898
- } else {
899
- // Converts RGB image data into grayscale using
900
- // weighted RGB components, and keeps alpha channel intact.
901
- // [toxi 040115]
902
- for (int i = 0; i < pixels.length; i++) {
903
- int col = pixels[i];
904
- // luminance = 0.3*red + 0.59*green + 0.11*blue
905
- // 0.30 * 256 = 77
906
- // 0.59 * 256 = 151
907
- // 0.11 * 256 = 28
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;
910
- }
911
- }
912
- break;
913
-
914
- case INVERT:
915
- for (int i = 0; i < pixels.length; i++) {
916
- //pixels[i] = 0xff000000 |
917
- pixels[i] ^= 0xffffff;
918
- }
919
- break;
920
-
921
- case POSTERIZE:
922
- throw new RuntimeException("Use filter(POSTERIZE, int levels) " +
923
- "instead of filter(POSTERIZE)");
924
-
925
- case OPAQUE:
926
- for (int i = 0; i < pixels.length; i++) {
927
- pixels[i] |= 0xff000000;
928
- }
929
- format = RGB;
930
- break;
931
-
932
- case THRESHOLD:
933
- filter(THRESHOLD, 0.5f);
934
- break;
935
-
936
- // [toxi 050728] added new filters
937
- case ERODE:
938
- erode(); // former dilate(true);
939
- break;
940
-
941
- case DILATE:
942
- dilate(); // former dilate(false);
943
- break;
944
- }
945
- updatePixels(); // mark as modified
946
- }
947
-
948
-
949
- /**
950
- * ( begin auto-generated from PImage_filter.xml )
951
- *
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
- *
958
- * GRAY - converts any colors in the image to grayscale equivalents
959
- *
960
- * INVERT - sets each pixel to its inverse value
961
- *
962
- * POSTERIZE - limits each channel of the image to the number of colors
963
- * specified as the level parameter
964
- *
965
- * BLUR - executes a Guassian blur with the level parameter specifying the
966
- * extent of the blurring. If no level parameter is used, the blur is
967
- * equivalent to Guassian blur of radius 1
968
- *
969
- * OPAQUE - sets the alpha channel to entirely opaque
970
- *
971
- * ERODE - reduces the light areas with the amount defined by the level
972
- * parameter
973
- *
974
- * DILATE - increases the light areas with the amount defined by the level parameter
975
- *
976
- * ( end auto-generated )
977
- *
978
- * <h3>Advanced</h3>
979
- * Method to apply a variety of basic filters to this image.
980
- * <P>
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>
990
- * Luminance conversion code contributed by
991
- * <A HREF="http://www.toxi.co.uk">toxi</A>
992
- *
993
- * Gaussian blur code contributed by
994
- * <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A>
995
- *
996
- * @webref image:pixels
997
- * @brief Converts the image to grayscale or black and white
998
- * @usage web_application
999
- * @param kind Either THRESHOLD, GRAY, OPAQUE, INVERT, POSTERIZE, BLUR, ERODE, or DILATE
1000
- * @param param unique for each, see above
1001
- */
1002
- public void filter(int kind, float param) {
1003
- loadPixels();
1004
-
1005
- switch (kind) {
1006
- case BLUR:
1007
- switch (format) {
1008
- case ALPHA:
1009
- blurAlpha(param);
1010
- break;
1011
- case ARGB:
1012
- blurARGB(param);
1013
- break;
1014
- default:
1015
- blurRGB(param);
1016
- break;
1017
- }
1018
- break;
1019
-
1020
-
1021
- case GRAY:
1022
- throw new RuntimeException("Use filter(GRAY) instead of " +
1023
- "filter(GRAY, param)");
1024
-
1025
- case INVERT:
1026
- throw new RuntimeException("Use filter(INVERT) instead of " +
1027
- "filter(INVERT, param)");
1028
-
1029
- case OPAQUE:
1030
- throw new RuntimeException("Use filter(OPAQUE) instead of " +
1031
- "filter(OPAQUE, param)");
1032
-
1033
- case POSTERIZE:
1034
- int levels = (int)param;
1035
- if ((levels < 2) || (levels > 255)) {
1036
- throw new RuntimeException("Levels must be between 2 and 255 for " +
1037
- "filter(POSTERIZE, levels)");
1038
- }
1039
- int levels1 = levels - 1;
1040
- for (int i = 0; i < pixels.length; i++) {
1041
- int rlevel = (pixels[i] >> 16) & 0xff;
1042
- int glevel = (pixels[i] >> 8) & 0xff;
1043
- int blevel = pixels[i] & 0xff;
1044
- rlevel = (((rlevel * levels) >> 8) * 255) / levels1;
1045
- glevel = (((glevel * levels) >> 8) * 255) / levels1;
1046
- blevel = (((blevel * levels) >> 8) * 255) / levels1;
1047
- pixels[i] = ((0xff000000 & pixels[i]) |
1048
- (rlevel << 16) |
1049
- (glevel << 8) |
1050
- blevel);
1051
- }
1052
- break;
1053
-
1054
- case THRESHOLD: // greater than or equal to the threshold
1055
- int thresh = (int) (param * 255);
1056
- for (int i = 0; i < pixels.length; i++) {
1057
- int max = Math.max((pixels[i] & RED_MASK) >> 16,
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);
1062
- }
1063
- break;
1064
-
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)");
1072
- }
1073
- updatePixels(); // mark as modified
1074
- }
1075
-
1076
-
1077
- /** Set the high bits of all pixels to opaque. */
1078
- protected void opaque() {
1079
- for (int i = 0; i < pixels.length; i++) {
1080
- pixels[i] = 0xFF000000 | pixels[i];
1081
- }
1082
- }
1083
-
1084
-
1085
- /**
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]
1091
- */
1092
- protected void buildBlurKernel(float r) {
1093
- int radius = (int) (r * 3.5f);
1094
- radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248);
1095
- if (blurRadius != radius) {
1096
- blurRadius = radius;
1097
- blurKernelSize = 1 + blurRadius<<1;
1098
- blurKernel = new int[blurKernelSize];
1099
- blurMult = new int[blurKernelSize][256];
1100
-
1101
- int bk,bki;
1102
- int[] bm,bmi;
1103
-
1104
- for (int i = 1, radiusi = radius - 1; i < radius; i++) {
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;
1110
- }
1111
- bk = blurKernel[radius] = radius * radius;
1112
- bm = blurMult[radius];
1113
- for (int j = 0; j < 256; j++)
1114
- bm[j] = bk*j;
1115
- }
1116
- }
1117
-
1118
-
1119
- protected void blurAlpha(float r) {
1120
- int sum, cb;
1121
- int read, ri, ym, ymi, bk0;
1122
- int[] b2 = new int[pixels.length];
1123
- int yi = 0;
1124
-
1125
- buildBlurKernel(r);
1126
-
1127
- for (int y = 0; y < pixelHeight; y++) {
1128
- for (int x = 0; x < pixelWidth; x++) {
1129
- //cb = cg = cr = sum = 0;
1130
- cb = sum = 0;
1131
- read = x - blurRadius;
1132
- if (read<0) {
1133
- bk0=-read;
1134
- read=0;
1135
- } else {
1136
- if (read >= pixelWidth)
1137
- break;
1138
- bk0=0;
1139
- }
1140
- for (int i = bk0; i < blurKernelSize; i++) {
1141
- if (read >= pixelWidth)
1142
- break;
1143
- int c = pixels[read + yi];
1144
- int[] bm = blurMult[i];
1145
- cb += bm[c & BLUE_MASK];
1146
- sum += blurKernel[i];
1147
- read++;
1148
- }
1149
- ri = yi + x;
1150
- b2[ri] = cb / sum;
1151
- }
1152
- yi += pixelWidth;
1153
- }
1154
-
1155
- yi = 0;
1156
- ym = -blurRadius;
1157
- ymi = ym * pixelWidth;
1158
-
1159
- for (int y = 0; y < pixelHeight; y++) {
1160
- for (int x = 0; x < pixelWidth; x++) {
1161
- cb = sum = 0;
1162
- if (ym < 0) {
1163
- bk0 = ri = -ym;
1164
- read = x;
1165
- } else {
1166
- if (ym >= pixelHeight)
1167
- break;
1168
- bk0 = 0;
1169
- ri = ym;
1170
- read = x + ymi;
1171
- }
1172
- for (int i = bk0; i < blurKernelSize; i++) {
1173
- if (ri >= pixelHeight)
1174
- break;
1175
- int[] bm = blurMult[i];
1176
- cb += bm[b2[read]];
1177
- sum += blurKernel[i];
1178
- ri++;
1179
- read += pixelWidth;
1180
- }
1181
- pixels[x+yi] = (cb/sum);
1182
- }
1183
- yi += pixelWidth;
1184
- ymi += pixelWidth;
1185
- ym++;
1186
- }
1187
- }
1188
-
1189
-
1190
- protected void blurRGB(float r) {
1191
- int sum, cr, cg, cb; //, k;
1192
- int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
1193
- int[] r2 = new int[pixels.length];
1194
- int[] g2 = new int[pixels.length];
1195
- int[] b2 = new int[pixels.length];
1196
- int yi = 0;
1197
-
1198
- buildBlurKernel(r);
1199
-
1200
- for (int y = 0; y < pixelHeight; y++) {
1201
- for (int x = 0; x < pixelWidth; x++) {
1202
- cb = cg = cr = sum = 0;
1203
- read = x - blurRadius;
1204
- if (read < 0) {
1205
- bk0 = -read;
1206
- read = 0;
1207
- } else {
1208
- if (read >= pixelWidth) {
1209
- break;
1210
- }
1211
- bk0 = 0;
1212
- }
1213
- for (int i = bk0; i < blurKernelSize; i++) {
1214
- if (read >= pixelWidth) {
1215
- break;
1216
- }
1217
- int c = pixels[read + yi];
1218
- int[] bm = blurMult[i];
1219
- cr += bm[(c & RED_MASK) >> 16];
1220
- cg += bm[(c & GREEN_MASK) >> 8];
1221
- cb += bm[c & BLUE_MASK];
1222
- sum += blurKernel[i];
1223
- read++;
1224
- }
1225
- ri = yi + x;
1226
- r2[ri] = cr / sum;
1227
- g2[ri] = cg / sum;
1228
- b2[ri] = cb / sum;
1229
- }
1230
- yi += pixelWidth;
1231
- }
1232
-
1233
- yi = 0;
1234
- ym = -blurRadius;
1235
- ymi = ym * pixelWidth;
1236
-
1237
- for (int y = 0; y < pixelHeight; y++) {
1238
- for (int x = 0; x < pixelWidth; x++) {
1239
- cb = cg = cr = sum = 0;
1240
- if (ym < 0) {
1241
- bk0 = ri = -ym;
1242
- read = x;
1243
- } else {
1244
- if (ym >= pixelHeight) {
1245
- break;
1246
- }
1247
- bk0 = 0;
1248
- ri = ym;
1249
- read = x + ymi;
1250
- }
1251
- for (int i = bk0; i < blurKernelSize; i++) {
1252
- if (ri >= pixelHeight) {
1253
- break;
1254
- }
1255
- int[] bm = blurMult[i];
1256
- cr += bm[r2[read]];
1257
- cg += bm[g2[read]];
1258
- cb += bm[b2[read]];
1259
- sum += blurKernel[i];
1260
- ri++;
1261
- read += pixelWidth;
1262
- }
1263
- pixels[x+yi] = 0xff000000 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum);
1264
- }
1265
- yi += pixelWidth;
1266
- ymi += pixelWidth;
1267
- ym++;
1268
- }
1269
- }
1270
-
1271
-
1272
- protected void blurARGB(float r) {
1273
- int sum, cr, cg, cb, ca;
1274
- int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
1275
- int wh = pixels.length;
1276
- int[] r2 = new int[wh];
1277
- int[] g2 = new int[wh];
1278
- int[] b2 = new int[wh];
1279
- int[] a2 = new int[wh];
1280
- int yi = 0;
1281
-
1282
- buildBlurKernel(r);
1283
-
1284
- for (int y = 0; y < pixelHeight; y++) {
1285
- for (int x = 0; x < pixelWidth; x++) {
1286
- cb = cg = cr = ca = sum = 0;
1287
- read = x - blurRadius;
1288
- if (read < 0) {
1289
- bk0 = -read;
1290
- read = 0;
1291
- } else {
1292
- if (read >= pixelWidth) {
1293
- break;
1294
- }
1295
- bk0=0;
1296
- }
1297
- for (int i = bk0; i < blurKernelSize; i++) {
1298
- if (read >= pixelWidth) {
1299
- break;
1300
- }
1301
- int c = pixels[read + yi];
1302
- int[] bm=blurMult[i];
1303
- ca += bm[(c & ALPHA_MASK) >>> 24];
1304
- cr += bm[(c & RED_MASK) >> 16];
1305
- cg += bm[(c & GREEN_MASK) >> 8];
1306
- cb += bm[c & BLUE_MASK];
1307
- sum += blurKernel[i];
1308
- read++;
1309
- }
1310
- ri = yi + x;
1311
- a2[ri] = ca / sum;
1312
- r2[ri] = cr / sum;
1313
- g2[ri] = cg / sum;
1314
- b2[ri] = cb / sum;
1315
- }
1316
- yi += pixelWidth;
1317
- }
1318
-
1319
- yi = 0;
1320
- ym = -blurRadius;
1321
- ymi = ym * pixelWidth;
1322
-
1323
- for (int y = 0; y < pixelHeight; y++) {
1324
- for (int x = 0; x < pixelWidth; x++) {
1325
- cb = cg = cr = ca = sum = 0;
1326
- if (ym < 0) {
1327
- bk0 = ri = -ym;
1328
- read = x;
1329
- } else {
1330
- if (ym >= pixelHeight) {
1331
- break;
1332
- }
1333
- bk0 = 0;
1334
- ri = ym;
1335
- read = x + ymi;
1336
- }
1337
- for (int i = bk0; i < blurKernelSize; i++) {
1338
- if (ri >= pixelHeight) {
1339
- break;
1340
- }
1341
- int[] bm=blurMult[i];
1342
- ca += bm[a2[read]];
1343
- cr += bm[r2[read]];
1344
- cg += bm[g2[read]];
1345
- cb += bm[b2[read]];
1346
- sum += blurKernel[i];
1347
- ri++;
1348
- read += pixelWidth;
1349
- }
1350
- pixels[x+yi] = (ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum);
1351
- }
1352
- yi += pixelWidth;
1353
- ymi += pixelWidth;
1354
- ym++;
1355
- }
1356
- }
1357
-
1358
-
1359
- /**
1360
- * Generic dilate/erode filter using luminance values
1361
- * as decision factor. [toxi 050728]
1362
- */
1363
- protected void dilate() { // formerly dilate(false)
1364
- int index = 0;
1365
- int maxIndex = pixels.length;
1366
- int[] outgoing = new int[maxIndex];
1367
-
1368
- // erosion (grow light areas)
1369
- while (index < maxIndex) {
1370
- int curRowIndex = index;
1371
- int maxRowIndex = index + pixelWidth;
1372
- while (index < maxRowIndex) {
1373
- int orig = pixels[index];
1374
- int result = orig;
1375
- int idxLeft = index - 1;
1376
- int idxRight = index + 1;
1377
- int idxUp = index - pixelWidth;
1378
- int idxDown = index + pixelWidth;
1379
- if (idxLeft < curRowIndex) {
1380
- idxLeft = index;
1381
- }
1382
- if (idxRight >= maxRowIndex) {
1383
- idxRight = index;
1384
- }
1385
- if (idxUp < 0) {
1386
- idxUp = index;
1387
- }
1388
- if (idxDown >= maxIndex) {
1389
- idxDown = index;
1390
- }
1391
-
1392
- int colUp = pixels[idxUp];
1393
- int colLeft = pixels[idxLeft];
1394
- int colDown = pixels[idxDown];
1395
- int colRight = pixels[idxRight];
1396
-
1397
- // compute luminance
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);
1408
-
1409
- if (lumLeft > currLum) {
1410
- result = colLeft;
1411
- currLum = lumLeft;
1412
- }
1413
- if (lumRight > currLum) {
1414
- result = colRight;
1415
- currLum = lumRight;
1416
- }
1417
- if (lumUp > currLum) {
1418
- result = colUp;
1419
- currLum = lumUp;
1420
- }
1421
- if (lumDown > currLum) {
1422
- result = colDown;
1423
- currLum = lumDown;
1424
- }
1425
- outgoing[index++] = result;
1426
- }
1427
- }
1428
- System.arraycopy(outgoing, 0, pixels, 0, maxIndex);
1429
- }
1430
-
1431
-
1432
- protected void erode() { // formerly dilate(true)
1433
- int index = 0;
1434
- int maxIndex = pixels.length;
1435
- int[] outgoing = new int[maxIndex];
1436
-
1437
- // dilate (grow dark areas)
1438
- while (index < maxIndex) {
1439
- int curRowIndex = index;
1440
- int maxRowIndex = index + pixelWidth;
1441
- while (index < maxRowIndex) {
1442
- int orig = pixels[index];
1443
- int result = orig;
1444
- int idxLeft = index - 1;
1445
- int idxRight = index + 1;
1446
- int idxUp = index - pixelWidth;
1447
- int idxDown = index + pixelWidth;
1448
- if (idxLeft < curRowIndex) {
1449
- idxLeft = index;
1450
- }
1451
- if (idxRight >= maxRowIndex) {
1452
- idxRight = index;
1453
- }
1454
- if (idxUp < 0) {
1455
- idxUp = index;
1456
- }
1457
- if (idxDown >= maxIndex) {
1458
- idxDown = index;
1459
- }
1460
-
1461
- int colUp = pixels[idxUp];
1462
- int colLeft = pixels[idxLeft];
1463
- int colDown = pixels[idxDown];
1464
- int colRight = pixels[idxRight];
1465
-
1466
- // compute luminance
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);
1477
-
1478
- if (lumLeft < currLum) {
1479
- result = colLeft;
1480
- currLum = lumLeft;
1481
- }
1482
- if (lumRight < currLum) {
1483
- result = colRight;
1484
- currLum = lumRight;
1485
- }
1486
- if (lumUp < currLum) {
1487
- result = colUp;
1488
- currLum = lumUp;
1489
- }
1490
- if (lumDown < currLum) {
1491
- result = colDown;
1492
- currLum = lumDown;
1493
- }
1494
- outgoing[index++] = result;
1495
- }
1496
- }
1497
- System.arraycopy(outgoing, 0, pixels, 0, maxIndex);
1498
- }
1499
-
1500
-
1501
-
1502
- //////////////////////////////////////////////////////////////
1503
-
1504
- // COPY
1505
-
1506
-
1507
- /**
1508
- * ( begin auto-generated from PImage_copy.xml )
1509
- *
1510
- * Copies a region of pixels from one image into another. If the source and
1511
- * destination regions aren't the same size, it will automatically resize
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
- *
1516
- * As of release 0149, this function ignores <b>imageMode()</b>.
1517
- *
1518
- * ( end auto-generated )
1519
- *
1520
- * @webref image:pixels
1521
- * @brief Copies the entire image
1522
- * @usage web_application
1523
- * @param sx X coordinate of the source's upper left corner
1524
- * @param sy Y coordinate of the source's upper left corner
1525
- * @param sw source image width
1526
- * @param sh source image height
1527
- * @param dx X coordinate of the destination's upper left corner
1528
- * @param dy Y coordinate of the destination's upper left corner
1529
- * @param dw destination image width
1530
- * @param dh destination image height
1531
- * @see PGraphics#alpha(int)
1532
- * @see PImage#blend(PImage, int, int, int, int, int, int, int, int, int)
1533
- */
1534
- public void copy(int sx, int sy, int sw, int sh,
1535
- int dx, int dy, int dw, int dh) {
1536
- blend(this, sx, sy, sw, sh, dx, dy, dw, dh, REPLACE);
1537
- }
1538
-
1539
-
1540
- /**
1541
- * @param src an image variable referring to the source image.
1542
- */
1543
- public void copy(PImage src,
1544
- int sx, int sy, int sw, int sh,
1545
- int dx, int dy, int dw, int dh) {
1546
- blend(src, sx, sy, sw, sh, dx, dy, dw, dh, REPLACE);
1547
- }
1548
-
1549
-
1550
-
1551
- //////////////////////////////////////////////////////////////
1552
-
1553
- // BLEND
1554
-
1555
-
1556
- /**
1557
- * ( begin auto-generated from blendColor.xml )
1558
- *
1559
- * Blends two color values together based on the blending mode given as the
1560
- * <b>MODE</b> parameter. The possible modes are described in the reference
1561
- * for the <b>blend()</b> function.
1562
- *
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.
1568
- *
1569
- * <LI>BLEND - linear interpolation of colours:
1570
- * <TT>C = A*factor + B</TT>
1571
- *
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".
1576
- *
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".
1581
- *
1582
- * <LI>DARKEST - only the darkest colour succeeds:
1583
- * <TT>C = min(A*factor, B)</TT>.
1584
- * Illustrator calls this "Darken".
1585
- *
1586
- * <LI>LIGHTEST - only the lightest colour succeeds:
1587
- * <TT>C = max(A*factor, B)</TT>.
1588
- * Illustrator calls this "Lighten".
1589
- *
1590
- * <LI>DIFFERENCE - subtract colors from underlying image.
1591
- *
1592
- * <LI>EXCLUSION - similar to DIFFERENCE, but less extreme.
1593
- *
1594
- * <LI>MULTIPLY - Multiply the colors, result will always be darker.
1595
- *
1596
- * <LI>SCREEN - Opposite multiply, uses inverse values of the colors.
1597
- *
1598
- * <LI>OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
1599
- * and screens light values.
1600
- *
1601
- * <LI>HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
1602
- *
1603
- * <LI>SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
1604
- * Works like OVERLAY, but not as harsh.
1605
- *
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>
1614
- * specification.</P>
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>&gt;&gt;8</TT> or <TT>&gt;&gt;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
- *
1627
- * @webref color:creating_reading
1628
- * @usage web_application
1629
- * @param c1 the first color to blend
1630
- * @param c2 the second color to blend
1631
- * @param mode either BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, or BURN
1632
- * @see PImage#blend(PImage, int, int, int, int, int, int, int, int, int)
1633
- * @see PApplet#color(float, float, float, float)
1634
- */
1635
- static public int blendColor(int c1, int c2, int mode) { // ignore
1636
- switch (mode) {
1637
- case REPLACE: return c2;
1638
- case BLEND: return blend_blend(c1, c2);
1639
-
1640
- case ADD: return blend_add_pin(c1, c2);
1641
- case SUBTRACT: return blend_sub_pin(c1, c2);
1642
-
1643
- case LIGHTEST: return blend_lightest(c1, c2);
1644
- case DARKEST: return blend_darkest(c1, c2);
1645
-
1646
- case DIFFERENCE: return blend_difference(c1, c2);
1647
- case EXCLUSION: return blend_exclusion(c1, c2);
1648
-
1649
- case MULTIPLY: return blend_multiply(c1, c2);
1650
- case SCREEN: return blend_screen(c1, c2);
1651
-
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);
1655
-
1656
- case DODGE: return blend_dodge(c1, c2);
1657
- case BURN: return blend_burn(c1, c2);
1658
- }
1659
- return 0;
1660
- }
1661
-
1662
-
1663
- public void blend(int sx, int sy, int sw, int sh,
1664
- int dx, int dy, int dw, int dh, int mode) {
1665
- blend(this, sx, sy, sw, sh, dx, dy, dw, dh, mode);
1666
- }
1667
-
1668
-
1669
- /**
1670
- * ( begin auto-generated from PImage_blend.xml )
1671
- *
1672
- * Blends a region of pixels into the image specified by the <b>img</b>
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
- *
1677
- * BLEND - linear interpolation of colours: C = A*factor + B
1678
- *
1679
- * ADD - additive blending with white clip: C = min(A*factor + B, 255)
1680
- *
1681
- * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor,
1682
- * 0)
1683
- *
1684
- * DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
1685
- *
1686
- * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
1687
- *
1688
- * DIFFERENCE - subtract colors from underlying image.
1689
- *
1690
- * EXCLUSION - similar to DIFFERENCE, but less extreme.
1691
- *
1692
- * MULTIPLY - Multiply the colors, result will always be darker.
1693
- *
1694
- * SCREEN - Opposite multiply, uses inverse values of the colors.
1695
- *
1696
- * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
1697
- * and screens light values.
1698
- *
1699
- * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
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
- *
1707
- * BURN - Darker areas are applied, increasing contrast, ignores lights.
1708
- * Called "Color Burn" in Illustrator and Photoshop.
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
- *
1716
- * As of release 0149, this function ignores <b>imageMode()</b>.
1717
- *
1718
- * ( end auto-generated )
1719
- *
1720
- * @webref image:pixels
1721
- * @brief Copies a pixel or rectangle of pixels using different blending modes
1722
- * @param src an image variable referring to the source image
1723
- * @param sx X coordinate of the source's upper left corner
1724
- * @param sy Y coordinate of the source's upper left corner
1725
- * @param sw source image width
1726
- * @param sh source image height
1727
- * @param dx X coordinate of the destinations's upper left corner
1728
- * @param dy Y coordinate of the destinations's upper left corner
1729
- * @param dw destination image width
1730
- * @param dh destination image height
1731
- * @param mode Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
1732
- *
1733
- * @see PApplet#alpha(int)
1734
- * @see PImage#copy(PImage, int, int, int, int, int, int, int, int)
1735
- * @see PImage#blendColor(int,int,int)
1736
- */
1737
- public void blend(PImage src,
1738
- int sx, int sy, int sw, int sh,
1739
- int dx, int dy, int dw, int dh, int mode) {
1740
- int sx2 = sx + sw;
1741
- int sy2 = sy + sh;
1742
- int dx2 = dx + dw;
1743
- int dy2 = dy + dh;
1744
-
1745
- loadPixels();
1746
- if (src == this) {
1747
- if (intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) {
1748
- blit_resize(get(sx, sy, sw, sh),
1749
- 0, 0, sw, sh,
1750
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1751
- } else {
1752
- // same as below, except skip the loadPixels() because it'd be redundant
1753
- blit_resize(src, sx, sy, sx2, sy2,
1754
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1755
- }
1756
- } else {
1757
- src.loadPixels();
1758
- blit_resize(src, sx, sy, sx2, sy2,
1759
- pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
1760
- //src.updatePixels();
1761
- }
1762
- updatePixels();
1763
- }
1764
-
1765
-
1766
- /**
1767
- * Check to see if two rectangles intersect one another
1768
- */
1769
- private boolean intersect(int sx1, int sy1, int sx2, int sy2,
1770
- int dx1, int dy1, int dx2, int dy2) {
1771
- int sw = sx2 - sx1 + 1;
1772
- int sh = sy2 - sy1 + 1;
1773
- int dw = dx2 - dx1 + 1;
1774
- int dh = dy2 - dy1 + 1;
1775
-
1776
- if (dx1 < sx1) {
1777
- dw += dx1 - sx1;
1778
- if (dw > sw) {
1779
- dw = sw;
1780
- }
1781
- } else {
1782
- int w = sw + sx1 - dx1;
1783
- if (dw > w) {
1784
- dw = w;
1785
- }
1786
- }
1787
- if (dy1 < sy1) {
1788
- dh += dy1 - sy1;
1789
- if (dh > sh) {
1790
- dh = sh;
1791
- }
1792
- } else {
1793
- int h = sh + sy1 - dy1;
1794
- if (dh > h) {
1795
- dh = h;
1796
- }
1797
- }
1798
- return !(dw <= 0 || dh <= 0);
1799
- }
1800
-
1801
-
1802
- //////////////////////////////////////////////////////////////
1803
-
1804
-
1805
- /**
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.
1809
- */
1810
- private void blit_resize(PImage img,
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;
1819
-
1820
- int srcW = srcX2 - srcX1;
1821
- int srcH = srcY2 - srcY1;
1822
- int destW = destX2 - destX1;
1823
- int destH = destY2 - destY1;
1824
-
1825
- boolean smooth = true; // may as well go with the smoothing these days
1826
-
1827
- if (!smooth) {
1828
- srcW++; srcH++;
1829
- }
1830
-
1831
- if (destW <= 0 || destH <= 0 ||
1832
- srcW <= 0 || srcH <= 0 ||
1833
- destX1 >= screenW || destY1 >= screenH ||
1834
- srcX1 >= img.pixelWidth || srcY1 >= img.pixelHeight) {
1835
- return;
1836
- }
1837
-
1838
- int dx = (int) (srcW / (float) destW * PRECISIONF);
1839
- int dy = (int) (srcH / (float) destH * PRECISIONF);
1840
-
1841
- srcXOffset = destX1 < 0 ? -destX1 * dx : srcX1 * PRECISIONF;
1842
- srcYOffset = destY1 < 0 ? -destY1 * dy : srcY1 * PRECISIONF;
1843
-
1844
- if (destX1 < 0) {
1845
- destW += destX1;
1846
- destX1 = 0;
1847
- }
1848
- if (destY1 < 0) {
1849
- destH += destY1;
1850
- destY1 = 0;
1851
- }
1852
-
1853
- destW = min(destW, screenW - destX1);
1854
- destH = min(destH, screenH - destY1);
1855
-
1856
- int destOffset = destY1 * screenW + destX1;
1857
- srcBuffer = img.pixels;
1858
-
1859
- if (smooth) {
1860
- // use bilinear filtering
1861
- iw = img.pixelWidth;
1862
- iw1 = img.pixelWidth - 1;
1863
- ih1 = img.pixelHeight - 1;
1864
-
1865
- switch (mode) {
1866
-
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;
1875
- }
1876
- destOffset += screenW;
1877
- srcYOffset += dy;
1878
- }
1879
- break;
1880
-
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;
1888
- }
1889
- destOffset += screenW;
1890
- srcYOffset += dy;
1891
- }
1892
- break;
1893
-
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;
1901
- }
1902
- destOffset += screenW;
1903
- srcYOffset += dy;
1904
- }
1905
- break;
1906
-
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;
1914
- }
1915
- destOffset += screenW;
1916
- srcYOffset += dy;
1917
- }
1918
- break;
1919
-
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;
1927
- }
1928
- destOffset += screenW;
1929
- srcYOffset += dy;
1930
- }
1931
- break;
1932
-
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;
1939
- }
1940
- destOffset += screenW;
1941
- srcYOffset += dy;
1942
- }
1943
- break;
1944
-
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;
1952
- }
1953
- destOffset += screenW;
1954
- srcYOffset += dy;
1955
- }
1956
- break;
1957
-
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;
1965
- }
1966
- destOffset += screenW;
1967
- srcYOffset += dy;
1968
- }
1969
- break;
1970
-
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;
1978
- }
1979
- destOffset += screenW;
1980
- srcYOffset += dy;
1981
- }
1982
- break;
1983
-
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;
1991
- }
1992
- destOffset += screenW;
1993
- srcYOffset += dy;
1994
- }
1995
- break;
1996
-
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;
2004
- }
2005
- destOffset += screenW;
2006
- srcYOffset += dy;
2007
- }
2008
- break;
2009
-
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;
2017
- }
2018
- destOffset += screenW;
2019
- srcYOffset += dy;
2020
- }
2021
- break;
2022
-
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;
2030
- }
2031
- destOffset += screenW;
2032
- srcYOffset += dy;
2033
- }
2034
- break;
2035
-
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;
2044
- }
2045
- destOffset += screenW;
2046
- srcYOffset += dy;
2047
- }
2048
- break;
2049
-
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;
2057
- }
2058
- destOffset += screenW;
2059
- srcYOffset += dy;
2060
- }
2061
- break;
2062
-
2063
- }
2064
-
2065
- } else {
2066
- // nearest neighbour scaling (++fast!)
2067
- switch (mode) {
2068
-
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;
2079
- }
2080
- destOffset += screenW;
2081
- srcYOffset += dy;
2082
- }
2083
- break;
2084
-
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;
2094
- }
2095
- destOffset += screenW;
2096
- srcYOffset += dy;
2097
- }
2098
- break;
2099
-
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;
2109
- }
2110
- destOffset += screenW;
2111
- srcYOffset += dy;
2112
- }
2113
- break;
2114
-
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;
2124
- }
2125
- destOffset += screenW;
2126
- srcYOffset += dy;
2127
- }
2128
- break;
2129
-
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;
2139
- }
2140
- destOffset += screenW;
2141
- srcYOffset += dy;
2142
- }
2143
- break;
2144
-
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;
2152
- }
2153
- destOffset += screenW;
2154
- srcYOffset += dy;
2155
- }
2156
- break;
2157
-
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;
2167
- }
2168
- destOffset += screenW;
2169
- srcYOffset += dy;
2170
- }
2171
- break;
2172
-
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;
2182
- }
2183
- destOffset += screenW;
2184
- srcYOffset += dy;
2185
- }
2186
- break;
2187
-
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;
2197
- }
2198
- destOffset += screenW;
2199
- srcYOffset += dy;
2200
- }
2201
- break;
2202
-
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;
2212
- }
2213
- destOffset += screenW;
2214
- srcYOffset += dy;
2215
- }
2216
- break;
2217
-
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;
2227
- }
2228
- destOffset += screenW;
2229
- srcYOffset += dy;
2230
- }
2231
- break;
2232
-
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;
2242
- }
2243
- destOffset += screenW;
2244
- srcYOffset += dy;
2245
- }
2246
- break;
2247
-
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;
2257
- }
2258
- destOffset += screenW;
2259
- srcYOffset += dy;
2260
- }
2261
- break;
2262
-
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;
2273
- }
2274
- destOffset += screenW;
2275
- srcYOffset += dy;
2276
- }
2277
- break;
2278
-
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;
2288
- }
2289
- destOffset += screenW;
2290
- srcYOffset += dy;
2291
- }
2292
- break;
2293
-
2294
- }
2295
- }
2296
- }
2297
-
2298
-
2299
- private void filter_new_scanline() {
2300
- sX = srcXOffset;
2301
- fracV = srcYOffset & PREC_MAXVAL;
2302
- ifV = PREC_MAXVAL - fracV + 1;
2303
- v1 = (srcYOffset >> PRECISIONB) * iw;
2304
- v2 = min((srcYOffset >> PRECISIONB) + 1, ih1) * iw;
2305
- }
2306
-
2307
-
2308
- private int filter_bilinear() {
2309
- fracU = sX & PREC_MAXVAL;
2310
- ifU = PREC_MAXVAL - fracU + 1;
2311
- ul = (ifU * ifV) >> PRECISIONB;
2312
- ll = ifU - ul;
2313
- ur = ifV - ul;
2314
- lr = PREC_MAXVAL + 1 - ul - ll - ur;
2315
- u1 = (sX >> PRECISIONB);
2316
- u2 = min(u1 + 1, iw1);
2317
-
2318
- // get color values of the 4 neighbouring texels
2319
- cUL = srcBuffer[v1 + u1];
2320
- cUR = srcBuffer[v1 + u2];
2321
- cLL = srcBuffer[v2 + u1];
2322
- cLR = srcBuffer[v2 + u2];
2323
-
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;
2327
-
2328
- g = ((ul*(cUL&GREEN_MASK) + ll*(cLL&GREEN_MASK) +
2329
- ur*(cUR&GREEN_MASK) + lr*(cLR&GREEN_MASK))
2330
- >>> PRECISIONB) & GREEN_MASK;
2331
-
2332
- b = (ul*(cUL&BLUE_MASK) + ll*(cLL&BLUE_MASK) +
2333
- ur*(cUR&BLUE_MASK) + lr*(cLR&BLUE_MASK))
2334
- >>> PRECISIONB;
2335
-
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;
2339
-
2340
- return a | r | g | b;
2341
- }
2342
-
2343
-
2344
-
2345
- //////////////////////////////////////////////////////////////
2346
-
2347
- // internal blending methods
2348
-
2349
-
2350
- private static int min(int a, int b) {
2351
- return (a < b) ? a : b;
2352
- }
2353
-
2354
-
2355
- private static int max(int a, int b) {
2356
- return (a > b) ? a : b;
2357
- }
2358
-
2359
-
2360
- /////////////////////////////////////////////////////////////
2361
-
2362
- // BLEND MODE IMPLEMENTATIONS
2363
-
2364
- /*
2365
- * Jakub Valtar
2366
- *
2367
- * All modes use SRC alpha to interpolate between DST and the result of
2368
- * the operation:
2369
- *
2370
- * R = (1 - SRC_ALPHA) * DST + SRC_ALPHA * <RESULT OF THE OPERATION>
2371
- *
2372
- * Comments above each mode only specify the formula of its operation.
2373
- *
2374
- * These implementations treat alpha 127 (=255/2) as a perfect 50 % mix.
2375
- *
2376
- * One alpha value between 126 and 127 is intentionally left out,
2377
- * so the step 126 -> 127 is twice as big compared to other steps.
2378
- * This is because our colors are in 0..255 range, but we divide
2379
- * by right shifting 8 places (=256) which is much faster than
2380
- * (correct) float division by 255.0f. The missing value was placed
2381
- * between 126 and 127, because limits of the range (near 0 and 255) and
2382
- * the middle value (127) have to blend correctly.
2383
- *
2384
- * Below you will often see RED and BLUE channels (RB) manipulated together
2385
- * and GREEN channel (GN) manipulated separately. It is sometimes possible
2386
- * because the operation won't use more than 16 bits, so we process the RED
2387
- * channel in the upper 16 bits and BLUE channel in the lower 16 bits. This
2388
- * decreases the number of operations per pixel and thus makes things faster.
2389
- *
2390
- * Some of the modes are hand tweaked (various +1s etc.) to be more accurate
2391
- * and to produce correct values in extremes. Below is a sketch you can use
2392
- * to check any blending function for
2393
- *
2394
- * 1) Discrepancies between color channels:
2395
- * - highlighted by the offending color
2396
- * 2) Behavior at extremes (set colorCount to 256):
2397
- * - values of all corners are printed to the console
2398
- * 3) Rounding errors:
2399
- * - set colorCount to lower value to better see color bands
2400
- *
2401
-
2402
- // use powers of 2 in range 2..256
2403
- // to better see color bands
2404
- final int colorCount = 256;
2405
-
2406
- final int blockSize = 3;
2407
-
2408
- void settings() {
2409
- size(blockSize * 256, blockSize * 256);
2410
- }
2411
-
2412
- void setup() { }
2413
-
2414
- void draw() {
2415
- noStroke();
2416
- colorMode(RGB, colorCount-1);
2417
- int alpha = (mouseX / blockSize) << 24;
2418
- int r, g, b, r2, g2, b2 = 0;
2419
- for (int x = 0; x <= 0xFF; x++) {
2420
- for (int y = 0; y <= 0xFF; y++) {
2421
- int dst = (x << 16) | (x << 8) | x;
2422
- int src = (y << 16) | (y << 8) | y | alpha;
2423
- int result = testFunction(dst, src);
2424
- r = r2 = (result >> 16 & 0xFF);
2425
- g = g2 = (result >> 8 & 0xFF);
2426
- b = b2 = (result >> 0 & 0xFF);
2427
- if (r != g && r != b) r2 = (128 + r2) % 255;
2428
- if (g != r && g != b) g2 = (128 + g2) % 255;
2429
- if (b != r && b != g) b2 = (128 + b2) % 255;
2430
- fill(r2 % colorCount, g2 % colorCount, b2 % colorCount);
2431
- rect(x * blockSize, y * blockSize, blockSize, blockSize);
2432
- }
2433
- }
2434
- println(
2435
- "alpha:", mouseX/blockSize,
2436
- "TL:", hex(get(0, 0)),
2437
- "TR:", hex(get(width-1, 0)),
2438
- "BR:", hex(get(width-1, height-1)),
2439
- "BL:", hex(get(0, height-1)));
2440
- }
2441
-
2442
- int testFunction(int dst, int src) {
2443
- // your function here
2444
- return dst;
2445
- }
2446
-
2447
- *
2448
- *
2449
- */
2450
-
2451
- private static final int RB_MASK = 0x00FF00FF;
2452
- private static final int GN_MASK = 0x0000FF00;
2453
-
2454
- /**
2455
- * Blend
2456
- * O = S
2457
- */
2458
- private static int blend_blend(int dst, int src) {
2459
- int a = src >>> 24;
2460
-
2461
- int s_a = a + (a >= 0x7F ? 1 : 0);
2462
- int d_a = 0x100 - s_a;
2463
-
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;
2467
- }
2468
-
2469
-
2470
- /**
2471
- * Add
2472
- * O = MIN(D + S, 1)
2473
- */
2474
- private static int blend_add_pin(int dst, int src) {
2475
- int a = src >>> 24;
2476
-
2477
- int s_a = a + (a >= 0x7F ? 1 : 0);
2478
-
2479
- int rb = (dst & RB_MASK) + ((src & RB_MASK) * s_a >>> 8 & RB_MASK);
2480
- int gn = (dst & GN_MASK) + ((src & GN_MASK) * s_a >>> 8);
2481
-
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);
2486
- }
2487
-
2488
-
2489
- /**
2490
- * Subtract
2491
- * O = MAX(0, D - S)
2492
- */
2493
- private static int blend_sub_pin(int dst, int src) {
2494
- int a = src >>> 24;
2495
-
2496
- int s_a = a + (a >= 0x7F ? 1 : 0);
2497
-
2498
- int rb = ((src & RB_MASK) * s_a >>> 8);
2499
- int gn = ((src & GREEN_MASK) * s_a >>> 8);
2500
-
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);
2505
- }
2506
-
2507
-
2508
- /**
2509
- * Lightest
2510
- * O = MAX(D, S)
2511
- */
2512
- private static int blend_lightest(int dst, int src) {
2513
- int a = src >>> 24;
2514
-
2515
- int s_a = a + (a >= 0x7F ? 1 : 0);
2516
- int d_a = 0x100 - s_a;
2517
-
2518
- int rb = max(src & RED_MASK, dst & RED_MASK) |
2519
- max(src & BLUE_MASK, dst & BLUE_MASK);
2520
- int gn = max(src & GREEN_MASK, dst & GREEN_MASK);
2521
-
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;
2525
- }
2526
-
2527
-
2528
- /**
2529
- * Darkest
2530
- * O = MIN(D, S)
2531
- */
2532
- private static int blend_darkest(int dst, int src) {
2533
- int a = src >>> 24;
2534
-
2535
- int s_a = a + (a >= 0x7F ? 1 : 0);
2536
- int d_a = 0x100 - s_a;
2537
-
2538
- int rb = min(src & RED_MASK, dst & RED_MASK) |
2539
- min(src & BLUE_MASK, dst & BLUE_MASK);
2540
- int gn = min(src & GREEN_MASK, dst & GREEN_MASK);
2541
-
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;
2545
- }
2546
-
2547
-
2548
- /**
2549
- * Difference
2550
- * O = ABS(D - S)
2551
- */
2552
- private static int blend_difference(int dst, int src) {
2553
- int a = src >>> 24;
2554
-
2555
- int s_a = a + (a >= 0x7F ? 1 : 0);
2556
- int d_a = 0x100 - s_a;
2557
-
2558
- int r = (dst & RED_MASK) - (src & RED_MASK);
2559
- int b = (dst & BLUE_MASK) - (src & BLUE_MASK);
2560
- int g = (dst & GREEN_MASK) - (src & GREEN_MASK);
2561
-
2562
- int rb = (r < 0 ? -r : r) |
2563
- (b < 0 ? -b : b);
2564
- int gn = (g < 0 ? -g : g);
2565
-
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;
2569
- }
2570
-
2571
-
2572
- /**
2573
- * Exclusion
2574
- * O = (1 - S)D + S(1 - D)
2575
- * O = D + S - 2DS
2576
- */
2577
- private static int blend_exclusion(int dst, int src) {
2578
- int a = src >>> 24;
2579
-
2580
- int s_a = a + (a >= 0x7F ? 1 : 0);
2581
- int d_a = 0x100 - s_a;
2582
-
2583
- int d_rb = dst & RB_MASK;
2584
- int d_gn = dst & GN_MASK;
2585
-
2586
- int s_gn = src & GN_MASK;
2587
-
2588
- int f_r = (dst & RED_MASK) >> 16;
2589
- int f_b = (dst & BLUE_MASK);
2590
-
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;
2595
- int gn_sub = s_gn * (d_gn + (d_gn >= 0x7F00 ? 0x100 : 0))
2596
- >>> 15 & 0x0001FF00;
2597
-
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;
2601
- }
2602
-
2603
-
2604
- /*
2605
- * Multiply
2606
- * O = DS
2607
- */
2608
- private static int blend_multiply(int dst, int src) {
2609
- int a = src >>> 24;
2610
-
2611
- int s_a = a + (a >= 0x7F ? 1 : 0);
2612
- int d_a = 0x100 - s_a;
2613
-
2614
- int d_gn = dst & GN_MASK;
2615
-
2616
- int f_r = (dst & RED_MASK) >> 16;
2617
- int f_b = (dst & BLUE_MASK);
2618
-
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;
2626
-
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;
2630
- }
2631
-
2632
-
2633
- /**
2634
- * Screen
2635
- * O = 1 - (1 - D)(1 - S)
2636
- * O = D + S - DS
2637
- */
2638
- private static int blend_screen(int dst, int src) {
2639
- int a = src >>> 24;
2640
-
2641
- int s_a = a + (a >= 0x7F ? 1 : 0);
2642
- int d_a = 0x100 - s_a;
2643
-
2644
- int d_rb = dst & RB_MASK;
2645
- int d_gn = dst & GN_MASK;
2646
-
2647
- int s_gn = src & GN_MASK;
2648
-
2649
- int f_r = (dst & RED_MASK) >> 16;
2650
- int f_b = (dst & BLUE_MASK);
2651
-
2652
- int rb_sub =
2653
- ((src & RED_MASK) * (f_r + 1) |
2654
- (src & BLUE_MASK) * (f_b + 1))
2655
- >>> 8 & RB_MASK;
2656
- int gn_sub = s_gn * (d_gn + 0x100)
2657
- >>> 16 & GN_MASK;
2658
-
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;
2662
- }
2663
-
2664
-
2665
- /**
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
2669
- */
2670
- private static int blend_overlay(int dst, int src) {
2671
- int a = src >>> 24;
2672
-
2673
- int s_a = a + (a >= 0x7F ? 1 : 0);
2674
- int d_a = 0x100 - s_a;
2675
-
2676
- int d_r = dst & RED_MASK;
2677
- int d_g = dst & GREEN_MASK;
2678
- int d_b = dst & BLUE_MASK;
2679
-
2680
- int s_r = src & RED_MASK;
2681
- int s_g = src & GREEN_MASK;
2682
- int s_b = src & BLUE_MASK;
2683
-
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;
2693
-
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;
2697
- }
2698
-
2699
-
2700
- /**
2701
- * Hard Light
2702
- * O = OVERLAY(S, D)
2703
- *
2704
- * O = 2 * MULTIPLY(D, S) = 2DS for S < 0.5
2705
- * O = 2 * SCREEN(D, S) - 1 = 2(S + D - DS) - 1 otherwise
2706
- */
2707
- private static int blend_hard_light(int dst, int src) {
2708
- int a = src >>> 24;
2709
-
2710
- int s_a = a + (a >= 0x7F ? 1 : 0);
2711
- int d_a = 0x100 - s_a;
2712
-
2713
- int d_r = dst & RED_MASK;
2714
- int d_g = dst & GREEN_MASK;
2715
- int d_b = dst & BLUE_MASK;
2716
-
2717
- int s_r = src & RED_MASK;
2718
- int s_g = src & GREEN_MASK;
2719
- int s_b = src & BLUE_MASK;
2720
-
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;
2730
-
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;
2734
- }
2735
-
2736
-
2737
- /**
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
2742
- */
2743
- private static int blend_soft_light(int dst, int src) {
2744
- int a = src >>> 24;
2745
-
2746
- int s_a = a + (a >= 0x7F ? 1 : 0);
2747
- int d_a = 0x100 - s_a;
2748
-
2749
- int d_r = dst & RED_MASK;
2750
- int d_g = dst & GREEN_MASK;
2751
- int d_b = dst & BLUE_MASK;
2752
-
2753
- int s_r1 = src & RED_MASK >> 16;
2754
- int s_g1 = src & GREEN_MASK >> 8;
2755
- int s_b1 = src & BLUE_MASK;
2756
-
2757
- int d_r1 = (d_r >> 16) + (s_r1 < 7F ? 1 : 0);
2758
- int d_g1 = (d_g >> 8) + (s_g1 < 7F ? 1 : 0);
2759
- int d_b1 = d_b + (s_b1 < 7F ? 1 : 0);
2760
-
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;
2767
-
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;
2771
- }
2772
-
2773
-
2774
- /**
2775
- * Dodge
2776
- * O = D / (1 - S)
2777
- */
2778
- private static int blend_dodge(int dst, int src) {
2779
- int a = src >>> 24;
2780
-
2781
- int s_a = a + (a >= 0x7F ? 1 : 0);
2782
- int d_a = 0x100 - s_a;
2783
-
2784
- int r = (dst & RED_MASK) / (256 - ((src & RED_MASK) >> 16));
2785
- int g = ((dst & GREEN_MASK) << 8) / (256 - ((src & GREEN_MASK) >> 8));
2786
- int b = ((dst & BLUE_MASK) << 8) / (256 - (src & BLUE_MASK));
2787
-
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));
2793
-
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;
2797
- }
2798
-
2799
-
2800
- /**
2801
- * Burn
2802
- * O = 1 - (1 - A) / B
2803
- */
2804
- private static int blend_burn(int dst, int src) {
2805
- int a = src >>> 24;
2806
-
2807
- int s_a = a + (a >= 0x7F ? 1 : 0);
2808
- int d_a = 0x100 - s_a;
2809
-
2810
- int r = ((0xFF0000 - (dst & RED_MASK))) / (1 + (src & RED_MASK >> 16));
2811
- int g = ((0x00FF00 - (dst & GREEN_MASK)) << 8) / (1 + (src & GREEN_MASK >> 8));
2812
- int b = ((0x0000FF - (dst & BLUE_MASK)) << 8) / (1 + (src & BLUE_MASK));
2813
-
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));
2819
-
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;
2823
- }
2824
-
2825
-
2826
- //////////////////////////////////////////////////////////////
2827
-
2828
- // FILE I/O
2829
-
2830
-
2831
- protected boolean saveImpl(String filename) {
2832
- return false;
2833
- }
2834
-
2835
-
2836
- static public PImage loadTIFF(InputStream input) { // ignore
2837
- byte tiff[] = PApplet.loadBytes(input);
2838
-
2839
- if ((tiff[42] != tiff[102]) || // width/height in both places
2840
- (tiff[43] != tiff[103])) {
2841
- System.err.println(TIFF_ERROR);
2842
- return null;
2843
- }
2844
-
2845
- int width =
2846
- ((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff);
2847
- int height =
2848
- ((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff);
2849
-
2850
- int count =
2851
- ((tiff[114] & 0xff) << 24) |
2852
- ((tiff[115] & 0xff) << 16) |
2853
- ((tiff[116] & 0xff) << 8) |
2854
- (tiff[117] & 0xff);
2855
- if (count != width * height * 3) {
2856
- System.err.println(TIFF_ERROR + " (" + width + ", " + height +")");
2857
- return null;
2858
- }
2859
-
2860
- // check the rest of the header
2861
- for (int i = 0; i < TIFF_HEADER.length; i++) {
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;
2865
-
2866
- if (tiff[i] != TIFF_HEADER[i]) {
2867
- System.err.println(TIFF_ERROR + " (" + i + ")");
2868
- return null;
2869
- }
2870
- }
2871
-
2872
- PImage outgoing = new PImage(width, height, RGB);
2873
- int index = 768;
2874
- count /= 3;
2875
- for (int i = 0; i < count; i++) {
2876
- outgoing.pixels[i] =
2877
- 0xFF000000 |
2878
- (tiff[index++] & 0xff) << 16 |
2879
- (tiff[index++] & 0xff) << 8 |
2880
- (tiff[index++] & 0xff);
2881
- }
2882
- return outgoing;
2883
- }
2884
-
2885
- protected boolean saveTIFF(OutputStream output) {
2886
- // shutting off the warning, people can figure this out themselves
2887
- /*
2888
- if (format != RGB) {
2889
- System.err.println("Warning: only RGB information is saved with " +
2890
- ".tif files. Use .tga or .png for ARGB images and others.");
2891
- }
2892
- */
2893
- try {
2894
- byte[] tiff = new byte[768];
2895
- System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length);
2896
-
2897
- tiff[30] = (byte) ((pixelWidth >> 8) & 0xff);
2898
- tiff[31] = (byte) ((pixelWidth) & 0xff);
2899
- tiff[42] = tiff[102] = (byte) ((pixelHeight >> 8) & 0xff);
2900
- tiff[43] = tiff[103] = (byte) ((pixelHeight) & 0xff);
2901
-
2902
- int count = pixelWidth*pixelHeight*3;
2903
- tiff[114] = (byte) ((count >> 24) & 0xff);
2904
- tiff[115] = (byte) ((count >> 16) & 0xff);
2905
- tiff[116] = (byte) ((count >> 8) & 0xff);
2906
- tiff[117] = (byte) ((count) & 0xff);
2907
-
2908
- // spew the header to the disk
2909
- output.write(tiff);
2910
-
2911
- for (int i = 0; i < pixels.length; i++) {
2912
- output.write((pixels[i] >> 16) & 0xff);
2913
- output.write((pixels[i] >> 8) & 0xff);
2914
- output.write(pixels[i] & 0xff);
2915
- }
2916
- output.flush();
2917
- return true;
2918
-
2919
- } catch (IOException e) {
2920
- }
2921
- return false;
2922
- }
2923
-
2924
-
2925
- /**
2926
- * Targa image loader for RLE-compressed TGA files.
2927
- * <p>
2928
- * Rewritten for 0115 to read/write RLE-encoded targa images.
2929
- * For 0125, non-RLE encoded images are now supported, along with
2930
- * images whose y-order is reversed (which is standard for TGA files).
2931
- * <p>
2932
- * A version of this function is in MovieMaker.java. Any fixes here
2933
- * should be applied over in MovieMaker as well.
2934
- * <p>
2935
- * Known issue with RLE encoding and odd behavior in some apps:
2936
- * https://github.com/processing/processing/issues/2096
2937
- * Please help!
2938
- */
2939
- static public PImage loadTGA(InputStream input) throws IOException { // ignore
2940
- byte[] header = new byte[18];
2941
- int offset = 0;
2942
- do {
2943
- int count = input.read(header, offset, header.length - offset);
2944
- if (count == -1) return null;
2945
- offset += count;
2946
- } while (offset < 18);
2947
-
2948
- /*
2949
- header[2] image type code
2950
- 2 (0x02) - Uncompressed, RGB images.
2951
- 3 (0x03) - Uncompressed, black and white images.
2952
- 10 (0x0A) - Run-length encoded RGB images.
2953
- 11 (0x0B) - Compressed, black and white images. (grayscale?)
2954
-
2955
- header[16] is the bit depth (8, 24, 32)
2956
-
2957
- header[17] image descriptor (packed bits)
2958
- 0x20 is 32 = origin upper-left
2959
- 0x28 is 32 + 8 = origin upper-left + 32 bits
2960
-
2961
- 7 6 5 4 3 2 1 0
2962
- 128 64 32 16 8 4 2 1
2963
- */
2964
-
2965
- int format = 0;
2966
-
2967
- if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not
2968
- (header[16] == 8) && // 8 bits
2969
- ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit
2970
- format = ALPHA;
2971
-
2972
- } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not
2973
- (header[16] == 24) && // 24 bits
2974
- ((header[17] == 0x20) || (header[17] == 0))) { // origin
2975
- format = RGB;
2976
-
2977
- } else if (((header[2] == 2) || (header[2] == 10)) &&
2978
- (header[16] == 32) &&
2979
- ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32
2980
- format = ARGB;
2981
- }
2982
-
2983
- if (format == 0) {
2984
- System.err.println("Unknown .tga file format");
2985
- return null;
2986
- }
2987
-
2988
- int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
2989
- int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
2990
- PImage outgoing = new PImage(w, h, format);
2991
-
2992
- // where "reversed" means upper-left corner (normal for most of
2993
- // the modernized world, but "reversed" for the tga spec)
2994
- //boolean reversed = (header[17] & 0x20) != 0;
2995
- // https://github.com/processing/processing/issues/1682
2996
- boolean reversed = (header[17] & 0x20) == 0;
2997
-
2998
- if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded
2999
- if (reversed) {
3000
- int index = (h-1) * w;
3001
- switch (format) {
3002
- case ALPHA:
3003
- for (int y = h-1; y >= 0; y--) {
3004
- for (int x = 0; x < w; x++) {
3005
- outgoing.pixels[index + x] = input.read();
3006
- }
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;
3016
- }
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);
3026
- }
3027
- index -= w;
3028
- }
3029
- }
3030
- } else { // not reversed
3031
- int count = w * h;
3032
- switch (format) {
3033
- case ALPHA:
3034
- for (int i = 0; i < count; i++) {
3035
- outgoing.pixels[i] = input.read();
3036
- }
3037
- break;
3038
- case RGB:
3039
- for (int i = 0; i < count; i++) {
3040
- outgoing.pixels[i] =
3041
- input.read() | (input.read() << 8) | (input.read() << 16) |
3042
- 0xff000000;
3043
- }
3044
- break;
3045
- case ARGB:
3046
- for (int i = 0; i < count; i++) {
3047
- outgoing.pixels[i] =
3048
- input.read() | (input.read() << 8) | (input.read() << 16) |
3049
- (input.read() << 24);
3050
- }
3051
- break;
3052
- }
3053
- }
3054
-
3055
- } else { // header[2] is 10 or 11
3056
- int index = 0;
3057
- int[] px = outgoing.pixels;
3058
-
3059
- while (index < px.length) {
3060
- int num = input.read();
3061
- boolean isRLE = (num & 0x80) != 0;
3062
- if (isRLE) {
3063
- num -= 127; // (num & 0x7F) + 1
3064
- int pixel = 0;
3065
- switch (format) {
3066
- case ALPHA:
3067
- pixel = input.read();
3068
- break;
3069
- case RGB:
3070
- pixel = 0xFF000000 |
3071
- input.read() | (input.read() << 8) | (input.read() << 16);
3072
- //(is.read() << 16) | (is.read() << 8) | is.read();
3073
- break;
3074
- case ARGB:
3075
- pixel = input.read() |
3076
- (input.read() << 8) | (input.read() << 16) | (input.read() << 24);
3077
- break;
3078
- }
3079
- for (int i = 0; i < num; i++) {
3080
- px[index++] = pixel;
3081
- if (index == px.length) break;
3082
- }
3083
- } else { // write up to 127 bytes as uncompressed
3084
- num += 1;
3085
- switch (format) {
3086
- case ALPHA:
3087
- for (int i = 0; i < num; i++) {
3088
- px[index++] = input.read();
3089
- }
3090
- break;
3091
- case RGB:
3092
- for (int i = 0; i < num; i++) {
3093
- px[index++] = 0xFF000000 |
3094
- input.read() | (input.read() << 8) | (input.read() << 16);
3095
- //(is.read() << 16) | (is.read() << 8) | is.read();
3096
- }
3097
- break;
3098
- case ARGB:
3099
- for (int i = 0; i < num; i++) {
3100
- px[index++] = input.read() | //(is.read() << 24) |
3101
- (input.read() << 8) | (input.read() << 16) | (input.read() << 24);
3102
- //(is.read() << 16) | (is.read() << 8) | is.read();
3103
- }
3104
- break;
3105
- }
3106
- }
3107
- }
3108
-
3109
- if (!reversed) {
3110
- int[] temp = new int[w];
3111
- for (int y = 0; y < h/2; y++) {
3112
- int z = (h-1) - y;
3113
- System.arraycopy(px, y*w, temp, 0, w);
3114
- System.arraycopy(px, z*w, px, y*w, w);
3115
- System.arraycopy(temp, 0, px, z*w, w);
3116
- }
3117
- }
3118
- }
3119
- input.close();
3120
- return outgoing;
3121
- }
3122
-
3123
-
3124
- /**
3125
- * Creates a Targa32 formatted byte sequence of specified
3126
- * pixel buffer using RLE compression.
3127
- * <p>
3128
- * Also figured out how to avoid parsing the image upside-down
3129
- * (there's a header flag to set the image origin to top-left)
3130
- * </p>
3131
- * Starting with revision 0092, the format setting is taken into account:
3132
- * <UL>
3133
- * <LI><TT>ALPHA</TT> images written as 8bit grayscale (uses lowest byte)
3134
- * <LI><TT>RGB</TT> &rarr; 24 bits
3135
- * <LI><TT>ARGB</TT> &rarr; 32 bits
3136
- * </UL>
3137
- * All versions are RLE compressed.
3138
- *
3139
- * Contributed by toxi 8-10 May 2005, based on this RLE
3140
- * <A HREF="http://www.wotsit.org/download.asp?f=tga">specification</A>
3141
- */
3142
- protected boolean saveTGA(OutputStream output) {
3143
- byte[] header = new byte[18];
3144
-
3145
- switch (format) {
3146
- case ALPHA:
3147
- // save ALPHA images as 8bit grayscale
3148
- header[2] = 0x0B;
3149
- header[16] = 0x08;
3150
- header[17] = 0x28;
3151
- break;
3152
- case RGB:
3153
- header[2] = 0x0A;
3154
- header[16] = 24;
3155
- header[17] = 0x20;
3156
- break;
3157
- case ARGB:
3158
- header[2] = 0x0A;
3159
- header[16] = 32;
3160
- header[17] = 0x28;
3161
- break;
3162
- default:
3163
- throw new RuntimeException("Image format not recognized inside save()");
3164
- }
3165
- // set image dimensions lo-hi byte order
3166
- header[12] = (byte) (pixelWidth & 0xff);
3167
- header[13] = (byte) (pixelWidth >> 8);
3168
- header[14] = (byte) (pixelHeight & 0xff);
3169
- header[15] = (byte) (pixelHeight >> 8);
3170
-
3171
- try {
3172
- output.write(header);
3173
-
3174
- int maxLen = pixelHeight * pixelWidth;
3175
- int index = 0;
3176
- int col; //, prevCol;
3177
- int[] currChunk = new int[128];
3178
-
3179
- // 8bit image exporter is in separate loop
3180
- // to avoid excessive conditionals...
3181
- if (format == ALPHA) {
3182
- while (index < maxLen) {
3183
- boolean isRLE = false;
3184
- int rle = 1;
3185
- currChunk[0] = col = pixels[index] & 0xff;
3186
- while (index + rle < maxLen) {
3187
- if (col != (pixels[index + rle]&0xff) || rle == 128) {
3188
- isRLE = (rle > 1);
3189
- break;
3190
- }
3191
- rle++;
3192
- }
3193
- if (isRLE) {
3194
- output.write(0x80 | (rle - 1));
3195
- output.write(col);
3196
-
3197
- } else {
3198
- rle = 1;
3199
- while (index + rle < maxLen) {
3200
- int cscan = pixels[index + rle] & 0xff;
3201
- if ((col != cscan && rle < 128) || rle < 3) {
3202
- currChunk[rle] = col = cscan;
3203
- } else {
3204
- if (col == cscan) rle -= 2;
3205
- break;
3206
- }
3207
- rle++;
3208
- }
3209
- output.write(rle - 1);
3210
- for (int i = 0; i < rle; i++) output.write(currChunk[i]);
3211
- }
3212
- index += rle;
3213
- }
3214
- } else { // export 24/32 bit TARGA
3215
- while (index < maxLen) {
3216
- boolean isRLE = false;
3217
- currChunk[0] = col = pixels[index];
3218
- int rle = 1;
3219
- // try to find repeating bytes (min. len = 2 pixels)
3220
- // maximum chunk size is 128 pixels
3221
- while (index + rle < maxLen) {
3222
- if (col != pixels[index + rle] || rle == 128) {
3223
- isRLE = (rle > 1); // set flag for RLE chunk
3224
- break;
3225
- }
3226
- rle++;
3227
- }
3228
- if (isRLE) {
3229
- output.write(128 | (rle - 1));
3230
- output.write(col & 0xff);
3231
- output.write(col >> 8 & 0xff);
3232
- output.write(col >> 16 & 0xff);
3233
- if (format == ARGB) output.write(col >>> 24 & 0xff);
3234
-
3235
- } else { // not RLE
3236
- rle = 1;
3237
- while (index + rle < maxLen) {
3238
- if ((col != pixels[index + rle] && rle < 128) || rle < 3) {
3239
- currChunk[rle] = col = pixels[index + rle];
3240
- } else {
3241
- // check if the exit condition was the start of
3242
- // a repeating colour
3243
- if (col == pixels[index + rle]) rle -= 2;
3244
- break;
3245
- }
3246
- rle++;
3247
- }
3248
- // write uncompressed chunk
3249
- output.write(rle - 1);
3250
- if (format == ARGB) {
3251
- for (int i = 0; i < rle; i++) {
3252
- col = currChunk[i];
3253
- output.write(col & 0xff);
3254
- output.write(col >> 8 & 0xff);
3255
- output.write(col >> 16 & 0xff);
3256
- output.write(col >>> 24 & 0xff);
3257
- }
3258
- } else {
3259
- for (int i = 0; i < rle; i++) {
3260
- col = currChunk[i];
3261
- output.write(col & 0xff);
3262
- output.write(col >> 8 & 0xff);
3263
- output.write(col >> 16 & 0xff);
3264
- }
3265
- }
3266
- }
3267
- index += rle;
3268
- }
3269
- }
3270
- output.flush();
3271
- return true;
3272
-
3273
- } catch (IOException e) {
3274
- return false;
3275
- }
3276
- }
3277
-
3278
-
3279
- /**
3280
- * ( begin auto-generated from PImage_save.xml )
3281
- *
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
3292
- * <b>createImage()</b> reference for more information.
3293
- *
3294
- * ( end auto-generated )
3295
- * <h3>Advanced</h3>
3296
- * Save this image to disk.
3297
- * <p>
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.
3304
- * <p>
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>
3311
- * <p>
3312
- * To use the original built-in image writers, use .tga or .tif as the
3313
- * extension, or don't include an extension. When no extension is used,
3314
- * the extension .tif will be added to the file name.
3315
- * <p>
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.
3319
- *
3320
- * @webref pimage:method
3321
- * @brief Saves the image to a TIFF, TARGA, PNG, or JPEG file
3322
- * @usage application
3323
- * @param filename a sequence of letters and numbers
3324
- */
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
- }
3377
- }