p5 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src → dist}/accessibility/color_namer.js +48 -3
- package/{src → dist}/accessibility/describe.js +2 -2
- package/{src → dist}/accessibility/gridOutput.js +2 -2
- package/dist/accessibility/index.js +60 -0
- package/{src → dist}/accessibility/outputs.js +2 -2
- package/{src → dist}/accessibility/textOutput.js +2 -2
- package/dist/app.js +120 -0
- package/{src → dist}/color/color_conversion.js +48 -10
- package/{src → dist}/color/color_spaces/hsb.js +3 -1
- package/dist/color/creating_reading.js +3 -0
- package/dist/color/index.js +13 -0
- package/dist/color/p5.Color.culori.js +1 -0
- package/dist/color/p5.Color.js +3 -0
- package/{src → dist}/color/setting.js +9 -6
- package/{src/core/constants.js → dist/constants-C-g_eAdC.js} +266 -130
- package/{src → dist}/core/States.js +3 -1
- package/dist/core/constants.js +1 -0
- package/{src → dist}/core/environment.js +7 -6
- package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
- package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
- package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
- package/dist/core/friendly_errors/index.js +23 -0
- package/dist/core/friendly_errors/param_validator.js +5455 -0
- package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
- package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
- package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
- package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
- package/{src → dist}/core/helpers.js +9 -6
- package/dist/core/init.js +105 -0
- package/dist/core/internationalization.js +302 -0
- package/dist/core/legacy.js +73 -0
- package/dist/core/main.js +44 -0
- package/dist/core/noop.js +3 -0
- package/dist/core/p5.Graphics.js +40 -0
- package/dist/core/p5.Renderer.js +11 -0
- package/dist/core/p5.Renderer2D.js +44 -0
- package/dist/core/reference.js +1 -0
- package/dist/core/rendering.js +40 -0
- package/{src → dist}/core/structure.js +3 -3
- package/{src → dist}/core/transform.js +2 -2
- package/{src/color/creating_reading.js → dist/creating_reading-D4AAKRbx.js} +841 -13
- package/{src → dist}/data/index.js +3 -1
- package/{src → dist}/data/local_storage.js +2 -8
- package/{src → dist}/dom/dom.js +11 -5
- package/dist/dom/index.js +18 -0
- package/{src → dist}/dom/p5.Element.js +14 -12
- package/{src → dist}/dom/p5.File.js +4 -4
- package/{src → dist}/dom/p5.MediaElement.js +10 -4
- package/{src → dist}/events/acceleration.js +2 -2
- package/{src → dist}/events/index.js +3 -1
- package/{src → dist}/events/keyboard.js +14 -11
- package/{src → dist}/events/pointer.js +16 -17
- package/dist/image/const.js +9 -0
- package/{src → dist}/image/filterRenderer2D.js +57 -37
- package/{src → dist}/image/filters.js +1 -3
- package/dist/image/image.js +40 -0
- package/dist/image/index.js +51 -0
- package/dist/image/loading_displaying.js +40 -0
- package/dist/image/p5.Image.js +11 -0
- package/{src → dist}/image/pixels.js +4 -3
- package/{src → dist}/io/csv.js +72 -70
- package/dist/io/files.js +40 -0
- package/dist/io/index.js +51 -0
- package/{src → dist}/io/p5.Table.js +6 -6
- package/{src → dist}/io/p5.TableRow.js +3 -4
- package/{src → dist}/io/p5.XML.js +2 -5
- package/{src → dist}/io/utilities.js +1 -1
- package/{src/core/p5.Renderer2D.js → dist/main-s72KWcUy.js} +735 -57
- package/{src → dist}/math/Matrices/Matrix.js +10 -8
- package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
- package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
- package/{src → dist}/math/calculation.js +2 -2
- package/{src → dist}/math/index.js +6 -3
- package/{src → dist}/math/math.js +2 -2
- package/{src → dist}/math/noise.js +2 -2
- package/{src → dist}/math/p5.Matrix.js +7 -4
- package/{src → dist}/math/p5.Vector.js +6 -6
- package/{src → dist}/math/random.js +2 -2
- package/{src → dist}/math/trigonometry.js +16 -15
- package/{src/image/p5.Image.js → dist/p5.Renderer-CwAYZOC2.js} +390 -19
- package/dist/rendering--aAe5aq3.js +24925 -0
- package/{src → dist}/shape/2d_primitives.js +18 -17
- package/{src → dist}/shape/attributes.js +18 -17
- package/{src → dist}/shape/curves.js +2 -2
- package/{src → dist}/shape/custom_shapes.js +44 -64
- package/{src → dist}/shape/index.js +10 -2
- package/{src → dist}/shape/vertex.js +2 -3
- package/dist/type/index.js +25 -0
- package/{src → dist}/type/lib/Typr.js +76 -94
- package/{src → dist}/type/p5.Font.js +37 -61
- package/{src → dist}/type/textCore.js +34 -57
- package/{src → dist}/type/unicodeRanges.js +3 -1
- package/{src → dist}/utilities/conversion.js +2 -2
- package/{src → dist}/utilities/index.js +3 -1
- package/{src → dist}/utilities/time_date.js +6 -7
- package/{src → dist}/utilities/utility_functions.js +2 -2
- package/dist/webgl/3d_primitives.js +40 -0
- package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
- package/{src → dist}/webgl/GeometryBuilder.js +12 -8
- package/{src → dist}/webgl/ShaderGenerator.js +79 -82
- package/{src → dist}/webgl/ShapeBuilder.js +26 -23
- package/dist/webgl/index.js +76 -0
- package/{src → dist}/webgl/interaction.js +7 -6
- package/dist/webgl/light.js +40 -0
- package/{src → dist}/webgl/loading.js +45 -12
- package/dist/webgl/material.js +40 -0
- package/dist/webgl/p5.Camera.js +40 -0
- package/{src → dist}/webgl/p5.DataArray.js +3 -5
- package/dist/webgl/p5.Framebuffer.js +40 -0
- package/{src → dist}/webgl/p5.Geometry.js +12 -15
- package/{src → dist}/webgl/p5.Quat.js +5 -4
- package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
- package/dist/webgl/p5.RendererGL.js +40 -0
- package/dist/webgl/p5.Shader.js +40 -0
- package/dist/webgl/p5.Texture.js +40 -0
- package/{src → dist}/webgl/text.js +51 -9
- package/lib/p5.esm.js +102 -48
- package/lib/p5.js +102 -48
- package/lib/p5.min.js +1 -1
- package/package.json +17 -16
- package/translations/dev.js +6 -6
- package/translations/index.js +1 -1
- package/src/README.md +0 -27
- package/src/accessibility/index.js +0 -13
- package/src/app.js +0 -61
- package/src/color/index.js +0 -9
- package/src/color/p5.Color.culori.js +0 -66
- package/src/color/p5.Color.js +0 -851
- package/src/core/README.md +0 -91
- package/src/core/friendly_errors/index.js +0 -13
- package/src/core/friendly_errors/param_validator.js +0 -561
- package/src/core/init.js +0 -58
- package/src/core/internationalization.js +0 -195
- package/src/core/legacy.js +0 -29
- package/src/core/main.js +0 -689
- package/src/core/noop.js +0 -1
- package/src/core/p5.Graphics.js +0 -696
- package/src/core/p5.Renderer.js +0 -408
- package/src/core/reference.js +0 -2060
- package/src/core/rendering.js +0 -697
- package/src/dom/index.js +0 -11
- package/src/image/const.js +0 -6
- package/src/image/image.js +0 -731
- package/src/image/index.js +0 -15
- package/src/image/loading_displaying.js +0 -1431
- package/src/io/files.js +0 -2210
- package/src/io/index.js +0 -11
- package/src/math/README.md +0 -40
- package/src/type/index.js +0 -9
- package/src/webgl/3d_primitives.js +0 -2741
- package/src/webgl/index.js +0 -37
- package/src/webgl/light.js +0 -1851
- package/src/webgl/material.js +0 -3854
- package/src/webgl/p5.Camera.js +0 -4010
- package/src/webgl/p5.Framebuffer.js +0 -1865
- package/src/webgl/p5.RendererGL.js +0 -2867
- package/src/webgl/p5.Shader.js +0 -1505
- package/src/webgl/p5.Texture.js +0 -541
- package/src/webgl/shaders/basic.frag +0 -6
- package/src/webgl/shaders/filters/base.frag +0 -22
- package/src/webgl/shaders/filters/base.vert +0 -19
- package/src/webgl/shaders/filters/blur.frag +0 -60
- package/src/webgl/shaders/filters/default.vert +0 -18
- package/src/webgl/shaders/filters/dilate.frag +0 -39
- package/src/webgl/shaders/filters/erode.frag +0 -39
- package/src/webgl/shaders/filters/gray.frag +0 -16
- package/src/webgl/shaders/filters/invert.frag +0 -15
- package/src/webgl/shaders/filters/opaque.frag +0 -12
- package/src/webgl/shaders/filters/posterize.frag +0 -29
- package/src/webgl/shaders/filters/threshold.frag +0 -23
- package/src/webgl/shaders/font.frag +0 -216
- package/src/webgl/shaders/font.vert +0 -44
- package/src/webgl/shaders/imageLight.vert +0 -33
- package/src/webgl/shaders/imageLightDiffused.frag +0 -82
- package/src/webgl/shaders/imageLightSpecular.frag +0 -134
- package/src/webgl/shaders/light.vert +0 -37
- package/src/webgl/shaders/light_texture.frag +0 -26
- package/src/webgl/shaders/lighting.glsl +0 -227
- package/src/webgl/shaders/line.frag +0 -74
- package/src/webgl/shaders/line.vert +0 -294
- package/src/webgl/shaders/normal.frag +0 -6
- package/src/webgl/shaders/normal.vert +0 -72
- package/src/webgl/shaders/phong.frag +0 -84
- package/src/webgl/shaders/phong.vert +0 -87
- package/src/webgl/shaders/point.frag +0 -29
- package/src/webgl/shaders/point.vert +0 -19
- package/src/webgl/shaders/sphereMapping.frag +0 -26
- package/src/webgl/shaders/webgl2Compatibility.glsl +0 -34
package/src/image/image.js
DELETED
|
@@ -1,731 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module Image
|
|
3
|
-
* @submodule Image
|
|
4
|
-
* @for p5
|
|
5
|
-
* @requires core
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* This module defines the p5 methods for the <a href="#/p5.Image">p5.Image</a> class
|
|
10
|
-
* for drawing images to the main display canvas.
|
|
11
|
-
*/
|
|
12
|
-
import * as omggif from 'omggif';
|
|
13
|
-
import { Element } from '../dom/p5.Element';
|
|
14
|
-
import { Framebuffer } from '../webgl/p5.Framebuffer';
|
|
15
|
-
|
|
16
|
-
function image(p5, fn){
|
|
17
|
-
/**
|
|
18
|
-
* Creates a new <a href="#/p5.Image">p5.Image</a> object.
|
|
19
|
-
*
|
|
20
|
-
* `createImage()` uses the `width` and `height` parameters to set the new
|
|
21
|
-
* <a href="#/p5.Image">p5.Image</a> object's dimensions in pixels. The new
|
|
22
|
-
* <a href="#/p5.Image">p5.Image</a> can be modified by updating its
|
|
23
|
-
* <a href="#/p5.Image/pixels">pixels</a> array or by calling its
|
|
24
|
-
* <a href="#/p5.Image/get">get()</a> and
|
|
25
|
-
* <a href="#/p5.Image/set">set()</a> methods. The
|
|
26
|
-
* <a href="#/p5.Image/loadPixels">loadPixels()</a> method must be called
|
|
27
|
-
* before reading or modifying pixel values. The
|
|
28
|
-
* <a href="#/p5.Image/updatePixels">updatePixels()</a> method must be called
|
|
29
|
-
* for updates to take effect.
|
|
30
|
-
*
|
|
31
|
-
* Note: The new <a href="#/p5.Image">p5.Image</a> object is transparent by
|
|
32
|
-
* default.
|
|
33
|
-
*
|
|
34
|
-
* @method createImage
|
|
35
|
-
* @param {Integer} width width in pixels.
|
|
36
|
-
* @param {Integer} height height in pixels.
|
|
37
|
-
* @return {p5.Image} new <a href="#/p5.Image">p5.Image</a> object.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* <div>
|
|
41
|
-
* <code>
|
|
42
|
-
* function setup() {
|
|
43
|
-
* createCanvas(100, 100);
|
|
44
|
-
*
|
|
45
|
-
* background(200);
|
|
46
|
-
*
|
|
47
|
-
* // Create a p5.Image object.
|
|
48
|
-
* let img = createImage(66, 66);
|
|
49
|
-
*
|
|
50
|
-
* // Load the image's pixels into memory.
|
|
51
|
-
* img.loadPixels();
|
|
52
|
-
*
|
|
53
|
-
* // Set all the image's pixels to black.
|
|
54
|
-
* for (let x = 0; x < img.width; x += 1) {
|
|
55
|
-
* for (let y = 0; y < img.height; y += 1) {
|
|
56
|
-
* img.set(x, y, 0);
|
|
57
|
-
* }
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* // Update the image's pixel values.
|
|
61
|
-
* img.updatePixels();
|
|
62
|
-
*
|
|
63
|
-
* // Draw the image.
|
|
64
|
-
* image(img, 17, 17);
|
|
65
|
-
*
|
|
66
|
-
* describe('A black square drawn in the middle of a gray square.');
|
|
67
|
-
* }
|
|
68
|
-
* </code>
|
|
69
|
-
* </div>
|
|
70
|
-
*
|
|
71
|
-
* <div>
|
|
72
|
-
* <code>
|
|
73
|
-
* function setup() {
|
|
74
|
-
* createCanvas(100, 100);
|
|
75
|
-
*
|
|
76
|
-
* background(200);
|
|
77
|
-
*
|
|
78
|
-
* // Create a p5.Image object.
|
|
79
|
-
* let img = createImage(66, 66);
|
|
80
|
-
*
|
|
81
|
-
* // Load the image's pixels into memory.
|
|
82
|
-
* img.loadPixels();
|
|
83
|
-
*
|
|
84
|
-
* // Create a color gradient.
|
|
85
|
-
* for (let x = 0; x < img.width; x += 1) {
|
|
86
|
-
* for (let y = 0; y < img.height; y += 1) {
|
|
87
|
-
* // Calculate the transparency.
|
|
88
|
-
* let a = map(x, 0, img.width, 0, 255);
|
|
89
|
-
*
|
|
90
|
-
* // Create a p5.Color object.
|
|
91
|
-
* let c = color(0, a);
|
|
92
|
-
*
|
|
93
|
-
* // Set the pixel's color.
|
|
94
|
-
* img.set(x, y, c);
|
|
95
|
-
* }
|
|
96
|
-
* }
|
|
97
|
-
*
|
|
98
|
-
* // Update the image's pixels.
|
|
99
|
-
* img.updatePixels();
|
|
100
|
-
*
|
|
101
|
-
* // Display the image.
|
|
102
|
-
* image(img, 17, 17);
|
|
103
|
-
*
|
|
104
|
-
* describe('A square with a horizontal color gradient that transitions from gray to black.');
|
|
105
|
-
* }
|
|
106
|
-
* </code>
|
|
107
|
-
* </div>
|
|
108
|
-
*
|
|
109
|
-
* <div>
|
|
110
|
-
* <code>
|
|
111
|
-
* function setup() {
|
|
112
|
-
* createCanvas(100, 100);
|
|
113
|
-
*
|
|
114
|
-
* background(200);
|
|
115
|
-
*
|
|
116
|
-
* // Create a p5.Image object.
|
|
117
|
-
* let img = createImage(66, 66);
|
|
118
|
-
*
|
|
119
|
-
* // Load the pixels into memory.
|
|
120
|
-
* img.loadPixels();
|
|
121
|
-
* // Get the current pixel density.
|
|
122
|
-
* let d = pixelDensity();
|
|
123
|
-
*
|
|
124
|
-
* // Calculate the pixel that is halfway through the image's pixel array.
|
|
125
|
-
* let halfImage = 4 * (d * img.width) * (d * img.height / 2);
|
|
126
|
-
*
|
|
127
|
-
* // Set half of the image's pixels to black.
|
|
128
|
-
* for (let i = 0; i < halfImage; i += 4) {
|
|
129
|
-
* // Red.
|
|
130
|
-
* img.pixels[i] = 0;
|
|
131
|
-
* // Green.
|
|
132
|
-
* img.pixels[i + 1] = 0;
|
|
133
|
-
* // Blue.
|
|
134
|
-
* img.pixels[i + 2] = 0;
|
|
135
|
-
* // Alpha.
|
|
136
|
-
* img.pixels[i + 3] = 255;
|
|
137
|
-
* }
|
|
138
|
-
*
|
|
139
|
-
* // Update the image's pixels.
|
|
140
|
-
* img.updatePixels();
|
|
141
|
-
*
|
|
142
|
-
* // Display the image.
|
|
143
|
-
* image(img, 17, 17);
|
|
144
|
-
*
|
|
145
|
-
* describe('A black square drawn in the middle of a gray square.');
|
|
146
|
-
* }
|
|
147
|
-
* </code>
|
|
148
|
-
* </div>
|
|
149
|
-
*/
|
|
150
|
-
fn.createImage = function(width, height) {
|
|
151
|
-
// p5._validateParameters('createImage', arguments);
|
|
152
|
-
return new p5.Image(width, height);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Saves the current canvas as an image.
|
|
157
|
-
*
|
|
158
|
-
* By default, `saveCanvas()` saves the canvas as a PNG image called
|
|
159
|
-
* `untitled.png`.
|
|
160
|
-
*
|
|
161
|
-
* The first parameter, `filename`, is optional. It's a string that sets the
|
|
162
|
-
* file's name. If a file extension is included, as in
|
|
163
|
-
* `saveCanvas('drawing.png')`, then the image will be saved using that
|
|
164
|
-
* format.
|
|
165
|
-
*
|
|
166
|
-
* The second parameter, `extension`, is also optional. It sets the files format.
|
|
167
|
-
* Either `'png'`, `'webp'`, or `'jpg'` can be used. For example, `saveCanvas('drawing', 'jpg')`
|
|
168
|
-
* saves the canvas to a file called `drawing.jpg`.
|
|
169
|
-
*
|
|
170
|
-
* Note: The browser will either save the file immediately or prompt the user
|
|
171
|
-
* with a dialogue window.
|
|
172
|
-
*
|
|
173
|
-
* @method saveCanvas
|
|
174
|
-
* @param {p5.Framebuffer|p5.Element|HTMLCanvasElement} selectedCanvas reference to a
|
|
175
|
-
* specific HTML5 canvas element.
|
|
176
|
-
* @param {String} [filename] file name. Defaults to 'untitled'.
|
|
177
|
-
* @param {String} [extension] file extension, either 'png', 'webp', or 'jpg'. Defaults to 'png'.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* <div class='norender'>
|
|
181
|
-
* <code>
|
|
182
|
-
* function setup() {
|
|
183
|
-
* createCanvas(100, 100);
|
|
184
|
-
* background(255);
|
|
185
|
-
*
|
|
186
|
-
* // Save the canvas to 'untitled.png'.
|
|
187
|
-
* saveCanvas();
|
|
188
|
-
*
|
|
189
|
-
* describe('A white square.');
|
|
190
|
-
* }
|
|
191
|
-
* </code>
|
|
192
|
-
* </div>
|
|
193
|
-
*
|
|
194
|
-
* <div class='norender'>
|
|
195
|
-
* <code>
|
|
196
|
-
* function setup() {
|
|
197
|
-
* createCanvas(100, 100);
|
|
198
|
-
*
|
|
199
|
-
* background(255);
|
|
200
|
-
*
|
|
201
|
-
* // Save the canvas to 'myCanvas.jpg'.
|
|
202
|
-
* saveCanvas('myCanvas.jpg');
|
|
203
|
-
*
|
|
204
|
-
* describe('A white square.');
|
|
205
|
-
* }
|
|
206
|
-
* </code>
|
|
207
|
-
* </div>
|
|
208
|
-
*
|
|
209
|
-
* <div class='norender'>
|
|
210
|
-
* <code>
|
|
211
|
-
* function setup() {
|
|
212
|
-
* createCanvas(100, 100);
|
|
213
|
-
*
|
|
214
|
-
* background(255);
|
|
215
|
-
*
|
|
216
|
-
* // Save the canvas to 'myCanvas.jpg'.
|
|
217
|
-
* saveCanvas('myCanvas', 'jpg');
|
|
218
|
-
*
|
|
219
|
-
* describe('A white square.');
|
|
220
|
-
* }
|
|
221
|
-
* </code>
|
|
222
|
-
* </div>
|
|
223
|
-
*
|
|
224
|
-
* <div class='norender'>
|
|
225
|
-
* <code>
|
|
226
|
-
* function setup() {
|
|
227
|
-
* let cnv = createCanvas(100, 100);
|
|
228
|
-
*
|
|
229
|
-
* background(255);
|
|
230
|
-
*
|
|
231
|
-
* // Save the canvas to 'untitled.png'.
|
|
232
|
-
* saveCanvas(cnv);
|
|
233
|
-
*
|
|
234
|
-
* describe('A white square.');
|
|
235
|
-
* }
|
|
236
|
-
* </code>
|
|
237
|
-
* </div>
|
|
238
|
-
*
|
|
239
|
-
* <div class='norender'>
|
|
240
|
-
* <code>
|
|
241
|
-
* function setup() {
|
|
242
|
-
* let cnv = createCanvas(100, 100);
|
|
243
|
-
*
|
|
244
|
-
* background(255);
|
|
245
|
-
*
|
|
246
|
-
* // Save the canvas to 'myCanvas.jpg'.
|
|
247
|
-
* saveCanvas(cnv, 'myCanvas.jpg');
|
|
248
|
-
*
|
|
249
|
-
* describe('A white square.');
|
|
250
|
-
* }
|
|
251
|
-
* </code>
|
|
252
|
-
* </div>
|
|
253
|
-
*
|
|
254
|
-
* <div class='norender'>
|
|
255
|
-
* <code>
|
|
256
|
-
* function setup() {
|
|
257
|
-
* let cnv = createCanvas(100, 100);
|
|
258
|
-
*
|
|
259
|
-
* background(255);
|
|
260
|
-
*
|
|
261
|
-
* // Save the canvas to 'myCanvas.jpg'.
|
|
262
|
-
* saveCanvas(cnv, 'myCanvas', 'jpg');
|
|
263
|
-
*
|
|
264
|
-
* describe('A white square.');
|
|
265
|
-
* }
|
|
266
|
-
* </code>
|
|
267
|
-
* </div>
|
|
268
|
-
*/
|
|
269
|
-
/**
|
|
270
|
-
* @method saveCanvas
|
|
271
|
-
* @param {String} [filename]
|
|
272
|
-
* @param {String} [extension]
|
|
273
|
-
*/
|
|
274
|
-
fn.saveCanvas = function(...args) {
|
|
275
|
-
// copy arguments to array
|
|
276
|
-
let htmlCanvas, filename, extension, temporaryGraphics;
|
|
277
|
-
|
|
278
|
-
if (args[0] instanceof HTMLCanvasElement) {
|
|
279
|
-
htmlCanvas = args[0];
|
|
280
|
-
args.shift();
|
|
281
|
-
} else if (args[0] instanceof Element) {
|
|
282
|
-
htmlCanvas = args[0].elt;
|
|
283
|
-
args.shift();
|
|
284
|
-
} else if (args[0] instanceof Framebuffer) {
|
|
285
|
-
const framebuffer = args[0];
|
|
286
|
-
temporaryGraphics = this.createGraphics(framebuffer.width,
|
|
287
|
-
framebuffer.height);
|
|
288
|
-
temporaryGraphics.pixelDensity(framebuffer.pixelDensity());
|
|
289
|
-
framebuffer.loadPixels();
|
|
290
|
-
temporaryGraphics.loadPixels();
|
|
291
|
-
temporaryGraphics.pixels.set(framebuffer.pixels);
|
|
292
|
-
temporaryGraphics.updatePixels();
|
|
293
|
-
|
|
294
|
-
htmlCanvas = temporaryGraphics._renderer.canvas;
|
|
295
|
-
args.shift();
|
|
296
|
-
} else {
|
|
297
|
-
htmlCanvas = this._curElement && this._curElement.elt;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (args.length >= 1) {
|
|
301
|
-
filename = args[0];
|
|
302
|
-
}
|
|
303
|
-
if (args.length >= 2) {
|
|
304
|
-
extension = args[1];
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
extension =
|
|
308
|
-
extension ||
|
|
309
|
-
fn._checkFileExtension(filename, extension)[1] ||
|
|
310
|
-
'png';
|
|
311
|
-
|
|
312
|
-
let mimeType;
|
|
313
|
-
switch (extension) {
|
|
314
|
-
default:
|
|
315
|
-
//case 'png':
|
|
316
|
-
mimeType = 'image/png';
|
|
317
|
-
break;
|
|
318
|
-
case 'webp':
|
|
319
|
-
mimeType = 'image/webp';
|
|
320
|
-
break;
|
|
321
|
-
case 'jpeg':
|
|
322
|
-
case 'jpg':
|
|
323
|
-
mimeType = 'image/jpeg';
|
|
324
|
-
break;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
htmlCanvas.toBlob(blob => {
|
|
328
|
-
fn.downloadFile(blob, filename, extension);
|
|
329
|
-
if(temporaryGraphics) temporaryGraphics.remove();
|
|
330
|
-
}, mimeType);
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
// this is the old saveGif, left here for compatibility purposes
|
|
334
|
-
// the only place I found it being used was on image/p5.Image.js, on the
|
|
335
|
-
// save function. that has been changed to use this function.
|
|
336
|
-
fn.encodeAndDownloadGif = function(pImg, filename) {
|
|
337
|
-
const props = pImg.gifProperties;
|
|
338
|
-
|
|
339
|
-
//convert loopLimit back into Netscape Block formatting
|
|
340
|
-
let loopLimit = props.loopLimit;
|
|
341
|
-
if (loopLimit === 1) {
|
|
342
|
-
loopLimit = null;
|
|
343
|
-
} else if (loopLimit === null) {
|
|
344
|
-
loopLimit = 0;
|
|
345
|
-
}
|
|
346
|
-
const buffer = new Uint8Array(pImg.width * pImg.height * props.numFrames);
|
|
347
|
-
|
|
348
|
-
const allFramesPixelColors = [];
|
|
349
|
-
|
|
350
|
-
// Used to determine the occurrence of unique palettes and the frames
|
|
351
|
-
// which use them
|
|
352
|
-
const paletteFreqsAndFrames = {};
|
|
353
|
-
|
|
354
|
-
// Pass 1:
|
|
355
|
-
//loop over frames and get the frequency of each palette
|
|
356
|
-
for (let i = 0; i < props.numFrames; i++) {
|
|
357
|
-
const paletteSet = new Set();
|
|
358
|
-
const data = props.frames[i].image.data;
|
|
359
|
-
const dataLength = data.length;
|
|
360
|
-
// The color for each pixel in this frame ( for easier lookup later )
|
|
361
|
-
const pixelColors = new Uint32Array(pImg.width * pImg.height);
|
|
362
|
-
for (let j = 0, k = 0; j < dataLength; j += 4, k++) {
|
|
363
|
-
const r = data[j + 0];
|
|
364
|
-
const g = data[j + 1];
|
|
365
|
-
const b = data[j + 2];
|
|
366
|
-
const color = (r << 16) | (g << 8) | (b << 0);
|
|
367
|
-
paletteSet.add(color);
|
|
368
|
-
|
|
369
|
-
// What color does this pixel have in this frame ?
|
|
370
|
-
pixelColors[k] = color;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// A way to put use the entire palette as an object key
|
|
374
|
-
const paletteStr = [...paletteSet].sort().toString();
|
|
375
|
-
if (paletteFreqsAndFrames[paletteStr] === undefined) {
|
|
376
|
-
paletteFreqsAndFrames[paletteStr] = { freq: 1, frames: [i] };
|
|
377
|
-
} else {
|
|
378
|
-
paletteFreqsAndFrames[paletteStr].freq += 1;
|
|
379
|
-
paletteFreqsAndFrames[paletteStr].frames.push(i);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
allFramesPixelColors.push(pixelColors);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
let framesUsingGlobalPalette = [];
|
|
386
|
-
|
|
387
|
-
// Now to build the global palette
|
|
388
|
-
// Sort all the unique palettes in descending order of their occurrence
|
|
389
|
-
const palettesSortedByFreq = Object.keys(paletteFreqsAndFrames).sort(function(
|
|
390
|
-
a,
|
|
391
|
-
b
|
|
392
|
-
) {
|
|
393
|
-
return paletteFreqsAndFrames[b].freq - paletteFreqsAndFrames[a].freq;
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
// The initial global palette is the one with the most occurrence
|
|
397
|
-
const globalPalette = palettesSortedByFreq[0]
|
|
398
|
-
.split(',')
|
|
399
|
-
.map(a => parseInt(a));
|
|
400
|
-
|
|
401
|
-
framesUsingGlobalPalette = framesUsingGlobalPalette.concat(
|
|
402
|
-
paletteFreqsAndFrames[globalPalette].frames
|
|
403
|
-
);
|
|
404
|
-
|
|
405
|
-
const globalPaletteSet = new Set(globalPalette);
|
|
406
|
-
|
|
407
|
-
// Build a more complete global palette
|
|
408
|
-
// Iterate over the remaining palettes in the order of
|
|
409
|
-
// their occurrence and see if the colors in this palette which are
|
|
410
|
-
// not in the global palette can be added there, while keeping the length
|
|
411
|
-
// of the global palette <= 256
|
|
412
|
-
for (let i = 1; i < palettesSortedByFreq.length; i++) {
|
|
413
|
-
const palette = palettesSortedByFreq[i].split(',').map(a => parseInt(a));
|
|
414
|
-
|
|
415
|
-
const difference = palette.filter(x => !globalPaletteSet.has(x));
|
|
416
|
-
if (globalPalette.length + difference.length <= 256) {
|
|
417
|
-
for (let j = 0; j < difference.length; j++) {
|
|
418
|
-
globalPalette.push(difference[j]);
|
|
419
|
-
globalPaletteSet.add(difference[j]);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// All frames using this palette now use the global palette
|
|
423
|
-
framesUsingGlobalPalette = framesUsingGlobalPalette.concat(
|
|
424
|
-
paletteFreqsAndFrames[palettesSortedByFreq[i]].frames
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
framesUsingGlobalPalette = new Set(framesUsingGlobalPalette);
|
|
430
|
-
|
|
431
|
-
// Build a lookup table of the index of each color in the global palette
|
|
432
|
-
// Maps a color to its index
|
|
433
|
-
const globalIndicesLookup = {};
|
|
434
|
-
for (let i = 0; i < globalPalette.length; i++) {
|
|
435
|
-
if (!globalIndicesLookup[globalPalette[i]]) {
|
|
436
|
-
globalIndicesLookup[globalPalette[i]] = i;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// force palette to be power of 2
|
|
441
|
-
let powof2 = 1;
|
|
442
|
-
while (powof2 < globalPalette.length) {
|
|
443
|
-
powof2 <<= 1;
|
|
444
|
-
}
|
|
445
|
-
globalPalette.length = powof2;
|
|
446
|
-
|
|
447
|
-
// global opts
|
|
448
|
-
const opts = {
|
|
449
|
-
loop: loopLimit,
|
|
450
|
-
palette: new Uint32Array(globalPalette)
|
|
451
|
-
};
|
|
452
|
-
const gifWriter = new omggif.GifWriter(buffer, pImg.width, pImg.height, opts);
|
|
453
|
-
let previousFrame = {};
|
|
454
|
-
|
|
455
|
-
// Pass 2
|
|
456
|
-
// Determine if the frame needs a local palette
|
|
457
|
-
// Also apply transparency optimization. This function will often blow up
|
|
458
|
-
// the size of a GIF if not for transparency. If a pixel in one frame has
|
|
459
|
-
// the same color in the previous frame, that pixel can be marked as
|
|
460
|
-
// transparent. We decide one particular color as transparent and make all
|
|
461
|
-
// transparent pixels take this color. This helps in later in compression.
|
|
462
|
-
for (let i = 0; i < props.numFrames; i++) {
|
|
463
|
-
const localPaletteRequired = !framesUsingGlobalPalette.has(i);
|
|
464
|
-
const palette = localPaletteRequired ? [] : globalPalette;
|
|
465
|
-
const pixelPaletteIndex = new Uint8Array(pImg.width * pImg.height);
|
|
466
|
-
|
|
467
|
-
// Lookup table mapping color to its indices
|
|
468
|
-
const colorIndicesLookup = {};
|
|
469
|
-
|
|
470
|
-
// All the colors that cannot be marked transparent in this frame
|
|
471
|
-
const cannotBeTransparent = new Set();
|
|
472
|
-
|
|
473
|
-
allFramesPixelColors[i].forEach((color, k) => {
|
|
474
|
-
if (localPaletteRequired) {
|
|
475
|
-
if (colorIndicesLookup[color] === undefined) {
|
|
476
|
-
colorIndicesLookup[color] = palette.length;
|
|
477
|
-
palette.push(color);
|
|
478
|
-
}
|
|
479
|
-
pixelPaletteIndex[k] = colorIndicesLookup[color];
|
|
480
|
-
} else {
|
|
481
|
-
pixelPaletteIndex[k] = globalIndicesLookup[color];
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
if (i > 0) {
|
|
485
|
-
// If even one pixel of this color has changed in this frame
|
|
486
|
-
// from the previous frame, we cannot mark it as transparent
|
|
487
|
-
if (allFramesPixelColors[i - 1][k] !== color) {
|
|
488
|
-
cannotBeTransparent.add(color);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
const frameOpts = {};
|
|
494
|
-
|
|
495
|
-
// Transparency optimization
|
|
496
|
-
const canBeTransparent = palette.filter(a => !cannotBeTransparent.has(a));
|
|
497
|
-
if (canBeTransparent.length > 0) {
|
|
498
|
-
// Select a color to mark as transparent
|
|
499
|
-
const transparent = canBeTransparent[0];
|
|
500
|
-
const transparentIndex = localPaletteRequired
|
|
501
|
-
? colorIndicesLookup[transparent]
|
|
502
|
-
: globalIndicesLookup[transparent];
|
|
503
|
-
if (i > 0) {
|
|
504
|
-
for (let k = 0; k < allFramesPixelColors[i].length; k++) {
|
|
505
|
-
// If this pixel in this frame has the same color in previous frame
|
|
506
|
-
if (allFramesPixelColors[i - 1][k] === allFramesPixelColors[i][k]) {
|
|
507
|
-
pixelPaletteIndex[k] = transparentIndex;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
frameOpts.transparent = transparentIndex;
|
|
511
|
-
// If this frame has any transparency, do not dispose the previous frame
|
|
512
|
-
previousFrame.frameOpts.disposal = 1;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
frameOpts.delay = props.frames[i].delay / 10; // Move timing back into GIF formatting
|
|
516
|
-
if (localPaletteRequired) {
|
|
517
|
-
// force palette to be power of 2
|
|
518
|
-
let powof2 = 1;
|
|
519
|
-
while (powof2 < palette.length) {
|
|
520
|
-
powof2 <<= 1;
|
|
521
|
-
}
|
|
522
|
-
palette.length = powof2;
|
|
523
|
-
frameOpts.palette = new Uint32Array(palette);
|
|
524
|
-
}
|
|
525
|
-
if (i > 0) {
|
|
526
|
-
// add the frame that came before the current one
|
|
527
|
-
gifWriter.addFrame(
|
|
528
|
-
0,
|
|
529
|
-
0,
|
|
530
|
-
pImg.width,
|
|
531
|
-
pImg.height,
|
|
532
|
-
previousFrame.pixelPaletteIndex,
|
|
533
|
-
previousFrame.frameOpts
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
// previous frame object should now have details of this frame
|
|
537
|
-
previousFrame = {
|
|
538
|
-
pixelPaletteIndex,
|
|
539
|
-
frameOpts
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
previousFrame.frameOpts.disposal = 1;
|
|
544
|
-
// add the last frame
|
|
545
|
-
gifWriter.addFrame(
|
|
546
|
-
0,
|
|
547
|
-
0,
|
|
548
|
-
pImg.width,
|
|
549
|
-
pImg.height,
|
|
550
|
-
previousFrame.pixelPaletteIndex,
|
|
551
|
-
previousFrame.frameOpts
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
const extension = 'gif';
|
|
555
|
-
const blob = new Blob([buffer.slice(0, gifWriter.end())], {
|
|
556
|
-
type: 'image/gif'
|
|
557
|
-
});
|
|
558
|
-
fn.downloadFile(blob, filename, extension);
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* Captures a sequence of frames from the canvas that can be saved as images.
|
|
563
|
-
*
|
|
564
|
-
* `saveFrames()` creates an array of frame objects. Each frame is stored as
|
|
565
|
-
* an object with its file type, file name, and image data as a string. For
|
|
566
|
-
* example, the first saved frame might have the following properties:
|
|
567
|
-
*
|
|
568
|
-
* `{ ext: 'png', filenmame: 'frame0', imageData: 'data:image/octet-stream;base64, abc123' }`.
|
|
569
|
-
*
|
|
570
|
-
* The first parameter, `filename`, sets the prefix for the file names. For
|
|
571
|
-
* example, setting the prefix to `'frame'` would generate the image files
|
|
572
|
-
* `frame0.png`, `frame1.png`, and so on.
|
|
573
|
-
*
|
|
574
|
-
* The second parameter, `extension`, sets the file type to either `'png'` or
|
|
575
|
-
* `'jpg'`.
|
|
576
|
-
*
|
|
577
|
-
* The third parameter, `duration`, sets the duration to record in seconds.
|
|
578
|
-
* The maximum duration is 15 seconds.
|
|
579
|
-
*
|
|
580
|
-
* The fourth parameter, `framerate`, sets the number of frames to record per
|
|
581
|
-
* second. The maximum frame rate value is 22. Limits are placed on `duration`
|
|
582
|
-
* and `framerate` to avoid using too much memory. Recording large canvases
|
|
583
|
-
* can easily crash sketches or even web browsers.
|
|
584
|
-
*
|
|
585
|
-
* The fifth parameter, `callback`, is optional. If a function is passed,
|
|
586
|
-
* image files won't be saved by default. The callback function can be used
|
|
587
|
-
* to process an array containing the data for each captured frame. The array
|
|
588
|
-
* of image data contains a sequence of objects with three properties for each
|
|
589
|
-
* frame: `imageData`, `filename`, and `extension`.
|
|
590
|
-
*
|
|
591
|
-
* Note: Frames are downloaded as individual image files by default.
|
|
592
|
-
*
|
|
593
|
-
* @method saveFrames
|
|
594
|
-
* @param {String} filename prefix of file name.
|
|
595
|
-
* @param {String} extension file extension, either 'jpg' or 'png'.
|
|
596
|
-
* @param {Number} duration duration in seconds to record. This parameter will be constrained to be less or equal to 15.
|
|
597
|
-
* @param {Number} framerate number of frames to save per second. This parameter will be constrained to be less or equal to 22.
|
|
598
|
-
* @param {function(Array)} [callback] callback function that will be executed
|
|
599
|
-
to handle the image data. This function
|
|
600
|
-
should accept an array as argument. The
|
|
601
|
-
array will contain the specified number of
|
|
602
|
-
frames of objects. Each object has three
|
|
603
|
-
properties: `imageData`, `filename`, and `extension`.
|
|
604
|
-
* @example
|
|
605
|
-
* <div>
|
|
606
|
-
* <code>
|
|
607
|
-
* function setup() {
|
|
608
|
-
* createCanvas(100, 100);
|
|
609
|
-
*
|
|
610
|
-
* describe('A square repeatedly changes color from blue to pink.');
|
|
611
|
-
* }
|
|
612
|
-
*
|
|
613
|
-
* function draw() {
|
|
614
|
-
* let r = frameCount % 255;
|
|
615
|
-
* let g = 50;
|
|
616
|
-
* let b = 100;
|
|
617
|
-
* background(r, g, b);
|
|
618
|
-
* }
|
|
619
|
-
*
|
|
620
|
-
* // Save the frames when the user presses the 's' key.
|
|
621
|
-
* function keyPressed() {
|
|
622
|
-
* if (key === 's') {
|
|
623
|
-
* saveFrames('frame', 'png', 1, 5);
|
|
624
|
-
* }
|
|
625
|
-
* }
|
|
626
|
-
* </code>
|
|
627
|
-
* </div>
|
|
628
|
-
*
|
|
629
|
-
* <div>
|
|
630
|
-
* <code>
|
|
631
|
-
* function setup() {
|
|
632
|
-
* createCanvas(100, 100);
|
|
633
|
-
*
|
|
634
|
-
* describe('A square repeatedly changes color from blue to pink.');
|
|
635
|
-
* }
|
|
636
|
-
*
|
|
637
|
-
* function draw() {
|
|
638
|
-
* let r = frameCount % 255;
|
|
639
|
-
* let g = 50;
|
|
640
|
-
* let b = 100;
|
|
641
|
-
* background(r, g, b);
|
|
642
|
-
* }
|
|
643
|
-
*
|
|
644
|
-
* // Print 5 frames when the user presses the mouse.
|
|
645
|
-
* function mousePressed() {
|
|
646
|
-
* saveFrames('frame', 'png', 1, 5, printFrames);
|
|
647
|
-
* }
|
|
648
|
-
*
|
|
649
|
-
* // Prints an array of objects containing raw image data, filenames, and extensions.
|
|
650
|
-
* function printFrames(frames) {
|
|
651
|
-
* for (let frame of frames) {
|
|
652
|
-
* print(frame);
|
|
653
|
-
* }
|
|
654
|
-
* }
|
|
655
|
-
* </code>
|
|
656
|
-
* </div>
|
|
657
|
-
*/
|
|
658
|
-
fn.saveFrames = function(fName, ext, _duration, _fps, callback) {
|
|
659
|
-
// p5._validateParameters('saveFrames', arguments);
|
|
660
|
-
let duration = _duration || 3;
|
|
661
|
-
duration = Math.max(Math.min(duration, 15), 0);
|
|
662
|
-
duration = duration * 1000;
|
|
663
|
-
let fps = _fps || 15;
|
|
664
|
-
fps = Math.max(Math.min(fps, 22), 0);
|
|
665
|
-
let count = 0;
|
|
666
|
-
|
|
667
|
-
const makeFrame = fn._makeFrame;
|
|
668
|
-
const cnv = this._curElement.elt;
|
|
669
|
-
let frames = [];
|
|
670
|
-
const frameFactory = setInterval(() => {
|
|
671
|
-
frames.push(makeFrame(fName + count, ext, cnv));
|
|
672
|
-
count++;
|
|
673
|
-
}, 1000 / fps);
|
|
674
|
-
|
|
675
|
-
setTimeout(() => {
|
|
676
|
-
clearInterval(frameFactory);
|
|
677
|
-
if (callback) {
|
|
678
|
-
callback(frames);
|
|
679
|
-
} else {
|
|
680
|
-
for (const f of frames) {
|
|
681
|
-
fn.downloadFile(f.imageData, f.filename, f.ext);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
frames = []; // clear frames
|
|
685
|
-
}, duration + 0.01);
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
fn._makeFrame = function(filename, extension, _cnv) {
|
|
689
|
-
let cnv;
|
|
690
|
-
if (this) {
|
|
691
|
-
cnv = this._curElement.elt;
|
|
692
|
-
} else {
|
|
693
|
-
cnv = _cnv;
|
|
694
|
-
}
|
|
695
|
-
let mimeType;
|
|
696
|
-
if (!extension) {
|
|
697
|
-
extension = 'png';
|
|
698
|
-
mimeType = 'image/png';
|
|
699
|
-
} else {
|
|
700
|
-
switch (extension.toLowerCase()) {
|
|
701
|
-
case 'png':
|
|
702
|
-
mimeType = 'image/png';
|
|
703
|
-
break;
|
|
704
|
-
case 'jpeg':
|
|
705
|
-
mimeType = 'image/jpeg';
|
|
706
|
-
break;
|
|
707
|
-
case 'jpg':
|
|
708
|
-
mimeType = 'image/jpeg';
|
|
709
|
-
break;
|
|
710
|
-
default:
|
|
711
|
-
mimeType = 'image/png';
|
|
712
|
-
break;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
const downloadMime = 'image/octet-stream';
|
|
716
|
-
let imageData = cnv.toDataURL(mimeType);
|
|
717
|
-
imageData = imageData.replace(mimeType, downloadMime);
|
|
718
|
-
|
|
719
|
-
const thisFrame = {};
|
|
720
|
-
thisFrame.imageData = imageData;
|
|
721
|
-
thisFrame.filename = filename;
|
|
722
|
-
thisFrame.ext = extension;
|
|
723
|
-
return thisFrame;
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
export default image;
|
|
728
|
-
|
|
729
|
-
if(typeof p5 !== 'undefined'){
|
|
730
|
-
image(p5, p5.prototype);
|
|
731
|
-
}
|