meta.c revision 524222d4afe8a310858650f263b23cc300d7d792
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-2011 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 MagickOffsetType 315 savedpos, 316 currentpos; 317 318 ssize_t 319 savedolen = 0L, 320 outputlen = 0L; 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\0"); 1311 (void) WriteBlobByte(buff,0xc6); 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 entry=SetMagickInfo("8BIMTEXT"); 1415 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1416 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1417 entry->adjoin=MagickFalse; 1418 entry->stealth=MagickTrue; 1419 entry->seekable_stream=MagickTrue; 1420 entry->description=ConstantString("Photoshop resource text format"); 1421 entry->module=ConstantString("META"); 1422 (void) RegisterMagickInfo(entry); 1423 entry=SetMagickInfo("8BIMWTEXT"); 1424 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1425 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1426 entry->adjoin=MagickFalse; 1427 entry->stealth=MagickTrue; 1428 entry->seekable_stream=MagickTrue; 1429 entry->description=ConstantString("Photoshop resource wide text format"); 1430 entry->module=ConstantString("META"); 1431 (void) RegisterMagickInfo(entry); 1432 entry=SetMagickInfo("APP1"); 1433 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1434 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1435 entry->adjoin=MagickFalse; 1436 entry->stealth=MagickTrue; 1437 entry->seekable_stream=MagickTrue; 1438 entry->description=ConstantString("Raw application information"); 1439 entry->module=ConstantString("META"); 1440 (void) RegisterMagickInfo(entry); 1441 entry=SetMagickInfo("APP1JPEG"); 1442 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1443 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1444 entry->adjoin=MagickFalse; 1445 entry->stealth=MagickTrue; 1446 entry->seekable_stream=MagickTrue; 1447 entry->description=ConstantString("Raw JPEG binary data"); 1448 entry->module=ConstantString("META"); 1449 (void) RegisterMagickInfo(entry); 1450 entry=SetMagickInfo("EXIF"); 1451 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1452 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1453 entry->adjoin=MagickFalse; 1454 entry->stealth=MagickTrue; 1455 entry->seekable_stream=MagickTrue; 1456 entry->description=ConstantString("Exif digital camera binary data"); 1457 entry->module=ConstantString("META"); 1458 (void) RegisterMagickInfo(entry); 1459 entry=SetMagickInfo("XMP"); 1460 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1461 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1462 entry->adjoin=MagickFalse; 1463 entry->stealth=MagickTrue; 1464 entry->seekable_stream=MagickTrue; 1465 entry->description=ConstantString("Adobe XML metadata"); 1466 entry->module=ConstantString("META"); 1467 (void) RegisterMagickInfo(entry); 1468 entry=SetMagickInfo("ICM"); 1469 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1470 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1471 entry->adjoin=MagickFalse; 1472 entry->stealth=MagickTrue; 1473 entry->seekable_stream=MagickTrue; 1474 entry->description=ConstantString("ICC Color Profile"); 1475 entry->module=ConstantString("META"); 1476 (void) RegisterMagickInfo(entry); 1477 entry=SetMagickInfo("ICC"); 1478 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1479 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1480 entry->adjoin=MagickFalse; 1481 entry->stealth=MagickTrue; 1482 entry->seekable_stream=MagickTrue; 1483 entry->description=ConstantString("ICC Color Profile"); 1484 entry->module=ConstantString("META"); 1485 (void) RegisterMagickInfo(entry); 1486 entry=SetMagickInfo("IPTC"); 1487 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1488 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1489 entry->adjoin=MagickFalse; 1490 entry->stealth=MagickTrue; 1491 entry->seekable_stream=MagickTrue; 1492 entry->description=ConstantString("IPTC Newsphoto"); 1493 entry->module=ConstantString("META"); 1494 (void) RegisterMagickInfo(entry); 1495 entry=SetMagickInfo("IPTCTEXT"); 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 text format"); 1502 entry->module=ConstantString("META"); 1503 (void) RegisterMagickInfo(entry); 1504 entry=SetMagickInfo("IPTCWTEXT"); 1505 entry->decoder=(DecodeImageHandler *) ReadMETAImage; 1506 entry->encoder=(EncodeImageHandler *) WriteMETAImage; 1507 entry->adjoin=MagickFalse; 1508 entry->stealth=MagickTrue; 1509 entry->seekable_stream=MagickTrue; 1510 entry->description=ConstantString("IPTC Newsphoto text format"); 1511 entry->module=ConstantString("META"); 1512 (void) RegisterMagickInfo(entry); 1513 return(MagickImageCoderSignature); 1514} 1515 1516/* 1517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1518% % 1519% % 1520% % 1521% U n r e g i s t e r M E T A I m a g e % 1522% % 1523% % 1524% % 1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1526% 1527% UnregisterMETAImage() removes format registrations made by the 1528% META module from the list of supported formats. 1529% 1530% The format of the UnregisterMETAImage method is: 1531% 1532% UnregisterMETAImage(void) 1533% 1534*/ 1535ModuleExport void UnregisterMETAImage(void) 1536{ 1537 (void) UnregisterMagickInfo("8BIM"); 1538 (void) UnregisterMagickInfo("8BIMTEXT"); 1539 (void) UnregisterMagickInfo("8BIMWTEXT"); 1540 (void) UnregisterMagickInfo("EXIF"); 1541 (void) UnregisterMagickInfo("APP1"); 1542 (void) UnregisterMagickInfo("APP1JPEG"); 1543 (void) UnregisterMagickInfo("ICCTEXT"); 1544 (void) UnregisterMagickInfo("ICM"); 1545 (void) UnregisterMagickInfo("ICC"); 1546 (void) UnregisterMagickInfo("IPTC"); 1547 (void) UnregisterMagickInfo("IPTCTEXT"); 1548 (void) UnregisterMagickInfo("IPTCWTEXT"); 1549 (void) UnregisterMagickInfo("XMP"); 1550} 1551 1552/* 1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1554% % 1555% % 1556% % 1557% W r i t e M E T A I m a g e % 1558% % 1559% % 1560% % 1561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1562% 1563% WriteMETAImage() writes a META image to a file. 1564% 1565% The format of the WriteMETAImage method is: 1566% 1567% MagickBooleanType WriteMETAImage(const ImageInfo *image_info, 1568% Image *image) 1569% 1570% Compression code contributed by Kyle Shorter. 1571% 1572% A description of each parameter follows: 1573% 1574% o image_info: Specifies a pointer to an ImageInfo structure. 1575% 1576% o image: A pointer to a Image structure. 1577% 1578*/ 1579 1580static size_t GetIPTCStream(unsigned char **info,size_t length) 1581{ 1582 int 1583 c; 1584 1585 register ssize_t 1586 i; 1587 1588 register unsigned char 1589 *p; 1590 1591 size_t 1592 extent, 1593 info_length; 1594 1595 unsigned char 1596 buffer[4] = { '\0', '\0', '\0', '\0' }; 1597 1598 unsigned int 1599 marker; 1600 1601 size_t 1602 tag_length; 1603 1604 p=(*info); 1605 extent=length; 1606 if ((*p == 0x1c) && (*(p+1) == 0x02)) 1607 return(length); 1608 /* 1609 Extract IPTC from 8BIM resource block. 1610 */ 1611 while (extent >= 12) 1612 { 1613 if (strncmp((const char *) p,"8BIM",4)) 1614 break; 1615 p+=4; 1616 extent-=4; 1617 marker=(unsigned int) (*p) << 8 | *(p+1); 1618 p+=2; 1619 extent-=2; 1620 c=*p++; 1621 extent--; 1622 c|=0x01; 1623 if ((size_t) c >= extent) 1624 break; 1625 p+=c; 1626 extent-=c; 1627 if (extent < 4) 1628 break; 1629 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) | 1630 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3)); 1631 p+=4; 1632 extent-=4; 1633 if (tag_length > extent) 1634 break; 1635 if (marker == IPTC_ID) 1636 { 1637 *info=p; 1638 return(tag_length); 1639 } 1640 if ((tag_length & 0x01) != 0) 1641 tag_length++; 1642 p+=tag_length; 1643 extent-=tag_length; 1644 } 1645 /* 1646 Find the beginning of the IPTC info. 1647 */ 1648 p=(*info); 1649 tag_length=0; 1650iptc_find: 1651 info_length=0; 1652 marker=MagickFalse; 1653 while (length != 0) 1654 { 1655 c=(*p++); 1656 length--; 1657 if (length == 0) 1658 break; 1659 if (c == 0x1c) 1660 { 1661 p--; 1662 *info=p; /* let the caller know were it is */ 1663 break; 1664 } 1665 } 1666 /* 1667 Determine the length of the IPTC info. 1668 */ 1669 while (length != 0) 1670 { 1671 c=(*p++); 1672 length--; 1673 if (length == 0) 1674 break; 1675 if (c == 0x1c) 1676 marker=MagickTrue; 1677 else 1678 if (marker) 1679 break; 1680 else 1681 continue; 1682 info_length++; 1683 /* 1684 Found the 0x1c tag; skip the dataset and record number tags. 1685 */ 1686 c=(*p++); /* should be 2 */ 1687 length--; 1688 if (length == 0) 1689 break; 1690 if ((info_length == 1) && (c != 2)) 1691 goto iptc_find; 1692 info_length++; 1693 c=(*p++); /* should be 0 */ 1694 length--; 1695 if (length == 0) 1696 break; 1697 if ((info_length == 2) && (c != 0)) 1698 goto iptc_find; 1699 info_length++; 1700 /* 1701 Decode the length of the block that follows - ssize_t or short format. 1702 */ 1703 c=(*p++); 1704 length--; 1705 if (length == 0) 1706 break; 1707 info_length++; 1708 if ((c & 0x80) != 0) 1709 { 1710 for (i=0; i < 4; i++) 1711 { 1712 buffer[i]=(*p++); 1713 length--; 1714 if (length == 0) 1715 break; 1716 info_length++; 1717 } 1718 tag_length=(((size_t) buffer[0]) << 24) | 1719 (((size_t) buffer[1]) << 16) | 1720 (((size_t) buffer[2]) << 8) | (((size_t) buffer[3])); 1721 } 1722 else 1723 { 1724 tag_length=(size_t) (c << 8); 1725 c=(*p++); 1726 length--; 1727 if (length == 0) 1728 break; 1729 info_length++; 1730 tag_length|=c; 1731 } 1732 if (tag_length > (length+1)) 1733 break; 1734 p+=tag_length; 1735 length-=tag_length; 1736 if (length == 0) 1737 break; 1738 info_length+=tag_length; 1739 } 1740 return(info_length); 1741} 1742 1743static void formatString(Image *ofile, const char *s, int len) 1744{ 1745 char 1746 temp[MaxTextExtent]; 1747 1748 (void) WriteBlobByte(ofile,'"'); 1749 for (; len > 0; len--, s++) { 1750 int c = (*s) & 255; 1751 switch (c) { 1752 case '&': 1753 (void) WriteBlobString(ofile,"&"); 1754 break; 1755#ifdef HANDLE_GT_LT 1756 case '<': 1757 (void) WriteBlobString(ofile,"<"); 1758 break; 1759 case '>': 1760 (void) WriteBlobString(ofile,">"); 1761 break; 1762#endif 1763 case '"': 1764 (void) WriteBlobString(ofile,"""); 1765 break; 1766 default: 1767 if (isprint(c)) 1768 (void) WriteBlobByte(ofile,(unsigned char) *s); 1769 else 1770 { 1771 (void) FormatMagickString(temp,MaxTextExtent,"&#%d;", c & 255); 1772 (void) WriteBlobString(ofile,temp); 1773 } 1774 break; 1775 } 1776 } 1777#if defined(MAGICKCORE_WINDOWS_SUPPORT) 1778 (void) WriteBlobString(ofile,"\"\r\n"); 1779#else 1780#if defined(macintosh) 1781 (void) WriteBlobString(ofile,"\"\r"); 1782#else 1783 (void) WriteBlobString(ofile,"\"\n"); 1784#endif 1785#endif 1786} 1787 1788typedef struct _tag_spec 1789{ 1790 short 1791 id; 1792 1793 const char 1794 *name; 1795} tag_spec; 1796 1797static const tag_spec tags[] = { 1798 { 5, "Image Name" }, 1799 { 7, "Edit Status" }, 1800 { 10, "Priority" }, 1801 { 15, "Category" }, 1802 { 20, "Supplemental Category" }, 1803 { 22, "Fixture Identifier" }, 1804 { 25, "Keyword" }, 1805 { 30, "Release Date" }, 1806 { 35, "Release Time" }, 1807 { 40, "Special Instructions" }, 1808 { 45, "Reference Service" }, 1809 { 47, "Reference Date" }, 1810 { 50, "Reference Number" }, 1811 { 55, "Created Date" }, 1812 { 60, "Created Time" }, 1813 { 65, "Originating Program" }, 1814 { 70, "Program Version" }, 1815 { 75, "Object Cycle" }, 1816 { 80, "Byline" }, 1817 { 85, "Byline Title" }, 1818 { 90, "City" }, 1819 { 95, "Province State" }, 1820 { 100, "Country Code" }, 1821 { 101, "Country" }, 1822 { 103, "Original Transmission Reference" }, 1823 { 105, "Headline" }, 1824 { 110, "Credit" }, 1825 { 115, "Source" }, 1826 { 116, "Copyright String" }, 1827 { 120, "Caption" }, 1828 { 121, "Image Orientation" }, 1829 { 122, "Caption Writer" }, 1830 { 131, "Local Caption" }, 1831 { 200, "Custom Field 1" }, 1832 { 201, "Custom Field 2" }, 1833 { 202, "Custom Field 3" }, 1834 { 203, "Custom Field 4" }, 1835 { 204, "Custom Field 5" }, 1836 { 205, "Custom Field 6" }, 1837 { 206, "Custom Field 7" }, 1838 { 207, "Custom Field 8" }, 1839 { 208, "Custom Field 9" }, 1840 { 209, "Custom Field 10" }, 1841 { 210, "Custom Field 11" }, 1842 { 211, "Custom Field 12" }, 1843 { 212, "Custom Field 13" }, 1844 { 213, "Custom Field 14" }, 1845 { 214, "Custom Field 15" }, 1846 { 215, "Custom Field 16" }, 1847 { 216, "Custom Field 17" }, 1848 { 217, "Custom Field 18" }, 1849 { 218, "Custom Field 19" }, 1850 { 219, "Custom Field 20" } 1851}; 1852 1853static int formatIPTC(Image *ifile, Image *ofile) 1854{ 1855 char 1856 temp[MaxTextExtent]; 1857 1858 unsigned int 1859 foundiptc, 1860 tagsfound; 1861 1862 unsigned char 1863 recnum, 1864 dataset; 1865 1866 unsigned char 1867 *readable, 1868 *str; 1869 1870 ssize_t 1871 tagindx, 1872 taglen; 1873 1874 int 1875 i, 1876 tagcount = (int) (sizeof(tags) / sizeof(tag_spec)); 1877 1878 int 1879 c; 1880 1881 foundiptc = 0; /* found the IPTC-Header */ 1882 tagsfound = 0; /* number of tags found */ 1883 1884 c = ReadBlobByte(ifile); 1885 while (c != EOF) 1886 { 1887 if (c == 0x1c) 1888 foundiptc = 1; 1889 else 1890 { 1891 if (foundiptc) 1892 return -1; 1893 else 1894 continue; 1895 } 1896 1897 /* we found the 0x1c tag and now grab the dataset and record number tags */ 1898 c = ReadBlobByte(ifile); 1899 if (c == EOF) return -1; 1900 dataset = (unsigned char) c; 1901 c = ReadBlobByte(ifile); 1902 if (c == EOF) return -1; 1903 recnum = (unsigned char) c; 1904 /* try to match this record to one of the ones in our named table */ 1905 for (i=0; i< tagcount; i++) 1906 { 1907 if (tags[i].id == (short) recnum) 1908 break; 1909 } 1910 if (i < tagcount) 1911 readable = (unsigned char *) tags[i].name; 1912 else 1913 readable = (unsigned char *) ""; 1914 /* 1915 We decode the length of the block that follows - ssize_t or short fmt. 1916 */ 1917 c=ReadBlobByte(ifile); 1918 if (c == EOF) return -1; 1919 if (c & (unsigned char) 0x80) 1920 return 0; 1921 else 1922 { 1923 int 1924 c0; 1925 1926 c0=ReadBlobByte(ifile); 1927 if (c0 == EOF) return -1; 1928 taglen = (c << 8) | c0; 1929 } 1930 if (taglen < 0) return -1; 1931 /* make a buffer to hold the tag datand snag it from the input stream */ 1932 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent), 1933 sizeof(*str)); 1934 if (str == (unsigned char *) NULL) 1935 { 1936 printf("MemoryAllocationFailed"); 1937 return 0; 1938 } 1939 for (tagindx=0; tagindx<taglen; tagindx++) 1940 { 1941 c=ReadBlobByte(ifile); 1942 if (c == EOF) return -1; 1943 str[tagindx] = (unsigned char) c; 1944 } 1945 str[taglen] = 0; 1946 1947 /* now finish up by formatting this binary data into ASCII equivalent */ 1948 if (strlen((char *)readable) > 0) 1949 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d#%s=", 1950 (unsigned int) dataset, (unsigned int) recnum, readable); 1951 else 1952 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d=", 1953 (unsigned int) dataset,(unsigned int) recnum); 1954 (void) WriteBlobString(ofile,temp); 1955 formatString( ofile, (char *)str, taglen ); 1956 str=(unsigned char *) RelinquishMagickMemory(str); 1957 1958 tagsfound++; 1959 1960 c=ReadBlobByte(ifile); 1961 } 1962 return((int) tagsfound); 1963} 1964 1965static int readWordFromBuffer(char **s, ssize_t *len) 1966{ 1967 unsigned char 1968 buffer[2]; 1969 1970 int 1971 i, 1972 c; 1973 1974 for (i=0; i<2; i++) 1975 { 1976 c = *(*s)++; (*len)--; 1977 if (*len < 0) return -1; 1978 buffer[i] = (unsigned char) c; 1979 } 1980 return (((int) buffer[ 0 ]) << 8) | 1981 (((int) buffer[ 1 ])); 1982} 1983 1984static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len) 1985{ 1986 char 1987 temp[MaxTextExtent]; 1988 1989 unsigned int 1990 foundiptc, 1991 tagsfound; 1992 1993 unsigned char 1994 recnum, 1995 dataset; 1996 1997 unsigned char 1998 *readable, 1999 *str; 2000 2001 ssize_t 2002 tagindx, 2003 taglen; 2004 2005 int 2006 i, 2007 tagcount = (int) (sizeof(tags) / sizeof(tag_spec)); 2008 2009 int 2010 c; 2011 2012 foundiptc = 0; /* found the IPTC-Header */ 2013 tagsfound = 0; /* number of tags found */ 2014 2015 while (len > 0) 2016 { 2017 c = *s++; len--; 2018 if (c == 0x1c) 2019 foundiptc = 1; 2020 else 2021 { 2022 if (foundiptc) 2023 return -1; 2024 else 2025 continue; 2026 } 2027 /* 2028 We found the 0x1c tag and now grab the dataset and record number tags. 2029 */ 2030 c = *s++; len--; 2031 if (len < 0) return -1; 2032 dataset = (unsigned char) c; 2033 c = *s++; len--; 2034 if (len < 0) return -1; 2035 recnum = (unsigned char) c; 2036 /* try to match this record to one of the ones in our named table */ 2037 for (i=0; i< tagcount; i++) 2038 if (tags[i].id == (short) recnum) 2039 break; 2040 if (i < tagcount) 2041 readable=(unsigned char *) tags[i].name; 2042 else 2043 readable=(unsigned char *) ""; 2044 /* 2045 We decode the length of the block that follows - ssize_t or short fmt. 2046 */ 2047 c=(*s++); 2048 len--; 2049 if (len < 0) 2050 return(-1); 2051 if (c & (unsigned char) 0x80) 2052 return(0); 2053 else 2054 { 2055 s--; 2056 len++; 2057 taglen=readWordFromBuffer(&s, &len); 2058 } 2059 if (taglen < 0) 2060 return(-1); 2061 /* make a buffer to hold the tag datand snag it from the input stream */ 2062 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent), 2063 sizeof(*str)); 2064 if (str == (unsigned char *) NULL) 2065 { 2066 printf("MemoryAllocationFailed"); 2067 return 0; 2068 } 2069 for (tagindx=0; tagindx<taglen; tagindx++) 2070 { 2071 c = *s++; len--; 2072 if (len < 0) 2073 return(-1); 2074 str[tagindx]=(unsigned char) c; 2075 } 2076 str[taglen]=0; 2077 2078 /* now finish up by formatting this binary data into ASCII equivalent */ 2079 if (strlen((char *)readable) > 0) 2080 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d#%s=", 2081 (unsigned int) dataset,(unsigned int) recnum, readable); 2082 else 2083 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d=", 2084 (unsigned int) dataset,(unsigned int) recnum); 2085 (void) WriteBlobString(ofile,temp); 2086 formatString( ofile, (char *)str, taglen ); 2087 str=(unsigned char *) RelinquishMagickMemory(str); 2088 2089 tagsfound++; 2090 } 2091 return ((int) tagsfound); 2092} 2093 2094static int format8BIM(Image *ifile, Image *ofile) 2095{ 2096 char 2097 temp[MaxTextExtent]; 2098 2099 unsigned int 2100 foundOSType; 2101 2102 int 2103 ID, 2104 resCount, 2105 i, 2106 c; 2107 2108 ssize_t 2109 count; 2110 2111 unsigned char 2112 *PString, 2113 *str; 2114 2115 resCount=0; 2116 foundOSType=0; /* found the OSType */ 2117 (void) foundOSType; 2118 c=ReadBlobByte(ifile); 2119 while (c != EOF) 2120 { 2121 if (c == '8') 2122 { 2123 unsigned char 2124 buffer[5]; 2125 2126 buffer[0]=(unsigned char) c; 2127 for (i=1; i<4; i++) 2128 { 2129 c=ReadBlobByte(ifile); 2130 if (c == EOF) 2131 return(-1); 2132 buffer[i] = (unsigned char) c; 2133 } 2134 buffer[4]=0; 2135 if (strcmp((const char *)buffer, "8BIM") == 0) 2136 foundOSType=1; 2137 else 2138 continue; 2139 } 2140 else 2141 { 2142 c=ReadBlobByte(ifile); 2143 continue; 2144 } 2145 /* 2146 We found the OSType (8BIM) and now grab the ID, PString, and Size fields. 2147 */ 2148 ID=(int) ReadBlobMSBShort(ifile); 2149 if (ID < 0) 2150 return(-1); 2151 { 2152 unsigned char 2153 plen; 2154 2155 c=ReadBlobByte(ifile); 2156 if (c == EOF) 2157 return(-1); 2158 plen = (unsigned char) c; 2159 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+ 2160 MaxTextExtent),sizeof(*PString)); 2161 if (PString == (unsigned char *) NULL) 2162 { 2163 printf("MemoryAllocationFailed"); 2164 return 0; 2165 } 2166 for (i=0; i<plen; i++) 2167 { 2168 c=ReadBlobByte(ifile); 2169 if (c == EOF) return -1; 2170 PString[i] = (unsigned char) c; 2171 } 2172 PString[ plen ] = 0; 2173 if ((plen & 0x01) == 0) 2174 { 2175 c=ReadBlobByte(ifile); 2176 if (c == EOF) 2177 return(-1); 2178 } 2179 } 2180 count = (int) ReadBlobMSBLong(ifile); 2181 if (count < 0) return -1; 2182 /* make a buffer to hold the datand snag it from the input stream */ 2183 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str)); 2184 if (str == (unsigned char *) NULL) 2185 { 2186 printf("MemoryAllocationFailed"); 2187 return 0; 2188 } 2189 for (i=0; i < (ssize_t) count; i++) 2190 { 2191 c=ReadBlobByte(ifile); 2192 if (c == EOF) 2193 return(-1); 2194 str[i]=(unsigned char) c; 2195 } 2196 2197 /* we currently skip thumbnails, since it does not make 2198 * any sense preserving them in a real world application 2199 */ 2200 if (ID != THUMBNAIL_ID) 2201 { 2202 /* now finish up by formatting this binary data into 2203 * ASCII equivalent 2204 */ 2205 if (strlen((const char *)PString) > 0) 2206 (void) FormatMagickString(temp,MaxTextExtent,"8BIM#%d#%s=",ID, 2207 PString); 2208 else 2209 (void) FormatMagickString(temp,MaxTextExtent,"8BIM#%d=",ID); 2210 (void) WriteBlobString(ofile,temp); 2211 if (ID == IPTC_ID) 2212 { 2213 formatString(ofile, "IPTC", 4); 2214 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count); 2215 } 2216 else 2217 formatString(ofile, (char *)str, (ssize_t) count); 2218 } 2219 str=(unsigned char *) RelinquishMagickMemory(str); 2220 PString=(unsigned char *) RelinquishMagickMemory(PString); 2221 resCount++; 2222 c=ReadBlobByte(ifile); 2223 } 2224 return resCount; 2225} 2226 2227static MagickBooleanType WriteMETAImage(const ImageInfo *image_info, 2228 Image *image) 2229{ 2230 const StringInfo 2231 *profile; 2232 2233 MagickBooleanType 2234 status; 2235 2236 size_t 2237 length; 2238 2239 /* 2240 Open image file. 2241 */ 2242 assert(image_info != (const ImageInfo *) NULL); 2243 assert(image_info->signature == MagickSignature); 2244 assert(image != (Image *) NULL); 2245 assert(image->signature == MagickSignature); 2246 if (image->debug != MagickFalse) 2247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2248 length=0; 2249 if (LocaleCompare(image_info->magick,"8BIM") == 0) 2250 { 2251 /* 2252 Write 8BIM image. 2253 */ 2254 profile=GetImageProfile(image,"8bim"); 2255 if (profile == (StringInfo *) NULL) 2256 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2257 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2258 if (status == MagickFalse) 2259 return(status); 2260 (void) WriteBlob(image,GetStringInfoLength(profile), 2261 GetStringInfoDatum(profile)); 2262 (void) CloseBlob(image); 2263 return(MagickTrue); 2264 } 2265 if (LocaleCompare(image_info->magick,"iptc") == 0) 2266 { 2267 size_t 2268 length; 2269 2270 unsigned char 2271 *info; 2272 2273 profile=GetImageProfile(image,"iptc"); 2274 if (profile == (StringInfo *) NULL) 2275 profile=GetImageProfile(image,"8bim"); 2276 if (profile == (StringInfo *) NULL) 2277 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2278 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2279 info=GetStringInfoDatum(profile); 2280 length=GetStringInfoLength(profile); 2281 length=GetIPTCStream(&info,length); 2282 if (length == 0) 2283 ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); 2284 (void) WriteBlob(image,length,info); 2285 (void) CloseBlob(image); 2286 return(MagickTrue); 2287 } 2288 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0) 2289 { 2290 Image 2291 *buff; 2292 2293 profile=GetImageProfile(image,"8bim"); 2294 if (profile == (StringInfo *) NULL) 2295 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2296 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2297 if (status == MagickFalse) 2298 return(status); 2299 buff=AcquireImage((ImageInfo *) NULL); 2300 if (buff == (Image *) NULL) 2301 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2302 AttachBlob(buff->blob,GetStringInfoDatum(profile), 2303 GetStringInfoLength(profile)); 2304 format8BIM(buff,image); 2305 (void) DetachBlob(buff->blob); 2306 buff=DestroyImage(buff); 2307 (void) CloseBlob(image); 2308 return(MagickTrue); 2309 } 2310 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0) 2311 return(MagickFalse); 2312 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0) 2313 { 2314 Image 2315 *buff; 2316 2317 unsigned char 2318 *info; 2319 2320 profile=GetImageProfile(image,"8bim"); 2321 if (profile == (StringInfo *) NULL) 2322 ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); 2323 info=GetStringInfoDatum(profile); 2324 length=GetStringInfoLength(profile); 2325 length=GetIPTCStream(&info,length); 2326 if (length == 0) 2327 ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); 2328 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2329 if (status == MagickFalse) 2330 return(status); 2331 buff=AcquireImage((ImageInfo *) NULL); 2332 if (buff == (Image *) NULL) 2333 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2334 AttachBlob(buff->blob,info,length); 2335 formatIPTC(buff,image); 2336 (void) DetachBlob(buff->blob); 2337 buff=DestroyImage(buff); 2338 (void) CloseBlob(image); 2339 return(MagickTrue); 2340 } 2341 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0) 2342 return(MagickFalse); 2343 if ((LocaleCompare(image_info->magick,"APP1") == 0) || 2344 (LocaleCompare(image_info->magick,"EXIF") == 0) || 2345 (LocaleCompare(image_info->magick,"XMP") == 0)) 2346 { 2347 /* 2348 (void) Write APP1 image. 2349 */ 2350 profile=GetImageProfile(image,image_info->magick); 2351 if (profile == (StringInfo *) NULL) 2352 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable"); 2353 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2354 if (status == MagickFalse) 2355 return(status); 2356 (void) WriteBlob(image,GetStringInfoLength(profile), 2357 GetStringInfoDatum(profile)); 2358 (void) CloseBlob(image); 2359 return(MagickTrue); 2360 } 2361 if ((LocaleCompare(image_info->magick,"ICC") == 0) || 2362 (LocaleCompare(image_info->magick,"ICM") == 0)) 2363 { 2364 /* 2365 Write ICM image. 2366 */ 2367 profile=GetImageProfile(image,"icc"); 2368 if (profile == (StringInfo *) NULL) 2369 ThrowWriterException(CoderError,"NoColorProfileIsAvailable"); 2370 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 2371 if (status == MagickFalse) 2372 return(status); 2373 (void) WriteBlob(image,GetStringInfoLength(profile), 2374 GetStringInfoDatum(profile)); 2375 (void) CloseBlob(image); 2376 return(MagickTrue); 2377 } 2378 return(MagickFalse); 2379} 2380