]> granicus.if.org Git - imagemagick/commitdiff
Some of the additional layer information will be preserved when converting from PSD...
authordirk <dirk@git.imagemagick.org>
Mon, 22 Aug 2016 21:30:07 +0000 (23:30 +0200)
committerdirk <dirk@git.imagemagick.org>
Mon, 22 Aug 2016 21:30:34 +0000 (23:30 +0200)
coders/psd.c

index 2a9d6a776d6cf0360077abfb1dba67c6f0c89a38..9879dd9ed3647015eb51e62833467cacb3a447c2 100644 (file)
@@ -84,6 +84,7 @@
 */
 #define MaxPSDChannels  56
 #define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
+#define PSDAdditionalInfo "PSDInfo"
 \f
 /*
   Enumerated declaractions.
@@ -165,6 +166,9 @@ typedef struct _LayerInfo
 
   unsigned short
     channels;
+
+  StringInfo
+    *info;
 } LayerInfo;
 
 /*
@@ -544,6 +548,8 @@ static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
       layer_info[i].image=DestroyImage(layer_info[i].image);
     if (layer_info[i].mask.image != (Image *) NULL)
       layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
+    if (layer_info[i].info != (StringInfo *) NULL)
+      layer_info[i].info=DestroyStringInfo(layer_info[i].info);
   }
 
   return (LayerInfo *) RelinquishMagickMemory(layer_info);
@@ -1557,7 +1563,7 @@ ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
                 /*
                   We read it, but don't use it...
                 */
-                for (j=0; j < (ssize_t) (length); j+=8)
+                for (j=0; j < (ssize_t) length; j+=8)
                 {
                   size_t blend_source=ReadBlobLong(image);
                   size_t blend_dest=ReadBlobLong(image);
@@ -1570,7 +1576,7 @@ ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
             /*
               Layer name.
             */
-            length=(size_t) ReadBlobByte(image);
+            length=(MagickSizeType) ReadBlobByte(image);
             combined_length+=length+1;
             if (length > 0)
               (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
@@ -1578,19 +1584,25 @@ ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
             if (image->debug != MagickFalse)
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                 "      layer name: %s",layer_info[i].name);
-            /*
-               Skip the rest of the variable data until we support it.
-            */
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "      unsupported data: length=%.20g",(double)
-                ((MagickOffsetType) (size-combined_length)));
-            if (DiscardBlobBytes(image,(MagickSizeType) (size-combined_length)) == MagickFalse)
+            length=(length+(4-(length % 4)))-length;
+            combined_length+=length;
+            /* Skip over the padding of the layer name */
+            if (DiscardBlobBytes(image,length) == MagickFalse)
               {
                 layer_info=DestroyLayerInfo(layer_info,number_layers);
                 ThrowBinaryException(CorruptImageError,
                   "UnexpectedEndOfFile",image->filename);
               }
+            length=(MagickSizeType) size-combined_length;
+            if (length > 0)
+              {
+                unsigned char
+                  *info;
+
+                layer_info[i].info=AcquireStringInfo((const size_t) length);
+                info=GetStringInfoDatum(layer_info[i].info);
+                (void) ReadBlob(image,(const size_t) length,info);
+              }
           }
       }
 
@@ -1619,6 +1631,13 @@ ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
             ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
               image->filename);
           }
+
+        if (layer_info[i].info != (StringInfo *) NULL)
+          {
+            (void) SetImageProfile(layer_info[i].image,PSDAdditionalInfo,
+              layer_info[i].info,exception);
+            layer_info[i].info=DestroyStringInfo(layer_info[i].info);
+          }
       }
 
       if (image_info->ping == MagickFalse)
@@ -2634,14 +2653,109 @@ static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
   }
 }
 
