|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % PPPP RRRR OOO PPPP EEEEE RRRR TTTTT Y Y % 00007 % P P R R O O P P E R R T Y Y % 00008 % PPPP RRRR O O PPPP EEE RRRR T Y % 00009 % P R R O O P E R R T Y % 00010 % P R R OOO P EEEEE R R T Y % 00011 % % 00012 % % 00013 % MagickCore Property Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % March 2000 % 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 /* 00041 Include declarations. 00042 */ 00043 #include "MagickCore/studio.h" 00044 #include "MagickCore/attribute.h" 00045 #include "MagickCore/cache.h" 00046 #include "MagickCore/color.h" 00047 #include "MagickCore/compare.h" 00048 #include "MagickCore/constitute.h" 00049 #include "MagickCore/draw.h" 00050 #include "MagickCore/effect.h" 00051 #include "MagickCore/exception.h" 00052 #include "MagickCore/exception-private.h" 00053 #include "MagickCore/fx.h" 00054 #include "MagickCore/fx-private.h" 00055 #include "MagickCore/gem.h" 00056 #include "MagickCore/geometry.h" 00057 #include "MagickCore/histogram.h" 00058 #include "MagickCore/image.h" 00059 #include "MagickCore/image.h" 00060 #include "MagickCore/layer.h" 00061 #include "MagickCore/locale-private.h" 00062 #include "MagickCore/list.h" 00063 #include "MagickCore/magick.h" 00064 #include "MagickCore/memory_.h" 00065 #include "MagickCore/monitor.h" 00066 #include "MagickCore/montage.h" 00067 #include "MagickCore/option.h" 00068 #include "MagickCore/profile.h" 00069 #include "MagickCore/property.h" 00070 #include "MagickCore/quantum.h" 00071 #include "MagickCore/resource_.h" 00072 #include "MagickCore/splay-tree.h" 00073 #include "MagickCore/signature.h" 00074 #include "MagickCore/statistic.h" 00075 #include "MagickCore/string_.h" 00076 #include "MagickCore/string-private.h" 00077 #include "MagickCore/token.h" 00078 #include "MagickCore/token-private.h" 00079 #include "MagickCore/utility.h" 00080 #include "MagickCore/utility-private.h" 00081 #include "MagickCore/version.h" 00082 #include "MagickCore/xml-tree.h" 00083 #include "MagickCore/xml-tree-private.h" 00084 00085 /* 00086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00087 % % 00088 % % 00089 % % 00090 % C l o n e I m a g e P r o p e r t i e s % 00091 % % 00092 % % 00093 % % 00094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00095 % 00096 % CloneImageProperties() clones one or more image properties. 00097 % 00098 % The format of the CloneImageProperties method is: 00099 % 00100 % MagickBooleanType CloneImageProperties(Image *image, 00101 % const Image *clone_image) 00102 % 00103 % A description of each parameter follows: 00104 % 00105 % o image: the image. 00106 % 00107 % o clone_image: the clone image. 00108 % 00109 */ 00110 MagickExport MagickBooleanType CloneImageProperties(Image *image, 00111 const Image *clone_image) 00112 { 00113 assert(image != (Image *) NULL); 00114 assert(image->signature == MagickSignature); 00115 if (image->debug != MagickFalse) 00116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00117 assert(clone_image != (const Image *) NULL); 00118 assert(clone_image->signature == MagickSignature); 00119 if (clone_image->debug != MagickFalse) 00120 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00121 clone_image->filename); 00122 (void) CopyMagickString(image->filename,clone_image->filename,MaxTextExtent); 00123 (void) CopyMagickString(image->magick_filename,clone_image->magick_filename, 00124 MaxTextExtent); 00125 image->compression=clone_image->compression; 00126 image->quality=clone_image->quality; 00127 image->depth=clone_image->depth; 00128 image->background_color=clone_image->background_color; 00129 image->border_color=clone_image->border_color; 00130 image->matte_color=clone_image->matte_color; 00131 image->transparent_color=clone_image->transparent_color; 00132 image->gamma=clone_image->gamma; 00133 image->chromaticity=clone_image->chromaticity; 00134 image->rendering_intent=clone_image->rendering_intent; 00135 image->black_point_compensation=clone_image->black_point_compensation; 00136 image->units=clone_image->units; 00137 image->montage=(char *) NULL; 00138 image->directory=(char *) NULL; 00139 (void) CloneString(&image->geometry,clone_image->geometry); 00140 image->offset=clone_image->offset; 00141 image->resolution.x=clone_image->resolution.x; 00142 image->resolution.y=clone_image->resolution.y; 00143 image->page=clone_image->page; 00144 image->tile_offset=clone_image->tile_offset; 00145 image->extract_info=clone_image->extract_info; 00146 image->bias=clone_image->bias; 00147 image->filter=clone_image->filter; 00148 image->blur=clone_image->blur; 00149 image->fuzz=clone_image->fuzz; 00150 image->interlace=clone_image->interlace; 00151 image->interpolate=clone_image->interpolate; 00152 image->endian=clone_image->endian; 00153 image->gravity=clone_image->gravity; 00154 image->compose=clone_image->compose; 00155 image->scene=clone_image->scene; 00156 image->orientation=clone_image->orientation; 00157 image->dispose=clone_image->dispose; 00158 image->delay=clone_image->delay; 00159 image->ticks_per_second=clone_image->ticks_per_second; 00160 image->iterations=clone_image->iterations; 00161 image->total_colors=clone_image->total_colors; 00162 image->taint=clone_image->taint; 00163 image->progress_monitor=clone_image->progress_monitor; 00164 image->client_data=clone_image->client_data; 00165 image->start_loop=clone_image->start_loop; 00166 image->error=clone_image->error; 00167 image->signature=clone_image->signature; 00168 if (clone_image->properties != (void *) NULL) 00169 { 00170 if (image->properties != (void *) NULL) 00171 DestroyImageProperties(image); 00172 image->properties=CloneSplayTree((SplayTreeInfo *) 00173 clone_image->properties,(void *(*)(void *)) ConstantString, 00174 (void *(*)(void *)) ConstantString); 00175 } 00176 return(MagickTrue); 00177 } 00178 00179 /* 00180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00181 % % 00182 % % 00183 % % 00184 % D e f i n e I m a g e P r o p e r t y % 00185 % % 00186 % % 00187 % % 00188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00189 % 00190 % DefineImageProperty() associates a key/value pair with an image property. 00191 % 00192 % The format of the DefineImageProperty method is: 00193 % 00194 % MagickBooleanType DefineImageProperty(Image *image, 00195 % const char *property,ExceptionInfo *exception) 00196 % 00197 % A description of each parameter follows: 00198 % 00199 % o image: the image. 00200 % 00201 % o property: the image property. 00202 % 00203 % o exception: return any errors or warnings in this structure. 00204 % 00205 */ 00206 MagickExport MagickBooleanType DefineImageProperty(Image *image, 00207 const char *property,ExceptionInfo *exception) 00208 { 00209 char 00210 key[MaxTextExtent], 00211 value[MaxTextExtent]; 00212 00213 register char 00214 *p; 00215 00216 assert(image != (Image *) NULL); 00217 assert(property != (const char *) NULL); 00218 (void) CopyMagickString(key,property,MaxTextExtent-1); 00219 for (p=key; *p != '\0'; p++) 00220 if (*p == '=') 00221 break; 00222 *value='\0'; 00223 if (*p == '=') 00224 (void) CopyMagickString(value,p+1,MaxTextExtent); 00225 *p='\0'; 00226 return(SetImageProperty(image,key,value,exception)); 00227 } 00228 00229 /* 00230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00231 % % 00232 % % 00233 % % 00234 % D e l e t e I m a g e P r o p e r t y % 00235 % % 00236 % % 00237 % % 00238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00239 % 00240 % DeleteImageProperty() deletes an image property. 00241 % 00242 % The format of the DeleteImageProperty method is: 00243 % 00244 % MagickBooleanType DeleteImageProperty(Image *image,const char *property) 00245 % 00246 % A description of each parameter follows: 00247 % 00248 % o image: the image. 00249 % 00250 % o property: the image property. 00251 % 00252 */ 00253 MagickExport MagickBooleanType DeleteImageProperty(Image *image, 00254 const char *property) 00255 { 00256 assert(image != (Image *) NULL); 00257 assert(image->signature == MagickSignature); 00258 if (image->debug != MagickFalse) 00259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00260 image->filename); 00261 if (image->properties == (void *) NULL) 00262 return(MagickFalse); 00263 return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->properties,property)); 00264 } 00265 00266 /* 00267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00268 % % 00269 % % 00270 % % 00271 % D e s t r o y I m a g e P r o p e r t i e s % 00272 % % 00273 % % 00274 % % 00275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00276 % 00277 % DestroyImageProperties() releases memory associated with image property 00278 % values. 00279 % 00280 % The format of the DestroyDefines method is: 00281 % 00282 % void DestroyImageProperties(Image *image) 00283 % 00284 % A description of each parameter follows: 00285 % 00286 % o image: the image. 00287 % 00288 */ 00289 MagickExport void DestroyImageProperties(Image *image) 00290 { 00291 assert(image != (Image *) NULL); 00292 assert(image->signature == MagickSignature); 00293 if (image->debug != MagickFalse) 00294 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 00295 image->filename); 00296 if (image->properties != (void *) NULL) 00297 image->properties=(void *) DestroySplayTree((SplayTreeInfo *) 00298 image->properties); 00299 } 00300 00301 /* 00302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00303 % % 00304 % % 00305 % % 00306 % F o r m a t I m a g e P r o p e r t y % 00307 % % 00308 % % 00309 % % 00310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00311 % 00312 % FormatImageProperty() permits formatted property/value pairs to be saved as 00313 % an image property. 00314 % 00315 % The format of the FormatImageProperty method is: 00316 % 00317 % MagickBooleanType FormatImageProperty(Image *image,const char *property, 00318 % const char *format,...) 00319 % 00320 % A description of each parameter follows. 00321 % 00322 % o image: The image. 00323 % 00324 % o property: The attribute property. 00325 % 00326 % o format: A string describing the format to use to write the remaining 00327 % arguments. 00328 % 00329 */ 00330 MagickExport MagickBooleanType FormatImageProperty(Image *image, 00331 const char *property,const char *format,...) 00332 { 00333 char 00334 value[MaxTextExtent]; 00335 00336 ExceptionInfo 00337 *exception; 00338 00339 MagickBooleanType 00340 status; 00341 00342 ssize_t 00343 n; 00344 00345 va_list 00346 operands; 00347 00348 va_start(operands,format); 00349 n=FormatLocaleStringList(value,MaxTextExtent,format,operands); 00350 (void) n; 00351 va_end(operands); 00352 exception=AcquireExceptionInfo(); 00353 status=SetImageProperty(image,property,value,exception); 00354 exception=DestroyExceptionInfo(exception); 00355 return(status); 00356 } 00357 00358 /* 00359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00360 % % 00361 % % 00362 % % 00363 % G e t I m a g e P r o p e r t y % 00364 % % 00365 % % 00366 % % 00367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00368 % 00369 % GetImageProperty() gets a value associated with an image property. 00370 % 00371 % The format of the GetImageProperty method is: 00372 % 00373 % const char *GetImageProperty(const Image *image,const char *key, 00374 % ExceptionInfo *exception) 00375 % 00376 % A description of each parameter follows: 00377 % 00378 % o image: the image. 00379 % 00380 % o key: the key. 00381 % 00382 % o exception: return any errors or warnings in this structure. 00383 % 00384 */ 00385 00386 static char 00387 *TracePSClippath(const unsigned char *,size_t,const size_t, 00388 const size_t), 00389 *TraceSVGClippath(const unsigned char *,size_t,const size_t, 00390 const size_t); 00391 00392 static MagickBooleanType GetIPTCProperty(const Image *image,const char *key, 00393 ExceptionInfo *exception) 00394 { 00395 char 00396 *attribute, 00397 *message; 00398 00399 const StringInfo 00400 *profile; 00401 00402 long 00403 count, 00404 dataset, 00405 record; 00406 00407 register ssize_t 00408 i; 00409 00410 size_t 00411 length; 00412 00413 profile=GetImageProfile(image,"iptc"); 00414 if (profile == (StringInfo *) NULL) 00415 profile=GetImageProfile(image,"8bim"); 00416 if (profile == (StringInfo *) NULL) 00417 return(MagickFalse); 00418 count=sscanf(key,"IPTC:%ld:%ld",&dataset,&record); 00419 if (count != 2) 00420 return(MagickFalse); 00421 attribute=(char *) NULL; 00422 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=(ssize_t) length) 00423 { 00424 length=1; 00425 if ((ssize_t) GetStringInfoDatum(profile)[i] != 0x1c) 00426 continue; 00427 length=(size_t) (GetStringInfoDatum(profile)[i+3] << 8); 00428 length|=GetStringInfoDatum(profile)[i+4]; 00429 if (((long) GetStringInfoDatum(profile)[i+1] == dataset) && 00430 ((long) GetStringInfoDatum(profile)[i+2] == record)) 00431 { 00432 message=(char *) NULL; 00433 if (~length >= 1) 00434 message=(char *) AcquireQuantumMemory(length+1UL,sizeof(*message)); 00435 if (message != (char *) NULL) 00436 { 00437 (void) CopyMagickString(message,(char *) GetStringInfoDatum( 00438 profile)+i+5,length+1); 00439 (void) ConcatenateString(&attribute,message); 00440 (void) ConcatenateString(&attribute,";"); 00441 message=DestroyString(message); 00442 } 00443 } 00444 i+=5; 00445 } 00446 if ((attribute == (char *) NULL) || (*attribute == ';')) 00447 { 00448 if (attribute != (char *) NULL) 00449 attribute=DestroyString(attribute); 00450 return(MagickFalse); 00451 } 00452 attribute[strlen(attribute)-1]='\0'; 00453 (void) SetImageProperty((Image *) image,key,(const char *) attribute, 00454 exception); 00455 attribute=DestroyString(attribute); 00456 return(MagickTrue); 00457 } 00458 00459 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 00460 { 00461 if (x > y) 00462 return(x); 00463 return(y); 00464 } 00465 00466 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 00467 { 00468 if (x < y) 00469 return(x); 00470 return(y); 00471 } 00472 00473 static inline int ReadPropertyByte(const unsigned char **p,size_t *length) 00474 { 00475 int 00476 c; 00477 00478 if (*length < 1) 00479 return(EOF); 00480 c=(int) (*(*p)++); 00481 (*length)--; 00482 return(c); 00483 } 00484 00485 static inline size_t ReadPropertyMSBLong(const unsigned char **p, 00486 size_t *length) 00487 { 00488 int 00489 c; 00490 00491 register ssize_t 00492 i; 00493 00494 unsigned char 00495 buffer[4]; 00496 00497 size_t 00498 value; 00499 00500 if (*length < 4) 00501 return(~0UL); 00502 for (i=0; i < 4; i++) 00503 { 00504 c=(int) (*(*p)++); 00505 (*length)--; 00506 buffer[i]=(unsigned char) c; 00507 } 00508 value=(size_t) (buffer[0] << 24); 00509 value|=buffer[1] << 16; 00510 value|=buffer[2] << 8; 00511 value|=buffer[3]; 00512 return(value & 0xffffffff); 00513 } 00514 00515 static inline unsigned short ReadPropertyMSBShort(const unsigned char **p, 00516 size_t *length) 00517 { 00518 int 00519 c; 00520 00521 register ssize_t 00522 i; 00523 00524 unsigned char 00525 buffer[2]; 00526 00527 unsigned short 00528 value; 00529 00530 if (*length < 2) 00531 return((unsigned short) ~0U); 00532 for (i=0; i < 2; i++) 00533 { 00534 c=(int) (*(*p)++); 00535 (*length)--; 00536 buffer[i]=(unsigned char) c; 00537 } 00538 value=(unsigned short) (buffer[0] << 8); 00539 value|=buffer[1]; 00540 return((unsigned short) (value & 0xffff)); 00541 } 00542 00543 static MagickBooleanType Get8BIMProperty(const Image *image,const char *key, 00544 ExceptionInfo *exception) 00545 { 00546 char 00547 *attribute, 00548 format[MaxTextExtent], 00549 name[MaxTextExtent], 00550 *resource; 00551 00552 const StringInfo 00553 *profile; 00554 00555 const unsigned char 00556 *info; 00557 00558 long 00559 start, 00560 stop; 00561 00562 MagickBooleanType 00563 status; 00564 00565 register ssize_t 00566 i; 00567 00568 ssize_t 00569 count, 00570 id, 00571 sub_number; 00572 00573 size_t 00574 length; 00575 00576 /* 00577 There are no newlines in path names, so it's safe as terminator. 00578 */ 00579 profile=GetImageProfile(image,"8bim"); 00580 if (profile == (StringInfo *) NULL) 00581 return(MagickFalse); 00582 count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%[^\n]\n%[^\n]",&start,&stop,name, 00583 format); 00584 if ((count != 2) && (count != 3) && (count != 4)) 00585 return(MagickFalse); 00586 if (count < 4) 00587 (void) CopyMagickString(format,"SVG",MaxTextExtent); 00588 if (count < 3) 00589 *name='\0'; 00590 sub_number=1; 00591 if (*name == '#') 00592 sub_number=(ssize_t) StringToLong(&name[1]); 00593 sub_number=MagickMax(sub_number,1L); 00594 resource=(char *) NULL; 00595 status=MagickFalse; 00596 length=GetStringInfoLength(profile); 00597 info=GetStringInfoDatum(profile); 00598 while ((length > 0) && (status == MagickFalse)) 00599 { 00600 if (ReadPropertyByte(&info,&length) != (unsigned char) '8') 00601 continue; 00602 if (ReadPropertyByte(&info,&length) != (unsigned char) 'B') 00603 continue; 00604 if (ReadPropertyByte(&info,&length) != (unsigned char) 'I') 00605 continue; 00606 if (ReadPropertyByte(&info,&length) != (unsigned char) 'M') 00607 continue; 00608 id=(ssize_t) ((int) ReadPropertyMSBShort(&info,&length)); 00609 if (id < (ssize_t) start) 00610 continue; 00611 if (id > (ssize_t) stop) 00612 continue; 00613 if (resource != (char *) NULL) 00614 resource=DestroyString(resource); 00615 count=(ssize_t) ReadPropertyByte(&info,&length); 00616 if ((count != 0) && ((size_t) count <= length)) 00617 { 00618 resource=(char *) NULL; 00619 if (~(1UL*count) >= (MaxTextExtent-1)) 00620 resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent, 00621 sizeof(*resource)); 00622 if (resource != (char *) NULL) 00623 { 00624 for (i=0; i < (ssize_t) count; i++) 00625 resource[i]=(char) ReadPropertyByte(&info,&length); 00626 resource[count]='\0'; 00627 } 00628 } 00629 if ((count & 0x01) == 0) 00630 (void) ReadPropertyByte(&info,&length); 00631 count=(ssize_t) ((int) ReadPropertyMSBLong(&info,&length)); 00632 if ((*name != '\0') && (*name != '#')) 00633 if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0)) 00634 { 00635 /* 00636 No name match, scroll forward and try next. 00637 */ 00638 info+=count; 00639 length-=MagickMin(count,(ssize_t) length); 00640 continue; 00641 } 00642 if ((*name == '#') && (sub_number != 1)) 00643 { 00644 /* 00645 No numbered match, scroll forward and try next. 00646 */ 00647 sub_number--; 00648 info+=count; 00649 length-=MagickMin(count,(ssize_t) length); 00650 continue; 00651 } 00652 /* 00653 We have the resource of interest. 00654 */ 00655 attribute=(char *) NULL; 00656 if (~(1UL*count) >= (MaxTextExtent-1)) 00657 attribute=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent, 00658 sizeof(*attribute)); 00659 if (attribute != (char *) NULL) 00660 { 00661 (void) CopyMagickMemory(attribute,(char *) info,(size_t) count); 00662 attribute[count]='\0'; 00663 info+=count; 00664 length-=MagickMin(count,(ssize_t) length); 00665 if ((id <= 1999) || (id >= 2999)) 00666 (void) SetImageProperty((Image *) image,key,(const char *) 00667 attribute,exception); 00668 else 00669 { 00670 char 00671 *path; 00672 00673 if (LocaleCompare(format,"svg") == 0) 00674 path=TraceSVGClippath((unsigned char *) attribute,(size_t) count, 00675 image->columns,image->rows); 00676 else 00677 path=TracePSClippath((unsigned char *) attribute,(size_t) count, 00678 image->columns,image->rows); 00679 (void) SetImageProperty((Image *) image,key,(const char *) path, 00680 exception); 00681 path=DestroyString(path); 00682 } 00683 attribute=DestroyString(attribute); 00684 status=MagickTrue; 00685 } 00686 } 00687 if (resource != (char *) NULL) 00688 resource=DestroyString(resource); 00689 return(status); 00690 } 00691 00692 static inline unsigned short ReadPropertyShort(const EndianType endian, 00693 const unsigned char *buffer) 00694 { 00695 unsigned short 00696 value; 00697 00698 if (endian == MSBEndian) 00699 { 00700 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) | 00701 ((unsigned char *) buffer)[1]); 00702 return((unsigned short) (value & 0xffff)); 00703 } 00704 value=(unsigned short) ((buffer[1] << 8) | buffer[0]); 00705 return((unsigned short) (value & 0xffff)); 00706 } 00707 00708 static inline size_t ReadPropertyLong(const EndianType endian, 00709 const unsigned char *buffer) 00710 { 00711 size_t 00712 value; 00713 00714 if (endian == MSBEndian) 00715 { 00716 value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) | 00717 (buffer[2] << 8) | buffer[3]); 00718 return((size_t) (value & 0xffffffff)); 00719 } 00720 value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) | 00721 (buffer[1] << 8 ) | (buffer[0])); 00722 return((size_t) (value & 0xffffffff)); 00723 } 00724 00725 static MagickBooleanType GetEXIFProperty(const Image *image, 00726 const char *property,ExceptionInfo *exception) 00727 { 00728 #define MaxDirectoryStack 16 00729 #define EXIF_DELIMITER "\n" 00730 #define EXIF_NUM_FORMATS 12 00731 #define EXIF_FMT_BYTE 1 00732 #define EXIF_FMT_STRING 2 00733 #define EXIF_FMT_USHORT 3 00734 #define EXIF_FMT_ULONG 4 00735 #define EXIF_FMT_URATIONAL 5 00736 #define EXIF_FMT_SBYTE 6 00737 #define EXIF_FMT_UNDEFINED 7 00738 #define EXIF_FMT_SSHORT 8 00739 #define EXIF_FMT_SLONG 9 00740 #define EXIF_FMT_SRATIONAL 10 00741 #define EXIF_FMT_SINGLE 11 00742 #define EXIF_FMT_DOUBLE 12 00743 #define TAG_EXIF_OFFSET 0x8769 00744 #define TAG_GPS_OFFSET 0x8825 00745 #define TAG_INTEROP_OFFSET 0xa005 00746 00747 #define EXIFMultipleValues(size,format,arg) \ 00748 { \ 00749 ssize_t \ 00750 component; \ 00751 \ 00752 size_t \ 00753 length; \ 00754 \ 00755 unsigned char \ 00756 *p1; \ 00757 \ 00758 length=0; \ 00759 p1=p; \ 00760 for (component=0; component < components; component++) \ 00761 { \ 00762 length+=FormatLocaleString(buffer+length,MaxTextExtent-length, \ 00763 format", ",arg); \ 00764 if (length >= (MaxTextExtent-1)) \ 00765 length=MaxTextExtent-1; \ 00766 p1+=size; \ 00767 } \ 00768 if (length > 1) \ 00769 buffer[length-2]='\0'; \ 00770 value=AcquireString(buffer); \ 00771 } 00772 00773 #define EXIFMultipleFractions(size,format,arg1,arg2) \ 00774 { \ 00775 ssize_t \ 00776 component; \ 00777 \ 00778 size_t \ 00779 length; \ 00780 \ 00781 unsigned char \ 00782 *p1; \ 00783 \ 00784 length=0; \ 00785 p1=p; \ 00786 for (component=0; component < components; component++) \ 00787 { \ 00788 length+=FormatLocaleString(buffer+length,MaxTextExtent-length, \ 00789 format", ",arg1,arg2); \ 00790 if (length >= (MaxTextExtent-1)) \ 00791 length=MaxTextExtent-1; \ 00792 p1+=size; \ 00793 } \ 00794 if (length > 1) \ 00795 buffer[length-2]='\0'; \ 00796 value=AcquireString(buffer); \ 00797 } 00798 00799 typedef struct _DirectoryInfo 00800 { 00801 const unsigned char 00802 *directory; 00803 00804 size_t 00805 entry, 00806 offset; 00807 } DirectoryInfo; 00808 00809 typedef struct _TagInfo 00810 { 00811 size_t 00812 tag; 00813 00814 const char 00815 *description; 00816 } TagInfo; 00817 00818 static TagInfo 00819 EXIFTag[] = 00820 { 00821 { 0x001, "exif:InteroperabilityIndex" }, 00822 { 0x002, "exif:InteroperabilityVersion" }, 00823 { 0x100, "exif:ImageWidth" }, 00824 { 0x101, "exif:ImageLength" }, 00825 { 0x102, "exif:BitsPerSample" }, 00826 { 0x103, "exif:Compression" }, 00827 { 0x106, "exif:PhotometricInterpretation" }, 00828 { 0x10a, "exif:FillOrder" }, 00829 { 0x10d, "exif:DocumentName" }, 00830 { 0x10e, "exif:ImageDescription" }, 00831 { 0x10f, "exif:Make" }, 00832 { 0x110, "exif:Model" }, 00833 { 0x111, "exif:StripOffsets" }, 00834 { 0x112, "exif:Orientation" }, 00835 { 0x115, "exif:SamplesPerPixel" }, 00836 { 0x116, "exif:RowsPerStrip" }, 00837 { 0x117, "exif:StripByteCounts" }, 00838 { 0x11a, "exif:XResolution" }, 00839 { 0x11b, "exif:YResolution" }, 00840 { 0x11c, "exif:PlanarConfiguration" }, 00841 { 0x11d, "exif:PageName" }, 00842 { 0x11e, "exif:XPosition" }, 00843 { 0x11f, "exif:YPosition" }, 00844 { 0x118, "exif:MinSampleValue" }, 00845 { 0x119, "exif:MaxSampleValue" }, 00846 { 0x120, "exif:FreeOffsets" }, 00847 { 0x121, "exif:FreeByteCounts" }, 00848 { 0x122, "exif:GrayResponseUnit" }, 00849 { 0x123, "exif:GrayResponseCurve" }, 00850 { 0x124, "exif:T4Options" }, 00851 { 0x125, "exif:T6Options" }, 00852 { 0x128, "exif:ResolutionUnit" }, 00853 { 0x12d, "exif:TransferFunction" }, 00854 { 0x131, "exif:Software" }, 00855 { 0x132, "exif:DateTime" }, 00856 { 0x13b, "exif:Artist" }, 00857 { 0x13e, "exif:WhitePoint" }, 00858 { 0x13f, "exif:PrimaryChromaticities" }, 00859 { 0x140, "exif:ColorMap" }, 00860 { 0x141, "exif:HalfToneHints" }, 00861 { 0x142, "exif:TileWidth" }, 00862 { 0x143, "exif:TileLength" }, 00863 { 0x144, "exif:TileOffsets" }, 00864 { 0x145, "exif:TileByteCounts" }, 00865 { 0x14a, "exif:SubIFD" }, 00866 { 0x14c, "exif:InkSet" }, 00867 { 0x14d, "exif:InkNames" }, 00868 { 0x14e, "exif:NumberOfInks" }, 00869 { 0x150, "exif:DotRange" }, 00870 { 0x151, "exif:TargetPrinter" }, 00871 { 0x152, "exif:ExtraSample" }, 00872 { 0x153, "exif:SampleFormat" }, 00873 { 0x154, "exif:SMinSampleValue" }, 00874 { 0x155, "exif:SMaxSampleValue" }, 00875 { 0x156, "exif:TransferRange" }, 00876 { 0x157, "exif:ClipPath" }, 00877 { 0x158, "exif:XClipPathUnits" }, 00878 { 0x159, "exif:YClipPathUnits" }, 00879 { 0x15a, "exif:Indexed" }, 00880 { 0x15b, "exif:JPEGTables" }, 00881 { 0x15f, "exif:OPIProxy" }, 00882 { 0x200, "exif:JPEGProc" }, 00883 { 0x201, "exif:JPEGInterchangeFormat" }, 00884 { 0x202, "exif:JPEGInterchangeFormatLength" }, 00885 { 0x203, "exif:JPEGRestartInterval" }, 00886 { 0x205, "exif:JPEGLosslessPredictors" }, 00887 { 0x206, "exif:JPEGPointTransforms" }, 00888 { 0x207, "exif:JPEGQTables" }, 00889 { 0x208, "exif:JPEGDCTables" }, 00890 { 0x209, "exif:JPEGACTables" }, 00891 { 0x211, "exif:YCbCrCoefficients" }, 00892 { 0x212, "exif:YCbCrSubSampling" }, 00893 { 0x213, "exif:YCbCrPositioning" }, 00894 { 0x214, "exif:ReferenceBlackWhite" }, 00895 { 0x2bc, "exif:ExtensibleMetadataPlatform" }, 00896 { 0x301, "exif:Gamma" }, 00897 { 0x302, "exif:ICCProfileDescriptor" }, 00898 { 0x303, "exif:SRGBRenderingIntent" }, 00899 { 0x320, "exif:ImageTitle" }, 00900 { 0x5001, "exif:ResolutionXUnit" }, 00901 { 0x5002, "exif:ResolutionYUnit" }, 00902 { 0x5003, "exif:ResolutionXLengthUnit" }, 00903 { 0x5004, "exif:ResolutionYLengthUnit" }, 00904 { 0x5005, "exif:PrintFlags" }, 00905 { 0x5006, "exif:PrintFlagsVersion" }, 00906 { 0x5007, "exif:PrintFlagsCrop" }, 00907 { 0x5008, "exif:PrintFlagsBleedWidth" }, 00908 { 0x5009, "exif:PrintFlagsBleedWidthScale" }, 00909 { 0x500A, "exif:HalftoneLPI" }, 00910 { 0x500B, "exif:HalftoneLPIUnit" }, 00911 { 0x500C, "exif:HalftoneDegree" }, 00912 { 0x500D, "exif:HalftoneShape" }, 00913 { 0x500E, "exif:HalftoneMisc" }, 00914 { 0x500F, "exif:HalftoneScreen" }, 00915 { 0x5010, "exif:JPEGQuality" }, 00916 { 0x5011, "exif:GridSize" }, 00917 { 0x5012, "exif:ThumbnailFormat" }, 00918 { 0x5013, "exif:ThumbnailWidth" }, 00919 { 0x5014, "exif:ThumbnailHeight" }, 00920 { 0x5015, "exif:ThumbnailColorDepth" }, 00921 { 0x5016, "exif:ThumbnailPlanes" }, 00922 { 0x5017, "exif:ThumbnailRawBytes" }, 00923 { 0x5018, "exif:ThumbnailSize" }, 00924 { 0x5019, "exif:ThumbnailCompressedSize" }, 00925 { 0x501a, "exif:ColorTransferFunction" }, 00926 { 0x501b, "exif:ThumbnailData" }, 00927 { 0x5020, "exif:ThumbnailImageWidth" }, 00928 { 0x5021, "exif:ThumbnailImageHeight" }, 00929 { 0x5022, "exif:ThumbnailBitsPerSample" }, 00930 { 0x5023, "exif:ThumbnailCompression" }, 00931 { 0x5024, "exif:ThumbnailPhotometricInterp" }, 00932 { 0x5025, "exif:ThumbnailImageDescription" }, 00933 { 0x5026, "exif:ThumbnailEquipMake" }, 00934 { 0x5027, "exif:ThumbnailEquipModel" }, 00935 { 0x5028, "exif:ThumbnailStripOffsets" }, 00936 { 0x5029, "exif:ThumbnailOrientation" }, 00937 { 0x502a, "exif:ThumbnailSamplesPerPixel" }, 00938 { 0x502b, "exif:ThumbnailRowsPerStrip" }, 00939 { 0x502c, "exif:ThumbnailStripBytesCount" }, 00940 { 0x502d, "exif:ThumbnailResolutionX" }, 00941 { 0x502e, "exif:ThumbnailResolutionY" }, 00942 { 0x502f, "exif:ThumbnailPlanarConfig" }, 00943 { 0x5030, "exif:ThumbnailResolutionUnit" }, 00944 { 0x5031, "exif:ThumbnailTransferFunction" }, 00945 { 0x5032, "exif:ThumbnailSoftwareUsed" }, 00946 { 0x5033, "exif:ThumbnailDateTime" }, 00947 { 0x5034, "exif:ThumbnailArtist" }, 00948 { 0x5035, "exif:ThumbnailWhitePoint" }, 00949 { 0x5036, "exif:ThumbnailPrimaryChromaticities" }, 00950 { 0x5037, "exif:ThumbnailYCbCrCoefficients" }, 00951 { 0x5038, "exif:ThumbnailYCbCrSubsampling" }, 00952 { 0x5039, "exif:ThumbnailYCbCrPositioning" }, 00953 { 0x503A, "exif:ThumbnailRefBlackWhite" }, 00954 { 0x503B, "exif:ThumbnailCopyRight" }, 00955 { 0x5090, "exif:LuminanceTable" }, 00956 { 0x5091, "exif:ChrominanceTable" }, 00957 { 0x5100, "exif:FrameDelay" }, 00958 { 0x5101, "exif:LoopCount" }, 00959 { 0x5110, "exif:PixelUnit" }, 00960 { 0x5111, "exif:PixelPerUnitX" }, 00961 { 0x5112, "exif:PixelPerUnitY" }, 00962 { 0x5113, "exif:PaletteHistogram" }, 00963 { 0x1000, "exif:RelatedImageFileFormat" }, 00964 { 0x1001, "exif:RelatedImageLength" }, 00965 { 0x1002, "exif:RelatedImageWidth" }, 00966 { 0x800d, "exif:ImageID" }, 00967 { 0x80e3, "exif:Matteing" }, 00968 { 0x80e4, "exif:DataType" }, 00969 { 0x80e5, "exif:ImageDepth" }, 00970 { 0x80e6, "exif:TileDepth" }, 00971 { 0x828d, "exif:CFARepeatPatternDim" }, 00972 { 0x828e, "exif:CFAPattern2" }, 00973 { 0x828f, "exif:BatteryLevel" }, 00974 { 0x8298, "exif:Copyright" }, 00975 { 0x829a, "exif:ExposureTime" }, 00976 { 0x829d, "exif:FNumber" }, 00977 { 0x83bb, "exif:IPTC/NAA" }, 00978 { 0x84e3, "exif:IT8RasterPadding" }, 00979 { 0x84e5, "exif:IT8ColorTable" }, 00980 { 0x8649, "exif:ImageResourceInformation" }, 00981 { 0x8769, "exif:ExifOffset" }, 00982 { 0x8773, "exif:InterColorProfile" }, 00983 { 0x8822, "exif:ExposureProgram" }, 00984 { 0x8824, "exif:SpectralSensitivity" }, 00985 { 0x8825, "exif:GPSInfo" }, 00986 { 0x8827, "exif:ISOSpeedRatings" }, 00987 { 0x8828, "exif:OECF" }, 00988 { 0x8829, "exif:Interlace" }, 00989 { 0x882a, "exif:TimeZoneOffset" }, 00990 { 0x882b, "exif:SelfTimerMode" }, 00991 { 0x9000, "exif:ExifVersion" }, 00992 { 0x9003, "exif:DateTimeOriginal" }, 00993 { 0x9004, "exif:DateTimeDigitized" }, 00994 { 0x9101, "exif:ComponentsConfiguration" }, 00995 { 0x9102, "exif:CompressedBitsPerPixel" }, 00996 { 0x9201, "exif:ShutterSpeedValue" }, 00997 { 0x9202, "exif:ApertureValue" }, 00998 { 0x9203, "exif:BrightnessValue" }, 00999 { 0x9204, "exif:ExposureBiasValue" }, 01000 { 0x9205, "exif:MaxApertureValue" }, 01001 { 0x9206, "exif:SubjectDistance" }, 01002 { 0x9207, "exif:MeteringMode" }, 01003 { 0x9208, "exif:LightSource" }, 01004 { 0x9209, "exif:Flash" }, 01005 { 0x920a, "exif:FocalLength" }, 01006 { 0x920b, "exif:FlashEnergy" }, 01007 { 0x920c, "exif:SpatialFrequencyResponse" }, 01008 { 0x920d, "exif:Noise" }, 01009 { 0x9211, "exif:ImageNumber" }, 01010 { 0x9212, "exif:SecurityClassification" }, 01011 { 0x9213, "exif:ImageHistory" }, 01012 { 0x9214, "exif:SubjectArea" }, 01013 { 0x9215, "exif:ExposureIndex" }, 01014 { 0x9216, "exif:TIFF-EPStandardID" }, 01015 { 0x927c, "exif:MakerNote" }, 01016 { 0x9C9b, "exif:WinXP-Title" }, 01017 { 0x9C9c, "exif:WinXP-Comments" }, 01018 { 0x9C9d, "exif:WinXP-Author" }, 01019 { 0x9C9e, "exif:WinXP-Keywords" }, 01020 { 0x9C9f, "exif:WinXP-Subject" }, 01021 { 0x9286, "exif:UserComment" }, 01022 { 0x9290, "exif:SubSecTime" }, 01023 { 0x9291, "exif:SubSecTimeOriginal" }, 01024 { 0x9292, "exif:SubSecTimeDigitized" }, 01025 { 0xa000, "exif:FlashPixVersion" }, 01026 { 0xa001, "exif:ColorSpace" }, 01027 { 0xa002, "exif:ExifImageWidth" }, 01028 { 0xa003, "exif:ExifImageLength" }, 01029 { 0xa004, "exif:RelatedSoundFile" }, 01030 { 0xa005, "exif:InteroperabilityOffset" }, 01031 { 0xa20b, "exif:FlashEnergy" }, 01032 { 0xa20c, "exif:SpatialFrequencyResponse" }, 01033 { 0xa20d, "exif:Noise" }, 01034 { 0xa20e, "exif:FocalPlaneXResolution" }, 01035 { 0xa20f, "exif:FocalPlaneYResolution" }, 01036 { 0xa210, "exif:FocalPlaneResolutionUnit" }, 01037 { 0xa214, "exif:SubjectLocation" }, 01038 { 0xa215, "exif:ExposureIndex" }, 01039 { 0xa216, "exif:TIFF/EPStandardID" }, 01040 { 0xa217, "exif:SensingMethod" }, 01041 { 0xa300, "exif:FileSource" }, 01042 { 0xa301, "exif:SceneType" }, 01043 { 0xa302, "exif:CFAPattern" }, 01044 { 0xa401, "exif:CustomRendered" }, 01045 { 0xa402, "exif:ExposureMode" }, 01046 { 0xa403, "exif:WhiteBalance" }, 01047 { 0xa404, "exif:DigitalZoomRatio" }, 01048 { 0xa405, "exif:FocalLengthIn35mmFilm" }, 01049 { 0xa406, "exif:SceneCaptureType" }, 01050 { 0xa407, "exif:GainControl" }, 01051 { 0xa408, "exif:Contrast" }, 01052 { 0xa409, "exif:Saturation" }, 01053 { 0xa40a, "exif:Sharpness" }, 01054 { 0xa40b, "exif:DeviceSettingDescription" }, 01055 { 0xa40c, "exif:SubjectDistanceRange" }, 01056 { 0xa420, "exif:ImageUniqueID" }, 01057 { 0xc4a5, "exif:PrintImageMatching" }, 01058 { 0xa500, "exif:Gamma" }, 01059 { 0xc640, "exif:CR2Slice" }, 01060 { 0x10000, "exif:GPSVersionID" }, 01061 { 0x10001, "exif:GPSLatitudeRef" }, 01062 { 0x10002, "exif:GPSLatitude" }, 01063 { 0x10003, "exif:GPSLongitudeRef" }, 01064 { 0x10004, "exif:GPSLongitude" }, 01065 { 0x10005, "exif:GPSAltitudeRef" }, 01066 { 0x10006, "exif:GPSAltitude" }, 01067 { 0x10007, "exif:GPSTimeStamp" }, 01068 { 0x10008, "exif:GPSSatellites" }, 01069 { 0x10009, "exif:GPSStatus" }, 01070 { 0x1000a, "exif:GPSMeasureMode" }, 01071 { 0x1000b, "exif:GPSDop" }, 01072 { 0x1000c, "exif:GPSSpeedRef" }, 01073 { 0x1000d, "exif:GPSSpeed" }, 01074 { 0x1000e, "exif:GPSTrackRef" }, 01075 { 0x1000f, "exif:GPSTrack" }, 01076 { 0x10010, "exif:GPSImgDirectionRef" }, 01077 { 0x10011, "exif:GPSImgDirection" }, 01078 { 0x10012, "exif:GPSMapDatum" }, 01079 { 0x10013, "exif:GPSDestLatitudeRef" }, 01080 { 0x10014, "exif:GPSDestLatitude" }, 01081 { 0x10015, "exif:GPSDestLongitudeRef" }, 01082 { 0x10016, "exif:GPSDestLongitude" }, 01083 { 0x10017, "exif:GPSDestBearingRef" }, 01084 { 0x10018, "exif:GPSDestBearing" }, 01085 { 0x10019, "exif:GPSDestDistanceRef" }, 01086 { 0x1001a, "exif:GPSDestDistance" }, 01087 { 0x1001b, "exif:GPSProcessingMethod" }, 01088 { 0x1001c, "exif:GPSAreaInformation" }, 01089 { 0x1001d, "exif:GPSDateStamp" }, 01090 { 0x1001e, "exif:GPSDifferential" }, 01091 { 0x0000, NULL} 01092 }; 01093 01094 const StringInfo 01095 *profile; 01096 01097 const unsigned char 01098 *directory, 01099 *exif; 01100 01101 DirectoryInfo 01102 directory_stack[MaxDirectoryStack]; 01103 01104 EndianType 01105 endian; 01106 01107 MagickBooleanType 01108 status; 01109 01110 register ssize_t 01111 i; 01112 01113 size_t 01114 entry, 01115 length, 01116 number_entries, 01117 tag_offset, 01118 tag; 01119 01120 SplayTreeInfo 01121 *exif_resources; 01122 01123 ssize_t 01124 all, 01125 id, 01126 level, 01127 offset, 01128 tag_value; 01129 01130 static int 01131 tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}; 01132 01133 /* 01134 If EXIF data exists, then try to parse the request for a tag. 01135 */ 01136 profile=GetImageProfile(image,"exif"); 01137 if (profile == (StringInfo *) NULL) 01138 return(MagickFalse); 01139 if ((property == (const char *) NULL) || (*property == '\0')) 01140 return(MagickFalse); 01141 while (isspace((int) ((unsigned char) *property)) != 0) 01142 property++; 01143 all=0; 01144 tag=(~0UL); 01145 switch (*(property+5)) 01146 { 01147 case '*': 01148 { 01149 /* 01150 Caller has asked for all the tags in the EXIF data. 01151 */ 01152 tag=0; 01153 all=1; /* return the data in description=value format */ 01154 break; 01155 } 01156 case '!': 01157 { 01158 tag=0; 01159 all=2; /* return the data in tagid=value format */ 01160 break; 01161 } 01162 case '#': 01163 case '@': 01164 { 01165 int 01166 c; 01167 01168 size_t 01169 n; 01170 01171 /* 01172 Check for a hex based tag specification first. 01173 */ 01174 tag=(*(property+5) == '@') ? 1UL : 0UL; 01175 property+=6; 01176 n=strlen(property); 01177 if (n != 4) 01178 return(MagickFalse); 01179 /* 01180 Parse tag specification as a hex number. 01181 */ 01182 n/=4; 01183 do 01184 { 01185 for (i=(ssize_t) n-1L; i >= 0; i--) 01186 { 01187 c=(*property++); 01188 tag<<=4; 01189 if ((c >= '0') && (c <= '9')) 01190 tag|=(c-'0'); 01191 else 01192 if ((c >= 'A') && (c <= 'F')) 01193 tag|=(c-('A'-10)); 01194 else 01195 if ((c >= 'a') && (c <= 'f')) 01196 tag|=(c-('a'-10)); 01197 else 01198 return(MagickFalse); 01199 } 01200 } while (*property != '\0'); 01201 break; 01202 } 01203 default: 01204 { 01205 /* 01206 Try to match the text with a tag name instead. 01207 */ 01208 for (i=0; ; i++) 01209 { 01210 if (EXIFTag[i].tag == 0) 01211 break; 01212 if (LocaleCompare(EXIFTag[i].description,property) == 0) 01213 { 01214 tag=(size_t) EXIFTag[i].tag; 01215 break; 01216 } 01217 } 01218 break; 01219 } 01220 } 01221 if (tag == (~0UL)) 01222 return(MagickFalse); 01223 length=GetStringInfoLength(profile); 01224 exif=GetStringInfoDatum(profile); 01225 while (length != 0) 01226 { 01227 if (ReadPropertyByte(&exif,&length) != 0x45) 01228 continue; 01229 if (ReadPropertyByte(&exif,&length) != 0x78) 01230 continue; 01231 if (ReadPropertyByte(&exif,&length) != 0x69) 01232 continue; 01233 if (ReadPropertyByte(&exif,&length) != 0x66) 01234 continue; 01235 if (ReadPropertyByte(&exif,&length) != 0x00) 01236 continue; 01237 if (ReadPropertyByte(&exif,&length) != 0x00) 01238 continue; 01239 break; 01240 } 01241 if (length < 16) 01242 return(MagickFalse); 01243 id=(ssize_t) ((int) ReadPropertyShort(LSBEndian,exif)); 01244 endian=LSBEndian; 01245 if (id == 0x4949) 01246 endian=LSBEndian; 01247 else 01248 if (id == 0x4D4D) 01249 endian=MSBEndian; 01250 else 01251 return(MagickFalse); 01252 if (ReadPropertyShort(endian,exif+2) != 0x002a) 01253 return(MagickFalse); 01254 /* 01255 This the offset to the first IFD. 01256 */ 01257 offset=(ssize_t) ((int) ReadPropertyLong(endian,exif+4)); 01258 if ((size_t) offset >= length) 01259 return(MagickFalse); 01260 /* 01261 Set the pointer to the first IFD and follow it were it leads. 01262 */ 01263 status=MagickFalse; 01264 directory=exif+offset; 01265 level=0; 01266 entry=0; 01267 tag_offset=0; 01268 exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL, 01269 (void *(*)(void *)) NULL,(void *(*)(void *)) NULL); 01270 do 01271 { 01272 /* 01273 If there is anything on the stack then pop it off. 01274 */ 01275 if (level > 0) 01276 { 01277 level--; 01278 directory=directory_stack[level].directory; 01279 entry=directory_stack[level].entry; 01280 tag_offset=directory_stack[level].offset; 01281 } 01282 /* 01283 Determine how many entries there are in the current IFD. 01284 */ 01285 number_entries=(size_t) ((int) ReadPropertyShort(endian,directory)); 01286 for ( ; entry < number_entries; entry++) 01287 { 01288 register unsigned char 01289 *p, 01290 *q; 01291 01292 size_t 01293 format, 01294 number_bytes; 01295 01296 ssize_t 01297 components; 01298 01299 q=(unsigned char *) (directory+(12*entry)+2); 01300 if (GetValueFromSplayTree(exif_resources,q) == q) 01301 break; 01302 (void) AddValueToSplayTree(exif_resources,q,q); 01303 tag_value=(ssize_t) ((int) ReadPropertyShort(endian,q)+tag_offset); 01304 format=(size_t) ((int) ReadPropertyShort(endian,q+2)); 01305 if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes))) 01306 break; 01307 components=(ssize_t) ((int) ReadPropertyLong(endian,q+4)); 01308 number_bytes=(size_t) components*tag_bytes[format]; 01309 if (number_bytes <= 4) 01310 p=q+8; 01311 else 01312 { 01313 ssize_t 01314 offset; 01315 01316 /* 01317 The directory entry contains an offset. 01318 */ 01319 offset=(ssize_t) ((int) ReadPropertyLong(endian,q+8)); 01320 if ((size_t) (offset+number_bytes) > length) 01321 continue; 01322 p=(unsigned char *) (exif+offset); 01323 } 01324 if ((all != 0) || (tag == (size_t) tag_value)) 01325 { 01326 char 01327 buffer[MaxTextExtent], 01328 *value; 01329 01330 switch (format) 01331 { 01332 case EXIF_FMT_BYTE: 01333 case EXIF_FMT_UNDEFINED: 01334 { 01335 EXIFMultipleValues(1,"%.20g",(double) (*(unsigned char *) p1)); 01336 break; 01337 } 01338 case EXIF_FMT_SBYTE: 01339 { 01340 EXIFMultipleValues(1,"%.20g",(double) (*(signed char *) p1)); 01341 break; 01342 } 01343 case EXIF_FMT_SSHORT: 01344 { 01345 EXIFMultipleValues(2,"%hd",ReadPropertyShort(endian,p1)); 01346 break; 01347 } 01348 case EXIF_FMT_USHORT: 01349 { 01350 EXIFMultipleValues(2,"%hu",ReadPropertyShort(endian,p1)); 01351 break; 01352 } 01353 case EXIF_FMT_ULONG: 01354 { 01355 EXIFMultipleValues(4,"%.20g",(double) 01356 ((int) ReadPropertyLong(endian,p1))); 01357 break; 01358 } 01359 case EXIF_FMT_SLONG: 01360 { 01361 EXIFMultipleValues(4,"%.20g",(double) 01362 ((int) ReadPropertyLong(endian,p1))); 01363 break; 01364 } 01365 case EXIF_FMT_URATIONAL: 01366 { 01367 EXIFMultipleFractions(8,"%.20g/%.20g",(double) 01368 ((int) ReadPropertyLong(endian,p1)),(double) 01369 ((int) ReadPropertyLong(endian,p1+4))); 01370 break; 01371 } 01372 case EXIF_FMT_SRATIONAL: 01373 { 01374 EXIFMultipleFractions(8,"%.20g/%.20g",(double) 01375 ((int) ReadPropertyLong(endian,p1)),(double) 01376 ((int) ReadPropertyLong(endian,p1+4))); 01377 break; 01378 } 01379 case EXIF_FMT_SINGLE: 01380 { 01381 EXIFMultipleValues(4,"%f",(double) *(float *) p1); 01382 break; 01383 } 01384 case EXIF_FMT_DOUBLE: 01385 { 01386 EXIFMultipleValues(8,"%f",*(double *) p1); 01387 break; 01388 } 01389 default: 01390 case EXIF_FMT_STRING: 01391 { 01392 value=(char *) NULL; 01393 if (~(1UL*number_bytes) >= 1) 01394 value=(char *) AcquireQuantumMemory((size_t) number_bytes+1UL, 01395 sizeof(*value)); 01396 if (value != (char *) NULL) 01397 { 01398 register ssize_t 01399 i; 01400 01401 for (i=0; i < (ssize_t) number_bytes; i++) 01402 { 01403 value[i]='.'; 01404 if ((isprint((int) p[i]) != 0) || (p[i] == '\0')) 01405 value[i]=(char) p[i]; 01406 } 01407 value[i]='\0'; 01408 } 01409 break; 01410 } 01411 } 01412 if (value != (char *) NULL) 01413 { 01414 char 01415 key[MaxTextExtent]; 01416 01417 register const char 01418 *p; 01419 01420 (void) CopyMagickString(key,property,MaxTextExtent); 01421 switch (all) 01422 { 01423 case 1: 01424 { 01425 const char 01426 *description; 01427 01428 register ssize_t 01429 i; 01430 01431 description="unknown"; 01432 for (i=0; ; i++) 01433 { 01434 if (EXIFTag[i].tag == 0) 01435 break; 01436 if ((ssize_t) EXIFTag[i].tag == tag_value) 01437 { 01438 description=EXIFTag[i].description; 01439 break; 01440 } 01441 } 01442 (void) FormatLocaleString(key,MaxTextExtent,"%s",description); 01443 break; 01444 } 01445 case 2: 01446 { 01447 if (tag_value < 0x10000) 01448 (void) FormatLocaleString(key,MaxTextExtent,"#%04lx", 01449 (unsigned long) tag_value); 01450 else 01451 if (tag_value < 0x20000) 01452 (void) FormatLocaleString(key,MaxTextExtent,"@%04lx", 01453 (unsigned long) (tag_value & 0xffff)); 01454 else 01455 (void) FormatLocaleString(key,MaxTextExtent,"unknown"); 01456 break; 01457 } 01458 } 01459 p=(const char *) NULL; 01460 if (image->properties != (void *) NULL) 01461 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 01462 image->properties,key); 01463 if (p == (const char *) NULL) 01464 (void) SetImageProperty((Image *) image,key,value,exception); 01465 value=DestroyString(value); 01466 status=MagickTrue; 01467 } 01468 } 01469 if ((tag_value == TAG_EXIF_OFFSET) || 01470 (tag_value == TAG_INTEROP_OFFSET) || (tag_value == TAG_GPS_OFFSET)) 01471 { 01472 size_t 01473 offset; 01474 01475 offset=(size_t) ((int) ReadPropertyLong(endian,p)); 01476 if ((offset < length) && (level < (MaxDirectoryStack-2))) 01477 { 01478 size_t 01479 tag_offset1; 01480 01481 tag_offset1=(tag_value == TAG_GPS_OFFSET) ? 0x10000UL : 0UL; 01482 directory_stack[level].directory=directory; 01483 entry++; 01484 directory_stack[level].entry=entry; 01485 directory_stack[level].offset=tag_offset; 01486 level++; 01487 directory_stack[level].directory=exif+offset; 01488 directory_stack[level].offset=tag_offset1; 01489 directory_stack[level].entry=0; 01490 level++; 01491 if ((directory+2+(12*number_entries)) > (exif+length)) 01492 break; 01493 offset=(size_t) ((int) ReadPropertyLong(endian,directory+2+(12* 01494 number_entries))); 01495 if ((offset != 0) && (offset < length) && 01496 (level < (MaxDirectoryStack-2))) 01497 { 01498 directory_stack[level].directory=exif+offset; 01499 directory_stack[level].entry=0; 01500 directory_stack[level].offset=tag_offset1; 01501 level++; 01502 } 01503 } 01504 break; 01505 } 01506 } 01507 } while (level > 0); 01508 exif_resources=DestroySplayTree(exif_resources); 01509 return(status); 01510 } 01511 01512 static MagickBooleanType GetXMPProperty(const Image *image,const char *property) 01513 { 01514 char 01515 *xmp_profile; 01516 01517 const StringInfo 01518 *profile; 01519 01520 ExceptionInfo 01521 *exception; 01522 01523 MagickBooleanType 01524 status; 01525 01526 register const char 01527 *p; 01528 01529 XMLTreeInfo 01530 *child, 01531 *description, 01532 *node, 01533 *rdf, 01534 *xmp; 01535 01536 profile=GetImageProfile(image,"xmp"); 01537 if (profile == (StringInfo *) NULL) 01538 return(MagickFalse); 01539 if ((property == (const char *) NULL) || (*property == '\0')) 01540 return(MagickFalse); 01541 xmp_profile=StringInfoToString(profile); 01542 if (xmp_profile == (char *) NULL) 01543 return(MagickFalse); 01544 for (p=xmp_profile; *p != '\0'; p++) 01545 if ((*p == '<') && (*(p+1) == 'x')) 01546 break; 01547 exception=AcquireExceptionInfo(); 01548 xmp=NewXMLTree((char *) p,exception); 01549 xmp_profile=DestroyString(xmp_profile); 01550 exception=DestroyExceptionInfo(exception); 01551 if (xmp == (XMLTreeInfo *) NULL) 01552 return(MagickFalse); 01553 status=MagickFalse; 01554 rdf=GetXMLTreeChild(xmp,"rdf:RDF"); 01555 if (rdf != (XMLTreeInfo *) NULL) 01556 { 01557 if (image->properties == (void *) NULL) 01558 ((Image *) image)->properties=NewSplayTree(CompareSplayTreeString, 01559 RelinquishMagickMemory,RelinquishMagickMemory); 01560 description=GetXMLTreeChild(rdf,"rdf:Description"); 01561 while (description != (XMLTreeInfo *) NULL) 01562 { 01563 node=GetXMLTreeChild(description,(const char *) NULL); 01564 while (node != (XMLTreeInfo *) NULL) 01565 { 01566 child=GetXMLTreeChild(node,(const char *) NULL); 01567 if (child == (XMLTreeInfo *) NULL) 01568 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties, 01569 ConstantString(GetXMLTreeTag(node)), 01570 ConstantString(GetXMLTreeContent(node))); 01571 while (child != (XMLTreeInfo *) NULL) 01572 { 01573 if (LocaleCompare(GetXMLTreeTag(child),"rdf:Seq") != 0) 01574 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties, 01575 ConstantString(GetXMLTreeTag(child)), 01576 ConstantString(GetXMLTreeContent(child))); 01577 child=GetXMLTreeSibling(child); 01578 } 01579 node=GetXMLTreeSibling(node); 01580 } 01581 description=GetNextXMLTreeTag(description); 01582 } 01583 } 01584 xmp=DestroyXMLTree(xmp); 01585 return(status); 01586 } 01587 01588 static char *TracePSClippath(const unsigned char *blob,size_t length, 01589 const size_t magick_unused(columns),const size_t magick_unused(rows)) 01590 { 01591 char 01592 *path, 01593 *message; 01594 01595 MagickBooleanType 01596 in_subpath; 01597 01598 PointInfo 01599 first[3], 01600 last[3], 01601 point[3]; 01602 01603 register ssize_t 01604 i, 01605 x; 01606 01607 ssize_t 01608 knot_count, 01609 selector, 01610 y; 01611 01612 path=AcquireString((char *) NULL); 01613 if (path == (char *) NULL) 01614 return((char *) NULL); 01615 message=AcquireString((char *) NULL); 01616 (void) FormatLocaleString(message,MaxTextExtent,"/ClipImage\n"); 01617 (void) ConcatenateString(&path,message); 01618 (void) FormatLocaleString(message,MaxTextExtent,"{\n"); 01619 (void) ConcatenateString(&path,message); 01620 (void) FormatLocaleString(message,MaxTextExtent," /c {curveto} bind def\n"); 01621 (void) ConcatenateString(&path,message); 01622 (void) FormatLocaleString(message,MaxTextExtent," /l {lineto} bind def\n"); 01623 (void) ConcatenateString(&path,message); 01624 (void) FormatLocaleString(message,MaxTextExtent," /m {moveto} bind def\n"); 01625 (void) ConcatenateString(&path,message); 01626 (void) FormatLocaleString(message,MaxTextExtent, 01627 " /v {currentpoint 6 2 roll curveto} bind def\n"); 01628 (void) ConcatenateString(&path,message); 01629 (void) FormatLocaleString(message,MaxTextExtent, 01630 " /y {2 copy curveto} bind def\n"); 01631 (void) ConcatenateString(&path,message); 01632 (void) FormatLocaleString(message,MaxTextExtent, 01633 " /z {closepath} bind def\n"); 01634 (void) ConcatenateString(&path,message); 01635 (void) FormatLocaleString(message,MaxTextExtent," newpath\n"); 01636 (void) ConcatenateString(&path,message); 01637 /* 01638 The clipping path format is defined in "Adobe Photoshop File 01639 Formats Specification" version 6.0 downloadable from adobe.com. 01640 */ 01641 (void) ResetMagickMemory(point,0,sizeof(point)); 01642 (void) ResetMagickMemory(first,0,sizeof(first)); 01643 (void) ResetMagickMemory(last,0,sizeof(last)); 01644 knot_count=0; 01645 in_subpath=MagickFalse; 01646 while (length > 0) 01647 { 01648 selector=(ssize_t) ((int) ReadPropertyMSBShort(&blob,&length)); 01649 switch (selector) 01650 { 01651 case 0: 01652 case 3: 01653 { 01654 if (knot_count != 0) 01655 { 01656 blob+=24; 01657 length-=MagickMin(24,(ssize_t) length); 01658 break; 01659 } 01660 /* 01661 Expected subpath length record. 01662 */ 01663 knot_count=(ssize_t) ((int) ReadPropertyMSBShort(&blob,&length)); 01664 blob+=22; 01665 length-=MagickMin(22,(ssize_t) length); 01666 break; 01667 } 01668 case 1: 01669 case 2: 01670 case 4: 01671 case 5: 01672 { 01673 if (knot_count == 0) 01674 { 01675 /* 01676 Unexpected subpath knot 01677 */ 01678 blob+=24; 01679 length-=MagickMin(24,(ssize_t) length); 01680 break; 01681 } 01682 /* 01683 Add sub-path knot 01684 */ 01685 for (i=0; i < 3; i++) 01686 { 01687 size_t 01688 xx, 01689 yy; 01690 01691 yy=(size_t) ((int) ReadPropertyMSBLong(&blob,&length)); 01692 xx=(size_t) ((int) ReadPropertyMSBLong(&blob,&length)); 01693 x=(ssize_t) xx; 01694 if (xx > 2147483647) 01695 x=(ssize_t) xx-4294967295U-1; 01696 y=(ssize_t) yy; 01697 if (yy > 2147483647) 01698 y=(ssize_t) yy-4294967295U-1; 01699 point[i].x=(double) x/4096/4096; 01700 point[i].y=1.0-(double) y/4096/4096; 01701 } 01702 if (in_subpath == MagickFalse) 01703 { 01704 (void) FormatLocaleString(message,MaxTextExtent," %g %g m\n", 01705 point[1].x,point[1].y); 01706 for (i=0; i < 3; i++) 01707 { 01708 first[i]=point[i]; 01709 last[i]=point[i]; 01710 } 01711 } 01712 else 01713 { 01714 /* 01715 Handle special cases when Bezier curves are used to describe 01716 corners and straight lines. 01717 */ 01718 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) && 01719 (point[0].x == point[1].x) && (point[0].y == point[1].y)) 01720 (void) FormatLocaleString(message,MaxTextExtent, 01721 " %g %g l\n",point[1].x,point[1].y); 01722 else 01723 if ((last[1].x == last[2].x) && (last[1].y == last[2].y)) 01724 (void) FormatLocaleString(message,MaxTextExtent, 01725 " %g %g %g %g v\n",point[0].x,point[0].y, 01726 point[1].x,point[1].y); 01727 else 01728 if ((point[0].x == point[1].x) && (point[0].y == point[1].y)) 01729 (void) FormatLocaleString(message,MaxTextExtent, 01730 " %g %g %g %g y\n",last[2].x,last[2].y, 01731 point[1].x,point[1].y); 01732 else 01733 (void) FormatLocaleString(message,MaxTextExtent, 01734 " %g %g %g %g %g %g c\n",last[2].x, 01735 last[2].y,point[0].x,point[0].y,point[1].x,point[1].y); 01736 for (i=0; i < 3; i++) 01737 last[i]=point[i]; 01738 } 01739 (void) ConcatenateString(&path,message); 01740 in_subpath=MagickTrue; 01741 knot_count--; 01742 /* 01743 Close the subpath if there are no more knots. 01744 */ 01745 if (knot_count == 0) 01746 { 01747 /* 01748 Same special handling as above except we compare to the 01749 first point in the path and close the path. 01750 */ 01751 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) && 01752 (first[0].x == first[1].x) && (first[0].y == first[1].y)) 01753 (void) FormatLocaleString(message,MaxTextExtent, 01754 " %g %g l z\n",first[1].x,first[1].y); 01755 else 01756 if ((last[1].x == last[2].x) && (last[1].y == last[2].y)) 01757 (void) FormatLocaleString(message,MaxTextExtent, 01758 " %g %g %g %g v z\n",first[0].x,first[0].y, 01759 first[1].x,first[1].y); 01760 else 01761 if ((first[0].x == first[1].x) && (first[0].y == first[1].y)) 01762 (void) FormatLocaleString(message,MaxTextExtent, 01763 " %g %g %g %g y z\n",last[2].x,last[2].y, 01764 first[1].x,first[1].y); 01765 else 01766 (void) FormatLocaleString(message,MaxTextExtent, 01767 " %g %g %g %g %g %g c z\n",last[2].x, 01768 last[2].y,first[0].x,first[0].y,first[1].x,first[1].y); 01769 (void) ConcatenateString(&path,message); 01770 in_subpath=MagickFalse; 01771 } 01772 break; 01773 } 01774 case 6: 01775 case 7: 01776 case 8: 01777 default: 01778 { 01779 blob+=24; 01780 length-=MagickMin(24,(ssize_t) length); 01781 break; 01782 } 01783 } 01784 } 01785 /* 01786 Returns an empty PS path if the path has no knots. 01787 */ 01788 (void) FormatLocaleString(message,MaxTextExtent," eoclip\n"); 01789 (void) ConcatenateString(&path,message); 01790 (void) FormatLocaleString(message,MaxTextExtent,"} bind def"); 01791 (void) ConcatenateString(&path,message); 01792 message=DestroyString(message); 01793 return(path); 01794 } 01795 01796 static char *TraceSVGClippath(const unsigned char *blob,size_t length, 01797 const size_t columns,const size_t rows) 01798 { 01799 char 01800 *path, 01801 *message; 01802 01803 MagickBooleanType 01804 in_subpath; 01805 01806 PointInfo 01807 first[3], 01808 last[3], 01809 point[3]; 01810 01811 register ssize_t 01812 i; 01813 01814 ssize_t 01815 knot_count, 01816 selector, 01817 x, 01818 y; 01819 01820 path=AcquireString((char *) NULL); 01821 if (path == (char *) NULL) 01822 return((char *) NULL); 01823 message=AcquireString((char *) NULL); 01824 (void) FormatLocaleString(message,MaxTextExtent, 01825 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"); 01826 (void) ConcatenateString(&path,message); 01827 (void) FormatLocaleString(message,MaxTextExtent, 01828 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) columns,(double) rows); 01829 (void) ConcatenateString(&path,message); 01830 (void) FormatLocaleString(message,MaxTextExtent,"<g>\n"); 01831 (void) ConcatenateString(&path,message); 01832 (void) FormatLocaleString(message,MaxTextExtent, 01833 "<path style=\"fill:#00000000;stroke:#00000000;"); 01834 (void) ConcatenateString(&path,message); 01835 (void) FormatLocaleString(message,MaxTextExtent, 01836 "stroke-width:0;stroke-antialiasing:false\" d=\"\n"); 01837 (void) ConcatenateString(&path,message); 01838 (void) ResetMagickMemory(point,0,sizeof(point)); 01839 (void) ResetMagickMemory(first,0,sizeof(first)); 01840 (void) ResetMagickMemory(last,0,sizeof(last)); 01841 knot_count=0; 01842 in_subpath=MagickFalse; 01843 while (length != 0) 01844 { 01845 selector=(ssize_t) ((int) ReadPropertyMSBShort(&blob,&length)); 01846 switch (selector) 01847 { 01848 case 0: 01849 case 3: 01850 { 01851 if (knot_count != 0) 01852 { 01853 blob+=24; 01854 length-=MagickMin(24,(ssize_t) length); 01855 break; 01856 } 01857 /* 01858 Expected subpath length record. 01859 */ 01860 knot_count=(ssize_t) ((int) ReadPropertyMSBShort(&blob,&length)); 01861 blob+=22; 01862 length-=MagickMin(22,(ssize_t) length); 01863 break; 01864 } 01865 case 1: 01866 case 2: 01867 case 4: 01868 case 5: 01869 { 01870 if (knot_count == 0) 01871 { 01872 /* 01873 Unexpected subpath knot. 01874 */ 01875 blob+=24; 01876 length-=MagickMin(24,(ssize_t) length); 01877 break; 01878 } 01879 /* 01880 Add sub-path knot 01881 */ 01882 for (i=0; i < 3; i++) 01883 { 01884 size_t 01885 xx, 01886 yy; 01887 01888 yy=(size_t) ((int) ReadPropertyMSBLong(&blob,&length)); 01889 xx=(size_t) ((int) ReadPropertyMSBLong(&blob,&length)); 01890 x=(ssize_t) xx; 01891 if (xx > 2147483647) 01892 x=(ssize_t) xx-4294967295U-1; 01893 y=(ssize_t) yy; 01894 if (yy > 2147483647) 01895 y=(ssize_t) yy-4294967295U-1; 01896 point[i].x=(double) x*columns/4096/4096; 01897 point[i].y=(double) y*rows/4096/4096; 01898 } 01899 if (in_subpath == MagickFalse) 01900 { 01901 (void) FormatLocaleString(message,MaxTextExtent,"M %g,%g\n", 01902 point[1].x,point[1].y); 01903 for (i=0; i < 3; i++) 01904 { 01905 first[i]=point[i]; 01906 last[i]=point[i]; 01907 } 01908 } 01909 else 01910 { 01911 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) && 01912 (point[0].x == point[1].x) && (point[0].y == point[1].y)) 01913 (void) FormatLocaleString(message,MaxTextExtent,"L %g,%g\n", 01914 point[1].x,point[1].y); 01915 else 01916 (void) FormatLocaleString(message,MaxTextExtent, 01917 "C %g,%g %g,%g %g,%g\n",last[2].x,last[2].y, 01918 point[0].x,point[0].y,point[1].x,point[1].y); 01919 for (i=0; i < 3; i++) 01920 last[i]=point[i]; 01921 } 01922 (void) ConcatenateString(&path,message); 01923 in_subpath=MagickTrue; 01924 knot_count--; 01925 /* 01926 Close the subpath if there are no more knots. 01927 */ 01928 if (knot_count == 0) 01929 { 01930 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) && 01931 (first[0].x == first[1].x) && (first[0].y == first[1].y)) 01932 (void) FormatLocaleString(message,MaxTextExtent, 01933 "L %g,%g Z\n",first[1].x,first[1].y); 01934 else 01935 { 01936 (void) FormatLocaleString(message,MaxTextExtent, 01937 "C %g,%g %g,%g %g,%g Z\n",last[2].x, 01938 last[2].y,first[0].x,first[0].y,first[1].x,first[1].y); 01939 (void) ConcatenateString(&path,message); 01940 } 01941 in_subpath=MagickFalse; 01942 } 01943 break; 01944 } 01945 case 6: 01946 case 7: 01947 case 8: 01948 default: 01949 { 01950 blob+=24; 01951 length-=MagickMin(24,(ssize_t) length); 01952 break; 01953 } 01954 } 01955 } 01956 /* 01957 Return an empty SVG image if the path does not have knots. 01958 */ 01959 (void) FormatLocaleString(message,MaxTextExtent,"\"/>\n"); 01960 (void) ConcatenateString(&path,message); 01961 (void) FormatLocaleString(message,MaxTextExtent,"</g>\n"); 01962 (void) ConcatenateString(&path,message); 01963 (void) FormatLocaleString(message,MaxTextExtent,"</svg>\n"); 01964 (void) ConcatenateString(&path,message); 01965 message=DestroyString(message); 01966 return(path); 01967 } 01968 01969 MagickExport const char *GetImageProperty(const Image *image, 01970 const char *property,ExceptionInfo *exception) 01971 { 01972 FxInfo 01973 *fx_info; 01974 01975 MagickRealType 01976 alpha; 01977 01978 MagickStatusType 01979 status; 01980 01981 register const char 01982 *p; 01983 01984 assert(image != (Image *) NULL); 01985 assert(image->signature == MagickSignature); 01986 if (image->debug != MagickFalse) 01987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01988 p=(const char *) NULL; 01989 if (image->properties != (void *) NULL) 01990 { 01991 if (property == (const char *) NULL) 01992 { 01993 ResetSplayTreeIterator((SplayTreeInfo *) image->properties); 01994 p=(const char *) GetNextValueInSplayTree((SplayTreeInfo *) 01995 image->properties); 01996 return(p); 01997 } 01998 if (LocaleNCompare("fx:",property,3) != 0) 01999 { 02000 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02001 image->properties,property); 02002 if (p != (const char *) NULL) 02003 return(p); 02004 } 02005 } 02006 if ((property == (const char *) NULL) || 02007 (strchr(property,':') == (char *) NULL)) 02008 return(p); 02009 switch (*property) 02010 { 02011 case '8': 02012 { 02013 if (LocaleNCompare("8bim:",property,5) == 0) 02014 { 02015 if ((Get8BIMProperty(image,property,exception) != MagickFalse) && 02016 (image->properties != (void *) NULL)) 02017 { 02018 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02019 image->properties,property); 02020 return(p); 02021 } 02022 } 02023 break; 02024 } 02025 case 'E': 02026 case 'e': 02027 { 02028 if (LocaleNCompare("exif:",property,5) == 0) 02029 { 02030 if ((GetEXIFProperty(image,property,exception) != MagickFalse) && 02031 (image->properties != (void *) NULL)) 02032 { 02033 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02034 image->properties,property); 02035 return(p); 02036 } 02037 } 02038 break; 02039 } 02040 case 'F': 02041 case 'f': 02042 { 02043 if (LocaleNCompare("fx:",property,3) == 0) 02044 { 02045 fx_info=AcquireFxInfo(image,property+3); 02046 status=FxEvaluateChannelExpression(fx_info,IntensityPixelChannel,0,0, 02047 &alpha,exception); 02048 fx_info=DestroyFxInfo(fx_info); 02049 if (status != MagickFalse) 02050 { 02051 char 02052 value[MaxTextExtent]; 02053 02054 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02055 GetMagickPrecision(),(double) alpha); 02056 (void) SetImageProperty((Image *) image,property,value,exception); 02057 } 02058 if (image->properties != (void *) NULL) 02059 { 02060 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02061 image->properties,property); 02062 return(p); 02063 } 02064 } 02065 break; 02066 } 02067 case 'I': 02068 case 'i': 02069 { 02070 if (LocaleNCompare("iptc:",property,5) == 0) 02071 { 02072 if ((GetIPTCProperty(image,property,exception) != MagickFalse) && 02073 (image->properties != (void *) NULL)) 02074 { 02075 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02076 image->properties,property); 02077 return(p); 02078 } 02079 } 02080 break; 02081 } 02082 case 'P': 02083 case 'p': 02084 { 02085 if (LocaleNCompare("pixel:",property,6) == 0) 02086 { 02087 PixelInfo 02088 pixel; 02089 02090 GetPixelInfo(image,&pixel); 02091 fx_info=AcquireFxInfo(image,property+6); 02092 status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,0,0, 02093 &alpha,exception); 02094 pixel.red=(MagickRealType) QuantumRange*alpha; 02095 status|=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,0,0, 02096 &alpha,exception); 02097 pixel.green=(MagickRealType) QuantumRange*alpha; 02098 status|=FxEvaluateChannelExpression(fx_info,BluePixelChannel,0,0, 02099 &alpha,exception); 02100 pixel.blue=(MagickRealType) QuantumRange*alpha; 02101 if (image->colorspace == CMYKColorspace) 02102 { 02103 status|=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,0,0, 02104 &alpha,exception); 02105 pixel.black=(MagickRealType) QuantumRange*alpha; 02106 } 02107 status|=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,0,0, 02108 &alpha,exception); 02109 pixel.alpha=(MagickRealType) QuantumRange*(1.0-alpha); 02110 fx_info=DestroyFxInfo(fx_info); 02111 if (status != MagickFalse) 02112 { 02113 char 02114 name[MaxTextExtent]; 02115 02116 (void) QueryColorname(image,&pixel,SVGCompliance,name, 02117 exception); 02118 (void) SetImageProperty((Image *) image,property,name,exception); 02119 return(GetImageProperty(image,property,exception)); 02120 } 02121 } 02122 break; 02123 } 02124 case 'X': 02125 case 'x': 02126 { 02127 if (LocaleNCompare("xmp:",property,4) == 0) 02128 { 02129 if ((GetXMPProperty(image,property) != MagickFalse) && 02130 (image->properties != (void *) NULL)) 02131 { 02132 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *) 02133 image->properties,property); 02134 return(p); 02135 } 02136 } 02137 break; 02138 } 02139 default: 02140 break; 02141 } 02142 return(p); 02143 } 02144 02145 /* 02146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02147 % % 02148 % % 02149 % % 02150 + G e t M a g i c k P r o p e r t y % 02151 % % 02152 % % 02153 % % 02154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02155 % 02156 % GetMagickProperty() gets a value associated with an image property. 02157 % 02158 % The format of the GetMagickProperty method is: 02159 % 02160 % const char *GetMagickProperty(const ImageInfo *image_info,Image *image, 02161 % const char *key,ExceptionInfo *exception) 02162 % 02163 % A description of each parameter follows: 02164 % 02165 % o image_info: the image info. 02166 % 02167 % o image: the image. 02168 % 02169 % o key: the key. 02170 % 02171 % o exception: return any errors or warnings in this structure. 02172 % 02173 */ 02174 MagickExport const char *GetMagickProperty(const ImageInfo *image_info, 02175 Image *image,const char *property,ExceptionInfo *exception) 02176 { 02177 char 02178 value[MaxTextExtent], 02179 filename[MaxTextExtent]; 02180 02181 *value='\0'; 02182 switch (*property) 02183 { 02184 case 'b': 02185 { 02186 if (LocaleNCompare("base",property,4) == 0) 02187 { 02188 GetPathComponent(image->magick_filename,BasePath,filename); 02189 (void) CopyMagickString(value,filename,MaxTextExtent); 02190 break; 02191 } 02192 break; 02193 } 02194 case 'c': 02195 { 02196 if (LocaleNCompare("channels",property,8) == 0) 02197 { 02198 /* 02199 Image channels. 02200 */ 02201 (void) FormatLocaleString(value,MaxTextExtent,"%s", 02202 CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) 02203 image->colorspace)); 02204 LocaleLower(value); 02205 if (image->matte != MagickFalse) 02206 (void) ConcatenateMagickString(value,"a",MaxTextExtent); 02207 break; 02208 } 02209 if (LocaleNCompare("colorspace",property,10) == 0) 02210 { 02211 ColorspaceType 02212 colorspace; 02213 02214 /* 02215 Image storage class and colorspace. 02216 */ 02217 colorspace=image->colorspace; 02218 if (IsImageGray(image,exception) != MagickFalse) 02219 colorspace=GRAYColorspace; 02220 (void) FormatLocaleString(value,MaxTextExtent,"%s", 02221 CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) 02222 colorspace)); 02223 break; 02224 } 02225 if (LocaleNCompare("copyright",property,9) == 0) 02226 { 02227 (void) CopyMagickString(value,GetMagickCopyright(),MaxTextExtent); 02228 break; 02229 } 02230 break; 02231 } 02232 case 'd': 02233 { 02234 if (LocaleNCompare("depth",property,5) == 0) 02235 { 02236 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02237 image->depth); 02238 break; 02239 } 02240 if (LocaleNCompare("directory",property,9) == 0) 02241 { 02242 GetPathComponent(image->magick_filename,HeadPath,filename); 02243 (void) CopyMagickString(value,filename,MaxTextExtent); 02244 break; 02245 } 02246 break; 02247 } 02248 case 'e': 02249 { 02250 if (LocaleNCompare("extension",property,9) == 0) 02251 { 02252 GetPathComponent(image->magick_filename,ExtensionPath,filename); 02253 (void) CopyMagickString(value,filename,MaxTextExtent); 02254 break; 02255 } 02256 break; 02257 } 02258 case 'g': 02259 { 02260 if (LocaleNCompare("group",property,5) == 0) 02261 { 02262 (void) FormatLocaleString(value,MaxTextExtent,"0x%lx", 02263 (unsigned long) image_info->group); 02264 break; 02265 } 02266 break; 02267 } 02268 case 'h': 02269 { 02270 if (LocaleNCompare("height",property,6) == 0) 02271 { 02272 (void) FormatLocaleString(value,MaxTextExtent,"%.20g", 02273 image->magick_rows != 0 ? (double) image->magick_rows : 256.0); 02274 break; 02275 } 02276 break; 02277 } 02278 case 'i': 02279 { 02280 if (LocaleNCompare("input",property,5) == 0) 02281 { 02282 (void) CopyMagickString(value,image->filename,MaxTextExtent); 02283 break; 02284 } 02285 break; 02286 } 02287 case 'k': 02288 { 02289 if (LocaleNCompare("kurtosis",property,8) == 0) 02290 { 02291 double 02292 kurtosis, 02293 skewness; 02294 02295 (void) GetImageKurtosis(image,&kurtosis,&skewness,exception); 02296 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02297 GetMagickPrecision(),kurtosis); 02298 break; 02299 } 02300 break; 02301 } 02302 case 'm': 02303 { 02304 if (LocaleNCompare("magick",property,6) == 0) 02305 { 02306 (void) CopyMagickString(value,image->magick,MaxTextExtent); 02307 break; 02308 } 02309 if (LocaleNCompare("max",property,3) == 0) 02310 { 02311 double 02312 maximum, 02313 minimum; 02314 02315 (void) GetImageRange(image,&minimum,&maximum,exception); 02316 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02317 GetMagickPrecision(),maximum); 02318 break; 02319 } 02320 if (LocaleNCompare("mean",property,4) == 0) 02321 { 02322 double 02323 mean, 02324 standard_deviation; 02325 02326 (void) GetImageMean(image,&mean,&standard_deviation, 02327 exception); 02328 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02329 GetMagickPrecision(),mean); 02330 break; 02331 } 02332 if (LocaleNCompare("min",property,3) == 0) 02333 { 02334 double 02335 maximum, 02336 minimum; 02337 02338 (void) GetImageRange(image,&minimum,&maximum,exception); 02339 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02340 GetMagickPrecision(),minimum); 02341 break; 02342 } 02343 break; 02344 } 02345 case 'n': 02346 { 02347 if (LocaleNCompare("name",property,4) == 0) 02348 { 02349 (void) CopyMagickString(value,filename,MaxTextExtent); 02350 break; 02351 } 02352 break; 02353 } 02354 case 'o': 02355 { 02356 if (LocaleNCompare("opaque",property,6) == 0) 02357 { 02358 MagickBooleanType 02359 opaque; 02360 02361 opaque=IsImageOpaque(image,exception); 02362 (void) CopyMagickString(value,opaque == MagickFalse ? "false" : 02363 "true",MaxTextExtent); 02364 break; 02365 } 02366 if (LocaleNCompare("output",property,6) == 0) 02367 { 02368 (void) CopyMagickString(value,image_info->filename,MaxTextExtent); 02369 break; 02370 } 02371 break; 02372 } 02373 case 'p': 02374 { 02375 if (LocaleNCompare("page",property,4) == 0) 02376 { 02377 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02378 GetImageIndexInList(image)+1); 02379 break; 02380 } 02381 break; 02382 } 02383 case 's': 02384 { 02385 if (LocaleNCompare("size",property,4) == 0) 02386 { 02387 char 02388 format[MaxTextExtent]; 02389 02390 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format); 02391 (void) FormatLocaleString(value,MaxTextExtent,"%sB",format); 02392 break; 02393 } 02394 if (LocaleNCompare("scenes",property,6) == 0) 02395 { 02396 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02397 GetImageListLength(image)); 02398 break; 02399 } 02400 if (LocaleNCompare("scene",property,5) == 0) 02401 { 02402 /* FUTURE: I am not certain this property return makes sense! */ 02403 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02404 image->scene); 02405 if (image_info->number_scenes != 0) 02406 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02407 image_info->scene); 02408 break; 02409 } 02410 if (LocaleNCompare("skewness",property,8) == 0) 02411 { 02412 double 02413 kurtosis, 02414 skewness; 02415 02416 (void) GetImageKurtosis(image,&kurtosis,&skewness,exception); 02417 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02418 GetMagickPrecision(),skewness); 02419 break; 02420 } 02421 if (LocaleNCompare("standard-deviation",property,18) == 0) 02422 { 02423 double 02424 mean, 02425 standard_deviation; 02426 02427 (void) GetImageMean(image,&mean,&standard_deviation, 02428 exception); 02429 (void) FormatLocaleString(value,MaxTextExtent,"%.*g", 02430 GetMagickPrecision(),standard_deviation); 02431 break; 02432 } 02433 break; 02434 } 02435 case 'u': 02436 { 02437 if (LocaleNCompare("unique",property,6) == 0) 02438 { 02439 (void) CopyMagickString(filename,image_info->unique,MaxTextExtent); 02440 (void) CopyMagickString(value,filename,MaxTextExtent); 02441 break; 02442 } 02443 break; 02444 } 02445 case 'v': 02446 { 02447 if (LocaleNCompare("version",property,7) == 0) 02448 { 02449 (void) CopyMagickString(value,GetMagickVersion((size_t *) NULL), 02450 MaxTextExtent); 02451 break; 02452 } 02453 break; 02454 } 02455 case 'w': 02456 { 02457 if (LocaleNCompare("width",property,5) == 0) 02458 { 02459 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 02460 (image->magick_columns != 0 ? image->magick_columns : 256)); 02461 break; 02462 } 02463 break; 02464 } 02465 case 'x': 02466 { 02467 if (LocaleNCompare("xresolution",property,11) == 0) 02468 { 02469 (void) FormatLocaleString(value,MaxTextExtent,"%g", 02470 image->resolution.x); 02471 break; 02472 } 02473 break; 02474 } 02475 case 'y': 02476 { 02477 if (LocaleNCompare("yresolution",property,11) == 0) 02478 { 02479 (void) FormatLocaleString(value,MaxTextExtent,"%g", 02480 image->resolution.y); 02481 break; 02482 } 02483 break; 02484 } 02485 case 'z': 02486 { 02487 if (LocaleNCompare("zero",property,4) == 0) 02488 { 02489 (void) CopyMagickString(filename,image_info->zero,MaxTextExtent); 02490 (void) CopyMagickString(value,filename,MaxTextExtent); 02491 break; 02492 } 02493 break; 02494 } 02495 } 02496 if (*value != '\0') 02497 { 02498 if (image->properties == (void *) NULL) 02499 image->properties=NewSplayTree(CompareSplayTreeString, 02500 RelinquishMagickMemory,RelinquishMagickMemory); 02501 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties, 02502 ConstantString(property),ConstantString(value)); 02503 } 02504 return(GetImageProperty(image,property,exception)); 02505 } 02506 02507 /* 02508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02509 % % 02510 % % 02511 % % 02512 % G e t N e x t I m a g e P r o p e r t y % 02513 % % 02514 % % 02515 % % 02516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02517 % 02518 % GetNextImageProperty() gets the next image property value. 02519 % 02520 % The format of the GetNextImageProperty method is: 02521 % 02522 % char *GetNextImageProperty(const Image *image) 02523 % 02524 % A description of each parameter follows: 02525 % 02526 % o image: the image. 02527 % 02528 */ 02529 MagickExport char *GetNextImageProperty(const Image *image) 02530 { 02531 assert(image != (Image *) NULL); 02532 assert(image->signature == MagickSignature); 02533 if (image->debug != MagickFalse) 02534 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 02535 image->filename); 02536 if (image->properties == (void *) NULL) 02537 return((char *) NULL); 02538 return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->properties)); 02539 } 02540 02541 /* 02542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02543 % % 02544 % % 02545 % % 02546 % I n t e r p r e t I m a g e P r o p e r t i e s % 02547 % % 02548 % % 02549 % % 02550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02551 % 02552 % InterpretImageProperties() replaces any embedded formatting characters with 02553 % the appropriate image property and returns the interpreted text. 02554 % 02555 % The format of the InterpretImageProperties method is: 02556 % 02557 % char *InterpretImageProperties(const ImageInfo *image_info,Image *image, 02558 % const char *embed_text,ExceptionInfo *exception) 02559 % 02560 % A description of each parameter follows: 02561 % 02562 % o image_info: the image info. 02563 % 02564 % o image: the image. 02565 % 02566 % o embed_text: the address of a character string containing the embedded 02567 % formatting characters. 02568 % 02569 % o exception: return any errors or warnings in this structure. 02570 % 02571 */ 02572 MagickExport char *InterpretImageProperties(const ImageInfo *image_info, 02573 Image *image,const char *embed_text,ExceptionInfo *exception) 02574 { 02575 char 02576 filename[MaxTextExtent], 02577 *interpret_text, 02578 *text; 02579 02580 const char 02581 *value; 02582 02583 register char 02584 *q; 02585 02586 register const char 02587 *p; 02588 02589 register ssize_t 02590 i; 02591 02592 size_t 02593 extent, 02594 length; 02595 02596 assert(image != (Image *) NULL); 02597 assert(image->signature == MagickSignature); 02598 if (image->debug != MagickFalse) 02599 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 02600 if ((embed_text == (const char *) NULL) || (*embed_text == '\0')) 02601 return((char *) NULL); 02602 text=(char *) embed_text; 02603 if ((*text == '@') && ((*(text+1) == '-') || 02604 (IsPathAccessible(text+1) != MagickFalse))) 02605 return(FileToString(embed_text+1,~0,exception)); 02606 /* 02607 Translate any embedded format characters. 02608 */ 02609 interpret_text=AcquireString(text); 02610 extent=MaxTextExtent; 02611 p=text; 02612 for (q=interpret_text; *p != '\0'; p++) 02613 { 02614 *q='\0'; 02615 if ((size_t) (q-interpret_text+MaxTextExtent) >= extent) 02616 { 02617 extent+=MaxTextExtent; 02618 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ 02619 MaxTextExtent+1,sizeof(*interpret_text)); 02620 if (interpret_text == (char *) NULL) 02621 break; 02622 q=interpret_text+strlen(interpret_text); 02623 } 02624 /* 02625 Process formatting characters in text. 02626 */ 02627 if ((*p == '\\') && (*(p+1) == 'r')) 02628 { 02629 *q++='\r'; 02630 p++; 02631 continue; 02632 } 02633 if ((*p == '\\') && (*(p+1) == 'n')) 02634 { 02635 *q++='\n'; 02636 p++; 02637 continue; 02638 } 02639 if (*p == '\\') 02640 { 02641 p++; 02642 *q++=(*p); 02643 continue; 02644 } 02645 if (*p != '%') 02646 { 02647 *q++=(*p); 02648 continue; 02649 } 02650 p++; 02651 switch (*p) 02652 { 02653 case '[': /* multi-character substitution */ 02654 { 02655 char 02656 pattern[MaxTextExtent]; 02657 02658 const char 02659 *key, 02660 *value; 02661 02662 ssize_t 02663 depth; 02664 02665 /* 02666 Image value. 02667 */ 02668 if (strchr(p,']') == (char *) NULL) 02669 break; 02670 depth=1; 02671 p++; 02672 for (i=0; (i < (MaxTextExtent-1L)) && (*p != '\0'); i++) 02673 { 02674 if (*p == '[') 02675 depth++; 02676 if (*p == ']') 02677 depth--; 02678 if (depth <= 0) 02679 break; 02680 pattern[i]=(*p++); 02681 } 02682 pattern[i]='\0'; 02683 value=GetImageProperty(image,pattern,exception); 02684 if (value != (const char *) NULL) 02685 { 02686 length=strlen(value); 02687 if ((size_t) (q-interpret_text+length+1) >= extent) 02688 { 02689 extent+=length; 02690 interpret_text=(char *) ResizeQuantumMemory(interpret_text, 02691 extent+MaxTextExtent,sizeof(*interpret_text)); 02692 if (interpret_text == (char *) NULL) 02693 break; 02694 q=interpret_text+strlen(interpret_text); 02695 } 02696 (void) CopyMagickString(q,value,extent); 02697 q+=length; 02698 break; 02699 } 02700 else 02701 if (IsGlob(pattern) != MagickFalse) 02702 { 02703 /* 02704 Iterate over image properties. 02705 */ 02706 ResetImagePropertyIterator(image); 02707 key=GetNextImageProperty(image); 02708 while (key != (const char *) NULL) 02709 { 02710 if (GlobExpression(key,pattern,MagickTrue) != MagickFalse) 02711 { 02712 value=GetImageProperty(image,key,exception); 02713 if (value != (const char *) NULL) 02714 { 02715 length=strlen(key)+strlen(value)+2; 02716 if ((size_t) (q-interpret_text+length+1) >= extent) 02717 { 02718 extent+=length; 02719 interpret_text=(char *) ResizeQuantumMemory( 02720 interpret_text,extent+MaxTextExtent, 02721 sizeof(*interpret_text)); 02722 if (interpret_text == (char *) NULL) 02723 break; 02724 q=interpret_text+strlen(interpret_text); 02725 } 02726 q+=FormatLocaleString(q,extent,"%s=%s\n",key,value); 02727 } 02728 } 02729 key=GetNextImageProperty(image); 02730 } 02731 } 02732 value=GetMagickProperty(image_info,image,pattern,exception); 02733 if (value != (const char *) NULL) 02734 { 02735 length=strlen(value); 02736 if ((size_t) (q-interpret_text+length+1) >= extent) 02737 { 02738 extent+=length; 02739 interpret_text=(char *) ResizeQuantumMemory(interpret_text, 02740 extent+MaxTextExtent,sizeof(*interpret_text)); 02741 if (interpret_text == (char *) NULL) 02742 break; 02743 q=interpret_text+strlen(interpret_text); 02744 } 02745 (void) CopyMagickString(q,value,extent); 02746 q+=length; 02747 break; 02748 } 02749 if (image_info == (ImageInfo *) NULL) 02750 break; 02751 value=GetImageOption(image_info,pattern); 02752 if (value != (char *) NULL) 02753 { 02754 length=strlen(value); 02755 if ((size_t) (q-interpret_text+length+1) >= extent) 02756 { 02757 extent+=length; 02758 interpret_text=(char *) ResizeQuantumMemory(interpret_text, 02759 extent+MaxTextExtent,sizeof(*interpret_text)); 02760 if (interpret_text == (char *) NULL) 02761 break; 02762 q=interpret_text+strlen(interpret_text); 02763 } 02764 (void) CopyMagickString(q,value,extent); 02765 q+=length; 02766 break; 02767 } 02768 break; 02769 } 02770 case 'b': /* image size as read in */ 02771 { 02772 char 02773 format[MaxTextExtent]; 02774 02775 (void) FormatLocaleString(format,MaxTextExtent,"%.20g",(double) 02776 ((MagickOffsetType) image->extent)); 02777 if (image->extent != (MagickSizeType) ((size_t) image->extent)) 02778 (void) FormatMagickSize(image->extent,MagickFalse,format); 02779 q+=ConcatenateMagickString(q,format,extent); 02780 q+=ConcatenateMagickString(q,"B",extent); 02781 break; 02782 } 02783 case 'c': /* image comment properity */ 02784 { 02785 value=GetImageProperty(image,"comment",exception); 02786 if (value == (const char *) NULL) 02787 break; 02788 length=strlen(value); 02789 if ((size_t) (q-interpret_text+length+1) >= extent) 02790 { 02791 extent+=length; 02792 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ 02793 MaxTextExtent,sizeof(*interpret_text)); 02794 if (interpret_text == (char *) NULL) 02795 break; 02796 q=interpret_text+strlen(interpret_text); 02797 } 02798 (void) CopyMagickString(q,value,extent); 02799 q+=length; 02800 break; 02801 } 02802 case 'd': /* Directory component of filename */ 02803 { 02804 GetPathComponent(image->magick_filename,HeadPath,filename); 02805 q+=CopyMagickString(q,filename,extent); 02806 break; 02807 } 02808 case 'e': /* Filename extension (suffix) of image file */ 02809 { 02810 GetPathComponent(image->magick_filename,ExtensionPath,filename); 02811 q+=CopyMagickString(q,filename,extent); 02812 break; 02813 } 02814 case 'f': /* Filename without directory component */ 02815 { 02816 GetPathComponent(image->magick_filename,TailPath,filename); 02817 q+=CopyMagickString(q,filename,extent); 02818 break; 02819 } 02820 case 't': /* Base filename without directory or extention */ 02821 { 02822 GetPathComponent(image->magick_filename,BasePath,filename); 02823 q+=CopyMagickString(q,filename,extent); 02824 break; 02825 } 02826 case 'g': /* Image geometry, canvas and offset */ 02827 { 02828 q+=FormatLocaleString(q,extent,"%.20gx%.20g%+.20g%+.20g",(double) 02829 image->page.width,(double) image->page.height,(double) image->page.x, 02830 (double) image->page.y); 02831 break; 02832 } 02833 case 'h': /* Image height */ 02834 { 02835 q+=FormatLocaleString(q,extent,"%.20g",(double) (image->rows != 0 ? 02836 image->rows : image->magick_rows)); 02837 break; 02838 } 02839 case 'i': /* Images filename - (output filename with "info:" ) */ 02840 { 02841 q+=CopyMagickString(q,image->filename,extent); 02842 break; 02843 } 02844 case 'k': /* Number of unique colors */ 02845 { 02846 q+=FormatLocaleString(q,extent,"%.20g",(double) GetNumberColors(image, 02847 (FILE *) NULL,exception)); 02848 break; 02849 } 02850 case 'l': /* Image label */ 02851 { 02852 value=GetImageProperty(image,"label",exception); 02853 if (value == (const char *) NULL) 02854 break; 02855 length=strlen(value); 02856 if ((size_t) (q-interpret_text+length+1) >= extent) 02857 { 02858 extent+=length; 02859 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ 02860 MaxTextExtent,sizeof(*interpret_text)); 02861 if (interpret_text == (char *) NULL) 02862 break; 02863 q=interpret_text+strlen(interpret_text); 02864 } 02865 q+=CopyMagickString(q,value,extent); 02866 break; 02867 } 02868 case 'm': /* Image format (file magick) */ 02869 { 02870 q+=CopyMagickString(q,image->magick,extent); 02871 break; 02872 } 02873 case 'M': /* Magick filename - exactly as given incl. read mods */ 02874 { 02875 q+=CopyMagickString(q,image->magick_filename,extent); 02876 break; 02877 } 02878 case 'n': /* Number of images in the list. */ 02879 { 02880 q+=FormatLocaleString(q,extent,"%.20g",(double) 02881 GetImageListLength(image)); 02882 break; 02883 } 02884 case 'o': /* Image output filename */ 02885 { 02886 q+=CopyMagickString(q,image_info->filename,extent); 02887 break; 02888 } 02889 case 'p': /* Image index in current image list */ 02890 { 02891 q+=FormatLocaleString(q,extent,"%.20g",(double) 02892 GetImageIndexInList(image)); 02893 break; 02894 } 02895 case 'q': /* Quantum depth of image in memory */ 02896 { 02897 q+=FormatLocaleString(q,extent,"%.20g",(double) 02898 MAGICKCORE_QUANTUM_DEPTH); 02899 break; 02900 } 02901 case 'r': /* Image storage class and colorspace. */ 02902 { 02903 ColorspaceType 02904 colorspace; 02905 02906 colorspace=image->colorspace; 02907 if (IsImageGray(image,exception) != MagickFalse) 02908 colorspace=GRAYColorspace; 02909 q+=FormatLocaleString(q,extent,"%s%s%s",CommandOptionToMnemonic( 02910 MagickClassOptions,(ssize_t) image->storage_class), 02911 CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) colorspace), 02912 image->matte != MagickFalse ? "Matte" : ""); 02913 break; 02914 } 02915 case 's': /* Image scene number */ 02916 { 02917 if (image_info->number_scenes == 0) 02918 q+=FormatLocaleString(q,extent,"%.20g",(double) image->scene); 02919 else 02920 q+=FormatLocaleString(q,extent,"%.20g",(double) image_info->scene); 02921 break; 02922 } 02923 case 'u': /* Unique filename */ 02924 { 02925 (void) CopyMagickString(filename,image_info->unique,extent); 02926 q+=CopyMagickString(q,filename,extent); 02927 break; 02928 } 02929 case 'w': /* Image width */ 02930 { 02931 q+=FormatLocaleString(q,extent,"%.20g",(double) (image->columns != 0 ? 02932 image->columns : image->magick_columns)); 02933 break; 02934 } 02935 case 'x': /* Image horizontal resolution (density). */ 02936 { 02937 q+=FormatLocaleString(q,extent,"%g %s",image->resolution.x, 02938 CommandOptionToMnemonic(MagickResolutionOptions,(ssize_t) 02939 image->units)); 02940 break; 02941 } 02942 case 'y': /* Image vertical resolution (density) */ 02943 { 02944 q+=FormatLocaleString(q,extent,"%g %s",image->resolution.y, 02945 CommandOptionToMnemonic(MagickResolutionOptions,(ssize_t) 02946 image->units)); 02947 break; 02948 } 02949 case 'z': /* Image depth as read in */ 02950 { 02951 q+=FormatLocaleString(q,extent,"%.20g",(double) image->depth); 02952 break; 02953 } 02954 case 'A': /* Image alpha channel */ 02955 { 02956 q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic( 02957 MagickBooleanOptions,(ssize_t) image->matte)); 02958 break; 02959 } 02960 case 'C': /* Image compression method. */ 02961 { 02962 q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic( 02963 MagickCompressOptions,(ssize_t) image->compression)); 02964 break; 02965 } 02966 case 'D': /* Image dispose method. */ 02967 { 02968 q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic( 02969 MagickDisposeOptions,(ssize_t) image->dispose)); 02970 break; 02971 } 02972 case 'G': /* Image size as geometry = "%wx%h" */ 02973 { 02974 q+=FormatLocaleString(q,extent,"%.20gx%.20g",(double) 02975 image->magick_columns,(double) image->magick_rows); 02976 break; 02977 } 02978 case 'H': /* layer canvas height */ 02979 { 02980 q+=FormatLocaleString(q,extent,"%.20g",(double) image->page.height); 02981 break; 02982 } 02983 case 'O': /* layer canvas offset with sign = "+%X+%Y" */ 02984 { 02985 q+=FormatLocaleString(q,extent,"%+ld%+ld",(long) image->page.x,(long) 02986 image->page.y); 02987 break; 02988 } 02989 case 'P': /* layer canvas page size = "%Wx%H" */ 02990 { 02991 q+=FormatLocaleString(q,extent,"%.20gx%.20g",(double) image->page.width, 02992 (double) image->page.height); 02993 break; 02994 } 02995 case 'Q': /* image compression quality */ 02996 { 02997 q+=FormatLocaleString(q,extent,"%.20g",(double) image->quality); 02998 break; 02999 } 03000 case 'S': /* Image scenes */ 03001 { 03002 if (image_info->number_scenes == 0) 03003 q+=CopyMagickString(q,"2147483647",extent); 03004 else 03005 q+=FormatLocaleString(q,extent,"%.20g",(double) (image_info->scene+ 03006 image_info->number_scenes)); 03007 break; 03008 } 03009 case 'T': /* image time delay for animations */ 03010 { 03011 q+=FormatLocaleString(q,extent,"%.20g",(double) image->delay); 03012 break; 03013 } 03014 case 'W': /* layer canvas width */ 03015 { 03016 q+=FormatLocaleString(q,extent,"%.20g",(double) image->page.width); 03017 break; 03018 } 03019 case 'X': /* layer canvas X offset */ 03020 { 03021 q+=FormatLocaleString(q,extent,"%+.20g",(double) image->page.x); 03022 break; 03023 } 03024 case 'Y': /* layer canvas Y offset */ 03025 { 03026 q+=FormatLocaleString(q,extent,"%+.20g",(double) image->page.y); 03027 break; 03028 } 03029 case 'Z': /* Unique filename. */ 03030 { 03031 (void) CopyMagickString(filename,image_info->zero,extent); 03032 q+=CopyMagickString(q,filename,extent); 03033 break; 03034 } 03035 case '@': /* Image bounding box. */ 03036 { 03037 RectangleInfo 03038 page; 03039 03040 page=GetImageBoundingBox(image,exception); 03041 q+=FormatLocaleString(q,MaxTextExtent,"%.20gx%.20g%+.20g%+.20g", 03042 (double) page.width,(double) page.height,(double) page.x,(double) 03043 page.y); 03044 break; 03045 } 03046 case '#': /* Image signature */ 03047 { 03048 (void) SignatureImage(image,exception); 03049 value=GetImageProperty(image,"signature",exception); 03050 if (value == (const char *) NULL) 03051 break; 03052 q+=CopyMagickString(q,value,extent); 03053 break; 03054 } 03055 case '%': /* percent escaped */ 03056 { 03057 *q++=(*p); 03058 break; 03059 } 03060 default: /* percent not expanded */ 03061 { 03062 *q++='%'; 03063 *q++=(*p); 03064 break; 03065 } 03066 } 03067 } 03068 *q='\0'; 03069 if (text != (const char *) embed_text) 03070 text=DestroyString(text); 03071 (void) SubstituteString(&interpret_text,"<","<"); 03072 (void) SubstituteString(&interpret_text,">",">"); 03073 return(interpret_text); 03074 } 03075 03076 /* 03077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03078 % % 03079 % % 03080 % % 03081 % R e m o v e I m a g e P r o p e r t y % 03082 % % 03083 % % 03084 % % 03085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03086 % 03087 % RemoveImageProperty() removes a property from the image and returns its 03088 % value. 03089 % 03090 % The format of the RemoveImageProperty method is: 03091 % 03092 % char *RemoveImageProperty(Image *image,const char *property) 03093 % 03094 % A description of each parameter follows: 03095 % 03096 % o image: the image. 03097 % 03098 % o property: the image property. 03099 % 03100 */ 03101 MagickExport char *RemoveImageProperty(Image *image, 03102 const char *property) 03103 { 03104 char 03105 *value; 03106 03107 assert(image != (Image *) NULL); 03108 assert(image->signature == MagickSignature); 03109 if (image->debug != MagickFalse) 03110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 03111 image->filename); 03112 if (image->properties == (void *) NULL) 03113 return((char *) NULL); 03114 value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->properties, 03115 property); 03116 return(value); 03117 } 03118 03119 /* 03120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03121 % % 03122 % % 03123 % % 03124 % R e s e t I m a g e P r o p e r t y I t e r a t o r % 03125 % % 03126 % % 03127 % % 03128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03129 % 03130 % ResetImagePropertyIterator() resets the image properties iterator. Use it 03131 % in conjunction with GetNextImageProperty() to iterate over all the values 03132 % associated with an image property. 03133 % 03134 % The format of the ResetImagePropertyIterator method is: 03135 % 03136 % ResetImagePropertyIterator(Image *image) 03137 % 03138 % A description of each parameter follows: 03139 % 03140 % o image: the image. 03141 % 03142 */ 03143 MagickExport void ResetImagePropertyIterator(const Image *image) 03144 { 03145 assert(image != (Image *) NULL); 03146 assert(image->signature == MagickSignature); 03147 if (image->debug != MagickFalse) 03148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 03149 image->filename); 03150 if (image->properties == (void *) NULL) 03151 return; 03152 ResetSplayTreeIterator((SplayTreeInfo *) image->properties); 03153 } 03154 03155 /* 03156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03157 % % 03158 % % 03159 % % 03160 % S e t I m a g e P r o p e r t y % 03161 % % 03162 % % 03163 % % 03164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03165 % 03166 % SetImageProperty() associates an value with an image property. 03167 % 03168 % The format of the SetImageProperty method is: 03169 % 03170 % MagickBooleanType SetImageProperty(Image *image,const char *property, 03171 % const char *value,ExceptionInfo *exception) 03172 % 03173 % A description of each parameter follows: 03174 % 03175 % o image: the image. 03176 % 03177 % o property: the image property. 03178 % 03179 % o values: the image property values. 03180 % 03181 % o exception: return any errors or warnings in this structure. 03182 % 03183 */ 03184 MagickExport MagickBooleanType SetImageProperty(Image *image, 03185 const char *property,const char *value,ExceptionInfo *exception) 03186 { 03187 MagickBooleanType 03188 status; 03189 03190 MagickStatusType 03191 flags; 03192 03193 assert(image != (Image *) NULL); 03194 assert(image->signature == MagickSignature); 03195 if (image->debug != MagickFalse) 03196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 03197 image->filename); 03198 if (image->properties == (void *) NULL) 03199 image->properties=NewSplayTree(CompareSplayTreeString, 03200 RelinquishMagickMemory,RelinquishMagickMemory); 03201 if ((value == (const char *) NULL) || (*value == '\0')) 03202 return(DeleteImageProperty(image,property)); 03203 status=MagickTrue; 03204 switch (*property) 03205 { 03206 case 'B': 03207 case 'b': 03208 { 03209 if (LocaleCompare(property,"background") == 0) 03210 { 03211 (void) QueryColorCompliance(value,AllCompliance, 03212 &image->background_color,exception); 03213 break; 03214 } 03215 if (LocaleCompare(property,"bias") == 0) 03216 { 03217 image->bias=StringToDoubleInterval(value,(double) QuantumRange+1.0); 03218 break; 03219 } 03220 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03221 ConstantString(property),ConstantString(value)); 03222 break; 03223 } 03224 case 'C': 03225 case 'c': 03226 { 03227 if (LocaleCompare(property,"colorspace") == 0) 03228 { 03229 ssize_t 03230 colorspace; 03231 03232 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse, 03233 value); 03234 if (colorspace < 0) 03235 break; 03236 (void) SetImageColorspace(image,(ColorspaceType) colorspace, 03237 exception); 03238 break; 03239 } 03240 if (LocaleCompare(property,"compose") == 0) 03241 { 03242 ssize_t 03243 compose; 03244 03245 compose=ParseCommandOption(MagickComposeOptions,MagickFalse,value); 03246 if (compose < 0) 03247 break; 03248 image->compose=(CompositeOperator) compose; 03249 break; 03250 } 03251 if (LocaleCompare(property,"compress") == 0) 03252 { 03253 ssize_t 03254 compression; 03255 03256 compression=ParseCommandOption(MagickCompressOptions,MagickFalse, 03257 value); 03258 if (compression < 0) 03259 break; 03260 image->compression=(CompressionType) compression; 03261 break; 03262 } 03263 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03264 ConstantString(property),ConstantString(value)); 03265 break; 03266 } 03267 case 'D': 03268 case 'd': 03269 { 03270 if (LocaleCompare(property,"delay") == 0) 03271 { 03272 GeometryInfo 03273 geometry_info; 03274 03275 flags=ParseGeometry(value,&geometry_info); 03276 if ((flags & GreaterValue) != 0) 03277 { 03278 if (image->delay > (size_t) floor(geometry_info.rho+0.5)) 03279 image->delay=(size_t) floor(geometry_info.rho+0.5); 03280 } 03281 else 03282 if ((flags & LessValue) != 0) 03283 { 03284 if (image->delay < (size_t) floor(geometry_info.rho+0.5)) 03285 image->ticks_per_second=(ssize_t) 03286 floor(geometry_info.sigma+0.5); 03287 } 03288 else 03289 image->delay=(size_t) floor(geometry_info.rho+0.5); 03290 if ((flags & SigmaValue) != 0) 03291 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5); 03292 break; 03293 } 03294 if (LocaleCompare(property,"density") == 0) 03295 { 03296 GeometryInfo 03297 geometry_info; 03298 03299 flags=ParseGeometry(value,&geometry_info); 03300 image->resolution.x=geometry_info.rho; 03301 image->resolution.y=geometry_info.sigma; 03302 if ((flags & SigmaValue) == 0) 03303 image->resolution.y=image->resolution.x; 03304 } 03305 if (LocaleCompare(property,"depth") == 0) 03306 { 03307 image->depth=StringToUnsignedLong(value); 03308 break; 03309 } 03310 if (LocaleCompare(property,"dispose") == 0) 03311 { 03312 ssize_t 03313 dispose; 03314 03315 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,value); 03316 if (dispose < 0) 03317 break; 03318 image->dispose=(DisposeType) dispose; 03319 break; 03320 } 03321 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03322 ConstantString(property),ConstantString(value)); 03323 break; 03324 } 03325 case 'G': 03326 case 'g': 03327 { 03328 if (LocaleCompare(property,"gravity") == 0) 03329 { 03330 ssize_t 03331 gravity; 03332 03333 gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,value); 03334 if (gravity < 0) 03335 break; 03336 image->gravity=(GravityType) gravity; 03337 break; 03338 } 03339 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03340 ConstantString(property),ConstantString(value)); 03341 break; 03342 } 03343 case 'I': 03344 case 'i': 03345 { 03346 if (LocaleCompare(property,"intent") == 0) 03347 { 03348 ssize_t 03349 rendering_intent; 03350 03351 rendering_intent=ParseCommandOption(MagickIntentOptions,MagickFalse, 03352 value); 03353 if (rendering_intent < 0) 03354 break; 03355 image->rendering_intent=(RenderingIntent) rendering_intent; 03356 break; 03357 } 03358 if (LocaleCompare(property,"interpolate") == 0) 03359 { 03360 ssize_t 03361 interpolate; 03362 03363 interpolate=ParseCommandOption(MagickInterpolateOptions,MagickFalse, 03364 value); 03365 if (interpolate < 0) 03366 break; 03367 image->interpolate=(PixelInterpolateMethod) interpolate; 03368 break; 03369 } 03370 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03371 ConstantString(property),ConstantString(value)); 03372 break; 03373 } 03374 case 'L': 03375 case 'l': 03376 { 03377 if (LocaleCompare(property,"loop") == 0) 03378 { 03379 image->iterations=StringToUnsignedLong(value); 03380 break; 03381 } 03382 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03383 ConstantString(property),ConstantString(value)); 03384 break; 03385 } 03386 case 'P': 03387 case 'p': 03388 { 03389 if (LocaleCompare(property,"page") == 0) 03390 { 03391 char 03392 *geometry; 03393 03394 geometry=GetPageGeometry(value); 03395 flags=ParseAbsoluteGeometry(geometry,&image->page); 03396 geometry=DestroyString(geometry); 03397 break; 03398 } 03399 if (LocaleCompare(property,"profile") == 0) 03400 { 03401 ImageInfo 03402 *image_info; 03403 03404 StringInfo 03405 *profile; 03406 03407 image_info=AcquireImageInfo(); 03408 (void) CopyMagickString(image_info->filename,value,MaxTextExtent); 03409 (void) SetImageInfo(image_info,1,exception); 03410 profile=FileToStringInfo(image_info->filename,~0UL,exception); 03411 if (profile != (StringInfo *) NULL) 03412 status=SetImageProfile(image,image_info->magick,profile,exception); 03413 image_info=DestroyImageInfo(image_info); 03414 break; 03415 } 03416 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03417 ConstantString(property),ConstantString(value)); 03418 break; 03419 } 03420 case 'R': 03421 case 'r': 03422 { 03423 if (LocaleCompare(property,"rendering-intent") == 0) 03424 { 03425 ssize_t 03426 rendering_intent; 03427 03428 rendering_intent=ParseCommandOption(MagickIntentOptions,MagickFalse, 03429 value); 03430 if (rendering_intent < 0) 03431 break; 03432 image->rendering_intent=(RenderingIntent) rendering_intent; 03433 break; 03434 } 03435 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03436 ConstantString(property),ConstantString(value)); 03437 break; 03438 } 03439 case 'T': 03440 case 't': 03441 { 03442 if (LocaleCompare(property,"tile-offset") == 0) 03443 { 03444 char 03445 *geometry; 03446 03447 geometry=GetPageGeometry(value); 03448 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset); 03449 geometry=DestroyString(geometry); 03450 break; 03451 } 03452 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03453 ConstantString(property),ConstantString(value)); 03454 break; 03455 } 03456 case 'U': 03457 case 'u': 03458 { 03459 if (LocaleCompare(property,"units") == 0) 03460 { 03461 ssize_t 03462 units; 03463 03464 units=ParseCommandOption(MagickResolutionOptions,MagickFalse,value); 03465 if (units < 0) 03466 break; 03467 image->units=(ResolutionType) units; 03468 break; 03469 } 03470 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03471 ConstantString(property),ConstantString(value)); 03472 break; 03473 } 03474 default: 03475 { 03476 status=AddValueToSplayTree((SplayTreeInfo *) image->properties, 03477 ConstantString(property),ConstantString(value)); 03478 break; 03479 } 03480 } 03481 return(status); 03482 }