root / ImageMagick / trunk / coders / exr.c

Revision 11742, 16.3 kB (checked in by cristy, 4 weeks ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                            EEEEE  X   X  RRRR                               %
7%                            E       X X   R   R                              %
8%                            EEE      X    RRRR                               %
9%                            E       X X   R R                                %
10%                            EEEEE  X   X  R  R                               %
11%                                                                             %
12%                                                                             %
13%            Read/Write High Dynamic-Range (HDR) Image File Format.           %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 April 2007                                  %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/exception.h"
46#include "magick/exception-private.h"
47#include "magick/image.h"
48#include "magick/image-private.h"
49#include "magick/list.h"
50#include "magick/magick.h"
51#include "magick/memory_.h"
52#include "magick/property.h"
53#include "magick/quantum-private.h"
54#include "magick/static.h"
55#include "magick/string_.h"
56#include "magick/module.h"
57#include "magick/resource_.h"
58#include "magick/utility.h"
59#if defined(MAGICKCORE_OPENEXR_DELEGATE)
60#include <ImfCRgbaFile.h>
61
62/*
63  Forward declarations.
64*/
65static MagickBooleanType
66  WriteEXRImage(const ImageInfo *,Image *);
67#endif
68
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71%                                                                             %
72%                                                                             %
73%                                                                             %
74%   I s E X R                                                                 %
75%                                                                             %
76%                                                                             %
77%                                                                             %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80%  IsEXR() returns MagickTrue if the image format type, identified by the
81%  magick string, is EXR.
82%
83%  The format of the IsEXR method is:
84%
85%      MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
86%
87%  A description of each parameter follows:
88%
89%    o magick: This string is generally the first few bytes of an image file
90%      or blob.
91%
92%    o length: Specifies the length of the magick string.
93%
94*/
95static MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
96{
97  if (length < 4)
98    return(MagickFalse);
99  if (memcmp(magick,"\166\057\061\001",4) == 0)
100    return(MagickTrue);
101  return(MagickFalse);
102}
103
104#if defined(MAGICKCORE_OPENEXR_DELEGATE)
105/*
106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107%                                                                             %
108%                                                                             %
109%                                                                             %
110%   R e a d E X R I m a g e                                                   %
111%                                                                             %
112%                                                                             %
113%                                                                             %
114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115%
116%  ReadEXRImage reads an image in the high dynamic-range (HDR) file format
117%  developed by Industrial Light & Magic.  It allocates the memory necessary
118%  for the new Image structure and returns a pointer to the new image.
119%
120%  The format of the ReadEXRImage method is:
121%
122%      Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
123%
124%  A description of each parameter follows:
125%
126%    o image_info: the image info.
127%
128%    o exception: return any errors or warnings in this structure.
129%
130*/
131static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
132{
133  const ImfHeader
134    *hdr_info;
135
136  Image
137    *image;
138
139  ImageInfo
140    *read_info;
141
142  ImfInputFile
143    *file;
144
145  ImfRgba
146    *scanline;
147
148  int
149    max_x,
150    max_y,
151    min_x,
152    min_y;
153
154  long
155    y;
156
157  register long
158    x;
159
160  register PixelPacket
161    *q;
162
163  MagickBooleanType
164    status;
165
166  /*
167    Open image.
168  */
169  assert(image_info != (const ImageInfo *) NULL);
170  assert(image_info->signature == MagickSignature);
171  if (image_info->debug != MagickFalse)
172    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
173      image_info->filename);
174  assert(exception != (ExceptionInfo *) NULL);
175  assert(exception->signature == MagickSignature);
176  image=AcquireImage(image_info);
177  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
178  if (status == MagickFalse)
179    {
180      image=DestroyImageList(image);
181      return((Image *) NULL);
182    }
183  read_info=CloneImageInfo(image_info);
184  if (IsAccessible(read_info->filename) == MagickFalse)
185    {
186      (void) AcquireUniqueFilename(read_info->filename);
187      (void) ImageToFile(image,read_info->filename,exception);
188    }
189  file=ImfOpenInputFile(read_info->filename);
190  if (file == (ImfInputFile *) NULL)
191    {
192      ThrowFileException(exception,BlobError,"UnableToOpenBlob",
193        ImfErrorMessage());
194      read_info=DestroyImageInfo(read_info);
195      return((Image *) NULL);
196    }
197  hdr_info=ImfInputHeader(file);
198  ImfHeaderDataWindow(hdr_info,&min_x,&min_y,&max_x,&max_y);
199  image->columns=max_x-min_x+1UL;
200  image->rows=max_y-min_y+1UL;
201  image->matte=MagickTrue;
202  if (image_info->ping != MagickFalse)
203    {
204      (void) ImfCloseInputFile(file);
205      if (LocaleCompare(image_info->filename,read_info->filename) != 0)
206        (void) RelinquishUniqueFileResource(read_info->filename);
207      read_info=DestroyImageInfo(read_info);
208      (void) CloseBlob(image);
209      return(GetFirstImageInList(image));
210    }
211  if (SetImageExtent(image,0,0) == MagickFalse)
212    {
213      (void) ImfCloseInputFile(file);
214      if (LocaleCompare(image_info->filename,read_info->filename) != 0)
215        (void) RelinquishUniqueFileResource(read_info->filename);
216      read_info=DestroyImageInfo(read_info);
217      InheritException(exception,&image->exception);
218      return(DestroyImageList(image));
219    }
220  scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
221  if (scanline == (ImfRgba *) NULL)
222    {
223      (void) ImfCloseInputFile(file);
224      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
225    }
226  for (y=0; y < (long) image->rows; y++)
227  {
228    q=SetImagePixels(image,0,y,image->columns,1);
229    if (q == (PixelPacket *) NULL)
230      break;
231    ImfInputSetFrameBuffer(file,scanline-min_x-image->columns*(min_y+y),1,
232      image->columns);
233    ImfInputReadPixels(file,min_y+y,min_y+y);
234    for (x=0; x < (long) image->columns; x++)
235    {
236      q->red=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat(
237        scanline[x].r));
238      q->green=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat(
239        scanline[x].g));
240      q->blue=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat(
241        scanline[x].b));
242      q->opacity=RoundToQuantum((MagickRealType) QuantumRange-QuantumRange*
243        ImfHalfToFloat(scanline[x].a));
244      q++;
245    }
246    if (SyncImagePixels(image) == MagickFalse)
247      break;
248  }
249  scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
250  (void) ImfCloseInputFile(file);
251  if (LocaleCompare(image_info->filename,read_info->filename) != 0)
252    (void) RelinquishUniqueFileResource(read_info->filename);
253  read_info=DestroyImageInfo(read_info);
254  (void) CloseBlob(image);
255  return(GetFirstImageInList(image));
256}
257#endif
258
259/*
260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261%                                                                             %
262%                                                                             %
263%                                                                             %
264%   R e g i s t e r E X R I m a g e                                           %
265%                                                                             %
266%                                                                             %
267%                                                                             %
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269%
270%  RegisterEXRImage() adds properties for the EXR image format
271%  to the list of supported formats.  The properties include the image format
272%  tag, a method to read and/or write the format, whether the format
273%  supports the saving of more than one frame to the same file or blob,
274%  whether the format supports native in-memory I/O, and a brief
275%  description of the format.
276%
277%  The format of the RegisterEXRImage method is:
278%
279%      unsigned long RegisterEXRImage(void)
280%
281*/
282ModuleExport unsigned long RegisterEXRImage(void)
283{
284  MagickInfo
285    *entry;
286
287  entry=SetMagickInfo("EXR");
288#if defined(MAGICKCORE_OPENEXR_DELEGATE)
289  entry->decoder=(DecodeImageHandler *) ReadEXRImage;
290  entry->encoder=(EncodeImageHandler *) WriteEXRImage;
291#endif
292  entry->magick=(IsImageFormatHandler *) IsEXR;
293  entry->description=ConstantString("High Dynamic-range (HDR)");
294  entry->module=ConstantString("EXR");
295  (void) RegisterMagickInfo(entry);
296  return(MagickImageCoderSignature);
297}
298
299/*
300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301%                                                                             %
302%                                                                             %
303%                                                                             %
304%   U n r e g i s t e r E X R I m a g e                                       %
305%                                                                             %
306%                                                                             %
307%                                                                             %
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309%
310%  UnregisterEXRImage() removes format registrations made by the
311%  EXR module from the list of supported formats.
312%
313%  The format of the UnregisterEXRImage method is:
314%
315%      UnregisterEXRImage(void)
316%
317*/
318ModuleExport void UnregisterEXRImage(void)
319{
320  (void) UnregisterMagickInfo("EXR");
321}
322
323#if defined(MAGICKCORE_OPENEXR_DELEGATE)
324/*
325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326%                                                                             %
327%                                                                             %
328%                                                                             %
329%   W r i t e E X R I m a g e                                                 %
330%                                                                             %
331%                                                                             %
332%                                                                             %
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334%
335%  WriteEXRImage() writes an image to a file the in the high dynamic-range
336% (HDR) file format developed by Industrial Light & Magic.
337%
338%  The format of the WriteEXRImage method is:
339%
340%      MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image)
341%
342%  A description of each parameter follows.
343%
344%    o image_info: the image info.
345%
346%    o image:  The image.
347%
348*/
349static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image)
350{
351  ImageInfo
352    *write_info;
353
354  ImfHalf
355    half_quantum;
356
357  ImfHeader
358    *hdr_info;
359
360  ImfOutputFile
361    *file;
362
363  ImfRgba
364    *scanline;
365
366  long
367    y;
368
369  MagickBooleanType
370    status;
371
372  register const PixelPacket
373    *p;
374
375  register long
376    x;
377
378  /*
379    Open output image file.
380  */
381  assert(image_info != (const ImageInfo *) NULL);
382  assert(image_info->signature == MagickSignature);
383  assert(image != (Image *) NULL);
384  assert(image->signature == MagickSignature);
385  if (image->debug != MagickFalse)
386    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
387  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
388  if (status == MagickFalse)
389    return(status);
390  write_info=CloneImageInfo(image_info);
391  if (IsAccessible(write_info->filename) == MagickFalse)
392    (void) AcquireUniqueFilename(write_info->filename);
393  hdr_info=ImfNewHeader();
394  ImfHeaderSetDataWindow(hdr_info,0,0,(int) image->columns-1,(int)
395    image->rows-1);
396  ImfHeaderSetDisplayWindow(hdr_info,0,0,(int) image->columns-1,(int)
397    image->rows-1);
398  ImfHeaderSetCompression(hdr_info,write_info->compression == NoCompression ?
399    IMF_NO_COMPRESSION : IMF_PIZ_COMPRESSION);
400  ImfHeaderSetLineOrder(hdr_info,IMF_INCREASING_Y);
401  file=ImfOpenOutputFile(write_info->filename,hdr_info,IMF_WRITE_RGBA);
402  ImfDeleteHeader(hdr_info);
403  if (file == (ImfOutputFile *) NULL)
404    {
405      ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
406        ImfErrorMessage());
407      write_info=DestroyImageInfo(write_info);
408      return(MagickFalse);
409    }
410  scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
411  if (scanline == (ImfRgba *) NULL)
412    {
413      (void) ImfCloseOutputFile(file);
414      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
415    }
416  for (y=0; y < (long) image->rows; y++)
417  {
418    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
419    if (p == (const PixelPacket *) NULL)
420      break;
421    for (x=0; x < (long) image->columns; x++)
422    {
423      ImfFloatToHalf(QuantumScale*p->red,&half_quantum);
424      scanline[x].r=half_quantum;
425      ImfFloatToHalf(QuantumScale*p->green,&half_quantum);
426      scanline[x].g=half_quantum;
427      ImfFloatToHalf(QuantumScale*p->blue,&half_quantum);
428      scanline[x].b=half_quantum;
429      if (image->matte == MagickFalse)
430        ImfFloatToHalf(1.0,&half_quantum);
431      else
432        ImfFloatToHalf(1.0-QuantumScale*p->opacity,&half_quantum);
433      scanline[x].a=half_quantum;
434      p++;
435    }
436    ImfOutputSetFrameBuffer(file,scanline-(y*image->columns),1,image->columns);
437    ImfOutputWritePixels(file,1);
438  }
439  (void) ImfCloseOutputFile(file);
440  scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
441  if (LocaleCompare(image_info->filename,write_info->filename) != 0)
442    {
443      (void) FileToImage(image,write_info->filename);
444      (void) RelinquishUniqueFileResource(write_info->filename);
445    }
446  write_info=DestroyImageInfo(write_info);
447  (void) CloseBlob(image);
448  return(MagickTrue);
449}
450#endif
Note: See TracBrowser for help on using the browser.