|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % CCCC OOO N N SSSSS TTTTT IIIII TTTTT U U TTTTT EEEEE % 00007 % C O O NN N SS T I T U U T E % 00008 % C O O N N N ESSS T I T U U T EEE % 00009 % C O O N NN SS T I T U U T E % 00010 % CCCC OOO N N SSSSS T IIIII T UUU T EEEEE % 00011 % % 00012 % % 00013 % MagickCore Methods to Consitute an Image % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % October 1998 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "MagickCore/studio.h" 00043 #include "MagickCore/blob.h" 00044 #include "MagickCore/blob-private.h" 00045 #include "MagickCore/exception.h" 00046 #include "MagickCore/exception-private.h" 00047 #include "MagickCore/cache.h" 00048 #include "MagickCore/client.h" 00049 #include "MagickCore/constitute.h" 00050 #include "MagickCore/constitute-private.h" 00051 #include "MagickCore/delegate.h" 00052 #include "MagickCore/geometry.h" 00053 #include "MagickCore/identify.h" 00054 #include "MagickCore/image-private.h" 00055 #include "MagickCore/list.h" 00056 #include "MagickCore/magick.h" 00057 #include "MagickCore/memory_.h" 00058 #include "MagickCore/monitor.h" 00059 #include "MagickCore/monitor-private.h" 00060 #include "MagickCore/option.h" 00061 #include "MagickCore/pixel.h" 00062 #include "MagickCore/pixel-accessor.h" 00063 #include "MagickCore/policy.h" 00064 #include "MagickCore/profile.h" 00065 #include "MagickCore/profile-private.h" 00066 #include "MagickCore/property.h" 00067 #include "MagickCore/quantum.h" 00068 #include "MagickCore/resize.h" 00069 #include "MagickCore/resource_.h" 00070 #include "MagickCore/semaphore.h" 00071 #include "MagickCore/statistic.h" 00072 #include "MagickCore/stream.h" 00073 #include "MagickCore/string_.h" 00074 #include "MagickCore/string-private.h" 00075 #include "MagickCore/timer.h" 00076 #include "MagickCore/transform.h" 00077 #include "MagickCore/utility.h" 00078 #include "MagickCore/utility-private.h" 00079 00080 static SemaphoreInfo 00081 *constitute_semaphore = (SemaphoreInfo *) NULL; 00082 00083 /* 00084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00085 % % 00086 % % 00087 % % 00088 + C o n s t i t u t e C o m p o n e n t G e n e s i s % 00089 % % 00090 % % 00091 % % 00092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00093 % 00094 % ConstituteComponentGenesis() instantiates the constitute component. 00095 % 00096 % The format of the ConstituteComponentGenesis method is: 00097 % 00098 % MagickBooleanType ConstituteComponentGenesis(void) 00099 % 00100 */ 00101 MagickPrivate MagickBooleanType ConstituteComponentGenesis(void) 00102 { 00103 AcquireSemaphoreInfo(&constitute_semaphore); 00104 return(MagickTrue); 00105 } 00106 00107 /* 00108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00109 % % 00110 % % 00111 % % 00112 + C o n s t i t u t e C o m p o n e n t T e r m i n u s % 00113 % % 00114 % % 00115 % % 00116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00117 % 00118 % ConstituteComponentTerminus() destroys the constitute component. 00119 % 00120 % The format of the ConstituteComponentTerminus method is: 00121 % 00122 % ConstituteComponentTerminus(void) 00123 % 00124 */ 00125 MagickPrivate void ConstituteComponentTerminus(void) 00126 { 00127 if (constitute_semaphore == (SemaphoreInfo *) NULL) 00128 AcquireSemaphoreInfo(&constitute_semaphore); 00129 DestroySemaphoreInfo(&constitute_semaphore); 00130 } 00131 00132 /* 00133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00134 % % 00135 % % 00136 % % 00137 % C o n s t i t u t e I m a g e % 00138 % % 00139 % % 00140 % % 00141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00142 % 00143 % ConstituteImage() returns an image from the pixel data you supply. 00144 % The pixel data must be in scanline order top-to-bottom. The data can be 00145 % char, short int, int, float, or double. Float and double require the 00146 % pixels to be normalized [0..1], otherwise [0..QuantumRange]. For example, to 00147 % create a 640x480 image from unsigned red-green-blue character data, use: 00148 % 00149 % image = ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception); 00150 % 00151 % The format of the ConstituteImage method is: 00152 % 00153 % Image *ConstituteImage(const size_t columns,const size_t rows, 00154 % const char *map,const StorageType storage,const void *pixels, 00155 % ExceptionInfo *exception) 00156 % 00157 % A description of each parameter follows: 00158 % 00159 % o columns: width in pixels of the image. 00160 % 00161 % o rows: height in pixels of the image. 00162 % 00163 % o map: This string reflects the expected ordering of the pixel array. 00164 % It can be any combination or order of R = red, G = green, B = blue, 00165 % A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan, 00166 % Y = yellow, M = magenta, K = black, I = intensity (for grayscale), 00167 % P = pad. 00168 % 00169 % o storage: Define the data type of the pixels. Float and double types are 00170 % expected to be normalized [0..1] otherwise [0..QuantumRange]. Choose 00171 % from these types: CharPixel, DoublePixel, FloatPixel, IntegerPixel, 00172 % LongPixel, QuantumPixel, or ShortPixel. 00173 % 00174 % o pixels: This array of values contain the pixel components as defined by 00175 % map and type. You must preallocate this array where the expected 00176 % length varies depending on the values of width, height, map, and type. 00177 % 00178 % o exception: return any errors or warnings in this structure. 00179 % 00180 */ 00181 MagickExport Image *ConstituteImage(const size_t columns, 00182 const size_t rows,const char *map,const StorageType storage, 00183 const void *pixels,ExceptionInfo *exception) 00184 { 00185 Image 00186 *image; 00187 00188 MagickBooleanType 00189 status; 00190 00191 /* 00192 Allocate image structure. 00193 */ 00194 assert(map != (const char *) NULL); 00195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map); 00196 assert(pixels != (void *) NULL); 00197 assert(exception != (ExceptionInfo *) NULL); 00198 assert(exception->signature == MagickSignature); 00199 image=AcquireImage((ImageInfo *) NULL,exception); 00200 if (image == (Image *) NULL) 00201 return((Image *) NULL); 00202 if ((columns == 0) || (rows == 0)) 00203 ThrowImageException(OptionError,"NonZeroWidthAndHeightRequired"); 00204 image->columns=columns; 00205 image->rows=rows; 00206 (void) SetImageBackgroundColor(image,exception); 00207 status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels,exception); 00208 if (status == MagickFalse) 00209 image=DestroyImage(image); 00210 return(image); 00211 } 00212 00213 /* 00214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00215 % % 00216 % % 00217 % % 00218 % P i n g I m a g e % 00219 % % 00220 % % 00221 % % 00222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00223 % 00224 % PingImage() returns all the properties of an image or image sequence 00225 % except for the pixels. It is much faster and consumes far less memory 00226 % than ReadImage(). On failure, a NULL image is returned and exception 00227 % describes the reason for the failure. 00228 % 00229 % The format of the PingImage method is: 00230 % 00231 % Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception) 00232 % 00233 % A description of each parameter follows: 00234 % 00235 % o image_info: Ping the image defined by the file or filename members of 00236 % this structure. 00237 % 00238 % o exception: return any errors or warnings in this structure. 00239 % 00240 */ 00241 00242 #if defined(__cplusplus) || defined(c_plusplus) 00243 extern "C" { 00244 #endif 00245 00246 static size_t PingStream(const Image *magick_unused(image), 00247 const void *magick_unused(pixels),const size_t columns) 00248 { 00249 return(columns); 00250 } 00251 00252 #if defined(__cplusplus) || defined(c_plusplus) 00253 } 00254 #endif 00255 00256 MagickExport Image *PingImage(const ImageInfo *image_info, 00257 ExceptionInfo *exception) 00258 { 00259 Image 00260 *image; 00261 00262 ImageInfo 00263 *ping_info; 00264 00265 assert(image_info != (ImageInfo *) NULL); 00266 assert(image_info->signature == MagickSignature); 00267 if (image_info->debug != MagickFalse) 00268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00269 image_info->filename); 00270 assert(exception != (ExceptionInfo *) NULL); 00271 ping_info=CloneImageInfo(image_info); 00272 ping_info->ping=MagickTrue; 00273 image=ReadStream(ping_info,&PingStream,exception); 00274 if (image != (Image *) NULL) 00275 { 00276 ResetTimer(&image->timer); 00277 if (ping_info->verbose != MagickFalse) 00278 (void) IdentifyImage(image,stdout,MagickFalse,exception); 00279 } 00280 ping_info=DestroyImageInfo(ping_info); 00281 return(image); 00282 } 00283 00284 /* 00285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00286 % % 00287 % % 00288 % % 00289 % P i n g I m a g e s % 00290 % % 00291 % % 00292 % % 00293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00294 % 00295 % PingImages() pings one or more images and returns them as an image list. 00296 % 00297 % The format of the PingImage method is: 00298 % 00299 % Image *PingImages(const ImageInfo *image_info,ExceptionInfo *exception) 00300 % 00301 % A description of each parameter follows: 00302 % 00303 % o image_info: the image info. 00304 % 00305 % o exception: return any errors or warnings in this structure. 00306 % 00307 */ 00308 MagickExport Image *PingImages(const ImageInfo *image_info, 00309 ExceptionInfo *exception) 00310 { 00311 char 00312 filename[MaxTextExtent]; 00313 00314 Image 00315 *image, 00316 *images; 00317 00318 ImageInfo 00319 *read_info; 00320 00321 /* 00322 Ping image list from a file. 00323 */ 00324 assert(image_info != (ImageInfo *) NULL); 00325 assert(image_info->signature == MagickSignature); 00326 if (image_info->debug != MagickFalse) 00327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00328 image_info->filename); 00329 assert(exception != (ExceptionInfo *) NULL); 00330 (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename, 00331 (int) image_info->scene,filename,exception); 00332 if (LocaleCompare(filename,image_info->filename) != 0) 00333 { 00334 ExceptionInfo 00335 *sans; 00336 00337 ssize_t 00338 extent, 00339 scene; 00340 00341 /* 00342 Images of the form image-%d.png[1-5]. 00343 */ 00344 read_info=CloneImageInfo(image_info); 00345 sans=AcquireExceptionInfo(); 00346 (void) SetImageInfo(read_info,0,sans); 00347 sans=DestroyExceptionInfo(sans); 00348 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 00349 images=NewImageList(); 00350 extent=(ssize_t) (read_info->scene+read_info->number_scenes); 00351 for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++) 00352 { 00353 (void) InterpretImageFilename(image_info,(Image *) NULL,filename,(int) 00354 scene,read_info->filename,exception); 00355 image=PingImage(read_info,exception); 00356 if (image == (Image *) NULL) 00357 continue; 00358 AppendImageToList(&images,image); 00359 } 00360 read_info=DestroyImageInfo(read_info); 00361 return(images); 00362 } 00363 return(PingImage(image_info,exception)); 00364 } 00365 00366 /* 00367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00368 % % 00369 % % 00370 % % 00371 % R e a d I m a g e % 00372 % % 00373 % % 00374 % % 00375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00376 % 00377 % ReadImage() reads an image or image sequence from a file or file handle. 00378 % The method returns a NULL if there is a memory shortage or if the image 00379 % cannot be read. On failure, a NULL image is returned and exception 00380 % describes the reason for the failure. 00381 % 00382 % The format of the ReadImage method is: 00383 % 00384 % Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception) 00385 % 00386 % A description of each parameter follows: 00387 % 00388 % o image_info: Read the image defined by the file or filename members of 00389 % this structure. 00390 % 00391 % o exception: return any errors or warnings in this structure. 00392 % 00393 */ 00394 MagickExport Image *ReadImage(const ImageInfo *image_info, 00395 ExceptionInfo *exception) 00396 { 00397 char 00398 filename[MaxTextExtent], 00399 magick[MaxTextExtent], 00400 magick_filename[MaxTextExtent]; 00401 00402 const char 00403 *value; 00404 00405 const DelegateInfo 00406 *delegate_info; 00407 00408 const MagickInfo 00409 *magick_info; 00410 00411 ExceptionInfo 00412 *sans_exception; 00413 00414 GeometryInfo 00415 geometry_info; 00416 00417 Image 00418 *image, 00419 *next; 00420 00421 ImageInfo 00422 *read_info; 00423 00424 MagickStatusType 00425 flags, 00426 thread_support; 00427 00428 PolicyDomain 00429 domain; 00430 00431 PolicyRights 00432 rights; 00433 00434 /* 00435 Determine image type from filename prefix or suffix (e.g. image.jpg). 00436 */ 00437 assert(image_info != (ImageInfo *) NULL); 00438 assert(image_info->signature == MagickSignature); 00439 assert(image_info->filename != (char *) NULL); 00440 if (image_info->debug != MagickFalse) 00441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00442 image_info->filename); 00443 assert(exception != (ExceptionInfo *) NULL); 00444 read_info=CloneImageInfo(image_info); 00445 (void) CopyMagickString(magick_filename,read_info->filename,MaxTextExtent); 00446 (void) SetImageInfo(read_info,0,exception); 00447 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 00448 (void) CopyMagickString(magick,read_info->magick,MaxTextExtent); 00449 domain=CoderPolicyDomain; 00450 rights=ReadPolicyRights; 00451 if (IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse) 00452 { 00453 errno=EPERM; 00454 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 00455 "NotAuthorized","`%s'",read_info->filename); 00456 return((Image *) NULL); 00457 } 00458 /* 00459 Call appropriate image reader based on image type. 00460 */ 00461 sans_exception=AcquireExceptionInfo(); 00462 magick_info=GetMagickInfo(read_info->magick,sans_exception); 00463 sans_exception=DestroyExceptionInfo(sans_exception); 00464 if (magick_info != (const MagickInfo *) NULL) 00465 { 00466 if (GetMagickEndianSupport(magick_info) == MagickFalse) 00467 read_info->endian=UndefinedEndian; 00468 else 00469 if ((image_info->endian == UndefinedEndian) && 00470 (GetMagickRawSupport(magick_info) != MagickFalse)) 00471 { 00472 size_t 00473 lsb_first; 00474 00475 lsb_first=1; 00476 read_info->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : 00477 MSBEndian; 00478 } 00479 } 00480 if ((magick_info != (const MagickInfo *) NULL) && 00481 (GetMagickSeekableStream(magick_info) != MagickFalse)) 00482 { 00483 MagickBooleanType 00484 status; 00485 00486 image=AcquireImage(read_info,exception); 00487 (void) CopyMagickString(image->filename,read_info->filename, 00488 MaxTextExtent); 00489 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 00490 if (status == MagickFalse) 00491 { 00492 read_info=DestroyImageInfo(read_info); 00493 image=DestroyImage(image); 00494 return((Image *) NULL); 00495 } 00496 if (IsBlobSeekable(image) == MagickFalse) 00497 { 00498 /* 00499 Coder requires a seekable stream. 00500 */ 00501 *read_info->filename='\0'; 00502 status=ImageToFile(image,read_info->filename,exception); 00503 if (status == MagickFalse) 00504 { 00505 (void) CloseBlob(image); 00506 read_info=DestroyImageInfo(read_info); 00507 image=DestroyImage(image); 00508 return((Image *) NULL); 00509 } 00510 read_info->temporary=MagickTrue; 00511 } 00512 (void) CloseBlob(image); 00513 image=DestroyImage(image); 00514 } 00515 image=NewImageList(); 00516 if (constitute_semaphore == (SemaphoreInfo *) NULL) 00517 AcquireSemaphoreInfo(&constitute_semaphore); 00518 if ((magick_info != (const MagickInfo *) NULL) && 00519 (GetImageDecoder(magick_info) != (DecodeImageHandler *) NULL)) 00520 { 00521 thread_support=GetMagickThreadSupport(magick_info); 00522 if ((thread_support & DecoderThreadSupport) == 0) 00523 LockSemaphoreInfo(constitute_semaphore); 00524 image=GetImageDecoder(magick_info)(read_info,exception); 00525 if ((thread_support & DecoderThreadSupport) == 0) 00526 UnlockSemaphoreInfo(constitute_semaphore); 00527 } 00528 else 00529 { 00530 delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception); 00531 if (delegate_info == (const DelegateInfo *) NULL) 00532 { 00533 (void) ThrowMagickException(exception,GetMagickModule(), 00534 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", 00535 read_info->filename); 00536 if (read_info->temporary != MagickFalse) 00537 (void) RelinquishUniqueFileResource(read_info->filename); 00538 read_info=DestroyImageInfo(read_info); 00539 return((Image *) NULL); 00540 } 00541 /* 00542 Let our decoding delegate process the image. 00543 */ 00544 image=AcquireImage(read_info,exception); 00545 if (image == (Image *) NULL) 00546 { 00547 read_info=DestroyImageInfo(read_info); 00548 return((Image *) NULL); 00549 } 00550 (void) CopyMagickString(image->filename,read_info->filename, 00551 MaxTextExtent); 00552 *read_info->filename='\0'; 00553 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 00554 LockSemaphoreInfo(constitute_semaphore); 00555 (void) InvokeDelegate(read_info,image,read_info->magick,(char *) NULL, 00556 exception); 00557 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 00558 UnlockSemaphoreInfo(constitute_semaphore); 00559 image=DestroyImageList(image); 00560 read_info->temporary=MagickTrue; 00561 (void) SetImageInfo(read_info,0,exception); 00562 magick_info=GetMagickInfo(read_info->magick,exception); 00563 if ((magick_info == (const MagickInfo *) NULL) || 00564 (GetImageDecoder(magick_info) == (DecodeImageHandler *) NULL)) 00565 { 00566 if (IsPathAccessible(read_info->filename) != MagickFalse) 00567 (void) ThrowMagickException(exception,GetMagickModule(), 00568 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", 00569 read_info->filename); 00570 else 00571 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 00572 read_info->filename); 00573 read_info=DestroyImageInfo(read_info); 00574 return((Image *) NULL); 00575 } 00576 thread_support=GetMagickThreadSupport(magick_info); 00577 if ((thread_support & DecoderThreadSupport) == 0) 00578 LockSemaphoreInfo(constitute_semaphore); 00579 image=(Image *) (GetImageDecoder(magick_info))(read_info,exception); 00580 if ((thread_support & DecoderThreadSupport) == 0) 00581 UnlockSemaphoreInfo(constitute_semaphore); 00582 } 00583 if (read_info->temporary != MagickFalse) 00584 { 00585 (void) RelinquishUniqueFileResource(read_info->filename); 00586 read_info->temporary=MagickFalse; 00587 if (image != (Image *) NULL) 00588 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 00589 } 00590 if (image == (Image *) NULL) 00591 { 00592 read_info=DestroyImageInfo(read_info); 00593 return(image); 00594 } 00595 if (exception->severity >= ErrorException) 00596 (void) LogMagickEvent(ExceptionEvent,GetMagickModule(), 00597 "Coder (%s) generated an image despite an error (%d), " 00598 "notify the developers",image->magick,exception->severity); 00599 if (IsBlobTemporary(image) != MagickFalse) 00600 (void) RelinquishUniqueFileResource(read_info->filename); 00601 if ((GetNextImageInList(image) != (Image *) NULL) && 00602 (IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse)) 00603 { 00604 Image 00605 *clones; 00606 00607 clones=CloneImages(image,read_info->scenes,exception); 00608 if (clones == (Image *) NULL) 00609 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00610 "SubimageSpecificationReturnsNoImages","`%s'",read_info->filename); 00611 else 00612 { 00613 image=DestroyImageList(image); 00614 image=GetFirstImageInList(clones); 00615 } 00616 } 00617 if (GetBlobError(image) != MagickFalse) 00618 { 00619 ThrowFileException(exception,FileOpenError, 00620 "AnErrorHasOccurredReadingFromFile",read_info->filename); 00621 image=DestroyImageList(image); 00622 read_info=DestroyImageInfo(read_info); 00623 return((Image *) NULL); 00624 } 00625 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) 00626 { 00627 char 00628 magick_path[MaxTextExtent], 00629 *property, 00630 timestamp[MaxTextExtent]; 00631 00632 const char 00633 *option; 00634 00635 const StringInfo 00636 *profile; 00637 00638 next->taint=MagickFalse; 00639 GetPathComponent(magick_filename,MagickPath,magick_path); 00640 if (*magick_path == '\0') 00641 (void) CopyMagickString(next->magick,magick,MaxTextExtent); 00642 (void) CopyMagickString(next->magick_filename,magick_filename, 00643 MaxTextExtent); 00644 if (IsBlobTemporary(image) != MagickFalse) 00645 (void) CopyMagickString(next->filename,filename,MaxTextExtent); 00646 if (next->magick_columns == 0) 00647 next->magick_columns=next->columns; 00648 if (next->magick_rows == 0) 00649 next->magick_rows=next->rows; 00650 value=GetImageProperty(next,"tiff:Orientation",exception); 00651 if (value == (char *) NULL) 00652 value=GetImageProperty(next,"exif:Orientation",exception); 00653 if (value != (char *) NULL) 00654 { 00655 next->orientation=(OrientationType) StringToLong(value); 00656 (void) DeleteImageProperty(next,"tiff:Orientation"); 00657 (void) DeleteImageProperty(next,"exif:Orientation"); 00658 } 00659 value=GetImageProperty(next,"exif:XResolution",exception); 00660 if (value != (char *) NULL) 00661 { 00662 geometry_info.rho=next->resolution.x; 00663 geometry_info.sigma=1.0; 00664 flags=ParseGeometry(value,&geometry_info); 00665 if (geometry_info.sigma != 0) 00666 next->resolution.x=geometry_info.rho/geometry_info.sigma; 00667 (void) DeleteImageProperty(next,"exif:XResolution"); 00668 } 00669 value=GetImageProperty(next,"exif:YResolution",exception); 00670 if (value != (char *) NULL) 00671 { 00672 geometry_info.rho=next->resolution.y; 00673 geometry_info.sigma=1.0; 00674 flags=ParseGeometry(value,&geometry_info); 00675 if (geometry_info.sigma != 0) 00676 next->resolution.y=geometry_info.rho/geometry_info.sigma; 00677 (void) DeleteImageProperty(next,"exif:YResolution"); 00678 } 00679 value=GetImageProperty(next,"tiff:ResolutionUnit",exception); 00680 if (value == (char *) NULL) 00681 value=GetImageProperty(next,"exif:ResolutionUnit",exception); 00682 if (value != (char *) NULL) 00683 { 00684 next->units=(ResolutionType) (StringToLong(value)-1); 00685 (void) DeleteImageProperty(next,"exif:ResolutionUnit"); 00686 (void) DeleteImageProperty(next,"tiff:ResolutionUnit"); 00687 } 00688 if (next->page.width == 0) 00689 next->page.width=next->columns; 00690 if (next->page.height == 0) 00691 next->page.height=next->rows; 00692 option=GetImageOption(read_info,"caption"); 00693 if (option != (const char *) NULL) 00694 { 00695 property=InterpretImageProperties(read_info,next,option,exception); 00696 (void) SetImageProperty(next,"caption",property,exception); 00697 property=DestroyString(property); 00698 } 00699 option=GetImageOption(read_info,"comment"); 00700 if (option != (const char *) NULL) 00701 { 00702 property=InterpretImageProperties(read_info,next,option,exception); 00703 (void) SetImageProperty(next,"comment",property,exception); 00704 property=DestroyString(property); 00705 } 00706 option=GetImageOption(read_info,"label"); 00707 if (option != (const char *) NULL) 00708 { 00709 property=InterpretImageProperties(read_info,next,option,exception); 00710 (void) SetImageProperty(next,"label",property,exception); 00711 property=DestroyString(property); 00712 } 00713 if (LocaleCompare(next->magick,"TEXT") == 0) 00714 (void) ParseAbsoluteGeometry("0x0+0+0",&next->page); 00715 if ((read_info->extract != (char *) NULL) && 00716 (read_info->stream == (StreamHandler) NULL)) 00717 { 00718 RectangleInfo 00719 geometry; 00720 00721 flags=ParseAbsoluteGeometry(read_info->extract,&geometry); 00722 if ((next->columns != geometry.width) || 00723 (next->rows != geometry.height)) 00724 { 00725 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 00726 { 00727 Image 00728 *crop_image; 00729 00730 crop_image=CropImage(next,&geometry,exception); 00731 if (crop_image != (Image *) NULL) 00732 ReplaceImageInList(&next,crop_image); 00733 } 00734 else 00735 if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) 00736 { 00737 Image 00738 *size_image; 00739 00740 flags=ParseRegionGeometry(next,read_info->extract,&geometry, 00741 exception); 00742 size_image=ResizeImage(next,geometry.width,geometry.height, 00743 next->filter,next->blur,exception); 00744 if (size_image != (Image *) NULL) 00745 ReplaceImageInList(&next,size_image); 00746 } 00747 } 00748 } 00749 profile=GetImageProfile(next,"icc"); 00750 if (profile == (const StringInfo *) NULL) 00751 profile=GetImageProfile(next,"icm"); 00752 profile=GetImageProfile(next,"iptc"); 00753 if (profile == (const StringInfo *) NULL) 00754 profile=GetImageProfile(next,"8bim"); 00755 (void) FormatMagickTime(GetBlobProperties(next)->st_mtime,MaxTextExtent, 00756 timestamp); 00757 (void) SetImageProperty(next,"date:modify",timestamp,exception); 00758 (void) FormatMagickTime(GetBlobProperties(next)->st_ctime,MaxTextExtent, 00759 timestamp); 00760 (void) SetImageProperty(next,"date:create",timestamp,exception); 00761 option=GetImageOption(image_info,"delay"); 00762 if (option != (const char *) NULL) 00763 { 00764 GeometryInfo 00765 geometry_info; 00766 00767 flags=ParseGeometry(option,&geometry_info); 00768 if ((flags & GreaterValue) != 0) 00769 { 00770 if (next->delay > (size_t) floor(geometry_info.rho+0.5)) 00771 next->delay=(size_t) floor(geometry_info.rho+0.5); 00772 } 00773 else 00774 if ((flags & LessValue) != 0) 00775 { 00776 if (next->delay < (size_t) floor(geometry_info.rho+0.5)) 00777 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 00778 } 00779 else 00780 next->delay=(size_t) floor(geometry_info.rho+0.5); 00781 if ((flags & SigmaValue) != 0) 00782 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 00783 } 00784 option=GetImageOption(image_info,"dispose"); 00785 if (option != (const char *) NULL) 00786 next->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions, 00787 MagickFalse,option); 00788 if (read_info->verbose != MagickFalse) 00789 (void) IdentifyImage(next,stderr,MagickFalse,exception); 00790 image=next; 00791 } 00792 read_info=DestroyImageInfo(read_info); 00793 return(GetFirstImageInList(image)); 00794 } 00795 00796 /* 00797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00798 % % 00799 % % 00800 % % 00801 % R e a d I m a g e s % 00802 % % 00803 % % 00804 % % 00805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00806 % 00807 % ReadImages() reads one or more images and returns them as an image list. 00808 % 00809 % The format of the ReadImage method is: 00810 % 00811 % Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception) 00812 % 00813 % A description of each parameter follows: 00814 % 00815 % o image_info: the image info. 00816 % 00817 % o exception: return any errors or warnings in this structure. 00818 % 00819 */ 00820 MagickExport Image *ReadImages(const ImageInfo *image_info, 00821 ExceptionInfo *exception) 00822 { 00823 char 00824 filename[MaxTextExtent]; 00825 00826 Image 00827 *image, 00828 *images; 00829 00830 ImageInfo 00831 *read_info; 00832 00833 /* 00834 Read image list from a file. 00835 */ 00836 assert(image_info != (ImageInfo *) NULL); 00837 assert(image_info->signature == MagickSignature); 00838 if (image_info->debug != MagickFalse) 00839 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00840 image_info->filename); 00841 assert(exception != (ExceptionInfo *) NULL); 00842 (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename, 00843 (int) image_info->scene,filename,exception); 00844 if (LocaleCompare(filename,image_info->filename) != 0) 00845 { 00846 ExceptionInfo 00847 *sans; 00848 00849 ssize_t 00850 extent, 00851 scene; 00852 00853 /* 00854 Images of the form image-%d.png[1-5]. 00855 */ 00856 read_info=CloneImageInfo(image_info); 00857 sans=AcquireExceptionInfo(); 00858 (void) SetImageInfo(read_info,0,sans); 00859 sans=DestroyExceptionInfo(sans); 00860 if (read_info->number_scenes == 0) 00861 { 00862 read_info=DestroyImageInfo(read_info); 00863 return(ReadImage(image_info,exception)); 00864 } 00865 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 00866 images=NewImageList(); 00867 extent=(ssize_t) (read_info->scene+read_info->number_scenes); 00868 for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++) 00869 { 00870 (void) InterpretImageFilename(image_info,(Image *) NULL,filename,(int) 00871 scene,read_info->filename,exception); 00872 image=ReadImage(read_info,exception); 00873 if (image == (Image *) NULL) 00874 continue; 00875 AppendImageToList(&images,image); 00876 } 00877 read_info=DestroyImageInfo(read_info); 00878 return(images); 00879 } 00880 return(ReadImage(image_info,exception)); 00881 } 00882 00883 /* 00884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00885 % % 00886 % % 00887 % % 00888 + R e a d I n l i n e I m a g e % 00889 % % 00890 % % 00891 % % 00892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00893 % 00894 % ReadInlineImage() reads a Base64-encoded inline image or image sequence. 00895 % The method returns a NULL if there is a memory shortage or if the image 00896 % cannot be read. On failure, a NULL image is returned and exception 00897 % describes the reason for the failure. 00898 % 00899 % The format of the ReadInlineImage method is: 00900 % 00901 % Image *ReadInlineImage(const ImageInfo *image_info,const char *content, 00902 % ExceptionInfo *exception) 00903 % 00904 % A description of each parameter follows: 00905 % 00906 % o image_info: the image info. 00907 % 00908 % o content: the image encoded in Base64. 00909 % 00910 % o exception: return any errors or warnings in this structure. 00911 % 00912 */ 00913 MagickExport Image *ReadInlineImage(const ImageInfo *image_info, 00914 const char *content,ExceptionInfo *exception) 00915 { 00916 Image 00917 *image; 00918 00919 ImageInfo 00920 *read_info; 00921 00922 unsigned char 00923 *blob; 00924 00925 size_t 00926 length; 00927 00928 register const char 00929 *p; 00930 00931 /* 00932 Skip over header (e.g. data:image/gif;base64,). 00933 */ 00934 image=NewImageList(); 00935 for (p=content; (*p != ',') && (*p != '\0'); p++) ; 00936 if (*p == '\0') 00937 ThrowReaderException(CorruptImageError,"CorruptImage"); 00938 p++; 00939 length=0; 00940 blob=Base64Decode(p,&length); 00941 if (length == 0) 00942 ThrowReaderException(CorruptImageError,"CorruptImage"); 00943 read_info=CloneImageInfo(image_info); 00944 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 00945 (void *) NULL); 00946 *read_info->filename='\0'; 00947 *read_info->magick='\0'; 00948 image=BlobToImage(read_info,blob,length,exception); 00949 blob=(unsigned char *) RelinquishMagickMemory(blob); 00950 read_info=DestroyImageInfo(read_info); 00951 return(image); 00952 } 00953 00954 /* 00955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00956 % % 00957 % % 00958 % % 00959 % W r i t e I m a g e % 00960 % % 00961 % % 00962 % % 00963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00964 % 00965 % WriteImage() writes an image or an image sequence to a file or file handle. 00966 % If writing to a file is on disk, the name is defined by the filename member 00967 % of the image structure. WriteImage() returns MagickFalse is there is a 00968 % memory shortage or if the image cannot be written. Check the exception 00969 % member of image to determine the cause for any failure. 00970 % 00971 % The format of the WriteImage method is: 00972 % 00973 % MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image, 00974 % ExceptionInfo *exception) 00975 % 00976 % A description of each parameter follows: 00977 % 00978 % o image_info: the image info. 00979 % 00980 % o image: the image. 00981 % 00982 % o exception: return any errors or warnings in this structure. 00983 % 00984 */ 00985 MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, 00986 Image *image,ExceptionInfo *exception) 00987 { 00988 char 00989 filename[MaxTextExtent]; 00990 00991 const char 00992 *option; 00993 00994 const DelegateInfo 00995 *delegate_info; 00996 00997 const MagickInfo 00998 *magick_info; 00999 01000 ExceptionInfo 01001 *sans_exception; 01002 01003 ImageInfo 01004 *write_info; 01005 01006 MagickBooleanType 01007 status, 01008 temporary; 01009 01010 MagickStatusType 01011 thread_support; 01012 01013 PolicyDomain 01014 domain; 01015 01016 PolicyRights 01017 rights; 01018 01019 /* 01020 Determine image type from filename prefix or suffix (e.g. image.jpg). 01021 */ 01022 assert(image_info != (ImageInfo *) NULL); 01023 assert(image_info->signature == MagickSignature); 01024 if (image->debug != MagickFalse) 01025 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 01026 image_info->filename); 01027 assert(image != (Image *) NULL); 01028 assert(image->signature == MagickSignature); 01029 assert(exception != (ExceptionInfo *) NULL); 01030 sans_exception=AcquireExceptionInfo(); 01031 write_info=CloneImageInfo(image_info); 01032 (void) CopyMagickString(write_info->filename,image->filename,MaxTextExtent); 01033 if (*write_info->magick == '\0') 01034 (void) CopyMagickString(write_info->magick,image->magick,MaxTextExtent); 01035 (void) SetImageInfo(write_info,1,sans_exception); 01036 (void) CopyMagickString(filename,image->filename,MaxTextExtent); 01037 (void) CopyMagickString(image->filename,write_info->filename,MaxTextExtent); 01038 domain=CoderPolicyDomain; 01039 rights=WritePolicyRights; 01040 if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse) 01041 { 01042 sans_exception=DestroyExceptionInfo(sans_exception); 01043 errno=EPERM; 01044 ThrowBinaryException(PolicyError,"NotAuthorized",filename); 01045 } 01046 magick_info=GetMagickInfo(write_info->magick,sans_exception); 01047 sans_exception=DestroyExceptionInfo(sans_exception); 01048 if (magick_info != (const MagickInfo *) NULL) 01049 { 01050 if (GetMagickEndianSupport(magick_info) == MagickFalse) 01051 image->endian=UndefinedEndian; 01052 else 01053 if ((image_info->endian == UndefinedEndian) && 01054 (GetMagickRawSupport(magick_info) != MagickFalse)) 01055 { 01056 size_t 01057 lsb_first; 01058 01059 lsb_first=1; 01060 image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian; 01061 } 01062 } 01063 (void) SyncImageProfiles(image); 01064 option=GetImageOption(image_info,"delegate:bimodal"); 01065 if ((option != (const char *) NULL) && 01066 (IsMagickTrue(option) != MagickFalse) && 01067 (write_info->page == (char *) NULL) && 01068 (GetPreviousImageInList(image) == (Image *) NULL) && 01069 (GetNextImageInList(image) == (Image *) NULL) && 01070 (IsTaintImage(image) == MagickFalse)) 01071 { 01072 delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception); 01073 if ((delegate_info != (const DelegateInfo *) NULL) && 01074 (GetDelegateMode(delegate_info) == 0) && 01075 (IsPathAccessible(image->magick_filename) != MagickFalse)) 01076 { 01077 /* 01078 Process image with bi-modal delegate. 01079 */ 01080 (void) CopyMagickString(image->filename,image->magick_filename, 01081 MaxTextExtent); 01082 status=InvokeDelegate(write_info,image,image->magick, 01083 write_info->magick,exception); 01084 write_info=DestroyImageInfo(write_info); 01085 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01086 return(status); 01087 } 01088 } 01089 status=MagickFalse; 01090 temporary=MagickFalse; 01091 if ((magick_info != (const MagickInfo *) NULL) && 01092 (GetMagickSeekableStream(magick_info) != MagickFalse)) 01093 { 01094 char 01095 filename[MaxTextExtent]; 01096 01097 (void) CopyMagickString(filename,image->filename,MaxTextExtent); 01098 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 01099 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01100 if (status != MagickFalse) 01101 { 01102 if (IsBlobSeekable(image) == MagickFalse) 01103 { 01104 /* 01105 A seekable stream is required by the encoder. 01106 */ 01107 write_info->adjoin=MagickTrue; 01108 (void) CopyMagickString(write_info->filename,image->filename, 01109 MaxTextExtent); 01110 (void) AcquireUniqueFilename(image->filename); 01111 temporary=MagickTrue; 01112 } 01113 (void) CloseBlob(image); 01114 } 01115 } 01116 if (constitute_semaphore == (SemaphoreInfo *) NULL) 01117 AcquireSemaphoreInfo(&constitute_semaphore); 01118 if ((magick_info != (const MagickInfo *) NULL) && 01119 (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL)) 01120 { 01121 /* 01122 Call appropriate image writer based on image type. 01123 */ 01124 thread_support=GetMagickThreadSupport(magick_info); 01125 if ((thread_support & EncoderThreadSupport) == 0) 01126 LockSemaphoreInfo(constitute_semaphore); 01127 status=GetImageEncoder(magick_info)(write_info,image,exception); 01128 if ((thread_support & EncoderThreadSupport) == 0) 01129 UnlockSemaphoreInfo(constitute_semaphore); 01130 } 01131 else 01132 { 01133 delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception); 01134 if (delegate_info != (DelegateInfo *) NULL) 01135 { 01136 /* 01137 Process the image with delegate. 01138 */ 01139 *write_info->filename='\0'; 01140 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 01141 LockSemaphoreInfo(constitute_semaphore); 01142 status=InvokeDelegate(write_info,image,(char *) NULL, 01143 write_info->magick,exception); 01144 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 01145 UnlockSemaphoreInfo(constitute_semaphore); 01146 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01147 } 01148 else 01149 { 01150 sans_exception=AcquireExceptionInfo(); 01151 magick_info=GetMagickInfo(write_info->magick,sans_exception); 01152 sans_exception=DestroyExceptionInfo(sans_exception); 01153 if ((write_info->affirm == MagickFalse) && 01154 (magick_info == (const MagickInfo *) NULL)) 01155 { 01156 (void) CopyMagickString(write_info->magick,image->magick, 01157 MaxTextExtent); 01158 magick_info=GetMagickInfo(write_info->magick,exception); 01159 } 01160 if ((magick_info == (const MagickInfo *) NULL) || 01161 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 01162 { 01163 char 01164 extension[MaxTextExtent]; 01165 01166 GetPathComponent(image->filename,ExtensionPath,extension); 01167 if (*extension != '\0') 01168 magick_info=GetMagickInfo(extension,exception); 01169 else 01170 magick_info=GetMagickInfo(image->magick,exception); 01171 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01172 } 01173 if ((magick_info == (const MagickInfo *) NULL) || 01174 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 01175 (void) ThrowMagickException(exception,GetMagickModule(), 01176 MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'", 01177 image->filename); 01178 else 01179 { 01180 /* 01181 Call appropriate image writer based on image type. 01182 */ 01183 thread_support=GetMagickThreadSupport(magick_info); 01184 if ((thread_support & EncoderThreadSupport) == 0) 01185 LockSemaphoreInfo(constitute_semaphore); 01186 status=GetImageEncoder(magick_info)(write_info,image,exception); 01187 if ((thread_support & EncoderThreadSupport) == 0) 01188 UnlockSemaphoreInfo(constitute_semaphore); 01189 } 01190 } 01191 } 01192 if (GetBlobError(image) != MagickFalse) 01193 ThrowFileException(exception,FileOpenError, 01194 "AnErrorHasOccurredWritingToFile",image->filename); 01195 if (temporary == MagickTrue) 01196 { 01197 /* 01198 Copy temporary image file to permanent. 01199 */ 01200 status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception); 01201 if (status != MagickFalse) 01202 { 01203 (void) RelinquishUniqueFileResource(write_info->filename); 01204 status=ImageToFile(image,write_info->filename,exception); 01205 } 01206 (void) CloseBlob(image); 01207 (void) RelinquishUniqueFileResource(image->filename); 01208 (void) CopyMagickString(image->filename,write_info->filename, 01209 MaxTextExtent); 01210 } 01211 if ((LocaleCompare(write_info->magick,"info") != 0) && 01212 (write_info->verbose != MagickFalse)) 01213 (void) IdentifyImage(image,stdout,MagickFalse,exception); 01214 write_info=DestroyImageInfo(write_info); 01215 return(status); 01216 } 01217 01218 /* 01219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01220 % % 01221 % % 01222 % % 01223 % W r i t e I m a g e s % 01224 % % 01225 % % 01226 % % 01227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01228 % 01229 % WriteImages() writes an image sequence into one or more files. While 01230 % WriteImage() can write an image sequence, it is limited to writing 01231 % the sequence into a single file using a format which supports multiple 01232 % frames. WriteImages(), however, does not have this limitation, instead it 01233 % generates multiple output files if necessary (or when requested). When 01234 % ImageInfo's adjoin flag is set to MagickFalse, the file name is expected 01235 % to include a printf-style formatting string for the frame number (e.g. 01236 % "image%02d.png"). 01237 % 01238 % The format of the WriteImages method is: 01239 % 01240 % MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images, 01241 % const char *filename,ExceptionInfo *exception) 01242 % 01243 % A description of each parameter follows: 01244 % 01245 % o image_info: the image info. 01246 % 01247 % o images: the image list. 01248 % 01249 % o filename: the image filename. 01250 % 01251 % o exception: return any errors or warnings in this structure. 01252 % 01253 */ 01254 MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info, 01255 Image *images,const char *filename,ExceptionInfo *exception) 01256 { 01257 #define WriteImageTag "Write/Image" 01258 01259 BlobInfo 01260 *blob; 01261 01262 ExceptionInfo 01263 *sans_exception; 01264 01265 ImageInfo 01266 *write_info; 01267 01268 MagickBooleanType 01269 proceed; 01270 01271 MagickOffsetType 01272 i; 01273 01274 MagickProgressMonitor 01275 progress_monitor; 01276 01277 MagickSizeType 01278 number_images; 01279 01280 MagickStatusType 01281 status; 01282 01283 register Image 01284 *p; 01285 01286 assert(image_info != (const ImageInfo *) NULL); 01287 assert(image_info->signature == MagickSignature); 01288 assert(images != (Image *) NULL); 01289 assert(images->signature == MagickSignature); 01290 if (images->debug != MagickFalse) 01291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 01292 assert(exception != (ExceptionInfo *) NULL); 01293 write_info=CloneImageInfo(image_info); 01294 images=GetFirstImageInList(images); 01295 blob=CloneBlobInfo(images->blob); /* thread specific I/O handler */ 01296 DestroyBlob(images); 01297 images->blob=blob; 01298 if (filename != (const char *) NULL) 01299 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01300 (void) CopyMagickString(p->filename,filename,MaxTextExtent); 01301 (void) CopyMagickString(write_info->filename,images->filename,MaxTextExtent); 01302 if (*write_info->magick == '\0') 01303 (void) CopyMagickString(write_info->magick,images->magick,MaxTextExtent); 01304 sans_exception=AcquireExceptionInfo(); 01305 (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images), 01306 sans_exception); 01307 sans_exception=DestroyExceptionInfo(sans_exception); 01308 p=images; 01309 for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p)) 01310 if (p->scene >= GetNextImageInList(p)->scene) 01311 { 01312 register ssize_t 01313 i; 01314 01315 /* 01316 Generate consistent scene numbers. 01317 */ 01318 i=(ssize_t) images->scene; 01319 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01320 p->scene=(size_t) i++; 01321 break; 01322 } 01323 /* 01324 Write images. 01325 */ 01326 status=MagickTrue; 01327 progress_monitor=(MagickProgressMonitor) NULL; 01328 i=0; 01329 number_images=GetImageListLength(images); 01330 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01331 { 01332 if (number_images != 1) 01333 progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL, 01334 p->client_data); 01335 status&=WriteImage(write_info,p,exception); 01336 if (number_images != 1) 01337 (void) SetImageProgressMonitor(p,progress_monitor,p->client_data); 01338 if (write_info->adjoin != MagickFalse) 01339 break; 01340 if (number_images != 1) 01341 { 01342 proceed=SetImageProgress(p,WriteImageTag,i++,number_images); 01343 if (proceed == MagickFalse) 01344 break; 01345 } 01346 } 01347 write_info=DestroyImageInfo(write_info); 01348 return(status != 0 ? MagickTrue : MagickFalse); 01349 }