]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/profile.c
(no commit message)
[imagemagick] / MagickCore / profile.c
index c78d85452f7d17654fbb6e3c9ede9d76cf91a79f..304dee0099e269882db04fa37135fcec61af128e 100644 (file)
 %                       MagickCore Image Profile Methods                      %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -163,8 +163,12 @@ MagickExport MagickBooleanType CloneImageProfiles(Image *image,
   assert(clone_image != (const Image *) NULL);
   assert(clone_image->signature == MagickSignature);
   if (clone_image->profiles != (void *) NULL)
-    image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
-      (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
+    {
+      if (image->profiles != (void *) NULL)
+        DestroyImageProfiles(image);
+      image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
+        (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
+    }
   return(MagickTrue);
 }
 \f
@@ -428,8 +432,8 @@ static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
   (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
   for (i=0; i < (ssize_t) number_threads; i++)
   {
-    transform[i]=cmsCreateTransformTHR(image,source_profile,source_type,
-      target_profile,target_type,intent,flags);
+    transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
+      source_type,target_profile,target_type,intent,flags);
     if (transform[i] == (cmsHTRANSFORM) NULL)
       return(DestroyTransformThreadSet(transform));
   }
@@ -457,14 +461,14 @@ static void CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
   if (image == (Image *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
-        "UnableToTransformColorspace","'%s'","unknown context");
+        "UnableToTransformColorspace","`%s'","unknown context");
       return;
     }
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
       severity,message != (char *) NULL ? message : "no message");
   (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
-    "UnableToTransformColorspace","'%s'",image->filename);
+    "UnableToTransformColorspace","`%s'",image->filename);
 }
 #else
 static int CMSExceptionHandler(int severity,const char *message)
@@ -601,7 +605,7 @@ MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
         cms_exception.image=image;
         cms_exception.exception=exception;
         (void) cms_exception;
-        source_profile=cmsOpenProfileFromMemTHR(&cms_exception,
+        source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
           GetStringInfoDatum(profile),(cmsUInt32Number)
           GetStringInfoLength(profile));
         if (source_profile == (cmsHPROFILE) NULL)
