mm2 / Little-CMS

A free, open source, CMM engine. It provides fast transforms between ICC profiles.
https://www.littlecms.com
MIT License
549 stars 174 forks source link

Having trouble with `cmsPluginTag` using `cmsSigUInt32ArrayType` as the data type #455

Closed DominikDeak closed 1 month ago

DominikDeak commented 1 month ago

I am experimenting around with embedding private tags into an ICC profile. Let's say this private tag has a cmsTagSignature named 'test', and I want to store cmsSigUInt32ArrayType for that tag. I want to store only 1 item in that array.

I have been following the example provided in the plugin documentation on page 8. Instead of registering cmsPluginTag using cmsSigLut16Type, as shown in the example, I'd like to use cmsSigUInt32ArrayType as an alternative. However cmsPluginTHR reports an error when adding my custom Tag plugin. The error handler emits the message "Unsupported type 'ui32' for tag 'test' (error code: 8)". See sample code below.

I feel like I'm doing something wrong here, perhaps I'm missing a detail that is required for handling cmsSigUInt32ArrayType data types?

Sample Code

#include <lcms2.h>
#include <lcms2_plugin.h>

static void errorHandler( cmsContext context, cmsUInt32Number errorCode, const char* message )
   {
   printf( "%s (error code: %d)\n", message, errorCode );
   };

void main()
   {
   static cmsTagSignature testSignature = ( cmsTagSignature )( int )'test';

   static cmsPluginTag testPlugin =
      {
      .base =
         {
         .Magic = cmsPluginMagicNumber,
         .ExpectedVersion = 2000,
         .Type = cmsPluginTagSig,
         .Next = NULL,
         },

      .Signature = testSignature,

      .Descriptor
         {
         .ElemCount = 1,
         .nSupportedTypes = 1,
         .SupportedTypes[ 0 ] = cmsSigUInt32ArrayType,
         .DecideType = NULL,
         },
      };

   // Create context
   cmsContext context = cmsCreateContext( NULL, NULL );
   assert( context );
   cmsSetLogErrorHandlerTHR( context, errorHandler );
   cmsPluginTHR( context, &testPlugin );

   // Create profile
   cmsHPROFILE profile = cmsCreateProfilePlaceholder( context );
   assert( profile );

   // Write and read custom tag
   cmsUInt32Number testData = 0x12345678;
   cmsBool result = cmsWriteTag( profile, testSignature, &testData );
   assert( result );

   cmsUInt32Number* p = ( cmsUInt32Number* )cmsReadTag( profile, testSignature );
   assert( p );
   assert( *p == testData );

   // Cleanup
   cmsCloseProfile( profile );
   cmsDeleteContext( context );
   }
mm2 commented 1 month ago

I was thinking the diagnostic is clear.. ok, it happens that only certain types (those already used by ICC spec) are implemented by default. Others are not.

Those are already defined:

cmsSigChromaticityType,         
cmsSigColorantOrderType,        
cmsSigS15Fixed16ArrayType,      
cmsSigU16Fixed16ArrayType,      
cmsSigTextType,                 
cmsSigTextDescriptionType,      
cmsSigCurveType,                
cmsSigParametricCurveType,      
cmsSigDateTimeType,             
cmsSigLut8Type,                 
cmsSigLut16Type,                
cmsSigColorantTableType,        
cmsSigNamedColor2Type,          
cmsSigMultiLocalizedUnicodeType,
cmsSigProfileSequenceDescType,  
cmsSigSignatureType,            
cmsSigMeasurementType,          
cmsSigDataType,                 
cmsSigLutAtoBType,              
cmsSigLutBtoAType,              
cmsSigUcrBgType,                
cmsSigCrdInfoType,              
cmsSigMultiProcessElementType,  
cmsSigScreeningType,            
cmsSigViewingConditionsType,    
cmsSigXYZType,                  
cmsCorbisBrokenXYZtype,         
cmsMonacoBrokenCurveType,       
cmsSigProfileSequenceIdType,    
cmsSigDictType,                 
cmsSigcicpType,                 
cmsSigVcgtType,                 
cmsSigMHC2Type,         

The type you are trying to use is not used by any tag in the ICC spec, so I didn't add it as built-in. You can implement it by using the type plug-in or re-use any other, like cmsSigU16Fixed16ArrayType, for example.

DominikDeak commented 1 month ago

it happens that only certain types (those already used by ICC spec) are implemented by default. Others are not.

I see, that makes more sense, thanks for clarifying. I was under the assumption that LCMS implemented all the ICC tag types internally. I can certainly work around the issue by specifying a custom tag type and then implementing read/write plugin for that.

I'm not sure how you feel about this, but perhaps listing the default implemented tag types in the Plug-in API documentation might be valuable reference for others like me in the future.

mm2 commented 1 month ago

FYI, in 059ebcfb3a7feca2c92bd800677ccb898ab25895 I have added handles for those types that, despite described in ICC spec, are not used by any tag. That would completely solve the issue.

DominikDeak commented 1 month ago

Fantastic! Thank you so much for implementing this.