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