@@ -657,9 +661,9 @@ MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
             if (icc_profile != (StringInfo *) NULL)
               {
                 target_profile=source_profile;
-                source_profile=cmsOpenProfileFromMemTHR(&cms_exception,
-                  GetStringInfoDatum(icc_profile),(cmsUInt32Number)
-                  GetStringInfoLength(icc_profile));
+                source_profile=cmsOpenProfileFromMemTHR((cmsContext)
+                  &cms_exception,GetStringInfoDatum(icc_profile),
+                  (cmsUInt32Number) GetStringInfoLength(icc_profile));
                 if (source_profile == (cmsHPROFILE) NULL)
                   ThrowProfileException(ResourceLimitError,
                     "ColorspaceColorProfileMismatch",name);
@@ -860,7 +864,7 @@ MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
             image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
             #pragma omp parallel for schedule(static,4) shared(status) \
-              dynamic_number_threads(image,image->columns,image->rows,1)
+              magick_threads(image,image,image->rows,1)
 #endif
             for (y=0; y < (ssize_t) image->rows; y++)
             {
@@ -949,20 +953,20 @@ MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
             {
               case cmsSigRgbData:
               {
-                image->type=image->alpha_trait != BlendPixelTrait ? TrueColorType :
-                  TrueColorMatteType;
+                image->type=image->alpha_trait != BlendPixelTrait ?
+                  TrueColorType : TrueColorMatteType;
                 break;
               }
               case cmsSigCmykData:
               {
-                image->type=image->alpha_trait != BlendPixelTrait ? ColorSeparationType :
-                  ColorSeparationMatteType;
+                image->type=image->alpha_trait != BlendPixelTrait ?
+                  ColorSeparationType : ColorSeparationMatteType;
                 break;
               }
               case cmsSigGrayData:
               {
-                image->type=image->alpha_trait != BlendPixelTrait ? GrayscaleType :
-                  GrayscaleMatteType;
+                image->type=image->alpha_trait != BlendPixelTrait ?
+                  GrayscaleType : GrayscaleMatteType;
                 break;
               }
               default:
@@ -1115,7 +1119,7 @@ static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
 }
 
 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
-  size_t *quantum)
+  unsigned int *quantum)
 {
   *quantum=(size_t) (*p++ << 24);
   *quantum|=(size_t) (*p++ << 16);
@@ -1144,14 +1148,17 @@ static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
   size_t
     length;
 
+  ssize_t
+    count;
+
   StringInfo
     *profile;
 
   unsigned char
     length_byte;
 
-  size_t
-    count;
+   unsigned int
+     value;
 
   unsigned short
     id;
@@ -1170,23 +1177,39 @@ static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
       p++;
     if (p > (datum+length-4))
       break;
-    p=ReadResourceLong(p,&count);
+    p=ReadResourceLong(p,&value);
+    count=(ssize_t) value;
     if ((p > (datum+length-count)) || (count > length))
       break;
     switch (id)
     {
       case 0x03ed:
       {
-        unsigned short
+        unsigned int
           resolution;
 
+        unsigned short
+          units;
+
         /*
           Resolution.
         */
-        p=ReadResourceShort(p,&resolution)+6;
-        image->resolution.x=(double) resolution;
-        p=ReadResourceShort(p,&resolution)+6;
-        image->resolution.y=(double) resolution;
+        p=ReadResourceLong(p,&resolution);
+        image->resolution.x=((double) resolution)/65536.0;
+        p=ReadResourceShort(p,&units)+2;
+        p=ReadResourceLong(p,&resolution)+4;
+        image->resolution.y=((double) resolution)/65536.0;
+        /*
+          Values are always stored as pixels per inch.
+        */
+        if ((ResolutionType) units != PixelsPerCentimeterResolution)
+          image->units=PixelsPerInchResolution;
+        else
+          {
+            image->units=PixelsPerCentimeterResolution;
+            image->resolution.x/=2.54;
+            image->resolution.y/=2.54;
+          }
         break;
       }
       case 0x0404:
@@ -1283,7 +1306,7 @@ MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
   /*
     Inject profile into image properties.
   */
-  (void) FormatLocaleString(property,MaxTextExtent,"%s:sans",name);
+  (void) FormatLocaleString(property,MaxTextExtent,"%s:*",name);
   (void) GetImageProperty(image,property,exception);
   return(status);
 }
@@ -1357,6 +1380,36 @@ static inline size_t ReadProfileLong(const EndianType endian,
   return((size_t) (value & 0xffffffff));
 }
 
+static inline size_t ReadProfileMSBLong(unsigned char **p,
+  size_t *length)
+{
+  size_t
+    value;
+
+  if (*length < 4)
+    return(0);
+
+  value=ReadProfileLong(MSBEndian,*p);
+  (*length)-=4;
+  *p+=4;
+  return(value);
+}
+
+static inline unsigned short ReadProfileMSBShort(unsigned char **p,
+  size_t *length)
+{
+  unsigned short
+    value;
+
+  if (*length < 2)
+    return(0);
+
+  value=ReadProfileShort(MSBEndian,*p);
+  (*length)-=2;
+  *p+=2;
+  return(value);
+}
+
 static inline void WriteProfileLong(const EndianType endian,
   const size_t value,unsigned char *p)
 {
@@ -1397,7 +1450,66 @@ static void WriteProfileShort(const EndianType endian,
   (void) CopyMagickMemory(p,buffer,2);
 }
 
-MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
+static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
+{
+  size_t
+    count,
+    length;
+
+  unsigned char
+    *p;
+
+  unsigned short
+    id;
+
+  length=GetStringInfoLength(profile);
+  p=GetStringInfoDatum(profile);
+  while(length != 0)
+  {
+    if (ReadProfileByte(&p,&length) != 0x38)
+      continue;
+    if (ReadProfileByte(&p,&length) != 0x42)
+      continue;
+    if (ReadProfileByte(&p,&length) != 0x49)
+      continue;
+    if (ReadProfileByte(&p,&length) != 0x4D)
+      continue;
+    if (length < 7)
+      return(MagickFalse);
+    id=ReadProfileMSBShort(&p,&length);
+    count=ReadProfileByte(&p,&length);
+    if (count > length)
+      return(MagickFalse);
+    p+=count;
+    if ((*p & 0x01) == 0)
+      p++;
+    count=ReadProfileMSBLong(&p,&length);
+    if (count > length)
+      return(MagickFalse);
+    if (id == 0x3ED && count == 16)
+      {
+        if (image->units == PixelsPerCentimeterResolution)
+          WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*2.54*
+            65536.0),p);
+        else
+          WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*
+            65536.0),p);
+        WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
+        if (image->units == PixelsPerCentimeterResolution)
+          WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*2.54*
+            65536.0),p+8);
+        else
+          WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*
+            65536.0),p+8);
+        WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
+      }
+    p+=count;
+    length-=count;
+  }
+  return(MagickTrue);
+}
+
+MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
 {
 #define MaxDirectoryStack  16
 #define EXIF_DELIMITER  "\n"
@@ -1433,9 +1545,6 @@ MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
   static int
     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
 
-  StringInfo
-    *profile;
-
   unsigned char
     *directory,
     *exif;
@@ -1443,30 +1552,33 @@ MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
   /*
     Set EXIF resolution tag.
   */
-  profile=(StringInfo *) GetImageProfile(image,"EXIF");
-  if (profile == (StringInfo *) NULL)
-    return(MagickTrue);
   length=GetStringInfoLength(profile);
   exif=GetStringInfoDatum(profile);
-  while (length != 0)
-  {
-    if (ReadProfileByte(&exif,&length) != 0x45)
-      continue;
-    if (ReadProfileByte(&exif,&length) != 0x78)
-      continue;
-    if (ReadProfileByte(&exif,&length) != 0x69)
-      continue;
-    if (ReadProfileByte(&exif,&length) != 0x66)
-      continue;
-    if (ReadProfileByte(&exif,&length) != 0x00)
-      continue;
-    if (ReadProfileByte(&exif,&length) != 0x00)
-      continue;
-    break;
-  }
   if (length < 16)
     return(MagickFalse);
   id=(ssize_t) ReadProfileShort(LSBEndian,exif);
+  if ((id != 0x4949) && (id != 0x4D4D))
+    {
+      while (length != 0)
+      {
+        if (ReadProfileByte(&exif,&length) != 0x45)
+          continue;
+        if (ReadProfileByte(&exif,&length) != 0x78)
+          continue;
+        if (ReadProfileByte(&exif,&length) != 0x69)
+          continue;
+        if (ReadProfileByte(&exif,&length) != 0x66)
+          continue;
+        if (ReadProfileByte(&exif,&length) != 0x00)
+          continue;
+        if (ReadProfileByte(&exif,&length) != 0x00)
+          continue;
+        break;
+      }
+      if (length < 16)
+        return(MagickFalse);
+      id=(ssize_t) ReadProfileShort(LSBEndian,exif);
+    }
   endian=LSBEndian;
   if (id == 0x4949)
     endian=LSBEndian;
@@ -1611,3 +1723,23 @@ MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
   } while (level > 0);
   return(MagickTrue);
 }
+
+MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
+{
+  MagickBooleanType
+    status;
+
+  StringInfo
+    *profile;
+
+  status=MagickTrue;
+  profile=(StringInfo *) GetImageProfile(image,"8BIM");
+  if (profile != (StringInfo *) NULL)
+    if (Sync8BimProfile(image,profile) == MagickFalse)
+      status=MagickFalse;
+  profile=(StringInfo *) GetImageProfile(image,"EXIF");
+  if (profile != (StringInfo *) NULL)
+    if (SyncExifProfile(image,profile) == MagickFalse)
+      status=MagickFalse;
+  return(status);
+}