Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 27 additions & 20 deletions src/image/p5.Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* drawing images to the main display canvas.
*/
import Filters from './filters';
import { Color } from '../color/p5.Color';
import { Renderer } from '../core/p5.Renderer';
import { downloadFile, _checkFileExtension } from '../io/utilities';

Expand Down Expand Up @@ -56,9 +57,9 @@ class Image {

this._pixelDensity = density;

// Adjust canvas dimensions based on pixel density
this.width /= density;
this.height /= density;
// Adjust logical dimensions based on physical canvas dimensions and pixel density
this.width = this.canvas.width / density;
this.height = this.canvas.height / density;

return this; // Return the image instance for chaining if needed
} else {
Expand Down Expand Up @@ -611,7 +612,7 @@ class Image {
a = imgOrCol[3];
//this.updatePixels.call(this);
}
} else if (imgOrCol instanceof p5.Color) {
} else if (imgOrCol instanceof Color) {
if (idx < pixelsState.pixels.length) {
[r, g, b, a] = imgOrCol._getRGBA([255, 255, 255, 255]);
//this.updatePixels.call(this);
Expand Down Expand Up @@ -721,20 +722,24 @@ class Image {

// auto-resize
if (width === 0 && height === 0) {
width = this.canvas.width;
height = this.canvas.height;
width = this.width;
height = this.height;
} else if (width === 0) {
width = (this.canvas.width * height) / this.canvas.height;
width = (this.width * height) / this.height;
} else if (height === 0) {
height = (this.canvas.height * width) / this.canvas.width;
height = (this.height * width) / this.width;
}

width = Math.floor(width);
height = Math.floor(height);

const pd = this._pixelDensity;
const canvasWidth = Math.floor(width * pd);
const canvasHeight = Math.floor(height * pd);

const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
tempCanvas.width = canvasWidth;
tempCanvas.height = canvasHeight;

if (this.gifProperties) {
const props = this.gifProperties;
Expand All @@ -755,8 +760,8 @@ class Image {
};
for (let i = 0; i < props.numFrames; i++) {
const resizedImageData = this.drawingContext.createImageData(
width,
height
canvasWidth,
canvasHeight
);
nearestNeighbor(props.frames[i].image, resizedImageData);
props.frames[i].image = resizedImageData;
Expand All @@ -773,25 +778,27 @@ class Image {
this.canvas.height,
0,
0,
tempCanvas.width,
tempCanvas.height
canvasWidth,
canvasHeight
);

// Resize the original canvas, which will clear its contents
this.canvas.width = this.width = width;
this.canvas.height = this.height = height;
this.width = width;
this.height = height;
this.canvas.width = canvasWidth;
this.canvas.height = canvasHeight;

//Copy the image back
this.drawingContext.drawImage(
tempCanvas,
0,
0,
width,
height,
canvasWidth,
canvasHeight,
0,
0,
width,
height
canvasWidth,
canvasHeight
);

if (this.pixels.length > 0) {
Expand Down
67 changes: 67 additions & 0 deletions test/unit/image/p5.Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,44 @@ suite('p5.Image', function () {
});
});

suite('p5.Image.prototype.pixelDensity', function () {
test('it sets and gets pixel density', function () {
const img = myp5.createImage(100, 100);
assert.strictEqual(img.pixelDensity(), 1);
img.pixelDensity(2);
assert.strictEqual(img.pixelDensity(), 2);
assert.strictEqual(img.width, 50);
assert.strictEqual(img.height, 50);
assert.strictEqual(img.canvas.width, 100);
assert.strictEqual(img.canvas.height, 100);
});

test('repeated calls are idempotent and can be restored', function () {
const img = myp5.createImage(100, 100);
img.pixelDensity(2);
assert.strictEqual(img.width, 50);
assert.strictEqual(img.height, 50);

// Calling again should not divide dimensions further
img.pixelDensity(2);
assert.strictEqual(img.width, 50);
assert.strictEqual(img.height, 50);

// Resetting to 1 restores original logical dimensions
img.pixelDensity(1);
assert.strictEqual(img.width, 100);
assert.strictEqual(img.height, 100);
});

test('setting non-positive density defaults to 1', function () {
const img = myp5.createImage(100, 100);
img.pixelDensity(0);
assert.strictEqual(img.pixelDensity(), 1);
assert.strictEqual(img.width, 100);
assert.strictEqual(img.height, 100);
});
});

suite('p5.Image.prototype.resize', function () {
test('it should resize the image', function () {
let img = myp5.createImage(10, 17);
Expand All @@ -49,6 +87,35 @@ suite('p5.Image', function () {
assert.strictEqual(img.width, 10);
assert.strictEqual(img.height, 30);
});

test('it should resize backing canvas with pixel density > 1', function () {
const img = myp5.createImage(100, 100);
img.pixelDensity(2);
assert.strictEqual(img.width, 50);
assert.strictEqual(img.height, 50);

img.resize(40, 60);
assert.strictEqual(img.width, 40);
assert.strictEqual(img.height, 60);
assert.strictEqual(img.canvas.width, 80);
assert.strictEqual(img.canvas.height, 120);
});

test('it allows get() and set() across full logical dimensions after resize with high pixel density', function () {
const img = myp5.createImage(100, 100);
img.pixelDensity(2);
img.resize(50, 50);

const red = myp5.color(255, 0, 0, 255);
img.set(30, 30, red);
img.updatePixels();

const pixel = img.get(30, 30);
assert.strictEqual(pixel[0], 255);
assert.strictEqual(pixel[1], 0);
assert.strictEqual(pixel[2], 0);
assert.strictEqual(pixel[3], 255);
});
});

suite.todo('p5.Image.prototype.mask', function () {
Expand Down