2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M EEEEE TTTTT AAA %
13 % Read/Write Embedded Image Profiles. %
20 % Copyright 1999-2015 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/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"
66 static MagickBooleanType
67 WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *);
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 % IsMETA() returns MagickTrue if the image format type, identified by the
81 % magick string, is META.
83 % The format of the IsMETA method is:
85 % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
87 % A description of each parameter follows:
89 % o magick: compare image format pattern against these bytes.
91 % o length: Specifies the length of the magick string.
95 #ifdef IMPLEMENT_IS_FUNCTION
96 static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
100 if (LocaleNCompare((char *) magick,"8BIM",4) == 0)
102 if (LocaleNCompare((char *) magick,"APP1",4) == 0)
104 if (LocaleNCompare((char *) magick,"\034\002",2) == 0)
111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 % R e a d M E T A I m a g e %
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
125 % The format of the ReadMETAImage method is:
127 % Image *ReadMETAImage(const ImageInfo *image_info,
128 % ExceptionInfo *exception)
130 % Decompression code contributed by Kyle Shorter.
132 % A description of each parameter follows:
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.
138 % o image_info: Specifies a pointer to an ImageInfo structure.
140 % o exception: return any errors or warnings in this structure.
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) memmove(s+1,s+1+o,strlen(s+1+o)+1);
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) 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;
241 static char *super_fgets(char **b, int *blen, Image *file)
252 p=(unsigned char *) (*b);
255 c=ReadBlobByte(file);
256 if (c == EOF || c == '\n')
258 if ((q-p+1) >= (int) len)
265 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) len+2UL,sizeof(*p));
267 if (p == (unsigned char *) NULL)
271 *q=(unsigned char) c;
274 if (p != (unsigned char *) NULL)
281 return (char *) NULL;
289 #define THUMBNAIL_ID 1033
291 static ssize_t parse8BIM(Image *ifile, Image *ofile)
312 inputlen = MaxTextExtent;
327 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
328 if (line == (char *) NULL)
330 name = token = (char *) NULL;
332 token_info=AcquireTokenInfo();
333 while (super_fgets(&line,&inputlen,ifile)!=NULL)
338 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
339 if (token == (char *) NULL)
341 newstr=(newstr *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
342 if (newstr == (char *) NULL)
344 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
345 &brkused,&next,"ed)==0)
359 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
360 "", 0,&brkused,&next,"ed)==0)
365 if (strcmp(newstr,"8BIM")==0)
368 dataset = (unsigned char) StringToLong(newstr);
371 recnum = (unsigned int) StringToUnsignedLong(newstr);
374 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
377 (void) strcpy(name,newstr);
397 len = (ssize_t) strlen(token);
398 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
399 "",0,&brkused,&next,"ed)==0)
401 if (brkused && next > 0)
406 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
423 ssize_t diff = outputlen - savedolen;
424 currentpos = TellBlob(ofile);
425 offset=SeekBlob(ofile,savedpos,SEEK_SET);
428 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
429 offset=SeekBlob(ofile,currentpos,SEEK_SET);
436 (void) WriteBlobByte(ofile,0x00);
439 (void) WriteBlobString(ofile,"8BIM");
440 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
443 nlen = (unsigned char) strlen(name);
444 (void) WriteBlobByte(ofile,nlen);
446 for (i=0; i<nlen; i++)
447 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
449 if ((nlen & 0x01) == 0)
451 (void) WriteBlobByte(ofile,0x00);
454 if (recnum != IPTC_ID)
456 (void) WriteBlobMSBLong(ofile, (unsigned int) len);
462 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
466 (void) WriteBlobByte(ofile,0x00);
472 /* patch in a fake length for now and fix it later */
473 savedpos = TellBlob(ofile);
474 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
476 savedolen = outputlen;
483 (void) WriteBlobByte(ofile,0x1c);
484 (void) WriteBlobByte(ofile,(unsigned char) dataset);
485 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
486 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
491 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
497 if (token != (char *) NULL)
498 token=DestroyString(token);
499 if (newstr != (char *) NULL)
500 newstr=DestroyString(newstr);
501 if (name != (char *) NULL)
502 name=DestroyString(name);
504 token_info=DestroyTokenInfo(token_info);
505 line=DestroyString(line);
511 ssize_t diff = outputlen - savedolen;
513 currentpos = TellBlob(ofile);
514 offset=SeekBlob(ofile,savedpos,SEEK_SET);
517 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
518 offset=SeekBlob(ofile,currentpos,SEEK_SET);
526 static char *super_fgets_w(char **b, int *blen, Image *file)
537 p=(unsigned char *) (*b);
540 c=(int) ReadBlobLSBShort(file);
541 if ((c == -1) || (c == '\n'))
545 if ((q-p+1) >= (int) len)
552 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
554 if (p == (unsigned char *) NULL)
558 *q=(unsigned char) c;
561 if ((*b) != (char *) NULL)
568 return (char *) NULL;
575 static ssize_t parse8BIMW(Image *ifile, Image *ofile)
596 inputlen = MaxTextExtent;
611 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
612 if (line == (char *) NULL)
614 name = token = (char *) NULL;
616 token_info=AcquireTokenInfo();
617 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
622 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
623 if (token == (char *) NULL)
625 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
626 if (newstr == (char *) NULL)
628 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
629 &brkused,&next,"ed)==0)
643 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
644 "",0,&brkused,&next,"ed)==0)
649 if (strcmp(newstr,"8BIM")==0)
652 dataset = (unsigned char) StringToLong(newstr);
655 recnum=(unsigned int) StringToUnsignedLong(newstr);
658 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
661 (void) CopyMagickString(name,newstr,strlen(newstr)+MaxTextExtent);
681 len = (ssize_t) strlen(token);
682 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
683 "",0,&brkused,&next,"ed)==0)
685 if (brkused && next > 0)
690 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
707 ssize_t diff = outputlen - savedolen;
708 currentpos = TellBlob(ofile);
709 offset=SeekBlob(ofile,savedpos,SEEK_SET);
712 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
713 offset=SeekBlob(ofile,currentpos,SEEK_SET);
720 (void) WriteBlobByte(ofile,0x00);
723 (void) WriteBlobString(ofile,"8BIM");
724 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
727 nlen = (unsigned char) strlen(name);
728 (void) WriteBlobByte(ofile,(unsigned char) nlen);
730 for (i=0; i<nlen; i++)
731 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
733 if ((nlen & 0x01) == 0)
735 (void) WriteBlobByte(ofile,0x00);
738 if (recnum != IPTC_ID)
740 (void) WriteBlobMSBLong(ofile,(unsigned int) len);
746 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
750 (void) WriteBlobByte(ofile,0x00);
756 /* patch in a fake length for now and fix it later */
757 savedpos = TellBlob(ofile);
758 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
760 savedolen = outputlen;
767 (void) WriteBlobByte(ofile,0x1c);
768 (void) WriteBlobByte(ofile,dataset);
769 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
770 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
775 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
781 if (token != (char *) NULL)
782 token=DestroyString(token);
783 if (newstr != (char *) NULL)
784 newstr=DestroyString(newstr);
785 if (name != (char *) NULL)
786 name=DestroyString(name);
788 token_info=DestroyTokenInfo(token_info);
789 line=DestroyString(line);
795 ssize_t diff = outputlen - savedolen;
797 currentpos = TellBlob(ofile);
798 offset=SeekBlob(ofile,savedpos,SEEK_SET);
801 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
802 offset=SeekBlob(ofile,currentpos,SEEK_SET);
810 /* some defines for the different JPEG block types */
811 #define M_SOF0 0xC0 /* Start Of Frame N */
812 #define M_SOF1 0xC1 /* N indicates which compression process */
813 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
815 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
825 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
826 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
844 static int jpeg_transfer_1(Image *ifile, Image *ofile)
848 c = ReadBlobByte(ifile);
851 (void) WriteBlobByte(ofile,(unsigned char) c);
856 static int jpeg_skip_1(Image *ifile)
860 c = ReadBlobByte(ifile);
867 static int jpeg_read_remaining(Image *ifile, Image *ofile)
871 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
876 static int jpeg_skip_variable(Image *ifile, Image *ofile)
881 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
883 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
886 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
890 if (jpeg_transfer_1(ifile, ofile) == EOF)
896 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
902 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
903 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
905 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
909 if (ReadBlobByte(ifile) == EOF)
915 static int jpeg_nextmarker(Image *ifile, Image *ofile)
919 /* transfer anything until we hit 0xff */
922 c = ReadBlobByte(ifile);
924 return M_EOI; /* we hit EOF */
927 (void) WriteBlobByte(ofile,(unsigned char) c);
930 /* get marker byte, swallowing possible padding */
933 c = ReadBlobByte(ifile);
935 return M_EOI; /* we hit EOF */
942 static int jpeg_skip_till_marker(Image *ifile, int marker)
948 /* skip anything until we hit 0xff */
952 c = ReadBlobByte(ifile);
955 return M_EOI; /* we hit EOF */
958 /* get marker byte, swallowing possible padding */
961 c = ReadBlobByte(ifile);
963 return M_EOI; /* we hit EOF */
965 } while (c != marker);
970 /* Embed binary IPTC data into a JPEG image. */
971 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
974 unsigned int done = 0;
978 if (jpeg_transfer_1(ifile, ofile) != 0xFF)
980 if (jpeg_transfer_1(ifile, ofile) != M_SOI)
983 while (done == MagickFalse)
985 marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
992 if (marker != M_APP13)
994 (void) WriteBlobByte(ofile,0xff);
995 (void) WriteBlobByte(ofile,(unsigned char) marker);
1002 /* we are going to write a new APP13 marker, so don't output the old one */
1003 jpeg_skip_variable2(ifile, ofile);
1007 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
1008 jpeg_skip_variable(ifile, ofile);
1010 if (iptc != (Image *) NULL)
1013 psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0";
1015 len=(unsigned int) GetBlobSize(iptc);
1017 len++; /* make the length even */
1018 psheader[2]=(char) ((len+16)>>8);
1019 psheader[3]=(char) ((len+16)&0xff);
1020 for (inx = 0; inx < 18; inx++)
1021 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1022 jpeg_read_remaining(iptc, ofile);
1023 len=(unsigned int) GetBlobSize(iptc);
1025 (void) WriteBlobByte(ofile,0);
1030 /* we hit data, no more marker-inserting can be done! */
1031 jpeg_read_remaining(ifile, ofile);
1036 jpeg_skip_variable(ifile, ofile);
1043 /* handle stripping the APP13 data out of a JPEG */
1045 static void jpeg_strip(Image *ifile, Image *ofile)
1047 unsigned int marker;
1049 marker = jpeg_skip_till_marker(ifile, M_SOI);
1050 if (marker == M_SOI)
1052 (void) WriteBlobByte(ofile,0xff);
1053 (void) WriteBlobByte(ofile,M_SOI);
1054 jpeg_read_remaining(ifile, ofile);
1058 /* Extract any APP13 binary data into a file. */
1059 static int jpeg_extract(Image *ifile, Image *ofile)
1061 unsigned int marker;
1062 unsigned int done = 0;
1064 if (jpeg_skip_1(ifile) != 0xff)
1066 if (jpeg_skip_1(ifile) != M_SOI)
1069 while (done == MagickFalse)
1071 marker = jpeg_skip_till_marker(ifile, M_APP13);
1072 if (marker == M_APP13)
1074 marker = jpeg_nextmarker(ifile, ofile);
1082 static inline void CopyBlob(Image *source,Image *destination)
1094 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1096 if (buffer != (unsigned char *) NULL)
1099 while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0)
1102 for (i=0; i < (ssize_t) length; i+=count)
1104 count=WriteBlob(destination,(size_t) (length-i),buffer+i);
1108 if (i < (ssize_t) length)
1111 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1115 static Image *ReadMETAImage(const ImageInfo *image_info,
1116 ExceptionInfo *exception)
1135 Open file containing binary metadata
1137 assert(image_info != (const ImageInfo *) NULL);
1138 assert(image_info->signature == MagickSignature);
1139 if (image_info->debug != MagickFalse)
1140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1141 image_info->filename);
1142 assert(exception != (ExceptionInfo *) NULL);
1143 assert(exception->signature == MagickSignature);
1144 image=AcquireImage(image_info,exception);
1145 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1146 if (status == MagickFalse)
1148 image=DestroyImageList(image);
1149 return((Image *) NULL);
1153 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1155 image=DestroyImageList(image);
1156 return((Image *) NULL);
1159 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1162 Read 8BIM binary metadata.
1164 buff=AcquireImage((ImageInfo *) NULL,exception);
1165 if (buff == (Image *) NULL)
1166 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1167 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1168 if (blob == (unsigned char *) NULL)
1170 buff=DestroyImage(buff);
1171 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1173 AttachBlob(buff->blob,blob,length);
1174 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1176 length=(size_t) parse8BIM(image, buff);
1178 (void) WriteBlobByte(buff,0x0);
1180 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1182 length=(size_t) parse8BIMW(image, buff);
1184 (void) WriteBlobByte(buff,0x0);
1187 CopyBlob(image,buff);
1188 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1190 if (profile == (StringInfo *) NULL)
1191 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1192 status=SetImageProfile(image,"8bim",profile,exception);
1193 profile=DestroyStringInfo(profile);
1194 if (status == MagickFalse)
1195 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1196 blob=DetachBlob(buff->blob);
1197 blob=(unsigned char *) RelinquishMagickMemory(blob);
1198 buff=DestroyImage(buff);
1200 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1203 name[MaxTextExtent];
1205 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",1);
1206 buff=AcquireImage((ImageInfo *) NULL,exception);
1207 if (buff == (Image *) NULL)
1208 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1209 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1210 if (blob == (unsigned char *) NULL)
1212 buff=DestroyImage(buff);
1213 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1215 AttachBlob(buff->blob,blob,length);
1216 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1224 if (image_info->profile == (void *) NULL)
1226 blob=DetachBlob(buff->blob);
1227 blob=RelinquishMagickMemory(blob);
1228 buff=DestroyImage(buff);
1229 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1231 profile=CloneStringInfo((StringInfo *) image_info->profile);
1232 iptc=AcquireImage((ImageInfo *) NULL,exception);
1233 if (iptc == (Image *) NULL)
1235 blob=DetachBlob(buff->blob);
1236 blob=RelinquishMagickMemory(blob);
1237 buff=DestroyImage(buff);
1238 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1240 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1241 GetStringInfoLength(profile));
1242 result=jpeg_embed(image,buff,iptc);
1243 blob=DetachBlob(iptc->blob);
1244 blob=RelinquishMagickMemory(blob);
1245 iptc=DestroyImage(iptc);
1248 blob=DetachBlob(buff->blob);
1249 blob=RelinquishMagickMemory(blob);
1250 buff=DestroyImage(buff);
1251 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1255 CopyBlob(image,buff);
1256 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1258 if (profile == (StringInfo *) NULL)
1259 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1260 status=SetImageProfile(image,name,profile,exception);
1261 profile=DestroyStringInfo(profile);
1262 if (status == MagickFalse)
1263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264 blob=DetachBlob(buff->blob);
1265 blob=RelinquishMagickMemory(blob);
1266 buff=DestroyImage(buff);
1268 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1269 (LocaleCompare(image_info->magick,"ICM") == 0))
1271 buff=AcquireImage((ImageInfo *) NULL,exception);
1272 if (buff == (Image *) NULL)
1273 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1274 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1275 if (blob == (unsigned char *) NULL)
1277 buff=DestroyImage(buff);
1278 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1280 AttachBlob(buff->blob,blob,length);
1281 CopyBlob(image,buff);
1282 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1284 if (profile == (StringInfo *) NULL)
1285 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1286 (void) SetImageProfile(image,"icc",profile,exception);
1287 profile=DestroyStringInfo(profile);
1288 blob=DetachBlob(buff->blob);
1289 blob=(unsigned char *) RelinquishMagickMemory(blob);
1290 buff=DestroyImage(buff);
1292 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1294 buff=AcquireImage((ImageInfo *) NULL,exception);
1295 if (buff == (Image *) NULL)
1296 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1297 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1298 if (blob == (unsigned char *) NULL)
1300 buff=DestroyImage(buff);
1301 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1303 AttachBlob(buff->blob,blob,length);
1304 CopyBlob(image,buff);
1305 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1307 if (profile == (StringInfo *) NULL)
1308 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1309 (void) SetImageProfile(image,"8bim",profile,exception);
1310 profile=DestroyStringInfo(profile);
1311 blob=DetachBlob(buff->blob);
1312 blob=(unsigned char *) RelinquishMagickMemory(blob);
1313 buff=DestroyImage(buff);
1315 if (LocaleCompare(image_info->magick,"XMP") == 0)
1317 buff=AcquireImage((ImageInfo *) NULL,exception);
1318 if (buff == (Image *) NULL)
1319 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1320 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1321 if (blob == (unsigned char *) NULL)
1323 buff=DestroyImage(buff);
1324 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1326 AttachBlob(buff->blob,blob,length);
1327 CopyBlob(image,buff);
1328 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1330 if (profile == (StringInfo *) NULL)
1331 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1332 (void) SetImageProfile(image,"xmp",profile,exception);
1333 profile=DestroyStringInfo(profile);
1334 blob=DetachBlob(buff->blob);
1335 blob=(unsigned char *) RelinquishMagickMemory(blob);
1336 buff=DestroyImage(buff);
1338 (void) CloseBlob(image);
1339 return(GetFirstImageInList(image));
1343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % R e g i s t e r M E T A I m a g e %
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 % RegisterMETAImage() adds attributes for the META image format to
1354 % the list of supported formats. The attributes include the image format
1355 % tag, a method to read and/or write the format, whether the format
1356 % supports the saving of more than one frame to the same file or blob,
1357 % whether the format supports native in-memory I/O, and a brief
1358 % description of the format.
1360 % The format of the RegisterMETAImage method is:
1362 % size_t RegisterMETAImage(void)
1365 ModuleExport size_t RegisterMETAImage(void)
1370 entry=SetMagickInfo("8BIM");
1371 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1372 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1373 entry->flags^=CoderAdjoinFlag;
1374 entry->flags|=CoderStealthFlag;
1375 entry->flags|=CoderSeekableStreamFlag;
1376 entry->description=ConstantString("Photoshop resource format");
1377 entry->module=ConstantString("META");
1378 (void) RegisterMagickInfo(entry);
1379 entry=SetMagickInfo("8BIMTEXT");
1380 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1381 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1382 entry->flags^=CoderAdjoinFlag;
1383 entry->flags|=CoderStealthFlag;
1384 entry->flags|=CoderSeekableStreamFlag;
1385 entry->description=ConstantString("Photoshop resource text format");
1386 entry->module=ConstantString("META");
1387 (void) RegisterMagickInfo(entry);
1388 entry=SetMagickInfo("8BIMWTEXT");
1389 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1390 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1391 entry->flags^=CoderAdjoinFlag;
1392 entry->flags|=CoderStealthFlag;
1393 entry->flags|=CoderSeekableStreamFlag;
1394 entry->description=ConstantString("Photoshop resource wide text format");
1395 entry->module=ConstantString("META");
1396 (void) RegisterMagickInfo(entry);
1397 entry=SetMagickInfo("APP1");
1398 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1399 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1400 entry->flags^=CoderAdjoinFlag;
1401 entry->flags|=CoderStealthFlag;
1402 entry->flags|=CoderSeekableStreamFlag;
1403 entry->description=ConstantString("Raw application information");
1404 entry->module=ConstantString("META");
1405 (void) RegisterMagickInfo(entry);
1406 entry=SetMagickInfo("APP1JPEG");
1407 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1408 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1409 entry->flags^=CoderAdjoinFlag;
1410 entry->flags|=CoderStealthFlag;
1411 entry->flags|=CoderSeekableStreamFlag;
1412 entry->description=ConstantString("Raw JPEG binary data");
1413 entry->module=ConstantString("META");
1414 (void) RegisterMagickInfo(entry);
1415 entry=SetMagickInfo("EXIF");
1416 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1417 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1418 entry->flags^=CoderAdjoinFlag;
1419 entry->flags|=CoderStealthFlag;
1420 entry->flags|=CoderSeekableStreamFlag;
1421 entry->description=ConstantString("Exif digital camera binary data");
1422 entry->module=ConstantString("META");
1423 (void) RegisterMagickInfo(entry);
1424 entry=SetMagickInfo("XMP");
1425 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1426 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1427 entry->flags^=CoderAdjoinFlag;
1428 entry->flags|=CoderStealthFlag;
1429 entry->flags|=CoderSeekableStreamFlag;
1430 entry->description=ConstantString("Adobe XML metadata");
1431 entry->module=ConstantString("META");
1432 (void) RegisterMagickInfo(entry);
1433 entry=SetMagickInfo("ICM");
1434 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1435 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1436 entry->flags^=CoderAdjoinFlag;
1437 entry->flags|=CoderStealthFlag;
1438 entry->flags|=CoderSeekableStreamFlag;
1439 entry->description=ConstantString("ICC Color Profile");
1440 entry->module=ConstantString("META");
1441 (void) RegisterMagickInfo(entry);
1442 entry=SetMagickInfo("ICC");
1443 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1444 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1445 entry->flags^=CoderAdjoinFlag;
1446 entry->flags|=CoderStealthFlag;
1447 entry->flags|=CoderSeekableStreamFlag;
1448 entry->description=ConstantString("ICC Color Profile");
1449 entry->module=ConstantString("META");
1450 (void) RegisterMagickInfo(entry);
1451 entry=SetMagickInfo("IPTC");
1452 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1453 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1454 entry->flags^=CoderAdjoinFlag;
1455 entry->flags|=CoderStealthFlag;
1456 entry->flags|=CoderSeekableStreamFlag;
1457 entry->description=ConstantString("IPTC Newsphoto");
1458 entry->module=ConstantString("META");
1459 (void) RegisterMagickInfo(entry);
1460 entry=SetMagickInfo("IPTCTEXT");
1461 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1462 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1463 entry->flags^=CoderAdjoinFlag;
1464 entry->flags|=CoderStealthFlag;
1465 entry->flags|=CoderSeekableStreamFlag;
1466 entry->description=ConstantString("IPTC Newsphoto text format");
1467 entry->module=ConstantString("META");
1468 (void) RegisterMagickInfo(entry);
1469 entry=SetMagickInfo("IPTCWTEXT");
1470 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1471 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1472 entry->flags^=CoderAdjoinFlag;
1473 entry->flags|=CoderStealthFlag;
1474 entry->flags|=CoderSeekableStreamFlag;
1475 entry->description=ConstantString("IPTC Newsphoto text format");
1476 entry->module=ConstantString("META");
1477 (void) RegisterMagickInfo(entry);
1478 return(MagickImageCoderSignature);
1482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486 % U n r e g i s t e r M E T A I m a g e %
1490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1492 % UnregisterMETAImage() removes format registrations made by the
1493 % META module from the list of supported formats.
1495 % The format of the UnregisterMETAImage method is:
1497 % UnregisterMETAImage(void)
1500 ModuleExport void UnregisterMETAImage(void)
1502 (void) UnregisterMagickInfo("8BIM");
1503 (void) UnregisterMagickInfo("8BIMTEXT");
1504 (void) UnregisterMagickInfo("8BIMWTEXT");
1505 (void) UnregisterMagickInfo("EXIF");
1506 (void) UnregisterMagickInfo("APP1");
1507 (void) UnregisterMagickInfo("APP1JPEG");
1508 (void) UnregisterMagickInfo("ICCTEXT");
1509 (void) UnregisterMagickInfo("ICM");
1510 (void) UnregisterMagickInfo("ICC");
1511 (void) UnregisterMagickInfo("IPTC");
1512 (void) UnregisterMagickInfo("IPTCTEXT");
1513 (void) UnregisterMagickInfo("IPTCWTEXT");
1514 (void) UnregisterMagickInfo("XMP");
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 % W r i t e M E T A I m a g e %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % WriteMETAImage() writes a META image to a file.
1530 % The format of the WriteMETAImage method is:
1532 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1533 % Image *image,ExceptionInfo *exception)
1535 % Compression code contributed by Kyle Shorter.
1537 % A description of each parameter follows:
1539 % o image_info: Specifies a pointer to an ImageInfo structure.
1541 % o image: A pointer to a Image structure.
1543 % o exception: return any errors or warnings in this structure.
1547 static size_t GetIPTCStream(unsigned char **info,size_t length)
1555 register unsigned char
1570 if ((*p == 0x1c) && (*(p+1) == 0x02))
1573 Extract IPTC from 8BIM resource block.
1575 while (extent >= 12)
1577 if (strncmp((const char *) p,"8BIM",4))
1581 marker=(unsigned int) (*p) << 8 | *(p+1);
1587 if ((size_t) c >= extent)
1593 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
1594 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
1597 if (tag_length > extent)
1599 if (marker == IPTC_ID)
1604 if ((tag_length & 0x01) != 0)
1610 Find the beginning of the IPTC info.
1626 *info=p; /* let the caller know were it is */
1631 Determine the length of the IPTC info.
1648 Found the 0x1c tag; skip the dataset and record number tags.
1650 c=(*p++); /* should be 2 */
1654 if ((info_length == 1) && (c != 2))
1657 c=(*p++); /* should be 0 */
1661 if ((info_length == 2) && (c != 0))
1665 Decode the length of the block that follows - ssize_t or short format.
1672 if ((c & 0x80) != 0)
1678 for (i=0; i < 4; i++)
1693 tag_length=((long) c) << 8;
1699 tag_length|=(long) c;
1701 if (tag_length > (length+1))
1707 info_length+=tag_length;
1709 return(info_length);
1712 static void formatString(Image *ofile, const char *s, int len)
1715 temp[MaxTextExtent];
1717 (void) WriteBlobByte(ofile,'"');
1718 for (; len > 0; len--, s++) {
1722 (void) WriteBlobString(ofile,"&");
1726 (void) WriteBlobString(ofile,"<");
1729 (void) WriteBlobString(ofile,">");
1733 (void) WriteBlobString(ofile,""");
1737 (void) WriteBlobByte(ofile,(unsigned char) *s);
1740 (void) FormatLocaleString(temp,MaxTextExtent,"&#%d;", c & 255);
1741 (void) WriteBlobString(ofile,temp);
1746 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1747 (void) WriteBlobString(ofile,"\"\r\n");
1749 #if defined(macintosh)
1750 (void) WriteBlobString(ofile,"\"\r");
1752 (void) WriteBlobString(ofile,"\"\n");
1757 typedef struct _tag_spec
1766 static const tag_spec tags[] = {
1767 { 5, "Image Name" },
1768 { 7, "Edit Status" },
1771 { 20, "Supplemental Category" },
1772 { 22, "Fixture Identifier" },
1774 { 30, "Release Date" },
1775 { 35, "Release Time" },
1776 { 40, "Special Instructions" },
1777 { 45, "Reference Service" },
1778 { 47, "Reference Date" },
1779 { 50, "Reference Number" },
1780 { 55, "Created Date" },
1781 { 60, "Created Time" },
1782 { 65, "Originating Program" },
1783 { 70, "Program Version" },
1784 { 75, "Object Cycle" },
1786 { 85, "Byline Title" },
1788 { 95, "Province State" },
1789 { 100, "Country Code" },
1791 { 103, "Original Transmission Reference" },
1792 { 105, "Headline" },
1795 { 116, "Copyright String" },
1797 { 121, "Image Orientation" },
1798 { 122, "Caption Writer" },
1799 { 131, "Local Caption" },
1800 { 200, "Custom Field 1" },
1801 { 201, "Custom Field 2" },
1802 { 202, "Custom Field 3" },
1803 { 203, "Custom Field 4" },
1804 { 204, "Custom Field 5" },
1805 { 205, "Custom Field 6" },
1806 { 206, "Custom Field 7" },
1807 { 207, "Custom Field 8" },
1808 { 208, "Custom Field 9" },
1809 { 209, "Custom Field 10" },
1810 { 210, "Custom Field 11" },
1811 { 211, "Custom Field 12" },
1812 { 212, "Custom Field 13" },
1813 { 213, "Custom Field 14" },
1814 { 214, "Custom Field 15" },
1815 { 215, "Custom Field 16" },
1816 { 216, "Custom Field 17" },
1817 { 217, "Custom Field 18" },
1818 { 218, "Custom Field 19" },
1819 { 219, "Custom Field 20" }
1822 static int formatIPTC(Image *ifile, Image *ofile)
1825 temp[MaxTextExtent];
1845 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1850 foundiptc = 0; /* found the IPTC-Header */
1851 tagsfound = 0; /* number of tags found */
1853 c = ReadBlobByte(ifile);
1869 /* we found the 0x1c tag and now grab the dataset and record number tags */
1870 c = ReadBlobByte(ifile);
1871 if (c == EOF) return -1;
1872 dataset = (unsigned char) c;
1873 c = ReadBlobByte(ifile);
1874 if (c == EOF) return -1;
1875 recnum = (unsigned char) c;
1876 /* try to match this record to one of the ones in our named table */
1877 for (i=0; i< tagcount; i++)
1879 if (tags[i].id == (short) recnum)
1883 readable = (unsigned char *) tags[i].name;
1885 readable = (unsigned char *) "";
1887 We decode the length of the block that follows - ssize_t or short fmt.
1889 c=ReadBlobByte(ifile);
1890 if (c == EOF) return -1;
1891 if (c & (unsigned char) 0x80)
1898 c0=ReadBlobByte(ifile);
1899 if (c0 == EOF) return -1;
1900 taglen = (c << 8) | c0;
1902 if (taglen < 0) return -1;
1903 /* make a buffer to hold the tag datand snag it from the input stream */
1904 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
1906 if (str == (unsigned char *) NULL)
1908 printf("MemoryAllocationFailed");
1911 for (tagindx=0; tagindx<taglen; tagindx++)
1913 c=ReadBlobByte(ifile);
1914 if (c == EOF) return -1;
1915 str[tagindx] = (unsigned char) c;
1919 /* now finish up by formatting this binary data into ASCII equivalent */
1920 if (strlen((char *)readable) > 0)
1921 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
1922 (unsigned int) dataset, (unsigned int) recnum, readable);
1924 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
1925 (unsigned int) dataset,(unsigned int) recnum);
1926 (void) WriteBlobString(ofile,temp);
1927 formatString( ofile, (char *)str, taglen );
1928 str=(unsigned char *) RelinquishMagickMemory(str);
1932 c=ReadBlobByte(ifile);
1934 return((int) tagsfound);
1937 static int readWordFromBuffer(char **s, ssize_t *len)
1948 c = *(*s)++; (*len)--;
1949 if (*len < 0) return -1;
1950 buffer[i] = (unsigned char) c;
1952 return (((int) buffer[ 0 ]) << 8) |
1953 (((int) buffer[ 1 ]));
1956 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
1959 temp[MaxTextExtent];
1979 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1984 foundiptc = 0; /* found the IPTC-Header */
1985 tagsfound = 0; /* number of tags found */
2000 We found the 0x1c tag and now grab the dataset and record number tags.
2003 if (len < 0) return -1;
2004 dataset = (unsigned char) c;
2006 if (len < 0) return -1;
2007 recnum = (unsigned char) c;
2008 /* try to match this record to one of the ones in our named table */
2009 for (i=0; i< tagcount; i++)
2010 if (tags[i].id == (short) recnum)
2013 readable=(unsigned char *) tags[i].name;
2015 readable=(unsigned char *) "";
2017 We decode the length of the block that follows - ssize_t or short fmt.
2023 if (c & (unsigned char) 0x80)
2029 taglen=readWordFromBuffer(&s, &len);
2035 /* make a buffer to hold the tag datand snag it from the input stream */
2036 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
2038 if (str == (unsigned char *) NULL)
2040 printf("MemoryAllocationFailed");
2043 for (tagindx=0; tagindx<taglen; tagindx++)
2048 str[tagindx]=(unsigned char) c;
2052 /* now finish up by formatting this binary data into ASCII equivalent */
2053 if (strlen((char *)readable) > 0)
2054 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
2055 (unsigned int) dataset,(unsigned int) recnum, readable);
2057 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
2058 (unsigned int) dataset,(unsigned int) recnum);
2059 (void) WriteBlobString(ofile,temp);
2060 formatString( ofile, (char *)str, taglen );
2061 str=(unsigned char *) RelinquishMagickMemory(str);
2065 return ((int) tagsfound);
2068 static int format8BIM(Image *ifile, Image *ofile)
2071 temp[MaxTextExtent];
2090 foundOSType=0; /* found the OSType */
2092 c=ReadBlobByte(ifile);
2100 buffer[0]=(unsigned char) c;
2103 c=ReadBlobByte(ifile);
2106 buffer[i] = (unsigned char) c;
2109 if (strcmp((const char *)buffer, "8BIM") == 0)
2116 c=ReadBlobByte(ifile);
2120 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2122 ID=(int) ReadBlobMSBShort(ifile);
2129 c=ReadBlobByte(ifile);
2132 plen = (unsigned char) c;
2133 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2134 MaxTextExtent),sizeof(*PString));
2135 if (PString == (unsigned char *) NULL)
2137 printf("MemoryAllocationFailed");
2140 for (i=0; i<plen; i++)
2142 c=ReadBlobByte(ifile);
2143 if (c == EOF) return -1;
2144 PString[i] = (unsigned char) c;
2146 PString[ plen ] = 0;
2147 if ((plen & 0x01) == 0)
2149 c=ReadBlobByte(ifile);
2154 count = (int) ReadBlobMSBLong(ifile);
2155 if (count < 0) return -1;
2156 /* make a buffer to hold the datand snag it from the input stream */
2157 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str));
2158 if (str == (unsigned char *) NULL)
2160 printf("MemoryAllocationFailed");
2163 for (i=0; i < (ssize_t) count; i++)
2165 c=ReadBlobByte(ifile);
2168 str[i]=(unsigned char) c;
2171 /* we currently skip thumbnails, since it does not make
2172 * any sense preserving them in a real world application
2174 if (ID != THUMBNAIL_ID)
2176 /* now finish up by formatting this binary data into
2179 if (strlen((const char *)PString) > 0)
2180 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d#%s=",ID,
2183 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d=",ID);
2184 (void) WriteBlobString(ofile,temp);
2187 formatString(ofile, "IPTC", 4);
2188 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
2191 formatString(ofile, (char *)str, (ssize_t) count);
2193 str=(unsigned char *) RelinquishMagickMemory(str);
2194 PString=(unsigned char *) RelinquishMagickMemory(PString);
2196 c=ReadBlobByte(ifile);
2201 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2202 Image *image,ExceptionInfo *exception)
2216 assert(image_info != (const ImageInfo *) NULL);
2217 assert(image_info->signature == MagickSignature);
2218 assert(image != (Image *) NULL);
2219 assert(image->signature == MagickSignature);
2220 if (image->debug != MagickFalse)
2221 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2223 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2228 profile=GetImageProfile(image,"8bim");
2229 if (profile == (StringInfo *) NULL)
2230 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2231 assert(exception != (ExceptionInfo *) NULL);
2232 assert(exception->signature == MagickSignature);
2233 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2234 if (status == MagickFalse)
2236 (void) WriteBlob(image,GetStringInfoLength(profile),
2237 GetStringInfoDatum(profile));
2238 (void) CloseBlob(image);
2241 if (LocaleCompare(image_info->magick,"iptc") == 0)
2249 profile=GetImageProfile(image,"iptc");
2250 if (profile == (StringInfo *) NULL)
2251 profile=GetImageProfile(image,"8bim");
2252 if (profile == (StringInfo *) NULL)
2253 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2254 assert(exception != (ExceptionInfo *) NULL);
2255 assert(exception->signature == MagickSignature);
2256 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2257 info=GetStringInfoDatum(profile);
2258 length=GetStringInfoLength(profile);
2259 length=GetIPTCStream(&info,length);
2261 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2262 (void) WriteBlob(image,length,info);
2263 (void) CloseBlob(image);
2266 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2271 profile=GetImageProfile(image,"8bim");
2272 if (profile == (StringInfo *) NULL)
2273 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2274 assert(exception != (ExceptionInfo *) NULL);
2275 assert(exception->signature == MagickSignature);
2276 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2277 if (status == MagickFalse)
2279 buff=AcquireImage((ImageInfo *) NULL,exception);
2280 if (buff == (Image *) NULL)
2281 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2282 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2283 GetStringInfoLength(profile));
2284 format8BIM(buff,image);
2285 (void) DetachBlob(buff->blob);
2286 buff=DestroyImage(buff);
2287 (void) CloseBlob(image);
2290 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2291 return(MagickFalse);
2292 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2300 profile=GetImageProfile(image,"8bim");
2301 if (profile == (StringInfo *) NULL)
2302 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2303 info=GetStringInfoDatum(profile);
2304 length=GetStringInfoLength(profile);
2305 length=GetIPTCStream(&info,length);
2307 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2308 assert(exception != (ExceptionInfo *) NULL);
2309 assert(exception->signature == MagickSignature);
2310 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2311 if (status == MagickFalse)
2313 buff=AcquireImage((ImageInfo *) NULL,exception);
2314 if (buff == (Image *) NULL)
2315 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2316 AttachBlob(buff->blob,info,length);
2317 formatIPTC(buff,image);
2318 (void) DetachBlob(buff->blob);
2319 buff=DestroyImage(buff);
2320 (void) CloseBlob(image);
2323 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2324 return(MagickFalse);
2325 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2326 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2327 (LocaleCompare(image_info->magick,"XMP") == 0))
2330 (void) Write APP1 image.
2332 profile=GetImageProfile(image,image_info->magick);
2333 if (profile == (StringInfo *) NULL)
2334 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2335 assert(exception != (ExceptionInfo *) NULL);
2336 assert(exception->signature == MagickSignature);
2337 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2338 if (status == MagickFalse)
2340 (void) WriteBlob(image,GetStringInfoLength(profile),
2341 GetStringInfoDatum(profile));
2342 (void) CloseBlob(image);
2345 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2346 (LocaleCompare(image_info->magick,"ICM") == 0))
2351 profile=GetImageProfile(image,"icc");
2352 if (profile == (StringInfo *) NULL)
2353 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2354 assert(exception != (ExceptionInfo *) NULL);
2355 assert(exception->signature == MagickSignature);
2356 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2357 if (status == MagickFalse)
2359 (void) WriteBlob(image,GetStringInfoLength(profile),
2360 GetStringInfoDatum(profile));
2361 (void) CloseBlob(image);
2364 return(MagickFalse);