From bfad570446c2f3e07defe703b5cbc23913860cf9 Mon Sep 17 00:00:00 2001 From: Nick McIntyre Date: Tue, 12 Sep 2023 18:11:13 -0500 Subject: [PATCH 1/2] Edit docs for image load & display --- src/image/loading_displaying.js | 430 ++++++++++++++++++-------------- 1 file changed, 244 insertions(+), 186 deletions(-) diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 76e59cf29f..220016572a 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -16,55 +16,78 @@ import '../core/friendly_errors/file_errors'; import '../core/friendly_errors/fes_core'; /** - * Loads an image from a path and creates a p5.Image from it. + * Loads an image to create a p5.Image object. * - * The image may not be immediately available for rendering. - * If you want to ensure that the image is ready before doing - * anything with it, place the loadImage() call in preload(). - * You may also supply a callback function to handle the image when it's ready. + * `loadImage()` interprets the first parameter one of two ways. If the path + * to an image file is provided, `loadImage()` will load it. Paths to local + * files should be relative, such as `'assets/thundercat.jpg'`. URLs such as + * `'https://example.com/thundercat.jpg'` may be blocked due to browser + * security. Raw image data can also be passed as a base64 encoded image in + * the form `'data:image/png;base64,arandomsequenceofcharacters'`. * - * The path to the image should be relative to the HTML file - * that links in your sketch. Loading an image from a URL or other - * remote location may be blocked due to your browser's built-in - * security. - - * You can also pass in a string of a base64 encoded image as an alternative to the file path. - * Remember to add "data:image/png;base64," in front of the string. + * The second parameter is optional. If a function is passed, it will be + * called once the image has loaded. The callback function can optionally use + * the new p5.Image object. + * + * The third parameter is also optional. If a function is passed, it will be + * called if the image fails to load. The callback function can optionally use + * the event error. + * + * Images can take time to load. Calling `loadImage()` in + * preload() ensures images load before they're + * used in setup() or draw(). * * @method loadImage - * @param {String} path Path of the image to be loaded - * @param {function(p5.Image)} [successCallback] Function to be called once - * the image is loaded. Will be passed the - * p5.Image. - * @param {function(Event)} [failureCallback] called with event error if - * the image fails to load. - * @return {p5.Image} the p5.Image object + * @param {String} path path of the image to be loaded or base64 encoded image. + * @param {function(p5.Image)} [successCallback] function called with + * p5.Image once it + * loads. + * @param {function(Event)} [failureCallback] function called with event + * error if the image fails to load. + * @return {p5.Image} the p5.Image object. * @example *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { * image(img, 0, 0); + * describe('Image of the underside of a white umbrella and a gridded ceiling.'); * } * *
+ * *
* * function setup() { - * // here we use a callback to display the image after loading * loadImage('assets/laDefense.jpg', img => { * image(img, 0, 0); * }); + * describe('Image of the underside of a white umbrella and a gridded ceiling.'); * } * *
* - * @alt - * image of the underside of a white umbrella and grided ceililng above - * image of the underside of a white umbrella and grided ceililng above + *
+ * + * function setup() { + * loadImage('assets/laDefense.jpg', success, failure); + * } + * + * function success(img) { + * image(img, 0, 0); + * describe('Image of the underside of a white umbrella and a gridded ceiling.'); + * } + * + * function failure(event) { + * console.error('Oops!', event); + * } + * + *
*/ p5.prototype.loadImage = function(path, successCallback, failureCallback) { p5._validateParameters('loadImage', arguments); @@ -163,74 +186,48 @@ p5.prototype.loadImage = function(path, successCallback, failureCallback) { }; /** - * Generates a gif of your current animation and downloads it to your computer! - * - * The duration argument specifies how many seconds you want to record from your animation. - * This value is then converted to the necessary number of frames to generate it, depending - * on the value of units. More on that on the next paragraph. - * - * An optional object that can contain two more arguments: delay (number) and units (string). - * - * `delay`, specifying how much time we should wait before recording - * - * `units`, a string that can be either 'seconds' or 'frames'. By default it's 'seconds'. + * Generates a gif from a sketch and downloads it. `saveGif()` may be called + * in setup() or at any point while a sketch is + * running. * - * `units` specifies how the duration and delay arguments will behave. - * If 'seconds', these arguments will correspond to seconds, meaning that 3 seconds worth of animation - * will be created. If 'frames', the arguments now correspond to the number of frames you want your - * animation to be, if you are very sure of this number. + * The first parameter, `fileName`, sets the gif's file name. The second + * parameter, `duration`, sets the gif's duration in seconds. * - * This may be called in setup, or, like in the example below, inside an event function, - * like keyPressed or mousePressed. + * The third parameter, `options`, is optional. If an object is passed, + * `saveGif()` will use its properties to customize the gif. `saveGif()` + * recognizes the properties `delay`, `units`, `silent`, + * `notificationDuration`, and `notificationID`. * * @method saveGif - * @param {String} filename File name of your gif - * @param {Number} duration Duration in seconds that you wish to capture from your sketch - * @param {Object} options An optional object that can contain five more arguments: - * delay, specifying how much time we should wait before recording; - * units, a string that can be either 'seconds' or 'frames'. By default it's 'seconds’; - * silent, a boolean that defines presence of progress notifications. By default it’s false; - * notificationDuration, a number that defines how long in seconds the final notification - * will live. 0, the default value, means that the notification will never be removed; - * notificationID, a string that specifies the notification DOM element id. By default it’s 'progressBar’. + * @param {String} filename file name of gif. + * @param {Number} duration duration in seconds to capture from the sketch. + * @param {Object} [options] an object that can contain five more properties: + * `delay`, a Number specifying how much time to wait before recording; + * `units`, a String that can be either 'seconds' or 'frames'. By default it's 'seconds’; + * `silent`, a Boolean that defines presence of progress notifications. By default it’s `false`; + * `notificationDuration`, a Number that defines how long in seconds the final notification + * will live. By default it's `0`, meaning the notification will never be removed; + * `notificationID`, a String that specifies the id of the notification's DOM element. By default it’s `'progressBar’`. * * @example *
* - * function setup() { - * createCanvas(100, 100); - * } - * * function draw() { - * colorMode(RGB); - * background(30); - * - * // create a bunch of circles that move in... circles! - * for (let i = 0; i < 10; i++) { - * let opacity = map(i, 0, 10, 0, 255); - * noStroke(); - * fill(230, 250, 90, opacity); - * circle( - * 30 * sin(frameCount / (30 - i)) + width / 2, - * 30 * cos(frameCount / (30 - i)) + height / 2, - * 10 - * ); - * } + * background(200); + * let c = frameCount % 255; + * fill(c); + * circle(50, 50, 25); + * + * describe('A circle drawn in the middle of a gray square. The circle changes color from black to white, then repeats.'); * } * - * // you can put it in the mousePressed function, - * // or keyPressed for example * function keyPressed() { - * // this will download the first 5 seconds of the animation! * if (key === 's') { * saveGif('mySketch', 5); * } * } * *
- * - * @alt - * animation of a group of yellow circles moving in circles over a dark background */ p5.prototype.saveGif = async function( fileName, @@ -833,130 +830,152 @@ function _sAssign(sVal, iVal) { } /** - * Draw an image to the p5.js canvas. - * - * This function can be used with different numbers of parameters. The - * simplest use requires only three parameters: img, x, and y—where (x, y) is - * the position of the image. Two more parameters can optionally be added to - * specify the width and height of the image. - * - * This function can also be used with eight Number parameters. To - * differentiate between all these parameters, p5.js uses the language of - * "destination rectangle" (which corresponds to "dx", "dy", etc.) and "source - * image" (which corresponds to "sx", "sy", etc.) below. Specifying the - * "source image" dimensions can be useful when you want to display a - * subsection of the source image instead of the whole thing. Here's a diagram - * to explain further: + * Draws a source image to the canvas. + * + * The first parameter, `img`, is the source image to be drawn. The second and + * third parameters, `dx` and `dy`, set the coordinates of the destination + * image's top left corner. See imageMode() for + * other ways to position images. + * + * Here's a diagram that explains how optional parameters work in `image()`: + * * * - * This function can also be used to draw images without distorting the orginal aspect ratio, - * by adding 9th parameter, fit, which can either be COVER or CONTAIN. - * CONTAIN, as the name suggests, contains the whole image within the specified destination box - * without distorting the image ratio. - * COVER covers the entire destination box. + * The fourth and fifth parameters, `dw` and `dh`, are optional. They set the + * the width and height to draw the destination image. By default, `image()` + * draws the full source image at its original size. + * + * The sixth and seventh parameters, `sx` and `sy`, are also optional. + * These coordinates define the top left corner of a subsection to draw from + * the source image. + * + * The eighth and ninth parameters, `sw` and `sh`, are also optional. + * They define the width and height of a subsection to draw from the source + * image. By default, `image()` draws the full subsection that begins at + * (`sx`, `sy`) and extends to the edges of the source image. * + * The ninth parameter, `fit`, is also optional. It enables a subsection of + * the source image to be drawn without affecting its aspect ratio. If + * `CONTAIN` is passed, the full subsection will appear within the destination + * rectangle. If `COVER` is passed, the subsection will completely cover the + * destination rectangle. This may have the effect of zooming into the + * subsection. * + * The tenth and eleventh paremeters, `xAlign` and `yAlign`, are also + * optional. They determine how to align the fitted subsection. `xAlign` can + * be set to either `LEFT`, `RIGHT`, or `CENTER`. `yAlign` can be set to + * either `TOP`, `BOTTOM`, or `CENTER`. By default, both `xAlign` and `yAlign` + * are set to `CENTER`. * * @method image - * @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img the image to display - * @param {Number} x the x-coordinate of the top-left corner of the image - * @param {Number} y the y-coordinate of the top-left corner of the image - * @param {Number} [width] the width to draw the image - * @param {Number} [height] the height to draw the image + * @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img image to display. + * @param {Number} x x-coordinate of the top-left corner of the image. + * @param {Number} y y-coordinate of the top-left corner of the image. + * @param {Number} [width] width to draw the image. + * @param {Number} [height] height to draw the image. * @example *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { - * // Top-left corner of the img is at (0, 0) - * // Width and height are the img's original width and height + * background(50); * image(img, 0, 0); + * + * describe('An image of the underside of a white umbrella with a gridded ceiling above.'); * } * *
+ * *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { * background(50); - * // Top-left corner of the img is at (10, 10) - * // Width and height are 50×50 - * image(img, 10, 10, 50, 50); + * image(img, 10, 10); + * + * 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.'); * } * *
+ * *
* + * let img; + * + * function preload() { + * img = loadImage('assets/laDefense.jpg'); + * } + * * function setup() { - * // Here, we use a callback to display the image after loading - * loadImage('assets/laDefense.jpg', img => { - * image(img, 0, 0); - * }); + * background(50); + * image(img, 0, 0, 50, 50); + * + * 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.'); * } * *
+ * *
* * let img; + * * function preload() { - * img = loadImage('assets/gradient.png'); + * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { - * // 1. Background image - * // Top-left corner of the img is at (0, 0) - * // Width and height are the img's original width and height, 100×100 - * image(img, 0, 0); - * // 2. Top right image - * // Top-left corner of destination rectangle is at (50, 0) - * // Destination rectangle width and height are 40×20 - * // The next parameters are relative to the source image: - * // - Starting at position (50, 50) on the source image, capture a 50×50 - * // subsection - * // - Draw this subsection to fill the dimensions of the destination rectangle - * image(img, 50, 0, 40, 20, 50, 50, 50, 50); + * background(50); + * image(img, 25, 25, 50, 50, 25, 25, 50, 50); + * + * describe('An image of a gridded ceiling drawn in the center of a dark gray square.'); * } * *
+ * *
* * let img; + * * function preload() { - * // dimensions of image are 780 x 440 - * // dimensions of canvas are 100 x 100 * img = loadImage('assets/moonwalk.jpg'); * } + * * function setup() { - * // CONTAIN the whole image without distorting the image's aspect ratio - * // CONTAIN the image within the specified destination box and display at LEFT,CENTER position - * background(color('green')); - * image(img, 0, 0, width, height, 0, 0, img.width, img.height, CONTAIN, LEFT); + * background(50); + * image(img, 0, 0, width, height, 0, 0, img.width, img.height, CONTAIN); + * + * describe('An image of an astronaut on the moon. The top and bottom borders of the image are dark gray.'); * } * *
+ * *
* * let img; + * * function preload() { - * img = loadImage('assets/laDefense50.png'); // dimensions of image are 50 x 50 + * // Image is 50 x 50 pixels. + * img = loadImage('assets/laDefense50.png'); * } + * * function setup() { - * // COVER the whole destination box without distorting the image's aspect ratio - * // COVER the specified destination box which is of dimension 100 x 100 - * // Without specifying xAlign or yAlign, the image will be - * // centered in the destination box in both axes + * background(50); * image(img, 0, 0, width, height, 0, 0, img.width, img.height, COVER); + * + * describe('A pixelated image of the underside of a white umbrella with a gridded ceiling above.'); * } * *
- * @alt - * image of the underside of a white umbrella and gridded ceiling above - * image of the underside of a white umbrella and gridded ceiling above */ /** * @method image @@ -1077,38 +1096,45 @@ p5.prototype.image = function( }; /** - * Sets the fill value for displaying images. Images can be tinted to - * specified colors or made transparent by including an alpha value. + * Tints images using a specified color. * - * To apply transparency to an image without affecting its color, use - * white as the tint color and specify an alpha value. For instance, - * tint(255, 128) will make an image 50% transparent (assuming the default - * alpha range of 0-255, which can be changed with colorMode()). + * The version of `tint()` with one parameter interprets it one of four ways. + * If the parameter is a number, it's interpreted as a grayscale value. If the + * parameter is a string, it's interpreted as a CSS color string. An array of + * `[R, G, B, A]` values or a p5.Color object can + * also be used to set the tint color. * - * The value for the gray parameter must be less than or equal to the current - * maximum value as specified by colorMode(). The default maximum value is - * 255. + * The version of `tint()` with two parameters uses the first one as a + * grayscale value and the second as an alpha value. For example, calling + * `tint(255, 128)` will make an image 50% transparent. + * + * The version of `tint()` with three parameters interprets them as RGB or + * HSB values, depending on the current + * colorMode(). The optional fourth parameter + * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images + * a red tint and make them transparent. * * @method tint - * @param {Number} v1 red or hue value relative to - * the current color range - * @param {Number} v2 green or saturation value - * relative to the current color range - * @param {Number} v3 blue or brightness value - * relative to the current color range + * @param {Number} v1 red or hue value. + * @param {Number} v2 green or saturation value. + * @param {Number} v3 blue or brightness. * @param {Number} [alpha] * * @example *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { * image(img, 0, 0); - * tint(0, 153, 204); // Tint blue + * tint('red'); * image(img, 50, 0); + * + * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a red tint.'); * } * *
@@ -1116,13 +1142,17 @@ p5.prototype.image = function( *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { * image(img, 0, 0); - * tint(0, 153, 204, 126); // Tint blue and set transparency + * tint(255, 0, 0); * image(img, 50, 0); + * + * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a red tint.'); * } * *
@@ -1130,38 +1160,54 @@ p5.prototype.image = function( *
* * let img; + * * function preload() { * img = loadImage('assets/laDefense.jpg'); * } + * * function setup() { * image(img, 0, 0); - * tint(255, 126); // Apply transparency without changing color + * tint(255, 0, 0, 100); * image(img, 50, 0); + * + * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right has a transparent red tint.'); * } * *
* - * @alt - * 2 side by side images of umbrella and ceiling, one image with blue tint - * Images of umbrella and ceiling, one half of image with blue tint - * 2 side by side images of umbrella and ceiling, one image translucent + *
+ * + * let img; + * + * function preload() { + * img = loadImage('assets/laDefense.jpg'); + * } + * + * function setup() { + * image(img, 0, 0); + * tint(255, 180); + * image(img, 50, 0); + * + * describe('Two images of an umbrella and a ceiling side-by-side. The image on the right is transparent.'); + * } + * + *
*/ - /** * @method tint - * @param {String} value a color string + * @param {String} value CSS color string. */ /** * @method tint - * @param {Number} gray a gray value + * @param {Number} gray grayscale value. * @param {Number} [alpha] */ /** * @method tint - * @param {Number[]} values an array containing the red,green,blue & - * and alpha components of the color + * @param {Number[]} values array containing the red, green, blue & + * alpha components of the color. */ /** @@ -1175,28 +1221,28 @@ p5.prototype.tint = function(...args) { }; /** - * Removes the current fill value for displaying images and reverts to - * displaying images with their original hues. + * Removes the current tint set by tint() and restores + * images to their original colors. * * @method noTint * @example *
* * let img; + * * function preload() { - * img = loadImage('assets/bricks.jpg'); + * img = loadImage('assets/laDefense.jpg'); * } * function setup() { - * tint(0, 153, 204); // Tint blue + * tint('red'); * image(img, 0, 0); - * noTint(); // Disable tint + * noTint(); * image(img, 50, 0); + * + * describe('Two images of an umbrella and a ceiling side-by-side. The image on the left has a red tint.'); * } * *
- * - * @alt - * 2 side by side images of bricks, left image with blue tint */ p5.prototype.noTint = function() { this._renderer._tint = null; @@ -1214,34 +1260,41 @@ p5.prototype._getTintedImageCanvas = p5.Renderer2D.prototype._getTintedImageCanvas; /** - * Set image mode. Modifies the location from which images are drawn by - * changing the way in which parameters given to image() are interpreted. - * The default mode is imageMode(CORNER), which interprets the second and - * third parameters of image() as the upper-left corner of the image. If - * two additional parameters are specified, they are used to set the image's - * width and height. + * Changes the location from which images are drawn when + * image() is called. + * + * By default, the first + * two parameters of image() are the x- and + * y-coordinates of the image's upper-left corner. The next parameters are + * its width and height. This is the same as calling `imageMode(CORNER)`. * - * imageMode(CORNERS) interprets the second and third parameters of image() - * as the location of one corner, and the fourth and fifth parameters as the - * opposite corner. + * `imageMode(CORNERS)` also uses the first two parameters of + * image() as the x- and y-coordinates of the image's + * top-left corner. The third and fourth parameters are the coordinates of its + * bottom-right corner. * - * imageMode(CENTER) interprets the second and third parameters of image() - * as the image's center point. If two additional parameters are specified, - * they are used to set the image's width and height. + * `imageMode(CENTER)` uses the first two parameters of + * image() as the x- and y-coordinates of the image's + * center. The next parameters are its width and height. * * @method imageMode - * @param {Constant} mode either CORNER, CORNERS, or CENTER + * @param {Constant} mode either CORNER, CORNERS, or CENTER. * @example * *
* * let img; + * * function preload() { * img = loadImage('assets/bricks.jpg'); * } + * * function setup() { + * background(200); * imageMode(CORNER); * image(img, 10, 10, 50, 50); + * + * describe('A square image of a brick wall is drawn at the top left of a gray square.'); * } * *
@@ -1249,12 +1302,17 @@ p5.prototype._getTintedImageCanvas = *
* * let img; + * * function preload() { * img = loadImage('assets/bricks.jpg'); * } + * * function setup() { + * background(200); * imageMode(CORNERS); * image(img, 10, 10, 90, 40); + * + * describe('An image of a brick wall is drawn on a gray square. The image is squeezed into a small rectangular area.'); * } * *
@@ -1262,20 +1320,20 @@ p5.prototype._getTintedImageCanvas = *
* * let img; + * * function preload() { * img = loadImage('assets/bricks.jpg'); * } + * * function setup() { + * background(200); * imageMode(CENTER); * image(img, 50, 50, 80, 80); + * + * describe('A square image of a brick wall is drawn on a gray square.'); * } * *
- * - * @alt - * small square image of bricks - * horizontal rectangle image of bricks - * large square image of bricks */ p5.prototype.imageMode = function(m) { p5._validateParameters('imageMode', arguments); From ec9638c35c96e420abf98ff5d547305e5dbc1362 Mon Sep 17 00:00:00 2001 From: Nick McIntyre Date: Tue, 3 Oct 2023 14:22:21 -0500 Subject: [PATCH 2/2] Revise docs for loading and displaying images --- src/image/loading_displaying.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 220016572a..981fb589ec 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -18,7 +18,7 @@ import '../core/friendly_errors/fes_core'; /** * Loads an image to create a p5.Image object. * - * `loadImage()` interprets the first parameter one of two ways. If the path + * `loadImage()` interprets the first parameter one of three ways. If the path * to an image file is provided, `loadImage()` will load it. Paths to local * files should be relative, such as `'assets/thundercat.jpg'`. URLs such as * `'https://example.com/thundercat.jpg'` may be blocked due to browser @@ -186,9 +186,9 @@ p5.prototype.loadImage = function(path, successCallback, failureCallback) { }; /** - * Generates a gif from a sketch and downloads it. `saveGif()` may be called - * in setup() or at any point while a sketch is - * running. + * Generates a gif from a sketch and saves it to a file. `saveGif()` may be + * called in setup() or at any point while a sketch + * is running. * * The first parameter, `fileName`, sets the gif's file name. The second * parameter, `duration`, sets the gif's duration in seconds.