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