p5 2.0.0 → 2.0.2

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.
Files changed (267) hide show
  1. package/{src → dist}/accessibility/color_namer.js +48 -3
  2. package/{src → dist}/accessibility/describe.js +12 -2
  3. package/{src → dist}/accessibility/gridOutput.js +2 -2
  4. package/dist/accessibility/index.js +60 -0
  5. package/{src → dist}/accessibility/outputs.js +23 -2
  6. package/{src → dist}/accessibility/textOutput.js +2 -2
  7. package/dist/app.js +120 -0
  8. package/{src → dist}/color/color_conversion.js +48 -10
  9. package/{src → dist}/color/color_spaces/hsb.js +3 -1
  10. package/dist/color/creating_reading.js +3 -0
  11. package/dist/color/index.js +13 -0
  12. package/dist/color/p5.Color.culori.js +1 -0
  13. package/dist/color/p5.Color.js +3 -0
  14. package/{src → dist}/color/setting.js +9 -6
  15. package/{src/core/constants.js → dist/constants-tYr0tCl8.js} +284 -132
  16. package/{src → dist}/core/States.js +3 -1
  17. package/dist/core/constants.js +1 -0
  18. package/{src → dist}/core/environment.js +12 -10
  19. package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
  20. package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
  21. package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
  22. package/dist/core/friendly_errors/index.js +23 -0
  23. package/dist/core/friendly_errors/param_validator.js +5421 -0
  24. package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
  25. package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
  26. package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
  27. package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
  28. package/{src → dist}/core/helpers.js +9 -6
  29. package/dist/core/init.js +105 -0
  30. package/dist/core/internationalization.js +302 -0
  31. package/dist/core/legacy.js +73 -0
  32. package/dist/core/main.js +44 -0
  33. package/dist/core/noop.js +3 -0
  34. package/dist/core/p5.Graphics.js +40 -0
  35. package/dist/core/p5.Renderer.js +11 -0
  36. package/dist/core/p5.Renderer2D.js +44 -0
  37. package/dist/core/reference.js +1 -0
  38. package/dist/core/rendering.js +40 -0
  39. package/{src → dist}/core/structure.js +3 -3
  40. package/{src → dist}/core/transform.js +2 -2
  41. package/{src/color/creating_reading.js → dist/creating_reading-Cr8L2Jnm.js} +841 -13
  42. package/{src → dist}/data/index.js +3 -1
  43. package/{src → dist}/data/local_storage.js +2 -8
  44. package/{src → dist}/dom/dom.js +19 -13
  45. package/dist/dom/index.js +18 -0
  46. package/{src → dist}/dom/p5.Element.js +14 -12
  47. package/{src → dist}/dom/p5.File.js +4 -4
  48. package/{src → dist}/dom/p5.MediaElement.js +10 -4
  49. package/{src → dist}/events/acceleration.js +26 -26
  50. package/{src → dist}/events/index.js +3 -1
  51. package/{src → dist}/events/keyboard.js +14 -12
  52. package/{src → dist}/events/pointer.js +16 -17
  53. package/dist/image/const.js +9 -0
  54. package/{src → dist}/image/filterRenderer2D.js +57 -37
  55. package/{src → dist}/image/filters.js +1 -3
  56. package/dist/image/image.js +40 -0
  57. package/dist/image/index.js +51 -0
  58. package/dist/image/loading_displaying.js +40 -0
  59. package/dist/image/p5.Image.js +11 -0
  60. package/{src → dist}/image/pixels.js +5 -3
  61. package/{src → dist}/io/csv.js +72 -70
  62. package/dist/io/files.js +40 -0
  63. package/dist/io/index.js +51 -0
  64. package/{src → dist}/io/p5.Table.js +6 -6
  65. package/{src → dist}/io/p5.TableRow.js +5 -6
  66. package/{src → dist}/io/p5.XML.js +2 -5
  67. package/{src → dist}/io/utilities.js +1 -1
  68. package/{src/core/p5.Renderer2D.js → dist/main-CAxvgiOV.js} +738 -57
  69. package/{src → dist}/math/Matrices/Matrix.js +10 -8
  70. package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
  71. package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
  72. package/{src → dist}/math/calculation.js +2 -2
  73. package/{src → dist}/math/index.js +6 -3
  74. package/{src → dist}/math/math.js +3 -3
  75. package/{src → dist}/math/noise.js +2 -2
  76. package/{src → dist}/math/p5.Matrix.js +7 -4
  77. package/{src → dist}/math/p5.Vector.js +6 -6
  78. package/{src → dist}/math/random.js +2 -2
  79. package/{src → dist}/math/trigonometry.js +16 -15
  80. package/{src/image/p5.Image.js → dist/p5.Renderer-Swjl9HQO.js} +393 -22
  81. package/dist/rendering-B5TRR7aY.js +24960 -0
  82. package/{src → dist}/shape/2d_primitives.js +18 -17
  83. package/{src → dist}/shape/attributes.js +18 -17
  84. package/{src → dist}/shape/curves.js +2 -2
  85. package/{src → dist}/shape/custom_shapes.js +44 -64
  86. package/{src → dist}/shape/index.js +10 -2
  87. package/{src → dist}/shape/vertex.js +2 -3
  88. package/dist/type/index.js +25 -0
  89. package/{src → dist}/type/lib/Typr.js +76 -94
  90. package/{src → dist}/type/p5.Font.js +37 -63
  91. package/{src → dist}/type/textCore.js +35 -58
  92. package/{src → dist}/type/unicodeRanges.js +3 -1
  93. package/{src → dist}/utilities/conversion.js +2 -2
  94. package/{src → dist}/utilities/index.js +3 -1
  95. package/{src → dist}/utilities/time_date.js +6 -7
  96. package/{src → dist}/utilities/utility_functions.js +2 -2
  97. package/dist/webgl/3d_primitives.js +40 -0
  98. package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
  99. package/{src → dist}/webgl/GeometryBuilder.js +12 -8
  100. package/{src → dist}/webgl/ShaderGenerator.js +79 -82
  101. package/{src → dist}/webgl/ShapeBuilder.js +26 -23
  102. package/dist/webgl/index.js +76 -0
  103. package/{src → dist}/webgl/interaction.js +7 -6
  104. package/dist/webgl/light.js +40 -0
  105. package/{src → dist}/webgl/loading.js +45 -12
  106. package/dist/webgl/material.js +40 -0
  107. package/dist/webgl/p5.Camera.js +40 -0
  108. package/{src → dist}/webgl/p5.DataArray.js +3 -5
  109. package/dist/webgl/p5.Framebuffer.js +40 -0
  110. package/{src → dist}/webgl/p5.Geometry.js +12 -15
  111. package/{src → dist}/webgl/p5.Quat.js +5 -4
  112. package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
  113. package/dist/webgl/p5.RendererGL.js +40 -0
  114. package/dist/webgl/p5.Shader.js +40 -0
  115. package/dist/webgl/p5.Texture.js +40 -0
  116. package/{src → dist}/webgl/text.js +78 -38
  117. package/lib/p5.esm.js +296 -194
  118. package/lib/p5.js +296 -194
  119. package/lib/p5.min.js +1 -1
  120. package/package.json +17 -17
  121. package/translations/dev.js +6 -6
  122. package/translations/index.js +1 -1
  123. package/types/accessibility/color_namer.d.ts +8 -0
  124. package/types/accessibility/describe.d.ts +184 -0
  125. package/types/accessibility/gridOutput.d.ts +8 -0
  126. package/types/accessibility/outputs.d.ts +235 -0
  127. package/types/accessibility/textOutput.d.ts +8 -0
  128. package/types/color/color_conversion.d.ts +47 -0
  129. package/types/color/creating_reading.d.ts +1348 -0
  130. package/types/color/p5.Color.d.ts +1070 -0
  131. package/types/color/setting.d.ts +2085 -0
  132. package/types/core/constants.d.ts +341 -0
  133. package/types/core/environment.d.ts +668 -0
  134. package/types/core/friendly_errors/fes_core.d.ts +8 -0
  135. package/types/core/friendly_errors/file_errors.d.ts +8 -0
  136. package/types/core/friendly_errors/param_validator.d.ts +30 -0
  137. package/types/core/friendly_errors/sketch_reader.d.ts +8 -0
  138. package/types/core/friendly_errors/stacktrace.d.ts +11 -0
  139. package/types/core/friendly_errors/validate_params.d.ts +8 -0
  140. package/types/core/helpers.d.ts +8 -0
  141. package/types/core/legacy.d.ts +8 -0
  142. package/types/core/main.d.ts +5996 -0
  143. package/types/core/p5.Graphics.d.ts +484 -0
  144. package/types/core/p5.Renderer.d.ts +14 -0
  145. package/types/core/reference.d.ts +8 -0
  146. package/types/core/rendering.d.ts +481 -0
  147. package/types/core/structure.d.ts +492 -0
  148. package/types/core/transform.d.ts +1638 -0
  149. package/types/data/local_storage.d.ts +323 -0
  150. package/types/dom/dom.d.ts +1295 -0
  151. package/types/dom/p5.Element.d.ts +2011 -0
  152. package/types/dom/p5.File.d.ts +13 -0
  153. package/types/dom/p5.MediaElement.d.ts +1249 -0
  154. package/types/events/acceleration.d.ts +193 -0
  155. package/types/events/keyboard.d.ts +499 -0
  156. package/types/events/pointer.d.ts +782 -0
  157. package/types/global.d.ts +5542 -0
  158. package/types/image/filterRenderer2D.d.ts +54 -0
  159. package/types/image/image.d.ts +326 -0
  160. package/types/image/loading_displaying.d.ts +580 -0
  161. package/types/image/p5.Image.d.ts +5882 -0
  162. package/types/image/pixels.d.ts +832 -0
  163. package/types/io/files.d.ts +1447 -0
  164. package/types/io/p5.Table.d.ts +1247 -0
  165. package/types/io/p5.TableRow.d.ts +343 -0
  166. package/types/io/p5.XML.d.ts +1188 -0
  167. package/types/math/Matrices/Matrix.d.ts +1029 -0
  168. package/types/math/Matrices/MatrixNumjs.d.ts +8 -0
  169. package/types/math/calculation.d.ts +923 -0
  170. package/types/math/math.d.ts +90 -0
  171. package/types/math/noise.d.ts +311 -0
  172. package/types/math/p5.Matrix.d.ts +8 -0
  173. package/types/math/p5.Vector.d.ts +3416 -0
  174. package/types/math/random.d.ts +267 -0
  175. package/types/math/trigonometry.d.ts +663 -0
  176. package/types/p5.d.ts +6663 -0
  177. package/types/shape/2d_primitives.d.ts +1033 -0
  178. package/types/shape/attributes.d.ts +466 -0
  179. package/types/shape/curves.d.ts +740 -0
  180. package/types/shape/custom_shapes.d.ts +888 -0
  181. package/types/shape/vertex.d.ts +1141 -0
  182. package/types/type/p5.Font.d.ts +575 -0
  183. package/types/type/textCore.d.ts +1198 -0
  184. package/types/utilities/conversion.d.ts +894 -0
  185. package/types/utilities/time_date.d.ts +295 -0
  186. package/types/utilities/utility_functions.d.ts +587 -0
  187. package/types/webgl/3d_primitives.d.ts +1432 -0
  188. package/types/webgl/ShaderGenerator.d.ts +8 -0
  189. package/types/webgl/interaction.d.ts +371 -0
  190. package/types/webgl/light.d.ts +1184 -0
  191. package/types/webgl/loading.d.ts +481 -0
  192. package/types/webgl/material.d.ts +2656 -0
  193. package/types/webgl/p5.Camera.d.ts +3023 -0
  194. package/types/webgl/p5.DataArray.d.ts +61 -0
  195. package/types/webgl/p5.Framebuffer.d.ts +760 -0
  196. package/types/webgl/p5.Geometry.d.ts +1191 -0
  197. package/types/webgl/p5.Quat.d.ts +45 -0
  198. package/types/webgl/p5.RendererGL.d.ts +234 -0
  199. package/types/webgl/p5.Shader.d.ts +660 -0
  200. package/types/webgl/p5.Texture.d.ts +61 -0
  201. package/types/webgl/text.d.ts +74 -0
  202. package/src/README.md +0 -27
  203. package/src/accessibility/index.js +0 -13
  204. package/src/app.js +0 -61
  205. package/src/color/index.js +0 -9
  206. package/src/color/p5.Color.culori.js +0 -66
  207. package/src/color/p5.Color.js +0 -851
  208. package/src/core/README.md +0 -91
  209. package/src/core/friendly_errors/index.js +0 -13
  210. package/src/core/friendly_errors/param_validator.js +0 -561
  211. package/src/core/init.js +0 -58
  212. package/src/core/internationalization.js +0 -195
  213. package/src/core/legacy.js +0 -29
  214. package/src/core/main.js +0 -689
  215. package/src/core/noop.js +0 -1
  216. package/src/core/p5.Graphics.js +0 -696
  217. package/src/core/p5.Renderer.js +0 -408
  218. package/src/core/reference.js +0 -2060
  219. package/src/core/rendering.js +0 -697
  220. package/src/dom/index.js +0 -11
  221. package/src/image/const.js +0 -6
  222. package/src/image/image.js +0 -731
  223. package/src/image/index.js +0 -15
  224. package/src/image/loading_displaying.js +0 -1431
  225. package/src/io/files.js +0 -2210
  226. package/src/io/index.js +0 -11
  227. package/src/math/README.md +0 -40
  228. package/src/type/index.js +0 -9
  229. package/src/webgl/3d_primitives.js +0 -2741
  230. package/src/webgl/index.js +0 -37
  231. package/src/webgl/light.js +0 -1851
  232. package/src/webgl/material.js +0 -3854
  233. package/src/webgl/p5.Camera.js +0 -4010
  234. package/src/webgl/p5.Framebuffer.js +0 -1865
  235. package/src/webgl/p5.RendererGL.js +0 -2867
  236. package/src/webgl/p5.Shader.js +0 -1505
  237. package/src/webgl/p5.Texture.js +0 -541
  238. package/src/webgl/shaders/basic.frag +0 -6
  239. package/src/webgl/shaders/filters/base.frag +0 -22
  240. package/src/webgl/shaders/filters/base.vert +0 -19
  241. package/src/webgl/shaders/filters/blur.frag +0 -60
  242. package/src/webgl/shaders/filters/default.vert +0 -18
  243. package/src/webgl/shaders/filters/dilate.frag +0 -39
  244. package/src/webgl/shaders/filters/erode.frag +0 -39
  245. package/src/webgl/shaders/filters/gray.frag +0 -16
  246. package/src/webgl/shaders/filters/invert.frag +0 -15
  247. package/src/webgl/shaders/filters/opaque.frag +0 -12
  248. package/src/webgl/shaders/filters/posterize.frag +0 -29
  249. package/src/webgl/shaders/filters/threshold.frag +0 -23
  250. package/src/webgl/shaders/font.frag +0 -216
  251. package/src/webgl/shaders/font.vert +0 -44
  252. package/src/webgl/shaders/imageLight.vert +0 -33
  253. package/src/webgl/shaders/imageLightDiffused.frag +0 -82
  254. package/src/webgl/shaders/imageLightSpecular.frag +0 -134
  255. package/src/webgl/shaders/light.vert +0 -37
  256. package/src/webgl/shaders/light_texture.frag +0 -26
  257. package/src/webgl/shaders/lighting.glsl +0 -227
  258. package/src/webgl/shaders/line.frag +0 -74
  259. package/src/webgl/shaders/line.vert +0 -294
  260. package/src/webgl/shaders/normal.frag +0 -6
  261. package/src/webgl/shaders/normal.vert +0 -72
  262. package/src/webgl/shaders/phong.frag +0 -84
  263. package/src/webgl/shaders/phong.vert +0 -87
  264. package/src/webgl/shaders/point.frag +0 -29
  265. package/src/webgl/shaders/point.vert +0 -19
  266. package/src/webgl/shaders/sphereMapping.frag +0 -26
  267. package/src/webgl/shaders/webgl2Compatibility.glsl +0 -34
