Skip to content

Commit

Permalink
Added combine to MagickImageCollection
Browse files Browse the repository at this point in the history
  • Loading branch information
dlemstra committed Aug 4, 2024
1 parent 316136d commit 06afc3e
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 4 deletions.
50 changes: 46 additions & 4 deletions src/magick-image-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { ByteArray } from './byte-array';
import { ColorSpace } from './enums/color-space';
import { Disposable } from './internal/disposable';
import { DisposableArray } from './internal/disposable-array';
import { EvaluateOperator } from './enums/evaluate-operator';
Expand Down Expand Up @@ -68,6 +69,32 @@ export interface IMagickImageCollection extends Array<IMagickImage>, IDisposable
*/
coalesce(): void;

/**
* Combines the images into a single image. The typical ordering would be
* image 1 => Red, 2 => Green, 3 => Blue, etc.
*/
combine<TReturnType>(func: (image: IMagickImage) => TReturnType): TReturnType;

/**
* Merge a sequence of images. This is useful for GIF animation sequences that have page
* offsets and disposal methods.
*/
combine<TReturnType>(func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>;

/**
* Combines the images into a single image. The typical ordering would be
* image 1 => Red, 2 => Green, 3 => Blue, etc.
* @param colorSpace - The image colorspace.
*/
combine<TReturnType>(colorSpace: ColorSpace, func: (image: IMagickImage) => TReturnType): TReturnType;

/**
* Combines the images into a single image. The typical ordering would be
* image 1 => Red, 2 => Green, 3 => Blue, etc.
* @param colorSpace - The image colorspace.
*/
combine<TReturnType>(colorSpace: ColorSpace, func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>;

/**
* Evaluate image pixels into a single image. All the images in the collection must be the
* same size in pixels.
Expand Down Expand Up @@ -252,6 +279,23 @@ export class MagickImageCollection extends Array<MagickImage> implements IMagick
this.addImages(result, settings);
}

combine<TReturnType>(func: (func: IMagickImage) => TReturnType): TReturnType;
combine<TReturnType>(func: (func: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>;
combine<TReturnType>(colorSpace: ColorSpace, func: (image: IMagickImage) => TReturnType): TReturnType;
combine<TReturnType>(colorSpace: ColorSpace, func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>
combine<TReturnType>(colorSpaceOrfunc: ColorSpace | ((image: IMagickImage) => TReturnType | Promise<TReturnType>), func?: (images: IMagickImage) => TReturnType | Promise<TReturnType>): TReturnType | Promise<TReturnType> {
let callback = func;
let colorSpace = ColorSpace.sRGB;
if (typeof colorSpaceOrfunc === 'number')
colorSpace = colorSpaceOrfunc;
else
callback = colorSpaceOrfunc;

return this.createImage((instance, exception) => {
return ImageMagick._api._MagickImageCollection_Combine(instance, colorSpace, exception.ptr);
}, callback!);
}

evaluate<TReturnType>(evaluateOperator: EvaluateOperator, func: (image: IMagickImage) => TReturnType): TReturnType;
evaluate<TReturnType>(evaluateOperator: EvaluateOperator, func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>;
evaluate<TReturnType>(evaluateOperator: EvaluateOperator, func: (image: IMagickImage) => TReturnType | Promise<TReturnType>): TReturnType | Promise<TReturnType> {
Expand Down Expand Up @@ -402,15 +446,13 @@ export class MagickImageCollection extends Array<MagickImage> implements IMagick
}

private attachImages<TReturnType>(func: (instance: number) => TReturnType): TReturnType {
try
{
try {
for (let i = 0; i < this.length - 1; i++)
ImageMagick._api._MagickImage_SetNext(this[i]._instance, this[i + 1]._instance);

return func(this[0]._instance);
}
finally
{
finally {
for (let i = 0; i < this.length - 1; i++)
ImageMagick._api._MagickImage_SetNext(this[i]._instance, 0);
}
Expand Down
47 changes: 47 additions & 0 deletions tests/magick-image-collection/combine.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

import { ColorSpace } from '@src/enums/color-space';
import { ErrorMetric } from '@src/enums/error-metric';
import { MagickImageCollection } from '@src/magick-image-collection';
import { MagickFormat } from '@src/enums/magick-format';
import { TestImages } from '@test/test-images';

describe('MagickImageCollection#combine', () => {
it('should throw exception when collection is empty', () => {
expect(() => {
const images = MagickImageCollection.create();
images.combine(() => { /* never reached */ });
}).toThrowError('operation requires at least one image');
});

it('should combine the channels into an image', () => {
TestImages.redPng.use(image => {
image.separate(images => {
images.combine(combinedImage => {
expect(combinedImage.format).toBe(MagickFormat.Png);
expect(combinedImage.width).toBe(image.width);
expect(combinedImage.height).toBe(image.height);

expect(image.compare(combinedImage, ErrorMetric.RootMeanSquared)).toBe(0);
});
})
});
});

it('should combine the channels using the specified colorspace into an image', () => {
TestImages.cmykJpg.use(image => {
image.separate(images => {
images.combine(ColorSpace.CMYK, combinedImage => {
expect(combinedImage.format).toBe(MagickFormat.Jpeg);
expect(combinedImage.width).toBe(image.width);
expect(combinedImage.height).toBe(image.height);

expect(image.compare(combinedImage, ErrorMetric.RootMeanSquared)).toBe(0);
});
})
});
});
});

0 comments on commit 06afc3e

Please sign in to comment.