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