2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M EEEEE TTTTT AAA %
13 % Read/Write Embedded Image Profiles. %
20 % Copyright 1999-2009 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 "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/exception.h"
46 #include "magick/exception-private.h"
47 #include "magick/image.h"
48 #include "magick/image-private.h"
49 #include "magick/list.h"
50 #include "magick/magick.h"
51 #include "magick/memory_.h"
52 #include "magick/profile.h"
53 #include "magick/splay-tree.h"
54 #include "magick/quantum-private.h"
55 #include "magick/static.h"
56 #include "magick/string_.h"
57 #include "magick/module.h"
58 #include "magick/token.h"
59 #include "magick/utility.h"
64 static MagickBooleanType
65 WriteMETAImage(const ImageInfo *,Image *);
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78 % IsMETA() returns MagickTrue if the image format type, identified by the
79 % magick string, is META.
81 % The format of the IsMETA method is:
83 % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
85 % A description of each parameter follows:
87 % o magick: compare image format pattern against these bytes.
89 % o length: Specifies the length of the magick string.
93 #ifdef IMPLEMENT_IS_FUNCTION
94 static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
98 if (LocaleNCompare((char *) magick,"8BIM",4) == 0)
100 if (LocaleNCompare((char *) magick,"APP1",4) == 0)
102 if (LocaleNCompare((char *) magick,"\034\002",2) == 0)
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 % R e a d M E T A I m a g e %
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119 % ReadMETAImage() reads a META image file and returns it. It
120 % allocates the memory necessary for the new Image structure and returns a
121 % pointer to the new image.
123 % The format of the ReadMETAImage method is:
125 % Image *ReadMETAImage(const ImageInfo *image_info,
126 % ExceptionInfo *exception)
128 % Decompression code contributed by Kyle Shorter.
130 % A description of each parameter follows:
132 % o image: Method ReadMETAImage returns a pointer to the image after
133 % reading. A null image is returned if there is a memory shortage or
134 % if the image cannot be read.
136 % o image_info: Specifies a pointer to an ImageInfo structure.
138 % o exception: return any errors or warnings in this structure.
141 #define BUFFER_SZ 4096
143 typedef struct _html_code
152 static html_code html_codes[] = {
162 static int stringnicmp(const char *p,const char *q,size_t n)
170 if (p == (char *) NULL)
172 if (q == (char *) NULL)
174 while ((*p != '\0') && (*q != '\0'))
176 if ((*p == '\0') || (*q == '\0'))
192 return(toupper((int) *p)-toupper((int) *q));
195 static int convertHTMLcodes(char *s, int len)
197 if (len <=0 || s==(char*)NULL || *s=='\0')
204 if (sscanf(s,"&#%d;",&val) == 1)
214 (void) strcpy(s+1,s+1+o);
223 codes = (int) (sizeof(html_codes) / sizeof(html_code));
225 for (i=0; i < codes; i++)
227 if (html_codes[i].len <= len)
228 if (stringnicmp(s,html_codes[i].code,(size_t) html_codes[i].len) == 0)
230 (void) strcpy(s+1,s+html_codes[i].len);
231 *s = html_codes[i].val;
232 return html_codes[i].len-1;
239 static char *super_fgets(char **b, int *blen, Image *file)
250 p=(unsigned char *) (*b);
253 c=ReadBlobByte(file);
254 if (c == EOF || c == '\n')
256 if ((q-p+1) >= (int) len)
263 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) len+2UL,sizeof(*p));
265 if (p == (unsigned char *) NULL)
269 *q=(unsigned char) c;
272 if (p != (unsigned char *) NULL)
279 return (char *) NULL;
286 #define BUFFER_SZ 4096
288 #define THUMBNAIL_ID 1033
290 static long parse8BIM(Image *ifile, Image *ofile)
311 inputlen = BUFFER_SZ;
326 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
327 name = token = (char *)NULL;
329 token_info=AcquireTokenInfo();
330 while (super_fgets(&line,&inputlen,ifile)!=NULL)
335 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
336 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
337 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
338 &brkused,&next,"ed)==0)
352 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
353 "", 0,&brkused,&next,"ed)==0)
358 if (strcmp(newstr,"8BIM")==0)
361 dataset = (unsigned char) atoi(newstr);
364 recnum = (unsigned int) atoi(newstr);
367 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
370 (void) strcpy(name,newstr);
390 len = (long) strlen(token);
391 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
392 "",0,&brkused,&next,"ed)==0)
394 if (brkused && next > 0)
399 len -= (long) convertHTMLcodes(s,(int) strlen(s));
416 long diff = outputlen - savedolen;
417 currentpos = TellBlob(ofile);
418 offset=SeekBlob(ofile,savedpos,SEEK_SET);
421 (void) WriteBlobMSBLong(ofile,(unsigned long) diff);
422 offset=SeekBlob(ofile,currentpos,SEEK_SET);
429 (void) WriteBlobByte(ofile,0x00);
432 (void) WriteBlobString(ofile,"8BIM");
433 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
436 nlen = (unsigned char) strlen(name);
437 (void) WriteBlobByte(ofile,nlen);
439 for (i=0; i<nlen; i++)
440 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
442 if ((nlen & 0x01) == 0)
444 (void) WriteBlobByte(ofile,0x00);
447 if (recnum != IPTC_ID)
449 (void) WriteBlobMSBLong(ofile, (unsigned long) len);
455 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
459 (void) WriteBlobByte(ofile,0x00);
465 /* patch in a fake length for now and fix it later */
466 savedpos = TellBlob(ofile);
467 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFUL);
469 savedolen = outputlen;
476 (void) WriteBlobByte(ofile,0x1c);
477 (void) WriteBlobByte(ofile,(unsigned char) dataset);
478 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
479 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
484 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
490 token=DestroyString(token);
491 newstr=DestroyString(newstr);
492 if (name != (char *) NULL)
493 name=DestroyString(name);
495 token_info=DestroyTokenInfo(token_info);
496 line=DestroyString(line);
502 long diff = outputlen - savedolen;
504 currentpos = TellBlob(ofile);
505 offset=SeekBlob(ofile,savedpos,SEEK_SET);
508 (void) WriteBlobMSBLong(ofile,(unsigned long) diff);
509 offset=SeekBlob(ofile,currentpos,SEEK_SET);
517 static char *super_fgets_w(char **b, int *blen, Image *file)
528 p=(unsigned char *) (*b);
531 c=(int) ReadBlobLSBShort(file);
532 if ((c == -1) || (c == '\n'))
536 if ((q-p+1) >= (int) len)
543 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
545 if (p == (unsigned char *) NULL)
549 *q=(unsigned char) c;
552 if ((*b) != (char *) NULL)
559 return (char *) NULL;
566 static long parse8BIMW(Image *ifile, Image *ofile)
587 inputlen = BUFFER_SZ;
602 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
603 name = token = (char *)NULL;
605 token_info=AcquireTokenInfo();
606 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
611 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
612 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
613 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
614 &brkused,&next,"ed)==0)
628 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
629 "",0,&brkused,&next,"ed)==0)
634 if (strcmp(newstr,"8BIM")==0)
637 dataset = (unsigned char) atoi(newstr);
640 recnum=(unsigned int) atoi(newstr);
643 name=(char *) AcquireQuantumMemory(strlen(newstr)+MaxTextExtent,
646 (void) CopyMagickString(name,newstr,strlen(newstr)+MaxTextExtent);
666 len = (long) strlen(token);
667 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
668 "",0,&brkused,&next,"ed)==0)
670 if (brkused && next > 0)
675 len -= (long) convertHTMLcodes(s,(int) strlen(s));
692 long diff = outputlen - savedolen;
693 currentpos = TellBlob(ofile);
694 offset=SeekBlob(ofile,savedpos,SEEK_SET);
697 (void) WriteBlobMSBLong(ofile,(unsigned long) diff);
698 offset=SeekBlob(ofile,currentpos,SEEK_SET);
705 (void) WriteBlobByte(ofile,0x00);
708 (void) WriteBlobString(ofile,"8BIM");
709 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
712 nlen = (unsigned char) strlen(name);
713 (void) WriteBlobByte(ofile,(unsigned char) nlen);
715 for (i=0; i<nlen; i++)
716 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
718 if ((nlen & 0x01) == 0)
720 (void) WriteBlobByte(ofile,0x00);
723 if (recnum != IPTC_ID)
725 (void) WriteBlobMSBLong(ofile,(unsigned long) len);
731 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
735 (void) WriteBlobByte(ofile,0x00);
741 /* patch in a fake length for now and fix it later */
742 savedpos = TellBlob(ofile);
743 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFUL);
745 savedolen = outputlen;
752 (void) WriteBlobByte(ofile,0x1c);
753 (void) WriteBlobByte(ofile,dataset);
754 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
755 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
760 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
766 token=DestroyString(token);
767 newstr=DestroyString(newstr);
768 name=DestroyString(name);
770 token_info=DestroyTokenInfo(token_info);
771 line=DestroyString(line);
777 long diff = outputlen - savedolen;
779 currentpos = TellBlob(ofile);
780 offset=SeekBlob(ofile,savedpos,SEEK_SET);
783 (void) WriteBlobMSBLong(ofile,(unsigned long) diff);
784 offset=SeekBlob(ofile,currentpos,SEEK_SET);
792 /* some defines for the different JPEG block types */
793 #define M_SOF0 0xC0 /* Start Of Frame N */
794 #define M_SOF1 0xC1 /* N indicates which compression process */
795 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
797 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
807 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
808 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
826 static int jpeg_transfer_1(Image *ifile, Image *ofile)
830 c = ReadBlobByte(ifile);
833 (void) WriteBlobByte(ofile,(unsigned char) c);
838 static int jpeg_skip_1(Image *ifile)
842 c = ReadBlobByte(ifile);
849 static int jpeg_read_remaining(Image *ifile, Image *ofile)
853 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
858 static int jpeg_skip_variable(Image *ifile, Image *ofile)
863 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
865 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
868 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
872 if (jpeg_transfer_1(ifile, ofile) == EOF)
878 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
884 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
885 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
887 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
891 if (ReadBlobByte(ifile) == EOF)
897 static int jpeg_nextmarker(Image *ifile, Image *ofile)
901 /* transfer anything until we hit 0xff */
904 c = ReadBlobByte(ifile);
906 return M_EOI; /* we hit EOF */
909 (void) WriteBlobByte(ofile,(unsigned char) c);
912 /* get marker byte, swallowing possible padding */
915 c = ReadBlobByte(ifile);
917 return M_EOI; /* we hit EOF */
924 static int jpeg_skip_till_marker(Image *ifile, int marker)
930 /* skip anything until we hit 0xff */
934 c = ReadBlobByte(ifile);
937 return M_EOI; /* we hit EOF */
940 /* get marker byte, swallowing possible padding */
943 c = ReadBlobByte(ifile);
945 return M_EOI; /* we hit EOF */
947 } while (c != marker);
952 static char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
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)
996 len=(unsigned int) GetBlobSize(iptc);
998 len++; /* make the length even */
999 psheader[2]=(char) ((len+16)>>8);
1000 psheader[3]=(char) ((len+16)&0xff);
1001 for (inx = 0; inx < 18; inx++)
1002 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1003 jpeg_read_remaining(iptc, ofile);
1004 len=(unsigned int) GetBlobSize(iptc);
1006 (void) WriteBlobByte(ofile,0);
1011 /* we hit data, no more marker-inserting can be done! */
1012 jpeg_read_remaining(ifile, ofile);
1017 jpeg_skip_variable(ifile, ofile);
1024 /* handle stripping the APP13 data out of a JPEG */
1026 static void jpeg_strip(Image *ifile, Image *ofile)
1028 unsigned int marker;
1030 marker = jpeg_skip_till_marker(ifile, M_SOI);
1031 if (marker == M_SOI)
1033 (void) WriteBlobByte(ofile,0xff);
1034 (void) WriteBlobByte(ofile,M_SOI);
1035 jpeg_read_remaining(ifile, ofile);
1039 /* Extract any APP13 binary data into a file. */
1040 static int jpeg_extract(Image *ifile, Image *ofile)
1042 unsigned int marker;
1043 unsigned int done = 0;
1045 if (jpeg_skip_1(ifile) != 0xff)
1047 if (jpeg_skip_1(ifile) != M_SOI)
1050 while (done == MagickFalse)
1052 marker = jpeg_skip_till_marker(ifile, M_APP13);
1053 if (marker == M_APP13)
1055 marker = jpeg_nextmarker(ifile, ofile);
1063 static Image *ReadMETAImage(const ImageInfo *image_info,
1064 ExceptionInfo *exception)
1086 Open file containing binary metadata
1088 assert(image_info != (const ImageInfo *) NULL);
1089 assert(image_info->signature == MagickSignature);
1090 if (image_info->debug != MagickFalse)
1091 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1092 image_info->filename);
1093 assert(exception != (ExceptionInfo *) NULL);
1094 assert(exception->signature == MagickSignature);
1095 image=AcquireImage(image_info);
1096 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1097 if (status == MagickFalse)
1099 image=DestroyImageList(image);
1100 return((Image *) NULL);
1104 (void) SetImageBackgroundColor(image);
1106 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1109 Read 8BIM binary metadata.
1111 buff=AcquireImage((ImageInfo *) NULL);
1112 if (buff == (Image *) NULL)
1113 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1114 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1115 if (blob == (unsigned char *) NULL)
1117 buff=DestroyImage(buff);
1118 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1120 AttachBlob(buff->blob,blob,length);
1121 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1123 length=(size_t) parse8BIM(image, buff);
1125 (void) WriteBlobByte(buff,0x0);
1127 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1129 length=(size_t) parse8BIMW(image, buff);
1131 (void) WriteBlobByte(buff,0x0);
1137 c=ReadBlobByte(image);
1140 (void) WriteBlobByte(buff,(unsigned char) c);
1143 profile=AcquireStringInfo((size_t) GetBlobSize(buff));
1144 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1145 status=SetImageProfile(image,"8bim",profile);
1146 profile=DestroyStringInfo(profile);
1147 if (status == MagickFalse)
1148 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1149 blob=DetachBlob(buff->blob);
1150 blob=(unsigned char *) RelinquishMagickMemory(blob);
1151 buff=DestroyImage(buff);
1153 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1156 name[MaxTextExtent];
1158 (void) FormatMagickString(name,MaxTextExtent,"APP%d",1);
1159 buff=AcquireImage((ImageInfo *) NULL);
1160 if (buff == (Image *) NULL)
1161 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1162 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1163 if (blob == (unsigned char *) NULL)
1165 buff=DestroyImage(buff);
1166 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1168 AttachBlob(buff->blob,blob,length);
1169 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1177 if (image_info->profile == (void *) NULL)
1179 blob=DetachBlob(buff->blob);
1180 blob=RelinquishMagickMemory(blob);
1181 buff=DestroyImage(buff);
1182 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1184 profile=CloneStringInfo((StringInfo *) image_info->profile);
1185 iptc=AcquireImage((ImageInfo *) NULL);
1186 if (iptc == (Image *) NULL)
1188 blob=DetachBlob(buff->blob);
1189 blob=RelinquishMagickMemory(blob);
1190 buff=DestroyImage(buff);
1191 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1193 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1194 GetStringInfoLength(profile));
1195 result=jpeg_embed(image,buff,iptc);
1196 blob=DetachBlob(iptc->blob);
1197 blob=RelinquishMagickMemory(blob);
1198 iptc=DestroyImage(iptc);
1201 blob=DetachBlob(buff->blob);
1202 blob=RelinquishMagickMemory(blob);
1203 buff=DestroyImage(buff);
1204 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1212 /* Really - really slow - FIX ME PLEASE!!!! */
1213 c=ReadBlobByte(image);
1216 (void) WriteBlobByte(buff,c);
1229 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1231 if (buffer != (unsigned char *) NULL)
1234 while ((length=ReadBlob(image,MagickMaxBufferExtent,buffer)) != 0)
1237 for (i=0; i < (long) length; i+=count)
1239 count=WriteBlob(buff,(size_t) (length-i),buffer+i);
1243 if (i < (long) length)
1246 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1250 profile=AcquireStringInfo((size_t) GetBlobSize(buff));
1251 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1252 status=SetImageProfile(image,name,profile);
1253 profile=DestroyStringInfo(profile);
1254 if (status == MagickFalse)
1255 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1256 blob=DetachBlob(buff->blob);
1257 blob=RelinquishMagickMemory(blob);
1258 buff=DestroyImage(buff);
1260 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1261 (LocaleCompare(image_info->magick,"ICM") == 0))
1263 buff=AcquireImage((ImageInfo *) NULL);
1264 if (buff == (Image *) NULL)
1265 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1266 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1267 if (blob == (unsigned char *) NULL)
1269 buff=DestroyImage(buff);
1270 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1272 AttachBlob(buff->blob,blob,length);
1275 c=ReadBlobByte(image);
1278 (void) WriteBlobByte(buff,(unsigned char) c);
1280 profile=AcquireStringInfo((size_t) GetBlobSize(buff));
1281 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1282 (void) SetImageProfile(image,"icc",profile);
1283 profile=DestroyStringInfo(profile);
1284 blob=DetachBlob(buff->blob);
1285 blob=(unsigned char *) RelinquishMagickMemory(blob);
1286 buff=DestroyImage(buff);
1288 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1290 register unsigned char
1293 buff=AcquireImage((ImageInfo *) NULL);
1294 if (buff == (Image *) NULL)
1295 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1296 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1297 if (blob == (unsigned char *) NULL)
1299 buff=DestroyImage(buff);
1300 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1302 AttachBlob(buff->blob,blob,length);
1303 /* write out the header - length field patched below */
1304 (void) WriteBlob(buff,11,(unsigned char *) "8BIM\04\04\0\0\0\0\01");
1305 (void) WriteBlobByte(buff,0xe0);
1306 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
1308 length=(size_t) parse8BIM(image,buff);
1310 (void) WriteBlobByte(buff,0x00);
1312 else if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
1319 c=ReadBlobByte(image);
1322 (void) WriteBlobByte(buff,(unsigned char) c);
1325 profile=AcquireStringInfo((size_t) GetBlobSize(buff));
1327 subtract off the length of the 8BIM stuff.
1329 length=GetStringInfoLength(profile)-12;
1330 p=GetStringInfoDatum(profile);
1331 p[10]=(unsigned char) (length >> 8);
1332 p[11]=(unsigned char) (length & 0xff);
1333 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1334 (void) SetImageProfile(image,"8bim",profile);
1335 profile=DestroyStringInfo(profile);
1336 blob=DetachBlob(buff->blob);
1337 blob=(unsigned char *) RelinquishMagickMemory(blob);
1338 buff=DestroyImage(buff);
1340 if (LocaleCompare(image_info->magick,"XMP") == 0)
1342 buff=AcquireImage((ImageInfo *) NULL);
1343 if (buff == (Image *) NULL)
1344 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1345 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1346 if (blob == (unsigned char *) NULL)
1348 buff=DestroyImage(buff);
1349 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1351 AttachBlob(buff->blob,blob,length);
1354 c=ReadBlobByte(image);
1357 (void) WriteBlobByte(buff,(unsigned char) c);
1359 profile=AcquireStringInfo((size_t) GetBlobSize(buff));
1360 SetStringInfoDatum(profile,GetBlobStreamData(buff));
1361 (void) SetImageProfile(image,"xmp",profile);
1362 profile=DestroyStringInfo(profile);
1363 blob=DetachBlob(buff->blob);
1364 blob=(unsigned char *) RelinquishMagickMemory(blob);
1365 buff=DestroyImage(buff);
1367 (void) CloseBlob(image);
1368 return(GetFirstImageInList(image));
1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 % R e g i s t e r M E T A I m a g e %
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382 % RegisterMETAImage() adds attributes for the META image format to
1383 % the list of supported formats. The attributes include the image format
1384 % tag, a method to read and/or write the format, whether the format
1385 % supports the saving of more than one frame to the same file or blob,
1386 % whether the format supports native in-memory I/O, and a brief
1387 % description of the format.
1389 % The format of the RegisterMETAImage method is:
1391 % unsigned long RegisterMETAImage(void)
1394 ModuleExport unsigned long RegisterMETAImage(void)
1399 entry=SetMagickInfo("8BIM");
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("Photoshop resource format");
1406 entry->module=ConstantString("META");
1407 (void) RegisterMagickInfo(entry);
1409 entry=SetMagickInfo("8BIMTEXT");
1410 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1411 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1412 entry->adjoin=MagickFalse;
1413 entry->stealth=MagickTrue;
1414 entry->seekable_stream=MagickTrue;
1415 entry->description=ConstantString("Photoshop resource text format");
1416 entry->module=ConstantString("META");
1417 (void) RegisterMagickInfo(entry);
1419 entry=SetMagickInfo("8BIMWTEXT");
1420 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1421 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1422 entry->adjoin=MagickFalse;
1423 entry->stealth=MagickTrue;
1424 entry->seekable_stream=MagickTrue;
1425 entry->description=ConstantString("Photoshop resource wide text format");
1426 entry->module=ConstantString("META");
1427 (void) RegisterMagickInfo(entry);
1429 entry=SetMagickInfo("APP1");
1430 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1431 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1432 entry->adjoin=MagickFalse;
1433 entry->stealth=MagickTrue;
1434 entry->seekable_stream=MagickTrue;
1435 entry->description=ConstantString("Raw application information");
1436 entry->module=ConstantString("META");
1437 (void) RegisterMagickInfo(entry);
1439 entry=SetMagickInfo("APP1JPEG");
1440 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1441 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1442 entry->adjoin=MagickFalse;
1443 entry->stealth=MagickTrue;
1444 entry->seekable_stream=MagickTrue;
1445 entry->description=ConstantString("Raw JPEG binary data");
1446 entry->module=ConstantString("META");
1447 (void) RegisterMagickInfo(entry);
1449 entry=SetMagickInfo("EXIF");
1450 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1451 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1452 entry->adjoin=MagickFalse;
1453 entry->stealth=MagickTrue;
1454 entry->seekable_stream=MagickTrue;
1455 entry->description=ConstantString("Exif digital camera binary data");
1456 entry->module=ConstantString("META");
1457 (void) RegisterMagickInfo(entry);
1459 entry=SetMagickInfo("XMP");
1460 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1461 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1462 entry->adjoin=MagickFalse;
1463 entry->stealth=MagickTrue;
1464 entry->seekable_stream=MagickTrue;
1465 entry->description=ConstantString("Adobe XML metadata");
1466 entry->module=ConstantString("META");
1467 (void) RegisterMagickInfo(entry);
1469 entry=SetMagickInfo("ICM");
1470 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1471 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1472 entry->adjoin=MagickFalse;
1473 entry->stealth=MagickTrue;
1474 entry->seekable_stream=MagickTrue;
1475 entry->description=ConstantString("ICC Color Profile");
1476 entry->module=ConstantString("META");
1477 (void) RegisterMagickInfo(entry);
1479 entry=SetMagickInfo("ICC");
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);
1489 entry=SetMagickInfo("IPTC");
1490 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1491 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1492 entry->adjoin=MagickFalse;
1493 entry->stealth=MagickTrue;
1494 entry->seekable_stream=MagickTrue;
1495 entry->description=ConstantString("IPTC Newsphoto");
1496 entry->module=ConstantString("META");
1497 (void) RegisterMagickInfo(entry);
1499 entry=SetMagickInfo("IPTCTEXT");
1500 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1501 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1502 entry->adjoin=MagickFalse;
1503 entry->stealth=MagickTrue;
1504 entry->seekable_stream=MagickTrue;
1505 entry->description=ConstantString("IPTC Newsphoto text format");
1506 entry->module=ConstantString("META");
1507 (void) RegisterMagickInfo(entry);
1509 entry=SetMagickInfo("IPTCWTEXT");
1510 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1511 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1512 entry->adjoin=MagickFalse;
1513 entry->stealth=MagickTrue;
1514 entry->seekable_stream=MagickTrue;
1515 entry->description=ConstantString("IPTC Newsphoto text format");
1516 entry->module=ConstantString("META");
1517 (void) RegisterMagickInfo(entry);
1518 return(MagickImageCoderSignature);
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526 % U n r e g i s t e r M E T A I m a g e %
1530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532 % UnregisterMETAImage() removes format registrations made by the
1533 % META module from the list of supported formats.
1535 % The format of the UnregisterMETAImage method is:
1537 % UnregisterMETAImage(void)
1540 ModuleExport void UnregisterMETAImage(void)
1542 (void) UnregisterMagickInfo("8BIM");
1543 (void) UnregisterMagickInfo("8BIMTEXT");
1544 (void) UnregisterMagickInfo("8BIMWTEXT");
1545 (void) UnregisterMagickInfo("EXIF");
1546 (void) UnregisterMagickInfo("APP1");
1547 (void) UnregisterMagickInfo("APP1JPEG");
1548 (void) UnregisterMagickInfo("ICCTEXT");
1549 (void) UnregisterMagickInfo("ICM");
1550 (void) UnregisterMagickInfo("ICC");
1551 (void) UnregisterMagickInfo("IPTC");
1552 (void) UnregisterMagickInfo("IPTCTEXT");
1553 (void) UnregisterMagickInfo("IPTCWTEXT");
1554 (void) UnregisterMagickInfo("XMP");
1558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562 % W r i t e M E T A I m a g e %
1566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568 % WriteMETAImage() writes a META image to a file.
1570 % The format of the WriteMETAImage method is:
1572 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1575 % Compression code contributed by Kyle Shorter.
1577 % A description of each parameter follows:
1579 % o image_info: Specifies a pointer to an ImageInfo structure.
1581 % o image: A pointer to a Image structure.
1585 static size_t GetIPTCStream(unsigned char **info,size_t length)
1593 register unsigned char
1601 buffer[4] = { '\0', '\0', '\0', '\0' };
1611 if ((*p == 0x1c) && (*(p+1) == 0x02))
1614 Extract IPTC from 8BIM resource block.
1616 while (extent >= 12)
1618 if (strncmp((const char *) p,"8BIM",4))
1622 marker=(unsigned int) (*p) << 8 | *(p+1);
1628 if ((size_t) c >= extent)
1634 tag_length=(((unsigned long) *p) << 24) | (((unsigned long) *(p+1)) << 16) |
1635 (((unsigned long) *(p+2)) << 8) | ((unsigned long) *(p+3));
1638 if (tag_length > extent)
1640 if (marker == IPTC_ID)
1642 *info=p; /* let the caller know were it is */
1649 Find the beginning of the IPTC info.
1665 *info=p; /* let the caller know were it is */
1670 Determine the length of the IPTC info.
1687 Found the 0x1c tag; skip the dataset and record number tags.
1689 c=(*p++); /* should be 2 */
1693 if ((info_length == 1) && (c != 2))
1696 c=(*p++); /* should be 0 */
1700 if ((info_length == 2) && (c != 0))
1704 Decode the length of the block that follows - long or short format.
1711 if ((c & 0x80) != 0)
1713 for (i=0; i < 4; i++)
1721 tag_length=(((unsigned long) buffer[0]) << 24) |
1722 (((unsigned long) buffer[1]) << 16) |
1723 (((unsigned long) buffer[2]) << 8) | (((unsigned long) buffer[3]));
1727 tag_length=(unsigned long) (c << 8);
1735 if (tag_length > (length+1))
1741 info_length+=tag_length;
1743 return(info_length);
1746 static void formatString(Image *ofile, const char *s, int len)
1749 temp[MaxTextExtent];
1751 (void) WriteBlobByte(ofile,'"');
1752 for (; len > 0; len--, s++) {
1756 (void) WriteBlobString(ofile,"&");
1760 (void) WriteBlobString(ofile,"<");
1763 (void) WriteBlobString(ofile,">");
1767 (void) WriteBlobString(ofile,""");
1771 (void) WriteBlobByte(ofile,(unsigned char) *s);
1774 (void) FormatMagickString(temp,MaxTextExtent,"&#%d;", c & 255);
1775 (void) WriteBlobString(ofile,temp);
1780 #if defined(__WINDOWS__)
1781 (void) WriteBlobString(ofile,"\"\r\n");
1783 #if defined(macintosh)
1784 (void) WriteBlobString(ofile,"\"\r");
1786 (void) WriteBlobString(ofile,"\"\n");
1791 typedef struct _tag_spec
1800 static const tag_spec tags[] = {
1801 { 5, "Image Name" },
1802 { 7, "Edit Status" },
1805 { 20, "Supplemental Category" },
1806 { 22, "Fixture Identifier" },
1808 { 30, "Release Date" },
1809 { 35, "Release Time" },
1810 { 40, "Special Instructions" },
1811 { 45, "Reference Service" },
1812 { 47, "Reference Date" },
1813 { 50, "Reference Number" },
1814 { 55, "Created Date" },
1815 { 60, "Created Time" },
1816 { 65, "Originating Program" },
1817 { 70, "Program Version" },
1818 { 75, "Object Cycle" },
1820 { 85, "Byline Title" },
1822 { 95, "Province State" },
1823 { 100, "Country Code" },
1825 { 103, "Original Transmission Reference" },
1826 { 105, "Headline" },
1829 { 116, "Copyright String" },
1831 { 121, "Image Orientation" },
1832 { 122, "Caption Writer" },
1833 { 131, "Local Caption" },
1834 { 200, "Custom Field 1" },
1835 { 201, "Custom Field 2" },
1836 { 202, "Custom Field 3" },
1837 { 203, "Custom Field 4" },
1838 { 204, "Custom Field 5" },
1839 { 205, "Custom Field 6" },
1840 { 206, "Custom Field 7" },
1841 { 207, "Custom Field 8" },
1842 { 208, "Custom Field 9" },
1843 { 209, "Custom Field 10" },
1844 { 210, "Custom Field 11" },
1845 { 211, "Custom Field 12" },
1846 { 212, "Custom Field 13" },
1847 { 213, "Custom Field 14" },
1848 { 214, "Custom Field 15" },
1849 { 215, "Custom Field 16" },
1850 { 216, "Custom Field 17" },
1851 { 217, "Custom Field 18" },
1852 { 218, "Custom Field 19" },
1853 { 219, "Custom Field 20" }
1856 static int formatIPTC(Image *ifile, Image *ofile)
1859 temp[MaxTextExtent];
1879 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1884 foundiptc = 0; /* found the IPTC-Header */
1885 tagsfound = 0; /* number of tags found */
1887 c = ReadBlobByte(ifile);
1900 /* we found the 0x1c tag and now grab the dataset and record number tags */
1901 c = ReadBlobByte(ifile);
1902 if (c == EOF) return -1;
1903 dataset = (unsigned char) c;
1904 c = ReadBlobByte(ifile);
1905 if (c == EOF) return -1;
1906 recnum = (unsigned char) c;
1907 /* try to match this record to one of the ones in our named table */
1908 for (i=0; i< tagcount; i++)
1910 if (tags[i].id == (short) recnum)
1914 readable = (unsigned char *) tags[i].name;
1916 readable = (unsigned char *) "";
1918 We decode the length of the block that follows - long or short fmt.
1920 c=ReadBlobByte(ifile);
1921 if (c == EOF) return -1;
1922 if (c & (unsigned char) 0x80)
1929 c0=ReadBlobByte(ifile);
1930 if (c0 == EOF) return -1;
1931 taglen = (c << 8) | c0;
1933 if (taglen < 0) return -1;
1934 /* make a buffer to hold the tag datand snag it from the input stream */
1935 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
1937 if (str == (unsigned char *) NULL)
1939 printf("MemoryAllocationFailed");
1942 for (tagindx=0; tagindx<taglen; tagindx++)
1944 c=ReadBlobByte(ifile);
1945 if (c == EOF) return -1;
1946 str[tagindx] = (unsigned char) c;
1950 /* now finish up by formatting this binary data into ASCII equivalent */
1951 if (strlen((char *)readable) > 0)
1952 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d#%s=",
1953 (unsigned int) dataset, (unsigned int) recnum, readable);
1955 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d=",
1956 (unsigned int) dataset,(unsigned int) recnum);
1957 (void) WriteBlobString(ofile,temp);
1958 formatString( ofile, (char *)str, taglen );
1959 str=(unsigned char *) RelinquishMagickMemory(str);
1963 c=ReadBlobByte(ifile);
1965 return((int) tagsfound);
1968 static int readWordFromBuffer(char **s, long *len)
1979 c = *(*s)++; (*len)--;
1980 if (*len < 0) return -1;
1981 buffer[i] = (unsigned char) c;
1983 return (((int) buffer[ 0 ]) << 8) |
1984 (((int) buffer[ 1 ]));
1987 static int formatIPTCfromBuffer(Image *ofile, char *s, long len)
1990 temp[MaxTextExtent];
2010 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
2015 foundiptc = 0; /* found the IPTC-Header */
2016 tagsfound = 0; /* number of tags found */
2031 We found the 0x1c tag and now grab the dataset and record number tags.
2034 if (len < 0) return -1;
2035 dataset = (unsigned char) c;
2037 if (len < 0) return -1;
2038 recnum = (unsigned char) c;
2039 /* try to match this record to one of the ones in our named table */
2040 for (i=0; i< tagcount; i++)
2041 if (tags[i].id == (short) recnum)
2044 readable=(unsigned char *) tags[i].name;
2046 readable=(unsigned char *) "";
2048 We decode the length of the block that follows - long or short fmt.
2054 if (c & (unsigned char) 0x80)
2060 taglen=readWordFromBuffer(&s, &len);
2064 /* make a buffer to hold the tag datand snag it from the input stream */
2065 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MaxTextExtent),
2067 if (str == (unsigned char *) NULL)
2069 printf("MemoryAllocationFailed");
2072 for (tagindx=0; tagindx<taglen; tagindx++)
2077 str[tagindx]=(unsigned char) c;
2081 /* now finish up by formatting this binary data into ASCII equivalent */
2082 if (strlen((char *)readable) > 0)
2083 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d#%s=",
2084 (unsigned int) dataset,(unsigned int) recnum, readable);
2086 (void) FormatMagickString(temp,MaxTextExtent,"%d#%d=",
2087 (unsigned int) dataset,(unsigned int) recnum);
2088 (void) WriteBlobString(ofile,temp);
2089 formatString( ofile, (char *)str, taglen );
2090 str=(unsigned char *) RelinquishMagickMemory(str);
2094 return ((int) tagsfound);
2097 static int format8BIM(Image *ifile, Image *ofile)
2100 temp[MaxTextExtent];
2119 foundOSType=0; /* found the OSType */
2120 c=ReadBlobByte(ifile);
2128 buffer[0]=(unsigned char) c;
2131 c=ReadBlobByte(ifile);
2134 buffer[i] = (unsigned char) c;
2137 if (strcmp((const char *)buffer, "8BIM") == 0)
2144 c=ReadBlobByte(ifile);
2148 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2150 ID=(int) ReadBlobMSBShort(ifile);
2157 c=ReadBlobByte(ifile);
2160 plen = (unsigned char) c;
2161 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2162 MaxTextExtent),sizeof(*PString));
2163 if (PString == (unsigned char *) NULL)
2165 printf("MemoryAllocationFailed");
2168 for (i=0; i<plen; i++)
2170 c=ReadBlobByte(ifile);
2171 if (c == EOF) return -1;
2172 PString[i] = (unsigned char) c;
2174 PString[ plen ] = 0;
2175 if ((plen & 0x01) == 0)
2177 c=ReadBlobByte(ifile);
2182 count = (ssize_t) ReadBlobMSBLong(ifile);
2183 if (count < 0) return -1;
2184 /* make a buffer to hold the datand snag it from the input stream */
2185 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str));
2186 if (str == (unsigned char *) NULL)
2188 printf("MemoryAllocationFailed");
2191 for (i=0; i < (long) count; i++)
2193 c=ReadBlobByte(ifile);
2196 str[i]=(unsigned char) c;
2199 /* we currently skip thumbnails, since it does not make
2200 * any sense preserving them in a real world application
2202 if (ID != THUMBNAIL_ID)
2204 /* now finish up by formatting this binary data into
2207 if (strlen((const char *)PString) > 0)
2208 (void) FormatMagickString(temp,MaxTextExtent,"8BIM#%d#%s=",ID,
2211 (void) FormatMagickString(temp,MaxTextExtent,"8BIM#%d=",ID);
2212 (void) WriteBlobString(ofile,temp);
2215 formatString(ofile, "IPTC", 4);
2216 formatIPTCfromBuffer(ofile, (char *)str, (long) count);
2219 formatString(ofile, (char *)str, (long) count);
2221 str=(unsigned char *) RelinquishMagickMemory(str);
2222 PString=(unsigned char *) RelinquishMagickMemory(PString);
2224 c=ReadBlobByte(ifile);
2229 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2244 assert(image_info != (const ImageInfo *) NULL);
2245 assert(image_info->signature == MagickSignature);
2246 assert(image != (Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 if (image->debug != MagickFalse)
2249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2251 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2256 profile=GetImageProfile(image,"8bim");
2257 if (profile == (StringInfo *) NULL)
2258 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2259 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2260 if (status == MagickFalse)
2262 (void) WriteBlob(image,GetStringInfoLength(profile),
2263 GetStringInfoDatum(profile));
2264 (void) CloseBlob(image);
2267 if (LocaleCompare(image_info->magick,"iptc") == 0)
2275 profile=GetImageProfile(image,"8bim");
2276 if (profile == (StringInfo *) NULL)
2277 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2278 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2279 info=GetStringInfoDatum(profile);
2280 length=GetStringInfoLength(profile);
2281 length=GetIPTCStream(&info,length);
2283 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2284 (void) WriteBlob(image,length,info);
2285 (void) CloseBlob(image);
2288 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2293 profile=GetImageProfile(image,"8bim");
2294 if (profile == (StringInfo *) NULL)
2295 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2296 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2297 if (status == MagickFalse)
2299 buff=AcquireImage((ImageInfo *) NULL);
2300 if (buff == (Image *) NULL)
2301 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2302 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2303 GetStringInfoLength(profile));
2304 format8BIM(buff,image);
2305 (void) DetachBlob(buff->blob);
2306 buff=DestroyImage(buff);
2307 (void) CloseBlob(image);
2310 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2311 return(MagickFalse);
2312 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2320 profile=GetImageProfile(image,"8bim");
2321 if (profile == (StringInfo *) NULL)
2322 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2323 info=GetStringInfoDatum(profile);
2324 length=GetStringInfoLength(profile);
2325 length=GetIPTCStream(&info,length);
2327 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2328 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2329 if (status == MagickFalse)
2331 buff=AcquireImage((ImageInfo *) NULL);
2332 if (buff == (Image *) NULL)
2333 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2334 AttachBlob(buff->blob,info,length);
2335 formatIPTC(buff,image);
2336 (void) DetachBlob(buff->blob);
2337 buff=DestroyImage(buff);
2338 (void) CloseBlob(image);
2341 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2342 return(MagickFalse);
2343 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2344 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2345 (LocaleCompare(image_info->magick,"XMP") == 0))
2348 (void) Write APP1 image.
2350 profile=GetImageProfile(image,image_info->magick);
2351 if (profile == (StringInfo *) NULL)
2352 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2353 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2354 if (status == MagickFalse)
2356 (void) WriteBlob(image,GetStringInfoLength(profile),
2357 GetStringInfoDatum(profile));
2358 (void) CloseBlob(image);
2361 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2362 (LocaleCompare(image_info->magick,"ICM") == 0))
2367 profile=GetImageProfile(image,"icc");
2368 if (profile == (StringInfo *) NULL)
2369 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2370 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2371 if (status == MagickFalse)
2373 (void) WriteBlob(image,GetStringInfoLength(profile),
2374 GetStringInfoDatum(profile));
2375 (void) CloseBlob(image);
2378 return(MagickFalse);