-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Image fit features #5784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
davepagurek
merged 17 commits into
processing:main
from
manpreeeeeet:image-fit-features
Sep 15, 2022
Merged
Image fit features #5784
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
def7f83
intial shrink functionality setup
manpreeeeeet ba8c237
initial setup and adding parameters
manpreeeeeet 92fc843
Merge branch 'main' into image-fit-features
manpreeeeeet 9aacc83
working features, need comments
manpreeeeeet 12c369c
Merge branch 'main' into image-fit-features
manpreeeeeet 52745f1
Merge branch 'main' into image-fit-features
manpreeeeeet 25876ca
removes the left-over console.log
manpreeeeeet 0d57a8e
removed the typo for valid params for yAlign
manpreeeeeet d58e658
contain now scales the smaller image up
manpreeeeeet a0ed0ba
removes the need for img.resize() plus further cleaning
manpreeeeeet 9b4a40c
takes imageMode into account
manpreeeeeet caf3692
removed the leftover console.log
manpreeeeeet 03c8d38
basic tests
manpreeeeeet 9ad9365
fix: minimal contains larger images in cover
manpreeeeeet 89c48fb
docs: added docs for the fit mode
manpreeeeeet 40edc0f
grammar: typos and grammar fix
manpreeeeeet 4336765
grammar: typo
manpreeeeeet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -280,6 +280,116 @@ function _createGif( | |
finishCallback(); | ||
} | ||
|
||
/** | ||
* @private | ||
* @param {Constant} xAlign either LEFT, RIGHT or CENTER | ||
* @param {Constant} yAlign either TOP, BOTTOM or CENTER | ||
* @param {Number} dx | ||
* @param {Number} dy | ||
* @param {Number} dw | ||
* @param {Number} dh | ||
* @param {Number} sw | ||
* @param {Number} sh | ||
* @returns {Object} | ||
*/ | ||
|
||
function _imageContain(xAlign, yAlign, dx, dy, dw, dh, sw, sh) { | ||
const r = Math.max(sw / dw, sh / dh); | ||
const [adjusted_dw, adjusted_dh] = [sw / r, sh / r]; | ||
let x = dx; | ||
let y = dy; | ||
|
||
if (xAlign === constants.CENTER) { | ||
x += (dw - adjusted_dw) / 2; | ||
} else if (xAlign === constants.RIGHT) { | ||
x += dw - adjusted_dw; | ||
} | ||
|
||
if (yAlign === constants.CENTER) { | ||
y += (dh - adjusted_dh) / 2; | ||
} else if (yAlign === constants.BOTTOM) { | ||
y += dh - adjusted_dh; | ||
} | ||
return { x, y, w: adjusted_dw, h: adjusted_dh }; | ||
} | ||
/** | ||
* @private | ||
* @param {Constant} xAlign either LEFT, RIGHT or CENTER | ||
* @param {Constant} yAlign either TOP, BOTTOM or CENTER | ||
* @param {Number} dw | ||
* @param {Number} dh | ||
* @param {Number} sx | ||
* @param {Number} sy | ||
* @param {Number} sw | ||
* @param {Number} sh | ||
* @returns {Object} | ||
*/ | ||
|
||
function _imageCover(xAlign, yAlign, dw, dh, sx, sy, sw, sh) { | ||
const r = Math.max(dw / sw, dh / sh); | ||
const [adjusted_sw, adjusted_sh] = [dw / r, dh / r]; | ||
|
||
let x = sx; | ||
let y = sy; | ||
|
||
if (xAlign === constants.CENTER) { | ||
x += (sw - adjusted_sw) / 2; | ||
} else if (xAlign === constants.RIGHT) { | ||
x += sw - adjusted_sw; | ||
} | ||
|
||
if (yAlign === constants.CENTER) { | ||
y += (sh - adjusted_sh) / 2; | ||
} else if (yAlign === constants.BOTTOM) { | ||
y += sh - adjusted_sh; | ||
} | ||
|
||
return { x, y, w: adjusted_sw, h: adjusted_sh }; | ||
} | ||
|
||
/** | ||
* @private | ||
* @param {Constant} [fit] either CONTAIN or COVER | ||
* @param {Constant} xAlign either LEFT, RIGHT or CENTER | ||
* @param {Constant} yAlign either TOP, BOTTOM or CENTER | ||
* @param {Number} dx | ||
* @param {Number} dy | ||
* @param {Number} dw | ||
* @param {Number} dh | ||
* @param {Number} sx | ||
* @param {Number} sy | ||
* @param {Number} sw | ||
* @param {Number} sh | ||
* @returns {Object} | ||
*/ | ||
function _imageFit(fit, xAlign, yAlign, dx, dy, dw, dh, sx, sy, sw, sh) { | ||
if (fit === constants.COVER) { | ||
const { x, y, w, h } = _imageCover(xAlign, yAlign, dw, dh, sx, sy, sw, sh); | ||
sx = x; | ||
sy = y; | ||
sw = w; | ||
sh = h; | ||
} | ||
|
||
if (fit === constants.CONTAIN) { | ||
const { x, y, w, h } = _imageContain( | ||
xAlign, | ||
yAlign, | ||
dx, | ||
dy, | ||
dw, | ||
dh, | ||
sw, | ||
sh | ||
); | ||
dx = x; | ||
dy = y; | ||
dw = w; | ||
dh = h; | ||
} | ||
return { sx, sy, sw, sh, dx, dy, dw, dh }; | ||
} | ||
|
||
/** | ||
* Validates clipping params. Per drawImage spec sWidth and sHight cannot be | ||
* negative or greater than image intrinsic width and height | ||
|
@@ -305,7 +415,7 @@ function _sAssign(sVal, iVal) { | |
* 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 all eight Number parameters. To | ||
* 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 | ||
|
@@ -314,6 +424,14 @@ function _sAssign(sVal, iVal) { | |
* to explain further: | ||
* <img src="assets/drawImage.png"></img> | ||
* | ||
* 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. | ||
* | ||
* | ||
* | ||
* @method image | ||
* @param {p5.Image|p5.Element|p5.Texture} img the image to display | ||
* @param {Number} x the x-coordinate of the top-left corner of the image | ||
|
@@ -380,6 +498,37 @@ function _sAssign(sVal, iVal) { | |
* } | ||
* </code> | ||
* </div> | ||
* <div> | ||
* <code> | ||
* 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); | ||
* } | ||
* </code> | ||
* </div> | ||
* <div> | ||
* <code> | ||
* let img; | ||
* function preload() { | ||
* img = loadImage('assets/laDefense50.png'); // dimensions of image are 50 x 50 | ||
* } | ||
* 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 | ||
* image(img, 0, 0, width, height, 0, 0, img.width, img.height, COVER); | ||
* } | ||
* </code> | ||
* </div> | ||
* @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 | ||
|
@@ -402,6 +551,9 @@ function _sAssign(sVal, iVal) { | |
* rectangle | ||
* @param {Number} [sHeight] the height of the subsection of the | ||
* source image to draw into the destination rectangle | ||
* @param {Constant} [fit] either CONTAIN or COVER | ||
* @param {Constant} [xAlign] either LEFT, RIGHT or CENTER default is CENTER | ||
* @param {Constant} [yAlign] either TOP, BOTTOM or CENTER default is CENTER | ||
*/ | ||
p5.prototype.image = function( | ||
img, | ||
|
@@ -412,25 +564,30 @@ p5.prototype.image = function( | |
sx, | ||
sy, | ||
sWidth, | ||
sHeight | ||
sHeight, | ||
fit, | ||
xAlign, | ||
yAlign | ||
) { | ||
// set defaults per spec: https://goo.gl/3ykfOq | ||
|
||
p5._validateParameters('image', arguments); | ||
|
||
let defW = img.width; | ||
let defH = img.height; | ||
yAlign = yAlign || constants.CENTER; | ||
xAlign = xAlign || constants.CENTER; | ||
|
||
if (img.elt && img.elt.videoWidth && !img.canvas) { | ||
// video no canvas | ||
defW = img.elt.videoWidth; | ||
defH = img.elt.videoHeight; | ||
} | ||
|
||
const _dx = dx; | ||
const _dy = dy; | ||
const _dw = dWidth || defW; | ||
const _dh = dHeight || defH; | ||
let _dx = dx; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the |
||
let _dy = dy; | ||
let _dw = dWidth || defW; | ||
let _dh = dHeight || defH; | ||
let _sx = sx || 0; | ||
let _sy = sy || 0; | ||
let _sw = sWidth || defW; | ||
|
@@ -461,10 +618,33 @@ p5.prototype.image = function( | |
_sh *= pd; | ||
_sw *= pd; | ||
|
||
const vals = canvas.modeAdjust(_dx, _dy, _dw, _dh, this._renderer._imageMode); | ||
let vals = canvas.modeAdjust(_dx, _dy, _dw, _dh, this._renderer._imageMode); | ||
vals = _imageFit( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, this code looks great! |
||
fit, | ||
xAlign, | ||
yAlign, | ||
vals.x, | ||
vals.y, | ||
vals.w, | ||
vals.h, | ||
_sx, | ||
_sy, | ||
_sw, | ||
_sh | ||
); | ||
|
||
// tint the image if there is a tint | ||
this._renderer.image(img, _sx, _sy, _sw, _sh, vals.x, vals.y, vals.w, vals.h); | ||
this._renderer.image( | ||
img, | ||
vals.sx, | ||
vals.sy, | ||
vals.sw, | ||
vals.sh, | ||
vals.dx, | ||
vals.dy, | ||
vals.dw, | ||
vals.dh | ||
); | ||
}; | ||
|
||
/** | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default is
CENTER
if not specified by user