diff --git a/src/enums/color-transform-mode.ts b/src/enums/color-transform-mode.ts new file mode 100644 index 0000000..1e50a2b --- /dev/null +++ b/src/enums/color-transform-mode.ts @@ -0,0 +1,19 @@ +/* + Copyright Dirk Lemstra https://github.com/dlemstra/magick-wasm. + Licensed under the Apache License, Version 2.0. +*/ + +/** + * Specifies color transform modes. + */ +export enum ColorTransformMode { + /** + * High resolution (double). + */ + HighRes, + + /** + * Quantum. + */ + Quantum, +} diff --git a/src/index.ts b/src/index.ts index 78c8839..decacee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,6 +39,7 @@ export * from './enums/auto-threshold-method'; export * from './enums/channels'; export * from './enums/class-type'; export * from './enums/color-space'; +export * from './enums/color-transform-mode'; export * from './enums/color-type'; export * from './enums/complex-operator'; export * from './enums/composite-operator'; diff --git a/src/magick-image.ts b/src/magick-image.ts index 04accff..9fc3446 100644 --- a/src/magick-image.ts +++ b/src/magick-image.ts @@ -12,6 +12,7 @@ import { ChromaticityInfo } from './types/chromaticity-info'; import { ClassType } from './enums/class-type'; import { ColorProfile, IColorProfile } from './profiles/color/color-profile'; import { ColorSpace } from './enums/color-space'; +import { ColorTransformMode } from './enums/color-transform-mode'; import { ColorType } from './enums/color-type'; import { CompareResult } from './types/compare-result'; import { CompareSettings } from './settings/compare-settings'; @@ -1705,6 +1706,15 @@ export interface IMagickImage extends IDisposable { */ transformColorSpace(target: IColorProfile): boolean; + /** + * Transforms the image from the colorspace of the source profile to the target profile. This + * requires the image to have a color profile. Nothing will happen if the image has no color profile. + * @param target The target color profile. + * @param mode The color transform node. + * @returns A value indicating whether the transformation was successful. + */ + transformColorSpace(target: IColorProfile, mode: ColorTransformMode): boolean; + /** * Transforms the image from the colorspace of the source profile to the target profile. The * source profile will only be used if the image does not contain a color profile. Nothing @@ -1715,6 +1725,17 @@ export interface IMagickImage extends IDisposable { */ transformColorSpace(source: IColorProfile, target: IColorProfile): boolean; + /** + * Transforms the image from the colorspace of the source profile to the target profile. The + * source profile will only be used if the image does not contain a color profile. Nothing + * will happen if the source profile has a different colorspace then that of the image. + * @param source The source color profile. + * @param target The target color profile. + * @param mode The color transform node. + * @returns A value indicating whether the transformation was successful. + */ + transformColorSpace(source: IColorProfile, target: IColorProfile, mode: ColorTransformMode): boolean; + /** * Threshold image. * @param percentage The threshold percentage. @@ -3281,12 +3302,21 @@ export class MagickImage extends NativeInstance implements IMagickImage { } transformColorSpace(target: IColorProfile): boolean; + transformColorSpace(target: IColorProfile, mode: ColorTransformMode): boolean; transformColorSpace(source: IColorProfile, target: IColorProfile): boolean; - transformColorSpace(sourceOrTarget: IColorProfile, targetOrUndefined?: IColorProfile): boolean { + transformColorSpace(source: IColorProfile, target: IColorProfile, mode: ColorTransformMode): boolean; + transformColorSpace(sourceOrTarget: IColorProfile, targetModeOrUndefined?: IColorProfile | ColorTransformMode, modeOrUndefined?: ColorTransformMode): boolean { const source = sourceOrTarget; let target: IColorProfile | undefined; - if (targetOrUndefined !== undefined) - target = targetOrUndefined; + let mode = ColorTransformMode.Quantum; + if (targetModeOrUndefined !== undefined) { + if (typeof targetModeOrUndefined === 'number') + mode = targetModeOrUndefined; + else + target = targetModeOrUndefined; + } + if (modeOrUndefined !== undefined) + mode = modeOrUndefined; const hasColorProfile = this.hasProfile('icc') || this.hasProfile('icm'); if (target === undefined) { @@ -3303,7 +3333,15 @@ export class MagickImage extends NativeInstance implements IMagickImage { this.setProfile(source); } - this.setProfile(target); + if (mode === ColorTransformMode.Quantum) { + TemporaryDefines.use(this, temporaryDefines => { + temporaryDefines.setArtifact('profile:highres-transform', false); + this.setProfile(target); + }); + } + else { + this.setProfile(target); + } return true; } diff --git a/tests/files/color-profiles/CoatedFOGRA39.icc b/tests/files/color-profiles/CoatedFOGRA39.icc new file mode 100644 index 0000000..61cb86a Binary files /dev/null and b/tests/files/color-profiles/CoatedFOGRA39.icc differ diff --git a/tests/magick-image/transform-color-space.spec.ts b/tests/magick-image/transform-color-space.spec.ts index c417ff5..c3fff4f 100644 --- a/tests/magick-image/transform-color-space.spec.ts +++ b/tests/magick-image/transform-color-space.spec.ts @@ -4,6 +4,7 @@ */ import { ColorSpace } from '@src/enums/color-space'; +import { ColorTransformMode } from '@src/enums/color-transform-mode'; import { TestFiles } from '@test/test-files'; describe('MagickImage#transformColorSpace', () => { @@ -52,4 +53,26 @@ describe('MagickImage#transformColorSpace', () => { expect(image.colorSpace).toBe(ColorSpace.CMYK); }); }); + + it('should use quantum color transform mode by default', () => { + const source = TestFiles.Profiles.Color.SRGB.load(); + const target = TestFiles.Profiles.Color.CoatedFOGRA39.load(); + + TestFiles.Images.Color.white.use((image) => { + image.transformColorSpace(source, target); + const result = image.formatExpression('%[pixel:u]'); + expect(result).toBe('cmyk(0,0,0,0)'); + }); + }); + + it('should support high res transform mode', () => { + const source = TestFiles.Profiles.Color.SRGB.load(); + const target = TestFiles.Profiles.Color.CoatedFOGRA39.load(); + + TestFiles.Images.Color.white.use((image) => { + image.transformColorSpace(source, target, ColorTransformMode.HighRes); + const result = image.formatExpression('%[pixel:u]'); + expect(result).toBe('cmyk(0,1,0,0)'); + }); + }); }); diff --git a/tests/test-files.ts b/tests/test-files.ts index 0f6bf0b..af55c67 100644 --- a/tests/test-files.ts +++ b/tests/test-files.ts @@ -162,7 +162,7 @@ export class TestFiles { red: new TestImageFromColor(MagickColors.Red, 1, 1), black: new TestImageFromColor(MagickColors.Black, 1, 1), purple: new TestImageFromColor(MagickColors.Purple, 1, 1), - white: new TestImageFromColor(MagickColors.Black, 2, 2), + white: new TestImageFromColor(MagickColors.White, 2, 2), } } @@ -170,6 +170,7 @@ export class TestFiles { Color: { SRGB: new TestColorProfile('tests/files/color-profiles/SRGB.icm'), USWebCoatedSWOP: new TestColorProfile('tests/files/color-profiles/USWebCoatedSWOP.icc'), + CoatedFOGRA39: new TestColorProfile('tests/files/color-profiles/CoatedFOGRA39.icc'), } } }