]> granicus.if.org Git - imagemagick/blobdiff - coders/exr.c
Removed png_write_chunk_from_profile()
[imagemagick] / coders / exr.c
index 1d960e1ef0ac2faa63b59e02937111802e15565d..43cb142b09c19870e901f1206dcd8cc1c030bfe9 100644 (file)
 %            Read/Write High Dynamic-Range (HDR) Image File Format            %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 April 2007                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2017 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  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -50,6 +50,7 @@
 #include "MagickCore/list.h"
 #include "MagickCore/magick.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/property.h"
 #include "MagickCore/quantum-private.h"
 #if defined(MAGICKCORE_OPENEXR_DELEGATE)
 #include <ImfCRgbaFile.h>
 \f
+/*
+  Typedef declaractions.
+*/
+typedef struct _ExrWindow
+{
+  int
+    max_x,
+    max_y,
+    min_x,
+    min_y;
+} ExrWindow;
+
 /*
   Forward declarations.
 */
@@ -131,6 +144,10 @@ static MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
 */
 static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
 {
+  ExrWindow
+    data_window,
+    display_window;
+
   const ImfHeader
     *hdr_info;
 
@@ -146,12 +163,6 @@ static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
   ImfRgba
     *scanline;
 
-  int
-    max_x,
-    max_y,
-    min_x,
-    min_y;
-
   MagickBooleanType
     status;
 
@@ -162,18 +173,19 @@ static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
     *q;
 
   ssize_t
+    columns,
     y;
 
   /*
     Open image.
   */
   assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
+  assert(image_info->signature == MagickCoreSignature);
   if (image_info->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
       image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   image=AcquireImage(image_info,exception);
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
@@ -192,14 +204,20 @@ static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
     {
       ThrowFileException(exception,BlobError,"UnableToOpenBlob",
         ImfErrorMessage());
+      if (LocaleCompare(image_info->filename,read_info->filename) != 0)
+        (void) RelinquishUniqueFileResource(read_info->filename);
       read_info=DestroyImageInfo(read_info);
+      image=DestroyImageList(image);
       return((Image *) NULL);
     }
   hdr_info=ImfInputHeader(file);
-  ImfHeaderDataWindow(hdr_info,&min_x,&min_y,&max_x,&max_y);
-  image->columns=max_x-min_x+1UL;
-  image->rows=max_y-min_y+1UL;
-  image->matte=MagickTrue;
+  ImfHeaderDisplayWindow(hdr_info,&display_window.min_x,&display_window.min_y,
+    &display_window.max_x,&display_window.max_y);
+  image->columns=display_window.max_x-display_window.min_x+1UL;
+  image->rows=display_window.max_y-display_window.min_y+1UL;
+  image->alpha_trait=BlendPixelTrait;
+  SetImageColorspace(image,RGBColorspace,exception);
+  image->gamma=1.0;
   if (image_info->ping != MagickFalse)
     {
       (void) ImfCloseInputFile(file);
@@ -209,30 +227,70 @@ static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
       (void) CloseBlob(image);
       return(GetFirstImageInList(image));
     }
-  scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
-  if (scanline == (ImfRgba *) NULL)
+  status=SetImageExtent(image,image->columns,image->rows,exception);
+  if (status == MagickFalse)
+    return(DestroyImageList(image));
+  ImfHeaderDataWindow(hdr_info,&data_window.min_x,&data_window.min_y,
+    &data_window.max_x,&data_window.max_y);
+  columns=(ssize_t) data_window.max_x-data_window.min_x+1UL;
+  if ((display_window.min_x > data_window.max_x) ||
+      (display_window.min_x+(int) image->columns <= data_window.min_x))
+    scanline=(ImfRgba *) NULL;
+  else
     {
-      (void) ImfCloseInputFile(file);
-      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+      scanline=(ImfRgba *) AcquireQuantumMemory(columns,sizeof(*scanline));
+      if (scanline == (ImfRgba *) NULL)
+        {
+          (void) ImfCloseInputFile(file);
+          if (LocaleCompare(image_info->filename,read_info->filename) != 0)
+            (void) RelinquishUniqueFileResource(read_info->filename);
+          read_info=DestroyImageInfo(read_info);
+          image=DestroyImageList(image);
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        }
     }
   for (y=0; y < (ssize_t) image->rows; y++)
   {
+    int
+      yy;
+
     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
     if (q == (Quantum *) NULL)
       break;
-    ImfInputSetFrameBuffer(file,scanline-min_x-image->columns*(min_y+y),1,
-      image->columns);
-    ImfInputReadPixels(file,min_y+y,min_y+y);
+    yy=display_window.min_y+y;
+    if ((yy < data_window.min_y) || (yy > data_window.max_y) ||
+        (scanline == (ImfRgba *) NULL))
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelViaPixelInfo(image,&image->background_color,q);
+          q+=GetPixelChannels(image);
+        }
+        continue;
+      }
+    ResetMagickMemory(scanline,0,columns*sizeof(*scanline));
+    ImfInputSetFrameBuffer(file,scanline-data_window.min_x-columns*yy,1,
+      columns);
+    ImfInputReadPixels(file,yy,yy);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
-        ImfHalfToFloat(scanline[x].r)),q);
-      SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
-        ImfHalfToFloat(scanline[x].g)),q);
-      SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
-        ImfHalfToFloat(scanline[x].b)),q);
-      SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
-        ImfHalfToFloat(scanline[x].a)),q);
+      int
+        xx;
+
+      xx=display_window.min_x+((int) x-data_window.min_x);
+      if ((xx < 0) || (display_window.min_x+(int) x > data_window.max_x))
+        SetPixelViaPixelInfo(image,&image->background_color,q);
+      else
+        {
+          SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+            ImfHalfToFloat(scanline[xx].r)),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+            ImfHalfToFloat(scanline[xx].g)),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+            ImfHalfToFloat(scanline[xx].b)),q);
+          SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
+            ImfHalfToFloat(scanline[xx].a)),q);
+        }
       q+=GetPixelChannels(image);
     }
     if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -276,16 +334,14 @@ ModuleExport size_t RegisterEXRImage(void)
   MagickInfo
     *entry;
 
