2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M EEEEE TTTTT AAA %
13 % Read/Write Embedded Image Profiles. %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/image.h"
48 #include "MagickCore/image-private.h"
49 #include "MagickCore/list.h"
50 #include "MagickCore/magick.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/module.h"
53 #include "MagickCore/profile.h"
54 #include "MagickCore/splay-tree.h"
55 #include "MagickCore/quantum-private.h"
56 #include "MagickCore/static.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/token.h"
60 #include "MagickCore/utility.h"
65 static MagickBooleanType
66 WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *);
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % IsMETA() returns MagickTrue if the image format type, identified by the
80 % magick string, is META.
82 % The format of the IsMETA method is:
84 % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
86 % A description of each parameter follows:
88 % o magick: compare image format pattern against these bytes.
90 % o length: Specifies the length of the magick string.
94 #ifdef IMPLEMENT_IS_FUNCTION
95 static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
99 if (LocaleNCompare((char *) magick,"8BIM",4) == 0)
101 if (LocaleNCompare((char *) magick,"APP1",4) == 0)
103 if (LocaleNCompare((char *) magick,"\034\002",2) == 0)
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114 % R e a d M E T A I m a g e %
118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 % ReadMETAImage() reads a META image file and returns it. It
121 % allocates the memory necessary for the new Image structure and returns a
122 % pointer to the new image.
124 % The format of the ReadMETAImage method is:
126 % Image *ReadMETAImage(const ImageInfo *image_info,
127 % ExceptionInfo *exception)
129 % Decompression code contributed by Kyle Shorter.
131 % A description of each parameter follows:
133 % o image: Method ReadMETAImage returns a pointer to the image after
134 % reading. A null image is returned if there is a memory shortage or
135 % if the image cannot be read.
137 % o image_info: Specifies a pointer to an ImageInfo structure.
139 % o exception: return any errors or warnings in this structure.
142 #define BUFFER_SZ 4096
144 typedef struct _html_code
153 static html_code html_codes[] = {
163 static int stringnicmp(const char *p,const char *q,size_t n)
171 if (p == (char *) NULL)
173 if (q == (char *) NULL)
175 while ((*p != '\0') && (*q != '\0'))
177 if ((*p == '\0') || (*q == '\0'))
193 return(toupper((int) *p)-toupper((int) *q));
196 static int convertHTMLcodes(char *s, int len)
198 if (len <=0 || s==(char*)NULL || *s=='\0')
205 if (sscanf(s,"&#%d;",&val) == 1)
215 (void) strcpy(s+1,s+1+o);
224 codes = (int) (sizeof(html_codes) / sizeof(html_code));
226 for (i=0; i < codes; i++)
228 if (html_codes[i].len <= len)
229 if (stringnicmp(s,html_codes[i].code,(size_t) html_codes[i].len) == 0)
231 (void) strcpy(s+1,s+html_codes[i].len);
232 *s = html_codes[i].val;
233 return html_codes[i].len-1;
240 static char *super_fgets(char **b, int *blen, Image *file)
251 p=(unsigned char *) (*b);
254 c=ReadBlobByte(file);
255 if (c == EOF || c == '\n')
257 if ((q-p+1) >= (int) len)
264 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) len+2UL,sizeof(*p));
266 if (p == (unsigned char *) NULL)
270 *q=(unsigned char) c;
273 if (p != (unsigned char *) NULL)
280 return (char *) NULL;
287 #define BUFFER_SZ 4096
289 #define THUMBNAIL_ID 1033
291 static ssize_t parse8BIM(Image *ifile, Image *ofile)
312 inputlen = BUFFER_SZ;
327 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
328 name = token = (char *)NULL;
330 token_info=AcquireTokenInfo();
331 while (super_fgets(&line,&inputlen,ifile)!=NULL)
336 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
337 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
338 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
339 &brkused,&next,"ed)==0)
353 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
354 "", 0,&brkused,&next,"ed)==0)
359 if (strcmp(newstr,"8BIM")==0)
362 dataset = (unsigned char) StringToLong(newstr);
365 recnum = (unsigned int) StringToUnsignedLong(newstr);
368 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
371 (void) strcpy(name,newstr);
391 len = (ssize_t) strlen(token);
392 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
393 "",0,&brkused,&next,"ed)==0)
395 if (brkused && next > 0)
400 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
417 ssize_t diff = outputlen - savedolen;
418 currentpos = TellBlob(ofile);
419 offset=SeekBlob(ofile,savedpos,SEEK_SET);
422 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
423 offset=SeekBlob(ofile,currentpos,SEEK_SET);
430 (void) WriteBlobByte(ofile,0x00);
433 (void) WriteBlobString(ofile,"8BIM");
434 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
437 nlen = (unsigned char) strlen(name);
438 (void) WriteBlobByte(ofile,nlen);
440 for (i=0; i<nlen; i++)
441 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
443 if ((nlen & 0x01) == 0)
445 (void) WriteBlobByte(ofile,0x00);
448 if (recnum != IPTC_ID)
450 (void) WriteBlobMSBLong(ofile, (unsigned int) len);
456 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
460 (void) WriteBlobByte(ofile,0x00);
466 /* patch in a fake length for now and fix it later */
467 savedpos = TellBlob(ofile);
468 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
470 savedolen = outputlen;
477 (void) WriteBlobByte(ofile,0x1c);
478 (void) WriteBlobByte(ofile,(unsigned char) dataset);
479 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
480 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
485 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
491 token=DestroyString(token);
492 newstr=DestroyString(newstr);
493 if (name != (char *) NULL)
494 name=DestroyString(name);
496 token_info=DestroyTokenInfo(token_info);
497 line=DestroyString(line);
503 ssize_t diff = outputlen - savedolen;
505 currentpos = TellBlob(ofile);
506 offset=SeekBlob(ofile,savedpos,SEEK_SET);
509 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
510 offset=SeekBlob(ofile,currentpos,SEEK_SET);
518 static char *super_fgets_w(char **b, int *blen, Image *file)
529 p=(unsigned char *) (*b);
532 c=(int) ReadBlobLSBShort(file);
533 if ((c == -1) || (c == '\n'))
537 if ((q-p+1) >= (int) len)
544 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
546 if (p == (unsigned char *) NULL)
550 *q=(unsigned char) c;
553 if ((*b) != (char *) NULL)
560 return (char *) NULL;
567 static ssize_t parse8BIMW(Image *ifile, Image *ofile)
588 inputlen = BUFFER_SZ;
603 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
604 name = token = (char *)NULL;
606 token_info=AcquireTokenInfo();
607 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
612 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
613 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
614 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
615 &brkused,&next,"ed)==0)
629 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
630 "",0,&brkused,&next,"ed)==0)
635 if (strcmp(newstr,"8BIM")==0)
638 dataset = (unsigned char) StringToLong(newstr);
641 recnum=(unsigned int) StringToUnsignedLong(newstr);
644 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
647 (void) CopyMagickString(name,newstr,strlen(newstr)+MaxTextExtent);
667 len = (ssize_t) strlen(token);
668 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
669 "",0,&brkused,&next,"ed)==0)
671 if (brkused && next > 0)
676 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
693 ssize_t diff = outputlen - savedolen;
694 currentpos = TellBlob(ofile);
695 offset=SeekBlob(ofile,savedpos,SEEK_SET);
698 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
699 offset=SeekBlob(ofile,currentpos,SEEK_SET);
706 (void) WriteBlobByte(ofile,0x00);
709 (void) WriteBlobString(ofile,"8BIM");
710 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
713 nlen = (unsigned char) strlen(name);
714 (void) WriteBlobByte(ofile,(unsigned char) nlen);
716 for (i=0; i<nlen; i++)
717 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
719 if ((nlen & 0x01) == 0)
721 (void) WriteBlobByte(ofile,0x00);
724 if (recnum != IPTC_ID)
726 (void) WriteBlobMSBLong(ofile,(unsigned int) len);
732 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
736 (void) WriteBlobByte(ofile,0x00);
742 /* patch in a fake length for now and fix it later */
743 savedpos = TellBlob(ofile);
744 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
746 savedolen = outputlen;
753 (void) WriteBlobByte(ofile,0x1c);
754 (void) WriteBlobByte(ofile,dataset);
755 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
756 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
761 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
767 token=DestroyString(token);
768 newstr=DestroyString(newstr);
769 name=DestroyString(name);
771 token_info=DestroyTokenInfo(token_info);
772 line=DestroyString(line);
778 ssize_t diff = outputlen - savedolen;
780 currentpos = TellBlob(ofile);
781 offset=SeekBlob(ofile,savedpos,SEEK_SET);
784 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
785 offset=SeekBlob(ofile,currentpos,SEEK_SET);
793 /* some defines for the different JPEG block types */
794 #define M_SOF0 0xC0 /* Start Of Frame N */
795 #define M_SOF1 0xC1 /* N indicates which compression process */
796 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
798 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
808 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
809 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
827 static int jpeg_transfer_1(Image *ifile, Image *ofile)
831 c = ReadBlobByte(ifile);
834 (void) WriteBlobByte(ofile,(unsigned char) c);
839 static int jpeg_skip_1(Image *ifile)
843 c = ReadBlobByte(ifile);
850 static int jpeg_read_remaining(Image *ifile, Image *ofile)
854 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
859 static int jpeg_skip_variable(Image *ifile, Image *ofile)
864 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
866 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
869 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
873 if (jpeg_transfer_1(ifile, ofile) == EOF)
879 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
885 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
886 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
888 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
892 if (ReadBlobByte(ifile) == EOF)
898 static int jpeg_nextmarker(Image *ifile, Image *ofile)
902 /* transfer anything until we hit 0xff */
905 c = ReadBlobByte(ifile);
907 return M_EOI; /* we hit EOF */
910 (void) WriteBlobByte(ofile,(unsigned char) c);
913 /* get marker byte, swallowing possible padding */
916 c = ReadBlobByte(ifile);
918 return M_EOI; /* we hit EOF */
925 static int jpeg_skip_till_marker(Image *ifile, int marker)
931 /* skip anything until we hit 0xff */
935 c = ReadBlobByte(ifile);
938 return M_EOI; /* we hit EOF */
941 /* get marker byte, swallowing possible padding */
944 c = ReadBlobByte(ifile);
946 return M_EOI; /* we hit EOF */
948 } while (c != marker);
953 static char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
955 /* Embed binary IPTC data into a JPEG image. */
956 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
959 unsigned int done = 0;
963 if (jpeg_transfer_1(ifile, ofile) != 0xFF)
965 if (jpeg_transfer_1(ifile, ofile) != M_SOI)
968 while (done == MagickFalse)
970 marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
977 if (marker != M_APP13)
979 (void) WriteBlobByte(ofile,0xff);
980 (void) WriteBlobByte(ofile,(unsigned char) marker);
987 /* we are going to write a new APP13 marker, so don't output the old one */
988 jpeg_skip_variable2(ifile, ofile);
992 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
993 jpeg_skip_variable(ifile, ofile);
995 if (iptc != (Image *)NULL)
997 len=(unsigned int) GetBlobSize(iptc);
999 len++; /* make the length even */
1000 psheader[2]=(char) ((len+16)>>8);
1001 psheader[3]=(char) ((len+16)&0xff);
1002 for (inx = 0; inx < 18; inx++)
1003 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1004 jpeg_read_remaining(iptc, ofile);
1005 len=(unsigned int) GetBlobSize(iptc);
1007 (void) WriteBlobByte(ofile,0);
1012 /* we hit data, no more marker-inserting can be done! */
1013 jpeg_read_remaining(ifile, ofile);
1018 jpeg_skip_variable(ifile, ofile);
1025 /* handle stripping the APP13 data out of a JPEG */
1027 static void jpeg_strip(Image *ifile, Image *ofile)
1029 unsigned int marker;
1031 marker = jpeg_skip_till_marker(ifile, M_SOI);
1032 if (marker == M_SOI)
1034 (void) WriteBlobByte(ofile,0xff);
1035 (void) WriteBlobByte(ofile,M_SOI);
1036 jpeg_read_remaining(ifile, ofile);
1040 /* Extract any APP13 binary data into a file. */
1041 static int jpeg_extract(Image *ifile, Image *ofile)
1043 unsigned int marker;
1044 unsigned int done = 0;
1046 if (jpeg_skip_1(ifile) != 0xff)
1048 if (jpeg_skip_1(ifile) != M_SOI)
1051 while (done == MagickFalse)
1053 marker = jpeg_skip_till_marker(ifile, M_APP13);
1054 if (marker == M_APP13)
1056 marker = jpeg_nextmarker(ifile, ofile);
1064 static Image *ReadMETAImage(const ImageInfo *image_info,
1065 ExceptionInfo *exception)
1087 Open file containing binary metadata
1089 assert(image_info != (const ImageInfo *) NULL);
1090 assert(image_info->signature == MagickSignature);
1091 if (image_info->debug != MagickFalse)
1092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1093 image_info->filename);
1094 assert(exception != (ExceptionInfo *) NULL);
1095 assert(exception->signature == MagickSignature);
1096 image=AcquireImage(image_info);
1097 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1098 if (status == MagickFalse)
1100 image=DestroyImageList(image);
1101 return((Image *) NULL);
1105 if (SetImageBackgroundColor(image) == MagickFalse)
1107 InheritException(exception,&image->exception);
1108 image=DestroyImageList(image);
1109 return((Image *) NULL);
1112 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1115 Read 8BIM binary metadata.
1117 buff=AcquireImage((ImageInfo *) NULL);
1118 if (buff == (Image *) NULL)
1119 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1120 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1121 if (blob == (unsigned char *) NULL)
1123 buff=DestroyImage(buff);
1124 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1126 AttachBlob(buff->blob,blob,length);
1127 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1129 length=(size_t) parse8BIM(image, buff);
1131 (void) WriteBlobByte(buff,0x0);
1133 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1135 length=(size_t) parse8BIMW(image, buff);
1137 (void) WriteBlobByte(buff,0x0);
1143 c=ReadBlobByte(image);
1146 (void) WriteBlobByte(buff,(unsigned char) c);
1149 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1151 if (profile == (StringInfo *) NULL)
1152 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1153 status=SetImageProfile(image,"8bim",profile);
1154 profile=DestroyStringInfo(profile);
1155 if (status == MagickFalse)
1156 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1157 blob=DetachBlob(buff->blob);
1158 blob=(unsigned char *) RelinquishMagickMemory(blob);
1159 buff=DestroyImage(buff);
1161 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1164 name[MaxTextExtent];
1166 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",1);
1167 buff=AcquireImage((ImageInfo *) NULL);
1168 if (buff == (Image *) NULL)
1169 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1170 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1171 if (blob == (unsigned char *) NULL)
1173 buff=DestroyImage(buff);
1174 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1176 AttachBlob(buff->blob,blob,length);
1177 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1185 if (image_info->profile == (void *) NULL)
1187 blob=DetachBlob(buff->blob);
1188 blob=RelinquishMagickMemory(blob);
1189 buff=DestroyImage(buff);
1190 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1192 profile=CloneStringInfo((StringInfo *) image_info->profile);
1193 iptc=AcquireImage((ImageInfo *) NULL);
1194 if (iptc == (Image *) NULL)
1196 blob=DetachBlob(buff->blob);
1197 blob=RelinquishMagickMemory(blob);
1198 buff=DestroyImage(buff);
1199 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1201 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1202 GetStringInfoLength(profile));
1203 result=jpeg_embed(image,buff,iptc);
1204 blob=DetachBlob(iptc->blob);
1205 blob=RelinquishMagickMemory(blob);
1206 iptc=DestroyImage(iptc);
1209 blob=DetachBlob(buff->blob);
1210 blob=RelinquishMagickMemory(blob);
1211 buff=DestroyImage(buff);
1212 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1220 /* Really - really slow - FIX ME PLEASE!!!! */
1221 c=ReadBlobByte(image);
1224 (void) WriteBlobByte(buff,c);
1237 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1239 if (buffer != (unsigned char *) NULL)
1242 while ((length=ReadBlob(image,MagickMaxBufferExtent,buffer)) != 0)
1245 for (i=0; i < (ssize_t) length; i+=count)
1247 count=WriteBlob(buff,(size_t) (length-i),buffer+i);
1251 if (i < (ssize_t) length)
1254 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1258 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1260 if (profile == (StringInfo *) NULL)
1261 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1262 status=SetImageProfile(image,name,profile);
1263 profile=DestroyStringInfo(profile);
1264 if (status == MagickFalse)
1265 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1266 blob=DetachBlob(buff->blob);
1267 blob=RelinquishMagickMemory(blob);
1268 buff=DestroyImage(buff);
1270 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1271 (LocaleCompare(image_info->magick,"ICM") == 0))
1273 buff=AcquireImage((ImageInfo *) NULL);
1274 if (buff == (Image *) NULL)
1275 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1276 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1277 if (blob == (unsigned char *) NULL)
1279 buff=DestroyImage(buff);
1280 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1282 AttachBlob(buff->blob,blob,length);
1285 c=ReadBlobByte(image);
1288 (void) WriteBlobByte(buff,(unsigned char) c);
1290 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1292 if (profile == (StringInfo *) NULL)
1293 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1294 (void) SetImageProfile(image,"icc",profile);
1295 profile=DestroyStringInfo(profile);
1296 blob=DetachBlob(buff->blob);
1297 blob=(unsigned char *) RelinquishMagickMemory(blob);
1298 buff=DestroyImage(buff);
1300 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1302 register unsigned char
1305 buff=AcquireImage((ImageInfo *) NULL);
1306 if (buff == (Image *) NULL)
1307 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1308 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1309 if (blob == (unsigned char *) NULL)
1311 buff=DestroyImage(buff);
1312 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1314 AttachBlob(buff->blob,blob,length);
1315 /* write out the header - length field patched below */
1316 (void) WriteBlob(buff,11,(unsigned char *) "8BIM\04\04\0\0\0\0\0");
1317 (void) WriteBlobByte(buff,0xc6);
1318 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
1320 length=(size_t) parse8BIM(image,buff);
1322 (void) WriteBlobByte(buff,0x00);
1324 else if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
1331 c=ReadBlobByte(image);
1334 (void) WriteBlobByte(buff,(unsigned char) c);
1337 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1339 if (profile == (StringInfo *) NULL)
1340 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1342 subtract off the length of the 8BIM stuff.
1344 length=GetStringInfoLength(profile)-12;
1345 p=GetStringInfoDatum(profile);
1346 p[10]=(unsigned char) (length >> 8);
1347 p[11]=(unsigned char) (length & 0xff);
1348 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1349 (void) SetImageProfile(image,"8bim",profile);
1350 profile=DestroyStringInfo(profile);
1351 blob=DetachBlob(buff->blob);
1352 blob=(unsigned char *) RelinquishMagickMemory(blob);
1353 buff=DestroyImage(buff);
1355 if (LocaleCompare(image_info->magick,"XMP") == 0)
1357 buff=AcquireImage((ImageInfo *) NULL);
1358 if (buff == (Image *) NULL)
1359 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1360 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1361 if (blob == (unsigned char *) NULL)
1363 buff=DestroyImage(buff);
1364 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1366 AttachBlob(buff->blob,blob,length);
1369 c=ReadBlobByte(image);
1372 (void) WriteBlobByte(buff,(unsigned char) c);
1374 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1376 if (profile == (StringInfo *) NULL)
1377 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1378 (void) SetImageProfile(image,"xmp",profile);
1379 profile=DestroyStringInfo(profile);
1380 blob=DetachBlob(buff->blob);
1381 blob=(unsigned char *) RelinquishMagickMemory(blob);
1382 buff=DestroyImage(buff);
1384 (void) CloseBlob(image);
1385 return(GetFirstImageInList(image));
1389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393 % R e g i s t e r M E T A I m a g e %
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1399 % RegisterMETAImage() adds attributes for the META image format to
1400 % the list of supported formats. The attributes include the image format
1401 % tag, a method to read and/or write the format, whether the format
1402 % supports the saving of more than one frame to the same file or blob,
1403 % whether the format supports native in-memory I/O, and a brief
1404 % description of the format.
1406 % The format of the RegisterMETAImage method is:
1408 % size_t RegisterMETAImage(void)
1411 ModuleExport size_t RegisterMETAImage(void)
1416 entry=SetMagickInfo("8BIM");
1417 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1418 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1419 entry->adjoin=MagickFalse;
1420 entry->stealth=MagickTrue;
1421 entry->seekable_stream=MagickTrue;
1422 entry->description=ConstantString("Photoshop resource format");
1423 entry->module=ConstantString("META");
1424 (void) RegisterMagickInfo(entry);
1425 entry=SetMagickInfo("8BIMTEXT");
1426 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1427 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1428 entry->adjoin=MagickFalse;
1429 entry->stealth=MagickTrue;
1430 entry->seekable_stream=MagickTrue;
1431 entry->description=ConstantString("Photoshop resource text format");
1432 entry->module=ConstantString("META");
1433 (void) RegisterMagickInfo(entry);
1434 entry=SetMagickInfo("8BIMWTEXT");
1435 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1436 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1437 entry->adjoin=MagickFalse;
1438 entry->stealth=MagickTrue;
1439 entry->seekable_stream=MagickTrue;
1440 entry->description=ConstantString("Photoshop resource wide text format");
1441 entry->module=ConstantString("META");
1442 (void) RegisterMagickInfo(entry);
1443 entry=SetMagickInfo("APP1");
1444 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1445 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1446 entry->adjoin=MagickFalse;
1447 entry->stealth=MagickTrue;
1448 entry->seekable_stream=MagickTrue;
1449 entry->description=ConstantString("Raw application information");
1450 entry->module=ConstantString("META");
1451 (void) RegisterMagickInfo(entry);
1452 entry=SetMagickInfo("APP1JPEG");
1453 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1454 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1455 entry->adjoin=MagickFalse;
1456 entry->stealth=MagickTrue;
1457 entry->seekable_stream=MagickTrue;
1458 entry->description=ConstantString("Raw JPEG binary data");
1459 entry->module=ConstantString("META");
1460 (void) RegisterMagickInfo(entry);
1461 entry=SetMagickInfo("EXIF");
1462 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1463 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1464 entry->adjoin=MagickFalse;
1465 entry->stealth=MagickTrue;
1466 entry->seekable_stream=MagickTrue;
1467 entry->description=ConstantString("Exif digital camera binary data");
1468 entry->module=ConstantString("META");
1469 (void) RegisterMagickInfo(entry);
1470 entry=SetMagickInfo("XMP");
1471 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1472 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1473 entry->adjoin=MagickFalse;
1474 entry->stealth=MagickTrue;
1475 entry->seekable_stream=MagickTrue;
1476 entry->description=ConstantString("Adobe XML metadata");
1477 entry->module=ConstantString("META");
1478 (void) RegisterMagickInfo(entry);
1479 entry=SetMagickInfo("ICM");
1480 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1481 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1482 entry->adjoin=MagickFalse;
1483 entry->stealth=MagickTrue;
1484 entry->seekable_stream=MagickTrue;
1485 entry->description=ConstantString("ICC Color Profile");
1486 entry->module=ConstantString("META");
1487 (void) RegisterMagickInfo(entry);
1488 entry=SetMagickInfo("ICC");
1489 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1490 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1491 entry->adjoin=MagickFalse;
1492 entry->stealth=MagickTrue;
1493 entry->seekable_stream=MagickTrue;
1494 entry->description=ConstantString("ICC Color Profile");
1495 entry->module=ConstantString("META");
1496 (void) RegisterMagickInfo(entry);
1497 entry=SetMagickInfo("IPTC");
1498 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1499 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1500 entry->adjoin=MagickFalse;
1501 entry->stealth=MagickTrue;
1502 entry->seekable_stream=MagickTrue;
1503 entry->description=ConstantString("IPTC Newsphoto");
1504 entry->module=ConstantString("META");
1505 (void) RegisterMagickInfo(entry);
1506 entry=SetMagickInfo("IPTCTEXT");
1507 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1508 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1509 entry->adjoin=MagickFalse;
1510 entry->stealth=MagickTrue;
1511 entry->seekable_stream=MagickTrue;
1512 entry->description=ConstantString("IPTC Newsphoto text format");
1513 entry->module=ConstantString("META");
1514 (void) RegisterMagickInfo(entry);
1515 entry=SetMagickInfo("IPTCWTEXT");
1516 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1517 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1518 entry->adjoin=MagickFalse;
1519 entry->stealth=MagickTrue;
1520 entry->seekable_stream=MagickTrue;
1521 entry->description=ConstantString("IPTC Newsphoto text format");
1522 entry->module=ConstantString("META");
1523 (void) RegisterMagickInfo(entry);
1524 return(MagickImageCoderSignature);
1528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532 % U n r e g i s t e r M E T A I m a g e %
1536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538 % UnregisterMETAImage() removes format registrations made by the
1539 % META module from the list of supported formats.
1541 % The format of the UnregisterMETAImage method is:
1543 % UnregisterMETAImage(void)
1546 ModuleExport void UnregisterMETAImage(void)
1548 (void) UnregisterMagickInfo("8BIM");
1549 (void) UnregisterMagickInfo("8BIMTEXT");
1550 (void) UnregisterMagickInfo("8BIMWTEXT");
1551 (void) UnregisterMagickInfo("EXIF");
1552 (void) UnregisterMagickInfo("APP1");
1553 (void) UnregisterMagickInfo("APP1JPEG");
1554 (void) UnregisterMagickInfo("ICCTEXT");
1555 (void) UnregisterMagickInfo("ICM");
1556 (void) UnregisterMagickInfo("ICC");
1557 (void) UnregisterMagickInfo("IPTC");
1558 (void) UnregisterMagickInfo("IPTCTEXT");
1559 (void) UnregisterMagickInfo("IPTCWTEXT");
1560 (void) UnregisterMagickInfo("XMP");
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568 % W r i t e M E T A I m a g e %
1572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574 % WriteMETAImage() writes a META image to a file.
1576 % The format of the WriteMETAImage method is:
1578 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1579 % Image *image,ExceptionInfo *exception)
1581 % Compression code contributed by Kyle Shorter.
1583 % A description of each parameter follows:
1585 % o image_info: Specifies a pointer to an ImageInfo structure.
1587 % o image: A pointer to a Image structure.
1589 % o exception: return any errors or warnings in this structure.
1593 static size_t GetIPTCStream(unsigned char **info,size_t length)
1601 register unsigned char
1609 buffer[4] = { '\0', '\0', '\0', '\0' };
1619 if ((*p == 0x1c) && (*(p+1) == 0x02))
1622 Extract IPTC from 8BIM resource block.
1624 while (extent >= 12)
1626 if (strncmp((const char *) p,"8BIM",4))
1630 marker=(unsigned int) (*p) << 8 | *(p+1);
1636 if ((size_t) c >= extent)
1642 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
1643 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
1646 if (tag_length > extent)
1648 if (marker == IPTC_ID)
1653 if ((tag_length & 0x01) != 0)
1659 Find the beginning of the IPTC info.
1675 *info=p; /* let the caller know were it is */
1680 Determine the length of the IPTC info.
1697 Found the 0x1c tag; skip the dataset and record number tags.
1699 c=(*p++); /* should be 2 */
1703 if ((info_length == 1) && (c != 2))
1706 c=(*p++); /* should be 0 */
1710 if ((info_length == 2) && (c != 0))
1714 Decode the length of the block that follows - ssize_t or short format.
1721 if ((c & 0x80) != 0)
1723 for (i=0; i < 4; i++)
1731 tag_length=(((size_t) buffer[0]) << 24) |
1732 (((size_t) buffer[1]) << 16) |
1733 (((size_t) buffer[2]) << 8) | (((size_t) buffer[3]));
1737 tag_length=(size_t) (c << 8);
1745 if (tag_length > (length+1))
1751 info_length+=tag_length;
1753 return(info_length);
1756 static void formatString(Image *ofile, const char *s, int len)
1759 temp[MaxTextExtent];
1761 (void) WriteBlobByte(ofile,'"');
1762 for (; len > 0; len--, s++) {
1766 (void) WriteBlobString(ofile,"&");
1770 (void) WriteBlobString(ofile,"<");
1773 (void) WriteBlobString(ofile,">");
1777 (void) WriteBlobString(ofile,""");
1781 (void) WriteBlobByte(ofile,(unsigned char) *s);
1784 (void) FormatLocaleString(temp,MaxTextExtent,"&#%d;", c & 255);
1785 (void) WriteBlobString(ofile,temp);
1790 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1791 (void) WriteBlobString(ofile,"\"\r\n");
1793 #if defined(macintosh)
1794 (void) WriteBlobString(ofile,"\"\r");
1796 (void) WriteBlobString(ofile,"\"\n");
1801 typedef struct _tag_spec
1810 static const tag_spec tags[] = {
1811 { 5, "Image Name" },
1812 { 7, "Edit Status" },
1815 { 20, "Supplemental Category" },
1816 { 22, "Fixture Identifier" },
1818 { 30, "Release Date" },
1819 { 35, "Release Time" },
1820 { 40, "Special Instructions" },
1821 { 45, "Reference Service" },
1822 { 47, "Reference Date" },
1823 { 50, "Reference Number" },
1824 { 55, "Created Date" },
1825 { 60, "Created Time" },
1826 { 65, "Originating Program" },
1827 { 70, "Program Version" },
1828 { 75, "Object Cycle" },
1830 { 85, "Byline Title" },
1832 { 95, "Province State" },
1833 { 100, "Country Code" },
1835 { 103, "Original Transmission Reference" },
1836 { 105, "Headline" },
1839 { 116, "Copyright String" },
1841 { 121, "Image Orientation" },
1842 { 122, "Caption Writer" },
1843 { 131, "Local Caption" },
1844 { 200, "Custom Field 1" },
1845 { 201, "Custom Field 2" },
1846 { 202, "Custom Field 3" },
1847 { 203, "Custom Field 4" },
1848 { 204, "Custom Field 5" },
1849 { 205, "Custom Field 6" },
1850 { 206, "Custom Field 7" },
1851 { 207, "Custom Field 8" },
1852 { 208, "Custom Field 9" },
1853 { 209, "Custom Field 10" },
1854 { 210, "Custom Field 11" },
1855 { 211, "Custom Field 12" },
1856 { 212, "Custom Field 13" },
1857 { 213, "Custom Field 14" },
1858 { 214, "Custom Field 15" },
1859 { 215, "Custom Field 16" },
1860 { 216, "Custom Field 17" },
1861 { 217, "Custom Field 18" },
1862 { 218, "Custom Field 19" },
1863 { 219, "Custom Field 20" }
1866 static int formatIPTC(Image *ifile, Image *ofile)
1869 temp[MaxTextExtent];
1889 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1894 foundiptc = 0; /* found the IPTC-Header */
1895 tagsfound = 0; /* number of tags found */
1897 c = ReadBlobByte(ifile);
1910 /* we found the 0x1c tag and now grab the dataset and record number tags */
1911 c = ReadBlobByte(ifile);
1912 if (c == EOF) return -1;
1913 dataset = (unsigned char) c;
1914 c = ReadBlobByte(ifile);
1915 if (c == EOF) return -1;
1916 recnum = (unsigned char) c;
1917 /* try to match this record to one of the ones in our named table */
1918 for (i=0; i< tagcount; i++)
1920 if (tags[i].id == (short) recnum)
1924 readable = (unsigned char *) tags[i].name;
1926 readable = (unsigned char *) "";
1928 We decode the length of the block that follows - ssize_t or short fmt.
1930 c=ReadBlobByte(ifile);
1931 if (c == EOF) return -1;
1932 if (c & (unsigned char) 0x80)
1939 c0=ReadBlobByte(ifile);
1940 if (c0 == EOF) return -1;
1941 taglen = (c << 8) | c0;
1943 if (taglen < 0) return -1;
1944 /* make a buffer to hold the tag datand snag it from the input stream */
1945 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
1947 if (str == (unsigned char *) NULL)
1949 printf("MemoryAllocationFailed");
1952 for (tagindx=0; tagindx<taglen; tagindx++)
1954 c=ReadBlobByte(ifile);
1955 if (c == EOF) return -1;
1956 str[tagindx] = (unsigned char) c;
1960 /* now finish up by formatting this binary data into ASCII equivalent */
1961 if (strlen((char *)readable) > 0)
1962 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
1963 (unsigned int) dataset, (unsigned int) recnum, readable);
1965 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
1966 (unsigned int) dataset,(unsigned int) recnum);
1967 (void) WriteBlobString(ofile,temp);
1968 formatString( ofile, (char *)str, taglen );
1969 str=(unsigned char *) RelinquishMagickMemory(str);
1973 c=ReadBlobByte(ifile);
1975 return((int) tagsfound);
1978 static int readWordFromBuffer(char **s, ssize_t *len)
1989 c = *(*s)++; (*len)--;
1990 if (*len < 0) return -1;
1991 buffer[i] = (unsigned char) c;
1993 return (((int) buffer[ 0 ]) << 8) |
1994 (((int) buffer[ 1 ]));
1997 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
2000 temp[MaxTextExtent];
2020 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
2025 foundiptc = 0; /* found the IPTC-Header */
2026 tagsfound = 0; /* number of tags found */
2041 We found the 0x1c tag and now grab the dataset and record number tags.
2044 if (len < 0) return -1;
2045 dataset = (unsigned char) c;
2047 if (len < 0) return -1;
2048 recnum = (unsigned char) c;
2049 /* try to match this record to one of the ones in our named table */
2050 for (i=0; i< tagcount; i++)
2051 if (tags[i].id == (short) recnum)
2054 readable=(unsigned char *) tags[i].name;
2056 readable=(unsigned char *) "";
2058 We decode the length of the block that follows - ssize_t or short fmt.
2064 if (c & (unsigned char) 0x80)
2070 taglen=readWordFromBuffer(&s, &len);
2074 /* make a buffer to hold the tag datand snag it from the input stream */
2075 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
2077 if (str == (unsigned char *) NULL)
2079 printf("MemoryAllocationFailed");
2082 for (tagindx=0; tagindx<taglen; tagindx++)
2087 str[tagindx]=(unsigned char) c;
2091 /* now finish up by formatting this binary data into ASCII equivalent */
2092 if (strlen((char *)readable) > 0)
2093 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
2094 (unsigned int) dataset,(unsigned int) recnum, readable);
2096 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
2097 (unsigned int) dataset,(unsigned int) recnum);
2098 (void) WriteBlobString(ofile,temp);
2099 formatString( ofile, (char *)str, taglen );
2100 str=(unsigned char *) RelinquishMagickMemory(str);
2104 return ((int) tagsfound);
2107 static int format8BIM(Image *ifile, Image *ofile)
2110 temp[MaxTextExtent];
2129 foundOSType=0; /* found the OSType */
2131 c=ReadBlobByte(ifile);
2139 buffer[0]=(unsigned char) c;
2142 c=ReadBlobByte(ifile);
2145 buffer[i] = (unsigned char) c;
2148 if (strcmp((const char *)buffer, "8BIM") == 0)
2155 c=ReadBlobByte(ifile);
2159 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2161 ID=(int) ReadBlobMSBShort(ifile);
2168 c=ReadBlobByte(ifile);
2171 plen = (unsigned char) c;
2172 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2173 MaxTextExtent),sizeof(*PString));
2174 if (PString == (unsigned char *) NULL)
2176 printf("MemoryAllocationFailed");
2179 for (i=0; i<plen; i++)
2181 c=ReadBlobByte(ifile);
2182 if (c == EOF) return -1;
2183 PString[i] = (unsigned char) c;
2185 PString[ plen ] = 0;
2186 if ((plen & 0x01) == 0)
2188 c=ReadBlobByte(ifile);
2193 count = (int) ReadBlobMSBLong(ifile);
2194 if (count < 0) return -1;
2195 /* make a buffer to hold the datand snag it from the input stream */
2196 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str));
2197 if (str == (unsigned char *) NULL)
2199 printf("MemoryAllocationFailed");
2202 for (i=0; i < (ssize_t) count; i++)
2204 c=ReadBlobByte(ifile);
2207 str[i]=(unsigned char) c;
2210 /* we currently skip thumbnails, since it does not make
2211 * any sense preserving them in a real world application
2213 if (ID != THUMBNAIL_ID)
2215 /* now finish up by formatting this binary data into
2218 if (strlen((const char *)PString) > 0)
2219 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d#%s=",ID,
2222 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d=",ID);
2223 (void) WriteBlobString(ofile,temp);
2226 formatString(ofile, "IPTC", 4);
2227 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
2230 formatString(ofile, (char *)str, (ssize_t) count);
2232 str=(unsigned char *) RelinquishMagickMemory(str);
2233 PString=(unsigned char *) RelinquishMagickMemory(PString);
2235 c=ReadBlobByte(ifile);
2240 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2241 Image *image,ExceptionInfo *exception)
2255 assert(image_info != (const ImageInfo *) NULL);
2256 assert(image_info->signature == MagickSignature);
2257 assert(image != (Image *) NULL);
2258 assert(image->signature == MagickSignature);
2259 if (image->debug != MagickFalse)
2260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2262 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2267 profile=GetImageProfile(image,"8bim");
2268 if (profile == (StringInfo *) NULL)
2269 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2270 assert(exception != (ExceptionInfo *) NULL);
2271 assert(exception->signature == MagickSignature);
2272 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2273 if (status == MagickFalse)
2275 (void) WriteBlob(image,GetStringInfoLength(profile),
2276 GetStringInfoDatum(profile));
2277 (void) CloseBlob(image);
2280 if (LocaleCompare(image_info->magick,"iptc") == 0)
2288 profile=GetImageProfile(image,"iptc");
2289 if (profile == (StringInfo *) NULL)
2290 profile=GetImageProfile(image,"8bim");
2291 if (profile == (StringInfo *) NULL)
2292 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2293 assert(exception != (ExceptionInfo *) NULL);
2294 assert(exception->signature == MagickSignature);
2295 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2296 info=GetStringInfoDatum(profile);
2297 length=GetStringInfoLength(profile);
2298 length=GetIPTCStream(&info,length);
2300 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2301 (void) WriteBlob(image,length,info);
2302 (void) CloseBlob(image);
2305 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2310 profile=GetImageProfile(image,"8bim");
2311 if (profile == (StringInfo *) NULL)
2312 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2313 assert(exception != (ExceptionInfo *) NULL);
2314 assert(exception->signature == MagickSignature);
2315 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2316 if (status == MagickFalse)
2318 buff=AcquireImage((ImageInfo *) NULL);
2319 if (buff == (Image *) NULL)
2320 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2321 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2322 GetStringInfoLength(profile));
2323 format8BIM(buff,image);
2324 (void) DetachBlob(buff->blob);
2325 buff=DestroyImage(buff);
2326 (void) CloseBlob(image);
2329 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2330 return(MagickFalse);
2331 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2339 profile=GetImageProfile(image,"8bim");
2340 if (profile == (StringInfo *) NULL)
2341 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2342 info=GetStringInfoDatum(profile);
2343 length=GetStringInfoLength(profile);
2344 length=GetIPTCStream(&info,length);
2346 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2347 assert(exception != (ExceptionInfo *) NULL);
2348 assert(exception->signature == MagickSignature);
2349 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2350 if (status == MagickFalse)
2352 buff=AcquireImage((ImageInfo *) NULL);
2353 if (buff == (Image *) NULL)
2354 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2355 AttachBlob(buff->blob,info,length);
2356 formatIPTC(buff,image);
2357 (void) DetachBlob(buff->blob);
2358 buff=DestroyImage(buff);
2359 (void) CloseBlob(image);
2362 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2363 return(MagickFalse);
2364 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2365 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2366 (LocaleCompare(image_info->magick,"XMP") == 0))
2369 (void) Write APP1 image.
2371 profile=GetImageProfile(image,image_info->magick);
2372 if (profile == (StringInfo *) NULL)
2373 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2374 assert(exception != (ExceptionInfo *) NULL);
2375 assert(exception->signature == MagickSignature);
2376 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2377 if (status == MagickFalse)
2379 (void) WriteBlob(image,GetStringInfoLength(profile),
2380 GetStringInfoDatum(profile));
2381 (void) CloseBlob(image);
2384 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2385 (LocaleCompare(image_info->magick,"ICM") == 0))
2390 profile=GetImageProfile(image,"icc");
2391 if (profile == (StringInfo *) NULL)
2392 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2393 assert(exception != (ExceptionInfo *) NULL);
2394 assert(exception->signature == MagickSignature);
2395 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2396 if (status == MagickFalse)
2398 (void) WriteBlob(image,GetStringInfoLength(profile),
2399 GetStringInfoDatum(profile));
2400 (void) CloseBlob(image);
2403 return(MagickFalse);