Skip to content
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

Added thumbnail to MagickImage #183

Merged
merged 1 commit into from
Oct 22, 2024
Merged
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
25 changes: 25 additions & 0 deletions src/magick-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1692,6 +1692,19 @@ export interface IMagickImage extends IDisposable {
*/
threshold(percentage: Percentage, channels: Channels): void;

/**
* Resize image to thumbnail size and remove all the image profiles except the icc/icm profile.
* @param width The new width.
* @param height The new height.
*/
thumbnail(width: number, height: number): void;

/**
* Resize image to thumbnail size and remove all the image profiles except the icc/icm profile.
* @param geometry The geometry to use.
*/
thumbnail(geometry: IMagickGeometry): void;

/**
* Returns a string that represents the current image.
*/
Expand Down Expand Up @@ -3209,6 +3222,18 @@ export class MagickImage extends NativeInstance implements IMagickImage {
});
}

thumbnail(width: number, height: number): void;
thumbnail(geometry: IMagickGeometry): void;
thumbnail(widthOrGeometry: number | IMagickGeometry, heightOrUndefined?: number): void {
const geometry = typeof widthOrGeometry === 'number' ? new MagickGeometry(widthOrGeometry, heightOrUndefined as number) : widthOrGeometry;
this.useException(exception => {
_withString(geometry.toString(), geometryPtr => {
const instance = ImageMagick._api._MagickImage_Thumbnail(this._instance, geometryPtr, exception.ptr);
this._setInstance(instance, exception);
});
});
}

toString = (): string => `${this.format} ${this.width}x${this.height} ${this.depth}-bit ${ColorSpace[this.colorSpace]}`

transparent(color: IMagickColor): void {
Expand Down
56 changes: 56 additions & 0 deletions tests/magick-image/thumbnail.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

import { MagickGeometry } from '@src/types/magick-geometry';
import { TestImages } from '@test/test-images';

describe('MagickImage#thumbnail', () => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need an extra test that makes sure that the some of the metadata is not available in the resulting image.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a test for that! FYI Magick.NET is also missing this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems EXIF attributes (so .getAttribute, not .getProfile) are not removed, also not by .strip(). Is this intended behaviour?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I try not to look at the Magick.NET tests and just add here what I think that should be added. Those attributes are not removed because they will not be stored to file. Maybe to make sure this is working correctly we could save the thumbnail to a blob and then read it again but I don't know if we really need to do that.

it('should resize the image to within the given dimensions', () => {
TestImages.Builtin.logo.use(image => {
image.thumbnail(100, 100);

expect(image.width).toBe(100);
expect(image.height).toBe(75);
});
});

it('should resize the image based on the given width', () => {
TestImages.Builtin.logo.use(image => {
image.thumbnail(150, 0);

expect(image.width).toBe(150);
expect(image.height).toBe(113);
});
});

it('should resize the image based on the given height', () => {
TestImages.Builtin.logo.use(image => {
image.thumbnail(0, 100);

expect(image.width).toBe(133);
expect(image.height).toBe(100);
});
});

it('should resize based on the given geometry', () => {
TestImages.Builtin.logo.use(image => {
image.thumbnail(new MagickGeometry(200, 200));

expect(image.width).toBe(200);
expect(image.height).toBe(150);
});
});

it('should remove all image profiles except the icc/icm profile', () => {
TestImages.fujiFilmFinePixS1ProJpg.use(image => {
expect(image.profileNames.length).toBe(5);

image.thumbnail(100, 100);

expect(image.profileNames.length).toBe(1);
expect(image.profileNames[0]).toBe('icc');
});
});
});