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