1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % M M PPPP EEEEE GGGG % 7 % MM MM P P E G % 8 % M M M PPPP EEE G GG % 9 % M M P E G G % 10 % M M P EEEEE GGGG % 11 % % 12 % % 13 % Read/Write MPEG Image Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1999 % 18 % % 19 % % 20 % Copyright 1999-2019 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 % https://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 Include declarations. 40 */ 41 #include "MagickCore/studio.h" 42 #include "MagickCore/blob.h" 43 #include "MagickCore/blob-private.h" 44 #include "MagickCore/constitute.h" 45 #include "MagickCore/delegate.h" 46 #include "MagickCore/exception.h" 47 #include "MagickCore/exception-private.h" 48 #include "MagickCore/geometry.h" 49 #include "MagickCore/image.h" 50 #include "MagickCore/image-private.h" 51 #include "MagickCore/layer.h" 52 #include "MagickCore/list.h" 53 #include "MagickCore/log.h" 54 #include "MagickCore/magick.h" 55 #include "MagickCore/memory_.h" 56 #include "MagickCore/resource_.h" 57 #include "MagickCore/quantum-private.h" 58 #include "MagickCore/static.h" 59 #include "MagickCore/string_.h" 60 #include "MagickCore/module.h" 61 #include "MagickCore/transform.h" 62 #include "MagickCore/utility.h" 63 #include "MagickCore/utility-private.h" 64 65 /* 67 Forward declarations. 68 */ 69 static MagickBooleanType 70 WriteMPEGImage(const ImageInfo *,Image *,ExceptionInfo *); 71 72 /* 74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 75 % % 76 % % 77 % % 78 % I s A V I % 79 % % 80 % % 81 % % 82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83 % 84 % IsAVI() returns MagickTrue if the image format type, identified by the 85 % magick string, is Audio/Video Interleaved file format. 86 % 87 % The format of the IsAVI method is: 88 % 89 % size_t IsAVI(const unsigned char *magick,const size_t length) 90 % 91 % A description of each parameter follows: 92 % 93 % o magick: compare image format pattern against these bytes. 94 % 95 % o length: Specifies the length of the magick string. 96 % 97 */ 98 static MagickBooleanType IsAVI(const unsigned char *magick,const size_t length) 99 { 100 if (length < 4) 101 return(MagickFalse); 102 if (memcmp(magick,"RIFF",4) == 0) 103 return(MagickTrue); 104 return(MagickFalse); 105 } 106 107 /* 109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 110 % % 111 % % 112 % % 113 % I s M P E G % 114 % % 115 % % 116 % % 117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118 % 119 % IsMPEG() returns MagickTrue if the image format type, identified by the 120 % magick string, is MPEG. 121 % 122 % The format of the IsMPEG method is: 123 % 124 % MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length) 125 % 126 % A description of each parameter follows: 127 % 128 % o magick: compare image format pattern against these bytes. 129 % 130 % o length: Specifies the length of the magick string. 131 % 132 */ 133 static MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length) 134 { 135 if (length < 4) 136 return(MagickFalse); 137 if (memcmp(magick,"\000\000\001\263",4) == 0) 138 return(MagickTrue); 139 return(MagickFalse); 140 } 141 142 /* 144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 145 % % 146 % % 147 % % 148 % R e a d M P E G I m a g e % 149 % % 150 % % 151 % % 152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153 % 154 % ReadMPEGImage() reads an binary file in the MPEG video stream format 155 % and returns it. It allocates the memory necessary for the new Image 156 % structure and returns a pointer to the new image. 157 % 158 % The format of the ReadMPEGImage method is: 159 % 160 % Image *ReadMPEGImage(const ImageInfo *image_info, 161 % ExceptionInfo *exception) 162 % 163 % A description of each parameter follows: 164 % 165 % o image_info: the image info. 166 % 167 % o exception: return any errors or warnings in this structure. 168 % 169 */ 170 static Image *ReadMPEGImage(const ImageInfo *image_info, 171 ExceptionInfo *exception) 172 { 173 #define ReadMPEGIntermediateFormat "pam" 174 175 Image 176 *image, 177 *images, 178 *next; 179 180 ImageInfo 181 *read_info; 182 183 MagickBooleanType 184 status; 185 186 /* 187 Open image file. 188 */ 189 assert(image_info != (const ImageInfo *) NULL); 190 assert(image_info->signature == MagickCoreSignature); 191 if (image_info->debug != MagickFalse) 192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 193 image_info->filename); 194 assert(exception != (ExceptionInfo *) NULL); 195 assert(exception->signature == MagickCoreSignature); 196 image=AcquireImage(image_info,exception); 197 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 198 if (status == MagickFalse) 199 { 200 image=DestroyImageList(image); 201 return((Image *) NULL); 202 } 203 (void) CloseBlob(image); 204 (void) DestroyImageList(image); 205 /* 206 Convert MPEG to PAM with delegate. 207 */ 208 images=(Image *) NULL; 209 read_info=CloneImageInfo(image_info); 210 image=AcquireImage(image_info,exception); 211 status=InvokeDelegate(read_info,image,"mpeg:decode",(char *) NULL,exception); 212 if (status != MagickFalse) 213 { 214 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"%s.%s", 215 read_info->unique,ReadMPEGIntermediateFormat); 216 *read_info->magick='\0'; 217 images=ReadImage(read_info,exception); 218 if (images != (Image *) NULL) 219 for (next=images; next != (Image *) NULL; next=next->next) 220 { 221 (void) CopyMagickString(next->filename,image->filename, 222 MagickPathExtent); 223 (void) CopyMagickString(next->magick,image->magick,MagickPathExtent); 224 } 225 (void) RelinquishUniqueFileResource(read_info->filename); 226 } 227 read_info=DestroyImageInfo(read_info); 228 image=DestroyImage(image); 229 return(images); 230 } 231 232 /* 234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 235 % % 236 % % 237 % % 238 % R e g i s t e r M P E G I m a g e % 239 % % 240 % % 241 % % 242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 243 % 244 % RegisterMPEGImage() adds attributes for the MPEG image format to 245 % the list of supported formats. The attributes include the image format 246 % tag, a method to read and/or write the format, whether the format 247 % supports the saving of more than one frame to the same file or blob, 248 % whether the format supports native in-memory I/O, and a brief 249 % description of the format. 250 % 251 % The format of the RegisterMPEGImage method is: 252 % 253 % size_t RegisterMPEGImage(void) 254 % 255 */ 256 ModuleExport size_t RegisterMPEGImage(void) 257 { 258 MagickInfo 259 *entry; 260 261 entry=AcquireMagickInfo("MPEG","3GP","Media Container"); 262 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 263 entry->flags^=CoderBlobSupportFlag; 264 entry->flags|=CoderSeekableStreamFlag; 265 (void) RegisterMagickInfo(entry); 266 entry=AcquireMagickInfo("MPEG","3G2","Media Container"); 267 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 268 entry->flags^=CoderBlobSupportFlag; 269 entry->flags|=CoderSeekableStreamFlag; 270 (void) RegisterMagickInfo(entry); 271 entry=AcquireMagickInfo("MPEG","AVI","Microsoft Audio/Visual Interleaved"); 272 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 273 entry->magick=(IsImageFormatHandler *) IsAVI; 274 entry->flags^=CoderBlobSupportFlag; 275 (void) RegisterMagickInfo(entry); 276 entry=AcquireMagickInfo("MPEG","MKV","Multimedia Container"); 277 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 278 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 279 entry->magick=(IsImageFormatHandler *) IsMPEG; 280 entry->flags^=CoderBlobSupportFlag; 281 (void) RegisterMagickInfo(entry); 282 entry=AcquireMagickInfo("MPEG","MOV","MPEG Video Stream"); 283 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 284 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 285 entry->magick=(IsImageFormatHandler *) IsMPEG; 286 entry->flags^=CoderBlobSupportFlag; 287 (void) RegisterMagickInfo(entry); 288 entry=AcquireMagickInfo("MPEG","MPEG","MPEG Video Stream"); 289 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 290 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 291 entry->magick=(IsImageFormatHandler *) IsMPEG; 292 entry->flags^=CoderBlobSupportFlag; 293 (void) RegisterMagickInfo(entry); 294 entry=AcquireMagickInfo("MPEG","MPG","MPEG Video Stream"); 295 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 296 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 297 entry->magick=(IsImageFormatHandler *) IsMPEG; 298 entry->flags^=CoderBlobSupportFlag; 299 (void) RegisterMagickInfo(entry); 300 entry=AcquireMagickInfo("MPEG","MP4","MPEG-4 Video Stream"); 301 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 302 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 303 entry->magick=(IsImageFormatHandler *) IsMPEG; 304 entry->flags^=CoderBlobSupportFlag; 305 (void) RegisterMagickInfo(entry); 306 entry=AcquireMagickInfo("MPEG","M2V","MPEG Video Stream"); 307 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 308 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 309 entry->magick=(IsImageFormatHandler *) IsMPEG; 310 entry->flags^=CoderBlobSupportFlag; 311 (void) RegisterMagickInfo(entry); 312 entry=AcquireMagickInfo("MPEG","M4V","Raw MPEG-4 Video"); 313 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 314 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 315 entry->magick=(IsImageFormatHandler *) IsMPEG; 316 entry->flags^=CoderBlobSupportFlag; 317 (void) RegisterMagickInfo(entry); 318 entry=AcquireMagickInfo("MPEG","WMV","Windows Media Video"); 319 entry->decoder=(DecodeImageHandler *) ReadMPEGImage; 320 entry->encoder=(EncodeImageHandler *) WriteMPEGImage; 321 entry->magick=(IsImageFormatHandler *) IsMPEG; 322 entry->flags^=CoderBlobSupportFlag; 323 (void) RegisterMagickInfo(entry); 324 return(MagickImageCoderSignature); 325 } 326 327 /* 329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 330 % % 331 % % 332 % % 333 % U n r e g i s t e r M P E G I m a g e % 334 % % 335 % % 336 % % 337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 338 % 339 % UnregisterMPEGImage() removes format registrations made by the 340 % BIM module from the list of supported formats. 341 % 342 % The format of the UnregisterBIMImage method is: 343 % 344 % UnregisterMPEGImage(void) 345 % 346 */ 347 ModuleExport void UnregisterMPEGImage(void) 348 { 349 (void) UnregisterMagickInfo("WMV"); 350 (void) UnregisterMagickInfo("MOV"); 351 (void) UnregisterMagickInfo("M4V"); 352 (void) UnregisterMagickInfo("M2V"); 353 (void) UnregisterMagickInfo("MP4"); 354 (void) UnregisterMagickInfo("MPG"); 355 (void) UnregisterMagickInfo("MPEG"); 356 (void) UnregisterMagickInfo("MKV"); 357 (void) UnregisterMagickInfo("AVI"); 358 (void) UnregisterMagickInfo("3G2"); 359 (void) UnregisterMagickInfo("3GP"); 360 } 361 362 /* 364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 365 % % 366 % % 367 % % 368 % W r i t e M P E G I m a g e % 369 % % 370 % % 371 % % 372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 373 % 374 % WriteMPEGImage() writes an image to a file in MPEG video stream format. 375 % Lawrence Livermore National Laboratory (LLNL) contributed code to adjust 376 % the MPEG parameters to correspond to the compression quality setting. 377 % 378 % The format of the WriteMPEGImage method is: 379 % 380 % MagickBooleanType WriteMPEGImage(const ImageInfo *image_info, 381 % Image *image,ExceptionInfo *exception) 382 % 383 % A description of each parameter follows. 384 % 385 % o image_info: the image info. 386 % 387 % o image: The image. 388 % 389 % o exception: return any errors or warnings in this structure. 390 % 391 */ 392 static MagickBooleanType CopyDelegateFile(const char *source, 393 const char *destination) 394 { 395 int 396 destination_file, 397 source_file; 398 399 MagickBooleanType 400 status; 401 402 register size_t 403 i; 404 405 size_t 406 length, 407 quantum; 408 409 ssize_t 410 count; 411 412 struct stat 413 attributes; 414 415 unsigned char 416 *buffer; 417 418 /* 419 Return if destination file already exists and is not empty. 420 */ 421 assert(source != (const char *) NULL); 422 assert(destination != (char *) NULL); 423 status=GetPathAttributes(destination,&attributes); 424 if ((status != MagickFalse) && (attributes.st_size > 0)) 425 return(MagickTrue); 426 /* 427 Copy source file to destination. 428 */ 429 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE); 430 if (destination_file == -1) 431 return(MagickFalse); 432 source_file=open_utf8(source,O_RDONLY | O_BINARY,0); 433 if (source_file == -1) 434 { 435 (void) close(destination_file); 436 return(MagickFalse); 437 } 438 quantum=(size_t) MagickMaxBufferExtent; 439 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0)) 440 quantum=(size_t) MagickMin((double) attributes.st_size, 441 MagickMaxBufferExtent); 442 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer)); 443 if (buffer == (unsigned char *) NULL) 444 { 445 (void) close(source_file); 446 (void) close(destination_file); 447 return(MagickFalse); 448 } 449 length=0; 450 for (i=0; ; i+=count) 451 { 452 count=(ssize_t) read(source_file,buffer,quantum); 453 if (count <= 0) 454 break; 455 length=(size_t) count; 456 count=(ssize_t) write(destination_file,buffer,length); 457 if ((size_t) count != length) 458 break; 459 } 460 (void) close(destination_file); 461 (void) close(source_file); 462 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 463 return(i != 0 ? MagickTrue : MagickFalse); 464 } 465 466 static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info, 467 Image *image,ExceptionInfo *exception) 468 { 469 #define WriteMPEGIntermediateFormat "jpg" 470 471 char 472 basename[MagickPathExtent], 473 filename[MagickPathExtent]; 474 475 double 476 delay; 477 478 Image 479 *coalesce_image; 480 481 ImageInfo 482 *write_info; 483 484 int 485 file; 486 487 MagickBooleanType 488 status; 489 490 register Image 491 *p; 492 493 register ssize_t 494 i; 495 496 size_t 497 count, 498 length, 499 scene; 500 501 unsigned char 502 *blob; 503 504 /* 505 Open output image file. 506 */ 507 assert(image_info != (const ImageInfo *) NULL); 508 assert(image_info->signature == MagickCoreSignature); 509 assert(image != (Image *) NULL); 510 assert(image->signature == MagickCoreSignature); 511 if (image->debug != MagickFalse) 512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 513 assert(exception != (ExceptionInfo *) NULL); 514 assert(exception->signature == MagickCoreSignature); 515 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 516 if (status == MagickFalse) 517 return(status); 518 (void) CloseBlob(image); 519 /* 520 Write intermediate files. 521 */ 522 coalesce_image=CoalesceImages(image,exception); 523 if (coalesce_image == (Image *) NULL) 524 return(MagickFalse); 525 file=AcquireUniqueFileResource(basename); 526 if (file != -1) 527 file=close(file)-1; 528 (void) FormatLocaleString(coalesce_image->filename,MagickPathExtent,"%s", 529 basename); 530 count=0; 531 write_info=CloneImageInfo(image_info); 532 *write_info->magick='\0'; 533 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p)) 534 { 535 char 536 previous_image[MagickPathExtent]; 537 538 blob=(unsigned char *) NULL; 539 length=0; 540 scene=p->scene; 541 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0); 542 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++) 543 { 544 p->scene=count; 545 count++; 546 status=MagickFalse; 547 switch (i) 548 { 549 case 0: 550 { 551 Image 552 *frame; 553 554 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s", 555 basename,(double) p->scene,WriteMPEGIntermediateFormat); 556 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s", 557 basename,(double) p->scene,WriteMPEGIntermediateFormat); 558 (void) FormatLocaleString(previous_image,MagickPathExtent, 559 "%s%.20g.%s",basename,(double) p->scene, 560 WriteMPEGIntermediateFormat); 561 frame=CloneImage(p,0,0,MagickTrue,exception); 562 if (frame == (Image *) NULL) 563 break; 564 status=WriteImage(write_info,frame,exception); 565 frame=DestroyImage(frame); 566 break; 567 } 568 case 1: 569 { 570 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length, 571 exception); 572 } 573 default: 574 { 575 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s", 576 basename,(double) p->scene,WriteMPEGIntermediateFormat); 577 if (length > 0) 578 status=BlobToFile(filename,blob,length,exception); 579 break; 580 } 581 } 582 if (image->debug != MagickFalse) 583 { 584 if (status != MagickFalse) 585 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 586 "%.20g. Wrote %s file for scene %.20g:",(double) i, 587 WriteMPEGIntermediateFormat,(double) p->scene); 588 else 589 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 590 "%.20g. Failed to write %s file for scene %.20g:",(double) i, 591 WriteMPEGIntermediateFormat,(double) p->scene); 592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename); 593 } 594 } 595 p->scene=scene; 596 if (blob != (unsigned char *) NULL) 597 blob=(unsigned char *) RelinquishMagickMemory(blob); 598 if (status == MagickFalse) 599 break; 600 } 601 /* 602 Convert JPEG to MPEG. 603 */ 604 (void) CopyMagickString(coalesce_image->magick_filename,basename, 605 MagickPathExtent); 606 (void) CopyMagickString(coalesce_image->filename,basename,MagickPathExtent); 607 GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick); 608 if (*coalesce_image->magick == '\0') 609 (void) CopyMagickString(coalesce_image->magick,image->magick, 610 MagickPathExtent); 611 status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode", 612 exception); 613 (void) FormatLocaleString(write_info->filename,MagickPathExtent,"%s.%s", 614 write_info->unique,coalesce_image->magick); 615 status=CopyDelegateFile(write_info->filename,image->filename); 616 (void) RelinquishUniqueFileResource(write_info->filename); 617 write_info=DestroyImageInfo(write_info); 618 /* 619 Relinquish resources. 620 */ 621 count=0; 622 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p)) 623 { 624 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0); 625 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++) 626 { 627 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s", 628 basename,(double) count++,WriteMPEGIntermediateFormat); 629 (void) RelinquishUniqueFileResource(p->filename); 630 } 631 (void) CopyMagickString(p->filename,image_info->filename,MagickPathExtent); 632 } 633 (void) RelinquishUniqueFileResource(basename); 634 coalesce_image=DestroyImageList(coalesce_image); 635 if (image->debug != MagickFalse) 636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit"); 637 return(status); 638 } 639