Commit 8cb2a8ebb for imagemagick.org

commit 8cb2a8ebbe3a8cc6dc4e5475ca54fa23e495c091
Author: Dirk Lemstra <dirk@lemstra.org>
Date:   Wed Apr 8 06:34:13 2026 +0200

    Added support for writing meta channels to the PSD coder (#8393)

diff --git a/coders/psd.c b/coders/psd.c
index d95be0dee..7733ac0ca 100644
--- a/coders/psd.c
+++ b/coders/psd.c
@@ -3059,9 +3059,10 @@ static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,

 static size_t WritePSDChannel(const PSDInfo *psd_info,
   const ImageInfo *image_info,Image *image,Image *layer,
-  const QuantumType quantum_type, unsigned char *compact_pixels,
-  MagickOffsetType size_offset,const MagickBooleanType separate,
-  const CompressionType compression,ExceptionInfo *exception)
+  const QuantumType quantum_type,const ssize_t meta_channel,
+  unsigned char *compact_pixels,MagickOffsetType size_offset,
+  const MagickBooleanType separate,const CompressionType compression,
+  ExceptionInfo *exception)
 {
   const Quantum
     *p;
@@ -3112,6 +3113,8 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
   quantum_info=AcquireQuantumInfo(image_info,layer);
   if (quantum_info == (QuantumInfo *) NULL)
     return(0);
+  if (quantum_type == MultispectralQuantum)
+    (void) SetQuantumMetaChannel(layer,quantum_info,meta_channel);
   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
 #ifdef MAGICKCORE_ZLIB_DELEGATE
   if (compression == ZipCompression)
@@ -3253,7 +3256,10 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
             channels=(size_t) (layer->colorspace == CMYKColorspace ? 4 :
               3);
           if (layer->alpha_trait != UndefinedPixelTrait)
-            channels++;
+            {
+              channels++;
+              channels+=layer->number_meta_channels;
+            }
         }
       rows_offset=TellBlob(image)+2;
       total_length+=WriteCompressionStart(psd_info,image,layer,compression,
@@ -3265,7 +3271,7 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
       (IsImageGray(layer) == MagickFalse))
     {
       length=WritePSDChannel(psd_info,image_info,image,layer,
-        IndexQuantum,compact_pixels,rows_offset,separate,compression,
+        IndexQuantum,-1,compact_pixels,rows_offset,separate,compression,
         exception);
       if (separate != MagickFalse)
         size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
@@ -3278,7 +3284,7 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
       if (IsImageGray(layer) != MagickFalse)
         {
           length=WritePSDChannel(psd_info,image_info,image,layer,
-            GrayQuantum,compact_pixels,rows_offset,separate,compression,
+            GrayQuantum,-1,compact_pixels,rows_offset,separate,compression,
             exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
@@ -3292,7 +3298,7 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
             (void) NegateCMYK(layer,exception);

           length=WritePSDChannel(psd_info,image_info,image,layer,
-            RedQuantum,compact_pixels,rows_offset,separate,compression,
+            RedQuantum,-1,compact_pixels,rows_offset,separate,compression,
             exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
@@ -3301,7 +3307,7 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           total_length+=length;

           length=WritePSDChannel(psd_info,image_info,image,layer,
-            GreenQuantum,compact_pixels,rows_offset,separate,compression,
+            GreenQuantum,-1,compact_pixels,rows_offset,separate,compression,
             exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
@@ -3310,7 +3316,7 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           total_length+=length;

           length=WritePSDChannel(psd_info,image_info,image,layer,
-            BlueQuantum,compact_pixels,rows_offset,separate,compression,
+            BlueQuantum,-1,compact_pixels,rows_offset,separate,compression,
             exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
@@ -3321,8 +3327,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           if (layer->colorspace == CMYKColorspace)
             {
               length=WritePSDChannel(psd_info,image_info,image,layer,
-                BlackQuantum,compact_pixels,rows_offset,separate,compression,
-                exception);
+                BlackQuantum,-1,compact_pixels,rows_offset,separate,
+                compression,exception);
               if (separate != MagickFalse)
                 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
               else
@@ -3332,14 +3338,29 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
         }
       if (layer->alpha_trait != UndefinedPixelTrait)
         {
+          ssize_t
+            i;
+
           length=WritePSDChannel(psd_info,image_info,image,layer,
-            AlphaQuantum,compact_pixels,rows_offset,separate,compression,
+            AlphaQuantum,-1,compact_pixels,rows_offset,separate,compression,
             exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
             rows_offset+=(MagickOffsetType) offset_length;
           total_length+=length;
+
+          for (i=0; i < (ssize_t) layer->number_meta_channels; i++)
+          {
+            length=WritePSDChannel(psd_info,image_info,image,layer,
+              MultispectralQuantum,i,compact_pixels,rows_offset,separate,
+              compression,exception);
+            if (separate != MagickFalse)
+              size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+            else
+              rows_offset+=(MagickOffsetType) offset_length;
+            total_length+=length;
+          }
         }
     }
   compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
@@ -3364,8 +3385,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
                     return(0);
                 }
               length=WritePSDChannel(psd_info,image_info,image,mask,
-                RedQuantum,compact_pixels,rows_offset,MagickTrue,compression,
-                exception);
+                RedQuantum,-1,compact_pixels,rows_offset,MagickTrue,
+                compression,exception);
               (void) WritePSDSize(psd_info,image,length,size_offset);
               total_length+=length;
               compact_pixels=(unsigned char *) RelinquishMagickMemory(
@@ -3752,7 +3773,10 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
         3);
     total_channels=channels;
     if (frame->alpha_trait != UndefinedPixelTrait)
-      total_channels++;
+      {
+        total_channels++;
+        total_channels+=(unsigned short) frame->number_meta_channels;
+      }
     if (mask != (Image *) NULL)
       total_channels++;
     size+=(size_t) WriteBlobShort(image,total_channels);
@@ -3760,7 +3784,12 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
     for (i=0; i < (ssize_t) channels; i++)
       size+=(size_t) WriteChannelSize(psd_info,image,(signed short) i);
     if (frame->alpha_trait != UndefinedPixelTrait)
-      size+=(size_t) WriteChannelSize(psd_info,image,-1);
+      {
+        size+=(size_t) WriteChannelSize(psd_info,image,-1);
+        for (i=0; i < (ssize_t) frame->number_meta_channels; i++)
+          size+=(size_t) WriteChannelSize(psd_info,image,
+            (signed short) (channels+1+i));
+      }
     if (mask != (Image *) NULL)
       size+=(size_t) WriteChannelSize(psd_info,image,-2);
     size+=(size_t) WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :
@@ -3930,21 +3959,23 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
     (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
   if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
       (SetImageGray(image,exception) != MagickFalse))
-    num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
+    num_channels=1;
   else
     if ((image_info->type != TrueColorType) &&
         (image_info->type != TrueColorAlphaType) &&
         (image->storage_class == PseudoClass))
-      num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
+      num_channels=1;
     else
       {
         if (image->storage_class == PseudoClass)
           (void) SetImageStorageClass(image,DirectClass,exception);
-        if (image->colorspace != CMYKColorspace)
-          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
-        else
-          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
+        num_channels=image->colorspace == CMYKColorspace ? 4 : 3;
       }
+  if (image->alpha_trait != UndefinedPixelTrait)
+    {
+      num_channels++;
+      num_channels+=image->number_meta_channels;
+    }
   (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
   (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
   (void) WriteBlobMSBLong(image,(unsigned int) image->columns);