exr.c revision e85007d004da78a4e1dc7738d894a7074cce596d
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-2010 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/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 63/* 64 Forward declarations. 65*/ 66static MagickBooleanType 67 WriteEXRImage(const ImageInfo *,Image *); 68#endif 69 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*/ 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 ssize_t 155 y; 156 157 register ssize_t 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 (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 q->red=ClampToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( 228 scanline[x].r)); 229 q->green=ClampToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( 230 scanline[x].g)); 231 q->blue=ClampToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( 232 scanline[x].b)); 233 q->opacity=ClampToQuantum((MagickRealType) QuantumRange-QuantumRange* 234 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 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*/ 273ModuleExport 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 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*/ 311ModuleExport void UnregisterEXRImage(void) 312{ 313 (void) UnregisterMagickInfo("EXR"); 314} 315 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*/ 342static 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 ssize_t 363 y; 364 365 MagickBooleanType 366 status; 367 368 register const PixelPacket 369 *p; 370 371 register ssize_t 372 x; 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*p->red,&half_quantum); 435 scanline[x].r=half_quantum; 436 ImfFloatToHalf(QuantumScale*p->green,&half_quantum); 437 scanline[x].g=half_quantum; 438 ImfFloatToHalf(QuantumScale*p->blue,&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*p->opacity,&half_quantum); 444 scanline[x].a=half_quantum; 445 p++; 446 } 447 ImfOutputSetFrameBuffer(file,scanline-(y*image->columns),1,image->columns); 448 ImfOutputWritePixels(file,1); 449 } 450 (void) ImfCloseOutputFile(file); 451 scanline=(ImfRgba *) RelinquishMagickMemory(scanline); 452 (void) FileToImage(image,write_info->filename); 453 (void) RelinquishUniqueFileResource(write_info->filename); 454 write_info=DestroyImageInfo(write_info); 455 (void) CloseBlob(image); 456 return(MagickTrue); 457} 458#endif 459