1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % M M EEEEE TTTTT AAA % 7 % MM MM E T A A % 8 % M M M EEE T AAAAA % 9 % M M E T A A % 10 % M M EEEEE T A A % 11 % % 12 % % 13 % Read/Write Embedded Image Profiles. % 14 % % 15 % Software Design % 16 % William Radcliffe % 17 % July 2001 % 18 % % 19 % % 20 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % http://www.imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % 37 */ 38 39 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/blob.h" 45 #include "MagickCore/blob-private.h" 46 #include "MagickCore/channel.h" 47 #include "MagickCore/exception.h" 48 #include "MagickCore/exception-private.h" 49 #include "MagickCore/image.h" 50 #include "MagickCore/image-private.h" 51 #include "MagickCore/list.h" 52 #include "MagickCore/magick.h" 53 #include "MagickCore/memory_.h" 54 #include "MagickCore/module.h" 55 #include "MagickCore/profile.h" 56 #include "MagickCore/splay-tree.h" 57 #include "MagickCore/quantum-private.h" 58 #include "MagickCore/static.h" 59 #include "MagickCore/string_.h" 60 #include "MagickCore/string-private.h" 61 #include "MagickCore/token.h" 62 #include "MagickCore/utility.h" 63 64 /* 66 Forward declarations. 67 */ 68 static MagickBooleanType 69 WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *); 70 71 /* 73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 74 % % 75 % % 76 % % 77 % I s M E T A % 78 % % 79 % % 80 % % 81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 82 % 83 % IsMETA() returns MagickTrue if the image format type, identified by the 84 % magick string, is META. 85 % 86 % The format of the IsMETA method is: 87 % 88 % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length) 89 % 90 % A description of each parameter follows: 91 % 92 % o magick: compare image format pattern against these bytes. 93 % 94 % o length: Specifies the length of the magick string. 95 % 96 % 97 */ 98 #ifdef IMPLEMENT_IS_FUNCTION 99 static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length) 100 { 101 if (length < 4) 102 return(MagickFalse); 103 if (LocaleNCompare((char *) magick,"8BIM",4) == 0) 104 return(MagickTrue); 105 if (LocaleNCompare((char *) magick,"APP1",4) == 0) 106 return(MagickTrue); 107 if (LocaleNCompare((char *) magick,"\034\002",2) == 0) 108 return(MagickTrue); 109 return(MagickFalse); 110 } 111 #endif 112 113 /* 115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 116 % % 117 % % 118 % % 119 % R e a d M E T A I m a g e % 120 % % 121 % % 122 % % 123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 124 % 125 % ReadMETAImage() reads a META image file and returns it. It 126 % allocates the memory necessary for the new Image structure and returns a 127 % pointer to the new image. 128 % 129 % The format of the ReadMETAImage method is: 130 % 131 % Image *ReadMETAImage(const ImageInfo *image_info, 132 % ExceptionInfo *exception) 133 % 134 % Decompression code contributed by Kyle Shorter. 135 % 136 % A description of each parameter follows: 137 % 138 % o image: Method ReadMETAImage returns a pointer to the image after 139 % reading. A null image is returned if there is a memory shortage or 140 % if the image cannot be read. 141 % 142 % o image_info: Specifies a pointer to an ImageInfo structure. 143 % 144 % o exception: return any errors or warnings in this structure. 145 % 146 */ 147 148 typedef struct _html_code 149 { 150 const short int 151 len; 152 153 const char 154 *code, 155 val; 156 } html_code; 157 158 static const html_code html_codes[] = { 159 #ifdef HANDLE_GT_LT 160 { 4,"<",'<' }, 161 { 4,">",'>' }, 162 #endif 163 { 5,"&",'&' }, 164 { 6,""",'"' }, 165 { 6,"'",'\''} 166 }; 167 168 static int stringnicmp(const char *p,const char *q,size_t n) 169 { 170 register ssize_t 171 i, 172 j; 173 174 if (p == q) 175 return(0); 176 if (p == (char *) NULL) 177 return(-1); 178 if (q == (char *) NULL) 179 return(1); 180 while ((*p != '\0') && (*q != '\0')) 181 { 182 if ((*p == '\0') || (*q == '\0')) 183 break; 184 i=(*p); 185 if (islower(i)) 186 i=toupper(i); 187 j=(*q); 188 if (islower(j)) 189 j=toupper(j); 190 if (i != j) 191 break; 192 n--; 193 if (n == 0) 194 break; 195 p++; 196 q++; 197 } 198 return(toupper((int) *p)-toupper((int) *q)); 199 } 200 201 static size_t convertHTMLcodes(char *s, const size_t len) 202 { 203 int 204 value; 205 206 if ((len == 0) || (s == (char*) NULL) || (*s=='\0')) 207 return(0); 208 if ((len > 3) && (s[1] == '#') && (strchr(s,';') != (char *) NULL) && 209 (sscanf(s,"&#%d;",&value) == 1)) 210 { 211 size_t o = 3; 212 while (s[o] != ';') 213 { 214 o++; 215 if (o > 5) 216 break; 217 } 218 if (o < 6) 219 (void) memmove(s+1,s+1+o,strlen(s+1+o)+1); 220 *s=value; 221 return(o); 222 } 223 else 224 { 225 int 226 i, 227 codes; 228 229 codes=sizeof(html_codes)/sizeof(html_code); 230 for (i=0; i < codes; i++) 231 { 232 if (html_codes[i].len <= (ssize_t) len) 233 if (stringnicmp(s, html_codes[i].code,(size_t) (html_codes[i].len)) == 0) 234 { 235 (void) memmove(s+1,s+html_codes[i].len, 236 strlen(s+html_codes[i].len)+1); 237 *s=html_codes[i].val; 238 return(html_codes[i].len-1); 239 } 240 } 241 } 242 return(0); 243 } 244 245 static char *super_fgets(char **b, int *blen, Image *file) 246 { 247 int 248 c, 249 len; 250 251 unsigned char 252 *p, 253 *q; 254 255 len=*blen; 256 p=(unsigned char *) (*b); 257 for (q=p; ; q++) 258 { 259 c=ReadBlobByte(file); 260 if (c == EOF || c == '\n') 261 break; 262 if ((q-p+1) >= (int) len) 263 { 264 int 265 tlen; 266 267 tlen=q-p; 268 len<<=1; 269 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) len+2UL,sizeof(*p)); 270 *b=(char *) p; 271 if (p == (unsigned char *) NULL) 272 break; 273 q=p+tlen; 274 } 275 *q=(unsigned char) c; 276 } 277 *blen=0; 278 if (p != (unsigned char *) NULL) 279 { 280 int 281 tlen; 282 283 tlen=q-p; 284 if (tlen == 0) 285 return (char *) NULL; 286 p[tlen] = '\0'; 287 *blen=++tlen; 288 } 289 return((char *) p); 290 } 291 292 #define IPTC_ID 1028 293 #define THUMBNAIL_ID 1033 294 295 static ssize_t parse8BIM(Image *ifile, Image *ofile) 296 { 297 char 298 brkused, 299 quoted, 300 *line, 301 *token, 302 *newstr, 303 *name; 304 305 int 306 state, 307 next; 308 309 unsigned char 310 dataset; 311 312 unsigned int 313 recnum; 314 315 int 316 inputlen = MagickPathExtent; 317 318 MagickOffsetType 319 savedpos, 320 currentpos; 321 322 ssize_t 323 savedolen = 0L, 324 outputlen = 0L; 325 326 TokenInfo 327 *token_info; 328 329 dataset = 0; 330 recnum = 0; 331 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line)); 332 if (line == (char *) NULL) 333 return(-1); 334 newstr = name = token = (char *) NULL; 335 savedpos = 0; 336 token_info=AcquireTokenInfo(); 337 while (super_fgets(&line,&inputlen,ifile)!=NULL) 338 { 339 state=0; 340 next=0; 341 342 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token)); 343 if (token == (char *) NULL) 344 break; 345 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr)); 346 if (newstr == (char *) NULL) 347 break; 348 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0, 349 &brkused,&next,"ed)==0) 350 { 351 if (state == 0) 352 { 353 int 354 state, 355 next; 356 357 char 358 brkused, 359 quoted; 360 361 state=0; 362 next=0; 363 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#", 364 "", 0,&brkused,&next,"ed)==0) 365 { 366 switch (state) 367 { 368 case 0: 369 if (strcmp(newstr,"8BIM")==0) 370 dataset = 255; 371 else 372 dataset = (unsigned char) StringToLong(newstr); 373 break; 374 case 1: 375 recnum = (unsigned int) StringToUnsignedLong(newstr); 376 break; 377 case 2: 378 name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent, 379 sizeof(*name)); 380 if (name) 381 (void) strcpy(name,newstr); 382 break; 383 } 384 state++; 385 } 386 } 387 else 388 if (state == 1) 389 { 390 int 391 next; 392 393 ssize_t 394 len; 395 396 char 397 brkused, 398 quoted; 399 400 next=0; 401 len = (ssize_t) strlen(token); 402 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&", 403 "",0,&brkused,&next,"ed)==0) 404 { 405 if (brkused && next > 0) 406 { 407 char 408 *s = &token[next-1]; 409 410 len -= (ssize_t) convertHTMLcodes(s,strlen(s)); 411 } 412 } 413 414 if (dataset == 255) 415 { 416 unsigned char 417 nlen = 0; 418 419 int 420 i; 421 422 if (savedolen > 0) 423 { 424 MagickOffsetType 425 offset; 426 427 ssize_t diff = outputlen - savedolen; 428 currentpos = TellBlob(ofile); 429 if (currentpos < 0) 430 return(-1); 431 offset=SeekBlob(ofile,savedpos,SEEK_SET); 432 if (offset < 0) 433 return(-1); 434 (void) WriteBlobMSBLong(ofile,(unsigned int) diff); 435 offset=SeekBlob(ofile,currentpos,SEEK_SET); 436 if (offset < 0) 437 return(-1); 438 savedolen = 0L; 439 } 440 if (outputlen & 1) 441 { 442 (void) WriteBlobByte(ofile,0x00); 443 outputlen++; 444 } 445 (void) WriteBlobString(ofile,"8BIM"); 446 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum); 447 outputlen += 6; 448 if (name) 449 nlen = (unsigned char) strlen(name); 450 (void) WriteBlobByte(ofile,nlen); 451 outputlen++; 452 for (i=0; i<nlen; i++) 453 (void) WriteBlobByte(ofile,(unsigned char) name[i]); 454 outputlen += nlen; 455 if ((nlen & 0x01) == 0) 456 { 457 (void) WriteBlobByte(ofile,0x00); 458 outputlen++; 459 } 460 if (recnum != IPTC_ID) 461 { 462 (void) WriteBlobMSBLong(ofile, (unsigned int) len); 463 outputlen += 4; 464 465 next=0; 466 outputlen += len; 467 while (len-- > 0) 468 (void) WriteBlobByte(ofile,(unsigned char) token[next++]); 469 470 if (outputlen & 1) 471 { 472 (void) WriteBlobByte(ofile,0x00); 473 outputlen++; 474 } 475 } 476 else 477 { 478 /* patch in a fake length for now and fix it later */ 479 savedpos = TellBlob(ofile); 480 if (savedpos < 0) 481 return(-1); 482 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU); 483 outputlen += 4; 484 savedolen = outputlen; 485 } 486 } 487 else 488 { 489 if (len <= 0x7FFF) 490 { 491 (void) WriteBlobByte(ofile,0x1c); 492 (void) WriteBlobByte(ofile,(unsigned char) dataset); 493 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff)); 494 (void) WriteBlobMSBShort(ofile,(unsigned short) len); 495 outputlen += 5; 496 next=0; 497 outputlen += len; 498 while (len-- > 0) 499 (void) WriteBlobByte(ofile,(unsigned char) token[next++]); 500 } 501 } 502 } 503 state++; 504 } 505 if (token != (char *) NULL) 506 token=DestroyString(token); 507 if (newstr != (char *) NULL) 508 newstr=DestroyString(newstr); 509 if (name != (char *) NULL) 510 name=DestroyString(name); 511 } 512 token_info=DestroyTokenInfo(token_info); 513 if (token != (char *) NULL) 514 token=DestroyString(token); 515 if (newstr != (char *) NULL) 516 newstr=DestroyString(newstr); 517 if (name != (char *) NULL) 518 name=DestroyString(name); 519 line=DestroyString(line); 520 if (savedolen > 0) 521 { 522 MagickOffsetType 523 offset; 524 525 ssize_t diff = outputlen - savedolen; 526 527 currentpos = TellBlob(ofile); 528 if (currentpos < 0) 529 return(-1); 530 offset=SeekBlob(ofile,savedpos,SEEK_SET); 531 if (offset < 0) 532 return(-1); 533 (void) WriteBlobMSBLong(ofile,(unsigned int) diff); 534 offset=SeekBlob(ofile,currentpos,SEEK_SET); 535 if (offset < 0) 536 return(-1); 537 savedolen = 0L; 538 } 539 return outputlen; 540 } 541 542 static char *super_fgets_w(char **b, int *blen, Image *file) 543 { 544 int 545 c, 546 len; 547 548 unsigned char 549 *p, 550 *q; 551 552 len=*blen; 553 p=(unsigned char *) (*b); 554 for (q=p; ; q++) 555 { 556 c=ReadBlobLSBSignedShort(file); 557 if ((c == -1) || (c == '\n')) 558 break; 559 if (EOFBlob(file)) 560 break; 561 if ((q-p+1) >= (int) len) 562 { 563 int 564 tlen; 565 566 tlen=q-p; 567 len<<=1; 568 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p)); 569 *b=(char *) p; 570 if (p == (unsigned char *) NULL) 571 break; 572 q=p+tlen; 573 } 574 *q=(unsigned char) c; 575 } 576 *blen=0; 577 if ((*b) != (char *) NULL) 578 { 579 int 580 tlen; 581 582 tlen=q-p; 583 if (tlen == 0) 584 return (char *) NULL; 585 p[tlen] = '\0'; 586 *blen=++tlen; 587 } 588 return((char *) p); 589 } 590 591 static ssize_t parse8BIMW(Image *ifile, Image *ofile) 592 { 593 char 594 brkused, 595 quoted, 596 *line, 597 *token, 598 *newstr, 599 *name; 600 601 int 602 state, 603 next; 604 605 unsigned char 606 dataset; 607 608 unsigned int 609 recnum; 610 611 int 612 inputlen = MagickPathExtent; 613 614 ssize_t 615 savedolen = 0L, 616 outputlen = 0L; 617 618 MagickOffsetType 619 savedpos, 620 currentpos; 621 622 TokenInfo 623 *token_info; 624 625 dataset = 0; 626 recnum = 0; 627 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line)); 628 if (line == (char *) NULL) 629 return(-1); 630 newstr = name = token = (char *) NULL; 631 savedpos = 0; 632 token_info=AcquireTokenInfo(); 633 while (super_fgets_w(&line,&inputlen,ifile) != NULL) 634 { 635 state=0; 636 next=0; 637 638 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token)); 639 if (token == (char *) NULL) 640 break; 641 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr)); 642 if (newstr == (char *) NULL) 643 break; 644 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0, 645 &brkused,&next,"ed)==0) 646 { 647 if (state == 0) 648 { 649 int 650 state, 651 next; 652 653 char 654 brkused, 655 quoted; 656 657 state=0; 658 next=0; 659 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#", 660 "",0,&brkused,&next,"ed)==0) 661 { 662 switch (state) 663 { 664 case 0: 665 if (strcmp(newstr,"8BIM")==0) 666 dataset = 255; 667 else 668 dataset = (unsigned char) StringToLong(newstr); 669 break; 670 case 1: 671 recnum=(unsigned int) StringToUnsignedLong(newstr); 672 break; 673 case 2: 674 name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent, 675 sizeof(*name)); 676 if (name) 677 (void) CopyMagickString(name,newstr,strlen(newstr)+MagickPathExtent); 678 break; 679 } 680 state++; 681 } 682 } 683 else 684 if (state == 1) 685 { 686 int 687 next; 688 689 ssize_t 690 len; 691 692 char 693 brkused, 694 quoted; 695 696 next=0; 697 len = (ssize_t) strlen(token); 698 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&", 699 "",0,&brkused,&next,"ed)==0) 700 { 701 if (brkused && next > 0) 702 { 703 char 704 *s = &token[next-1]; 705 706 len -= (ssize_t) convertHTMLcodes(s,strlen(s)); 707 } 708 } 709 710 if (dataset == 255) 711 { 712 unsigned char 713 nlen = 0; 714 715 int 716 i; 717 718 if (savedolen > 0) 719 { 720 MagickOffsetType 721 offset; 722 723 ssize_t diff = outputlen - savedolen; 724 currentpos = TellBlob(ofile); 725 if (currentpos < 0) 726 return(-1); 727 offset=SeekBlob(ofile,savedpos,SEEK_SET); 728 if (offset < 0) 729 return(-1); 730 (void) WriteBlobMSBLong(ofile,(unsigned int) diff); 731 offset=SeekBlob(ofile,currentpos,SEEK_SET); 732 if (offset < 0) 733 return(-1); 734 savedolen = 0L; 735 } 736 if (outputlen & 1) 737 { 738 (void) WriteBlobByte(ofile,0x00); 739 outputlen++; 740 } 741 (void) WriteBlobString(ofile,"8BIM"); 742 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum); 743 outputlen += 6; 744 if (name) 745 nlen = (unsigned char) strlen(name); 746 (void) WriteBlobByte(ofile,(unsigned char) nlen); 747 outputlen++; 748 for (i=0; i<nlen; i++) 749 (void) WriteBlobByte(ofile,(unsigned char) name[i]); 750 outputlen += nlen; 751 if ((nlen & 0x01) == 0) 752 { 753 (void) WriteBlobByte(ofile,0x00); 754 outputlen++; 755 } 756 if (recnum != IPTC_ID) 757 { 758 (void) WriteBlobMSBLong(ofile,(unsigned int) len); 759 outputlen += 4; 760 761 next=0; 762 outputlen += len; 763 while (len--) 764 (void) WriteBlobByte(ofile,(unsigned char) token[next++]); 765 766 if (outputlen & 1) 767 { 768 (void) WriteBlobByte(ofile,0x00); 769 outputlen++; 770 } 771 } 772 else 773 { 774 /* patch in a fake length for now and fix it later */ 775 savedpos = TellBlob(ofile); 776 if (savedpos < 0) 777 return(-1); 778 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU); 779 outputlen += 4; 780 savedolen = outputlen; 781 } 782 } 783 else 784 { 785 if (len <= 0x7FFF) 786 { 787 (void) WriteBlobByte(ofile,0x1c); 788 (void) WriteBlobByte(ofile,dataset); 789 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff)); 790 (void) WriteBlobMSBShort(ofile,(unsigned short) len); 791 outputlen += 5; 792 next=0; 793 outputlen += len; 794 while (len--) 795 (void) WriteBlobByte(ofile,(unsigned char) token[next++]); 796 } 797 } 798 } 799 state++; 800 } 801 if (token != (char *) NULL) 802 token=DestroyString(token); 803 if (newstr != (char *) NULL) 804 newstr=DestroyString(newstr); 805 if (name != (char *) NULL) 806 name=DestroyString(name); 807 } 808 token_info=DestroyTokenInfo(token_info); 809 if (token != (char *) NULL) 810 token=DestroyString(token); 811 if (newstr != (char *) NULL) 812 newstr=DestroyString(newstr); 813 if (name != (char *) NULL) 814 name=DestroyString(name); 815 line=DestroyString(line); 816 if (savedolen > 0) 817 { 818 MagickOffsetType 819 offset; 820 821 ssize_t diff = outputlen - savedolen; 822 823 currentpos = TellBlob(ofile); 824 if (currentpos < 0) 825 return(-1); 826 offset=SeekBlob(ofile,savedpos,SEEK_SET); 827 if (offset < 0) 828 return(-1); 829 (void) WriteBlobMSBLong(ofile,(unsigned int) diff); 830 offset=SeekBlob(ofile,currentpos,SEEK_SET); 831 if (offset < 0) 832 return(-1); 833 savedolen = 0L; 834 } 835 return(outputlen); 836 } 837 838 /* some defines for the different JPEG block types */ 839 #define M_SOF0 0xC0 /* Start Of Frame N */ 840 #define M_SOF1 0xC1 /* N indicates which compression process */ 841 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ 842 #define M_SOF3 0xC3 843 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ 844 #define M_SOF6 0xC6 845 #define M_SOF7 0xC7 846 #define M_SOF9 0xC9 847 #define M_SOF10 0xCA 848 #define M_SOF11 0xCB 849 #define M_SOF13 0xCD 850 #define M_SOF14 0xCE 851 #define M_SOF15 0xCF 852 #define M_SOI 0xD8 853 #define M_EOI 0xD9 /* End Of Image (end of datastream) */ 854 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ 855 #define M_APP0 0xe0 856 #define M_APP1 0xe1 857 #define M_APP2 0xe2 858 #define M_APP3 0xe3 859 #define M_APP4 0xe4 860 #define M_APP5 0xe5 861 #define M_APP6 0xe6 862 #define M_APP7 0xe7 863 #define M_APP8 0xe8 864 #define M_APP9 0xe9 865 #define M_APP10 0xea 866 #define M_APP11 0xeb 867 #define M_APP12 0xec 868 #define M_APP13 0xed 869 #define M_APP14 0xee 870 #define M_APP15 0xef 871 872 static int jpeg_transfer_1(Image *ifile, Image *ofile) 873 { 874 int c; 875 876 c = ReadBlobByte(ifile); 877 if (c == EOF) 878 return EOF; 879 (void) WriteBlobByte(ofile,(unsigned char) c); 880 return c; 881 } 882 883 #if defined(future) 884 static int jpeg_skip_1(Image *ifile) 885 { 886 int c; 887 888 c = ReadBlobByte(ifile); 889 if (c == EOF) 890 return EOF; 891 return c; 892 } 893 #endif 894 895 static int jpeg_read_remaining(Image *ifile, Image *ofile) 896 { 897 int c; 898 899 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF) 900 continue; 901 return M_EOI; 902 } 903 904 static int jpeg_skip_variable(Image *ifile, Image *ofile) 905 { 906 unsigned int length; 907 int c1,c2; 908 909 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF) 910 return M_EOI; 911 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF) 912 return M_EOI; 913 914 length = (((unsigned char) c1) << 8) + ((unsigned char) c2); 915 length -= 2; 916 917 while (length--) 918 if (jpeg_transfer_1(ifile, ofile) == EOF) 919 return M_EOI; 920 921 return 0; 922 } 923 924 static int jpeg_skip_variable2(Image *ifile, Image *ofile) 925 { 926 unsigned int length; 927 int c1,c2; 928 929 (void) ofile; 930 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI; 931 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI; 932 933 length = (((unsigned char) c1) << 8) + ((unsigned char) c2); 934 length -= 2; 935 936 while (length--) 937 if (ReadBlobByte(ifile) == EOF) 938 return M_EOI; 939 940 return 0; 941 } 942 943 static int jpeg_nextmarker(Image *ifile, Image *ofile) 944 { 945 int c; 946 947 /* transfer anything until we hit 0xff */ 948 do 949 { 950 c = ReadBlobByte(ifile); 951 if (c == EOF) 952 return M_EOI; /* we hit EOF */ 953 else 954 if (c != 0xff) 955 (void) WriteBlobByte(ofile,(unsigned char) c); 956 } while (c != 0xff); 957 958 /* get marker byte, swallowing possible padding */ 959 do 960 { 961 c = ReadBlobByte(ifile); 962 if (c == EOF) 963 return M_EOI; /* we hit EOF */ 964 } while (c == 0xff); 965 966 return c; 967 } 968 969 #if defined(future) 970 static int jpeg_skip_till_marker(Image *ifile, int marker) 971 { 972 int c, i; 973 974 do 975 { 976 /* skip anything until we hit 0xff */ 977 i = 0; 978 do 979 { 980 c = ReadBlobByte(ifile); 981 i++; 982 if (c == EOF) 983 return M_EOI; /* we hit EOF */ 984 } while (c != 0xff); 985 986 /* get marker byte, swallowing possible padding */ 987 do 988 { 989 c = ReadBlobByte(ifile); 990 if (c == EOF) 991 return M_EOI; /* we hit EOF */ 992 } while (c == 0xff); 993 } while (c != marker); 994 return c; 995 } 996 #endif 997 998 /* Embed binary IPTC data into a JPEG image. */ 999 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc) 1000 { 1001 unsigned int marker; 1002 unsigned int done = 0; 1003 unsigned int len; 1004 int inx; 1005 1006 if (jpeg_transfer_1(ifile, ofile) != 0xFF) 1007 return 0; 1008 if (jpeg_transfer_1(ifile, ofile) != M_SOI) 1009 return 0; 1010 1011 while (done == MagickFalse) 1012 { 1013 marker=(unsigned int) jpeg_nextmarker(ifile, ofile); 1014 if (marker == M_EOI) 1015 { /* EOF */ 1016 break; 1017 } 1018 else 1019 { 1020 if (marker != M_APP13) 1021 { 1022 (void) WriteBlobByte(ofile,0xff); 1023 (void) WriteBlobByte(ofile,(unsigned char) marker); 1024 } 1025 } 1026 1027 switch (marker) 1028 { 1029 case M_APP13: 1030 /* we are going to write a new APP13 marker, so don't output the old one */ 1031 jpeg_skip_variable2(ifile, ofile); 1032 break; 1033 1034 case M_APP0: 1035 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */ 1036 jpeg_skip_variable(ifile, ofile); 1037 1038 if (iptc != (Image *) NULL) 1039 { 1040 char 1041 psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0"; 1042 1043 len=(unsigned int) GetBlobSize(iptc); 1044 if (len & 1) 1045 len++; /* make the length even */ 1046 psheader[2]=(char) ((len+16)>>8); 1047 psheader[3]=(char) ((len+16)&0xff); 1048 for (inx = 0; inx < 18; inx++) 1049 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]); 1050 jpeg_read_remaining(iptc, ofile); 1051 len=(unsigned int) GetBlobSize(iptc); 1052 if (len & 1) 1053 (void) WriteBlobByte(ofile,0); 1054 } 1055 break; 1056 1057 case M_SOS: 1058 /* we hit data, no more marker-inserting can be done! */ 1059 jpeg_read_remaining(ifile, ofile); 1060 done = 1; 1061 break; 1062 1063 default: 1064 jpeg_skip_variable(ifile, ofile); 1065 break; 1066 } 1067 } 1068 return 1; 1069 } 1070 1071 /* handle stripping the APP13 data out of a JPEG */ 1072 #if defined(future) 1073 static void jpeg_strip(Image *ifile, Image *ofile) 1074 { 1075 unsigned int marker; 1076 1077 marker = jpeg_skip_till_marker(ifile, M_SOI); 1078 if (marker == M_SOI) 1079 { 1080 (void) WriteBlobByte(ofile,0xff); 1081 (void) WriteBlobByte(ofile,M_SOI); 1082 jpeg_read_remaining(ifile, ofile); 1083 } 1084 } 1085 1086 /* Extract any APP13 binary data into a file. */ 1087 static int jpeg_extract(Image *ifile, Image *ofile) 1088 { 1089 unsigned int marker; 1090 unsigned int done = 0; 1091 1092 if (jpeg_skip_1(ifile) != 0xff) 1093 return 0; 1094 if (jpeg_skip_1(ifile) != M_SOI) 1095 return 0; 1096 1097 while (done == MagickFalse) 1098 { 1099 marker = jpeg_skip_till_marker(ifile, M_APP13); 1100 if (marker == M_APP13) 1101 { 1102 marker = jpeg_nextmarker(ifile, ofile); 1103 break; 1104 } 1105 } 1106 return 1; 1107 } 1108 #endif 1109 1110 static inline void CopyBlob(Image *source,Image *destination) 1111 { 1112 ssize_t 1113 i; 1114 1115 unsigned char 1116 *buffer; 1117 1118 ssize_t 1119 count, 1120 length; 1121 1122 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, 1123 sizeof(*buffer)); 1124 if (buffer != (unsigned char *) NULL) 1125 { 1126 i=0; 1127 while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0) 1128 { 1129 count=0; 1130 for (i=0; i < (ssize_t) length; i+=count) 1131 { 1132 count=WriteBlob(destination,(size_t) (length-i),buffer+i); 1133 if (count <= 0) 1134 break; 1135 } 1136 if (i < (ssize_t) length) 1137 break; 1138 } 1139 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 1140 } 1141 } 1142 1143 static Image *ReadMETAImage(const ImageInfo *image_info, 1144 ExceptionInfo *exception) 1145 { 1146 Image 1147 *buff, 1148 *image; 1149 1150 MagickBooleanType 1151 status; 1152 1153 StringInfo 1154 *profile; 1155 1156 size_t 1157 length; 1158 1159 void 1160 *blob; 1161 1162 /* 1163 Open file containing binary metadata 1164 */ 1165 assert(image_info != (const ImageInfo *) NULL); 1166 assert(image_info->signature == MagickCoreSignature); 1167 if (image_info->debug != MagickFalse) 1168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 1169 image_info->filename); 1170 assert(exception != (ExceptionInfo *) NULL); 1171 assert(exception->signature == MagickCoreSignature); 1172 image=AcquireImage(image_info,exception); 1173 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 1174 if (status == MagickFalse) 1175 { 1176 image=DestroyImageList(image); 1177 return((Image *) NULL); 1178 } 1179 image->columns=1; 1180 image->rows=1; 1181 if (SetImageBackgroundColor(image,exception) == MagickFalse) 1182 { 1183 image=DestroyImageList(image); 1184 return((Image *) NULL); 1185 } 1186 length=1; 1187 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0) 1188 { 1189 /* 1190 Read 8BIM binary metadata. 1191 */ 1192 buff=AcquireImage((ImageInfo *) NULL,exception); 1193 if (buff == (Image *) NULL) 1194 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1195 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); 1196 if (blob == (unsigned char *) NULL) 1197 { 1198 buff=DestroyImage(buff); 1199 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1200 } 1201 AttachBlob(buff->blob,blob,length); 1202 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0) 1203 { 1204 length=(size_t) parse8BIM(image, buff); 1205 if (length & 1) 1206 (void) WriteBlobByte(buff,0x0); 1207 } 1208 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0) 1209 { 1210 length=(size_t) parse8BIMW(image, buff); 1211 if (length & 1) 1212 (void) WriteBlobByte(buff,0x0); 1213 } 1214 else 1215 CopyBlob(image,buff); 1216 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t) 1217 GetBlobSize(buff)); 1218 if (profile == (StringInfo *) NULL) 1219 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1220 status=SetImageProfile(image,"8bim",profile,exception); 1221 profile=DestroyStringInfo(profile); 1222 if (status == MagickFalse) 1223 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1224 blob=DetachBlob(buff->blob); 1225 blob=(unsigned char *) RelinquishMagickMemory(blob); 1226 buff=DestroyImage(buff); 1227 } 1228 if (LocaleNCompare(image_info->magick,"APP1",4) == 0) 1229 { 1230 char 1231 name[MagickPathExtent]; 1232 1233 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",1); 1234 buff=AcquireImage((ImageInfo *) NULL,exception); 1235 if (buff == (Image *) NULL) 1236 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1237 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); 1238 if (blob == (unsigned char *) NULL) 1239 { 1240 buff=DestroyImage(buff); 1241 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1242 } 1243 AttachBlob(buff->blob,blob,length); 1244 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0) 1245 { 1246 Image 1247 *iptc; 1248 1249 int 1250 result; 1251 1252 if (image_info->profile == (void *) NULL) 1253 { 1254 blob=DetachBlob(buff->blob); 1255 blob=RelinquishMagickMemory(blob); 1256 buff=DestroyImage(buff); 1257 ThrowReaderException(CoderError,"NoIPTCProfileAvailable"); 1258 } 1259 profile=CloneStringInfo((StringInfo *) image_info->profile); 1260 iptc=AcquireImage((ImageInfo *) NULL,exception); 1261 if (iptc == (Image *) NULL) 1262 { 1263 blob=DetachBlob(buff->blob); 1264 blob=RelinquishMagickMemory(blob); 1265 buff=DestroyImage(buff); 1266 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1267 } 1268 AttachBlob(iptc->blob,GetStringInfoDatum(profile), 1269 GetStringInfoLength(profile)); 1270 result=jpeg_embed(image,buff,iptc); 1271 blob=DetachBlob(iptc->blob); 1272 blob=RelinquishMagickMemory(blob); 1273 iptc=DestroyImage(iptc); 1274 if (result == 0) 1275 { 1276 blob=DetachBlob(buff->blob); 1277 blob=RelinquishMagickMemory(blob); 1278 buff=DestroyImage(buff); 1279 ThrowReaderException(CoderError,"JPEGEmbeddingFailed"); 1280 } 1281 } 1282 else 1283 CopyBlob(image,buff); 1284 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t) 1285 GetBlobSize(buff)); 1286 if (profile == (StringInfo *) NULL) 1287 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1288 status=SetImageProfile(image,name,profile,exception); 1289 profile=DestroyStringInfo(profile); 1290 if (status == MagickFalse) 1291 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1292 blob=DetachBlob(buff->blob); 1293 blob=RelinquishMagickMemory(blob); 1294 buff=DestroyImage(buff); 1295 } 1296 if ((LocaleCompare(image_info->magick,"ICC") == 0) || 1297 (LocaleCompare(image_info->magick,"ICM") == 0)) 1298 { 1299 buff=AcquireImage((ImageInfo *) NULL,exception); 1300 if (buff == (Image *) NULL) 1301 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1302 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); 1303 if (blob == (unsigned char *) NULL) 1304 { 1305 buff=DestroyImage(buff); 1306 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1307 } 1308 AttachBlob(buff->blob,blob,length); 1309 CopyBlob(image,buff); 1310 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t) 1311 GetBlobSize(buff)); 1312 if (profile == (StringInfo *) NULL) 1313 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1314 (void) SetImageProfile(image,"icc",profile,exception); 1315 profile=DestroyStringInfo(profile); 1316 blob=DetachBlob(buff->blob); 1317 blob=(unsigned char *) RelinquishMagickMemory(blob); 1318 buff=DestroyImage(buff); 1319 } 1320 if (LocaleCompare(image_info->magick,"IPTC") == 0) 1321 { 1322 buff=AcquireImage((ImageInfo *) NULL,exception); 1323 if (buff == (Image *) NULL) 1324 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1325 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); 1326 if (blob == (unsigned char *) NULL) 1327 { 1328 buff=DestroyImage(buff); 1329 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1330 } 1331 AttachBlob(buff->blob,blob,length); 1332 CopyBlob(image,buff); 1333 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t) 1334 GetBlobSize(buff)); 1335 if (profile == (StringInfo *) NULL) 1336 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1337 (void) SetImageProfile(image,"8bim",profile,exception); 1338 profile=DestroyStringInfo(profile); 1339 blob=DetachBlob(buff->blob); 1340 blob=(unsigned char *) RelinquishMagickMemory(blob); 1341 buff=DestroyImage(buff); 1342 } 1343 if (LocaleCompare(image_info->magick,"XMP") == 0) 1344 { 1345 buff=AcquireImage((ImageInfo *) NULL,exception); 1346 if (buff == (Image *) NULL) 1347 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1348 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); 1349 if (blob == (unsigned char *) NULL) 1350 { 1351 buff=DestroyImage(buff); 1352 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1353 } 1354 AttachBlob(buff->blob,blob,length); 1355 CopyBlob(image,buff); 1356 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t) 1357 GetBlobSize(buff)); 1358 if (profile == (StringInfo *) NULL) 1359 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1360 (void) SetImageProfile(image,"xmp",profile,exception); 1361 profile=DestroyStringInfo(profile); 1362 blob=DetachBlob(buff->blob); 1363 blob=(unsigned char *) RelinquishMagickMemory(blob); 1364 buff=DestroyImage(buff); 1365 } 1366 (void) CloseBlob(image); 1367 return(GetFirstImageInList(image)); 1368 } 1369 1370 /* 1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1373 % % 1374 % % 1375 % % 1376 % R e g i s t e r M E T A I m a g e % 1377 % % 1378 % % 1379 % % 1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1381 % 1382 % RegisterMETAImage() adds attributes for the META image format to 1383 % the list of supported formats. The attributes include the image format 1384 % tag, a method to read and/or write the format, whether the format 1385 % supports the saving of more than one frame to the same file or blob, 1386 % whether the format supports native in-memory I/O, and a brief 1387 % description of the format. 1388 % 1389 % The format of the RegisterMETAImage method is: 1390 % 1391 % size_t RegisterMETAImage(void) 1392 % 1393 */ 1394 ModuleExport size_t RegisterMETAImage(void) 1395 { 1396 MagickInfo 1397 *entry; 1398 1399 entry=AcquireMagickInfo("META","8BIM","Photoshop resource format"); 1400 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1401 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1402 entry->flags^=CoderAdjoinFlag; 1403 entry->flags|=CoderStealthFlag; 1404 entry->flags|=CoderSeekableStreamFlag; 1405 (void) RegisterMagickInfo(entry); 1406 entry=AcquireMagickInfo("META","8BIMTEXT","Photoshop resource text format"); 1407 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1408 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1409 entry->flags^=CoderAdjoinFlag; 1410 entry->flags|=CoderStealthFlag; 1411 entry->flags|=CoderSeekableStreamFlag; 1412 (void) RegisterMagickInfo(entry); 1413 entry=AcquireMagickInfo("META","8BIMWTEXT", 1414 "Photoshop resource wide text format"); 1415 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1416 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1417 entry->flags^=CoderAdjoinFlag; 1418 entry->flags|=CoderStealthFlag; 1419 entry->flags|=CoderSeekableStreamFlag; 1420 (void) RegisterMagickInfo(entry); 1421 entry=AcquireMagickInfo("META","APP1","Raw application information"); 1422 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1423 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1424 entry->flags^=CoderAdjoinFlag; 1425 entry->flags|=CoderStealthFlag; 1426 entry->flags|=CoderSeekableStreamFlag; 1427 (void) RegisterMagickInfo(entry); 1428 entry=AcquireMagickInfo("META","APP1JPEG","Raw JPEG binary data"); 1429 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1430 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1431 entry->flags^=CoderAdjoinFlag; 1432 entry->flags|=CoderStealthFlag; 1433 entry->flags|=CoderSeekableStreamFlag; 1434 (void) RegisterMagickInfo(entry); 1435 entry=AcquireMagickInfo("META","EXIF","Exif digital camera binary data"); 1436 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1437 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1438 entry->flags^=CoderAdjoinFlag; 1439 entry->flags|=CoderStealthFlag; 1440 entry->flags|=CoderSeekableStreamFlag; 1441 (void) RegisterMagickInfo(entry); 1442 entry=AcquireMagickInfo("META","XMP","Adobe XML metadata"); 1443 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1444 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1445 entry->flags^=CoderAdjoinFlag; 1446 entry->flags|=CoderStealthFlag; 1447 entry->flags|=CoderSeekableStreamFlag; 1448 (void) RegisterMagickInfo(entry); 1449 entry=AcquireMagickInfo("META","ICM","ICC Color Profile"); 1450 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1451 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1452 entry->flags^=CoderAdjoinFlag; 1453 entry->flags|=CoderStealthFlag; 1454 entry->flags|=CoderSeekableStreamFlag; 1455 (void) RegisterMagickInfo(entry); 1456 entry=AcquireMagickInfo("META","ICC","ICC Color Profile"); 1457 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1458 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1459 entry->flags^=CoderAdjoinFlag; 1460 entry->flags|=CoderStealthFlag; 1461 entry->flags|=CoderSeekableStreamFlag; 1462 (void) RegisterMagickInfo(entry); 1463 entry=AcquireMagickInfo("META","IPTC","IPTC Newsphoto"); 1464 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1465 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1466 entry->flags^=CoderAdjoinFlag; 1467 entry->flags|=CoderStealthFlag; 1468 entry->flags|=CoderSeekableStreamFlag; 1469 (void) RegisterMagickInfo(entry); 1470 entry=AcquireMagickInfo("META","IPTCTEXT","IPTC Newsphoto text format"); 1471 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1472 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1473 entry->flags^=CoderAdjoinFlag; 1474 entry->flags|=CoderStealthFlag; 1475 entry->flags|=CoderSeekableStreamFlag; 1476 (void) RegisterMagickInfo(entry); 1477 entry=AcquireMagickInfo("META","IPTCWTEXT","IPTC Newsphoto text format"); 1478 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1479 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1480 entry->flags^=CoderAdjoinFlag; 1481 entry->flags|=CoderStealthFlag; 1482 entry->flags|=CoderSeekableStreamFlag; 1483 (void) RegisterMagickInfo(entry); 1484 return(MagickImageCoderSignature); 1485 } 1486 1487 /* 1489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1490 % % 1491 % % 1492 % % 1493 % U n r e g i s t e r M E T A I m a g e % 1494 % % 1495 % % 1496 % % 1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1498 % 1499 % UnregisterMETAImage() removes format registrations made by the 1500 % META module from the list of supported formats. 1501 % 1502 % The format of the UnregisterMETAImage method is: 1503 % 1504 % UnregisterMETAImage(void) 1505 % 1506 */ 1507 ModuleExport void UnregisterMETAImage(void) 1508 { 1509 (void) UnregisterMagickInfo("8BIM"); 1510 (void) UnregisterMagickInfo("8BIMTEXT"); 1511 (void) UnregisterMagickInfo("8BIMWTEXT"); 1512 (void) UnregisterMagickInfo("EXIF"); 1513 (void) UnregisterMagickInfo("APP1"); 1514 (void) UnregisterMagickInfo("APP1JPEG"); 1515 (void) UnregisterMagickInfo("ICCTEXT"); 1516 (void) UnregisterMagickInfo("ICM"); 1517 (void) UnregisterMagickInfo("ICC"); 1518 (void) UnregisterMagickInfo("IPTC"); 1519 (void) UnregisterMagickInfo("IPTCTEXT"); 1520 (void) UnregisterMagickInfo("IPTCWTEXT"); 1521 (void) UnregisterMagickInfo("XMP"); 1522 } 1523 1524 /* 1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1527 % % 1528 % % 1529 % % 1530 % W r i t e M E T A I m a g e % 1531 % % 1532 % % 1533 % % 1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1535 % 1536 % WriteMETAImage() writes a META image to a file. 1537 % 1538 % The format of the WriteMETAImage method is: 1539 % 1540 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info, 1541 % Image *image,ExceptionInfo *exception) 1542 % 1543 % Compression code contributed by Kyle Shorter. 1544 % 1545 % A description of each parameter follows: 1546 % 1547 % o image_info: Specifies a pointer to an ImageInfo structure. 1548 % 1549 % o image: A pointer to a Image structure. 1550 % 1551 % o exception: return any errors or warnings in this structure. 1552 % 1553 */ 1554 1555 static size_t GetIPTCStream(unsigned char **info,size_t length) 1556 { 1557 int 1558 c; 1559 1560 register ssize_t 1561 i; 1562 1563 register unsigned char 1564 *p; 1565 1566 size_t 1567 extent, 1568 info_length; 1569 1570 unsigned int 1571 marker; 1572 1573 size_t 1574 tag_length; 1575 1576 p=(*info); 1577 extent=length; 1578 if ((*p == 0x1c) && (*(p+1) == 0x02)) 1579 return(length); 1580 /* 1581 Extract IPTC from 8BIM resource block. 1582 */ 1583 while (extent >= 12) 1584 { 1585 if (strncmp((const char *) p,"8BIM",4)) 1586 break; 1587 p+=4; 1588 extent-=4; 1589 marker=(unsigned int) (*p) << 8 | *(p+1); 1590 p+=2; 1591 extent-=2; 1592 c=*p++; 1593 extent--; 1594 c|=0x01; 1595 if ((size_t) c >= extent) 1596 break; 1597 p+=c; 1598 extent-=c; 1599 if (extent < 4) 1600 break; 1601 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) | 1602 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3)); 1603 p+=4; 1604 extent-=4; 1605 if (tag_length > extent) 1606 break; 1607 if (marker == IPTC_ID) 1608 { 1609 *info=p; 1610 return(tag_length); 1611 } 1612 if ((tag_length & 0x01) != 0) 1613 tag_length++; 1614 p+=tag_length; 1615 extent-=tag_length; 1616 } 1617 /* 1618 Find the beginning of the IPTC info. 1619 */ 1620 p=(*info); 1621 tag_length=0; 1622 iptc_find: 1623 info_length=0; 1624 marker=MagickFalse; 1625 while (length != 0) 1626 { 1627 c=(*p++); 1628 length--; 1629 if (length == 0) 1630 break; 1631 if (c == 0x1c) 1632 { 1633 p--; 1634 *info=p; /* let the caller know were it is */ 1635 break; 1636 } 1637 } 1638 /* 1639 Determine the length of the IPTC info. 1640 */ 1641 while (length != 0) 1642 { 1643 c=(*p++); 1644 length--; 1645 if (length == 0) 1646 break; 1647 if (c == 0x1c) 1648 marker=MagickTrue; 1649 else 1650 if (marker) 1651 break; 1652 else 1653 continue; 1654 info_length++; 1655 /* 1656 Found the 0x1c tag; skip the dataset and record number tags. 1657 */ 1658 c=(*p++); /* should be 2 */ 1659 length--; 1660 if (length == 0) 1661 break; 1662 if ((info_length == 1) && (c != 2)) 1663 goto iptc_find; 1664 info_length++; 1665 c=(*p++); /* should be 0 */ 1666 length--; 1667 if (length == 0) 1668 break; 1669 if ((info_length == 2) && (c != 0)) 1670 goto iptc_find; 1671 info_length++; 1672 /* 1673 Decode the length of the block that follows - ssize_t or short format. 1674 */ 1675 c=(*p++); 1676 length--; 1677 if (length == 0) 1678 break; 1679 info_length++; 1680 if ((c & 0x80) != 0) 1681 { 1682 /* 1683 Long format. 1684 */ 1685 tag_length=0; 1686 for (i=0; i < 4; i++) 1687 { 1688 tag_length<<=8; 1689 tag_length|=(*p++); 1690 length--; 1691 if (length == 0) 1692 break; 1693 info_length++; 1694 } 1695 } 1696 else 1697 { 1698 /* 1699 Short format. 1700 */ 1701 tag_length=((long) c) << 8; 1702 c=(*p++); 1703 length--; 1704 if (length == 0) 1705 break; 1706 info_length++; 1707 tag_length|=(long) c; 1708 } 1709 if (tag_length > (length+1)) 1710 break; 1711 p+=tag_length; 1712 length-=tag_length; 1713 if (length == 0) 1714 break; 1715 info_length+=tag_length; 1716 } 1717 return(info_length); 1718 } 1719 1720 static void formatString(Image *ofile, const char *s, int len) 1721 { 1722 char 1723 temp[MagickPathExtent]; 1724 1725 (void) WriteBlobByte(ofile,'"'); 1726 for (; len > 0; len--, s++) { 1727 int c = (*s) & 255; 1728 switch (c) { 1729 case '&': 1730 (void) WriteBlobString(ofile,"&"); 1731 break; 1732 #ifdef HANDLE_GT_LT 1733 case '<': 1734 (void) WriteBlobString(ofile,"<"); 1735 break; 1736 case '>': 1737 (void) WriteBlobString(ofile,">"); 1738 break; 1739 #endif 1740 case '"': 1741 (void) WriteBlobString(ofile,"""); 1742 break; 1743 default: 1744 if (isprint(c)) 1745 (void) WriteBlobByte(ofile,(unsigned char) *s); 1746 else 1747 { 1748 (void) FormatLocaleString(temp,MagickPathExtent,"&#%d;", c & 255); 1749 (void) WriteBlobString(ofile,temp); 1750 } 1751 break; 1752 } 1753 } 1754 #if defined(MAGICKCORE_WINDOWS_SUPPORT) 1755 (void) WriteBlobString(ofile,"\"\r\n"); 1756 #else 1757 #if defined(macintosh) 1758 (void) WriteBlobString(ofile,"\"\r"); 1759 #else 1760 (void) WriteBlobString(ofile,"\"\n"); 1761 #endif 1762 #endif 1763 } 1764 1765 typedef struct _tag_spec 1766 { 1767 const short 1768 id; 1769 1770 const char 1771 *name; 1772 } tag_spec; 1773 1774 static const tag_spec tags[] = { 1775 { 5, "Image Name" }, 1776 { 7, "Edit Status" }, 1777 { 10, "Priority" }, 1778 { 15, "Category" }, 1779 { 20, "Supplemental Category" }, 1780 { 22, "Fixture Identifier" }, 1781 { 25, "Keyword" }, 1782 { 30, "Release Date" }, 1783 { 35, "Release Time" }, 1784 { 40, "Special Instructions" }, 1785 { 45, "Reference Service" }, 1786 { 47, "Reference Date" }, 1787 { 50, "Reference Number" }, 1788 { 55, "Created Date" }, 1789 { 60, "Created Time" }, 1790 { 65, "Originating Program" }, 1791 { 70, "Program Version" }, 1792 { 75, "Object Cycle" }, 1793 { 80, "Byline" }, 1794 { 85, "Byline Title" }, 1795 { 90, "City" }, 1796 { 92, "Sub-Location" }, 1797 { 95, "Province State" }, 1798 { 100, "Country Code" }, 1799 { 101, "Country" }, 1800 { 103, "Original Transmission Reference" }, 1801 { 105, "Headline" }, 1802 { 110, "Credit" }, 1803 { 115, "Source" }, 1804 { 116, "Copyright String" }, 1805 { 120, "Caption" }, 1806 { 121, "Image Orientation" }, 1807 { 122, "Caption Writer" }, 1808 { 131, "Local Caption" }, 1809 { 200, "Custom Field 1" }, 1810 { 201, "Custom Field 2" }, 1811 { 202, "Custom Field 3" }, 1812 { 203, "Custom Field 4" }, 1813 { 204, "Custom Field 5" }, 1814 { 205, "Custom Field 6" }, 1815 { 206, "Custom Field 7" }, 1816 { 207, "Custom Field 8" }, 1817 { 208, "Custom Field 9" }, 1818 { 209, "Custom Field 10" }, 1819 { 210, "Custom Field 11" }, 1820 { 211, "Custom Field 12" }, 1821 { 212, "Custom Field 13" }, 1822 { 213, "Custom Field 14" }, 1823 { 214, "Custom Field 15" }, 1824 { 215, "Custom Field 16" }, 1825 { 216, "Custom Field 17" }, 1826 { 217, "Custom Field 18" }, 1827 { 218, "Custom Field 19" }, 1828 { 219, "Custom Field 20" } 1829 }; 1830 1831 static int formatIPTC(Image *ifile, Image *ofile) 1832 { 1833 char 1834 temp[MagickPathExtent]; 1835 1836 unsigned int 1837 foundiptc, 1838 tagsfound; 1839 1840 unsigned char 1841 recnum, 1842 dataset; 1843 1844 unsigned char 1845 *readable, 1846 *str; 1847 1848 ssize_t 1849 tagindx, 1850 taglen; 1851 1852 int 1853 i, 1854 tagcount = (int) (sizeof(tags) / sizeof(tag_spec)); 1855 1856 int 1857 c; 1858 1859 foundiptc = 0; /* found the IPTC-Header */ 1860 tagsfound = 0; /* number of tags found */ 1861 1862 c = ReadBlobByte(ifile); 1863 while (c != EOF) 1864 { 1865 if (c == 0x1c) 1866 foundiptc = 1; 1867 else 1868 { 1869 if (foundiptc) 1870 return(-1); 1871 else 1872 { 1873 c=0; 1874 continue; 1875 } 1876 } 1877 1878 /* we found the 0x1c tag and now grab the dataset and record number tags */ 1879 c = ReadBlobByte(ifile); 1880 if (c == EOF) return -1; 1881 dataset = (unsigned char) c; 1882 c = ReadBlobByte(ifile); 1883 if (c == EOF) return -1; 1884 recnum = (unsigned char) c; 1885 /* try to match this record to one of the ones in our named table */ 1886 for (i=0; i< tagcount; i++) 1887 { 1888 if (tags[i].id == (short) recnum) 1889 break; 1890 } 1891 if (i < tagcount) 1892 readable = (unsigned char *) tags[i].name; 1893 else 1894 readable = (unsigned char *) ""; 1895 /* 1896 We decode the length of the block that follows - ssize_t or short fmt. 1897 */ 1898 c=ReadBlobByte(ifile); 1899 if (c == EOF) return -1; 1900 if (c & (unsigned char) 0x80) 1901 return 0; 1902 else 1903 { 1904 int 1905 c0; 1906 1907 c0=ReadBlobByte(ifile); 1908 if (c0 == EOF) return -1; 1909 taglen = (c << 8) | c0; 1910 } 1911 if (taglen < 0) return -1; 1912 /* make a buffer to hold the tag datand snag it from the input stream */ 1913 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MagickPathExtent), 1914 sizeof(*str)); 1915 if (str == (unsigned char *) NULL) 1916 { 1917 printf("MemoryAllocationFailed"); 1918 return 0; 1919 } 1920 for (tagindx=0; tagindx<taglen; tagindx++) 1921 { 1922 c=ReadBlobByte(ifile); 1923 if (c == EOF) return -1; 1924 str[tagindx] = (unsigned char) c; 1925 } 1926 str[taglen] = 0; 1927 1928 /* now finish up by formatting this binary data into ASCII equivalent */ 1929 if (strlen((char *)readable) > 0) 1930 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=", 1931 (unsigned int) dataset, (unsigned int) recnum, readable); 1932 else 1933 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=", 1934 (unsigned int) dataset,(unsigned int) recnum); 1935 (void) WriteBlobString(ofile,temp); 1936 formatString( ofile, (char *)str, taglen ); 1937 str=(unsigned char *) RelinquishMagickMemory(str); 1938 1939 tagsfound++; 1940 1941 c=ReadBlobByte(ifile); 1942 } 1943 return((int) tagsfound); 1944 } 1945 1946 static int readWordFromBuffer(char **s, ssize_t *len) 1947 { 1948 unsigned char 1949 buffer[2]; 1950 1951 int 1952 i, 1953 c; 1954 1955 for (i=0; i<2; i++) 1956 { 1957 c = *(*s)++; (*len)--; 1958 if (*len < 0) return -1; 1959 buffer[i] = (unsigned char) c; 1960 } 1961 return (((int) buffer[ 0 ]) << 8) | 1962 (((int) buffer[ 1 ])); 1963 } 1964 1965 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len) 1966 { 1967 char 1968 temp[MagickPathExtent]; 1969 1970 unsigned int 1971 foundiptc, 1972 tagsfound; 1973 1974 unsigned char 1975 recnum, 1976 dataset; 1977 1978 unsigned char 1979 *readable, 1980 *str; 1981 1982 ssize_t 1983 tagindx, 1984 taglen; 1985 1986 int 1987 i, 1988 tagcount = (int) (sizeof(tags) / sizeof(tag_spec)); 1989 1990 int 1991 c; 1992 1993 foundiptc = 0; /* found the IPTC-Header */ 1994 tagsfound = 0; /* number of tags found */ 1995 1996 while (len > 0) 1997 { 1998 c = *s++; len--; 1999 if (c == 0x1c) 2000 foundiptc = 1; 2001 else 2002 { 2003 if (foundiptc) 2004 return -1; 2005 else 2006 continue; 2007 } 2008 /* 2009 We found the 0x1c tag and now grab the dataset and record number tags. 2010 */ 2011 c = *s++; len--; 2012 if (len < 0) return -1; 2013 dataset = (unsigned char) c; 2014 c = *s++; len--; 2015 if (len < 0) return -1; 2016 recnum = (unsigned char) c; 2017 /* try to match this record to one of the ones in our named table */ 2018 for (i=0; i< tagcount; i++) 2019 if (tags[i].id == (short) recnum) 2020 break; 2021 if (i < tagcount) 2022 readable=(unsigned char *) tags[i].name; 2023 else 2024 readable=(unsigned char *) ""; 2025 /* 2026 We decode the length of the block that follows - ssize_t or short fmt. 2027 */ 2028 c=(*s++); 2029 len--; 2030 if (len < 0) 2031 return(-1); 2032 if (c & (unsigned char) 0x80) 2033 return(0); 2034 else 2035 { 2036 s--; 2037 len++; 2038 taglen=readWordFromBuffer(&s, &len); 2039 } 2040 if (taglen < 0) 2041 return(-1); 2042 if (taglen > 65535) 2043 return(-1); 2044 /* make a buffer to hold the tag datand snag it from the input stream */ 2045 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MagickPathExtent), 2046 sizeof(*str)); 2047 if (str == (unsigned char *) NULL) 2048 { 2049 printf("MemoryAllocationFailed"); 2050 return 0; 2051 } 2052 for (tagindx=0; tagindx<taglen; tagindx++) 2053 { 2054 c = *s++; len--; 2055 if (len < 0) 2056 return(-1); 2057 str[tagindx]=(unsigned char) c; 2058 } 2059 str[taglen]=0; 2060 2061 /* now finish up by formatting this binary data into ASCII equivalent */ 2062 if (strlen((char *)readable) > 0) 2063 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=", 2064 (unsigned int) dataset,(unsigned int) recnum, readable); 2065 else 2066 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=", 2067 (unsigned int) dataset,(unsigned int) recnum); 2068 (void) WriteBlobString(ofile,temp); 2069 formatString( ofile, (char *)str, taglen ); 2070 str=(unsigned char *) RelinquishMagickMemory(str); 2071 2072 tagsfound++; 2073 } 2074 return ((int) tagsfound); 2075 } 2076 2077 static int format8BIM(Image *ifile, Image *ofile) 2078 { 2079 char 2080 temp[MagickPathExtent]; 2081 2082 unsigned int 2083 foundOSType; 2084 2085 int 2086 ID, 2087 resCount, 2088 i, 2089 c; 2090 2091 ssize_t 2092 count; 2093 2094 unsigned char 2095 *PString, 2096 *str; 2097 2098 resCount=0; 2099 foundOSType=0; /* found the OSType */ 2100 (void) foundOSType; 2101 c=ReadBlobByte(ifile); 2102 while (c != EOF) 2103 { 2104 if (c == '8') 2105 { 2106 unsigned char 2107 buffer[5]; 2108 2109 buffer[0]=(unsigned char) c; 2110 for (i=1; i<4; i++) 2111 { 2112 c=ReadBlobByte(ifile); 2113 if (c == EOF) 2114 return(-1); 2115 buffer[i] = (unsigned char) c; 2116 } 2117 buffer[4]=0; 2118 if (strcmp((const char *)buffer, "8BIM") == 0) 2119 foundOSType=1; 2120 else 2121 continue; 2122 } 2123 else 2124 { 2125 c=ReadBlobByte(ifile); 2126 continue; 2127 } 2128 /* 2129 We found the OSType (8BIM) and now grab the ID, PString, and Size fields. 2130 */ 2131 ID=ReadBlobMSBSignedShort(ifile); 2132 if (ID < 0) 2133 return(-1); 2134 { 2135 unsigned char 2136 plen; 2137 2138 c=ReadBlobByte(ifile); 2139 if (c == EOF) 2140 return(-1); 2141 plen = (unsigned char) c; 2142 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+ 2143 MagickPathExtent),sizeof(*PString)); 2144 if (PString == (unsigned char *) NULL) 2145 { 2146 printf("MemoryAllocationFailed"); 2147 return 0; 2148 } 2149 for (i=0; i<plen; i++) 2150 { 2151 c=ReadBlobByte(ifile); 2152 if (c == EOF) return -1; 2153 PString[i] = (unsigned char) c; 2154 } 2155 PString[ plen ] = 0; 2156 if ((plen & 0x01) == 0) 2157 { 2158 c=ReadBlobByte(ifile); 2159 if (c == EOF) 2160 return(-1); 2161 } 2162 } 2163 count=ReadBlobMSBSignedLong(ifile); 2164 if (count < 0) return -1; 2165 /* make a buffer to hold the datand snag it from the input stream */ 2166 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str)); 2167 if (str == (unsigned char *) NULL) 2168 { 2169 printf("MemoryAllocationFailed"); 2170 return 0; 2171 } 2172 for (i=0; i < (ssize_t) count; i++) 2173 { 2174 c=ReadBlobByte(ifile); 2175 if (c == EOF) 2176 return(-1); 2177 str[i]=(unsigned char) c; 2178 } 2179 2180 /* we currently skip thumbnails, since it does not make 2181 * any sense preserving them in a real world application 2182 */ 2183 if (ID != THUMBNAIL_ID) 2184 { 2185 /* now finish up by formatting this binary data into 2186 * ASCII equivalent 2187 */ 2188 if (strlen((const char *)PString) > 0) 2189 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d#%s=",ID, 2190 PString); 2191 else 2192 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d=",ID); 2193 (void) WriteBlobString(ofile,temp); 2194 if (ID == IPTC_ID) 2195 { 2196 formatString(ofile, "IPTC", 4); 2197 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count); 2198 } 2199 else 2200 formatString(ofile, (char *)str, (ssize_t) count); 2201 } 2202 str=(unsigned char *) RelinquishMagickMemory(str); 2203 PString=(unsigned char *) RelinquishMagickMemory(PString); 2204 resCount++; 2205 c=ReadBlobByte(ifile); 2206 } 2207 return resCount; 2208 } 2209 2210 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info, 2211 Image *image,ExceptionInfo *exception) 2212 { 2213 const StringInfo 2214 *profile; 2215 2216 MagickBooleanType 2217 status; 2218 2219 size_t 2220 length; 2221 2222 /* 2223 Open image file. 2224 */ 2225 assert(image_info != (const ImageInfo *) NULL); 2226 assert(image_info->signature == MagickCoreSignature); 2227 assert(image != (Image *) NULL); 2228 assert(image->signature == MagickCoreSignature); 2229 if (image->debug != MagickFalse) 2230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2231 length=0; 2232 if (LocaleCompare(image_info->magick,"8BIM") == 0) 2233 { 2234 /* 2235 Write 8BIM image. 2236 */ 2237 profile=GetImageProfile(image,"8bim"); 2238 if (profile == (StringInfo *) NULL) 2239 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2240 assert(exception != (ExceptionInfo *) NULL); 2241 assert(exception->signature == MagickCoreSignature); 2242 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2243 if (status == MagickFalse) 2244 return(status); 2245 (void) WriteBlob(image,GetStringInfoLength(profile), 2246 GetStringInfoDatum(profile)); 2247 (void) CloseBlob(image); 2248 return(MagickTrue); 2249 } 2250 if (LocaleCompare(image_info->magick,"iptc") == 0) 2251 { 2252 size_t 2253 length; 2254 2255 unsigned char 2256 *info; 2257 2258 profile=GetImageProfile(image,"iptc"); 2259 if (profile == (StringInfo *) NULL) 2260 profile=GetImageProfile(image,"8bim"); 2261 if (profile == (StringInfo *) NULL) 2262 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2263 assert(exception != (ExceptionInfo *) NULL); 2264 assert(exception->signature == MagickCoreSignature); 2265 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2266 info=GetStringInfoDatum(profile); 2267 length=GetStringInfoLength(profile); 2268 length=GetIPTCStream(&info,length); 2269 if (length == 0) 2270 ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); 2271 (void) WriteBlob(image,length,info); 2272 (void) CloseBlob(image); 2273 return(MagickTrue); 2274 } 2275 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0) 2276 { 2277 Image 2278 *buff; 2279 2280 profile=GetImageProfile(image,"8bim"); 2281 if (profile == (StringInfo *) NULL) 2282 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2283 assert(exception != (ExceptionInfo *) NULL); 2284 assert(exception->signature == MagickCoreSignature); 2285 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2286 if (status == MagickFalse) 2287 return(status); 2288 buff=AcquireImage((ImageInfo *) NULL,exception); 2289 if (buff == (Image *) NULL) 2290 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2291 AttachBlob(buff->blob,GetStringInfoDatum(profile), 2292 GetStringInfoLength(profile)); 2293 format8BIM(buff,image); 2294 (void) DetachBlob(buff->blob); 2295 buff=DestroyImage(buff); 2296 (void) CloseBlob(image); 2297 return(MagickTrue); 2298 } 2299 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0) 2300 return(MagickFalse); 2301 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0) 2302 { 2303 Image 2304 *buff; 2305 2306 unsigned char 2307 *info; 2308 2309 profile=GetImageProfile(image,"8bim"); 2310 if (profile == (StringInfo *) NULL) 2311 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2312 info=GetStringInfoDatum(profile); 2313 length=GetStringInfoLength(profile); 2314 length=GetIPTCStream(&info,length); 2315 if (length == 0) 2316 ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); 2317 assert(exception != (ExceptionInfo *) NULL); 2318 assert(exception->signature == MagickCoreSignature); 2319 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2320 if (status == MagickFalse) 2321 return(status); 2322 buff=AcquireImage((ImageInfo *) NULL,exception); 2323 if (buff == (Image *) NULL) 2324 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2325 AttachBlob(buff->blob,info,length); 2326 formatIPTC(buff,image); 2327 (void) DetachBlob(buff->blob); 2328 buff=DestroyImage(buff); 2329 (void) CloseBlob(image); 2330 return(MagickTrue); 2331 } 2332 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0) 2333 return(MagickFalse); 2334 if ((LocaleCompare(image_info->magick,"APP1") == 0) || 2335 (LocaleCompare(image_info->magick,"EXIF") == 0) || 2336 (LocaleCompare(image_info->magick,"XMP") == 0)) 2337 { 2338 /* 2339 (void) Write APP1 image. 2340 */ 2341 profile=GetImageProfile(image,image_info->magick); 2342 if (profile == (StringInfo *) NULL) 2343 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable"); 2344 assert(exception != (ExceptionInfo *) NULL); 2345 assert(exception->signature == MagickCoreSignature); 2346 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2347 if (status == MagickFalse) 2348 return(status); 2349 (void) WriteBlob(image,GetStringInfoLength(profile), 2350 GetStringInfoDatum(profile)); 2351 (void) CloseBlob(image); 2352 return(MagickTrue); 2353 } 2354 if ((LocaleCompare(image_info->magick,"ICC") == 0) || 2355 (LocaleCompare(image_info->magick,"ICM") == 0)) 2356 { 2357 /* 2358 Write ICM image. 2359 */ 2360 profile=GetImageProfile(image,"icc"); 2361 if (profile == (StringInfo *) NULL) 2362 ThrowWriterException(CoderError,"NoColorProfileIsAvailable"); 2363 assert(exception != (ExceptionInfo *) NULL); 2364 assert(exception->signature == MagickCoreSignature); 2365 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2366 if (status == MagickFalse) 2367 return(status); 2368 (void) WriteBlob(image,GetStringInfoLength(profile), 2369 GetStringInfoDatum(profile)); 2370 (void) CloseBlob(image); 2371 return(MagickTrue); 2372 } 2373 return(MagickFalse); 2374 } 2375