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.
143 #define BUFFER_SZ 4096
145 typedef struct _html_code
154 static html_code html_codes[] = {
164 static int stringnicmp(const char *p,const char *q,size_t n)
172 if (p == (char *) NULL)
174 if (q == (char *) NULL)
176 while ((*p != '\0') && (*q != '\0'))
178 if ((*p == '\0') || (*q == '\0'))
194 return(toupper((int) *p)-toupper((int) *q));
197 static int convertHTMLcodes(char *s, int len)
199 if (len <=0 || s==(char*) NULL || *s=='\0')
206 if (sscanf(s,"&#%d;",&val) == 1)
216 (void) strcpy(s+1,s+1+o);
225 codes = (int) (sizeof(html_codes) / sizeof(html_code));
227 for (i=0; i < codes; i++)
229 if (html_codes[i].len <= len)
230 if (stringnicmp(s,html_codes[i].code,(size_t) html_codes[i].len) == 0)
232 (void) strcpy(s+1,s+html_codes[i].len);
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;
288 #define BUFFER_SZ 4096
290 #define THUMBNAIL_ID 1033
292 static ssize_t parse8BIM(Image *ifile, Image *ofile)
313 inputlen = BUFFER_SZ;
328 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
329 name = token = (char *) NULL;
331 token_info=AcquireTokenInfo();
332 while (super_fgets(&line,&inputlen,ifile)!=NULL)
337 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
338 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
339 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
340 &brkused,&next,"ed)==0)
354 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
355 "", 0,&brkused,&next,"ed)==0)
360 if (strcmp(newstr,"8BIM")==0)
363 dataset = (unsigned char) StringToLong(newstr);
366 recnum = (unsigned int) StringToUnsignedLong(newstr);
369 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
372 (void) strcpy(name,newstr);
392 len = (ssize_t) strlen(token);
393 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
394 "",0,&brkused,&next,"ed)==0)
396 if (brkused && next > 0)
401 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
418 ssize_t diff = outputlen - savedolen;
419 currentpos = TellBlob(ofile);
420 offset=SeekBlob(ofile,savedpos,SEEK_SET);
423 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
424 offset=SeekBlob(ofile,currentpos,SEEK_SET);
431 (void) WriteBlobByte(ofile,0x00);
434 (void) WriteBlobString(ofile,"8BIM");
435 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
438 nlen = (unsigned char) strlen(name);
439 (void) WriteBlobByte(ofile,nlen);
441 for (i=0; i<nlen; i++)
442 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
444 if ((nlen & 0x01) == 0)
446 (void) WriteBlobByte(ofile,0x00);
449 if (recnum != IPTC_ID)
451 (void) WriteBlobMSBLong(ofile, (unsigned int) len);
457 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
461 (void) WriteBlobByte(ofile,0x00);
467 /* patch in a fake length for now and fix it later */
468 savedpos = TellBlob(ofile);
469 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
471 savedolen = outputlen;
478 (void) WriteBlobByte(ofile,0x1c);
479 (void) WriteBlobByte(ofile,(unsigned char) dataset);
480 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
481 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
486 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
492 token=DestroyString(token);
493 newstr=DestroyString(newstr);
494 if (name != (char *) NULL)
495 name=DestroyString(name);
497 token_info=DestroyTokenInfo(token_info);
498 line=DestroyString(line);
504 ssize_t diff = outputlen - savedolen;
506 currentpos = TellBlob(ofile);
507 offset=SeekBlob(ofile,savedpos,SEEK_SET);
510 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
511 offset=SeekBlob(ofile,currentpos,SEEK_SET);
519 static char *super_fgets_w(char **b, int *blen, Image *file)
530 p=(unsigned char *) (*b);
533 c=(int) ReadBlobLSBShort(file);
534 if ((c == -1) || (c == '\n'))
538 if ((q-p+1) >= (int) len)
545 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
547 if (p == (unsigned char *) NULL)
551 *q=(unsigned char) c;
554 if ((*b) != (char *) NULL)
561 return (char *) NULL;
568 static ssize_t parse8BIMW(Image *ifile, Image *ofile)
589 inputlen = BUFFER_SZ;
604 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
605 name = token = (char *) NULL;
607 token_info=AcquireTokenInfo();
608 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
613 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
614 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
615 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
616 &brkused,&next,"ed)==0)
630 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
631 "",0,&brkused,&next,"ed)==0)
636 if (strcmp(newstr,"8BIM")==0)
639 dataset = (unsigned char) StringToLong(newstr);
642 recnum=(unsigned int) StringToUnsignedLong(newstr);
645 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
648 (void) CopyMagickString(name,newstr,strlen(newstr)+MaxTextExtent);
668 len = (ssize_t) strlen(token);
669 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
670 "",0,&brkused,&next,"ed)==0)
672 if (brkused && next > 0)
677 len -= (ssize_t) convertHTMLcodes(s,(int) strlen(s));
694 ssize_t diff = outputlen - savedolen;
695 currentpos = TellBlob(ofile);
696 offset=SeekBlob(ofile,savedpos,SEEK_SET);
699 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
700 offset=SeekBlob(ofile,currentpos,SEEK_SET);
707 (void) WriteBlobByte(ofile,0x00);
710 (void) WriteBlobString(ofile,"8BIM");
711 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
714 nlen = (unsigned char) strlen(name);
715 (void) WriteBlobByte(ofile,(unsigned char) nlen);
717 for (i=0; i<nlen; i++)
718 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
720 if ((nlen & 0x01) == 0)
722 (void) WriteBlobByte(ofile,0x00);
725 if (recnum != IPTC_ID)
727 (void) WriteBlobMSBLong(ofile,(unsigned int) len);
733 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
737 (void) WriteBlobByte(ofile,0x00);
743 /* patch in a fake length for now and fix it later */
744 savedpos = TellBlob(ofile);
745 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
747 savedolen = outputlen;
754 (void) WriteBlobByte(ofile,0x1c);
755 (void) WriteBlobByte(ofile,dataset);
756 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
757 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
762 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
768 token=DestroyString(token);
769 newstr=DestroyString(newstr);
770 name=DestroyString(name);
772 token_info=DestroyTokenInfo(token_info);
773 line=DestroyString(line);
779 ssize_t diff = outputlen - savedolen;
781 currentpos = TellBlob(ofile);
782 offset=SeekBlob(ofile,savedpos,SEEK_SET);
785 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
786 offset=SeekBlob(ofile,currentpos,SEEK_SET);
794 /* some defines for the different JPEG block types */
795 #define M_SOF0 0xC0 /* Start Of Frame N */
796 #define M_SOF1 0xC1 /* N indicates which compression process */
797 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
799 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
809 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
810 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
828 static int jpeg_transfer_1(Image *ifile, Image *ofile)
832 c = ReadBlobByte(ifile);
835 (void) WriteBlobByte(ofile,(unsigned char) c);
840 static int jpeg_skip_1(Image *ifile)
844 c = ReadBlobByte(ifile);
851 static int jpeg_read_remaining(Image *ifile, Image *ofile)
855 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
860 static int jpeg_skip_variable(Image *ifile, Image *ofile)
865 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
867 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
870 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
874 if (jpeg_transfer_1(ifile, ofile) == EOF)
880 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
886 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
887 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
889 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
893 if (ReadBlobByte(ifile) == EOF)
899 static int jpeg_nextmarker(Image *ifile, Image *ofile)
903 /* transfer anything until we hit 0xff */
906 c = ReadBlobByte(ifile);
908 return M_EOI; /* we hit EOF */
911 (void) WriteBlobByte(ofile,(unsigned char) c);
914 /* get marker byte, swallowing possible padding */
917 c = ReadBlobByte(ifile);
919 return M_EOI; /* we hit EOF */
926 static int jpeg_skip_till_marker(Image *ifile, int marker)
932 /* skip anything until we hit 0xff */
936 c = ReadBlobByte(ifile);
939 return M_EOI; /* we hit EOF */
942 /* get marker byte, swallowing possible padding */
945 c = ReadBlobByte(ifile);
947 return M_EOI; /* we hit EOF */
949 } while (c != marker);
954 /* Embed binary IPTC data into a JPEG image. */
955 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
958 unsigned int done = 0;
962 if (jpeg_transfer_1(ifile, ofile) != 0xFF)
964 if (jpeg_transfer_1(ifile, ofile) != M_SOI)
967 while (done == MagickFalse)
969 marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
976 if (marker != M_APP13)
978 (void) WriteBlobByte(ofile,0xff);
979 (void) WriteBlobByte(ofile,(unsigned char) marker);
986 /* we are going to write a new APP13 marker, so don't output the old one */
987 jpeg_skip_variable2(ifile, ofile);
991 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
992 jpeg_skip_variable(ifile, ofile);
994 if (iptc != (Image *) NULL)
997 psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0";
999 len=(unsigned int) GetBlobSize(iptc);
1001 len++; /* make the length even */
1002 psheader[2]=(char) ((len+16)>>8);
1003 psheader[3]=(char) ((len+16)&0xff);
1004 for (inx = 0; inx < 18; inx++)
1005 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1006 jpeg_read_remaining(iptc, ofile);
1007 len=(unsigned int) GetBlobSize(iptc);
1009 (void) WriteBlobByte(ofile,0);
1014 /* we hit data, no more marker-inserting can be done! */
1015 jpeg_read_remaining(ifile, ofile);
1020 jpeg_skip_variable(ifile, ofile);
1027 /* handle stripping the APP13 data out of a JPEG */
1029 static void jpeg_strip(Image *ifile, Image *ofile)
1031 unsigned int marker;
1033 marker = jpeg_skip_till_marker(ifile, M_SOI);
1034 if (marker == M_SOI)
1036 (void) WriteBlobByte(ofile,0xff);
1037 (void) WriteBlobByte(ofile,M_SOI);
1038 jpeg_read_remaining(ifile, ofile);
1042 /* Extract any APP13 binary data into a file. */
1043 static int jpeg_extract(Image *ifile, Image *ofile)
1045 unsigned int marker;
1046 unsigned int done = 0;
1048 if (jpeg_skip_1(ifile) != 0xff)
1050 if (jpeg_skip_1(ifile) != M_SOI)
1053 while (done == MagickFalse)
1055 marker = jpeg_skip_till_marker(ifile, M_APP13);
1056 if (marker == M_APP13)
1058 marker = jpeg_nextmarker(ifile, ofile);
1066 static inline void CopyBlob(Image *source,Image *destination)
1078 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1080 if (buffer != (unsigned char *) NULL)
1083 while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0)
1086 for (i=0; i < (ssize_t) length; i+=count)
1088 count=WriteBlob(destination,(size_t) (length-i),buffer+i);
1092 if (i < (ssize_t) length)
1095 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1099 static Image *ReadMETAImage(const ImageInfo *image_info,
1100 ExceptionInfo *exception)
1119 Open file containing binary metadata
1121 assert(image_info != (const ImageInfo *) NULL);
1122 assert(image_info->signature == MagickSignature);
1123 if (image_info->debug != MagickFalse)
1124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1125 image_info->filename);
1126 assert(exception != (ExceptionInfo *) NULL);
1127 assert(exception->signature == MagickSignature);
1128 image=AcquireImage(image_info,exception);
1129 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1130 if (status == MagickFalse)
1132 image=DestroyImageList(image);
1133 return((Image *) NULL);
1137 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1139 image=DestroyImageList(image);
1140 return((Image *) NULL);
1143 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1146 Read 8BIM binary metadata.
1148 buff=AcquireImage((ImageInfo *) NULL,exception);
1149 if (buff == (Image *) NULL)
1150 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1151 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1152 if (blob == (unsigned char *) NULL)
1154 buff=DestroyImage(buff);
1155 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1157 AttachBlob(buff->blob,blob,length);
1158 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1160 length=(size_t) parse8BIM(image, buff);
1162 (void) WriteBlobByte(buff,0x0);
1164 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1166 length=(size_t) parse8BIMW(image, buff);
1168 (void) WriteBlobByte(buff,0x0);
1171 CopyBlob(image,buff);
1172 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1174 if (profile == (StringInfo *) NULL)
1175 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1176 status=SetImageProfile(image,"8bim",profile,exception);
1177 profile=DestroyStringInfo(profile);
1178 if (status == MagickFalse)
1179 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1180 blob=DetachBlob(buff->blob);
1181 blob=(unsigned char *) RelinquishMagickMemory(blob);
1182 buff=DestroyImage(buff);
1184 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1187 name[MaxTextExtent];
1189 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",1);
1190 buff=AcquireImage((ImageInfo *) NULL,exception);
1191 if (buff == (Image *) NULL)
1192 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1193 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1194 if (blob == (unsigned char *) NULL)
1196 buff=DestroyImage(buff);
1197 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1199 AttachBlob(buff->blob,blob,length);
1200 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1208 if (image_info->profile == (void *) NULL)
1210 blob=DetachBlob(buff->blob);
1211 blob=RelinquishMagickMemory(blob);
1212 buff=DestroyImage(buff);
1213 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1215 profile=CloneStringInfo((StringInfo *) image_info->profile);
1216 iptc=AcquireImage((ImageInfo *) NULL,exception);
1217 if (iptc == (Image *) NULL)
1219 blob=DetachBlob(buff->blob);
1220 blob=RelinquishMagickMemory(blob);
1221 buff=DestroyImage(buff);
1222 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1224 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1225 GetStringInfoLength(profile));
1226 result=jpeg_embed(image,buff,iptc);
1227 blob=DetachBlob(iptc->blob);
1228 blob=RelinquishMagickMemory(blob);
1229 iptc=DestroyImage(iptc);
1232 blob=DetachBlob(buff->blob);
1233 blob=RelinquishMagickMemory(blob);
1234 buff=DestroyImage(buff);
1235 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1239 CopyBlob(image,buff);
1240 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1242 if (profile == (StringInfo *) NULL)
1243 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1244 status=SetImageProfile(image,name,profile,exception);
1245 profile=DestroyStringInfo(profile);
1246 if (status == MagickFalse)
1247 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1248 blob=DetachBlob(buff->blob);
1249 blob=RelinquishMagickMemory(blob);
1250 buff=DestroyImage(buff);
1252 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1253 (LocaleCompare(image_info->magick,"ICM") == 0))
1255 buff=AcquireImage((ImageInfo *) NULL,exception);
1256 if (buff == (Image *) NULL)
1257 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1258 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1259 if (blob == (unsigned char *) NULL)
1261 buff=DestroyImage(buff);
1262 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264 AttachBlob(buff->blob,blob,length);
1265 CopyBlob(image,buff);
1266 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1268 if (profile == (StringInfo *) NULL)
1269 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1270 (void) SetImageProfile(image,"icc",profile,exception);
1271 profile=DestroyStringInfo(profile);
1272 blob=DetachBlob(buff->blob);
1273 blob=(unsigned char *) RelinquishMagickMemory(blob);
1274 buff=DestroyImage(buff);
1276 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1278 buff=AcquireImage((ImageInfo *) NULL,exception);
1279 if (buff == (Image *) NULL)
1280 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1281 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1282 if (blob == (unsigned char *) NULL)
1284 buff=DestroyImage(buff);
1285 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1287 AttachBlob(buff->blob,blob,length);
1288 CopyBlob(image,buff);
1289 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1291 if (profile == (StringInfo *) NULL)
1292 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1293 (void) SetImageProfile(image,"8bim",profile,exception);
1294 profile=DestroyStringInfo(profile);
1295 blob=DetachBlob(buff->blob);
1296 blob=(unsigned char *) RelinquishMagickMemory(blob);
1297 buff=DestroyImage(buff);
1299 if (LocaleCompare(image_info->magick,"XMP") == 0)
1301 buff=AcquireImage((ImageInfo *) NULL,exception);
1302 if (buff == (Image *) NULL)
1303 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1304 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1305 if (blob == (unsigned char *) NULL)
1307 buff=DestroyImage(buff);
1308 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1310 AttachBlob(buff->blob,blob,length);
1311 CopyBlob(image,buff);
1312 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1314 if (profile == (StringInfo *) NULL)
1315 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1316 (void) SetImageProfile(image,"xmp",profile,exception);
1317 profile=DestroyStringInfo(profile);
1318 blob=DetachBlob(buff->blob);
1319 blob=(unsigned char *) RelinquishMagickMemory(blob);
1320 buff=DestroyImage(buff);
1322 (void) CloseBlob(image);
1323 return(GetFirstImageInList(image));
1327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331 % R e g i s t e r M E T A I m a g e %
1335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337 % RegisterMETAImage() adds attributes for the META image format to
1338 % the list of supported formats. The attributes include the image format
1339 % tag, a method to read and/or write the format, whether the format
1340 % supports the saving of more than one frame to the same file or blob,
1341 % whether the format supports native in-memory I/O, and a brief
1342 % description of the format.
1344 % The format of the RegisterMETAImage method is:
1346 % size_t RegisterMETAImage(void)
1349 ModuleExport size_t RegisterMETAImage(void)
1354 entry=SetMagickInfo("8BIM");
1355 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1356 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1357 entry->adjoin=MagickFalse;
1358 entry->stealth=MagickTrue;
1359 entry->seekable_stream=MagickTrue;
1360 entry->description=ConstantString("Photoshop resource format");
1361 entry->module=ConstantString("META");
1362 (void) RegisterMagickInfo(entry);
1363 entry=SetMagickInfo("8BIMTEXT");
1364 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1365 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1366 entry->adjoin=MagickFalse;
1367 entry->stealth=MagickTrue;
1368 entry->seekable_stream=MagickTrue;
1369 entry->description=ConstantString("Photoshop resource text format");
1370 entry->module=ConstantString("META");
1371 (void) RegisterMagickInfo(entry);
1372 entry=SetMagickInfo("8BIMWTEXT");
1373 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1374 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1375 entry->adjoin=MagickFalse;
1376 entry->stealth=MagickTrue;
1377 entry->seekable_stream=MagickTrue;
1378 entry->description=ConstantString("Photoshop resource wide text format");
1379 entry->module=ConstantString("META");
1380 (void) RegisterMagickInfo(entry);
1381 entry=SetMagickInfo("APP1");
1382 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1383 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1384 entry->adjoin=MagickFalse;
1385 entry->stealth=MagickTrue;
1386 entry->seekable_stream=MagickTrue;
1387 entry->description=ConstantString("Raw application information");
1388 entry->module=ConstantString("META");
1389 (void) RegisterMagickInfo(entry);
1390 entry=SetMagickInfo("APP1JPEG");
1391 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1392 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1393 entry->adjoin=MagickFalse;
1394 entry->stealth=MagickTrue;
1395 entry->seekable_stream=MagickTrue;
1396 entry->description=ConstantString("Raw JPEG binary data");
1397 entry->module=ConstantString("META");
1398 (void) RegisterMagickInfo(entry);
1399 entry=SetMagickInfo("EXIF");
1400 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1401 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1402 entry->adjoin=MagickFalse;
1403 entry->stealth=MagickTrue;
1404 entry->seekable_stream=MagickTrue;
1405 entry->description=ConstantString("Exif digital camera binary data");
1406 entry->module=ConstantString("META");
1407 (void) RegisterMagickInfo(entry);
1408 entry=SetMagickInfo("XMP");
1409 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1410 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1411 entry->adjoin=MagickFalse;
1412 entry->stealth=MagickTrue;
1413 entry->seekable_stream=MagickTrue;
1414 entry->description=ConstantString("Adobe XML metadata");
1415 entry->module=ConstantString("META");
1416 (void) RegisterMagickInfo(entry);
1417 entry=SetMagickInfo("ICM");
1418 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1419 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1420 entry->adjoin=MagickFalse;
1421 entry->stealth=MagickTrue;
1422 entry->seekable_stream=MagickTrue;
1423 entry->description=ConstantString("ICC Color Profile");
1424 entry->module=ConstantString("META");
1425 (void) RegisterMagickInfo(entry);
1426 entry=SetMagickInfo("ICC");
1427 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1428 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1429 entry->adjoin=MagickFalse;
1430 entry->stealth=MagickTrue;
1431 entry->seekable_stream=MagickTrue;
1432 entry->description=ConstantString("ICC Color Profile");
1433 entry->module=ConstantString("META");
1434 (void) RegisterMagickInfo(entry);
1435 entry=SetMagickInfo("IPTC");
1436 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1437 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1438 entry->adjoin=MagickFalse;
1439 entry->stealth=MagickTrue;
1440 entry->seekable_stream=MagickTrue;
1441 entry->description=ConstantString("IPTC Newsphoto");
1442 entry->module=ConstantString("META");
1443 (void) RegisterMagickInfo(entry);
1444 entry=SetMagickInfo("IPTCTEXT");
1445 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1446 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1447 entry->adjoin=MagickFalse;
1448 entry->stealth=MagickTrue;
1449 entry->seekable_stream=MagickTrue;
1450 entry->description=ConstantString("IPTC Newsphoto text format");
1451 entry->module=ConstantString("META");
1452 (void) RegisterMagickInfo(entry);
1453 entry=SetMagickInfo("IPTCWTEXT");
1454 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1455 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1456 entry->adjoin=MagickFalse;
1457 entry->stealth=MagickTrue;
1458 entry->seekable_stream=MagickTrue;
1459 entry->description=ConstantString("IPTC Newsphoto text format");
1460 entry->module=ConstantString("META");
1461 (void) RegisterMagickInfo(entry);
1462 return(MagickImageCoderSignature);
1466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470 % U n r e g i s t e r M E T A I m a g e %
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476 % UnregisterMETAImage() removes format registrations made by the
1477 % META module from the list of supported formats.
1479 % The format of the UnregisterMETAImage method is:
1481 % UnregisterMETAImage(void)
1484 ModuleExport void UnregisterMETAImage(void)
1486 (void) UnregisterMagickInfo("8BIM");
1487 (void) UnregisterMagickInfo("8BIMTEXT");
1488 (void) UnregisterMagickInfo("8BIMWTEXT");
1489 (void) UnregisterMagickInfo("EXIF");
1490 (void) UnregisterMagickInfo("APP1");
1491 (void) UnregisterMagickInfo("APP1JPEG");
1492 (void) UnregisterMagickInfo("ICCTEXT");
1493 (void) UnregisterMagickInfo("ICM");
1494 (void) UnregisterMagickInfo("ICC");
1495 (void) UnregisterMagickInfo("IPTC");
1496 (void) UnregisterMagickInfo("IPTCTEXT");
1497 (void) UnregisterMagickInfo("IPTCWTEXT");
1498 (void) UnregisterMagickInfo("XMP");
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 % W r i t e M E T A I m a g e %
1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % WriteMETAImage() writes a META image to a file.
1514 % The format of the WriteMETAImage method is:
1516 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1517 % Image *image,ExceptionInfo *exception)
1519 % Compression code contributed by Kyle Shorter.
1521 % A description of each parameter follows:
1523 % o image_info: Specifies a pointer to an ImageInfo structure.
1525 % o image: A pointer to a Image structure.
1527 % o exception: return any errors or warnings in this structure.
1531 static size_t GetIPTCStream(unsigned char **info,size_t length)
1539 register unsigned char
1554 if ((*p == 0x1c) && (*(p+1) == 0x02))
1557 Extract IPTC from 8BIM resource block.
1559 while (extent >= 12)
1561 if (strncmp((const char *) p,"8BIM",4))
1565 marker=(unsigned int) (*p) << 8 | *(p+1);
1571 if ((size_t) c >= extent)
1577 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
1578 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
1581 if (tag_length > extent)
1583 if (marker == IPTC_ID)
1588 if ((tag_length & 0x01) != 0)
1594 Find the beginning of the IPTC info.
1610 *info=p; /* let the caller know were it is */
1615 Determine the length of the IPTC info.
1632 Found the 0x1c tag; skip the dataset and record number tags.
1634 c=(*p++); /* should be 2 */
1638 if ((info_length == 1) && (c != 2))
1641 c=(*p++); /* should be 0 */
1645 if ((info_length == 2) && (c != 0))
1649 Decode the length of the block that follows - ssize_t or short format.
1656 if ((c & 0x80) != 0)
1662 for (i=0; i < 4; i++)
1677 tag_length=((long) c) << 8;
1683 tag_length|=(long) c;
1685 if (tag_length > (length+1))
1691 info_length+=tag_length;
1693 return(info_length);
1696 static void formatString(Image *ofile, const char *s, int len)
1699 temp[MaxTextExtent];
1701 (void) WriteBlobByte(ofile,'"');
1702 for (; len > 0; len--, s++) {
1706 (void) WriteBlobString(ofile,"&");
1710 (void) WriteBlobString(ofile,"<");
1713 (void) WriteBlobString(ofile,">");
1717 (void) WriteBlobString(ofile,""");
1721 (void) WriteBlobByte(ofile,(unsigned char) *s);
1724 (void) FormatLocaleString(temp,MaxTextExtent,"&#%d;", c & 255);
1725 (void) WriteBlobString(ofile,temp);
1730 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1731 (void) WriteBlobString(ofile,"\"\r\n");
1733 #if defined(macintosh)
1734 (void) WriteBlobString(ofile,"\"\r");
1736 (void) WriteBlobString(ofile,"\"\n");
1741 typedef struct _tag_spec
1750 static const tag_spec tags[] = {
1751 { 5, "Image Name" },
1752 { 7, "Edit Status" },
1755 { 20, "Supplemental Category" },
1756 { 22, "Fixture Identifier" },
1758 { 30, "Release Date" },
1759 { 35, "Release Time" },
1760 { 40, "Special Instructions" },
1761 { 45, "Reference Service" },
1762 { 47, "Reference Date" },
1763 { 50, "Reference Number" },
1764 { 55, "Created Date" },
1765 { 60, "Created Time" },
1766 { 65, "Originating Program" },
1767 { 70, "Program Version" },
1768 { 75, "Object Cycle" },
1770 { 85, "Byline Title" },
1772 { 95, "Province State" },
1773 { 100, "Country Code" },
1775 { 103, "Original Transmission Reference" },
1776 { 105, "Headline" },
1779 { 116, "Copyright String" },
1781 { 121, "Image Orientation" },
1782 { 122, "Caption Writer" },
1783 { 131, "Local Caption" },
1784 { 200, "Custom Field 1" },
1785 { 201, "Custom Field 2" },
1786 { 202, "Custom Field 3" },
1787 { 203, "Custom Field 4" },
1788 { 204, "Custom Field 5" },
1789 { 205, "Custom Field 6" },
1790 { 206, "Custom Field 7" },
1791 { 207, "Custom Field 8" },
1792 { 208, "Custom Field 9" },
1793 { 209, "Custom Field 10" },
1794 { 210, "Custom Field 11" },
1795 { 211, "Custom Field 12" },
1796 { 212, "Custom Field 13" },
1797 { 213, "Custom Field 14" },
1798 { 214, "Custom Field 15" },
1799 { 215, "Custom Field 16" },
1800 { 216, "Custom Field 17" },
1801 { 217, "Custom Field 18" },
1802 { 218, "Custom Field 19" },
1803 { 219, "Custom Field 20" }
1806 static int formatIPTC(Image *ifile, Image *ofile)
1809 temp[MaxTextExtent];
1829 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1834 foundiptc = 0; /* found the IPTC-Header */
1835 tagsfound = 0; /* number of tags found */
1837 c = ReadBlobByte(ifile);
1853 /* we found the 0x1c tag and now grab the dataset and record number tags */
1854 c = ReadBlobByte(ifile);
1855 if (c == EOF) return -1;
1856 dataset = (unsigned char) c;
1857 c = ReadBlobByte(ifile);
1858 if (c == EOF) return -1;
1859 recnum = (unsigned char) c;
1860 /* try to match this record to one of the ones in our named table */
1861 for (i=0; i< tagcount; i++)
1863 if (tags[i].id == (short) recnum)
1867 readable = (unsigned char *) tags[i].name;
1869 readable = (unsigned char *) "";
1871 We decode the length of the block that follows - ssize_t or short fmt.
1873 c=ReadBlobByte(ifile);
1874 if (c == EOF) return -1;
1875 if (c & (unsigned char) 0x80)
1882 c0=ReadBlobByte(ifile);
1883 if (c0 == EOF) return -1;
1884 taglen = (c << 8) | c0;
1886 if (taglen < 0) return -1;
1887 /* make a buffer to hold the tag datand snag it from the input stream */
1888 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
1890 if (str == (unsigned char *) NULL)
1892 printf("MemoryAllocationFailed");
1895 for (tagindx=0; tagindx<taglen; tagindx++)
1897 c=ReadBlobByte(ifile);
1898 if (c == EOF) return -1;
1899 str[tagindx] = (unsigned char) c;
1903 /* now finish up by formatting this binary data into ASCII equivalent */
1904 if (strlen((char *)readable) > 0)
1905 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
1906 (unsigned int) dataset, (unsigned int) recnum, readable);
1908 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
1909 (unsigned int) dataset,(unsigned int) recnum);
1910 (void) WriteBlobString(ofile,temp);
1911 formatString( ofile, (char *)str, taglen );
1912 str=(unsigned char *) RelinquishMagickMemory(str);
1916 c=ReadBlobByte(ifile);
1918 return((int) tagsfound);
1921 static int readWordFromBuffer(char **s, ssize_t *len)
1932 c = *(*s)++; (*len)--;
1933 if (*len < 0) return -1;
1934 buffer[i] = (unsigned char) c;
1936 return (((int) buffer[ 0 ]) << 8) |
1937 (((int) buffer[ 1 ]));
1940 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
1943 temp[MaxTextExtent];
1963 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1968 foundiptc = 0; /* found the IPTC-Header */
1969 tagsfound = 0; /* number of tags found */
1984 We found the 0x1c tag and now grab the dataset and record number tags.
1987 if (len < 0) return -1;
1988 dataset = (unsigned char) c;
1990 if (len < 0) return -1;
1991 recnum = (unsigned char) c;
1992 /* try to match this record to one of the ones in our named table */
1993 for (i=0; i< tagcount; i++)
1994 if (tags[i].id == (short) recnum)
1997 readable=(unsigned char *) tags[i].name;
1999 readable=(unsigned char *) "";
2001 We decode the length of the block that follows - ssize_t or short fmt.
2007 if (c & (unsigned char) 0x80)
2013 taglen=readWordFromBuffer(&s, &len);
2019 /* make a buffer to hold the tag datand snag it from the input stream */
2020 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
2022 if (str == (unsigned char *) NULL)
2024 printf("MemoryAllocationFailed");
2027 for (tagindx=0; tagindx<taglen; tagindx++)
2032 str[tagindx]=(unsigned char) c;
2036 /* now finish up by formatting this binary data into ASCII equivalent */
2037 if (strlen((char *)readable) > 0)
2038 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d#%s=",
2039 (unsigned int) dataset,(unsigned int) recnum, readable);
2041 (void) FormatLocaleString(temp,MaxTextExtent,"%d#%d=",
2042 (unsigned int) dataset,(unsigned int) recnum);
2043 (void) WriteBlobString(ofile,temp);
2044 formatString( ofile, (char *)str, taglen );
2045 str=(unsigned char *) RelinquishMagickMemory(str);
2049 return ((int) tagsfound);
2052 static int format8BIM(Image *ifile, Image *ofile)
2055 temp[MaxTextExtent];
2074 foundOSType=0; /* found the OSType */
2076 c=ReadBlobByte(ifile);
2084 buffer[0]=(unsigned char) c;
2087 c=ReadBlobByte(ifile);
2090 buffer[i] = (unsigned char) c;
2093 if (strcmp((const char *)buffer, "8BIM") == 0)
2100 c=ReadBlobByte(ifile);
2104 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2106 ID=(int) ReadBlobMSBShort(ifile);
2113 c=ReadBlobByte(ifile);
2116 plen = (unsigned char) c;
2117 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2118 MaxTextExtent),sizeof(*PString));
2119 if (PString == (unsigned char *) NULL)
2121 printf("MemoryAllocationFailed");
2124 for (i=0; i<plen; i++)
2126 c=ReadBlobByte(ifile);
2127 if (c == EOF) return -1;
2128 PString[i] = (unsigned char) c;
2130 PString[ plen ] = 0;
2131 if ((plen & 0x01) == 0)
2133 c=ReadBlobByte(ifile);
2138 count = (int) ReadBlobMSBLong(ifile);
2139 if (count < 0) return -1;
2140 /* make a buffer to hold the datand snag it from the input stream */
2141 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str));
2142 if (str == (unsigned char *) NULL)
2144 printf("MemoryAllocationFailed");
2147 for (i=0; i < (ssize_t) count; i++)
2149 c=ReadBlobByte(ifile);
2152 str[i]=(unsigned char) c;
2155 /* we currently skip thumbnails, since it does not make
2156 * any sense preserving them in a real world application
2158 if (ID != THUMBNAIL_ID)
2160 /* now finish up by formatting this binary data into
2163 if (strlen((const char *)PString) > 0)
2164 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d#%s=",ID,
2167 (void) FormatLocaleString(temp,MaxTextExtent,"8BIM#%d=",ID);
2168 (void) WriteBlobString(ofile,temp);
2171 formatString(ofile, "IPTC", 4);
2172 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
2175 formatString(ofile, (char *)str, (ssize_t) count);
2177 str=(unsigned char *) RelinquishMagickMemory(str);
2178 PString=(unsigned char *) RelinquishMagickMemory(PString);
2180 c=ReadBlobByte(ifile);
2185 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2186 Image *image,ExceptionInfo *exception)
2200 assert(image_info != (const ImageInfo *) NULL);
2201 assert(image_info->signature == MagickSignature);
2202 assert(image != (Image *) NULL);
2203 assert(image->signature == MagickSignature);
2204 if (image->debug != MagickFalse)
2205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2207 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2212 profile=GetImageProfile(image,"8bim");
2213 if (profile == (StringInfo *) NULL)
2214 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2215 assert(exception != (ExceptionInfo *) NULL);
2216 assert(exception->signature == MagickSignature);
2217 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2218 if (status == MagickFalse)
2220 (void) WriteBlob(image,GetStringInfoLength(profile),
2221 GetStringInfoDatum(profile));
2222 (void) CloseBlob(image);
2225 if (LocaleCompare(image_info->magick,"iptc") == 0)
2233 profile=GetImageProfile(image,"iptc");
2234 if (profile == (StringInfo *) NULL)
2235 profile=GetImageProfile(image,"8bim");
2236 if (profile == (StringInfo *) NULL)
2237 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2238 assert(exception != (ExceptionInfo *) NULL);
2239 assert(exception->signature == MagickSignature);
2240 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2241 info=GetStringInfoDatum(profile);
2242 length=GetStringInfoLength(profile);
2243 length=GetIPTCStream(&info,length);
2245 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2246 (void) WriteBlob(image,length,info);
2247 (void) CloseBlob(image);
2250 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2255 profile=GetImageProfile(image,"8bim");
2256 if (profile == (StringInfo *) NULL)
2257 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2258 assert(exception != (ExceptionInfo *) NULL);
2259 assert(exception->signature == MagickSignature);
2260 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2261 if (status == MagickFalse)
2263 buff=AcquireImage((ImageInfo *) NULL,exception);
2264 if (buff == (Image *) NULL)
2265 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2266 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2267 GetStringInfoLength(profile));
2268 format8BIM(buff,image);
2269 (void) DetachBlob(buff->blob);
2270 buff=DestroyImage(buff);
2271 (void) CloseBlob(image);
2274 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2275 return(MagickFalse);
2276 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2284 profile=GetImageProfile(image,"8bim");
2285 if (profile == (StringInfo *) NULL)
2286 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2287 info=GetStringInfoDatum(profile);
2288 length=GetStringInfoLength(profile);
2289 length=GetIPTCStream(&info,length);
2291 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2292 assert(exception != (ExceptionInfo *) NULL);
2293 assert(exception->signature == MagickSignature);
2294 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2295 if (status == MagickFalse)
2297 buff=AcquireImage((ImageInfo *) NULL,exception);
2298 if (buff == (Image *) NULL)
2299 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2300 AttachBlob(buff->blob,info,length);
2301 formatIPTC(buff,image);
2302 (void) DetachBlob(buff->blob);
2303 buff=DestroyImage(buff);
2304 (void) CloseBlob(image);
2307 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2308 return(MagickFalse);
2309 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2310 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2311 (LocaleCompare(image_info->magick,"XMP") == 0))
2314 (void) Write APP1 image.
2316 profile=GetImageProfile(image,image_info->magick);
2317 if (profile == (StringInfo *) NULL)
2318 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2319 assert(exception != (ExceptionInfo *) NULL);
2320 assert(exception->signature == MagickSignature);
2321 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2322 if (status == MagickFalse)
2324 (void) WriteBlob(image,GetStringInfoLength(profile),
2325 GetStringInfoDatum(profile));
2326 (void) CloseBlob(image);
2329 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2330 (LocaleCompare(image_info->magick,"ICM") == 0))
2335 profile=GetImageProfile(image,"icc");
2336 if (profile == (StringInfo *) NULL)
2337 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2338 assert(exception != (ExceptionInfo *) NULL);
2339 assert(exception->signature == MagickSignature);
2340 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2341 if (status == MagickFalse)
2343 (void) WriteBlob(image,GetStringInfoLength(profile),
2344 GetStringInfoDatum(profile));
2345 (void) CloseBlob(image);
2348 return(MagickFalse);