1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % CCCC OOO N N SSSSS TTTTT IIIII TTTTT U U TTTTT EEEEE % 7 % C O O NN N SS T I T U U T E % 8 % C O O N N N ESSS T I T U U T EEE % 9 % C O O N NN SS T I T U U T E % 10 % CCCC OOO N N SSSSS T IIIII T UUU T EEEEE % 11 % % 12 % % 13 % MagickCore Methods to Consitute an Image % 14 % % 15 % Software Design % 16 % Cristy % 17 % October 1998 % 18 % % 19 % % 20 % Copyright 1999-2016 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 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/attribute.h" 45 #include "MagickCore/blob.h" 46 #include "MagickCore/blob-private.h" 47 #include "MagickCore/exception.h" 48 #include "MagickCore/exception-private.h" 49 #include "MagickCore/cache.h" 50 #include "MagickCore/client.h" 51 #include "MagickCore/colorspace-private.h" 52 #include "MagickCore/constitute.h" 53 #include "MagickCore/constitute-private.h" 54 #include "MagickCore/delegate.h" 55 #include "MagickCore/geometry.h" 56 #include "MagickCore/identify.h" 57 #include "MagickCore/image-private.h" 58 #include "MagickCore/list.h" 59 #include "MagickCore/magick.h" 60 #include "MagickCore/memory_.h" 61 #include "MagickCore/monitor.h" 62 #include "MagickCore/monitor-private.h" 63 #include "MagickCore/option.h" 64 #include "MagickCore/pixel.h" 65 #include "MagickCore/pixel-accessor.h" 66 #include "MagickCore/policy.h" 67 #include "MagickCore/profile.h" 68 #include "MagickCore/profile-private.h" 69 #include "MagickCore/property.h" 70 #include "MagickCore/quantum.h" 71 #include "MagickCore/resize.h" 72 #include "MagickCore/resource_.h" 73 #include "MagickCore/semaphore.h" 74 #include "MagickCore/statistic.h" 75 #include "MagickCore/stream.h" 76 #include "MagickCore/string_.h" 77 #include "MagickCore/string-private.h" 78 #include "MagickCore/timer.h" 79 #include "MagickCore/token.h" 80 #include "MagickCore/transform.h" 81 #include "MagickCore/utility.h" 82 #include "MagickCore/utility-private.h" 83 84 /* 86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 87 % % 88 % % 89 % % 90 % C o n s t i t u t e I m a g e % 91 % % 92 % % 93 % % 94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 95 % 96 % ConstituteImage() returns an image from the pixel data you supply. 97 % The pixel data must be in scanline order top-to-bottom. The data can be 98 % char, short int, int, float, or double. Float and double require the 99 % pixels to be normalized [0..1], otherwise [0..QuantumRange]. For example, to 100 % create a 640x480 image from unsigned red-green-blue character data, use: 101 % 102 % image = ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception); 103 % 104 % The format of the ConstituteImage method is: 105 % 106 % Image *ConstituteImage(const size_t columns,const size_t rows, 107 % const char *map,const StorageType storage,const void *pixels, 108 % ExceptionInfo *exception) 109 % 110 % A description of each parameter follows: 111 % 112 % o columns: width in pixels of the image. 113 % 114 % o rows: height in pixels of the image. 115 % 116 % o map: This string reflects the expected ordering of the pixel array. 117 % It can be any combination or order of R = red, G = green, B = blue, 118 % A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan, 119 % Y = yellow, M = magenta, K = black, I = intensity (for grayscale), 120 % P = pad. 121 % 122 % o storage: Define the data type of the pixels. Float and double types are 123 % expected to be normalized [0..1] otherwise [0..QuantumRange]. Choose 124 % from these types: CharPixel, DoublePixel, FloatPixel, IntegerPixel, 125 % LongPixel, QuantumPixel, or ShortPixel. 126 % 127 % o pixels: This array of values contain the pixel components as defined by 128 % map and type. You must preallocate this array where the expected 129 % length varies depending on the values of width, height, map, and type. 130 % 131 % o exception: return any errors or warnings in this structure. 132 % 133 */ 134 MagickExport Image *ConstituteImage(const size_t columns,const size_t rows, 135 const char *map,const StorageType storage,const void *pixels, 136 ExceptionInfo *exception) 137 { 138 Image 139 *image; 140 141 MagickBooleanType 142 status; 143 144 /* 145 Allocate image structure. 146 */ 147 assert(map != (const char *) NULL); 148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map); 149 assert(pixels != (void *) NULL); 150 assert(exception != (ExceptionInfo *) NULL); 151 assert(exception->signature == MagickCoreSignature); 152 image=AcquireImage((ImageInfo *) NULL,exception); 153 if (image == (Image *) NULL) 154 return((Image *) NULL); 155 if ((columns == 0) || (rows == 0)) 156 ThrowImageException(OptionError,"NonZeroWidthAndHeightRequired"); 157 image->columns=columns; 158 image->rows=rows; 159 (void) SetImageBackgroundColor(image,exception); 160 status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels,exception); 161 if (status == MagickFalse) 162 image=DestroyImage(image); 163 return(image); 164 } 165 166 /* 168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 169 % % 170 % % 171 % % 172 % P i n g I m a g e % 173 % % 174 % % 175 % % 176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 177 % 178 % PingImage() returns all the properties of an image or image sequence 179 % except for the pixels. It is much faster and consumes far less memory 180 % than ReadImage(). On failure, a NULL image is returned and exception 181 % describes the reason for the failure. 182 % 183 % The format of the PingImage method is: 184 % 185 % Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception) 186 % 187 % A description of each parameter follows: 188 % 189 % o image_info: Ping the image defined by the file or filename members of 190 % this structure. 191 % 192 % o exception: return any errors or warnings in this structure. 193 % 194 */ 195 196 #if defined(__cplusplus) || defined(c_plusplus) 197 extern "C" { 198 #endif 199 200 static size_t PingStream(const Image *magick_unused(image), 201 const void *magick_unused(pixels),const size_t columns) 202 { 203 magick_unreferenced(image); 204 magick_unreferenced(pixels); 205 return(columns); 206 } 207 208 #if defined(__cplusplus) || defined(c_plusplus) 209 } 210 #endif 211 212 MagickExport Image *PingImage(const ImageInfo *image_info, 213 ExceptionInfo *exception) 214 { 215 Image 216 *image; 217 218 ImageInfo 219 *ping_info; 220 221 assert(image_info != (ImageInfo *) NULL); 222 assert(image_info->signature == MagickCoreSignature); 223 if (image_info->debug != MagickFalse) 224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 225 image_info->filename); 226 assert(exception != (ExceptionInfo *) NULL); 227 ping_info=CloneImageInfo(image_info); 228 ping_info->ping=MagickTrue; 229 image=ReadStream(ping_info,&PingStream,exception); 230 if (image != (Image *) NULL) 231 { 232 ResetTimer(&image->timer); 233 if (ping_info->verbose != MagickFalse) 234 (void) IdentifyImage(image,stdout,MagickFalse,exception); 235 } 236 ping_info=DestroyImageInfo(ping_info); 237 return(image); 238 } 239 240 /* 242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 243 % % 244 % % 245 % % 246 % P i n g I m a g e s % 247 % % 248 % % 249 % % 250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 251 % 252 % PingImages() pings one or more images and returns them as an image list. 253 % 254 % The format of the PingImage method is: 255 % 256 % Image *PingImages(ImageInfo *image_info,const char *filename, 257 % ExceptionInfo *exception) 258 % 259 % A description of each parameter follows: 260 % 261 % o image_info: the image info. 262 % 263 % o filename: the image filename. 264 % 265 % o exception: return any errors or warnings in this structure. 266 % 267 */ 268 MagickExport Image *PingImages(ImageInfo *image_info,const char *filename, 269 ExceptionInfo *exception) 270 { 271 char 272 ping_filename[MagickPathExtent]; 273 274 Image 275 *image, 276 *images; 277 278 ImageInfo 279 *read_info; 280 281 /* 282 Ping image list from a file. 283 */ 284 assert(image_info != (ImageInfo *) NULL); 285 assert(image_info->signature == MagickCoreSignature); 286 if (image_info->debug != MagickFalse) 287 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 288 image_info->filename); 289 assert(exception != (ExceptionInfo *) NULL); 290 (void) SetImageOption(image_info,"filename",filename); 291 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 292 (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename, 293 (int) image_info->scene,ping_filename,exception); 294 if (LocaleCompare(ping_filename,image_info->filename) != 0) 295 { 296 ExceptionInfo 297 *sans; 298 299 ssize_t 300 extent, 301 scene; 302 303 /* 304 Images of the form image-%d.png[1-5]. 305 */ 306 read_info=CloneImageInfo(image_info); 307 sans=AcquireExceptionInfo(); 308 (void) SetImageInfo(read_info,0,sans); 309 sans=DestroyExceptionInfo(sans); 310 if (read_info->number_scenes == 0) 311 { 312 read_info=DestroyImageInfo(read_info); 313 return(PingImage(image_info,exception)); 314 } 315 (void) CopyMagickString(ping_filename,read_info->filename,MagickPathExtent); 316 images=NewImageList(); 317 extent=(ssize_t) (read_info->scene+read_info->number_scenes); 318 for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++) 319 { 320 (void) InterpretImageFilename(image_info,(Image *) NULL,ping_filename, 321 (int) scene,read_info->filename,exception); 322 image=PingImage(read_info,exception); 323 if (image == (Image *) NULL) 324 continue; 325 AppendImageToList(&images,image); 326 } 327 read_info=DestroyImageInfo(read_info); 328 return(images); 329 } 330 return(PingImage(image_info,exception)); 331 } 332 333 /* 335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 336 % % 337 % % 338 % % 339 % R e a d I m a g e % 340 % % 341 % % 342 % % 343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 344 % 345 % ReadImage() reads an image or image sequence from a file or file handle. 346 % The method returns a NULL if there is a memory shortage or if the image 347 % cannot be read. On failure, a NULL image is returned and exception 348 % describes the reason for the failure. 349 % 350 % The format of the ReadImage method is: 351 % 352 % Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception) 353 % 354 % A description of each parameter follows: 355 % 356 % o image_info: Read the image defined by the file or filename members of 357 % this structure. 358 % 359 % o exception: return any errors or warnings in this structure. 360 % 361 */ 362 MagickExport Image *ReadImage(const ImageInfo *image_info, 363 ExceptionInfo *exception) 364 { 365 char 366 filename[MagickPathExtent], 367 magick[MagickPathExtent], 368 magick_filename[MagickPathExtent]; 369 370 const char 371 *value; 372 373 const DelegateInfo 374 *delegate_info; 375 376 const MagickInfo 377 *magick_info; 378 379 ExceptionInfo 380 *sans_exception; 381 382 GeometryInfo 383 geometry_info; 384 385 Image 386 *image, 387 *next; 388 389 ImageInfo 390 *read_info; 391 392 MagickStatusType 393 flags; 394 395 PolicyDomain 396 domain; 397 398 PolicyRights 399 rights; 400 401 /* 402 Determine image type from filename prefix or suffix (e.g. image.jpg). 403 */ 404 assert(image_info != (ImageInfo *) NULL); 405 assert(image_info->signature == MagickCoreSignature); 406 assert(image_info->filename != (char *) NULL); 407 if (image_info->debug != MagickFalse) 408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 409 image_info->filename); 410 assert(exception != (ExceptionInfo *) NULL); 411 read_info=CloneImageInfo(image_info); 412 (void) CopyMagickString(magick_filename,read_info->filename,MagickPathExtent); 413 (void) SetImageInfo(read_info,0,exception); 414 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent); 415 (void) CopyMagickString(magick,read_info->magick,MagickPathExtent); 416 domain=CoderPolicyDomain; 417 rights=ReadPolicyRights; 418 if (IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse) 419 { 420 errno=EPERM; 421 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 422 "NotAuthorized","`%s'",read_info->filename); 423 read_info=DestroyImageInfo(read_info); 424 return((Image *) NULL); 425 } 426 /* 427 Call appropriate image reader based on image type. 428 */ 429 sans_exception=AcquireExceptionInfo(); 430 magick_info=GetMagickInfo(read_info->magick,sans_exception); 431 sans_exception=DestroyExceptionInfo(sans_exception); 432 if (magick_info != (const MagickInfo *) NULL) 433 { 434 if (GetMagickEndianSupport(magick_info) == MagickFalse) 435 read_info->endian=UndefinedEndian; 436 else 437 if ((image_info->endian == UndefinedEndian) && 438 (GetMagickRawSupport(magick_info) != MagickFalse)) 439 { 440 unsigned long 441 lsb_first; 442 443 lsb_first=1; 444 read_info->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : 445 MSBEndian; 446 } 447 } 448 if ((magick_info != (const MagickInfo *) NULL) && 449 (GetMagickSeekableStream(magick_info) != MagickFalse)) 450 { 451 MagickBooleanType 452 status; 453 454 image=AcquireImage(read_info,exception); 455 (void) CopyMagickString(image->filename,read_info->filename, 456 MagickPathExtent); 457 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 458 if (status == MagickFalse) 459 { 460 read_info=DestroyImageInfo(read_info); 461 image=DestroyImage(image); 462 return((Image *) NULL); 463 } 464 if (IsBlobSeekable(image) == MagickFalse) 465 { 466 /* 467 Coder requires a seekable stream. 468 */ 469 *read_info->filename='\0'; 470 status=ImageToFile(image,read_info->filename,exception); 471 if (status == MagickFalse) 472 { 473 (void) CloseBlob(image); 474 read_info=DestroyImageInfo(read_info); 475 image=DestroyImage(image); 476 return((Image *) NULL); 477 } 478 read_info->temporary=MagickTrue; 479 } 480 (void) CloseBlob(image); 481 image=DestroyImage(image); 482 } 483 image=NewImageList(); 484 if ((magick_info == (const MagickInfo *) NULL) || 485 (GetImageDecoder(magick_info) == (DecodeImageHandler *) NULL)) 486 { 487 delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception); 488 if (delegate_info == (const DelegateInfo *) NULL) 489 { 490 (void) SetImageInfo(read_info,0,exception); 491 (void) CopyMagickString(read_info->filename,filename, 492 MagickPathExtent); 493 magick_info=GetMagickInfo(read_info->magick,exception); 494 } 495 } 496 if ((magick_info != (const MagickInfo *) NULL) && 497 (GetImageDecoder(magick_info) != (DecodeImageHandler *) NULL)) 498 { 499 if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse) 500 LockSemaphoreInfo(magick_info->semaphore); 501 image=GetImageDecoder(magick_info)(read_info,exception); 502 if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse) 503 UnlockSemaphoreInfo(magick_info->semaphore); 504 } 505 else 506 { 507 MagickBooleanType 508 status; 509 510 delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception); 511 if (delegate_info == (const DelegateInfo *) NULL) 512 { 513 (void) ThrowMagickException(exception,GetMagickModule(), 514 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", 515 read_info->magick); 516 if (read_info->temporary != MagickFalse) 517 (void) RelinquishUniqueFileResource(read_info->filename); 518 read_info=DestroyImageInfo(read_info); 519 return((Image *) NULL); 520 } 521 /* 522 Let our decoding delegate process the image. 523 */ 524 image=AcquireImage(read_info,exception); 525 if (image == (Image *) NULL) 526 { 527 read_info=DestroyImageInfo(read_info); 528 return((Image *) NULL); 529 } 530 (void) CopyMagickString(image->filename,read_info->filename, 531 MagickPathExtent); 532 *read_info->filename='\0'; 533 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 534 LockSemaphoreInfo(delegate_info->semaphore); 535 status=InvokeDelegate(read_info,image,read_info->magick,(char *) NULL, 536 exception); 537 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 538 UnlockSemaphoreInfo(delegate_info->semaphore); 539 image=DestroyImageList(image); 540 read_info->temporary=MagickTrue; 541 if (status != MagickFalse) 542 (void) SetImageInfo(read_info,0,exception); 543 magick_info=GetMagickInfo(read_info->magick,exception); 544 if ((magick_info == (const MagickInfo *) NULL) || 545 (GetImageDecoder(magick_info) == (DecodeImageHandler *) NULL)) 546 { 547 if (IsPathAccessible(read_info->filename) != MagickFalse) 548 (void) ThrowMagickException(exception,GetMagickModule(), 549 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", 550 read_info->magick); 551 else 552 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 553 read_info->filename); 554 read_info=DestroyImageInfo(read_info); 555 return((Image *) NULL); 556 } 557 if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse) 558 LockSemaphoreInfo(magick_info->semaphore); 559 image=(Image *) (GetImageDecoder(magick_info))(read_info,exception); 560 if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse) 561 UnlockSemaphoreInfo(magick_info->semaphore); 562 } 563 if (read_info->temporary != MagickFalse) 564 { 565 (void) RelinquishUniqueFileResource(read_info->filename); 566 read_info->temporary=MagickFalse; 567 if (image != (Image *) NULL) 568 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 569 } 570 if (image == (Image *) NULL) 571 { 572 read_info=DestroyImageInfo(read_info); 573 return(image); 574 } 575 if (exception->severity >= ErrorException) 576 (void) LogMagickEvent(ExceptionEvent,GetMagickModule(), 577 "Coder (%s) generated an image despite an error (%d), " 578 "notify the developers",image->magick,exception->severity); 579 if (IsBlobTemporary(image) != MagickFalse) 580 (void) RelinquishUniqueFileResource(read_info->filename); 581 if ((GetNextImageInList(image) != (Image *) NULL) && 582 (IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse)) 583 { 584 Image 585 *clones; 586 587 clones=CloneImages(image,read_info->scenes,exception); 588 if (clones == (Image *) NULL) 589 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 590 "SubimageSpecificationReturnsNoImages","`%s'",read_info->filename); 591 else 592 { 593 image=DestroyImageList(image); 594 image=GetFirstImageInList(clones); 595 } 596 } 597 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) 598 { 599 char 600 magick_path[MagickPathExtent], 601 *property, 602 timestamp[MagickPathExtent]; 603 604 const char 605 *option; 606 607 const StringInfo 608 *profile; 609 610 next->taint=MagickFalse; 611 GetPathComponent(magick_filename,MagickPath,magick_path); 612 if (*magick_path == '\0' && *next->magick == '\0') 613 (void) CopyMagickString(next->magick,magick,MagickPathExtent); 614 (void) CopyMagickString(next->magick_filename,magick_filename, 615 MagickPathExtent); 616 if (IsBlobTemporary(image) != MagickFalse) 617 (void) CopyMagickString(next->filename,filename,MagickPathExtent); 618 if (next->magick_columns == 0) 619 next->magick_columns=next->columns; 620 if (next->magick_rows == 0) 621 next->magick_rows=next->rows; 622 value=GetImageProperty(next,"tiff:Orientation",exception); 623 if (value == (char *) NULL) 624 value=GetImageProperty(next,"exif:Orientation",exception); 625 if (value != (char *) NULL) 626 { 627 next->orientation=(OrientationType) StringToLong(value); 628 (void) DeleteImageProperty(next,"tiff:Orientation"); 629 (void) DeleteImageProperty(next,"exif:Orientation"); 630 } 631 value=GetImageProperty(next,"exif:XResolution",exception); 632 if (value != (char *) NULL) 633 { 634 geometry_info.rho=next->resolution.x; 635 geometry_info.sigma=1.0; 636 flags=ParseGeometry(value,&geometry_info); 637 if (geometry_info.sigma != 0) 638 next->resolution.x=geometry_info.rho/geometry_info.sigma; 639 (void) DeleteImageProperty(next,"exif:XResolution"); 640 } 641 value=GetImageProperty(next,"exif:YResolution",exception); 642 if (value != (char *) NULL) 643 { 644 geometry_info.rho=next->resolution.y; 645 geometry_info.sigma=1.0; 646 flags=ParseGeometry(value,&geometry_info); 647 if (geometry_info.sigma != 0) 648 next->resolution.y=geometry_info.rho/geometry_info.sigma; 649 (void) DeleteImageProperty(next,"exif:YResolution"); 650 } 651 value=GetImageProperty(next,"tiff:ResolutionUnit",exception); 652 if (value == (char *) NULL) 653 value=GetImageProperty(next,"exif:ResolutionUnit",exception); 654 if (value != (char *) NULL) 655 { 656 next->units=(ResolutionType) (StringToLong(value)-1); 657 (void) DeleteImageProperty(next,"exif:ResolutionUnit"); 658 (void) DeleteImageProperty(next,"tiff:ResolutionUnit"); 659 } 660 if (next->page.width == 0) 661 next->page.width=next->columns; 662 if (next->page.height == 0) 663 next->page.height=next->rows; 664 option=GetImageOption(read_info,"caption"); 665 if (option != (const char *) NULL) 666 { 667 property=InterpretImageProperties(read_info,next,option,exception); 668 (void) SetImageProperty(next,"caption",property,exception); 669 property=DestroyString(property); 670 } 671 option=GetImageOption(read_info,"comment"); 672 if (option != (const char *) NULL) 673 { 674 property=InterpretImageProperties(read_info,next,option,exception); 675 (void) SetImageProperty(next,"comment",property,exception); 676 property=DestroyString(property); 677 } 678 option=GetImageOption(read_info,"label"); 679 if (option != (const char *) NULL) 680 { 681 property=InterpretImageProperties(read_info,next,option,exception); 682 (void) SetImageProperty(next,"label",property,exception); 683 property=DestroyString(property); 684 } 685 if (LocaleCompare(next->magick,"TEXT") == 0) 686 (void) ParseAbsoluteGeometry("0x0+0+0",&next->page); 687 if ((read_info->extract != (char *) NULL) && 688 (read_info->stream == (StreamHandler) NULL)) 689 { 690 RectangleInfo 691 geometry; 692 693 flags=ParseAbsoluteGeometry(read_info->extract,&geometry); 694 if ((next->columns != geometry.width) || 695 (next->rows != geometry.height)) 696 { 697 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 698 { 699 Image 700 *crop_image; 701 702 crop_image=CropImage(next,&geometry,exception); 703 if (crop_image != (Image *) NULL) 704 ReplaceImageInList(&next,crop_image); 705 } 706 else 707 if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) 708 { 709 Image 710 *size_image; 711 712 flags=ParseRegionGeometry(next,read_info->extract,&geometry, 713 exception); 714 size_image=ResizeImage(next,geometry.width,geometry.height, 715 next->filter,exception); 716 if (size_image != (Image *) NULL) 717 ReplaceImageInList(&next,size_image); 718 } 719 } 720 } 721 profile=GetImageProfile(next,"icc"); 722 if (profile == (const StringInfo *) NULL) 723 profile=GetImageProfile(next,"icm"); 724 profile=GetImageProfile(next,"iptc"); 725 if (profile == (const StringInfo *) NULL) 726 profile=GetImageProfile(next,"8bim"); 727 (void) FormatMagickTime(GetBlobProperties(next)->st_mtime,MagickPathExtent, 728 timestamp); 729 (void) SetImageProperty(next,"date:modify",timestamp,exception); 730 (void) FormatMagickTime(GetBlobProperties(next)->st_ctime,MagickPathExtent, 731 timestamp); 732 (void) SetImageProperty(next,"date:create",timestamp,exception); 733 option=GetImageOption(image_info,"delay"); 734 if (option != (const char *) NULL) 735 { 736 flags=ParseGeometry(option,&geometry_info); 737 if ((flags & GreaterValue) != 0) 738 { 739 if (next->delay > (size_t) floor(geometry_info.rho+0.5)) 740 next->delay=(size_t) floor(geometry_info.rho+0.5); 741 } 742 else 743 if ((flags & LessValue) != 0) 744 { 745 if (next->delay < (size_t) floor(geometry_info.rho+0.5)) 746 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 747 } 748 else 749 next->delay=(size_t) floor(geometry_info.rho+0.5); 750 if ((flags & SigmaValue) != 0) 751 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 752 } 753 option=GetImageOption(image_info,"dispose"); 754 if (option != (const char *) NULL) 755 next->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions, 756 MagickFalse,option); 757 if (read_info->verbose != MagickFalse) 758 (void) IdentifyImage(next,stderr,MagickFalse,exception); 759 image=next; 760 } 761 read_info=DestroyImageInfo(read_info); 762 return(GetFirstImageInList(image)); 763 } 764 765 /* 767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 768 % % 769 % % 770 % % 771 % R e a d I m a g e s % 772 % % 773 % % 774 % % 775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 776 % 777 % ReadImages() reads one or more images and returns them as an image list. 778 % 779 % The format of the ReadImage method is: 780 % 781 % Image *ReadImages(ImageInfo *image_info,const char *filename, 782 % ExceptionInfo *exception) 783 % 784 % A description of each parameter follows: 785 % 786 % o image_info: the image info. 787 % 788 % o filename: the image filename. 789 % 790 % o exception: return any errors or warnings in this structure. 791 % 792 */ 793 MagickExport Image *ReadImages(ImageInfo *image_info,const char *filename, 794 ExceptionInfo *exception) 795 { 796 char 797 read_filename[MagickPathExtent]; 798 799 Image 800 *image, 801 *images; 802 803 ImageInfo 804 *read_info; 805 806 /* 807 Read image list from a file. 808 */ 809 assert(image_info != (ImageInfo *) NULL); 810 assert(image_info->signature == MagickCoreSignature); 811 if (image_info->debug != MagickFalse) 812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 813 image_info->filename); 814 assert(exception != (ExceptionInfo *) NULL); 815 read_info=CloneImageInfo(image_info); 816 *read_info->magick='\0'; 817 (void) SetImageOption(read_info,"filename",filename); 818 (void) CopyMagickString(read_info->filename,filename,MagickPathExtent); 819 (void) InterpretImageFilename(read_info,(Image *) NULL,filename, 820 (int) read_info->scene,read_filename,exception); 821 if (LocaleCompare(read_filename,read_info->filename) != 0) 822 { 823 ExceptionInfo 824 *sans; 825 826 ssize_t 827 extent, 828 scene; 829 830 /* 831 Images of the form image-%d.png[1-5]. 832 */ 833 sans=AcquireExceptionInfo(); 834 (void) SetImageInfo(read_info,0,sans); 835 sans=DestroyExceptionInfo(sans); 836 if (read_info->number_scenes == 0) 837 { 838 read_info=DestroyImageInfo(read_info); 839 return(ReadImage(image_info,exception)); 840 } 841 (void) CopyMagickString(read_filename,read_info->filename, 842 MagickPathExtent); 843 images=NewImageList(); 844 extent=(ssize_t) (read_info->scene+read_info->number_scenes); 845 for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++) 846 { 847 (void) InterpretImageFilename(image_info,(Image *) NULL,read_filename, 848 (int) scene,read_info->filename,exception); 849 image=ReadImage(read_info,exception); 850 if (image == (Image *) NULL) 851 continue; 852 AppendImageToList(&images,image); 853 } 854 read_info=DestroyImageInfo(read_info); 855 return(images); 856 } 857 image=ReadImage(read_info,exception); 858 read_info=DestroyImageInfo(read_info); 859 return(image); 860 } 861 862 /* 864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 865 % % 866 % % 867 % % 868 + R e a d I n l i n e I m a g e % 869 % % 870 % % 871 % % 872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 873 % 874 % ReadInlineImage() reads a Base64-encoded inline image or image sequence. 875 % The method returns a NULL if there is a memory shortage or if the image 876 % cannot be read. On failure, a NULL image is returned and exception 877 % describes the reason for the failure. 878 % 879 % The format of the ReadInlineImage method is: 880 % 881 % Image *ReadInlineImage(const ImageInfo *image_info,const char *content, 882 % ExceptionInfo *exception) 883 % 884 % A description of each parameter follows: 885 % 886 % o image_info: the image info. 887 % 888 % o content: the image encoded in Base64. 889 % 890 % o exception: return any errors or warnings in this structure. 891 % 892 */ 893 MagickExport Image *ReadInlineImage(const ImageInfo *image_info, 894 const char *content,ExceptionInfo *exception) 895 { 896 Image 897 *image; 898 899 ImageInfo 900 *read_info; 901 902 unsigned char 903 *blob; 904 905 size_t 906 length; 907 908 register const char 909 *p; 910 911 /* 912 Skip over header (e.g. data:image/gif;base64,). 913 */ 914 image=NewImageList(); 915 for (p=content; (*p != ',') && (*p != '\0'); p++) ; 916 if (*p == '\0') 917 ThrowReaderException(CorruptImageError,"CorruptImage"); 918 p++; 919 length=0; 920 blob=Base64Decode(p,&length); 921 if (length == 0) 922 ThrowReaderException(CorruptImageError,"CorruptImage"); 923 read_info=CloneImageInfo(image_info); 924 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 925 (void *) NULL); 926 *read_info->filename='\0'; 927 *read_info->magick='\0'; 928 image=BlobToImage(read_info,blob,length,exception); 929 blob=(unsigned char *) RelinquishMagickMemory(blob); 930 read_info=DestroyImageInfo(read_info); 931 return(image); 932 } 933 934 /* 936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 937 % % 938 % % 939 % % 940 % W r i t e I m a g e % 941 % % 942 % % 943 % % 944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 945 % 946 % WriteImage() writes an image or an image sequence to a file or file handle. 947 % If writing to a file is on disk, the name is defined by the filename member 948 % of the image structure. WriteImage() returns MagickFalse is there is a 949 % memory shortage or if the image cannot be written. Check the exception 950 % member of image to determine the cause for any failure. 951 % 952 % The format of the WriteImage method is: 953 % 954 % MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image, 955 % ExceptionInfo *exception) 956 % 957 % A description of each parameter follows: 958 % 959 % o image_info: the image info. 960 % 961 % o image: the image. 962 % 963 % o exception: return any errors or warnings in this structure. 964 % 965 */ 966 MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, 967 Image *image,ExceptionInfo *exception) 968 { 969 char 970 filename[MagickPathExtent]; 971 972 const char 973 *option; 974 975 const DelegateInfo 976 *delegate_info; 977 978 const MagickInfo 979 *magick_info; 980 981 ExceptionInfo 982 *sans_exception; 983 984 ImageInfo 985 *write_info; 986 987 MagickBooleanType 988 status, 989 temporary; 990 991 PolicyDomain 992 domain; 993 994 PolicyRights 995 rights; 996 997 /* 998 Determine image type from filename prefix or suffix (e.g. image.jpg). 999 */ 1000 assert(image_info != (ImageInfo *) NULL); 1001 assert(image_info->signature == MagickCoreSignature); 1002 if (image->debug != MagickFalse) 1003 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 1004 image_info->filename); 1005 assert(image != (Image *) NULL); 1006 assert(image->signature == MagickCoreSignature); 1007 assert(exception != (ExceptionInfo *) NULL); 1008 sans_exception=AcquireExceptionInfo(); 1009 write_info=CloneImageInfo(image_info); 1010 (void) CopyMagickString(write_info->filename,image->filename, 1011 MagickPathExtent); 1012 (void) SetImageInfo(write_info,1,sans_exception); 1013 if (*write_info->magick == '\0') 1014 (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent); 1015 (void) CopyMagickString(filename,image->filename,MagickPathExtent); 1016 (void) CopyMagickString(image->filename,write_info->filename, 1017 MagickPathExtent); 1018 domain=CoderPolicyDomain; 1019 rights=WritePolicyRights; 1020 if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse) 1021 { 1022 sans_exception=DestroyExceptionInfo(sans_exception); 1023 write_info=DestroyImageInfo(write_info); 1024 errno=EPERM; 1025 ThrowBinaryException(PolicyError,"NotAuthorized",filename); 1026 } 1027 /* 1028 Call appropriate image writer based on image type. 1029 */ 1030 magick_info=GetMagickInfo(write_info->magick,sans_exception); 1031 sans_exception=DestroyExceptionInfo(sans_exception); 1032 if (magick_info != (const MagickInfo *) NULL) 1033 { 1034 if (GetMagickEndianSupport(magick_info) == MagickFalse) 1035 image->endian=UndefinedEndian; 1036 else 1037 if ((image_info->endian == UndefinedEndian) && 1038 (GetMagickRawSupport(magick_info) != MagickFalse)) 1039 { 1040 unsigned long 1041 lsb_first; 1042 1043 lsb_first=1; 1044 image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian; 1045 } 1046 } 1047 (void) SyncImageProfiles(image); 1048 DisassociateImageStream(image); 1049 option=GetImageOption(image_info,"delegate:bimodal"); 1050 if ((IsStringTrue(option) != MagickFalse) && 1051 (write_info->page == (char *) NULL) && 1052 (GetPreviousImageInList(image) == (Image *) NULL) && 1053 (GetNextImageInList(image) == (Image *) NULL) && 1054 (IsTaintImage(image) == MagickFalse) ) 1055 { 1056 delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception); 1057 if ((delegate_info != (const DelegateInfo *) NULL) && 1058 (GetDelegateMode(delegate_info) == 0) && 1059 (IsPathAccessible(image->magick_filename) != MagickFalse)) 1060 { 1061 /* 1062 Process image with bi-modal delegate. 1063 */ 1064 (void) CopyMagickString(image->filename,image->magick_filename, 1065 MagickPathExtent); 1066 status=InvokeDelegate(write_info,image,image->magick, 1067 write_info->magick,exception); 1068 write_info=DestroyImageInfo(write_info); 1069 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 1070 return(status); 1071 } 1072 } 1073 status=MagickFalse; 1074 temporary=MagickFalse; 1075 if ((magick_info != (const MagickInfo *) NULL) && 1076 (GetMagickSeekableStream(magick_info) != MagickFalse)) 1077 { 1078 char 1079 image_filename[MagickPathExtent]; 1080 1081 (void) CopyMagickString(image_filename,image->filename,MagickPathExtent); 1082 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 1083 (void) CopyMagickString(image->filename, image_filename,MagickPathExtent); 1084 if (status != MagickFalse) 1085 { 1086 if (IsBlobSeekable(image) == MagickFalse) 1087 { 1088 /* 1089 A seekable stream is required by the encoder. 1090 */ 1091 write_info->adjoin=MagickTrue; 1092 (void) CopyMagickString(write_info->filename,image->filename, 1093 MagickPathExtent); 1094 (void) AcquireUniqueFilename(image->filename); 1095 temporary=MagickTrue; 1096 } 1097 (void) CloseBlob(image); 1098 } 1099 } 1100 if ((magick_info != (const MagickInfo *) NULL) && 1101 (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL)) 1102 { 1103 /* 1104 Call appropriate image writer based on image type. 1105 */ 1106 if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse) 1107 LockSemaphoreInfo(magick_info->semaphore); 1108 status=GetImageEncoder(magick_info)(write_info,image,exception); 1109 if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse) 1110 UnlockSemaphoreInfo(magick_info->semaphore); 1111 } 1112 else 1113 { 1114 delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception); 1115 if (delegate_info != (DelegateInfo *) NULL) 1116 { 1117 /* 1118 Process the image with delegate. 1119 */ 1120 *write_info->filename='\0'; 1121 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 1122 LockSemaphoreInfo(delegate_info->semaphore); 1123 status=InvokeDelegate(write_info,image,(char *) NULL, 1124 write_info->magick,exception); 1125 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 1126 UnlockSemaphoreInfo(delegate_info->semaphore); 1127 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 1128 } 1129 else 1130 { 1131 sans_exception=AcquireExceptionInfo(); 1132 magick_info=GetMagickInfo(write_info->magick,sans_exception); 1133 sans_exception=DestroyExceptionInfo(sans_exception); 1134 if ((write_info->affirm == MagickFalse) && 1135 (magick_info == (const MagickInfo *) NULL)) 1136 { 1137 (void) CopyMagickString(write_info->magick,image->magick, 1138 MagickPathExtent); 1139 magick_info=GetMagickInfo(write_info->magick,exception); 1140 } 1141 if ((magick_info == (const MagickInfo *) NULL) || 1142 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 1143 { 1144 char 1145 extension[MagickPathExtent]; 1146 1147 GetPathComponent(image->filename,ExtensionPath,extension); 1148 if (*extension != '\0') 1149 magick_info=GetMagickInfo(extension,exception); 1150 else 1151 magick_info=GetMagickInfo(image->magick,exception); 1152 (void) CopyMagickString(image->filename,filename, 1153 MagickPathExtent); 1154 } 1155 if ((magick_info == (const MagickInfo *) NULL) || 1156 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 1157 { 1158 magick_info=GetMagickInfo(image->magick,exception); 1159 if ((magick_info == (const MagickInfo *) NULL) || 1160 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 1161 (void) ThrowMagickException(exception,GetMagickModule(), 1162 MissingDelegateError,"NoEncodeDelegateForThisImageFormat", 1163 "`%s'",write_info->magick); 1164 else 1165 (void) ThrowMagickException(exception,GetMagickModule(), 1166 MissingDelegateWarning,"NoEncodeDelegateForThisImageFormat", 1167 "`%s'",write_info->magick); 1168 } 1169 if ((magick_info != (const MagickInfo *) NULL) && 1170 (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL)) 1171 { 1172 /* 1173 Call appropriate image writer based on image type. 1174 */ 1175 if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse) 1176 LockSemaphoreInfo(magick_info->semaphore); 1177 status=GetImageEncoder(magick_info)(write_info,image,exception); 1178 if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse) 1179 UnlockSemaphoreInfo(magick_info->semaphore); 1180 } 1181 } 1182 } 1183 if (temporary != MagickFalse) 1184 { 1185 /* 1186 Copy temporary image file to permanent. 1187 */ 1188 status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception); 1189 if (status != MagickFalse) 1190 { 1191 (void) RelinquishUniqueFileResource(write_info->filename); 1192 status=ImageToFile(image,write_info->filename,exception); 1193 } 1194 (void) CloseBlob(image); 1195 (void) RelinquishUniqueFileResource(image->filename); 1196 (void) CopyMagickString(image->filename,write_info->filename, 1197 MagickPathExtent); 1198 } 1199 if ((LocaleCompare(write_info->magick,"info") != 0) && 1200 (write_info->verbose != MagickFalse)) 1201 (void) IdentifyImage(image,stdout,MagickFalse,exception); 1202 write_info=DestroyImageInfo(write_info); 1203 return(status); 1204 } 1205 1206 /* 1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1209 % % 1210 % % 1211 % % 1212 % W r i t e I m a g e s % 1213 % % 1214 % % 1215 % % 1216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1217 % 1218 % WriteImages() writes an image sequence into one or more files. While 1219 % WriteImage() can write an image sequence, it is limited to writing 1220 % the sequence into a single file using a format which supports multiple 1221 % frames. WriteImages(), however, does not have this limitation, instead it 1222 % generates multiple output files if necessary (or when requested). When 1223 % ImageInfo's adjoin flag is set to MagickFalse, the file name is expected 1224 % to include a printf-style formatting string for the frame number (e.g. 1225 % "image%02d.png"). 1226 % 1227 % The format of the WriteImages method is: 1228 % 1229 % MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images, 1230 % const char *filename,ExceptionInfo *exception) 1231 % 1232 % A description of each parameter follows: 1233 % 1234 % o image_info: the image info. 1235 % 1236 % o images: the image list. 1237 % 1238 % o filename: the image filename. 1239 % 1240 % o exception: return any errors or warnings in this structure. 1241 % 1242 */ 1243 MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info, 1244 Image *images,const char *filename,ExceptionInfo *exception) 1245 { 1246 #define WriteImageTag "Write/Image" 1247 1248 ExceptionInfo 1249 *sans_exception; 1250 1251 ImageInfo 1252 *write_info; 1253 1254 MagickBooleanType 1255 proceed; 1256 1257 MagickOffsetType 1258 progress; 1259 1260 MagickProgressMonitor 1261 progress_monitor; 1262 1263 MagickSizeType 1264 number_images; 1265 1266 MagickStatusType 1267 status; 1268 1269 register Image 1270 *p; 1271 1272 assert(image_info != (const ImageInfo *) NULL); 1273 assert(image_info->signature == MagickCoreSignature); 1274 assert(images != (Image *) NULL); 1275 assert(images->signature == MagickCoreSignature); 1276 if (images->debug != MagickFalse) 1277 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1278 assert(exception != (ExceptionInfo *) NULL); 1279 write_info=CloneImageInfo(image_info); 1280 *write_info->magick='\0'; 1281 images=GetFirstImageInList(images); 1282 if (filename != (const char *) NULL) 1283 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 1284 (void) CopyMagickString(p->filename,filename,MagickPathExtent); 1285 (void) CopyMagickString(write_info->filename,images->filename, 1286 MagickPathExtent); 1287 sans_exception=AcquireExceptionInfo(); 1288 (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images), 1289 sans_exception); 1290 sans_exception=DestroyExceptionInfo(sans_exception); 1291 if (*write_info->magick == '\0') 1292 (void) CopyMagickString(write_info->magick,images->magick,MagickPathExtent); 1293 p=images; 1294 for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p)) 1295 { 1296 register Image 1297 *next; 1298 1299 next=GetNextImageInList(p); 1300 if (next == (Image *) NULL) 1301 break; 1302 if (p->scene >= next->scene) 1303 { 1304 register ssize_t 1305 i; 1306 1307 /* 1308 Generate consistent scene numbers. 1309 */ 1310 i=(ssize_t) images->scene; 1311 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 1312 p->scene=(size_t) i++; 1313 break; 1314 } 1315 } 1316 /* 1317 Write images. 1318 */ 1319 status=MagickTrue; 1320 progress_monitor=(MagickProgressMonitor) NULL; 1321 progress=0; 1322 number_images=GetImageListLength(images); 1323 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 1324 { 1325 if (number_images != 1) 1326 progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL, 1327 p->client_data); 1328 status&=WriteImage(write_info,p,exception); 1329 if (number_images != 1) 1330 (void) SetImageProgressMonitor(p,progress_monitor,p->client_data); 1331 if (write_info->adjoin != MagickFalse) 1332 break; 1333 if (number_images != 1) 1334 { 1335 proceed=SetImageProgress(p,WriteImageTag,progress++,number_images); 1336 if (proceed == MagickFalse) 1337 break; 1338 } 1339 } 1340 write_info=DestroyImageInfo(write_info); 1341 return(status != 0 ? MagickTrue : MagickFalse); 1342 } 1343