]> granicus.if.org Git - imagemagick/blob - coders/exr.c
(no commit message)
[imagemagick] / coders / exr.c
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-2011 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 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/image.h"
49 #include "magick/image-private.h"
50 #include "magick/list.h"
51 #include "magick/magick.h"
52 #include "magick/memory_.h"
53 #include "magick/property.h"
54 #include "magick/quantum-private.h"
55 #include "magick/static.h"
56 #include "magick/string_.h"
57 #include "magick/module.h"
58 #include "magick/resource_.h"
59 #include "magick/utility.h"
60 #if defined(MAGICKCORE_OPENEXR_DELEGATE)
61 #include <ImfCRgbaFile.h>
62 \f
63 /*
64   Forward declarations.
65 */
66 static MagickBooleanType
67   WriteEXRImage(const ImageInfo *,Image *);
68 #endif
69 \f
70 /*
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %                                                                             %
73 %                                                                             %
74 %                                                                             %
75 %   I s E X R                                                                 %
76 %                                                                             %
77 %                                                                             %
78 %                                                                             %
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 %
81 %  IsEXR() returns MagickTrue if the image format type, identified by the
82 %  magick string, is EXR.
83 %
84 %  The format of the IsEXR method is:
85 %
86 %      MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
87 %
88 %  A description of each parameter follows:
89 %
90 %    o magick: compare image format pattern against these bytes.
91 %
92 %    o length: Specifies the length of the magick string.
93 %
94 */
95 static 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 \f
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 */
131 static 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   MagickBooleanType
155     status;
156
157   register ssize_t
158     x;
159
160   register PixelPacket
161     *q;
162
163   ssize_t
164     y;
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 (IsPathAccessible(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   scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
212   if (scanline == (ImfRgba *) NULL)
213     {
214       (void) ImfCloseInputFile(file);
215       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
216     }
217   for (y=0; y < (ssize_t) image->rows; y++)
218   {
219     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
220     if (q == (PixelPacket *) NULL)
221       break;
222     ImfInputSetFrameBuffer(file,scanline-min_x-image->columns*(min_y+y),1,
223       image->columns);
224     ImfInputReadPixels(file,min_y+y,min_y+y);
225     for (x=0; x < (ssize_t) image->columns; x++)
226     {
227       SetRedPixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
228         ImfHalfToFloat(scanline[x].r)));
229       SetGreenPixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
230         ImfHalfToFloat(scanline[x].g)));
231       SetBluePixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
232         ImfHalfToFloat(scanline[x].b)));
233       SetOpacityPixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange-
234         QuantumRange*ImfHalfToFloat(scanline[x].a)));
235       q++;
236     }
237     if (SyncAuthenticPixels(image,exception) == MagickFalse)
238       break;
239   }
240   scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
241   (void) ImfCloseInputFile(file);
242   if (LocaleCompare(image_info->filename,read_info->filename) != 0)
243     (void) RelinquishUniqueFileResource(read_info->filename);
244   read_info=DestroyImageInfo(read_info);
245   (void) CloseBlob(image);
246   return(GetFirstImageInList(image));
247 }
248 #endif
249 \f
250 /*
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 %                                                                             %
253 %                                                                             %
254 %                                                                             %
255 %   R e g i s t e r E X R I m a g e                                           %
256 %                                                                             %
257 %                                                                             %
258 %                                                                             %
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 %
261 %  RegisterEXRImage() adds properties for the EXR image format
262 %  to the list of supported formats.  The properties include the image format
263 %  tag, a method to read and/or write the format, whether the format
264 %  supports the saving of more than one frame to the same file or blob,
265 %  whether the format supports native in-memory I/O, and a brief
266 %  description of the format.
267 %
268 %  The format of the RegisterEXRImage method is:
269 %
270 %      size_t RegisterEXRImage(void)
271 %
272 */
273 ModuleExport size_t RegisterEXRImage(void)
274 {
275   MagickInfo
276     *entry;
277
278   entry=SetMagickInfo("EXR");
279 #if defined(MAGICKCORE_OPENEXR_DELEGATE)
280   entry->decoder=(DecodeImageHandler *) ReadEXRImage;
281   entry->encoder=(EncodeImageHandler *) WriteEXRImage;
282 #endif
283   entry->magick=(IsImageFormatHandler *) IsEXR;
284   entry->adjoin=MagickFalse;
285   entry->description=ConstantString("High Dynamic-range (HDR)");
286   entry->blob_support=MagickFalse;
287   entry->module=ConstantString("EXR");
288   (void) RegisterMagickInfo(entry);
289   return(MagickImageCoderSignature);
290 }
291 \f
292 /*
293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294 %                                                                             %
295 %                                                                             %
296 %                                                                             %
297 %   U n r e g i s t e r E X R I m a g e                                       %
298 %                                                                             %
299 %                                                                             %
300 %                                                                             %
301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302 %
303 %  UnregisterEXRImage() removes format registrations made by the
304 %  EXR module from the list of supported formats.
305 %
306 %  The format of the UnregisterEXRImage method is:
307 %
308 %      UnregisterEXRImage(void)
309 %
310 */
311 ModuleExport void UnregisterEXRImage(void)
312 {
313   (void) UnregisterMagickInfo("EXR");
314 }
315 \f
316 #if defined(MAGICKCORE_OPENEXR_DELEGATE)
317 /*
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 %                                                                             %
320 %                                                                             %
321 %                                                                             %
322 %   W r i t e E X R I m a g e                                                 %
323 %                                                                             %
324 %                                                                             %
325 %                                                                             %
326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 %
328 %  WriteEXRImage() writes an image to a file the in the high dynamic-range
329 %  (HDR) file format developed by Industrial Light & Magic.
330 %
331 %  The format of the WriteEXRImage method is:
332 %
333 %      MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image)
334 %
335 %  A description of each parameter follows.
336 %
337 %    o image_info: the image info.
338 %
339 %    o image:  The image.
340 %
341 */
342 static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image)
343 {
344   ImageInfo
345     *write_info;
346
347   ImfHalf
348     half_quantum;
349
350   ImfHeader
351     *hdr_info;
352
353   ImfOutputFile
354     *file;
355
356   ImfRgba
357     *scanline;
358
359   int
360     compression;
361
362   MagickBooleanType
363     status;
364
365   register const PixelPacket
366     *p;
367
368   register ssize_t
369     x;
370
371   ssize_t
372     y;
373
374   /*
375     Open output image file.
376   */
377   assert(image_info != (const ImageInfo *) NULL);
378   assert(image_info->signature == MagickSignature);
379   assert(image != (Image *) NULL);
380   assert(image->signature == MagickSignature);
381   if (image->debug != MagickFalse)
382     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
383   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
384   if (status == MagickFalse)
385     return(status);
386   write_info=CloneImageInfo(image_info);
387   (void) AcquireUniqueFilename(write_info->filename);
388   hdr_info=ImfNewHeader();
389   ImfHeaderSetDataWindow(hdr_info,0,0,(int) image->columns-1,(int)
390     image->rows-1);
391   ImfHeaderSetDisplayWindow(hdr_info,0,0,(int) image->columns-1,(int)
392     image->rows-1);
393   compression=IMF_NO_COMPRESSION;
394   if (write_info->compression == ZipSCompression)
395     compression=IMF_ZIPS_COMPRESSION;
396   if (write_info->compression == ZipCompression)
397     compression=IMF_ZIP_COMPRESSION;
398   if (write_info->compression == PizCompression)
399     compression=IMF_PIZ_COMPRESSION;
400   if (write_info->compression == Pxr24Compression)
401     compression=IMF_PXR24_COMPRESSION;
402 #if defined(B44Compression)
403   if (write_info->compression == B44Compression)
404     compression=IMF_B44_COMPRESSION;
405 #endif
406 #if defined(B44ACompression)
407   if (write_info->compression == B44ACompression)
408     compression=IMF_B44A_COMPRESSION;
409 #endif
410   ImfHeaderSetCompression(hdr_info,compression);
411   ImfHeaderSetLineOrder(hdr_info,IMF_INCREASING_Y);
412   file=ImfOpenOutputFile(write_info->filename,hdr_info,IMF_WRITE_RGBA);
413   ImfDeleteHeader(hdr_info);
414   if (file == (ImfOutputFile *) NULL)
415     {
416       ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
417         ImfErrorMessage());
418       write_info=DestroyImageInfo(write_info);
419       return(MagickFalse);
420     }
421   scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
422   if (scanline == (ImfRgba *) NULL)
423     {
424       (void) ImfCloseOutputFile(file);
425       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
426     }
427   for (y=0; y < (ssize_t) image->rows; y++)
428   {
429     p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
430     if (p == (const PixelPacket *) NULL)
431       break;
432     for (x=0; x < (ssize_t) image->columns; x++)
433     {
434       ImfFloatToHalf(QuantumScale*GetRedPixelComponent(p),&half_quantum);
435       scanline[x].r=half_quantum;
436       ImfFloatToHalf(QuantumScale*GetGreenPixelComponent(p),&half_quantum);
437       scanline[x].g=half_quantum;
438       ImfFloatToHalf(QuantumScale*GetBluePixelComponent(p),&half_quantum);
439       scanline[x].b=half_quantum;
440       if (image->matte == MagickFalse)
441         ImfFloatToHalf(1.0,&half_quantum);
442       else
443         ImfFloatToHalf(1.0-QuantumScale*GetOpacityPixelComponent(p),
444           &half_quantum);
445       scanline[x].a=half_quantum;
446       p++;
447     }
448     ImfOutputSetFrameBuffer(file,scanline-(y*image->columns),1,image->columns);
449     ImfOutputWritePixels(file,1);
450   }
451   (void) ImfCloseOutputFile(file);
452   scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
453   (void) FileToImage(image,write_info->filename);
454   (void) RelinquishUniqueFileResource(write_info->filename);
455   write_info=DestroyImageInfo(write_info);
456   (void) CloseBlob(image);
457   return(MagickTrue);
458 }
459 #endif