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