+static const StringInfo *FilterAdditionalLayerInformation(Image *image,
+  ExceptionInfo *exception)
+{
+#define PSDKeySize 5
+#define PSDAllowedLength 36
+
+  char
+    key[PSDKeySize];
+
+  /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
+  const char
+    allowed[PSDAllowedLength][PSDKeySize] = {
+      "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
+      "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
+      "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
+      "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
+    };
+
+  const StringInfo
+    *info;
+
+  MagickBooleanType
+    found;
+
+  register size_t
+    i;
+
+  size_t
+    remaining_length,
+    length;
+
+  StringInfo
+    *profile;
+
+  unsigned char
+    *p;
+
+  unsigned int
+    size;
+
+  info=GetImageProfile(image,PSDAdditionalInfo);
+  if (info == (const StringInfo *) NULL)
+    return((const StringInfo *) NULL);
+  length=GetStringInfoLength(info);
+  p=GetStringInfoDatum(info);
+  remaining_length=length;
+  length=0;
+  while (remaining_length >= 12)
+  {
+    /* skip over signature */
+    p+=4;
+    key[0]=(*p++);
+    key[1]=(*p++);
+    key[2]=(*p++);
+    key[3]=(*p++);
+    key[4]='\0';
+    size=(unsigned int) (*p++) << 24;
+    size|=(unsigned int) (*p++) << 16;
+    size|=(unsigned int) (*p++) << 8;
+    size|=(unsigned int) (*p++);
+    size=size & 0xffffffff;
+    remaining_length-=12;
+    if ((size_t) size > remaining_length)
+      return((const StringInfo *) NULL);
+    found=MagickFalse;
+    for (i=0; i < PSDAllowedLength; i++)
+    {
+      if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
+        continue;
+
+      found=MagickTrue;
+      break;
+    }
+    remaining_length-=(size_t) size;
+    if (found == MagickFalse)
+    {
+      if (remaining_length > 0)
+        p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
+      continue;
+    }
+    length+=(size_t) size+12;
+    p+=size;
+  }
+  profile=RemoveImageProfile(image,PSDAdditionalInfo);
+  if (length == 0)
+    return(DestroyStringInfo(profile));
+  SetStringInfoLength(profile,(const size_t) length);
+  SetImageProfile(image,PSDAdditionalInfo,info,exception);
+  return(profile);
+}
+
 static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
   Image *image,ExceptionInfo *exception)
 {
+  char
+    layer_name[MagickPathExtent];
+
   const char
     *property;
 
   const StringInfo
-    *icc_profile;
+    *icc_profile,
+    *info;
 
   Image
     *base_image,
@@ -2662,6 +2776,7 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
     layer_count,
     layer_info_size,
     length,
+    name_length,
     num_channels,
     packet_size,
     rounded_layer_info_size;
@@ -2840,6 +2955,9 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
         layer_length=strlen(property);
         layer_info_size+=8+layer_length+(4-(layer_length % 4));
       }
+    info=FilterAdditionalLayerInformation(next_image,exception);
+    if (info != (const StringInfo *) NULL)
+      layer_info_size+=GetStringInfoLength(info);
     layer_count++;
     next_image=GetNextImageInList(next_image);
   }
@@ -2931,31 +3049,24 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
         (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
           1 << 0x02 : 1); /* layer properties - visible, etc. */
         (void) WriteBlobByte(image,0);
+        info=GetImageProfile(next_image,PSDAdditionalInfo);
         property=(const char *) GetImageProperty(next_image,"label",exception);
         if (property == (const char *) NULL)
           {
-            char
-              layer_name[MagickPathExtent];
-
-            (void) WriteBlobMSBLong(image,16);
-            (void) WriteBlobMSBLong(image,0);
-            (void) WriteBlobMSBLong(image,0);
-            (void) FormatLocaleString(layer_name,MagickPathExtent,"L%04ld",(long)
-              layer_count++);
-            WritePascalString(image,layer_name,4);
-          }
-        else
-          {
-            size_t
-              label_length;
-
-            label_length=strlen(property);
-            (void) WriteBlobMSBLong(image,(unsigned int) (label_length+(4-
-              (label_length % 4))+8));
-            (void) WriteBlobMSBLong(image,0);
-            (void) WriteBlobMSBLong(image,0);
-            WritePascalString(image,property,4);
+            (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
+              (double) layer_count++);
+            property=layer_name;
           }
+        name_length=strlen(property);
+        name_length+=(4-(name_length % 4));
+        if (info != (const StringInfo *) NULL)
+          name_length+=GetStringInfoLength(info);
+        (void) WriteBlobMSBLong(image,(unsigned int)name_length+8);
+        (void) WriteBlobMSBLong(image,0);
+        (void) WriteBlobMSBLong(image,0);
+        WritePascalString(image,property,4);
+        if (info != (const StringInfo *) NULL)
+          (void) WriteBlob(image,GetStringInfoLength(info),GetStringInfoDatum(info));
         next_image=GetNextImageInList(next_image);
       }
       /*