Path: blob/master/src/java.desktop/share/native/liblcms/cmsxform.c
41152 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324// This file is available under and governed by the GNU General Public25// License version 2 only, as published by the Free Software Foundation.26// However, the following notice accompanied the original version of this27// file:28//29//---------------------------------------------------------------------------------30//31// Little Color Management System32// Copyright (c) 1998-2020 Marti Maria Saguer33//34// Permission is hereby granted, free of charge, to any person obtaining35// a copy of this software and associated documentation files (the "Software"),36// to deal in the Software without restriction, including without limitation37// the rights to use, copy, modify, merge, publish, distribute, sublicense,38// and/or sell copies of the Software, and to permit persons to whom the Software39// is furnished to do so, subject to the following conditions:40//41// The above copyright notice and this permission notice shall be included in42// all copies or substantial portions of the Software.43//44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.51//52//---------------------------------------------------------------------------------53//5455#include "lcms2_internal.h"5657// Transformations stuff58// -----------------------------------------------------------------------5960#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.06162// The Context0 observer adaptation state.63_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };6465// Init and duplicate observer adaptation state66void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,67const struct _cmsContext_struct* src)68{69static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };70void* from;7172if (src != NULL) {73from = src ->chunks[AdaptationStateContext];74}75else {76from = &AdaptationStateChunk;77}7879ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));80}818283// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all84// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states.85cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)86{87cmsFloat64Number prev;88_cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);8990// Get previous value for return91prev = ptr ->AdaptationState;9293// Set the value if d is positive or zero94if (d >= 0.0) {9596ptr ->AdaptationState = d;97}9899// Always return previous value100return prev;101}102103104// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine105cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)106{107return cmsSetAdaptationStateTHR(NULL, d);108}109110// -----------------------------------------------------------------------111112// Alarm codes for 16-bit transformations, because the fixed range of containers there are113// no values left to mark out of gamut.114115#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}116117_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };118119// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be120// encoded in 16 bits.121void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])122{123_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);124125_cmsAssert(ContextAlarmCodes != NULL); // Can't happen126127memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));128}129130// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.131// Values are meant to be encoded in 16 bits.132void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])133{134_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);135136_cmsAssert(ContextAlarmCodes != NULL); // Can't happen137138memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));139}140141void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])142{143_cmsAssert(NewAlarm != NULL);144145cmsSetAlarmCodesTHR(NULL, NewAlarm);146}147148void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])149{150_cmsAssert(OldAlarm != NULL);151cmsGetAlarmCodesTHR(NULL, OldAlarm);152}153154155// Init and duplicate alarm codes156void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,157const struct _cmsContext_struct* src)158{159static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };160void* from;161162if (src != NULL) {163from = src ->chunks[AlarmCodesContext];164}165else {166from = &AlarmCodesChunk;167}168169ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));170}171172// -----------------------------------------------------------------------173174// Get rid of transform resources175void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)176{177_cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;178179_cmsAssert(p != NULL);180181if (p -> GamutCheck)182cmsPipelineFree(p -> GamutCheck);183184if (p -> Lut)185cmsPipelineFree(p -> Lut);186187if (p ->InputColorant)188cmsFreeNamedColorList(p ->InputColorant);189190if (p -> OutputColorant)191cmsFreeNamedColorList(p ->OutputColorant);192193if (p ->Sequence)194cmsFreeProfileSequenceDescription(p ->Sequence);195196if (p ->UserData)197p ->FreeUserData(p ->ContextID, p ->UserData);198199_cmsFree(p ->ContextID, (void *) p);200}201202203static204cmsUInt32Number PixelSize(cmsUInt32Number Format)205{206cmsUInt32Number fmt_bytes = T_BYTES(Format);207208// For double, the T_BYTES field is zero209if (fmt_bytes == 0)210return sizeof(cmsUInt64Number);211212// Otherwise, it is already correct for all formats213return fmt_bytes;214}215216217218219// Apply transform.220void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,221const void* InputBuffer,222void* OutputBuffer,223cmsUInt32Number Size)224225{226_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;227cmsStride stride;228229stride.BytesPerLineIn = 0; // Not used230stride.BytesPerLineOut = 0;231stride.BytesPerPlaneIn = Size * PixelSize(p->InputFormat);232stride.BytesPerPlaneOut = Size * PixelSize(p->OutputFormat);233234p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);235}236237238// This is a legacy stride for planar239void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,240const void* InputBuffer,241void* OutputBuffer,242cmsUInt32Number Size, cmsUInt32Number Stride)243244{245_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;246cmsStride stride;247248stride.BytesPerLineIn = 0;249stride.BytesPerLineOut = 0;250stride.BytesPerPlaneIn = Stride;251stride.BytesPerPlaneOut = Stride;252253p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);254}255256// This is the "fast" function for plugins257void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform,258const void* InputBuffer,259void* OutputBuffer,260cmsUInt32Number PixelsPerLine,261cmsUInt32Number LineCount,262cmsUInt32Number BytesPerLineIn,263cmsUInt32Number BytesPerLineOut,264cmsUInt32Number BytesPerPlaneIn,265cmsUInt32Number BytesPerPlaneOut)266267{268_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;269cmsStride stride;270271stride.BytesPerLineIn = BytesPerLineIn;272stride.BytesPerLineOut = BytesPerLineOut;273stride.BytesPerPlaneIn = BytesPerPlaneIn;274stride.BytesPerPlaneOut = BytesPerPlaneOut;275276p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride);277}278279280281// Transform routines ----------------------------------------------------------------------------------------------------------282283// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.284// Note that because extended range, we can use a -1.0 value for out of gamut in this case.285static286void FloatXFORM(_cmsTRANSFORM* p,287const void* in,288void* out,289cmsUInt32Number PixelsPerLine,290cmsUInt32Number LineCount,291const cmsStride* Stride)292{293cmsUInt8Number* accum;294cmsUInt8Number* output;295cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];296cmsFloat32Number OutOfGamut;297cmsUInt32Number i, j, c, strideIn, strideOut;298299_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);300301strideIn = 0;302strideOut = 0;303memset(fIn, 0, sizeof(fIn));304memset(fOut, 0, sizeof(fOut));305306for (i = 0; i < LineCount; i++) {307308accum = (cmsUInt8Number*)in + strideIn;309output = (cmsUInt8Number*)out + strideOut;310311for (j = 0; j < PixelsPerLine; j++) {312313accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);314315// Any gamut chack to do?316if (p->GamutCheck != NULL) {317318// Evaluate gamut marker.319cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck);320321// Is current color out of gamut?322if (OutOfGamut > 0.0) {323324// Certainly, out of gamut325for (c = 0; c < cmsMAXCHANNELS; c++)326fOut[c] = -1.0;327328}329else {330// No, proceed normally331cmsPipelineEvalFloat(fIn, fOut, p->Lut);332}333}334else {335336// No gamut check at all337cmsPipelineEvalFloat(fIn, fOut, p->Lut);338}339340341output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut);342}343344strideIn += Stride->BytesPerLineIn;345strideOut += Stride->BytesPerLineOut;346}347348}349350351static352void NullFloatXFORM(_cmsTRANSFORM* p,353const void* in,354void* out,355cmsUInt32Number PixelsPerLine,356cmsUInt32Number LineCount,357const cmsStride* Stride)358359{360cmsUInt8Number* accum;361cmsUInt8Number* output;362cmsFloat32Number fIn[cmsMAXCHANNELS];363cmsUInt32Number i, j, strideIn, strideOut;364365_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);366367strideIn = 0;368strideOut = 0;369memset(fIn, 0, sizeof(fIn));370371for (i = 0; i < LineCount; i++) {372373accum = (cmsUInt8Number*) in + strideIn;374output = (cmsUInt8Number*) out + strideOut;375376for (j = 0; j < PixelsPerLine; j++) {377378accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn);379output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut);380}381382strideIn += Stride->BytesPerLineIn;383strideOut += Stride->BytesPerLineOut;384}385}386387// 16 bit precision -----------------------------------------------------------------------------------------------------------388389// Null transformation, only applies formatters. No cache390static391void NullXFORM(_cmsTRANSFORM* p,392const void* in,393void* out,394cmsUInt32Number PixelsPerLine,395cmsUInt32Number LineCount,396const cmsStride* Stride)397{398cmsUInt8Number* accum;399cmsUInt8Number* output;400cmsUInt16Number wIn[cmsMAXCHANNELS];401cmsUInt32Number i, j, strideIn, strideOut;402403_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);404405strideIn = 0;406strideOut = 0;407memset(wIn, 0, sizeof(wIn));408409for (i = 0; i < LineCount; i++) {410411accum = (cmsUInt8Number*)in + strideIn;412output = (cmsUInt8Number*)out + strideOut;413414for (j = 0; j < PixelsPerLine; j++) {415416accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);417output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut);418}419420strideIn += Stride->BytesPerLineIn;421strideOut += Stride->BytesPerLineOut;422}423424}425426427// No gamut check, no cache, 16 bits428static429void PrecalculatedXFORM(_cmsTRANSFORM* p,430const void* in,431void* out,432cmsUInt32Number PixelsPerLine,433cmsUInt32Number LineCount,434const cmsStride* Stride)435{436CMSREGISTER cmsUInt8Number* accum;437CMSREGISTER cmsUInt8Number* output;438cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];439cmsUInt32Number i, j, strideIn, strideOut;440441_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);442443strideIn = 0;444strideOut = 0;445memset(wIn, 0, sizeof(wIn));446memset(wOut, 0, sizeof(wOut));447448for (i = 0; i < LineCount; i++) {449450accum = (cmsUInt8Number*)in + strideIn;451output = (cmsUInt8Number*)out + strideOut;452453for (j = 0; j < PixelsPerLine; j++) {454455accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);456p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);457output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);458}459460strideIn += Stride->BytesPerLineIn;461strideOut += Stride->BytesPerLineOut;462}463464}465466467// Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.468static469void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,470const cmsUInt16Number wIn[],471cmsUInt16Number wOut[])472{473cmsUInt16Number wOutOfGamut;474475p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);476if (wOutOfGamut >= 1) {477478cmsUInt32Number i;479_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);480481for (i=0; i < p ->Lut->OutputChannels; i++) {482483wOut[i] = ContextAlarmCodes ->AlarmCodes[i];484}485}486else487p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);488}489490// Gamut check, No cache, 16 bits.491static492void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,493const void* in,494void* out,495cmsUInt32Number PixelsPerLine,496cmsUInt32Number LineCount,497const cmsStride* Stride)498{499cmsUInt8Number* accum;500cmsUInt8Number* output;501cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];502cmsUInt32Number i, j, strideIn, strideOut;503504_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);505506strideIn = 0;507strideOut = 0;508memset(wIn, 0, sizeof(wIn));509memset(wOut, 0, sizeof(wOut));510511for (i = 0; i < LineCount; i++) {512513accum = (cmsUInt8Number*)in + strideIn;514output = (cmsUInt8Number*)out + strideOut;515516for (j = 0; j < PixelsPerLine; j++) {517518accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);519TransformOnePixelWithGamutCheck(p, wIn, wOut);520output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);521}522523strideIn += Stride->BytesPerLineIn;524strideOut += Stride->BytesPerLineOut;525}526}527528529// No gamut check, Cache, 16 bits,530static531void CachedXFORM(_cmsTRANSFORM* p,532const void* in,533void* out,534cmsUInt32Number PixelsPerLine,535cmsUInt32Number LineCount,536const cmsStride* Stride)537{538cmsUInt8Number* accum;539cmsUInt8Number* output;540cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];541_cmsCACHE Cache;542cmsUInt32Number i, j, strideIn, strideOut;543544_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);545546// Empty buffers for quick memcmp547memset(wIn, 0, sizeof(wIn));548memset(wOut, 0, sizeof(wOut));549550// Get copy of zero cache551memcpy(&Cache, &p->Cache, sizeof(Cache));552553strideIn = 0;554strideOut = 0;555556for (i = 0; i < LineCount; i++) {557558accum = (cmsUInt8Number*)in + strideIn;559output = (cmsUInt8Number*)out + strideOut;560561for (j = 0; j < PixelsPerLine; j++) {562563accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);564565if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {566567memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));568}569else {570p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);571572memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));573memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));574}575576output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);577}578579strideIn += Stride->BytesPerLineIn;580strideOut += Stride->BytesPerLineOut;581}582}583584// All those nice features together585static586void CachedXFORMGamutCheck(_cmsTRANSFORM* p,587const void* in,588void* out,589cmsUInt32Number PixelsPerLine,590cmsUInt32Number LineCount,591const cmsStride* Stride)592{593cmsUInt8Number* accum;594cmsUInt8Number* output;595cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];596_cmsCACHE Cache;597cmsUInt32Number i, j, strideIn, strideOut;598599_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);600601// Empty buffers for quick memcmp602memset(wIn, 0, sizeof(wIn));603memset(wOut, 0, sizeof(wOut));604605// Get copy of zero cache606memcpy(&Cache, &p->Cache, sizeof(Cache));607608strideIn = 0;609strideOut = 0;610611for (i = 0; i < LineCount; i++) {612613accum = (cmsUInt8Number*)in + strideIn;614output = (cmsUInt8Number*)out + strideOut;615616for (j = 0; j < PixelsPerLine; j++) {617618accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);619620if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {621622memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));623}624else {625TransformOnePixelWithGamutCheck(p, wIn, wOut);626627memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));628memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));629}630631output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);632}633634strideIn += Stride->BytesPerLineIn;635strideOut += Stride->BytesPerLineOut;636}637}638639// Transform plug-ins ----------------------------------------------------------------------------------------------------640641// List of used-defined transform factories642typedef struct _cmsTransformCollection_st {643644_cmsTransform2Factory Factory;645cmsBool OldXform; // Factory returns xform function in the old style646647struct _cmsTransformCollection_st *Next;648649} _cmsTransformCollection;650651// The linked list head652_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };653654655// Duplicates the zone of memory used by the plug-in in the new context656static657void DupPluginTransformList(struct _cmsContext_struct* ctx,658const struct _cmsContext_struct* src)659{660_cmsTransformPluginChunkType newHead = { NULL };661_cmsTransformCollection* entry;662_cmsTransformCollection* Anterior = NULL;663_cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];664665// Walk the list copying all nodes666for (entry = head->TransformCollection;667entry != NULL;668entry = entry ->Next) {669670_cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));671672if (newEntry == NULL)673return;674675// We want to keep the linked list order, so this is a little bit tricky676newEntry -> Next = NULL;677if (Anterior)678Anterior -> Next = newEntry;679680Anterior = newEntry;681682if (newHead.TransformCollection == NULL)683newHead.TransformCollection = newEntry;684}685686ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));687}688689// Allocates memory for transform plugin factory690void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,691const struct _cmsContext_struct* src)692{693if (src != NULL) {694695// Copy all linked list696DupPluginTransformList(ctx, src);697}698else {699static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };700ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));701}702}703704// Adaptor for old versions of plug-in705static706void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo,707const void* InputBuffer,708void* OutputBuffer,709cmsUInt32Number PixelsPerLine,710cmsUInt32Number LineCount,711const cmsStride* Stride)712{713714cmsUInt32Number i, strideIn, strideOut;715716_cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride);717718strideIn = 0;719strideOut = 0;720721for (i = 0; i < LineCount; i++) {722723void *accum = (cmsUInt8Number*)InputBuffer + strideIn;724void *output = (cmsUInt8Number*)OutputBuffer + strideOut;725726CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn);727728strideIn += Stride->BytesPerLineIn;729strideOut += Stride->BytesPerLineOut;730}731}732733734735// Register new ways to transform736cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)737{738cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;739_cmsTransformCollection* fl;740_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);741742if (Data == NULL) {743744// Free the chain. Memory is safely freed at exit745ctx->TransformCollection = NULL;746return TRUE;747}748749// Factory callback is required750if (Plugin->factories.xform == NULL) return FALSE;751752753fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));754if (fl == NULL) return FALSE;755756// Check for full xform plug-ins previous to 2.8, we would need an adapter in that case757if (Plugin->base.ExpectedVersion < 2080) {758759fl->OldXform = TRUE;760}761else762fl->OldXform = FALSE;763764// Copy the parameters765fl->Factory = Plugin->factories.xform;766767// Keep linked list768fl ->Next = ctx->TransformCollection;769ctx->TransformCollection = fl;770771// All is ok772return TRUE;773}774775776void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)777{778_cmsAssert(CMMcargo != NULL);779CMMcargo ->UserData = ptr;780CMMcargo ->FreeUserData = FreePrivateDataFn;781}782783// returns the pointer defined by the plug-in to store private data784void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)785{786_cmsAssert(CMMcargo != NULL);787return CMMcargo ->UserData;788}789790// returns the current formatters791void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)792{793_cmsAssert(CMMcargo != NULL);794if (FromInput) *FromInput = CMMcargo ->FromInput;795if (ToOutput) *ToOutput = CMMcargo ->ToOutput;796}797798void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)799{800_cmsAssert(CMMcargo != NULL);801if (FromInput) *FromInput = CMMcargo ->FromInputFloat;802if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat;803}804805// returns original flags806cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo)807{808_cmsAssert(CMMcargo != NULL);809return CMMcargo->dwOriginalFlags;810}811812// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper813// for separated transforms. If this is the case,814static815_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,816cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)817{818_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);819_cmsTransformCollection* Plugin;820821// Allocate needed memory822_cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));823if (!p) {824cmsPipelineFree(lut);825return NULL;826}827828// Store the proposed pipeline829p->Lut = lut;830831// Let's see if any plug-in want to do the transform by itself832if (p->Lut != NULL) {833834if (!(*dwFlags & cmsFLAGS_NOOPTIMIZE))835{836for (Plugin = ctx->TransformCollection;837Plugin != NULL;838Plugin = Plugin->Next) {839840if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) {841842// Last plugin in the declaration order takes control. We just keep843// the original parameters as a logging.844// Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default845// an optimized transform is not reusable. The plug-in can, however, change846// the flags and make it suitable.847848p->ContextID = ContextID;849p->InputFormat = *InputFormat;850p->OutputFormat = *OutputFormat;851p->dwOriginalFlags = *dwFlags;852853// Fill the formatters just in case the optimized routine is interested.854// No error is thrown if the formatter doesn't exist. It is up to the optimization855// factory to decide what to do in those cases.856p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;857p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;858p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;859p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;860861// Save the day? (Ignore the warning)862if (Plugin->OldXform) {863p->OldXform = (_cmsTransformFn)(void*)p->xform;864p->xform = _cmsTransform2toTransformAdaptor;865}866867return p;868}869}870}871872// Not suitable for the transform plug-in, let's check the pipeline plug-in873_cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);874}875876// Check whatever this is a true floating point transform877if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {878879// Get formatter function always return a valid union, but the contents of this union may be NULL.880p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;881p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;882*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;883884if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {885886cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");887cmsDeleteTransform(p);888return NULL;889}890891if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {892893p ->xform = NullFloatXFORM;894}895else {896// Float transforms don't use cache, always are non-NULL897p ->xform = FloatXFORM;898}899900}901else {902903if (*InputFormat == 0 && *OutputFormat == 0) {904p ->FromInput = p ->ToOutput = NULL;905*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;906}907else {908909cmsUInt32Number BytesPerPixelInput;910911p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;912p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;913914if (p ->FromInput == NULL || p ->ToOutput == NULL) {915916cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");917cmsDeleteTransform(p);918return NULL;919}920921BytesPerPixelInput = T_BYTES(p ->InputFormat);922if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)923*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;924925}926927if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {928929p ->xform = NullXFORM;930}931else {932if (*dwFlags & cmsFLAGS_NOCACHE) {933934if (*dwFlags & cmsFLAGS_GAMUTCHECK)935p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache936else937p ->xform = PrecalculatedXFORM; // No cache, no gamut check938}939else {940941if (*dwFlags & cmsFLAGS_GAMUTCHECK)942p ->xform = CachedXFORMGamutCheck; // Gamut check, cache943else944p ->xform = CachedXFORM; // No gamut check, cache945946}947}948}949950p ->InputFormat = *InputFormat;951p ->OutputFormat = *OutputFormat;952p ->dwOriginalFlags = *dwFlags;953p ->ContextID = ContextID;954p ->UserData = NULL;955return p;956}957958static959cmsBool GetXFormColorSpaces(cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)960{961cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;962cmsColorSpaceSignature PostColorSpace;963cmsUInt32Number i;964965if (nProfiles == 0) return FALSE;966if (hProfiles[0] == NULL) return FALSE;967968*Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);969970for (i=0; i < nProfiles; i++) {971972cmsProfileClassSignature cls;973cmsHPROFILE hProfile = hProfiles[i];974975int lIsInput = (PostColorSpace != cmsSigXYZData) &&976(PostColorSpace != cmsSigLabData);977978if (hProfile == NULL) return FALSE;979980cls = cmsGetDeviceClass(hProfile);981982if (cls == cmsSigNamedColorClass) {983984ColorSpaceIn = cmsSig1colorData;985ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);986}987else988if (lIsInput || (cls == cmsSigLinkClass)) {989990ColorSpaceIn = cmsGetColorSpace(hProfile);991ColorSpaceOut = cmsGetPCS(hProfile);992}993else994{995ColorSpaceIn = cmsGetPCS(hProfile);996ColorSpaceOut = cmsGetColorSpace(hProfile);997}998999if (i==0)1000*Input = ColorSpaceIn;10011002PostColorSpace = ColorSpaceOut;1003}10041005*Output = PostColorSpace;10061007return TRUE;1008}10091010// Check colorspace1011static1012cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)1013{1014int Space1 = (int) T_COLORSPACE(dwFormat);1015int Space2 = _cmsLCMScolorSpace(Check);10161017if (Space1 == PT_ANY) return TRUE;1018if (Space1 == Space2) return TRUE;10191020if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;1021if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;10221023return FALSE;1024}10251026// ----------------------------------------------------------------------------------------------------------------10271028// Jun-21-2000: Some profiles (those that comes with W2K) comes1029// with the media white (media black?) x 100. Add a sanity check10301031static1032void NormalizeXYZ(cmsCIEXYZ* Dest)1033{1034while (Dest -> X > 2. &&1035Dest -> Y > 2. &&1036Dest -> Z > 2.) {10371038Dest -> X /= 10.;1039Dest -> Y /= 10.;1040Dest -> Z /= 10.;1041}1042}10431044static1045void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)1046{1047if (src == NULL) {1048wtPt ->X = cmsD50X;1049wtPt ->Y = cmsD50Y;1050wtPt ->Z = cmsD50Z;1051}1052else {1053wtPt ->X = src->X;1054wtPt ->Y = src->Y;1055wtPt ->Z = src->Z;10561057NormalizeXYZ(wtPt);1058}10591060}10611062// New to lcms 2.0 -- have all parameters available.1063cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,1064cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],1065cmsBool BPC[],1066cmsUInt32Number Intents[],1067cmsFloat64Number AdaptationStates[],1068cmsHPROFILE hGamutProfile,1069cmsUInt32Number nGamutPCSposition,1070cmsUInt32Number InputFormat,1071cmsUInt32Number OutputFormat,1072cmsUInt32Number dwFlags)1073{1074_cmsTRANSFORM* xform;1075cmsColorSpaceSignature EntryColorSpace;1076cmsColorSpaceSignature ExitColorSpace;1077cmsPipeline* Lut;1078cmsUInt32Number LastIntent = Intents[nProfiles-1];10791080// If it is a fake transform1081if (dwFlags & cmsFLAGS_NULLTRANSFORM)1082{1083return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);1084}10851086// If gamut check is requested, make sure we have a gamut profile1087if (dwFlags & cmsFLAGS_GAMUTCHECK) {1088if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;1089}10901091// On floating point transforms, inhibit cache1092if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))1093dwFlags |= cmsFLAGS_NOCACHE;10941095// Mark entry/exit spaces1096if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {1097cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");1098return NULL;1099}11001101// Check if proper colorspaces1102if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {1103cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");1104return NULL;1105}11061107if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {1108cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");1109return NULL;1110}11111112// Create a pipeline with all transformations1113Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);1114if (Lut == NULL) {1115cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");1116return NULL;1117}11181119// Check channel count1120if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||1121(cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {1122cmsPipelineFree(Lut);1123cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");1124return NULL;1125}112611271128// All seems ok1129xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);1130if (xform == NULL) {1131return NULL;1132}11331134// Keep values1135xform ->EntryColorSpace = EntryColorSpace;1136xform ->ExitColorSpace = ExitColorSpace;1137xform ->RenderingIntent = Intents[nProfiles-1];11381139// Take white points1140SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));1141SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));114211431144// Create a gamut check LUT if requested1145if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))1146xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,1147BPC, Intents,1148AdaptationStates,1149nGamutPCSposition,1150hGamutProfile);115111521153// Try to read input and output colorant table1154if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {11551156// Input table can only come in this way.1157xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));1158}11591160// Output is a little bit more complex.1161if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {11621163// This tag may exist only on devicelink profiles.1164if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {11651166// It may be NULL if error1167xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));1168}11691170} else {11711172if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {11731174xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));1175}1176}11771178// Store the sequence of profiles1179if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {1180xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);1181}1182else1183xform ->Sequence = NULL;11841185// If this is a cached transform, init first value, which is zero (16 bits only)1186if (!(dwFlags & cmsFLAGS_NOCACHE)) {11871188memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));11891190if (xform ->GamutCheck != NULL) {1191TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);1192}1193else {11941195xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);1196}11971198}11991200return (cmsHTRANSFORM) xform;1201}12021203// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.1204cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,1205cmsHPROFILE hProfiles[],1206cmsUInt32Number nProfiles,1207cmsUInt32Number InputFormat,1208cmsUInt32Number OutputFormat,1209cmsUInt32Number Intent,1210cmsUInt32Number dwFlags)1211{1212cmsUInt32Number i;1213cmsBool BPC[256];1214cmsUInt32Number Intents[256];1215cmsFloat64Number AdaptationStates[256];12161217if (nProfiles <= 0 || nProfiles > 255) {1218cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);1219return NULL;1220}12211222for (i=0; i < nProfiles; i++) {1223BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;1224Intents[i] = Intent;1225AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);1226}122712281229return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);1230}1231123212331234cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],1235cmsUInt32Number nProfiles,1236cmsUInt32Number InputFormat,1237cmsUInt32Number OutputFormat,1238cmsUInt32Number Intent,1239cmsUInt32Number dwFlags)1240{12411242if (nProfiles <= 0 || nProfiles > 255) {1243cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);1244return NULL;1245}12461247return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),1248hProfiles,1249nProfiles,1250InputFormat,1251OutputFormat,1252Intent,1253dwFlags);1254}12551256cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,1257cmsHPROFILE Input,1258cmsUInt32Number InputFormat,1259cmsHPROFILE Output,1260cmsUInt32Number OutputFormat,1261cmsUInt32Number Intent,1262cmsUInt32Number dwFlags)1263{12641265cmsHPROFILE hArray[2];12661267hArray[0] = Input;1268hArray[1] = Output;12691270return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1U : 2U, InputFormat, OutputFormat, Intent, dwFlags);1271}12721273CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,1274cmsUInt32Number InputFormat,1275cmsHPROFILE Output,1276cmsUInt32Number OutputFormat,1277cmsUInt32Number Intent,1278cmsUInt32Number dwFlags)1279{1280return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);1281}128212831284cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,1285cmsHPROFILE InputProfile,1286cmsUInt32Number InputFormat,1287cmsHPROFILE OutputProfile,1288cmsUInt32Number OutputFormat,1289cmsHPROFILE ProofingProfile,1290cmsUInt32Number nIntent,1291cmsUInt32Number ProofingIntent,1292cmsUInt32Number dwFlags)1293{1294cmsHPROFILE hArray[4];1295cmsUInt32Number Intents[4];1296cmsBool BPC[4];1297cmsFloat64Number Adaptation[4];1298cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;129913001301hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;1302Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;1303BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;13041305Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);13061307if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))1308return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);13091310return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,1311ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);13121313}131413151316cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,1317cmsUInt32Number InputFormat,1318cmsHPROFILE OutputProfile,1319cmsUInt32Number OutputFormat,1320cmsHPROFILE ProofingProfile,1321cmsUInt32Number nIntent,1322cmsUInt32Number ProofingIntent,1323cmsUInt32Number dwFlags)1324{1325return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),1326InputProfile,1327InputFormat,1328OutputProfile,1329OutputFormat,1330ProofingProfile,1331nIntent,1332ProofingIntent,1333dwFlags);1334}133513361337// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed1338cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)1339{1340_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;13411342if (xform == NULL) return NULL;1343return xform -> ContextID;1344}13451346// Grab the input/output formats1347cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)1348{1349_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;13501351if (xform == NULL) return 0;1352return xform->InputFormat;1353}13541355cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)1356{1357_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;13581359if (xform == NULL) return 0;1360return xform->OutputFormat;1361}13621363// For backwards compatibility1364cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,1365cmsUInt32Number InputFormat,1366cmsUInt32Number OutputFormat)1367{1368_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;1369cmsFormatter16 FromInput, ToOutput;137013711372// We only can afford to change formatters if previous transform is at least 16 bits1373if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {13741375cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");1376return FALSE;1377}13781379FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;1380ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;13811382if (FromInput == NULL || ToOutput == NULL) {13831384cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");1385return FALSE;1386}13871388xform ->InputFormat = InputFormat;1389xform ->OutputFormat = OutputFormat;1390xform ->FromInput = FromInput;1391xform ->ToOutput = ToOutput;1392return TRUE;1393}139413951396