@@ -1,1431 +0,0 @@
1
- /**
2
- * @module Image
3
- * @submodule Loading & Displaying
4
- * @for p5
5
- * @requires core
6
- */
7
-
8
- import canvas from '../core/helpers';
9
- import * as constants from '../core/constants';
10
- import { request } from '../io/files';
11
- import * as omggif from 'omggif';
12
- import { GIFEncoder, quantize, nearestColorIndex } from 'gifenc';
13
-
14
- function loadingDisplaying(p5, fn){
15
- /**
16
- * Loads an image to create a <a href="#/p5.Image">p5.Image</a> object.
17
- *
18
- * `loadImage()` interprets the first parameter one of three ways. If the path
19
- * to an image file is provided, `loadImage()` will load it. Paths to local
20
- * files should be relative, such as `'assets/thundercat.jpg'`. URLs such as
21
- * `'https://example.com/thundercat.jpg'` may be blocked due to browser
22
- * security. Raw image data can also be passed as a base64 encoded image in
23
- * the form `'data:image/png;base64,arandomsequenceofcharacters'`. The `path`
24
- * parameter can also be defined as a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
25
- * object for more advanced usage.
26
- *
27
- * The second parameter is optional. If a function is passed, it will be
28
- * called once the image has loaded. The callback function can optionally use
29
- * the new <a href="#/p5.Image">p5.Image</a> object. The return value of the
30
- * function will be used as the final return value of `loadImage()`.
31
- *
32
- * The third parameter is also optional. If a function is passed, it will be
33
- * called if the image fails to load. The callback function can optionally use
34
- * the event error. The return value of the function will be used as the final
35
- * return value of `loadImage()`.
36
- *
37
- * This function returns a `Promise` and should be used in an `async` setup with
38
- * `await`. See the examples for the usage syntax.
39
- *
40
- * @method loadImage
41
- * @param {String|Request} path path of the image to be loaded or base64 encoded image.
42
- * @param {function(p5.Image)} [successCallback] function called with
43
- * <a href="#/p5.Image">p5.Image</a> once it
44
- * loads.
45
- * @param {function(Event)} [failureCallback] function called with event
46
- * error if the image fails to load.
47
- * @return {Promise<p5.Image>} the <a href="#/p5.Image">p5.Image</a> object.
48
- *
49
- * @example
50
- * <div>
51
- * <code>
52
- * let img;
53
- *
54
- * // Load the image and create a p5.Image object.
55
- * async function setup() {
56
- * img = await loadImage('assets/laDefense.jpg');
57
- * createCanvas(100, 100);
58
- *
59
- * // Draw the image.
60
- * image(img, 0, 0);
61
- *
62
- * describe('Image of the underside of a white umbrella and a gridded ceiling.');
63
- * }
64
- * </code>
65
- * </div>
66
- *
67
- * <div>
68
- * <code>
69
- * async function setup() {
70
- * // Call handleImage() once the image loads.
71
- * await loadImage('assets/laDefense.jpg', handleImage);
72
- *
73
- * describe('Image of the underside of a white umbrella and a gridded ceiling.');
74
- * }
75
- *
76
- * // Display the image.
77
- * function handleImage(img) {
78
- * image(img, 0, 0);
79
- * }
80
- * </code>
81
- * </div>
82
- *
83
- * <div>
84
- * <code>
85
- * async function setup() {
86
- * // Call handleImage() once the image loads or
87
- * // call handleError() if an error occurs.
88
- * await loadImage('assets/laDefense.jpg', handleImage, handleError);
89
- * }
90
- *
91
- * // Display the image.
92
- * function handleImage(img) {
93
- * image(img, 0, 0);
94
- *
95
- * describe('Image of the underside of a white umbrella and a gridded ceiling.');
96
- * }
97
- *
98
- * // Log the error.
99
- * function handleError(event) {
100
- * console.error('Oops!', event);
101
- * }
102
- * </code>
103
- * </div>
104
- */
105
- fn.loadImage = async function(
106
- path,
107
- successCallback,
108
- failureCallback
109
- ) {
110
- // p5._validateParameters('loadImage', arguments);
111
-
112
- try{
113
- let pImg = new p5.Image(1, 1, this);
114
-
115
- const req = new Request(path, {
116
- method: 'GET',
117
- mode: 'cors'
118
- });
119
-
120
- const { data, headers } = await request(req, 'bytes');
121
-
122
- // GIF section
123
- const contentType = headers.get('content-type');
124
-
125
- if (contentType === null) {
126
- console.warn(
127
- 'The image you loaded does not have a Content-Type header. If you are using the online editor consider reuploading the asset.'
128
- );
129
- }
130
-
131
- if (contentType && contentType.includes('image/gif')) {
132
- await _createGif(
133
- data,
134
- pImg
135
- );
136
-
137
- } else {
138
- // Non-GIF Section
139
- const blob = new Blob([data]);
140
- const img = await createImageBitmap(blob);
141
-
142
- pImg.width = pImg.canvas.width = img.width;
143
- pImg.height = pImg.canvas.height = img.height;
144
-
145
- // Draw the image into the backing canvas of the p5.Image
146
- pImg.drawingContext.drawImage(img, 0, 0);
147
- }
148
-
149
- pImg.modified = true;
150
-
151
- if(successCallback){
152
- return successCallback(pImg);
153
- }else{
154
- return pImg;
155
- }
156
-
157
- } catch(err) {
158
- p5._friendlyFileLoadError(0, path);
159
- if (typeof failureCallback === 'function') {
160
- return failureCallback(err);
161
- } else {
162
- throw err;
163
- }
164
- }
165
- };
166
-
167
- /**
168
- * Generates a gif from a sketch and saves it to a file.
169
- *
170
- * `saveGif()` may be called in <a href="#/p5/setup">setup()</a> or at any
171
- * point while a sketch is running.
172
- *
173
- * The first parameter, `fileName`, sets the gif's file name.
174
- *
175
- * The second parameter, `duration`, sets the gif's duration in seconds.
176
- *
177
- * The third parameter, `options`, is optional. If an object is passed,
178
- * `saveGif()` will use its properties to customize the gif. `saveGif()`
179
- * recognizes the properties `delay`, `units`, `silent`,
180
- * `notificationDuration`, and `notificationID`.
181
- *
182
- * @method saveGif
183
- * @param {String} filename file name of gif.
184
- * @param {Number} duration duration in seconds to capture from the sketch.
185
- * @param {Object} [options] an object that can contain five more properties:
186
- * `delay`, a Number specifying how much time to wait before recording;
187
- * `units`, a String that can be either 'seconds' or 'frames'. By default it's 'seconds’;
188
- * `silent`, a Boolean that defines presence of progress notifications. By default it’s `false`;
189
- * `notificationDuration`, a Number that defines how long in seconds the final notification
190
- * will live. By default it's `0`, meaning the notification will never be removed;
191
- * `notificationID`, a String that specifies the id of the notification's DOM element. By default it’s `'progressBar’`.
192
- *
193
- * @example
194
- * <div>
195
- * <code>
196
- * function setup() {
197
- * createCanvas(100, 100);
198
- *
199
- * describe('A circle drawn in the middle of a gray square. The circle changes color from black to white, then repeats.');
200
- * }
201
- *
202
- * function draw() {
203
- * background(200);
204
- *
205
- * // Style the circle.
206
- * let c = frameCount % 255;
207
- * fill(c);
208
- *
209
- * // Display the circle.
210
- * circle(50, 50, 25);
211
- * }
212
- *
213
- * // Save a 5-second gif when the user presses the 's' key.
214
- * function keyPressed() {
215
- * if (key === 's') {
216
- * saveGif('mySketch', 5);
217
- * }
218
- * }
219
- * </code>
220
- * </div>
221
- *
222
- * <div>
223
- * <code>
224
- * function setup() {
225
- * createCanvas(100, 100);
226
- *
227
- * describe('A circle drawn in the middle of a gray square. The circle changes color from black to white, then repeats.');
228
- * }
229
- *
230
- * function draw() {
231
- * background(200);
232
- *
233
- * // Style the circle.
234
- * let c = frameCount % 255;
235
- * fill(c);
236
- *
237
- * // Display the circle.
238
- * circle(50, 50, 25);
239
- * }
240
- *
241
- * // Save a 5-second gif when the user presses the 's' key.
242
- * // Wait 1 second after the key press before recording.
243
- * function keyPressed() {
244
- * if (key === 's') {
245
- * saveGif('mySketch', 5, { delay: 1 });
246
- * }
247
- * }
248
- * </code>
249
- * </div>
250
- */
251
- fn.saveGif = async function(
252
- fileName,
253
- duration,
254
- options = {
255
- delay: 0,
256
- units: 'seconds',
257
- silent: false,
258
- notificationDuration: 0,
259
- notificationID: 'progressBar'
260
- }
261
- ) {
262
- // validate parameters
263
- if (typeof fileName !== 'string') {
264
- throw TypeError('fileName parameter must be a string');
265
- }
266
- if (typeof duration !== 'number') {
267
- throw TypeError('Duration parameter must be a number');
268
- }
269
-
270
- // extract variables for more comfortable use
271
- const delay = (options && options.delay) || 0; // in seconds
272
- const units = (options && options.units) || 'seconds'; // either 'seconds' or 'frames'
273
- const silent = (options && options.silent) || false;
274
- const notificationDuration = (options && options.notificationDuration) || 0;
275
- const notificationID = (options && options.notificationID) || 'progressBar';
276
-
277
- // if arguments in the options object are not correct, cancel operation
278
- if (typeof delay !== 'number') {
279
- throw TypeError('Delay parameter must be a number');
280
- }
281
- // if units is not seconds nor frames, throw error
282
- if (units !== 'seconds' && units !== 'frames') {
283
- throw TypeError('Units parameter must be either "frames" or "seconds"');
284
- }
285
-
286
- if (typeof silent !== 'boolean') {
287
- throw TypeError('Silent parameter must be a boolean');
288
- }
289
-
290
- if (typeof notificationDuration !== 'number') {
291
- throw TypeError('Notification duration parameter must be a number');
292
- }
293
-
294
- if (typeof notificationID !== 'string') {
295
- throw TypeError('Notification ID parameter must be a string');
296
- }
297
-
298
- this._recording = true;
299
-
300
- // get the project's framerate
301
- let _frameRate = this._targetFrameRate;
302
- // if it is undefined or some non useful value, assume it's 60
303
- if (_frameRate === Infinity || _frameRate === undefined || _frameRate === 0) {
304
- _frameRate = 60;
305
- }
306
-
307
- // calculate frame delay based on frameRate
308
-
309
- // this delay has nothing to do with the
310
- // delay in options, but rather is the delay
311
- // we have to specify to the gif encoder between frames.
312
- let gifFrameDelay = 1 / _frameRate * 1000;
313
-
314
- // constrain it to be always greater than 20,
315
- // otherwise it won't work in some browsers and systems
316
- // reference: https://stackoverflow.com/questions/64473278/gif-frame-duration-seems-slower-than-expected
317
- gifFrameDelay = gifFrameDelay < 20 ? 20 : gifFrameDelay;
318
-
319
- // check the mode we are in and how many frames
320
- // that duration translates to
321
- const nFrames = units === 'seconds' ? duration * _frameRate : duration;
322
- const nFramesDelay = units === 'seconds' ? delay * _frameRate : delay;
323
- const totalNumberOfFrames = nFrames + nFramesDelay;
324
-
325
- // initialize variables for the frames processing
326
- let frameIterator = nFramesDelay;
327
- this.frameCount = frameIterator;
328
-
329
- const lastPixelDensity = this._renderer._pixelDensity;
330
- this.pixelDensity(1);
331
-
332
- // We first take every frame that we are going to use for the animation
333
- let frames = [];
334
-
335
- if (document.getElementById(notificationID) !== null)
336
- document.getElementById(notificationID).remove();
337
-
338
- let p;
339
- if (!silent){
340
- p = this.createP('');
341
- p.id(notificationID);
342
- p.style('font-size', '16px');
343
- p.style('font-family', 'Montserrat');
344
- p.style('background-color', '#ffffffa0');
345
- p.style('padding', '8px');
346
- p.style('border-radius', '10px');
347
- p.position(0, 0);
348
- }
349
-
350
- let pixels;
351
- let gl;
352
- if (this._renderer instanceof p5.RendererGL) {
353
- // if we have a WEBGL context, initialize the pixels array
354
- // and the gl context to use them inside the loop
355
- gl = this.drawingContext;
356
- pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
357
- }
358
-
359
- // stop the loop since we are going to manually redraw
360
- this.noLoop();
361
-
362
- // Defer execution until the rest of the call stack finishes, allowing the
363
- // rest of `setup` to be called (and, importantly, canvases hidden in setup
364
- // to be unhidden.)
365
- //
366
- // Waiting on this empty promise means we'll continue as soon as setup
367
- // finishes without waiting for another frame.
368
- await Promise.resolve();
369
-
370
- while (frameIterator < totalNumberOfFrames) {
371
- /*
372
- we draw the next frame. this is important, since
373
- busy sketches or low end devices might take longer
374
- to render some frames. So we just wait for the frame
375
- to be drawn and immediately save it to a buffer and continue
376
- */
377
- this.redraw();
378
-
379
- // depending on the context we'll extract the pixels one way
380
- // or another
381
- let data = undefined;
382
-
383
- if (this._renderer instanceof p5.RendererGL) {
384
- pixels = new Uint8Array(
385
- gl.drawingBufferWidth * gl.drawingBufferHeight * 4
386
- );
387
- gl.readPixels(
388
- 0,
389
- 0,
390
- gl.drawingBufferWidth,
391
- gl.drawingBufferHeight,
392
- gl.RGBA,
393
- gl.UNSIGNED_BYTE,
394
- pixels
395
- );
396
-
397
- data = _flipPixels(pixels, this.width, this.height);
398
- } else {
399
- data = this.drawingContext.getImageData(0, 0, this.width, this.height)
400
- .data;
401
- }
402
-
403
- frames.push(data);
404
- frameIterator++;
405
-
406
- if (!silent) {
407
- p.html(
408
- 'Saved frame <b>' +
409
- frames.length.toString() +
410
- '</b> out of ' +
411
- nFrames.toString()
412
- );
413
- }
414
- await new Promise(resolve => setTimeout(resolve, 0));
415
- }
416
- if (!silent) p.html('Frames processed, generating color palette...');
417
-
418
- this.loop();
419
- this.pixelDensity(lastPixelDensity);
420
-
421
- // create the gif encoder and the colorspace format
422
- const gif = GIFEncoder();
423
-
424
- // calculate the global palette for this set of frames
425
- const globalPalette = _generateGlobalPalette(frames);
426
-
427
- // Rather than using applyPalette() from the gifenc library, we use our
428
- // own function to map frame pixels to a palette color. This way, we can
429
- // cache palette color mappings between frames for extra performance, and
430
- // use our own caching mechanism to avoid flickering colors from cache
431
- // key collisions.
432
- const paletteCache = {};
433
- const getIndexedFrame = frame => {
434
- const length = frame.length / 4;
435
- const index = new Uint8Array(length);
436
- for (let i = 0; i < length; i++) {
437
- const key =
438
- (frame[i * 4] << 24) |
439
- (frame[i * 4 + 1] << 16) |
440
- (frame[i * 4 + 2] << 8) |
441
- frame[i * 4 + 3];
442
- if (paletteCache[key] === undefined) {
443
- paletteCache[key] = nearestColorIndex(
444
- globalPalette,
445
- frame.slice(i * 4, (i + 1) * 4)
446
- );
447
- }
448
- index[i] = paletteCache[key];
449
- }
450
- return index;
451
- };
452
-
453
- // the way we designed the palette means we always take the last index for transparency
454
- const transparentIndex = globalPalette.length - 1;
455
-
456
- // we are going to iterate the frames in pairs, n-1 and n
457
- let prevIndexedFrame = [];
458
- for (let i = 0; i < frames.length; i++) {
459
- //const indexedFrame = applyPalette(frames[i], globalPaletteWithoutAlpha, 'rgba565');
460
- const indexedFrame = getIndexedFrame(frames[i]);
461
-
462
- // Make a copy of the palette-applied frame before editing the original
463
- // to use transparent pixels
464
- const originalIndexedFrame = indexedFrame.slice();
465
-
466
- if (i === 0) {
467
- gif.writeFrame(indexedFrame, this.width, this.height, {
468
- palette: globalPalette,
469
- delay: gifFrameDelay,
470
- dispose: 1
471
- });
472
- } else {
473
- // Matching pixels between frames can be set to full transparency,
474
- // allowing the previous frame's pixels to show through. We only do
475
- // this for pixels that get mapped to the same quantized color so that
476
- // the resulting image would be the same.
477
- for (let i = 0; i < indexedFrame.length; i++) {
478
- if (indexedFrame[i] === prevIndexedFrame[i]) {
479
- indexedFrame[i] = transparentIndex;
480
- }
481
- }
482
-
483
- // Write frame into the encoder
484
- gif.writeFrame(indexedFrame, this.width, this.height, {
485
- delay: gifFrameDelay,
486
- transparent: true,
487
- transparentIndex,
488
- dispose: 1
489
- });
490
- }
491
-
492
- prevIndexedFrame = originalIndexedFrame;
493
-
494
- if (!silent) {
495
- p.html(
496
- 'Rendered frame <b>' + i.toString() + '</b> out of ' + nFrames.toString()
497
- );
498
- }
499
-
500
-
501
- // this just makes the process asynchronous, preventing
502
- // that the encoding locks up the browser
503
- await new Promise(resolve => setTimeout(resolve, 0));
504
- }
505
-
506
- gif.finish();
507
-
508
- // Get a direct typed array view into the buffer to avoid copying it
509
- const buffer = gif.bytesView();
510
- const extension = 'gif';
511
-
512
- const blob = new Blob([buffer], {
513
- type: 'image/gif'
514
- });
515
-
516
- frames = [];
517
- this._recording = false;
518
- this.loop();
519
-
520
- if (!silent){
521
- p.html('Done. Downloading your gif!🌸');
522
- if(notificationDuration > 0)
523
- setTimeout(() => p.remove(), notificationDuration * 1000);
524
- }
525
-
526
- fn.downloadFile(blob, fileName, extension);
527
- };
528
-
529
- function _flipPixels(pixels, width, height) {
530
- // extracting the pixels using readPixels returns
531
- // an upside down image. we have to flip it back
532
- // first. this solution is proposed by gman on
533
- // this stack overflow answer:
534
- // https://stackoverflow.com/questions/41969562/how-can-i-flip-the-result-of-webglrenderingcontext-readpixels
535
-
536
- const halfHeight = parseInt(height / 2);
537
- const bytesPerRow = width * 4;
538
-
539
- // make a temp buffer to hold one row
540
- const temp = new Uint8Array(width * 4);
541
- for (let y = 0; y < halfHeight; ++y) {
542
- const topOffset = y * bytesPerRow;
543
- const bottomOffset = (height - y - 1) * bytesPerRow;
544
-
545
- // make copy of a row on the top half
546
- temp.set(pixels.subarray(topOffset, topOffset + bytesPerRow));
547
-
548
- // copy a row from the bottom half to the top
549
- pixels.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow);
550
-
551
- // copy the copy of the top half row to the bottom half
552
- pixels.set(temp, bottomOffset);
553
- }
554
- return pixels;
555
- }
556
-
557
- function _generateGlobalPalette(frames) {
558
- // make an array the size of every possible color in every possible frame
559
- // that is: width * height * frames.
560
- let allColors = new Uint8Array(frames.length * frames[0].length);
561
-
562
- // put every frame one after the other in sequence.
563
- // this array will hold absolutely every pixel from the animation.
564
- // the set function on the Uint8Array works super fast tho!
565
- for (let f = 0; f < frames.length; f++) {
566
- allColors.set(frames[f], f * frames[0].length);
567
- }
568
-
569
- // quantize this massive array into 256 colors and return it!
570
- let colorPalette = quantize(allColors, 256, {
571
- format: 'rgba4444',
572
- oneBitAlpha: true
573
- });
574
-
575
- // when generating the palette, we have to leave space for 1 of the
576
- // indices to be a random color that does not appear anywhere in our
577
- // animation to use for transparency purposes. So, if the palette is full
578
- // (has 256 colors), we overwrite the last one with a random, fully transparent
579
- // color. Otherwise, we just push a new color into the palette the same way.
580
-
581
- // this guarantees that when using the transparency index, there are no matches
582
- // between some colors of the animation and the "holes" we want to dig on them,
583
- // which would cause pieces of some frames to be transparent and thus look glitchy.
584
- if (colorPalette.length === 256) {
585
- colorPalette[colorPalette.length - 1] = [
586
- Math.random() * 255,
587
- Math.random() * 255,
588
- Math.random() * 255,
589
- 0
590
- ];
591
- } else {
592
- colorPalette.push([
593
- Math.random() * 255,
594
- Math.random() * 255,
595
- Math.random() * 255,
596
- 0
597
- ]);
598
- }
599
- return colorPalette;
600
- }
601
-
602
- /**
603
- * Helper function for loading GIF-based images
604
- */
605
- async function _createGif(arrayBuffer, pImg) {
606
- // TODO: Replace with ImageDecoder once it is widely available
607
- // https://developer.mozilla.org/en-US/docs/Web/API/ImageDecoder
608
- const gifReader = new omggif.GifReader(arrayBuffer);
609
- pImg.width = pImg.canvas.width = gifReader.width;
610
- pImg.height = pImg.canvas.height = gifReader.height;
611
- const frames = [];
612
- const numFrames = gifReader.numFrames();
613
- let framePixels = new Uint8ClampedArray(pImg.width * pImg.height * 4);
614
-
615
- const loadGIFFrameIntoImage = (frameNum, gifReader) => {
616
- try {
617
- gifReader.decodeAndBlitFrameRGBA(frameNum, framePixels);
618
- } catch (e) {
619
- p5._friendlyFileLoadError(8, pImg.src);
620
- throw e;
621
- }
622
- };
623
-
624
- for (let j = 0; j < numFrames; j++) {
625
- const frameInfo = gifReader.frameInfo(j);
626
- const prevFrameData = pImg.drawingContext.getImageData(
627
- 0,
628
- 0,
629
- pImg.width,
630
- pImg.height
631
- );
632
- framePixels = prevFrameData.data.slice();
633
- loadGIFFrameIntoImage(j, gifReader);
634
- const imageData = new ImageData(framePixels, pImg.width, pImg.height);
635
- pImg.drawingContext.putImageData(imageData, 0, 0);
636
- let frameDelay = frameInfo.delay;
637
- // To maintain the default of 10FPS when frameInfo.delay equals to 0
638
- if (frameDelay === 0) {
639
- frameDelay = 10;
640
- }
641
- frames.push({
642
- image: pImg.drawingContext.getImageData(0, 0, pImg.width, pImg.height),
643
- delay: frameDelay * 10 //GIF stores delay in one-hundredth of a second, shift to ms
644
- });
645
-
646
- // Some GIFs are encoded so that they expect the previous frame
647
- // to be under the current frame. This can occur at a sub-frame level
648
- //
649
- // Values : 0 - No disposal specified. The decoder is
650
- // not required to take any action.
651
- // 1 - Do not dispose. The graphic is to be left
652
- // in place.
653
- // 2 - Restore to background color. The area used by the
654
- // graphic must be restored to the background color.
655
- // 3 - Restore to previous. The decoder is required to
656
- // restore the area overwritten by the graphic with
657
- // what was there prior to rendering the graphic.
658
- // 4-7 - To be defined.
659
- if (frameInfo.disposal === 2) {
660
- // Restore background color
661
- pImg.drawingContext.clearRect(
662
- frameInfo.x,
663
- frameInfo.y,
664
- frameInfo.width,
665
- frameInfo.height
666
- );
667
- } else if (frameInfo.disposal === 3) {
668
- // Restore previous
669
- pImg.drawingContext.putImageData(
670
- prevFrameData,
671
- 0,
672
- 0,
673
- frameInfo.x,
674
- frameInfo.y,
675
- frameInfo.width,
676
- frameInfo.height
677
- );
678
- }
679
- }
680
-
681
- //Uses Netscape block encoding
682
- //to repeat forever, this will be 0
683
- //to repeat just once, this will be null
684
- //to repeat N times (1<N), should contain integer for loop number
685
- //this is changed to more usable values for us
686
- //to repeat forever, loopCount = null
687
- //everything else is just the number of loops
688
- let loopLimit = gifReader.loopCount();
689
- if (loopLimit === null) {
690
- loopLimit = 1;
691
- } else if (loopLimit === 0) {
692
- loopLimit = null;
693
- }
694
-
695
- // we used the pImg for painting and saving during load
696
- // so we have to reset it to the first frame
697
- pImg.drawingContext.putImageData(frames[0].image, 0, 0);
698
-
699
- if (frames.length > 1) {
700
- pImg.gifProperties = {
701
- displayIndex: 0,
702
- loopLimit,
703
- loopCount: 0,
704
- frames,
705
- numFrames,
706
- playing: true,
707
- timeDisplayed: 0,
708
- lastChangeTime: 0
709
- };
710
- }
711
-
712
- return pImg;
713
- }
714
-
715
- /**
716
- * @private
717
- * @param {(LEFT|RIGHT|CENTER)} xAlign either LEFT, RIGHT or CENTER
718
- * @param {(TOP|BOTTOM|CENTER)} yAlign either TOP, BOTTOM or CENTER
719
- * @param {Number} dx
720
- * @param {Number} dy
721
- * @param {Number} dw
722
- * @param {Number} dh
723
- * @param {Number} sw
724
- * @param {Number} sh
725
- * @returns {Object}
726
- */
727
-
728
- function _imageContain(xAlign, yAlign, dx, dy, dw, dh, sw, sh) {
729
- const r = Math.max(sw / dw, sh / dh);
730
- const [adjusted_dw, adjusted_dh] = [sw / r, sh / r];
731
- let x = dx;
732
- let y = dy;
733
-
734
- if (xAlign === constants.CENTER) {
735
- x += (dw - adjusted_dw) / 2;
736
- } else if (xAlign === constants.RIGHT) {
737
- x += dw - adjusted_dw;
738
- }
739
-
740
- if (yAlign === constants.CENTER) {
741
- y += (dh - adjusted_dh) / 2;
742
- } else if (yAlign === constants.BOTTOM) {
743
- y += dh - adjusted_dh;
744
- }
745
- return { x, y, w: adjusted_dw, h: adjusted_dh };
746
- }
747
-
748
- /**
749
- * @private
750
- * @param {(LEFT|RIGHT|CENTER)} xAlign either LEFT, RIGHT or CENTER
751
- * @param {(TOP|BOTTOM|CENTER)} yAlign either TOP, BOTTOM or CENTER
752
- * @param {Number} dw
753
- * @param {Number} dh
754
- * @param {Number} sx
755
- * @param {Number} sy
756
- * @param {Number} sw
757
- * @param {Number} sh
758
- * @returns {Object}
759
- */
760
- function _imageCover(xAlign, yAlign, dw, dh, sx, sy, sw, sh) {
761
- const r = Math.max(dw / sw, dh / sh);
762
- const [adjusted_sw, adjusted_sh] = [dw / r, dh / r];
763
-
764
- let x = sx;
765
- let y = sy;
766
-
767
- if (xAlign === constants.CENTER) {
768
- x += (sw - adjusted_sw) / 2;
769
- } else if (xAlign === constants.RIGHT) {
770
- x += sw - adjusted_sw;
771
- }
772
-
773
- if (yAlign === constants.CENTER) {
774
- y += (sh - adjusted_sh) / 2;
775
- } else if (yAlign === constants.BOTTOM) {
776
- y += sh - adjusted_sh;
777
- }
778
-
779
- return { x, y, w: adjusted_sw, h: adjusted_sh };
780
- }
781
-
782
- /**
783
- * @private
784
- * @param {(CONTAIN|COVER)} [fit] either CONTAIN or COVER
785
- * @param {(LEFT|RIGHT|CENTER)} xAlign either LEFT, RIGHT or CENTER
786
- * @param {(TOP|BOTTOM|CENTER)} yAlign either TOP, BOTTOM or CENTER
787
- * @param {Number} dx
788
- * @param {Number} dy
789
- * @param {Number} dw
790
- * @param {Number} dh
791
- * @param {Number} sx
792
- * @param {Number} sy
793
- * @param {Number} sw
794
- * @param {Number} sh
795
- * @returns {Object}
796
- */
797
- function _imageFit(fit, xAlign, yAlign, dx, dy, dw, dh, sx, sy, sw, sh) {
798
- if (fit === constants.COVER) {
799
- const { x, y, w, h } = _imageCover(xAlign, yAlign, dw, dh, sx, sy, sw, sh);
800
- sx = x;
801
- sy = y;
802
- sw = w;
803
- sh = h;
804
- }
805
-
806
- if (fit === constants.CONTAIN) {
807
- const { x, y, w, h } = _imageContain(
808
- xAlign,
809
- yAlign,
810
- dx,
811
- dy,
812
- dw,
813
- dh,
814
- sw,
815
- sh
816
- );
817
- dx = x;
818
- dy = y;
819
- dw = w;
820
- dh = h;
821
- }
822
- return { sx, sy, sw, sh, dx, dy, dw, dh };
823
- }
824
-
825
- /**
826
- * Validates clipping params. Per drawImage spec sWidth and sHight cannot be
827
- * negative or greater than image intrinsic width and height
828
- * @private
829
- * @param {Number} sVal
830
- * @param {Number} iVal
831
- * @returns {Number}
832
- * @private
833
- */
834
- function _sAssign(sVal, iVal) {
835
- if (sVal > 0 && sVal < iVal) {
836
- return sVal;
837
- } else {
838
- return iVal;
839
- }
840
- }
841
-
842
- /**
843
- * Draws an image to the canvas.
844
- *
845
- * The first parameter, `img`, is the source image to be drawn. `img` can be
846
- * any of the following objects:
847
- * - <a href="#/p5.Image">p5.Image</a>
848
- * - <a href="#/p5.Element">p5.Element</a>
849
- * - <a href="#/p5.Texture">p5.Texture</a>
850
- * - <a href="#/p5.Framebuffer">p5.Framebuffer</a>
851
- * - <a href="#/p5.FramebufferTexture">p5.FramebufferTexture</a>
852
- *
853
- * The second and third parameters, `dx` and `dy`, set the coordinates of the
854
- * destination image's top left corner. See
855
- * <a href="#/p5/imageMode">imageMode()</a> for other ways to position images.
856
- *
857
- * ```js example
858
- * let img;
859
- *
860
- * async function setup() {
861
- * // Load the image.
862
- * img = await loadImage('assets/laDefense.jpg');
863
- *
864
- * createCanvas(100, 100);
865
- *
866
- * background(50);
867
- *
868
- * // Draw the image.
869
- * image(img, 0, 0);
870
- *
871
- * describe('An image of the underside of a white umbrella with a gridded ceiling above.');
872
- * }
873
- * ```
874
- *
875
- * Here's a diagram that explains how optional parameters work in `image()`:
876
- *
877
- * <img src="assets/drawImage.png"></img>
878
- *
879
- * The fourth and fifth parameters, `dw` and `dh`, are optional. They set the
880
- * the width and height to draw the destination image. By default, `image()`
881
- * draws the full source image at its original size.
882
- *
883
- * The sixth and seventh parameters, `sx` and `sy`, are also optional.
884
- * These coordinates define the top left corner of a subsection to draw from
885
- * the source image.
886
- *
887
- * The eighth and ninth parameters, `sw` and `sh`, are also optional.
888
- * They define the width and height of a subsection to draw from the source
889
- * image. By default, `image()` draws the full subsection that begins at
890
- * `(sx, sy)` and extends to the edges of the source image.
891
- *
892
- * The ninth parameter, `fit`, is also optional. It enables a subsection of
893
- * the source image to be drawn without affecting its aspect ratio. If
894
- * `CONTAIN` is passed, the full subsection will appear within the destination
895
- * rectangle. If `COVER` is passed, the subsection will completely cover the
896
- * destination rectangle. This may have the effect of zooming into the
897
- * subsection.
898
- *
899
- * The tenth and eleventh paremeters, `xAlign` and `yAlign`, are also
900
- * optional. They determine how to align the fitted subsection. `xAlign` can
901
- * be set to either `LEFT`, `RIGHT`, or `CENTER`. `yAlign` can be set to
902
- * either `TOP`, `BOTTOM`, or `CENTER`. By default, both `xAlign` and `yAlign`
903
- * are set to `CENTER`.
904
- *
905
- * @method image
906
- * @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img image to display.
907
- * @param {Number} x x-coordinate of the top-left corner of the image.
908
- * @param {Number} y y-coordinate of the top-left corner of the image.
909
- * @param {Number} [width] width to draw the image.
910
- * @param {Number} [height] height to draw the image.
911
- *
912
- * @example
913
- * <div>
914
- * <code>
915
- * let img;
916
- *
917
- * async function setup() {
918
- * // Load the image.
919
- * img = await loadImage('assets/laDefense.jpg');
920
- *
921
- * createCanvas(100, 100);
922
- *
923
- * background(50);
924
- *
925
- * // Draw the image.
926
- * image(img, 10, 10);
927
- *
928
- * describe('An image of the underside of a white umbrella with a gridded ceiling above. The image has dark gray borders on its left and top.');
929
- * }
930
- * </code>
931
- * </div>
932
- *
933
- * <div>
934
- * <code>
935
- * let img;
936
- *
937
- * async function setup() {
938
- * // Load the image.
939
- * img = await loadImage('assets/laDefense.jpg');
940
- *
941
- * createCanvas(100, 100);
942
- *
943
- * background(50);
944
- *
945
- * // Draw the image 50x50.
946
- * image(img, 0, 0, 50, 50);
947
- *
948
- * describe('An image of the underside of a white umbrella with a gridded ceiling above. The image is drawn in the top left corner of a dark gray square.');
949
- * }
950
- * </code>
951
- * </div>
952
- *
953
- * <div>
954
- * <code>
955
- * let img;
956
- *
957
- * async function setup() {
958
- * // Load the image.
959
- * img = await loadImage('assets/laDefense.jpg');
960
- *
961
- * createCanvas(100, 100);
962
- *
963
- * background(50);
964
- *
965
- * // Draw the center of the image.
966
- * image(img, 25, 25, 50, 50, 25, 25, 50, 50);
967
- *
968
- * describe('An image of a gridded ceiling drawn in the center of a dark gray square.');
969
- * }
970
- * </code>
971
- * </div>
972
- *
973
- * <div>
974
- * <code>
975
- * let img;
976
- *
977
- * async function setup() {
978
- * // Load the image.
979
- * img = await loadImage('assets/moonwalk.jpg');
980
- * createCanvas(100, 100);
981
- *
982
- * background(50);
983
- *
984
- * // Draw the image and scale it to fit within the canvas.
985
- * image(img, 0, 0, width, height, 0, 0, img.width, img.height, CONTAIN);
986
- *
987
- * describe('An image of an astronaut on the moon. The top and bottom borders of the image are dark gray.');
988
- * }
989
- * </code>
990
- * </div>
991
- *
992
- * <div>
993
- * <code>
994
- * let img;
995
- *
996
- * async function setup() {
997
- * // Load the image.
998
- * img = await loadImage('assets/laDefense50.png');
999
- *
1000
- * createCanvas(100, 100);
1001
- *
1002
- * background(50);
1003
- *
1004
- * // Draw the image and scale it to cover the canvas.
1005
- * image(img, 0, 0, width, height, 0, 0, img.width, img.height, COVER);
1006
- *
1007
- * describe('A pixelated image of the underside of a white umbrella with a gridded ceiling above.');
1008
- * }
1009
- * </code>
1010
- * </div>
1011
- */
1012
- /**
1013
- * @method image
1014
- * @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img
1015
- * @param {Number} dx the x-coordinate of the destination
1016
- * rectangle in which to draw the source image
1017
- * @param {Number} dy the y-coordinate of the destination
1018
- * rectangle in which to draw the source image
1019
- * @param {Number} dWidth the width of the destination rectangle
1020
- * @param {Number} dHeight the height of the destination rectangle
1021
- * @param {Number} sx the x-coordinate of the subsection of the source
1022
- * image to draw into the destination rectangle
1023
- * @param {Number} sy the y-coordinate of the subsection of the source
1024
- * image to draw into the destination rectangle
1025
- * @param {Number} [sWidth] the width of the subsection of the
1026
- * source image to draw into the destination
1027
- * rectangle
1028
- * @param {Number} [sHeight] the height of the subsection of the
1029
- * source image to draw into the destination rectangle
1030
- * @param {(CONTAIN|COVER)} [fit] either CONTAIN or COVER
1031
- * @param {(LEFT|RIGHT|CENTER)} [xAlign=CENTER] either LEFT, RIGHT or CENTER default is CENTER
1032
- * @param {(TOP|BOTTOM|CENTER)} [yAlign=CENTER] either TOP, BOTTOM or CENTER default is CENTER
1033
- */
1034
- fn.image = function(
1035
- img,
1036
- dx,
1037
- dy,
1038
- dWidth,
1039
- dHeight,
1040
- sx,
1041
- sy,
1042
- sWidth,
1043
- sHeight,
1044
- fit,
1045
- xAlign,
1046
- yAlign
1047
- ) {
1048
- // set defaults per spec: https://goo.gl/3ykfOq
1049
-
1050
- // p5._validateParameters('image', arguments);
1051
-
1052
- let defW = img.width;
1053
- let defH = img.height;
1054
- yAlign = yAlign || constants.CENTER;
1055
- xAlign = xAlign || constants.CENTER;
1056
-
1057
- if (img.elt) {
1058
- defW = defW !== undefined ? defW : img.elt.width;
1059
- defH = defH !== undefined ? defH : img.elt.height;
1060
- }
1061
- if (img.elt && img.elt.videoWidth && !img.canvas) {
1062
- // video no canvas
1063
- defW = defW !== undefined ? defW : img.elt.videoWidth;
1064
- defH = defH !== undefined ? defH : img.elt.videoHeight;
1065
- }
1066
-
1067
- let _dx = dx;
1068
- let _dy = dy;
1069
- let _dw = dWidth || defW;
1070
- let _dh = dHeight || defH;
1071
- let _sx = sx || 0;
1072
- let _sy = sy || 0;
1073
- let _sw = sWidth !== undefined ? sWidth : defW;
1074
- let _sh = sHeight !== undefined ? sHeight : defH;
1075
-
1076
- _sw = _sAssign(_sw, defW);
1077
- _sh = _sAssign(_sh, defH);
1078
-
1079
- // This part needs cleanup and unit tests
1080
- // see issues https://github.com/processing/p5.js/issues/1741
1081
- // and https://github.com/processing/p5.js/issues/1673
1082
- let pd = 1;
1083
-
1084
- if (img.elt && !img.canvas && img.elt.style.width) {
1085
- //if img is video and img.elt.size() has been used and
1086
- //no width passed to image()
1087
- if (img.elt.videoWidth && !dWidth) {
1088
- pd = img.elt.videoWidth;
1089
- } else {
1090
- //all other cases
1091
- pd = img.elt.width;
1092
- }
1093
- pd /= parseInt(img.elt.style.width, 10);
1094
- }
1095
-
1096
- _sx *= pd;
1097
- _sy *= pd;
1098
- _sh *= pd;
1099
- _sw *= pd;
1100
-
1101
- let vals = canvas.modeAdjust(_dx, _dy, _dw, _dh, this._renderer.states.imageMode);
1102
- vals = _imageFit(
1103
- fit,
1104
- xAlign,
1105
- yAlign,
1106
- vals.x,
1107
- vals.y,
1108
- vals.w,
1109
- vals.h,
1110
- _sx,
1111
- _sy,
1112
- _sw,
1113
- _sh
1114
- );
1115
-
1116
- // tint the image if there is a tint
1117
- this._renderer.image(
1118
- img,
1119
- vals.sx,
1120
- vals.sy,
1121
- vals.sw,
1122
- vals.sh,
1123
- vals.dx,
1124
- vals.dy,
1125
- vals.dw,
1126
- vals.dh
1127
- );
1128
- };
1129
-
1130
- /**
1131
- * Tints images using a color.
1132
- *
1133
- * The version of `tint()` with one parameter interprets it one of four ways.
1134
- * If the parameter is a number, it's interpreted as a grayscale value. If the
1135
- * parameter is a string, it's interpreted as a CSS color string. An array of
1136
- * `[R, G, B, A]` values or a <a href="#/p5.Color">p5.Color</a> object can
1137
- * also be used to set the tint color.
1138
- *
1139
- * The version of `tint()` with two parameters uses the first one as a
1140
- * grayscale value and the second as an alpha value. For example, calling
1141
- * `tint(255, 128)` will make an image 50% transparent.
1142
- *
1143
- * The version of `tint()` with three parameters interprets them as RGB or
1144
- * HSB values, depending on the current
1145
- * <a href="#/p5/colorMode">colorMode()</a>. The optional fourth parameter
1146
- * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images
1147
- * a red tint and make them transparent.
1148
- *
1149
- * @method tint
1150
- * @param {Number} v1 red or hue value.
1151
- * @param {Number} v2 green or saturation value.
1152
- * @param {Number} v3 blue or brightness.
1153
- * @param {Number} [alpha]
1154
- *
1155
- * @example
1156
- * <div>
1157
- * <code>
1158
- * let img;
1159
- *
1160
- * async function setup() {
1161
- * // Load the image.
1162
- * img = await loadImage('assets/laDefense.jpg');
1163
- *
1164
- * createCanvas(100, 100);
1165
- *
1166
- * // Left image.
1167
- * image(img, 0, 0);
1168
- *
1169
- * // Right image.
1170
- * // Tint with a CSS color string.
1171
- * tint('red');
1172
- * image(img, 50, 0);
1173
- *
1174
- * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a red tint.');
1175
- * }
1176
- * </code>
1177
- * </div>
1178
- *
1179
- * <div>
1180
- * <code>
1181
- * let img;
1182
- *
1183
- * async function setup() {
1184
- * // Load the image.
1185
- * img = await loadImage('assets/laDefense.jpg');
1186
- *
1187
- * createCanvas(100, 100);
1188
- *
1189
- * // Left image.
1190
- * image(img, 0, 0);
1191
- *
1192
- * // Right image.
1193
- * // Tint with RGB values.
1194
- * tint(255, 0, 0);
1195
- * image(img, 50, 0);
1196
- *
1197
- * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a red tint.');
1198
- * }
1199
- * </code>
1200
- * </div>
1201
- *
1202
- * <div>
1203
- * <code>
1204
- * let img;
1205
- **
1206
- * async function setup() {
1207
- * // Load the image.
1208
- * img = await loadImage('assets/laDefense.jpg');
1209
- *
1210
- * createCanvas(100, 100);
1211
- *
1212
- * // Left.
1213
- * image(img, 0, 0);
1214
- *
1215
- * // Right.
1216
- * // Tint with RGBA values.
1217
- * tint(255, 0, 0, 100);
1218
- * image(img, 50, 0);
1219
- *
1220
- * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a transparent red tint.');
1221
- * }
1222
- * </code>
1223
- * </div>
1224
- *
1225
- * <div>
1226
- * <code>
1227
- * let img;
1228
- *
1229
- * async function setup() {
1230
- * // Load the image.
1231
- * img = await loadImage('assets/laDefense.jpg');
1232
- *
1233
- * createCanvas(100, 100);
1234
- *
1235
- * // Left.
1236
- * image(img, 0, 0);
1237
- *
1238
- * // Right.
1239
- * // Tint with grayscale and alpha values.
1240
- * tint(255, 180);
1241
- * image(img, 50, 0);
1242
- *
1243
- * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right is transparent.');
1244
- * }
1245
- * </code>
1246
- * </div>
1247
- */
1248
- /**
1249
- * @method tint
1250
- * @param {String} value CSS color string.
1251
- */
1252
-
1253
- /**
1254
- * @method tint
1255
- * @param {Number} gray grayscale value.
1256
- * @param {Number} [alpha]
1257
- */
1258
-
1259
- /**
1260
- * @method tint
1261
- * @param {Number[]} values array containing the red, green, blue &
1262
- * alpha components of the color.
1263
- */
1264
-
1265
- /**
1266
- * @method tint
1267
- * @param {p5.Color} color the tint color
1268
- */
1269
- fn.tint = function(...args) {
1270
- // p5._validateParameters('tint', args);
1271
- const c = this.color(...args);
1272
- this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255]));
1273
- };
1274
-
1275
- /**
1276
- * Removes the current tint set by <a href="#/p5/tint">tint()</a>.
1277
- *
1278
- * `noTint()` restores images to their original colors.
1279
- *
1280
- * @method noTint
1281
- *
1282
- * @example
1283
- * <div>
1284
- * <code>
1285
- * let img;
1286
- *
1287
- * async function setup() {
1288
- * // Load the image.
1289
- * img = await loadImage('assets/laDefense.jpg');
1290
- *
1291
- * createCanvas(100, 100);
1292
- *
1293
- * // Left.
1294
- * // Tint with a CSS color string.
1295
- * tint('red');
1296
- * image(img, 0, 0);
1297
- *
1298
- * // Right.
1299
- * // Remove the tint.
1300
- * noTint();
1301
- * image(img, 50, 0);
1302
- *
1303
- * describe('Two images of an umbrella and a ceiling side-by-side. The image on the left has a red tint.');
1304
- * }
1305
- * </code>
1306
- * </div>
1307
- */
1308
- fn.noTint = function() {
1309
- this._renderer.states.setValue('tint', null);
1310
- };
1311
-
1312
- /**
1313
- * Apply the current tint color to the input image, return the resulting
1314
- * canvas.
1315
- *
1316
- * @private
1317
- * @param {p5.Image} The image to be tinted
1318
- * @return {canvas} The resulting tinted canvas
1319
- */
1320
- // fn._getTintedImageCanvas =
1321
- // p5.Renderer2D.prototype._getTintedImageCanvas;
1322
-
1323
- /**
1324
- * Changes the location from which images are drawn when
1325
- * <a href="#/p5/image">image()</a> is called.
1326
- *
1327
- * By default, the first
1328
- * two parameters of <a href="#/p5/image">image()</a> are the x- and
1329
- * y-coordinates of the image's upper-left corner. The next parameters are
1330
- * its width and height. This is the same as calling `imageMode(CORNER)`.
1331
- *
1332
- * `imageMode(CORNERS)` also uses the first two parameters of
1333
- * <a href="#/p5/image">image()</a> as the x- and y-coordinates of the image's
1334
- * top-left corner. The third and fourth parameters are the coordinates of its
1335
- * bottom-right corner.
1336
- *
1337
- * `imageMode(CENTER)` uses the first two parameters of
1338
- * <a href="#/p5/image">image()</a> as the x- and y-coordinates of the image's
1339
- * center. The next parameters are its width and height.
1340
- *
1341
- * @method imageMode
1342
- * @param {(CORNER|CORNERS|CENTER)} mode either CORNER, CORNERS, or CENTER.
1343
- *
1344
- * @example
1345
- *
1346
- * <div>
1347
- * <code>
1348
- * let img;
1349
- *
1350
- * async function setup() {
1351
- * // Load the image.
1352
- * img = await loadImage('assets/bricks.jpg');
1353
- *
1354
- * createCanvas(100, 100);
1355
- *
1356
- * background(200);
1357
- *
1358
- * // Use CORNER mode.
1359
- * imageMode(CORNER);
1360
- *
1361
- * // Display the image.
1362
- * image(img, 10, 10, 50, 50);
1363
- *
1364
- * describe('A square image of a brick wall is drawn at the top left of a gray square.');
1365
- * }
1366
- * </code>
1367
- * </div>
1368
- *
1369
- * <div>
1370
- * <code>
1371
- * let img;
1372
- *
1373
- * async function setup() {
1374
- * // Load the image.
1375
- * img = await loadImage('assets/bricks.jpg');
1376
- *
1377
- * createCanvas(100, 100);
1378
- *
1379
- * background(200);
1380
- *
1381
- * // Use CORNERS mode.
1382
- * imageMode(CORNERS);
1383
- *
1384
- * // Display the image.
1385
- * image(img, 10, 10, 90, 40);
1386
- *
1387
- * describe('An image of a brick wall is drawn on a gray square. The image is squeezed into a small rectangular area.');
1388
- * }
1389
- * </code>
1390
- * </div>
1391
- *
1392
- * <div>
1393
- * <code>
1394
- * let img;
1395
- *
1396
- * async function setup() {
1397
- * // Load the image.
1398
- * img = await loadImage('assets/bricks.jpg');
1399
- *
1400
- * createCanvas(100, 100);
1401
- *
1402
- * background(200);
1403
- *
1404
- * // Use CENTER mode.
1405
- * imageMode(CENTER);
1406
- *
1407
- * // Display the image.
1408
- * image(img, 50, 50, 80, 80);
1409
- *
1410
- * describe('A square image of a brick wall is drawn on a gray square.');
1411
- * }
1412
- * </code>
1413
- * </div>
1414
- */
1415
- fn.imageMode = function(m) {
1416
- // p5._validateParameters('imageMode', arguments);
1417
- if (
1418
- m === constants.CORNER ||
1419
- m === constants.CORNERS ||
1420
- m === constants.CENTER
1421
- ) {
1422
- this._renderer.states.setValue('imageMode', m);
1423
- }
1424
- };
1425
- }
1426
-
1427
- export default loadingDisplaying;
1428
-
1429
- if(typeof p5 !== 'undefined'){
1430
- loadingDisplaying(p5, p5.prototype);
1431
- }