-  entry=SetMagickInfo("EXR");
+  entry=AcquireMagickInfo("EXR","EXR","High Dynamic-range (HDR)");
 #if defined(MAGICKCORE_OPENEXR_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadEXRImage;
   entry->encoder=(EncodeImageHandler *) WriteEXRImage;
 #endif
   entry->magick=(IsImageFormatHandler *) IsEXR;
-  entry->adjoin=MagickFalse;
-  entry->description=ConstantString("High Dynamic-range (HDR)");
-  entry->blob_support=MagickFalse;
-  entry->module=ConstantString("EXR");
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags^=CoderBlobSupportFlag;
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
@@ -346,6 +402,10 @@ ModuleExport void UnregisterEXRImage(void)
 static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
   ExceptionInfo *exception)
 {
+  const char
+    *sampling_factor,
+    *value;
+
   ImageInfo
     *write_info;
 
@@ -362,7 +422,9 @@ static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
     *scanline;
 
   int
-    compression;
+    channels,
+    compression,
+    factors[3];
 
   MagickBooleanType
     status;
@@ -380,16 +442,17 @@ static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
     Open output image file.
   */
   assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
+  assert(image_info->signature == MagickCoreSignature);
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
+  (void) SetImageColorspace(image,RGBColorspace,exception);
   write_info=CloneImageInfo(image_info);
   (void) AcquireUniqueFilename(write_info->filename);
   hdr_info=ImfNewHeader();
@@ -414,23 +477,106 @@ static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
   if (write_info->compression == B44ACompression)
     compression=IMF_B44A_COMPRESSION;
 #endif
+  channels=0;
+  value=GetImageOption(image_info,"exr:color-type");
+  if (value != (const char *) NULL)
+    {
+      if (LocaleCompare(value,"RGB") == 0)
+        channels=IMF_WRITE_RGB;
+      else if (LocaleCompare(value,"RGBA") == 0)
+        channels=IMF_WRITE_RGBA;
+      else if (LocaleCompare(value,"YC") == 0)
+        channels=IMF_WRITE_YC;
+      else if (LocaleCompare(value,"YCA") == 0)
+        channels=IMF_WRITE_YCA;
+      else if (LocaleCompare(value,"Y") == 0)
+        channels=IMF_WRITE_Y;
+      else if (LocaleCompare(value,"YA") == 0)
+        channels=IMF_WRITE_YA;
+      else if (LocaleCompare(value,"R") == 0)
+        channels=IMF_WRITE_R;
+      else if (LocaleCompare(value,"G") == 0)
+        channels=IMF_WRITE_G;
+      else if (LocaleCompare(value,"B") == 0)
+        channels=IMF_WRITE_B;
+      else if (LocaleCompare(value,"A") == 0)
+        channels=IMF_WRITE_A;
+      else
+        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
+          "ignoring invalid defined exr:color-type","=%s",value);
+   }
+  sampling_factor=(const char *) NULL;
+  factors[0]=0;
+  if (image_info->sampling_factor != (char *) NULL)
+    sampling_factor=image_info->sampling_factor;
+  if (sampling_factor != NULL)
+    {
+      /*
+        Sampling factors, valid values are 1x1 or 2x2.
+      */
+      if (sscanf(sampling_factor,"%d:%d:%d",factors,factors+1,factors+2) == 3)
+        {
+          if ((factors[0] == factors[1]) && (factors[1] == factors[2]))
+            factors[0]=1;
+          else
+            if ((factors[0] == (2*factors[1])) && (factors[2] == 0))
+              factors[0]=2;
+        }
+      else
+        if (sscanf(sampling_factor,"%dx%d",factors,factors+1) == 2)
+          {
+            if (factors[0] != factors[1])
+              factors[0]=0;
+          }
+      if ((factors[0] != 1) && (factors[0] != 2))
+        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
+          "ignoring sampling-factor","=%s",sampling_factor);
+      else if (channels != 0)
+        {
+          /*
+            Cross check given color type and subsampling.
+          */
+          factors[1]=((channels == IMF_WRITE_YCA) ||
+            (channels == IMF_WRITE_YC)) ? 2 : 1;
+          if (factors[0] != factors[1])
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              CoderWarning,"sampling-factor and color type mismatch","=%s",
+              sampling_factor);
+        }
+    }
+  if (channels == 0)
+    {
+      /*
+        If no color type given, select it now.
+      */
+      if (factors[0] == 2)
+        channels=image->alpha_trait != UndefinedPixelTrait ? IMF_WRITE_YCA :
+          IMF_WRITE_YC;
+      else
+        channels=image->alpha_trait != UndefinedPixelTrait ? IMF_WRITE_RGBA :
+          IMF_WRITE_RGB;
+    }
   ImfHeaderSetCompression(hdr_info,compression);
   ImfHeaderSetLineOrder(hdr_info,IMF_INCREASING_Y);
