Powered by Pair ImageMagick logo
Image Magick
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Globals | Related Pages

ImageMagick-6.1.1/magick/attribute.c

Go to the documentation of this file.
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % AAA TTTTT TTTTT RRRR IIIII BBBB U U TTTTT EEEEE % 00007 % A A T T R R I B B U U T E % 00008 % AAAAA T T RRRR I BBBB U U T EEE % 00009 % A A T T R R I B B U U T E % 00010 % A A T T R R IIIII BBBB UUU T EEEEE % 00011 % % 00012 % % 00013 % Methods to Get/Set/Destroy Image Text Attributes % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % February 2000 % 00018 % % 00019 % % 00020 % Copyright 1999-2004 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/www/Copyright.html % 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 % The Attributes methods gets, sets, or destroys attributes associated 00037 % with a particular image (e.g. comments, copyright, author, etc). 00038 % 00039 % 00040 */ 00041 00042 /* 00043 Include declarations. 00044 */ 00045 #include "magick/studio.h" 00046 #include "magick/attribute.h" 00047 #include "magick/blob.h" 00048 #include "magick/draw.h" 00049 #include "magick/error_private.h" 00050 #include "magick/list.h" 00051 #include "magick/memory_.h" 00052 #include "magick/profile.h" 00053 #include "magick/string_.h" 00054 #include "magick/utility.h" 00055 00056 /* 00057 Forward declarations. 00058 */ 00059 static char 00060 *TracePSClippath(unsigned char *,size_t,const unsigned long, 00061 const unsigned long), 00062 *TraceSVGClippath(unsigned char *,size_t,const unsigned long, 00063 const unsigned long); 00064 00065 /* 00066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00067 % % 00068 % % 00069 % % 00070 % D e s t r o y I m a g e A t t r i b u t e s % 00071 % % 00072 % % 00073 % % 00074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00075 % 00076 % DestroyImageAttributes() deallocates memory associated with the image 00077 % attribute list. 00078 % 00079 % The format of the DestroyImageAttributes method is: 00080 % 00081 % DestroyImageAttributes(Image *image) 00082 % 00083 % A description of each parameter follows: 00084 % 00085 % o image: The image. 00086 % 00087 % 00088 */ 00089 MagickExport void DestroyImageAttributes(Image *image) 00090 { 00091 ImageAttribute 00092 *attribute; 00093 00094 register ImageAttribute 00095 *p; 00096 00097 assert(image != (Image *) NULL); 00098 assert(image->signature == MagickSignature); 00099 if (image->debug != MagickFalse) 00100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00101 for (p=image->attributes; p != (ImageAttribute *) NULL; ) 00102 { 00103 attribute=p; 00104 p=p->next; 00105 if (attribute->key != (char *) NULL) 00106 attribute->key=(char *) RelinquishMagickMemory(attribute->key); 00107 if (attribute->value != (char *) NULL) 00108 attribute->value=(char *) RelinquishMagickMemory(attribute->value); 00109 attribute=(ImageAttribute *) RelinquishMagickMemory(attribute); 00110 } 00111 image->attributes=(ImageAttribute *) NULL; 00112 } 00113 00114 /* 00115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00116 % % 00117 % % 00118 % % 00119 % G e t I m a g e A t t r i b u t e % 00120 % % 00121 % % 00122 % % 00123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00124 % 00125 % GetImageAttribute() searches the list of image attributes and returns 00126 % a pointer to the attribute if it exists otherwise NULL. 00127 % 00128 % The format of the GetImageAttribute method is: 00129 % 00130 % const ImageAttribute *GetImageAttribute(const Image *image, 00131 % const char *key) 00132 % 00133 % A description of each parameter follows: 00134 % 00135 % o image: The image. 00136 % 00137 % o key: These character strings are the name of an image attribute to 00138 % return. 00139 % 00140 % 00141 */ 00142 00143 static MagickBooleanType GenerateIPTCAttribute(Image *image,const char *key) 00144 { 00145 char 00146 *attribute; 00147 00148 const StringInfo 00149 *profile; 00150 00151 int 00152 count, 00153 dataset, 00154 record; 00155 00156 register long 00157 i; 00158 00159 size_t 00160 length; 00161 00162 profile=GetImageProfile(image,"8bim"); 00163 if (profile == (StringInfo *) NULL) 00164 return(MagickFalse); 00165 count=sscanf(key,"IPTC:%d:%d",&dataset,&record); 00166 if (count != 2) 00167 return(MagickFalse); 00168 for (i=0; i < (long) profile->length; i++) 00169 { 00170 if ((int) profile->datum[i] != 0x1c) 00171 continue; 00172 if ((int) profile->datum[i+1] != dataset) 00173 continue; 00174 if ((int) profile->datum[i+2] != record) 00175 continue; 00176 length=(size_t) (profile->datum[i+3] << 8); 00177 length|=profile->datum[i+4]; 00178 attribute=(char *) AcquireMagickMemory(length+MaxTextExtent); 00179 if (attribute == (char *) NULL) 00180 continue; 00181 (void) CopyMagickString(attribute,(char *) profile->datum+i+5,length+1); 00182 (void) SetImageAttribute(image,key,(const char *) attribute); 00183 attribute=(char *) RelinquishMagickMemory(attribute); 00184 break; 00185 } 00186 return((MagickBooleanType) (i < (long) profile->length)); 00187 } 00188 00189 static unsigned char ReadByte(unsigned char **p,size_t *length) 00190 { 00191 unsigned char 00192 c; 00193 00194 if (*length < 1) 00195 return((unsigned char) 0xff); 00196 c=(*(*p)++); 00197 (*length)--; 00198 return(c); 00199 } 00200 00201 static long ReadMSBLong(unsigned char **p,size_t *length) 00202 { 00203 int 00204 c; 00205 00206 long 00207 value; 00208 00209 register long 00210 i; 00211 00212 unsigned char 00213 buffer[4]; 00214 00215 if (*length < 4) 00216 return(-1); 00217 for (i=0; i < 4; i++) 00218 { 00219 c=(int) (*(*p)++); 00220 (*length)--; 00221 buffer[i]=(unsigned char) c; 00222 } 00223 value=(long) (buffer[0] << 24); 00224 value|=buffer[1] << 16; 00225 value|=buffer[2] << 8; 00226 value|=buffer[3]; 00227 return(value); 00228 } 00229 00230 static long ReadMSBShort(unsigned char **p,size_t *length) 00231 { 00232 int 00233 c; 00234 00235 long 00236 value; 00237 00238 register long 00239 i; 00240 00241 unsigned char 00242 buffer[2]; 00243 00244 if (*length < 2) 00245 return(-1); 00246 for (i=0; i < 2; i++) 00247 { 00248 c=(int) (*(*p)++); 00249 (*length)--; 00250 buffer[i]=(unsigned char) c; 00251 } 00252 value=(long) (buffer[0] << 8); 00253 value|=buffer[1]; 00254 return(value); 00255 } 00256 00257 static MagickBooleanType Generate8BIMAttribute(Image *image,const char *key) 00258 { 00259 char 00260 *attribute, 00261 format[MaxTextExtent], 00262 name[MaxTextExtent], 00263 *resource; 00264 00265 const StringInfo 00266 *profile; 00267 00268 long 00269 id, 00270 start, 00271 stop, 00272 sub_number; 00273 00274 MagickBooleanType 00275 status; 00276 00277 register long 00278 i; 00279 00280 ssize_t 00281 count; 00282 00283 size_t 00284 length; 00285 00286 unsigned char 00287 *info; 00288 00289 /* 00290 There's no newlines in path names, so it's safe as terminator. 00291 */ 00292 profile=GetImageProfile(image,"iptc"); 00293 if (profile == (StringInfo *) NULL) 00294 return(MagickFalse); 00295 count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%[^\n]\n%[^\n]",&start,&stop,name, 00296 format); 00297 if ((count != 2) && (count != 3) && (count != 4)) 00298 return(MagickFalse); 00299 if (count < 4) 00300 (void) strcpy(format,"SVG"); 00301 if (count < 3) 00302 *name='\0'; 00303 sub_number=1; 00304 if (*name == '#') 00305 sub_number=atol(&name[1]); 00306 sub_number=Max(sub_number,1); 00307 resource=(char *) NULL; 00308 status=MagickFalse; 00309 length=profile->length; 00310 info=(unsigned char *) profile->datum; 00311 while ((length > 0) && (status == MagickFalse)) 00312 { 00313 if (ReadByte(&info,&length) != (unsigned char) '8') 00314 continue; 00315 if (ReadByte(&info,&length) != (unsigned char) 'B') 00316 continue; 00317 if (ReadByte(&info,&length) != (unsigned char) 'I') 00318 continue; 00319 if (ReadByte(&info,&length) != (unsigned char) 'M') 00320 continue; 00321 id=ReadMSBShort(&info,&length); 00322 if (id < start) 00323 continue; 00324 if (id > stop) 00325 continue; 00326 if (resource != (char *) NULL) 00327 resource=(char *) RelinquishMagickMemory(resource); 00328 count=(ssize_t) ReadByte(&info,&length); 00329 if ((count != 0) && ((size_t) count <= length)) 00330 { 00331 resource=(char *) AcquireMagickMemory((size_t) count+MaxTextExtent); 00332 if (resource != (char *) NULL) 00333 { 00334 for (i=0; i < (long) count; i++) 00335 resource[i]=(char) ReadByte(&info,&length); 00336 resource[count]='\0'; 00337 } 00338 } 00339 if ((count & 0x01) == 0) 00340 (void) ReadByte(&info,&length); 00341 count=(ssize_t) ReadMSBLong(&info,&length); 00342 if ((*name != '\0') && (*name != '#')) 00343 if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0)) 00344 { 00345 /* 00346 No name match, scroll forward and try next. 00347 */ 00348 info+=count; 00349 length-=count; 00350 continue; 00351 } 00352 if ((*name == '#') && (sub_number != 1)) 00353 { 00354 /* 00355 No numbered match, scroll forward and try next. 00356 */ 00357 sub_number--; 00358 info+=count; 00359 length-=count; 00360 continue; 00361 } 00362 /* 00363 We have the resource of interest. 00364 */ 00365 attribute=(char *) AcquireMagickMemory((size_t) count+MaxTextExtent); 00366 if (attribute != (char *) NULL) 00367 { 00368 (void) CopyMagickMemory(attribute,(char *) info,(size_t) count); 00369 attribute[count]='\0'; 00370 info+=count; 00371 length-=count; 00372 if ((id <= 1999) || (id >= 2999)) 00373 (void) SetImageAttribute(image,key,(const char *) attribute); 00374 else 00375 { 00376 char 00377 *path; 00378 00379 if (LocaleCompare("svg",format) == 0) 00380 path=TraceSVGClippath((unsigned char *) attribute,(size_t) count, 00381 image->columns,image->rows); 00382 else 00383 path=TracePSClippath((unsigned char *) attribute,(size_t) count, 00384 image->columns,image->rows); 00385 (void) SetImageAttribute(image,key,(const char *) path); 00386 path=(char *) RelinquishMagickMemory(path); 00387 } 00388 attribute=(char *) RelinquishMagickMemory(attribute); 00389 status=MagickTrue; 00390 } 00391 } 00392 if (resource != (char *) NULL) 00393 resource=(char *) RelinquishMagickMemory(resource); 00394 return(status); 00395 } 00396 00397 #define DE_STACK_SIZE 16 00398 #define EXIF_DELIMITER "\n" 00399 #define EXIF_NUM_FORMATS 12 00400 #define EXIF_FMT_BYTE 1 00401 #define EXIF_FMT_STRING 2 00402 #define EXIF_FMT_USHORT 3 00403 #define EXIF_FMT_ULONG 4 00404 #define EXIF_FMT_URATIONAL 5 00405 #define EXIF_FMT_SBYTE 6 00406 #define EXIF_FMT_UNDEFINED 7 00407 #define EXIF_FMT_SSHORT 8 00408 #define EXIF_FMT_SLONG 9 00409 #define EXIF_FMT_SRATIONAL 10 00410 #define EXIF_FMT_SINGLE 11 00411 #define EXIF_FMT_DOUBLE 12 00412 #define TAG_EXIF_OFFSET 0x8769 00413 #define TAG_INTEROP_OFFSET 0xa005 00414 00415 typedef struct _TagInfo 00416 { 00417 unsigned short 00418 tag; 00419 00420 char 00421 *description; 00422 } TagInfo; 00423 00424 static TagInfo 00425 tag_table[] = 00426 { 00427 { 0x100, (char *) "ImageWidth"}, 00428 { 0x101, (char *) "ImageLength"}, 00429 { 0x102, (char *) "BitsPerSample"}, 00430 { 0x103, (char *) "Compression"}, 00431 { 0x106, (char *) "PhotometricInterpretation"}, 00432 { 0x10a, (char *) "FillOrder"}, 00433 { 0x10d, (char *) "DocumentName"}, 00434 { 0x10e, (char *) "ImageDescription"}, 00435 { 0x10f, (char *) "Make"}, 00436 { 0x110, (char *) "Model"}, 00437 { 0x111, (char *) "StripOffsets"}, 00438 { 0x112, (char *) "Orientation"}, 00439 { 0x115, (char *) "SamplesPerPixel"}, 00440 { 0x116, (char *) "RowsPerStrip"}, 00441 { 0x117, (char *) "StripByteCounts"}, 00442 { 0x11a, (char *) "XResolution"}, 00443 { 0x11b, (char *) "YResolution"}, 00444 { 0x11c, (char *) "PlanarConfiguration"}, 00445 { 0x128, (char *) "ResolutionUnit"}, 00446 { 0x12d, (char *) "TransferFunction"}, 00447 { 0x131, (char *) "Software"}, 00448 { 0x132, (char *) "DateTime"}, 00449 { 0x13b, (char *) "Artist"}, 00450 { 0x13e, (char *) "WhitePoint"}, 00451 { 0x13f, (char *) "PrimaryChromaticities"}, 00452 { 0x156, (char *) "TransferRange"}, 00453 { 0x200, (char *) "JPEGProc"}, 00454 { 0x201, (char *) "JPEGInterchangeFormat"}, 00455 { 0x202, (char *) "JPEGInterchangeFormatLength"}, 00456 { 0x211, (char *) "YCbCrCoefficients"}, 00457 { 0x212, (char *) "YCbCrSubSampling"}, 00458 { 0x213, (char *) "YCbCrPositioning"}, 00459 { 0x214, (char *) "ReferenceBlackWhite"}, 00460 { 0x1000, (char *) "RelatedImageFileFormat"}, 00461 { 0x1001, (char *) "RelatedImageLength"}, 00462 { 0x1002, (char *) "RelatedImageWidth"}, 00463 { 0x828d, (char *) "CFARepeatPatternDim"}, 00464 { 0x828e, (char *) "CFAPattern"}, 00465 { 0x828f, (char *) "BatteryLevel"}, 00466 { 0x8298, (char *) "Copyright"}, 00467 { 0x829a, (char *) "ExposureTime"}, 00468 { 0x829d, (char *) "FNumber"}, 00469 { 0x83Bb, (char *) "IPTC/NAA"}, 00470 { 0x8769, (char *) "ExifOffset"}, 00471 { 0x8773, (char *) "InterColorProfile"}, 00472 { 0x8822, (char *) "ExposureProgram"}, 00473 { 0x8824, (char *) "SpectralSensitivity"}, 00474 { 0x8825, (char *) "GPSInfo"}, 00475 { 0x8827, (char *) "ISOSpeedRatings"}, 00476 { 0x8828, (char *) "OECF"}, 00477 { 0x8829, (char *) "Interlace"}, 00478 { 0x882a, (char *) "TimeZoneOffset"}, 00479 { 0x882b, (char *) "SelfTimerMode"}, 00480 { 0x9000, (char *) "ExifVersion"}, 00481 { 0x9003, (char *) "DateTimeOriginal"}, 00482 { 0x9004, (char *) "DateTimeDigitized"}, 00483 { 0x9101, (char *) "ComponentsConfiguration"}, 00484 { 0x9102, (char *) "CompressedBitsPerPixel"}, 00485 { 0x9201, (char *) "ShutterSpeedValue"}, 00486 { 0x9202, (char *) "ApertureValue"}, 00487 { 0x9203, (char *) "BrightnessValue"}, 00488 { 0x9204, (char *) "ExposureBiasValue"}, 00489 { 0x9205, (char *) "MaxApertureValue"}, 00490 { 0x9206, (char *) "SubjectDistance"}, 00491 { 0x9207, (char *) "MeteringMode"}, 00492 { 0x9208, (char *) "LightSrc"}, 00493 { 0x9209, (char *) "Flash"}, 00494 { 0x920a, (char *) "FocalLength"}, 00495 { 0x920b, (char *) "FlashEnergy"}, 00496 { 0x920c, (char *) "SpatialFrequencyResponse"}, 00497 { 0x920d, (char *) "Noise"}, 00498 { 0x9211, (char *) "ImageNumber"}, 00499 { 0x9212, (char *) "SecurityClassification"}, 00500 { 0x9213, (char *) "ImageHistory"}, 00501 { 0x9214, (char *) "SubjectLocation"}, 00502 { 0x9215, (char *) "ExposureIndex"}, 00503 { 0x9216, (char *) "TIFF/EPStandardID"}, 00504 { 0x927c, (char *) "MakerNote"}, 00505 { 0x9286, (char *) "UserComment"}, 00506 { 0x9290, (char *) "SubSecTime"}, 00507 { 0x9291, (char *) "SubSecTimeOriginal"}, 00508 { 0x9292, (char *) "SubSecTimeDigitized"}, 00509 { 0xA000, (char *) "FlashPixVersion"}, 00510 { 0xA001, (char *) "ColorSpace"}, 00511 { 0xA002, (char *) "ExifImageWidth"}, 00512 { 0xA003, (char *) "ExifImageLength"}, 00513 { 0xA005, (char *) "InteroperabilityOffset"}, 00514 { 0xA20b, (char *) "FlashEnergy"}, 00515 { 0xA20c, (char *) "SpatialFrequencyResponse"}, 00516 { 0xA20e, (char *) "FocalPlaneXResolution"}, 00517 { 0xA20f, (char *) "FocalPlaneYResolution"}, 00518 { 0xA210, (char *) "FocalPlaneResolutionUnit"}, 00519 { 0xA214, (char *) "SubjectLocation"}, 00520 { 0xA215, (char *) "ExposureIndex"}, 00521 { 0xA217, (char *) "SensingMethod"}, 00522 { 0xA300, (char *) "FileSource"}, 00523 { 0xA301, (char *) "SceneType"}, 00524 { 0xA302, (char *) "CFAPattern"}, 00525 { 0x0000, (char *) NULL} 00526 }; 00527 00528 static int 00529 format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}; 00530 00531 static short ReadInt16(unsigned int msb_order,void *buffer) 00532 { 00533 short 00534 value; 00535 00536 if (msb_order != MagickFalse) 00537 { 00538 value=(short) ((((unsigned char *) buffer)[0] << 8) | 00539 ((unsigned char *) buffer)[1]); 00540 return(value); 00541 } 00542 value=(short) ((((unsigned char *) buffer)[1] << 8) | 00543 ((unsigned char *) buffer)[0]); 00544 return(value); 00545 } 00546 00547 static long ReadInt32(unsigned int msb_order,void *buffer) 00548 { 00549 long 00550 value; 00551 00552 if (msb_order != MagickFalse) 00553 { 00554 value=(long) ((((unsigned char *) buffer)[0] << 24) | 00555 (((unsigned char *) buffer)[1] << 16) | 00556 (((unsigned char *) buffer)[2] << 8) | (((unsigned char *) buffer)[3])); 00557 return(value); 00558 } 00559 value=(long) ((((unsigned char *) buffer)[3] << 24) | 00560 (((unsigned char *) buffer)[2] << 16) | 00561 (((unsigned char *) buffer)[1] << 8 ) | 00562 (((unsigned char *) buffer)[0])); 00563 return(value); 00564 } 00565 00566 static unsigned short ReadUint16(unsigned int msb_order,void *buffer) 00567 { 00568 unsigned short 00569 value; 00570 00571 if (msb_order != MagickFalse) 00572 { 00573 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) | 00574 ((unsigned char *) buffer)[1]); 00575 return(value); 00576 } 00577 value=(unsigned short) ((((unsigned char *) buffer)[1] << 8) | 00578 ((unsigned char *) buffer)[0]); 00579 return(value); 00580 } 00581 00582 static unsigned long ReadUint32(unsigned int msb_order,void *buffer) 00583 { 00584 return((unsigned long) ReadInt32(msb_order,buffer) & 0xffffffff); 00585 } 00586 00587 static int GenerateEXIFAttribute(Image *image,const char *specification) 00588 { 00589 char 00590 *key, 00591 *value, 00592 *final; 00593 00594 const StringInfo 00595 *profile; 00596 00597 int 00598 all, 00599 id, 00600 level; 00601 00602 register long 00603 i; 00604 00605 size_t 00606 length; 00607 00608 unsigned long 00609 offset; 00610 00611 unsigned char 00612 *tiffp, 00613 *ifdstack[DE_STACK_SIZE], 00614 *ifdp, 00615 *info; 00616 00617 unsigned int 00618 de, 00619 destack[DE_STACK_SIZE], 00620 msb_order, 00621 nde; 00622 00623 unsigned long 00624 tag; 00625 00626 /* 00627 If EXIF data exists, then try to parse the request for a tag. 00628 */ 00629 profile=GetImageProfile(image,"exif"); 00630 if (profile == (StringInfo *) NULL) 00631 return(MagickFalse); 00632 value=(char *) NULL; 00633 final=AcquireString(""); 00634 key=(char *) &specification[5]; 00635 if ((key == (char *) NULL) || (*key == '\0')) 00636 return(MagickFalse); 00637 while (isspace((int) ((unsigned char) *key)) != 0) 00638 key++; 00639 all=0; 00640 tag=(~0UL); 00641 switch (*key) 00642 { 00643 /* 00644 Caller has asked for all the tags in the EXIF data. 00645 */ 00646 case '*': 00647 { 00648 tag=0; 00649 all=1; /* return the data in description=value format */ 00650 break; 00651 } 00652 case '!': 00653 { 00654 tag=0; 00655 all=2; /* return the data in tageid=value format */ 00656 break; 00657 } 00658 /* 00659 Check for a hex based tag specification first. 00660 */ 00661 case '#': 00662 { 00663 char 00664 c; 00665 00666 unsigned long 00667 n; 00668 00669 tag=0; 00670 key++; 00671 n=(unsigned long) strlen(key); 00672 if (n != 4) 00673 return(MagickFalse); 00674 else 00675 { 00676 /* 00677 Parse tag specification as a hex number. 00678 */ 00679 n/=4; 00680 do 00681 { 00682 for (i=(long) n-1; i >= 0; i--) 00683 { 00684 c=(*key++); 00685 tag<<=4; 00686 if ((c >= '0') && (c <= '9')) 00687 tag|=(int) (c-'0'); 00688 else 00689 if ((c >= 'A') && (c <= 'F')) 00690 tag|=(int) (c-('A'-(char) 10)); 00691 else 00692 if ((c >= 'a') && (c <= 'f')) 00693 tag|=(int) (c-('a'-(char) 10)); 00694 else 00695 return(MagickFalse); 00696 } 00697 } while (*key != '\0'); 00698 } 00699 break; 00700 } 00701 default: 00702 { 00703 /* 00704 Try to match the text with a tag name instead. 00705 */ 00706 for (i=0; ; i++) 00707 { 00708 if (tag_table[i].tag == 0) 00709 break; 00710 if (LocaleCompare(tag_table[i].description,key) == 0) 00711 { 00712 tag=(unsigned long) tag_table[i].tag; 00713 break; 00714 } 00715 } 00716 break; 00717 } 00718 } 00719 if (tag == (~0UL)) 00720 return(MagickFalse); 00721 length=profile->length; 00722 info=(unsigned char *) profile->datum; 00723 while (length != 0) 00724 { 00725 if ((int) ReadByte(&info,&length) != 0x45) 00726 continue; 00727 if ((int) ReadByte(&info,&length) != 0x78) 00728 continue; 00729 if ((int) ReadByte(&info,&length) != 0x69) 00730 continue; 00731 if ((int) ReadByte(&info,&length) != 0x66) 00732 continue; 00733 if ((int) ReadByte(&info,&length) != 0x00) 00734 continue; 00735 if ((int) ReadByte(&info,&length) != 0x00) 00736 continue; 00737 break; 00738 } 00739 if (length < 16) 00740 return(MagickFalse); 00741 tiffp=info; 00742 id=(int) ReadUint16(0,tiffp); 00743 msb_order=0; 00744 if (id == 0x4949) /* LSB */ 00745 msb_order=0; 00746 else 00747 if (id == 0x4D4D) /* MSB */ 00748 msb_order=1; 00749 else 00750 return(MagickFalse); 00751 if (ReadUint16(msb_order,tiffp+2) != 0x002a) 00752 return(MagickFalse); 00753 /* 00754 This is the offset to the first IFD. 00755 */ 00756 offset=ReadUint32(msb_order,tiffp+4); 00757 if ((size_t) offset >= length) 00758 return(MagickFalse); 00759 /* 00760 Set the pointer to the first IFD and follow it were it leads. 00761 */ 00762 ifdp=tiffp+offset; 00763 level=0; 00764 de=0; 00765 do 00766 { 00767 /* 00768 If there is anything on the stack then pop it off. 00769 */ 00770 if (level > 0) 00771 { 00772 level--; 00773 ifdp=ifdstack[level]; 00774 de=destack[level]; 00775 } 00776 /* 00777 Determine how many entries there are in the current IFD. 00778 */ 00779 nde=ReadUint16(msb_order,ifdp); 00780 for (; de < nde; de++) 00781 { 00782 long 00783 n, 00784 t, 00785 f, 00786 c; 00787 00788 char 00789 *pde, 00790 *pval; 00791 00792 pde=(char *) (ifdp+2+(12*de)); 00793 t=(long) ReadUint16(msb_order,pde); /* get tag value */ 00794 f=(long) ReadUint16(msb_order,pde+2); /* get the format */ 00795 if ((f-1) >= EXIF_NUM_FORMATS) 00796 break; 00797 c=(long) ReadUint32(msb_order,pde+4); /* get number of components */ 00798 n=c*format_bytes[f]; 00799 if (n <= 4) 00800 pval=pde+8; 00801 else 00802 { 00803 unsigned long 00804 oval; 00805 00806 /* 00807 The directory entry contains an offset. 00808 */ 00809 oval=ReadUint32(msb_order,pde+8); 00810 if ((size_t) (oval+n) > length) 00811 continue; 00812 pval=(char *)(tiffp+oval); 00813 } 00814 if ((all != 0) || (tag == (unsigned long) t)) 00815 { 00816 char 00817 buffer[MaxTextExtent]; 00818 00819 switch (f) 00820 { 00821 case EXIF_FMT_SBYTE: 00822 { 00823 (void) FormatMagickString(buffer,MaxTextExtent,"%ld", 00824 (long) (*(char *) pval)); 00825 value=AcquireString(buffer); 00826 break; 00827 } 00828 case EXIF_FMT_BYTE: 00829 { 00830 (void) FormatMagickString(buffer,MaxTextExtent,"%ld", 00831 (long) (*(unsigned char *) pval)); 00832 value=AcquireString(buffer); 00833 break; 00834 } 00835 case EXIF_FMT_SSHORT: 00836 { 00837 (void) FormatMagickString(buffer,MaxTextExtent,"%hd", 00838 ReadUint16(msb_order,pval)); 00839 value=AcquireString(buffer); 00840 break; 00841 } 00842 case EXIF_FMT_USHORT: 00843 { 00844 (void) FormatMagickString(buffer,MaxTextExtent,"%hu", 00845 ReadInt16(msb_order,pval)); 00846 value=AcquireString(buffer); 00847 break; 00848 } 00849 case EXIF_FMT_ULONG: 00850 { 00851 (void) FormatMagickString(buffer,MaxTextExtent,"%lu", 00852 ReadUint32(msb_order,pval)); 00853 value=AcquireString(buffer); 00854 break; 00855 } 00856 case EXIF_FMT_SLONG: 00857 { 00858 (void) FormatMagickString(buffer,MaxTextExtent,"%ld", 00859 ReadInt32(msb_order,pval)); 00860 value=AcquireString(buffer); 00861 break; 00862 } 00863 case EXIF_FMT_URATIONAL: 00864 { 00865 (void) FormatMagickString(buffer,MaxTextExtent,"%ld/%ld", 00866 ReadUint32(msb_order,pval), 00867 ReadUint32(msb_order,4+(char *) pval)); 00868 value=AcquireString(buffer); 00869 break; 00870 } 00871 case EXIF_FMT_SRATIONAL: 00872 { 00873 (void) FormatMagickString(buffer,MaxTextExtent,"%ld/%ld", 00874 ReadInt32(msb_order,pval), 00875 ReadInt32(msb_order,4+(char *) pval)); 00876 value=AcquireString(buffer); 00877 break; 00878 } 00879 case EXIF_FMT_SINGLE: 00880 { 00881 (void) FormatMagickString(buffer,MaxTextExtent,"%f", 00882 (double) *(float *) pval); 00883 value=AcquireString(buffer); 00884 break; 00885 } 00886 case EXIF_FMT_DOUBLE: 00887 { 00888 (void) FormatMagickString(buffer,MaxTextExtent,"%f", 00889 *(double *) pval); 00890 value=AcquireString(buffer); 00891 break; 00892 } 00893 default: 00894 case EXIF_FMT_UNDEFINED: 00895 case EXIF_FMT_STRING: 00896 { 00897 value=(char *) AcquireMagickMemory((size_t) n+1); 00898 if (value != (char *) NULL) 00899 { 00900 long 00901 a; 00902 00903 for (a=0; a < n; a++) 00904 { 00905 value[a]='.'; 00906 if (isprint((int) ((unsigned char) pval[a])) != 0) 00907 value[a]=pval[a]; 00908 } 00909 value[a]='\0'; 00910 break; 00911 } 00912 break; 00913 } 00914 } 00915 if (value != (char *) NULL) 00916 { 00917 int 00918 i; 00919 00920 char 00921 *description; 00922 00923 if (strlen(final) != 0) 00924 (void) ConcatenateString(&final,EXIF_DELIMITER); 00925 description=(char *) NULL; 00926 switch (all) 00927 { 00928 case 1: 00929 { 00930 description=(char *) "unknown"; 00931 for (i=0; ; i++) 00932 { 00933 if (tag_table[i].tag == 0) 00934 break; 00935 if ((long) tag_table[i].tag == t) 00936 { 00937 description=tag_table[i].description; 00938 break; 00939 } 00940 } 00941 (void) FormatMagickString(buffer,MaxTextExtent,"%s=", 00942 description); 00943 (void) ConcatenateString(&final,buffer); 00944 break; 00945 } 00946 case 2: 00947 { 00948 (void) FormatMagickString(buffer,MaxTextExtent,"#%04lx=",t); 00949 (void) ConcatenateString(&final,buffer); 00950 break; 00951 } 00952 } 00953 (void) ConcatenateString(&final,value); 00954 value=(char *) RelinquishMagickMemory(value); 00955 } 00956 } 00957 if ((t == TAG_EXIF_OFFSET) || (t == TAG_INTEROP_OFFSET)) 00958 { 00959 long 00960 offset; 00961 00962 offset=(long) ReadUint32(msb_order,pval); 00963 if ((offset < (long) length) || (level < (DE_STACK_SIZE-2))) 00964 { 00965 /* 00966 Push our current directory state onto the stack. 00967 */ 00968 ifdstack[level]=ifdp; 00969 de++; /* bump to the next entry */ 00970 destack[level]=de; 00971 level++; 00972 /* 00973 Push new state onto of stack to cause a jump. 00974 */ 00975 ifdstack[level]=tiffp+offset; 00976 destack[level]=0; 00977 level++; 00978 } 00979 break; /* break out of the for loop */ 00980 } 00981 } 00982 } while ((level > 0) && (level < DE_STACK_SIZE)); 00983 if (strlen(final) == 0) 00984 (void) ConcatenateString(&final,"unknown"); 00985 (void) SetImageAttribute(image,specification,(const char *) final); 00986 final=(char *) RelinquishMagickMemory(final); 00987 return(MagickTrue); 00988 } 00989 00990 MagickExport const ImageAttribute *GetImageAttribute(const Image *image, 00991 const char *key) 00992 { 00993 register ImageAttribute 00994 *p; 00995 00996 assert(image != (Image *) NULL); 00997 assert(image->signature == MagickSignature); 00998 if (image->debug != MagickFalse) 00999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 01000 if (key == (char *) NULL) 01001 return(image->attributes); 01002 for (p=image->attributes; p != (ImageAttribute *) NULL; p=p->next) 01003 if (LocaleCompare(key,p->key) == 0) 01004 return(p); 01005 if (LocaleNCompare("iptc:",key,5) == 0) 01006 { 01007 if (GenerateIPTCAttribute((Image *) image,key) == MagickTrue) 01008 return(GetImageAttribute(image,key)); 01009 } 01010 if (LocaleNCompare("8bim:",key,5) == 0) 01011 { 01012 if (Generate8BIMAttribute((Image *) image,key) == MagickTrue) 01013 return(GetImageAttribute(image,key)); 01014 } 01015 if (LocaleNCompare("exif:",key,5) == 0) 01016 { 01017 if (GenerateEXIFAttribute((Image *) image,key) == MagickTrue) 01018 return(GetImageAttribute(image,key)); 01019 } 01020 return(p); 01021 } 01022 01023 /* 01024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01025 % % 01026 % % 01027 % % 01028 % G e t I m a g e C l i p p i n g P a t h A t t r i b u t e % 01029 % % 01030 % % 01031 % % 01032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01033 % 01034 % GetImageClippingPathAttribute() searches the list of image attributes and 01035 % returns a pointer to a clipping path if it exists otherwise NULL. 01036 % 01037 % The format of the GetImageClippingPathAttribute method is: 01038 % 01039 % const ImageAttribute *GetImageClippingPathAttribute(const Image *image) 01040 % 01041 % A description of each parameter follows: 01042 % 01043 % o attribute: Method GetImageClippingPathAttribute returns the clipping 01044 % path if it exists otherwise NULL. 01045 % 01046 % o image: The image. 01047 % 01048 % 01049 */ 01050 MagickExport const ImageAttribute *GetImageClippingPathAttribute( 01051 const Image *image) 01052 { 01053 return(GetImageAttribute(image,"8BIM:1999,2998")); 01054 } 01055 01056 /* 01057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01058 % % 01059 % % 01060 % % 01061 + G e t I m a g e I n f o A t t r i b u t e % 01062 % % 01063 % % 01064 % % 01065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01066 % 01067 % GetImageInfoAttribute() returns a "fake" attribute based on data in the 01068 % image info or image structures. 01069 % 01070 % The format of the GetImageInfoAttribute method is: 01071 % 01072 % const ImageAttribute *GetImageAttribute(const ImageInfo *image_info, 01073 % const Image *image,const char *key) 01074 % 01075 % A description of each parameter follows: 01076 % 01077 % o attribute: Method GetImageInfoAttribute returns the attribute if it 01078 % exists otherwise NULL. 01079 % 01080 % o image_info: The imageInfo. 01081 % 01082 % o image: The image. 01083 % 01084 % o key: These character strings are the name of an image attribute to 01085 % return. 01086 % 01087 */ 01088 MagickExport const ImageAttribute *GetImageInfoAttribute( 01089 const ImageInfo *image_info,const Image *image,const char *key) 01090 { 01091 char 01092 attribute[MaxTextExtent], 01093 filename[MaxTextExtent]; 01094 01095 attribute[0]='\0'; 01096 switch (*(key)) 01097 { 01098 case 'b': 01099 { 01100 if (LocaleNCompare("base",key,2) == 0) 01101 { 01102 GetPathComponent(image->magick_filename,BasePath,filename); 01103 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01104 break; 01105 } 01106 break; 01107 } 01108 case 'd': 01109 { 01110 if (LocaleNCompare("depth",key,2) == 0) 01111 { 01112 (void) FormatMagickString(attribute,MaxTextExtent,"%lu",image->depth); 01113 break; 01114 } 01115 if (LocaleNCompare("directory",key,2) == 0) 01116 { 01117 GetPathComponent(image->magick_filename,HeadPath,filename); 01118 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01119 break; 01120 } 01121 break; 01122 } 01123 case 'e': 01124 { 01125 if (LocaleNCompare("extension",key,2) == 0) 01126 { 01127 GetPathComponent(image->magick_filename,ExtensionPath,filename); 01128 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01129 break; 01130 } 01131 break; 01132 } 01133 case 'g': 01134 { 01135 if (LocaleNCompare("group",key,2) == 0) 01136 { 01137 (void) FormatMagickString(attribute,MaxTextExtent,"0x%lx", 01138 image_info->group); 01139 break; 01140 } 01141 break; 01142 } 01143 case 'h': 01144 { 01145 if (LocaleNCompare("height",key,2) == 0) 01146 { 01147 (void) FormatMagickString(attribute,MaxTextExtent,"%lu", 01148 image->magick_rows != 0 ? image->magick_rows : 256UL); 01149 break; 01150 } 01151 break; 01152 } 01153 case 'i': 01154 { 01155 if (LocaleNCompare("input",key,2) == 0) 01156 { 01157 (void) CopyMagickString(attribute,image->filename,MaxTextExtent); 01158 break; 01159 } 01160 break; 01161 } 01162 case 'm': 01163 { 01164 if (LocaleNCompare("magick",key,2) == 0) 01165 { 01166 (void) CopyMagickString(attribute,image->magick,MaxTextExtent); 01167 break; 01168 } 01169 break; 01170 } 01171 case 'n': 01172 { 01173 if (LocaleNCompare("name",key,2) == 0) 01174 { 01175 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01176 break; 01177 } 01178 break; 01179 } 01180 case 's': 01181 { 01182 if (LocaleNCompare("size",key,2) == 0) 01183 { 01184 char 01185 format[MaxTextExtent]; 01186 01187 FormatSize(GetBlobSize(image),format); 01188 (void) FormatMagickString(attribute,MaxTextExtent,"%s",format); 01189 break; 01190 } 01191 if (LocaleNCompare("scene",key,2) == 0) 01192 { 01193 (void) FormatMagickString(attribute,MaxTextExtent,"%lu",image->scene); 01194 if (image_info->number_scenes != 0) 01195 (void) FormatMagickString(attribute,MaxTextExtent,"%lu", 01196 image_info->scene); 01197 break; 01198 } 01199 if (LocaleNCompare("scenes",key,6) == 0) 01200 { 01201 (void) FormatMagickString(attribute,MaxTextExtent,"%lu", 01202 (unsigned long) GetImageListLength(image)); 01203 break; 01204 } 01205 break; 01206 } 01207 case 'o': 01208 { 01209 if (LocaleNCompare("output",key,2) == 0) 01210 { 01211 (void) CopyMagickString(attribute,image_info->filename,MaxTextExtent); 01212 break; 01213 } 01214 break; 01215 } 01216 case 'p': 01217 { 01218 if (LocaleNCompare("page",key,2) == 0) 01219 { 01220 register const Image 01221 *p; 01222 01223 unsigned long 01224 page; 01225 01226 p=image; 01227 for (page=1; p->previous != (Image *) NULL; page++) 01228 p=p->previous; 01229 (void) FormatMagickString(attribute,MaxTextExtent,"%lu",page); 01230 break; 01231 } 01232 break; 01233 } 01234 case 'u': 01235 { 01236 if (LocaleNCompare("unique",key,2) == 0) 01237 { 01238 (void) CopyMagickString(filename,image_info->unique,MaxTextExtent); 01239 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01240 break; 01241 } 01242 break; 01243 } 01244 case 'w': 01245 { 01246 if (LocaleNCompare("width",key,2) == 0) 01247 { 01248 (void) FormatMagickString(attribute,MaxTextExtent,"%lu", 01249 image->magick_columns != 0 ? image->magick_columns : 256UL); 01250 break; 01251 } 01252 break; 01253 } 01254 case 'x': 01255 { 01256 if (LocaleNCompare("xresolution",key,2) == 0) 01257 { 01258 (void) FormatMagickString(attribute,MaxTextExtent,"%g", 01259 image->x_resolution); 01260 break; 01261 } 01262 break; 01263 } 01264 case 'y': 01265 { 01266 if (LocaleNCompare("yresolution",key,2) == 0) 01267 { 01268 (void) FormatMagickString(attribute,MaxTextExtent,"%g", 01269 image->y_resolution); 01270 break; 01271 } 01272 break; 01273 } 01274 case 'z': 01275 { 01276 if (LocaleNCompare("zero",key,2) == 0) 01277 { 01278 (void) CopyMagickString(filename,image_info->zero,MaxTextExtent); 01279 (void) CopyMagickString(attribute,filename,MaxTextExtent); 01280 break; 01281 } 01282 break; 01283 } 01284 } 01285 if (strlen(image->magick_filename) != 0) 01286 return(GetImageAttribute(image,key)); 01287 return((ImageAttribute *) NULL); 01288 } 01289 01290 /* 01291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01292 % % 01293 % % 01294 % % 01295 % S e t I m a g e A t t r i b u t e % 01296 % % 01297 % % 01298 % % 01299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01300 % 01301 % SetImageAttribute() searches the list of image attributes and replaces the 01302 % attribute value. If it is not found in the list, the attribute name 01303 % and value is added to the list. If the attribute exists in the list, 01304 % the value is concatenated to the attribute. SetImageAttribute returns 01305 % MagickTrue if the attribute is successfully concatenated or added to the 01306 % list, otherwise MagickFalse. If the value is NULL, the matching key is 01307 % deleted from the list. 01308 % 01309 % The format of the SetImageAttribute method is: 01310 % 01311 % MagickBooleanType SetImageAttribute(Image *image,const char *key, 01312 % const char *value) 01313 % 01314 % A description of each parameter follows: 01315 % 01316 % o image: The image. 01317 % 01318 % o key,value: These character strings are the name and value of an image 01319 % attribute to replace or add to the list. 01320 % 01321 % 01322 */ 01323 MagickExport MagickBooleanType SetImageAttribute(Image *image,const char *key, 01324 const char *value) 01325 { 01326 ImageAttribute 01327 *attribute; 01328 01329 register const char 01330 *q; 01331 01332 register ImageAttribute 01333 *p; 01334 01335 /* 01336 Initialize new attribute. 01337 */ 01338 assert(image != (Image *) NULL); 01339 assert(image->signature == MagickSignature); 01340 if (image->debug != MagickFalse) 01341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 01342 if ((key == (const char *) NULL) || (*key == '\0')) 01343 return(MagickFalse); 01344 if (value == (const char *) NULL) 01345 { 01346 /* 01347 Delete attribute from the image attributes list. 01348 */ 01349 for (p=image->attributes; p != (ImageAttribute *) NULL; p=p->next) 01350 if (LocaleCompare(key,p->key) == 0) 01351 break; 01352 if (p == (ImageAttribute *) NULL) 01353 return(MagickFalse); 01354 if (p->key != (char *) NULL) 01355 p->key=(char *) RelinquishMagickMemory(p->key); 01356 if (p->value != (char *) NULL) 01357 p->value=(char *) RelinquishMagickMemory(p->value); 01358 if (p->previous != (ImageAttribute *) NULL) 01359 p->previous->next=p->next; 01360 else 01361 { 01362 image->attributes=p->next; 01363 if (p->next != (ImageAttribute *) NULL) 01364 p->next->previous=(ImageAttribute *) NULL; 01365 } 01366 if (p->next != (ImageAttribute *) NULL) 01367 p->next->previous=p->previous; 01368 attribute=p; 01369 attribute=(ImageAttribute *) RelinquishMagickMemory(attribute); 01370 return(MagickTrue); 01371 } 01372 if (*value == '\0') 01373 return(MagickFalse); 01374 attribute=(ImageAttribute *) AcquireMagickMemory(sizeof(ImageAttribute)); 01375 if (attribute == (ImageAttribute *) NULL) 01376 return(MagickFalse); 01377 attribute->key=AcquireString(key); 01378 for (q=value; *q != '\0'; q++) 01379 if (((int) ((unsigned char) *q) < 32) && 01380 (isspace((int) ((unsigned char) *q)) == 0)) 01381 break; 01382 if (*q != '\0') 01383 attribute->value=AcquireString(value); 01384 else 01385 attribute->value=TranslateText((ImageInfo *) NULL,image,value); 01386 attribute->compression=MagickFalse; 01387 attribute->previous=(ImageAttribute *) NULL; 01388 attribute->next=(ImageAttribute *) NULL; 01389 if (image->attributes == (ImageAttribute *) NULL) 01390 { 01391 image->attributes=attribute; 01392 return(MagickTrue); 01393 } 01394 for (p=image->attributes; p != (ImageAttribute *) NULL; p=p->next) 01395 { 01396 if (LocaleCompare(attribute->key,p->key) == 0) 01397 { 01398 (void) ConcatenateString(&p->value,attribute->value); 01399 attribute->value=(char *) RelinquishMagickMemory(attribute->value); 01400 attribute->key=(char *) RelinquishMagickMemory(attribute->key); 01401 attribute=(ImageAttribute *) RelinquishMagickMemory(attribute); 01402 return(MagickTrue); 01403 } 01404 if (p->next == (ImageAttribute *) NULL) 01405 break; 01406 } 01407 /* 01408 Place new attribute at the end of the attribute list. 01409 */ 01410 attribute->previous=p; 01411 p->next=attribute; 01412 return(MagickTrue); 01413 } 01414 01415 /* 01416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01417 % % 01418 % % 01419 % % 01420 % T r a c e P S C l i p p a t h % 01421 % % 01422 % % 01423 % % 01424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01425 % 01426 % TracePSClipPath() traces a clip path and returns it as Postscript. 01427 % 01428 % The format of the TracePSClipPath method is: 01429 % 01430 % char *TracePSClipPath(unsigned char *blob,size_t length, 01431 % const unsigned long columns,const unsigned long rows) 01432 % 01433 % A description of each parameter follows: 01434 % 01435 % o blob: The blob. 01436 % 01437 % o length: The length of the blob. 01438 % 01439 % o columns: The image width. 01440 % 01441 % o rows: The image height. 01442 % 01443 % 01444 */ 01445 static char *TracePSClippath(unsigned char *blob,size_t length, 01446 const unsigned long magick_unused(columns), 01447 const unsigned long magick_unused(rows)) 01448 { 01449 char 01450 *path, 01451 *message; 01452 01453 long 01454