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