|
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 if ((next->colorspace == sRGBColorspace) && (next->gamma == 1.0)) 00651 next->colorspace=RGBColorspace; 00652 value=GetImageProperty(next,"tiff:Orientation",exception); 00653 if (value == (char *) NULL) 00654 value=GetImageProperty(next,"exif:Orientation",exception); 00655 if (value != (char *) NULL) 00656 { 00657 next->orientation=(OrientationType) StringToLong(value); 00658 (void) DeleteImageProperty(next,"tiff:Orientation"); 00659 (void) DeleteImageProperty(next,"exif:Orientation"); 00660 } 00661 value=GetImageProperty(next,"exif:XResolution",exception); 00662 if (value != (char *) NULL) 00663 { 00664 geometry_info.rho=next->resolution.x; 00665 geometry_info.sigma=1.0; 00666 flags=ParseGeometry(value,&geometry_info); 00667 if (geometry_info.sigma != 0) 00668 next->resolution.x=geometry_info.rho/geometry_info.sigma; 00669 (void) DeleteImageProperty(next,"exif:XResolution"); 00670 } 00671 value=GetImageProperty(next,"exif:YResolution",exception); 00672 if (value != (char *) NULL) 00673 { 00674 geometry_info.rho=next->resolution.y; 00675 geometry_info.sigma=1.0; 00676 flags=ParseGeometry(value,&geometry_info); 00677 if (geometry_info.sigma != 0) 00678 next->resolution.y=geometry_info.rho/geometry_info.sigma; 00679 (void) DeleteImageProperty(next,"exif:YResolution"); 00680 } 00681 value=GetImageProperty(next,"tiff:ResolutionUnit",exception); 00682 if (value == (char *) NULL) 00683 value=GetImageProperty(next,"exif:ResolutionUnit",exception); 00684 if (value != (char *) NULL) 00685 { 00686 next->units=(ResolutionType) (StringToLong(value)-1); 00687 (void) DeleteImageProperty(next,"exif:ResolutionUnit"); 00688 (void) DeleteImageProperty(next,"tiff:ResolutionUnit"); 00689 } 00690 if (next->page.width == 0) 00691 next->page.width=next->columns; 00692 if (next->page.height == 0) 00693 next->page.height=next->rows; 00694 option=GetImageOption(read_info,"caption"); 00695 if (option != (const char *) NULL) 00696 { 00697 property=InterpretImageProperties(read_info,next,option,exception); 00698 (void) SetImageProperty(next,"caption",property,exception); 00699 property=DestroyString(property); 00700 } 00701 option=GetImageOption(read_info,"comment"); 00702 if (option != (const char *) NULL) 00703 { 00704 property=InterpretImageProperties(read_info,next,option,exception); 00705 (void) SetImageProperty(next,"comment",property,exception); 00706 property=DestroyString(property); 00707 } 00708 option=GetImageOption(read_info,"label"); 00709 if (option != (const char *) NULL) 00710 { 00711 property=InterpretImageProperties(read_info,next,option,exception); 00712 (void) SetImageProperty(next,"label",property,exception); 00713 property=DestroyString(property); 00714 } 00715 if (LocaleCompare(next->magick,"TEXT") == 0) 00716 (void) ParseAbsoluteGeometry("0x0+0+0",&next->page); 00717 if ((read_info->extract != (char *) NULL) && 00718 (read_info->stream == (StreamHandler) NULL)) 00719 { 00720 RectangleInfo 00721 geometry; 00722 00723 flags=ParseAbsoluteGeometry(read_info->extract,&geometry); 00724 if ((next->columns != geometry.width) || 00725 (next->rows != geometry.height)) 00726 { 00727 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 00728 { 00729 Image 00730 *crop_image; 00731 00732 crop_image=CropImage(next,&geometry,exception); 00733 if (crop_image != (Image *) NULL) 00734 ReplaceImageInList(&next,crop_image); 00735 } 00736 else 00737 if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) 00738 { 00739 Image 00740 *size_image; 00741 00742 flags=ParseRegionGeometry(next,read_info->extract,&geometry, 00743 exception); 00744 size_image=ResizeImage(next,geometry.width,geometry.height, 00745 next->filter,next->blur,exception); 00746 if (size_image != (Image *) NULL) 00747 ReplaceImageInList(&next,size_image); 00748 } 00749 } 00750 } 00751 profile=GetImageProfile(next,"icc"); 00752 if (profile == (const StringInfo *) NULL) 00753 profile=GetImageProfile(next,"icm"); 00754 profile=GetImageProfile(next,"iptc"); 00755 if (profile == (const StringInfo *) NULL) 00756 profile=GetImageProfile(next,"8bim"); 00757 (void) FormatMagickTime(GetBlobProperties(next)->st_mtime,MaxTextExtent, 00758 timestamp); 00759 (void) SetImageProperty(next,"date:modify",timestamp,exception); 00760 (void) FormatMagickTime(GetBlobProperties(next)->st_ctime,MaxTextExtent, 00761 timestamp); 00762 (void) SetImageProperty(next,"date:create",timestamp,exception); 00763 option=GetImageOption(image_info,"delay"); 00764 if (option != (const char *) NULL) 00765 { 00766 GeometryInfo 00767 geometry_info; 00768 00769 flags=ParseGeometry(option,&geometry_info); 00770 if ((flags & GreaterValue) != 0) 00771 { 00772 if (next->delay > (size_t) floor(geometry_info.rho+0.5)) 00773 next->delay=(size_t) floor(geometry_info.rho+0.5); 00774 } 00775 else 00776 if ((flags & LessValue) != 0) 00777 { 00778 if (next->delay < (size_t) floor(geometry_info.rho+0.5)) 00779 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 00780 } 00781 else 00782 next->delay=(size_t) floor(geometry_info.rho+0.5); 00783 if ((flags & SigmaValue) != 0) 00784 next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 00785 } 00786 option=GetImageOption(image_info,"dispose"); 00787 if (option != (const char *) NULL) 00788 next->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions, 00789 MagickFalse,option); 00790 if (read_info->verbose != MagickFalse) 00791 (void) IdentifyImage(next,stderr,MagickFalse,exception); 00792 image=next; 00793 } 00794 read_info=DestroyImageInfo(read_info); 00795 return(GetFirstImageInList(image)); 00796 } 00797 00798 /* 00799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00800 % % 00801 % % 00802 % % 00803 % R e a d I m a g e s % 00804 % % 00805 % % 00806 % % 00807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00808 % 00809 % ReadImages() reads one or more images and returns them as an image list. 00810 % 00811 % The format of the ReadImage method is: 00812 % 00813 % Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception) 00814 % 00815 % A description of each parameter follows: 00816 % 00817 % o image_info: the image info. 00818 % 00819 % o exception: return any errors or warnings in this structure. 00820 % 00821 */ 00822 MagickExport Image *ReadImages(const ImageInfo *image_info, 00823 ExceptionInfo *exception) 00824 { 00825 char 00826 filename[MaxTextExtent]; 00827 00828 Image 00829 *image, 00830 *images; 00831 00832 ImageInfo 00833 *read_info; 00834 00835 /* 00836 Read image list from a file. 00837 */ 00838 assert(image_info != (ImageInfo *) NULL); 00839 assert(image_info->signature == MagickSignature); 00840 if (image_info->debug != MagickFalse) 00841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00842 image_info->filename); 00843 assert(exception != (ExceptionInfo *) NULL); 00844 (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename, 00845 (int) image_info->scene,filename,exception); 00846 if (LocaleCompare(filename,image_info->filename) != 0) 00847 { 00848 ExceptionInfo 00849 *sans; 00850 00851 ssize_t 00852 extent, 00853 scene; 00854 00855 /* 00856 Images of the form image-%d.png[1-5]. 00857 */ 00858 read_info=CloneImageInfo(image_info); 00859 sans=AcquireExceptionInfo(); 00860 (void) SetImageInfo(read_info,0,sans); 00861 sans=DestroyExceptionInfo(sans); 00862 if (read_info->number_scenes == 0) 00863 { 00864 read_info=DestroyImageInfo(read_info); 00865 return(ReadImage(image_info,exception)); 00866 } 00867 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 00868 images=NewImageList(); 00869 extent=(ssize_t) (read_info->scene+read_info->number_scenes); 00870 for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++) 00871 { 00872 (void) InterpretImageFilename(image_info,(Image *) NULL,filename,(int) 00873 scene,read_info->filename,exception); 00874 image=ReadImage(read_info,exception); 00875 if (image == (Image *) NULL) 00876 continue; 00877 AppendImageToList(&images,image); 00878 } 00879 read_info=DestroyImageInfo(read_info); 00880 return(images); 00881 } 00882 return(ReadImage(image_info,exception)); 00883 } 00884 00885 /* 00886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00887 % % 00888 % % 00889 % % 00890 + R e a d I n l i n e I m a g e % 00891 % % 00892 % % 00893 % % 00894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00895 % 00896 % ReadInlineImage() reads a Base64-encoded inline image or image sequence. 00897 % The method returns a NULL if there is a memory shortage or if the image 00898 % cannot be read. On failure, a NULL image is returned and exception 00899 % describes the reason for the failure. 00900 % 00901 % The format of the ReadInlineImage method is: 00902 % 00903 % Image *ReadInlineImage(const ImageInfo *image_info,const char *content, 00904 % ExceptionInfo *exception) 00905 % 00906 % A description of each parameter follows: 00907 % 00908 % o image_info: the image info. 00909 % 00910 % o content: the image encoded in Base64. 00911 % 00912 % o exception: return any errors or warnings in this structure. 00913 % 00914 */ 00915 MagickExport Image *ReadInlineImage(const ImageInfo *image_info, 00916 const char *content,ExceptionInfo *exception) 00917 { 00918 Image 00919 *image; 00920 00921 ImageInfo 00922 *read_info; 00923 00924 unsigned char 00925 *blob; 00926 00927 size_t 00928 length; 00929 00930 register const char 00931 *p; 00932 00933 /* 00934 Skip over header (e.g. data:image/gif;base64,). 00935 */ 00936 image=NewImageList(); 00937 for (p=content; (*p != ',') && (*p != '\0'); p++) ; 00938 if (*p == '\0') 00939 ThrowReaderException(CorruptImageError,"CorruptImage"); 00940 p++; 00941 length=0; 00942 blob=Base64Decode(p,&length); 00943 if (length == 0) 00944 ThrowReaderException(CorruptImageError,"CorruptImage"); 00945 read_info=CloneImageInfo(image_info); 00946 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 00947 (void *) NULL); 00948 *read_info->filename='\0'; 00949 *read_info->magick='\0'; 00950 image=BlobToImage(read_info,blob,length,exception); 00951 blob=(unsigned char *) RelinquishMagickMemory(blob); 00952 read_info=DestroyImageInfo(read_info); 00953 return(image); 00954 } 00955 00956 /* 00957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00958 % % 00959 % % 00960 % % 00961 % W r i t e I m a g e % 00962 % % 00963 % % 00964 % % 00965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00966 % 00967 % WriteImage() writes an image or an image sequence to a file or file handle. 00968 % If writing to a file is on disk, the name is defined by the filename member 00969 % of the image structure. WriteImage() returns MagickFalse is there is a 00970 % memory shortage or if the image cannot be written. Check the exception 00971 % member of image to determine the cause for any failure. 00972 % 00973 % The format of the WriteImage method is: 00974 % 00975 % MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image, 00976 % ExceptionInfo *exception) 00977 % 00978 % A description of each parameter follows: 00979 % 00980 % o image_info: the image info. 00981 % 00982 % o image: the image. 00983 % 00984 % o exception: return any errors or warnings in this structure. 00985 % 00986 */ 00987 MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, 00988 Image *image,ExceptionInfo *exception) 00989 { 00990 char 00991 filename[MaxTextExtent]; 00992 00993 const char 00994 *option; 00995 00996 const DelegateInfo 00997 *delegate_info; 00998 00999 const MagickInfo 01000 *magick_info; 01001 01002 ExceptionInfo 01003 *sans_exception; 01004 01005 ImageInfo 01006 *write_info; 01007 01008 MagickBooleanType 01009 status, 01010 temporary; 01011 01012 MagickStatusType 01013 thread_support; 01014 01015 PolicyDomain 01016 domain; 01017 01018 PolicyRights 01019 rights; 01020 01021 /* 01022 Determine image type from filename prefix or suffix (e.g. image.jpg). 01023 */ 01024 assert(image_info != (ImageInfo *) NULL); 01025 assert(image_info->signature == MagickSignature); 01026 if (image->debug != MagickFalse) 01027 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 01028 image_info->filename); 01029 assert(image != (Image *) NULL); 01030 assert(image->signature == MagickSignature); 01031 assert(exception != (ExceptionInfo *) NULL); 01032 sans_exception=AcquireExceptionInfo(); 01033 write_info=CloneImageInfo(image_info); 01034 (void) CopyMagickString(write_info->filename,image->filename,MaxTextExtent); 01035 if (*write_info->magick == '\0') 01036 (void) CopyMagickString(write_info->magick,image->magick,MaxTextExtent); 01037 (void) SetImageInfo(write_info,1,sans_exception); 01038 (void) CopyMagickString(filename,image->filename,MaxTextExtent); 01039 (void) CopyMagickString(image->filename,write_info->filename,MaxTextExtent); 01040 domain=CoderPolicyDomain; 01041 rights=WritePolicyRights; 01042 if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse) 01043 { 01044 sans_exception=DestroyExceptionInfo(sans_exception); 01045 errno=EPERM; 01046 ThrowBinaryException(PolicyError,"NotAuthorized",filename); 01047 } 01048 magick_info=GetMagickInfo(write_info->magick,sans_exception); 01049 sans_exception=DestroyExceptionInfo(sans_exception); 01050 if (magick_info != (const MagickInfo *) NULL) 01051 { 01052 if (GetMagickEndianSupport(magick_info) == MagickFalse) 01053 image->endian=UndefinedEndian; 01054 else 01055 if ((image_info->endian == UndefinedEndian) && 01056 (GetMagickRawSupport(magick_info) != MagickFalse)) 01057 { 01058 size_t 01059 lsb_first; 01060 01061 lsb_first=1; 01062 image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian; 01063 } 01064 } 01065 (void) SyncImageProfiles(image); 01066 option=GetImageOption(image_info,"delegate:bimodal"); 01067 if ((option != (const char *) NULL) && 01068 (IsMagickTrue(option) != MagickFalse) && 01069 (write_info->page == (char *) NULL) && 01070 (GetPreviousImageInList(image) == (Image *) NULL) && 01071 (GetNextImageInList(image) == (Image *) NULL) && 01072 (IsTaintImage(image) == MagickFalse)) 01073 { 01074 delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception); 01075 if ((delegate_info != (const DelegateInfo *) NULL) && 01076 (GetDelegateMode(delegate_info) == 0) && 01077 (IsPathAccessible(image->magick_filename) != MagickFalse)) 01078 { 01079 /* 01080 Process image with bi-modal delegate. 01081 */ 01082 (void) CopyMagickString(image->filename,image->magick_filename, 01083 MaxTextExtent); 01084 status=InvokeDelegate(write_info,image,image->magick, 01085 write_info->magick,exception); 01086 write_info=DestroyImageInfo(write_info); 01087 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01088 return(status); 01089 } 01090 } 01091 status=MagickFalse; 01092 temporary=MagickFalse; 01093 if ((magick_info != (const MagickInfo *) NULL) && 01094 (GetMagickSeekableStream(magick_info) != MagickFalse)) 01095 { 01096 char 01097 filename[MaxTextExtent]; 01098 01099 (void) CopyMagickString(filename,image->filename,MaxTextExtent); 01100 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 01101 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01102 if (status != MagickFalse) 01103 { 01104 if (IsBlobSeekable(image) == MagickFalse) 01105 { 01106 /* 01107 A seekable stream is required by the encoder. 01108 */ 01109 write_info->adjoin=MagickTrue; 01110 (void) CopyMagickString(write_info->filename,image->filename, 01111 MaxTextExtent); 01112 (void) AcquireUniqueFilename(image->filename); 01113 temporary=MagickTrue; 01114 } 01115 (void) CloseBlob(image); 01116 } 01117 } 01118 if (constitute_semaphore == (SemaphoreInfo *) NULL) 01119 AcquireSemaphoreInfo(&constitute_semaphore); 01120 if ((magick_info != (const MagickInfo *) NULL) && 01121 (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL)) 01122 { 01123 /* 01124 Call appropriate image writer based on image type. 01125 */ 01126 thread_support=GetMagickThreadSupport(magick_info); 01127 if ((thread_support & EncoderThreadSupport) == 0) 01128 LockSemaphoreInfo(constitute_semaphore); 01129 status=GetImageEncoder(magick_info)(write_info,image,exception); 01130 if ((thread_support & EncoderThreadSupport) == 0) 01131 UnlockSemaphoreInfo(constitute_semaphore); 01132 } 01133 else 01134 { 01135 delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception); 01136 if (delegate_info != (DelegateInfo *) NULL) 01137 { 01138 /* 01139 Process the image with delegate. 01140 */ 01141 *write_info->filename='\0'; 01142 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 01143 LockSemaphoreInfo(constitute_semaphore); 01144 status=InvokeDelegate(write_info,image,(char *) NULL, 01145 write_info->magick,exception); 01146 if (GetDelegateThreadSupport(delegate_info) == MagickFalse) 01147 UnlockSemaphoreInfo(constitute_semaphore); 01148 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01149 } 01150 else 01151 { 01152 sans_exception=AcquireExceptionInfo(); 01153 magick_info=GetMagickInfo(write_info->magick,sans_exception); 01154 sans_exception=DestroyExceptionInfo(sans_exception); 01155 if ((write_info->affirm == MagickFalse) && 01156 (magick_info == (const MagickInfo *) NULL)) 01157 { 01158 (void) CopyMagickString(write_info->magick,image->magick, 01159 MaxTextExtent); 01160 magick_info=GetMagickInfo(write_info->magick,exception); 01161 } 01162 if ((magick_info == (const MagickInfo *) NULL) || 01163 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 01164 { 01165 char 01166 extension[MaxTextExtent]; 01167 01168 GetPathComponent(image->filename,ExtensionPath,extension); 01169 if (*extension != '\0') 01170 magick_info=GetMagickInfo(extension,exception); 01171 else 01172 magick_info=GetMagickInfo(image->magick,exception); 01173 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 01174 } 01175 if ((magick_info == (const MagickInfo *) NULL) || 01176 (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) 01177 (void) ThrowMagickException(exception,GetMagickModule(), 01178 MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'", 01179 image->filename); 01180 else 01181 { 01182 /* 01183 Call appropriate image writer based on image type. 01184 */ 01185 thread_support=GetMagickThreadSupport(magick_info); 01186 if ((thread_support & EncoderThreadSupport) == 0) 01187 LockSemaphoreInfo(constitute_semaphore); 01188 status=GetImageEncoder(magick_info)(write_info,image,exception); 01189 if ((thread_support & EncoderThreadSupport) == 0) 01190 UnlockSemaphoreInfo(constitute_semaphore); 01191 } 01192 } 01193 } 01194 if (GetBlobError(image) != MagickFalse) 01195 ThrowFileException(exception,FileOpenError, 01196 "AnErrorHasOccurredWritingToFile",image->filename); 01197 if (temporary == MagickTrue) 01198 { 01199 /* 01200 Copy temporary image file to permanent. 01201 */ 01202 status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception); 01203 if (status != MagickFalse) 01204 { 01205 (void) RelinquishUniqueFileResource(write_info->filename); 01206 status=ImageToFile(image,write_info->filename,exception); 01207 } 01208 (void) CloseBlob(image); 01209 (void) RelinquishUniqueFileResource(image->filename); 01210 (void) CopyMagickString(image->filename,write_info->filename, 01211 MaxTextExtent); 01212 } 01213 if ((LocaleCompare(write_info->magick,"info") != 0) && 01214 (write_info->verbose != MagickFalse)) 01215 (void) IdentifyImage(image,stdout,MagickFalse,exception); 01216 write_info=DestroyImageInfo(write_info); 01217 return(status); 01218 } 01219 01220 /* 01221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01222 % % 01223 % % 01224 % % 01225 % W r i t e I m a g e s % 01226 % % 01227 % % 01228 % % 01229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01230 % 01231 % WriteImages() writes an image sequence into one or more files. While 01232 % WriteImage() can write an image sequence, it is limited to writing 01233 % the sequence into a single file using a format which supports multiple 01234 % frames. WriteImages(), however, does not have this limitation, instead it 01235 % generates multiple output files if necessary (or when requested). When 01236 % ImageInfo's adjoin flag is set to MagickFalse, the file name is expected 01237 % to include a printf-style formatting string for the frame number (e.g. 01238 % "image%02d.png"). 01239 % 01240 % The format of the WriteImages method is: 01241 % 01242 % MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images, 01243 % const char *filename,ExceptionInfo *exception) 01244 % 01245 % A description of each parameter follows: 01246 % 01247 % o image_info: the image info. 01248 % 01249 % o images: the image list. 01250 % 01251 % o filename: the image filename. 01252 % 01253 % o exception: return any errors or warnings in this structure. 01254 % 01255 */ 01256 MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info, 01257 Image *images,const char *filename,ExceptionInfo *exception) 01258 { 01259 #define WriteImageTag "Write/Image" 01260 01261 BlobInfo 01262 *blob; 01263 01264 ExceptionInfo 01265 *sans_exception; 01266 01267 ImageInfo 01268 *write_info; 01269 01270 MagickBooleanType 01271 proceed; 01272 01273 MagickOffsetType 01274 i; 01275 01276 MagickProgressMonitor 01277 progress_monitor; 01278 01279 MagickSizeType 01280 number_images; 01281 01282 MagickStatusType 01283 status; 01284 01285 register Image 01286 *p; 01287 01288 assert(image_info != (const ImageInfo *) NULL); 01289 assert(image_info->signature == MagickSignature); 01290 assert(images != (Image *) NULL); 01291 assert(images->signature == MagickSignature); 01292 if (images->debug != MagickFalse) 01293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 01294 assert(exception != (ExceptionInfo *) NULL); 01295 write_info=CloneImageInfo(image_info); 01296 images=GetFirstImageInList(images); 01297 blob=CloneBlobInfo(images->blob); /* thread specific I/O handler */ 01298 DestroyBlob(images); 01299 images->blob=blob; 01300 if (filename != (const char *) NULL) 01301 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01302 (void) CopyMagickString(p->filename,filename,MaxTextExtent); 01303 (void) CopyMagickString(write_info->filename,images->filename,MaxTextExtent); 01304 if (*write_info->magick == '\0') 01305 (void) CopyMagickString(write_info->magick,images->magick,MaxTextExtent); 01306 sans_exception=AcquireExceptionInfo(); 01307 (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images), 01308 sans_exception); 01309 sans_exception=DestroyExceptionInfo(sans_exception); 01310 p=images; 01311 for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p)) 01312 if (p->scene >= GetNextImageInList(p)->scene) 01313 { 01314 register ssize_t 01315 i; 01316 01317 /* 01318 Generate consistent scene numbers. 01319 */ 01320 i=(ssize_t) images->scene; 01321 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01322 p->scene=(size_t) i++; 01323 break; 01324 } 01325 /* 01326 Write images. 01327 */ 01328 status=MagickTrue; 01329 progress_monitor=(MagickProgressMonitor) NULL; 01330 i=0; 01331 number_images=GetImageListLength(images); 01332 for (p=images; p != (Image *) NULL; p=GetNextImageInList(p)) 01333 { 01334 if (number_images != 1) 01335 progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL, 01336 p->client_data); 01337 status&=WriteImage(write_info,p,exception); 01338 if (number_images != 1) 01339 (void) SetImageProgressMonitor(p,progress_monitor,p->client_data); 01340 if (write_info->adjoin != MagickFalse) 01341 break; 01342 if (number_images != 1) 01343 { 01344 proceed=SetImageProgress(p,WriteImageTag,i++,number_images); 01345 if (proceed == MagickFalse) 01346 break; 01347 } 01348 } 01349 write_info=DestroyImageInfo(write_info); 01350 return(status != 0 ? MagickTrue : MagickFalse); 01351 }