blob: 6e5049b021cf24fa045b2194176462b56318bb1f [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% April 2007 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
48#include "MagickCore/image.h"
49#include "MagickCore/image-private.h"
50#include "MagickCore/list.h"
51#include "MagickCore/magick.h"
52#include "MagickCore/memory_.h"
cristy1838bfe2015-06-04 10:48:38 +000053#include "MagickCore/option.h"
cristy4c08aed2011-07-01 19:47:50 +000054#include "MagickCore/pixel-accessor.h"
55#include "MagickCore/property.h"
56#include "MagickCore/quantum-private.h"
57#include "MagickCore/static.h"
58#include "MagickCore/string_.h"
59#include "MagickCore/module.h"
60#include "MagickCore/resource_.h"
61#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000062#if defined(MAGICKCORE_OPENEXR_DELEGATE)
63#include <ImfCRgbaFile.h>
64
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000069 WriteEXRImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000070#endif
71
72/*
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74% %
75% %
76% %
77% I s E X R %
78% %
79% %
80% %
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82%
83% IsEXR() returns MagickTrue if the image format type, identified by the
84% magick string, is EXR.
85%
86% The format of the IsEXR method is:
87%
88% MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
89%
90% A description of each parameter follows:
91%
92% o magick: compare image format pattern against these bytes.
93%
94% o length: Specifies the length of the magick string.
95%
96*/
97static MagickBooleanType IsEXR(const unsigned char *magick,const size_t length)
98{
99 if (length < 4)
100 return(MagickFalse);
101 if (memcmp(magick,"\166\057\061\001",4) == 0)
102 return(MagickTrue);
103 return(MagickFalse);
104}
105
106#if defined(MAGICKCORE_OPENEXR_DELEGATE)
107/*
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109% %
110% %
111% %
112% R e a d E X R I m a g e %
113% %
114% %
115% %
116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117%
118% ReadEXRImage reads an image in the high dynamic-range (HDR) file format
119% developed by Industrial Light & Magic. It allocates the memory necessary
120% for the new Image structure and returns a pointer to the new image.
121%
122% The format of the ReadEXRImage method is:
123%
124% Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
125%
126% A description of each parameter follows:
127%
128% o image_info: the image info.
129%
130% o exception: return any errors or warnings in this structure.
131%
132*/
133static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception)
134{
135 const ImfHeader
136 *hdr_info;
137
138 Image
139 *image;
140
141 ImageInfo
142 *read_info;
143
144 ImfInputFile
145 *file;
146
147 ImfRgba
148 *scanline;
149
150 int
151 max_x,
152 max_y,
153 min_x,
154 min_y;
155
cristy202de442011-04-24 18:19:07 +0000156 MagickBooleanType
157 status;
cristy3ed852e2009-09-05 21:47:34 +0000158
cristybb503372010-05-27 20:51:26 +0000159 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000160 x;
161
cristy4c08aed2011-07-01 19:47:50 +0000162 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000163 *q;
164
cristy202de442011-04-24 18:19:07 +0000165 ssize_t
166 y;
cristy3ed852e2009-09-05 21:47:34 +0000167
168 /*
169 Open image.
170 */
171 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000172 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000173 if (image_info->debug != MagickFalse)
174 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
175 image_info->filename);
176 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000177 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000178 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000179 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
180 if (status == MagickFalse)
181 {
182 image=DestroyImageList(image);
183 return((Image *) NULL);
184 }
185 read_info=CloneImageInfo(image_info);
186 if (IsPathAccessible(read_info->filename) == MagickFalse)
187 {
188 (void) AcquireUniqueFilename(read_info->filename);
189 (void) ImageToFile(image,read_info->filename,exception);
190 }
191 file=ImfOpenInputFile(read_info->filename);
192 if (file == (ImfInputFile *) NULL)
193 {
194 ThrowFileException(exception,BlobError,"UnableToOpenBlob",
195 ImfErrorMessage());
dirkce6b1222014-11-06 21:09:46 +0000196 if (LocaleCompare(image_info->filename,read_info->filename) != 0)
197 (void) RelinquishUniqueFileResource(read_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000198 read_info=DestroyImageInfo(read_info);
199 return((Image *) NULL);
200 }
201 hdr_info=ImfInputHeader(file);
cristy1ff6c472012-03-21 11:39:04 +0000202 ImfHeaderDisplayWindow(hdr_info,&min_x,&min_y,&max_x,&max_y);
cristy3ed852e2009-09-05 21:47:34 +0000203 image->columns=max_x-min_x+1UL;
204 image->rows=max_y-min_y+1UL;
cristy8a46d822012-08-28 23:32:39 +0000205 image->alpha_trait=BlendPixelTrait;
cristye2c4f182012-05-12 14:11:53 +0000206 SetImageColorspace(image,RGBColorspace,exception);
cristy65147832012-05-01 10:57:51 +0000207 image->gamma=1.0;
cristy3ed852e2009-09-05 21:47:34 +0000208 if (image_info->ping != MagickFalse)
209 {
210 (void) ImfCloseInputFile(file);
211 if (LocaleCompare(image_info->filename,read_info->filename) != 0)
212 (void) RelinquishUniqueFileResource(read_info->filename);
213 read_info=DestroyImageInfo(read_info);
214 (void) CloseBlob(image);
215 return(GetFirstImageInList(image));
216 }
cristyacabb842014-12-14 23:36:33 +0000217 status=SetImageExtent(image,image->columns,image->rows,exception);
218 if (status == MagickFalse)
219 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000220 scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
221 if (scanline == (ImfRgba *) NULL)
222 {
223 (void) ImfCloseInputFile(file);
dirkce6b1222014-11-06 21:09:46 +0000224 if (LocaleCompare(image_info->filename,read_info->filename) != 0)
225 (void) RelinquishUniqueFileResource(read_info->filename);
226 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +0000227 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
228 }
cristybb503372010-05-27 20:51:26 +0000229 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000230 {
231 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000232 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000233 break;
cristy96eafde2013-04-29 11:31:02 +0000234 ResetMagickMemory(scanline,0,image->columns*sizeof(*scanline));
cristy3ed852e2009-09-05 21:47:34 +0000235 ImfInputSetFrameBuffer(file,scanline-min_x-image->columns*(min_y+y),1,
236 image->columns);
237 ImfInputReadPixels(file,min_y+y,min_y+y);
cristybb503372010-05-27 20:51:26 +0000238 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000239 {
cristy8cd03c32012-07-07 18:57:59 +0000240 SetPixelRed(image,ClampToQuantum(QuantumRange*
cristy4c08aed2011-07-01 19:47:50 +0000241 ImfHalfToFloat(scanline[x].r)),q);
cristy8cd03c32012-07-07 18:57:59 +0000242 SetPixelGreen(image,ClampToQuantum(QuantumRange*
cristy4c08aed2011-07-01 19:47:50 +0000243 ImfHalfToFloat(scanline[x].g)),q);
cristy8cd03c32012-07-07 18:57:59 +0000244 SetPixelBlue(image,ClampToQuantum(QuantumRange*
cristy4c08aed2011-07-01 19:47:50 +0000245 ImfHalfToFloat(scanline[x].b)),q);
cristy8cd03c32012-07-07 18:57:59 +0000246 SetPixelAlpha(image,ClampToQuantum(QuantumRange*
cristy4c08aed2011-07-01 19:47:50 +0000247 ImfHalfToFloat(scanline[x].a)),q);
cristyed231572011-07-14 02:18:59 +0000248 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000249 }
250 if (SyncAuthenticPixels(image,exception) == MagickFalse)
251 break;
252 }
253 scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
254 (void) ImfCloseInputFile(file);
255 if (LocaleCompare(image_info->filename,read_info->filename) != 0)
256 (void) RelinquishUniqueFileResource(read_info->filename);
257 read_info=DestroyImageInfo(read_info);
258 (void) CloseBlob(image);
259 return(GetFirstImageInList(image));
260}
261#endif
262
263/*
264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265% %
266% %
267% %
268% R e g i s t e r E X R I m a g e %
269% %
270% %
271% %
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273%
274% RegisterEXRImage() adds properties for the EXR image format
275% to the list of supported formats. The properties include the image format
276% tag, a method to read and/or write the format, whether the format
277% supports the saving of more than one frame to the same file or blob,
278% whether the format supports native in-memory I/O, and a brief
279% description of the format.
280%
281% The format of the RegisterEXRImage method is:
282%
cristybb503372010-05-27 20:51:26 +0000283% size_t RegisterEXRImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000284%
285*/
cristybb503372010-05-27 20:51:26 +0000286ModuleExport size_t RegisterEXRImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000287{
288 MagickInfo
289 *entry;
290
dirk06b627a2015-04-06 18:59:17 +0000291 entry=AcquireMagickInfo("EXR","EXR","High Dynamic-range (HDR)");
cristy3ed852e2009-09-05 21:47:34 +0000292#if defined(MAGICKCORE_OPENEXR_DELEGATE)
293 entry->decoder=(DecodeImageHandler *) ReadEXRImage;
294 entry->encoder=(EncodeImageHandler *) WriteEXRImage;
295#endif
296 entry->magick=(IsImageFormatHandler *) IsEXR;
dirk08e9a112015-02-22 01:51:41 +0000297 entry->flags^=CoderAdjoinFlag;
dirk08e9a112015-02-22 01:51:41 +0000298 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000299 (void) RegisterMagickInfo(entry);
300 return(MagickImageCoderSignature);
301}
302
303/*
304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305% %
306% %
307% %
308% U n r e g i s t e r E X R I m a g e %
309% %
310% %
311% %
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313%
314% UnregisterEXRImage() removes format registrations made by the
315% EXR module from the list of supported formats.
316%
317% The format of the UnregisterEXRImage method is:
318%
319% UnregisterEXRImage(void)
320%
321*/
322ModuleExport void UnregisterEXRImage(void)
323{
324 (void) UnregisterMagickInfo("EXR");
325}
326
327#if defined(MAGICKCORE_OPENEXR_DELEGATE)
328/*
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330% %
331% %
332% %
333% W r i t e E X R I m a g e %
334% %
335% %
336% %
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338%
339% WriteEXRImage() writes an image to a file the in the high dynamic-range
340% (HDR) file format developed by Industrial Light & Magic.
341%
342% The format of the WriteEXRImage method is:
343%
cristy1e178e72011-08-28 19:44:34 +0000344% MagickBooleanType WriteEXRImage(const ImageInfo *image_info,
345% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000346%
347% A description of each parameter follows.
348%
349% o image_info: the image info.
350%
351% o image: The image.
352%
cristy1e178e72011-08-28 19:44:34 +0000353% o exception: return any errors or warnings in this structure.
354%
cristy3ed852e2009-09-05 21:47:34 +0000355*/
cristy1e178e72011-08-28 19:44:34 +0000356static MagickBooleanType WriteEXRImage(const ImageInfo *image_info,Image *image,
357 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000358{
cristy1838bfe2015-06-04 10:48:38 +0000359 const char
360 *sampling_factor,
361 *value;
362
cristy3ed852e2009-09-05 21:47:34 +0000363 ImageInfo
364 *write_info;
365
366 ImfHalf
367 half_quantum;
368
369 ImfHeader
370 *hdr_info;
371
372 ImfOutputFile
373 *file;
374
375 ImfRgba
376 *scanline;
377
378 int
cristy1838bfe2015-06-04 10:48:38 +0000379 channels,
380 compression,
381 factors[3];
cristy3ed852e2009-09-05 21:47:34 +0000382
cristy3ed852e2009-09-05 21:47:34 +0000383 MagickBooleanType
384 status;
385
cristy4c08aed2011-07-01 19:47:50 +0000386 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000387 *p;
388
cristybb503372010-05-27 20:51:26 +0000389 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000390 x;
391
cristy202de442011-04-24 18:19:07 +0000392 ssize_t
393 y;
394
cristy3ed852e2009-09-05 21:47:34 +0000395 /*
396 Open output image file.
397 */
398 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000399 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000400 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000401 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000402 if (image->debug != MagickFalse)
403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000404 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000405 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000406 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000407 if (status == MagickFalse)
408 return(status);
cristyd74fdd02012-05-04 10:35:02 +0000409 (void) SetImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000410 write_info=CloneImageInfo(image_info);
411 (void) AcquireUniqueFilename(write_info->filename);
412 hdr_info=ImfNewHeader();
413 ImfHeaderSetDataWindow(hdr_info,0,0,(int) image->columns-1,(int)
414 image->rows-1);
415 ImfHeaderSetDisplayWindow(hdr_info,0,0,(int) image->columns-1,(int)
416 image->rows-1);
417 compression=IMF_NO_COMPRESSION;
418 if (write_info->compression == ZipSCompression)
419 compression=IMF_ZIPS_COMPRESSION;
420 if (write_info->compression == ZipCompression)
421 compression=IMF_ZIP_COMPRESSION;
422 if (write_info->compression == PizCompression)
423 compression=IMF_PIZ_COMPRESSION;
424 if (write_info->compression == Pxr24Compression)
425 compression=IMF_PXR24_COMPRESSION;
426#if defined(B44Compression)
427 if (write_info->compression == B44Compression)
428 compression=IMF_B44_COMPRESSION;
429#endif
430#if defined(B44ACompression)
431 if (write_info->compression == B44ACompression)
432 compression=IMF_B44A_COMPRESSION;
433#endif
cristy1838bfe2015-06-04 10:48:38 +0000434 channels=0;
435 value=GetImageOption(image_info,"exr:color-type");
436 if (value != (const char *) NULL)
437 {
438 if (LocaleCompare(value,"RGB") == 0)
439 channels=IMF_WRITE_RGB;
440 else if (LocaleCompare(value,"RGBA") == 0)
441 channels=IMF_WRITE_RGBA;
442 else if (LocaleCompare(value,"YC") == 0)
443 channels=IMF_WRITE_YC;
444 else if (LocaleCompare(value,"YCA") == 0)
445 channels=IMF_WRITE_YCA;
446 else if (LocaleCompare(value,"Y") == 0)
447 channels=IMF_WRITE_Y;
448 else if (LocaleCompare(value,"YA") == 0)
449 channels=IMF_WRITE_YA;
450 else if (LocaleCompare(value,"R") == 0)
451 channels=IMF_WRITE_R;
452 else if (LocaleCompare(value,"G") == 0)
453 channels=IMF_WRITE_G;
454 else if (LocaleCompare(value,"B") == 0)
455 channels=IMF_WRITE_B;
456 else if (LocaleCompare(value,"A") == 0)
457 channels=IMF_WRITE_A;
458 else
459 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
460 "ignoring invalid defined exr:color-type","=%s",value);
461 }
462 sampling_factor=(const char *) NULL;
463 factors[0]=0;
464 if (image_info->sampling_factor != (char *) NULL)
465 sampling_factor=image_info->sampling_factor;
466 if (sampling_factor != NULL)
467 {
468 /*
469 Sampling factors, valid values are 1x1 or 2x2.
470 */
471 if (sscanf(sampling_factor,"%d:%d:%d",factors,factors+1,factors+2) == 3)
472 {
473 if ((factors[0] == factors[1]) && (factors[1] == factors[2]))
474 factors[0]=1;
475 else
476 if ((factors[0] == (2*factors[1])) && (factors[2] == 0))
477 factors[0]=2;
478 }
479 else
480 if (sscanf(sampling_factor,"%dx%d",factors,factors+1) == 2)
481 {
482 if (factors[0] != factors[1])
483 factors[0]=0;
484 }
485 if ((factors[0] != 1) && (factors[0] != 2))
486 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
487 "ignoring sampling-factor","=%s",sampling_factor);
488 else if (channels != 0)
489 {
490 /*
491 Cross check given color type and subsampling.
492 */
493 factors[1]=((channels == IMF_WRITE_YCA) ||
494 (channels == IMF_WRITE_YC)) ? 2 : 1;
495 if (factors[0] != factors[1])
496 (void) ThrowMagickException(exception,GetMagickModule(),
497 CoderWarning,"sampling-factor and color type mismatch","=%s",
498 sampling_factor);
499 }
500 }
501 if (channels == 0)
502 {
503 /*
504 If no color type given, select it now.
505 */
506 if (factors[0] == 2)
507 channels=image->alpha_trait != UndefinedPixelTrait ? IMF_WRITE_YCA :
508 IMF_WRITE_YC;
509 else
510 channels=image->alpha_trait != UndefinedPixelTrait ? IMF_WRITE_RGBA :
511 IMF_WRITE_RGB;
512 }
cristy3ed852e2009-09-05 21:47:34 +0000513 ImfHeaderSetCompression(hdr_info,compression);
514 ImfHeaderSetLineOrder(hdr_info,IMF_INCREASING_Y);
cristy1838bfe2015-06-04 10:48:38 +0000515 file=ImfOpenOutputFile(write_info->filename,hdr_info,channels);
cristy3ed852e2009-09-05 21:47:34 +0000516 ImfDeleteHeader(hdr_info);
517 if (file == (ImfOutputFile *) NULL)
518 {
dirkce6b1222014-11-06 21:09:46 +0000519 (void) RelinquishUniqueFileResource(write_info->filename);
520 write_info=DestroyImageInfo(write_info);
cristy1e178e72011-08-28 19:44:34 +0000521 ThrowFileException(exception,BlobError,"UnableToOpenBlob",
cristy3ed852e2009-09-05 21:47:34 +0000522 ImfErrorMessage());
cristy3ed852e2009-09-05 21:47:34 +0000523 return(MagickFalse);
524 }
525 scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline));
526 if (scanline == (ImfRgba *) NULL)
527 {
528 (void) ImfCloseOutputFile(file);
dirkce6b1222014-11-06 21:09:46 +0000529 (void) RelinquishUniqueFileResource(write_info->filename);
530 write_info=DestroyImageInfo(write_info);
cristy3ed852e2009-09-05 21:47:34 +0000531 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
532 }
cristy96eafde2013-04-29 11:31:02 +0000533 ResetMagickMemory(scanline,0,image->columns*sizeof(*scanline));
cristybb503372010-05-27 20:51:26 +0000534 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000535 {
cristy1e178e72011-08-28 19:44:34 +0000536 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000537 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000538 break;
cristybb503372010-05-27 20:51:26 +0000539 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000540 {
cristy4c08aed2011-07-01 19:47:50 +0000541 ImfFloatToHalf(QuantumScale*GetPixelRed(image,p),&half_quantum);
cristy3ed852e2009-09-05 21:47:34 +0000542 scanline[x].r=half_quantum;
cristy4c08aed2011-07-01 19:47:50 +0000543 ImfFloatToHalf(QuantumScale*GetPixelGreen(image,p),&half_quantum);
cristy3ed852e2009-09-05 21:47:34 +0000544 scanline[x].g=half_quantum;
cristy4c08aed2011-07-01 19:47:50 +0000545 ImfFloatToHalf(QuantumScale*GetPixelBlue(image,p),&half_quantum);
cristy3ed852e2009-09-05 21:47:34 +0000546 scanline[x].b=half_quantum;
cristy17f11b02014-12-20 19:37:04 +0000547 if (image->alpha_trait == UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +0000548 ImfFloatToHalf(1.0,&half_quantum);
549 else
cristy4c08aed2011-07-01 19:47:50 +0000550 ImfFloatToHalf(QuantumScale*GetPixelAlpha(image,p),&half_quantum);
cristy3ed852e2009-09-05 21:47:34 +0000551 scanline[x].a=half_quantum;
cristyed231572011-07-14 02:18:59 +0000552 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000553 }
554 ImfOutputSetFrameBuffer(file,scanline-(y*image->columns),1,image->columns);
555 ImfOutputWritePixels(file,1);
556 }
557 (void) ImfCloseOutputFile(file);
558 scanline=(ImfRgba *) RelinquishMagickMemory(scanline);
cristyc82a27b2011-10-21 01:07:16 +0000559 (void) FileToImage(image,write_info->filename,exception);
cristy3ed852e2009-09-05 21:47:34 +0000560 (void) RelinquishUniqueFileResource(write_info->filename);
561 write_info=DestroyImageInfo(write_info);
562 (void) CloseBlob(image);
563 return(MagickTrue);
564}
565#endif