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