-  file=ImfOpenOutputFile(write_info->filename,hdr_info,IMF_WRITE_RGBA);
+  file=ImfOpenOutputFile(write_info->filename,hdr_info,channels);
   ImfDeleteHeader(hdr_info);
   if (file == (ImfOutputFile *) NULL)
     {
+      (void) RelinquishUniqueFileResource(write_info->filename);
+      write_info=DestroyImageInfo(write_info);
       ThrowFileException(exception,BlobError,"UnableToOpenBlob",
         ImfErrorMessage());
-      write_info=DestroyImageInfo(write_info);
       return(MagickFalse);
     }
   scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
   if (scanline == (ImfRgba *) NULL)
     {
       (void) ImfCloseOutputFile(file);
+      (void) RelinquishUniqueFileResource(write_info->filename);
+      write_info=DestroyImageInfo(write_info);
       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
     }
+  ResetMagickMemory(scanline,0,image->columns*sizeof(*scanline));
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
@@ -444,7 +590,7 @@ static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
       scanline[x].g=half_quantum;
       ImfFloatToHalf(QuantumScale*GetPixelBlue(image,p),&half_quantum);
       scanline[x].b=half_quantum;
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait == UndefinedPixelTrait)
         ImfFloatToHalf(1.0,&half_quantum);
       else
         ImfFloatToHalf(QuantumScale*GetPixelAlpha(image,p),&half_quantum);