Skip to content

Commit

Permalink
Added complex to the MagickImageCollection.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlemstra committed Aug 5, 2024
1 parent ae3b64e commit 0606dcd
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 4 deletions.
49 changes: 49 additions & 0 deletions src/enums/complex-operator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

/**
* Specifies a kind of complex operator.
*/
export enum ComplexOperator {
/**
* Undefined.
*/
Undefined,

/**
* Add.
*/
Add,

/**
* Conjugate.
*/
Conjugate,

/**
* Divide.
*/
Divide,

/**
* Magnitude phase.
*/
MagnitudePhase,

/**
* Multiply.
*/
Multiply,

/**
* Real imaginary.
*/
RealImaginary,

/**
* Subtract.
*/
Subtract,
}
5 changes: 3 additions & 2 deletions src/helpers/temporary-defines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ export class TemporaryDefines {
this._image = image;
}

setArtifact(name: string, value: string): void;
setArtifact(name: string, value: boolean): void;
setArtifact(name: string, value: IMagickColor): void;
setArtifact(name: string, value: string | boolean | IMagickColor): void {
setArtifact(name: string, value: number): void;
setArtifact(name: string, value: string): void;
setArtifact(name: string, value: boolean | IMagickColor | number | string): void {
this._names.push(name);
this._image.setArtifact(name, value);
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export * from './enums/channels';
export * from './enums/class-type';
export * from './enums/color-space';
export * from './enums/color-type';
export * from './enums/complex-operator';
export * from './enums/composite-operator';
export * from './enums/compression-method';
export * from './enums/density-unit';
Expand Down Expand Up @@ -86,6 +87,7 @@ export * from './pixels/pixel-collection';
export * from './profiles/image-profile';
export * from './quantum';
export * from './settings/compare-settings';
export * from './settings/complex-settings';
export * from './settings/connected-components-settings';
export * from './settings/distort-settings';
export * from './settings/magick-read-settings';
Expand Down
27 changes: 27 additions & 0 deletions src/magick-image-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { ByteArray } from './byte-array';
import { ColorSpace } from './enums/color-space';
import { ComplexSettings } from './settings/complex-settings';
import { Disposable } from './internal/disposable';
import { DisposableArray } from './internal/disposable-array';
import { EvaluateOperator } from './enums/evaluate-operator';
Expand All @@ -20,6 +21,7 @@ import { MagickImage } from './magick-image';
import { MagickReadSettings } from './settings/magick-read-settings';
import { MagickSettings } from './settings/magick-settings';
import { MontageSettings } from './settings/montage-settings';
import { TemporaryDefines } from './helpers/temporary-defines';

export interface IMagickImageCollection extends Array<IMagickImage>, IDisposable {
/** @internal */
Expand Down Expand Up @@ -95,6 +97,19 @@ export interface IMagickImageCollection extends Array<IMagickImage>, IDisposable
*/
combine<TReturnType>(colorSpace: ColorSpace, func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>;

/**
* Perform complex mathematics on an image sequence.
* @param func - The function to execute with the image.
*/
complex<TReturnType>(settings: ComplexSettings, func: (image: IMagickImage) => TReturnType): TReturnType;

/**
* Perform complex mathematics on an image sequence.
* @param func - The function to execute with the image.
*/
complex<TReturnType>(settings: ComplexSettings, 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 @@ -219,6 +234,7 @@ export class MagickImageCollection extends Array<MagickImage> implements IMagick
* Creates a new {@link IMagickImageCollection} instance.
*/
static create(): IMagickImageCollection;

/**
* Creates a new {@link IMagickImageCollection} instance from the specified byte array.
*/
Expand Down Expand Up @@ -296,6 +312,17 @@ export class MagickImageCollection extends Array<MagickImage> implements IMagick
}, callback!);
}

complex<TReturnType>(settings: ComplexSettings, func: (image: IMagickImage) => TReturnType): TReturnType;
complex<TReturnType>(settings: ComplexSettings, func: (image: IMagickImage) => Promise<TReturnType>): Promise<TReturnType>
complex<TReturnType>(settings: ComplexSettings, func: (image: IMagickImage) => TReturnType | Promise<TReturnType>): TReturnType | Promise<TReturnType> {
return TemporaryDefines.use(this[0], temporaryDefines => {
settings._setArtifacts(temporaryDefines);
return this.createImage((instance, exception) => {
return ImageMagick._api._MagickImageCollection_Complex(instance, settings.complexOperator, exception.ptr);
}, func);
});
}

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
4 changes: 2 additions & 2 deletions src/magick-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1469,7 +1469,7 @@ export interface IMagickImage extends IDisposable {
* @param name - The name of the artifact.
* @param value - The value of the artifact.
*/
setArtifact(name: string, value: string | boolean | IMagickColor): void;
setArtifact(name: string, value: boolean | IMagickColor | number | string): void;

/**
* Inserts the attribute with the specified name and value into the artifact tree of the image.
Expand Down Expand Up @@ -2938,7 +2938,7 @@ export class MagickImage extends NativeInstance implements IMagickImage {
});
}

setArtifact(name: string, value: string | boolean | IMagickColor): void {
setArtifact(name: string, value: boolean | IMagickColor | number | string): void {
let strValue: string;
if (typeof value === 'string')
strValue = value;
Expand Down
37 changes: 37 additions & 0 deletions src/settings/complex-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

import { ComplexOperator } from '../enums/complex-operator';
import { TemporaryDefines } from '../helpers/temporary-defines';

/**
* Settings for the complex operation.
*/
export class ComplexSettings {
/**
* Initializes a new instance of the {@link ComplexSettings} class.
* @param complexOperator - The complex operator.
*/
constructor(complexOperator: ComplexOperator) {
this.complexOperator = complexOperator;
}

/**F
* Gets or sets the complex operator.
**/
readonly complexOperator: ComplexOperator;

/**
* Gets or sets the signal to noise ratio.
**/
signalToNoiseRatio?: number;


/** @internal */
_setArtifacts(temporaryDefines: TemporaryDefines): void {
if (this.signalToNoiseRatio !== undefined)
temporaryDefines.setArtifact('complex:snr', this.signalToNoiseRatio);
}
}
32 changes: 32 additions & 0 deletions tests/magick-image-collection/complex.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

import { ComplexOperator } from '@src/enums/complex-operator';
import { ErrorMetric } from '@src/enums/error-metric';
import { ComplexSettings } from '@src/settings/complex-settings';
import { TestImages } from '@test/test-images';

describe('MagickImageCollection#coalesce', () => {
it('should throw exception when collection is empty', () => {
const settings = new ComplexSettings(ComplexOperator.Add);

TestImages.emptyCollection.use((images) => {
expect(() => {
images.complex(settings, () => { /* never reached */ });
}).toThrowError('operation requires at least one image');
});
});

it('should apply the complex operation', () => {
const settings = new ComplexSettings(ComplexOperator.Divide);
settings.signalToNoiseRatio = 5;

TestImages.roseSparkleGif.use(images => {
images.complex(settings, (image) => {
expect(image.compare(images[0], ErrorMetric.RootMeanSquared)).toBeCloseTo(0.56843);
});
});
});
});
28 changes: 28 additions & 0 deletions tests/settings/complex-settings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm.
Licensed under the Apache License, Version 2.0.
*/

import { ComplexOperator } from '@src/enums/complex-operator';
import { TemporaryDefines } from '@src/helpers/temporary-defines';
import { ComplexSettings } from '@src/settings/complex-settings';
import { TestImages } from '@test/test-images';

describe('ConnectedComponentsSettings', () => {
const settings = new ComplexSettings(ComplexOperator.Multiply);
settings.signalToNoiseRatio = 42;

describe('#_setArtifacts', () => {
it('should add all defined artifacts to the provided image', () => {
TestImages.Builtin.logo.use((image) => {
TemporaryDefines.use(image, (temporaryDefines) => {
settings._setArtifacts(temporaryDefines);

expect(settings.complexOperator).toBe(ComplexOperator.Multiply);
expect(image.artifactNames.length).toBe(1);
expect(image.getArtifact('complex:snr')).toBe('42');
});
});
});
});
});

0 comments on commit 0606dcd

Please sign in to comment.