2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M EEEEE TTTTT AAA %
13 % Read/Write Embedded Image Profiles. %
20 % Copyright 1999-2017 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 % https://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
154 static const 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 size_t convertHTMLcodes(char *s, const size_t len)
202 if ((len == 0) || (s == (char*) NULL) || (*s=='\0'))
204 if ((len > 3) && (s[1] == '#') && (strchr(s,';') != (char *) NULL) &&
205 (sscanf(s,"&#%d;",&value) == 1))
215 (void) memmove(s+1,s+1+o,strlen(s+1+o)+1);
225 codes=sizeof(html_codes)/sizeof(html_code);
226 for (i=0; i < codes; i++)
228 if (html_codes[i].len <= (ssize_t) 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 = MagickPathExtent;
327 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
328 if (line == (char *) NULL)
330 newstr = 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=(char *) 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)+MagickPathExtent,
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)
409 codes_length=convertHTMLcodes(s, strlen(s));
410 if ((ssize_t) codes_length > len)
430 ssize_t diff = outputlen - savedolen;
431 currentpos = TellBlob(ofile);
434 offset=SeekBlob(ofile,savedpos,SEEK_SET);
437 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
438 offset=SeekBlob(ofile,currentpos,SEEK_SET);
445 (void) WriteBlobByte(ofile,0x00);
448 (void) WriteBlobString(ofile,"8BIM");
449 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
452 nlen = (unsigned char) strlen(name);
453 (void) WriteBlobByte(ofile,nlen);
455 for (i=0; i<nlen; i++)
456 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
458 if ((nlen & 0x01) == 0)
460 (void) WriteBlobByte(ofile,0x00);
463 if (recnum != IPTC_ID)
465 (void) WriteBlobMSBLong(ofile, (unsigned int) len);
471 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
475 (void) WriteBlobByte(ofile,0x00);
481 /* patch in a fake length for now and fix it later */
482 savedpos = TellBlob(ofile);
485 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
487 savedolen = outputlen;
494 (void) WriteBlobByte(ofile,0x1c);
495 (void) WriteBlobByte(ofile,(unsigned char) dataset);
496 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
497 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
502 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
508 if (token != (char *) NULL)
509 token=DestroyString(token);
510 if (newstr != (char *) NULL)
511 newstr=DestroyString(newstr);
512 if (name != (char *) NULL)
513 name=DestroyString(name);
515 token_info=DestroyTokenInfo(token_info);
516 if (token != (char *) NULL)
517 token=DestroyString(token);
518 if (newstr != (char *) NULL)
519 newstr=DestroyString(newstr);
520 if (name != (char *) NULL)
521 name=DestroyString(name);
522 line=DestroyString(line);
528 ssize_t diff = outputlen - savedolen;
530 currentpos = TellBlob(ofile);
533 offset=SeekBlob(ofile,savedpos,SEEK_SET);
536 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
537 offset=SeekBlob(ofile,currentpos,SEEK_SET);
545 static char *super_fgets_w(char **b, int *blen, Image *file)
556 p=(unsigned char *) (*b);
559 c=ReadBlobLSBSignedShort(file);
560 if ((c == -1) || (c == '\n'))
564 if ((q-p+1) >= (int) len)
571 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
573 if (p == (unsigned char *) NULL)
577 *q=(unsigned char) c;
580 if ((*b) != (char *) NULL)
587 return (char *) NULL;
594 static ssize_t parse8BIMW(Image *ifile, Image *ofile)
615 inputlen = MagickPathExtent;
630 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
631 if (line == (char *) NULL)
633 newstr = name = token = (char *) NULL;
635 token_info=AcquireTokenInfo();
636 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
641 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
642 if (token == (char *) NULL)
644 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
645 if (newstr == (char *) NULL)
647 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
648 &brkused,&next,"ed)==0)
662 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
663 "",0,&brkused,&next,"ed)==0)
668 if (strcmp(newstr,"8BIM")==0)
671 dataset = (unsigned char) StringToLong(newstr);
674 recnum=(unsigned int) StringToUnsignedLong(newstr);
677 name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent,
680 (void) CopyMagickString(name,newstr,strlen(newstr)+MagickPathExtent);
700 len = (ssize_t) strlen(token);
701 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
702 "",0,&brkused,&next,"ed)==0)
704 if (brkused && next > 0)
712 codes_length=convertHTMLcodes(s, strlen(s));
713 if ((ssize_t) codes_length > len)
733 ssize_t diff = outputlen - savedolen;
734 currentpos = TellBlob(ofile);
737 offset=SeekBlob(ofile,savedpos,SEEK_SET);
740 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
741 offset=SeekBlob(ofile,currentpos,SEEK_SET);
748 (void) WriteBlobByte(ofile,0x00);
751 (void) WriteBlobString(ofile,"8BIM");
752 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
755 nlen = (unsigned char) strlen(name);
756 (void) WriteBlobByte(ofile,(unsigned char) nlen);
758 for (i=0; i<nlen; i++)
759 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
761 if ((nlen & 0x01) == 0)
763 (void) WriteBlobByte(ofile,0x00);
766 if (recnum != IPTC_ID)
768 (void) WriteBlobMSBLong(ofile,(unsigned int) len);
774 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
778 (void) WriteBlobByte(ofile,0x00);
784 /* patch in a fake length for now and fix it later */
785 savedpos = TellBlob(ofile);
788 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
790 savedolen = outputlen;
797 (void) WriteBlobByte(ofile,0x1c);
798 (void) WriteBlobByte(ofile,dataset);
799 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
800 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
805 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
811 if (token != (char *) NULL)
812 token=DestroyString(token);
813 if (newstr != (char *) NULL)
814 newstr=DestroyString(newstr);
815 if (name != (char *) NULL)
816 name=DestroyString(name);
818 token_info=DestroyTokenInfo(token_info);
819 if (token != (char *) NULL)
820 token=DestroyString(token);
821 if (newstr != (char *) NULL)
822 newstr=DestroyString(newstr);
823 if (name != (char *) NULL)
824 name=DestroyString(name);
825 line=DestroyString(line);
831 ssize_t diff = outputlen - savedolen;
833 currentpos = TellBlob(ofile);
836 offset=SeekBlob(ofile,savedpos,SEEK_SET);
839 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
840 offset=SeekBlob(ofile,currentpos,SEEK_SET);
848 /* some defines for the different JPEG block types */
849 #define M_SOF0 0xC0 /* Start Of Frame N */
850 #define M_SOF1 0xC1 /* N indicates which compression process */
851 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
853 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
863 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
864 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
882 static int jpeg_transfer_1(Image *ifile, Image *ofile)
886 c = ReadBlobByte(ifile);
889 (void) WriteBlobByte(ofile,(unsigned char) c);
894 static int jpeg_skip_1(Image *ifile)
898 c = ReadBlobByte(ifile);
905 static int jpeg_read_remaining(Image *ifile, Image *ofile)
909 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
914 static int jpeg_skip_variable(Image *ifile, Image *ofile)
919 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
921 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
924 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
928 if (jpeg_transfer_1(ifile, ofile) == EOF)
934 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
940 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
941 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
943 length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
947 if (ReadBlobByte(ifile) == EOF)
953 static int jpeg_nextmarker(Image *ifile, Image *ofile)
957 /* transfer anything until we hit 0xff */
960 c = ReadBlobByte(ifile);
962 return M_EOI; /* we hit EOF */
965 (void) WriteBlobByte(ofile,(unsigned char) c);
968 /* get marker byte, swallowing possible padding */
971 c = ReadBlobByte(ifile);
973 return M_EOI; /* we hit EOF */
980 static int jpeg_skip_till_marker(Image *ifile, int marker)
986 /* skip anything until we hit 0xff */
990 c = ReadBlobByte(ifile);
993 return M_EOI; /* we hit EOF */
996 /* get marker byte, swallowing possible padding */
999 c = ReadBlobByte(ifile);
1001 return M_EOI; /* we hit EOF */
1002 } while (c == 0xff);
1003 } while (c != marker);
1008 /* Embed binary IPTC data into a JPEG image. */
1009 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
1011 unsigned int marker;
1012 unsigned int done = 0;
1016 if (jpeg_transfer_1(ifile, ofile) != 0xFF)
1018 if (jpeg_transfer_1(ifile, ofile) != M_SOI)
1021 while (done == MagickFalse)
1023 marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
1024 if (marker == M_EOI)
1030 if (marker != M_APP13)
1032 (void) WriteBlobByte(ofile,0xff);
1033 (void) WriteBlobByte(ofile,(unsigned char) marker);
1040 /* we are going to write a new APP13 marker, so don't output the old one */
1041 jpeg_skip_variable2(ifile, ofile);
1045 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
1046 jpeg_skip_variable(ifile, ofile);
1048 if (iptc != (Image *) NULL)
1051 psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0";
1053 len=(unsigned int) GetBlobSize(iptc);
1055 len++; /* make the length even */
1056 psheader[2]=(char) ((len+16)>>8);
1057 psheader[3]=(char) ((len+16)&0xff);
1058 for (inx = 0; inx < 18; inx++)
1059 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1060 jpeg_read_remaining(iptc, ofile);
1061 len=(unsigned int) GetBlobSize(iptc);
1063 (void) WriteBlobByte(ofile,0);
1068 /* we hit data, no more marker-inserting can be done! */
1069 jpeg_read_remaining(ifile, ofile);
1074 jpeg_skip_variable(ifile, ofile);
1081 /* handle stripping the APP13 data out of a JPEG */
1083 static void jpeg_strip(Image *ifile, Image *ofile)
1085 unsigned int marker;
1087 marker = jpeg_skip_till_marker(ifile, M_SOI);
1088 if (marker == M_SOI)
1090 (void) WriteBlobByte(ofile,0xff);
1091 (void) WriteBlobByte(ofile,M_SOI);
1092 jpeg_read_remaining(ifile, ofile);
1096 /* Extract any APP13 binary data into a file. */
1097 static int jpeg_extract(Image *ifile, Image *ofile)
1099 unsigned int marker;
1100 unsigned int done = 0;
1102 if (jpeg_skip_1(ifile) != 0xff)
1104 if (jpeg_skip_1(ifile) != M_SOI)
1107 while (done == MagickFalse)
1109 marker = jpeg_skip_till_marker(ifile, M_APP13);
1110 if (marker == M_APP13)
1112 marker = jpeg_nextmarker(ifile, ofile);
1120 static inline void CopyBlob(Image *source,Image *destination)
1132 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1134 if (buffer != (unsigned char *) NULL)
1137 while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0)
1140 for (i=0; i < (ssize_t) length; i+=count)
1142 count=WriteBlob(destination,(size_t) (length-i),buffer+i);
1146 if (i < (ssize_t) length)
1149 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1153 static Image *ReadMETAImage(const ImageInfo *image_info,
1154 ExceptionInfo *exception)
1173 Open file containing binary metadata
1175 assert(image_info != (const ImageInfo *) NULL);
1176 assert(image_info->signature == MagickCoreSignature);
1177 if (image_info->debug != MagickFalse)
1178 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1179 image_info->filename);
1180 assert(exception != (ExceptionInfo *) NULL);
1181 assert(exception->signature == MagickCoreSignature);
1182 image=AcquireImage(image_info,exception);
1183 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1184 if (status == MagickFalse)
1186 image=DestroyImageList(image);
1187 return((Image *) NULL);
1191 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1193 image=DestroyImageList(image);
1194 return((Image *) NULL);
1197 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1200 Read 8BIM binary metadata.
1202 buff=AcquireImage((ImageInfo *) NULL,exception);
1203 if (buff == (Image *) NULL)
1204 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1205 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1206 if (blob == (unsigned char *) NULL)
1208 buff=DestroyImage(buff);
1209 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1211 AttachBlob(buff->blob,blob,length);
1212 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1214 length=(size_t) parse8BIM(image, buff);
1216 (void) WriteBlobByte(buff,0x0);
1218 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1220 length=(size_t) parse8BIMW(image, buff);
1222 (void) WriteBlobByte(buff,0x0);
1225 CopyBlob(image,buff);
1226 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1228 if (profile == (StringInfo *) NULL)
1230 blob=DetachBlob(buff->blob);
1231 blob=(unsigned char *) RelinquishMagickMemory(blob);
1232 buff=DestroyImage(buff);
1233 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1235 status=SetImageProfile(image,"8bim",profile,exception);
1236 profile=DestroyStringInfo(profile);
1237 blob=DetachBlob(buff->blob);
1238 blob=(unsigned char *) RelinquishMagickMemory(blob);
1239 buff=DestroyImage(buff);
1240 if (status == MagickFalse)
1241 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1243 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1246 name[MagickPathExtent];
1248 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",1);
1249 buff=AcquireImage((ImageInfo *) NULL,exception);
1250 if (buff == (Image *) NULL)
1251 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1252 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1253 if (blob == (unsigned char *) NULL)
1255 buff=DestroyImage(buff);
1256 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1258 AttachBlob(buff->blob,blob,length);
1259 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1267 if (image_info->profile == (void *) NULL)
1269 blob=DetachBlob(buff->blob);
1270 blob=(unsigned char *) RelinquishMagickMemory(blob);
1271 buff=DestroyImage(buff);
1272 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1274 profile=CloneStringInfo((StringInfo *) image_info->profile);
1275 iptc=AcquireImage((ImageInfo *) NULL,exception);
1276 if (iptc == (Image *) NULL)
1278 blob=DetachBlob(buff->blob);
1279 blob=(unsigned char *) RelinquishMagickMemory(blob);
1280 buff=DestroyImage(buff);
1281 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1283 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1284 GetStringInfoLength(profile));
1285 result=jpeg_embed(image,buff,iptc);
1286 blob=DetachBlob(iptc->blob);
1287 blob=(unsigned char *) RelinquishMagickMemory(blob);
1288 iptc=DestroyImage(iptc);
1291 buff=DestroyImage(buff);
1292 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1296 CopyBlob(image,buff);
1297 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1299 if (profile == (StringInfo *) NULL)
1301 blob=DetachBlob(buff->blob);
1302 blob=(unsigned char *) RelinquishMagickMemory(blob);
1303 buff=DestroyImage(buff);
1304 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1306 status=SetImageProfile(image,name,profile,exception);
1307 profile=DestroyStringInfo(profile);
1308 blob=DetachBlob(buff->blob);
1309 blob=(unsigned char *) RelinquishMagickMemory(blob);
1310 buff=DestroyImage(buff);
1311 if (status == MagickFalse)
1312 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1314 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1315 (LocaleCompare(image_info->magick,"ICM") == 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)
1332 blob=DetachBlob(buff->blob);
1333 blob=(unsigned char *) RelinquishMagickMemory(blob);
1334 buff=DestroyImage(buff);
1335 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1337 (void) SetImageProfile(image,"icc",profile,exception);
1338 profile=DestroyStringInfo(profile);
1339 blob=DetachBlob(buff->blob);
1340 blob=(unsigned char *) RelinquishMagickMemory(blob);
1341 buff=DestroyImage(buff);
1343 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1345 buff=AcquireImage((ImageInfo *) NULL,exception);
1346 if (buff == (Image *) NULL)
1347 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1348 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1349 if (blob == (unsigned char *) NULL)
1351 buff=DestroyImage(buff);
1352 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1354 AttachBlob(buff->blob,blob,length);
1355 CopyBlob(image,buff);
1356 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1358 if (profile == (StringInfo *) NULL)
1360 blob=DetachBlob(buff->blob);
1361 blob=(unsigned char *) RelinquishMagickMemory(blob);
1362 buff=DestroyImage(buff);
1363 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1365 (void) SetImageProfile(image,"8bim",profile,exception);
1366 profile=DestroyStringInfo(profile);
1367 blob=DetachBlob(buff->blob);
1368 blob=(unsigned char *) RelinquishMagickMemory(blob);
1369 buff=DestroyImage(buff);
1371 if (LocaleCompare(image_info->magick,"XMP") == 0)
1373 buff=AcquireImage((ImageInfo *) NULL,exception);
1374 if (buff == (Image *) NULL)
1375 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1376 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1377 if (blob == (unsigned char *) NULL)
1379 buff=DestroyImage(buff);
1380 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1382 AttachBlob(buff->blob,blob,length);
1383 CopyBlob(image,buff);
1384 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1386 if (profile == (StringInfo *) NULL)
1388 blob=DetachBlob(buff->blob);
1389 blob=(unsigned char *) RelinquishMagickMemory(blob);
1390 buff=DestroyImage(buff);
1391 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1393 (void) SetImageProfile(image,"xmp",profile,exception);
1394 profile=DestroyStringInfo(profile);
1395 blob=DetachBlob(buff->blob);
1396 blob=(unsigned char *) RelinquishMagickMemory(blob);
1397 buff=DestroyImage(buff);
1399 (void) CloseBlob(image);
1400 return(GetFirstImageInList(image));
1404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 % R e g i s t e r M E T A I m a g e %
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414 % RegisterMETAImage() adds attributes for the META image format to
1415 % the list of supported formats. The attributes include the image format
1416 % tag, a method to read and/or write the format, whether the format
1417 % supports the saving of more than one frame to the same file or blob,
1418 % whether the format supports native in-memory I/O, and a brief
1419 % description of the format.
1421 % The format of the RegisterMETAImage method is:
1423 % size_t RegisterMETAImage(void)
1426 ModuleExport size_t RegisterMETAImage(void)
1431 entry=AcquireMagickInfo("META","8BIM","Photoshop resource format");
1432 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1433 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1434 entry->flags^=CoderAdjoinFlag;
1435 entry->flags|=CoderStealthFlag;
1436 entry->flags|=CoderDecoderSeekableStreamFlag;
1437 (void) RegisterMagickInfo(entry);
1438 entry=AcquireMagickInfo("META","8BIMTEXT","Photoshop resource text format");
1439 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1440 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1441 entry->flags^=CoderAdjoinFlag;
1442 entry->flags|=CoderStealthFlag;
1443 entry->flags|=CoderDecoderSeekableStreamFlag;
1444 (void) RegisterMagickInfo(entry);
1445 entry=AcquireMagickInfo("META","8BIMWTEXT",
1446 "Photoshop resource wide text format");
1447 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1448 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1449 entry->flags^=CoderAdjoinFlag;
1450 entry->flags|=CoderStealthFlag;
1451 entry->flags|=CoderDecoderSeekableStreamFlag;
1452 (void) RegisterMagickInfo(entry);
1453 entry=AcquireMagickInfo("META","APP1","Raw application information");
1454 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1455 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1456 entry->flags^=CoderAdjoinFlag;
1457 entry->flags|=CoderStealthFlag;
1458 entry->flags|=CoderDecoderSeekableStreamFlag;
1459 (void) RegisterMagickInfo(entry);
1460 entry=AcquireMagickInfo("META","APP1JPEG","Raw JPEG binary data");
1461 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1462 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1463 entry->flags^=CoderAdjoinFlag;
1464 entry->flags|=CoderStealthFlag;
1465 entry->flags|=CoderDecoderSeekableStreamFlag;
1466 (void) RegisterMagickInfo(entry);
1467 entry=AcquireMagickInfo("META","EXIF","Exif digital camera binary data");
1468 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1469 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1470 entry->flags^=CoderAdjoinFlag;
1471 entry->flags|=CoderStealthFlag;
1472 entry->flags|=CoderDecoderSeekableStreamFlag;
1473 (void) RegisterMagickInfo(entry);
1474 entry=AcquireMagickInfo("META","XMP","Adobe XML metadata");
1475 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1476 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1477 entry->flags^=CoderAdjoinFlag;
1478 entry->flags|=CoderStealthFlag;
1479 entry->flags|=CoderDecoderSeekableStreamFlag;
1480 (void) RegisterMagickInfo(entry);
1481 entry=AcquireMagickInfo("META","ICM","ICC Color Profile");
1482 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1483 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1484 entry->flags^=CoderAdjoinFlag;
1485 entry->flags|=CoderStealthFlag;
1486 entry->flags|=CoderDecoderSeekableStreamFlag;
1487 (void) RegisterMagickInfo(entry);
1488 entry=AcquireMagickInfo("META","ICC","ICC Color Profile");
1489 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1490 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1491 entry->flags^=CoderAdjoinFlag;
1492 entry->flags|=CoderStealthFlag;
1493 entry->flags|=CoderDecoderSeekableStreamFlag;
1494 (void) RegisterMagickInfo(entry);
1495 entry=AcquireMagickInfo("META","IPTC","IPTC Newsphoto");
1496 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1497 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1498 entry->flags^=CoderAdjoinFlag;
1499 entry->flags|=CoderStealthFlag;
1500 entry->flags|=CoderDecoderSeekableStreamFlag;
1501 (void) RegisterMagickInfo(entry);
1502 entry=AcquireMagickInfo("META","IPTCTEXT","IPTC Newsphoto text format");
1503 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1504 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1505 entry->flags^=CoderAdjoinFlag;
1506 entry->flags|=CoderStealthFlag;
1507 entry->flags|=CoderDecoderSeekableStreamFlag;
1508 (void) RegisterMagickInfo(entry);
1509 entry=AcquireMagickInfo("META","IPTCWTEXT","IPTC Newsphoto text format");
1510 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1511 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1512 entry->flags^=CoderAdjoinFlag;
1513 entry->flags|=CoderStealthFlag;
1514 entry->flags|=CoderDecoderSeekableStreamFlag;
1515 (void) RegisterMagickInfo(entry);
1516 return(MagickImageCoderSignature);
1520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524 % U n r e g i s t e r M E T A I m a g e %
1528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530 % UnregisterMETAImage() removes format registrations made by the
1531 % META module from the list of supported formats.
1533 % The format of the UnregisterMETAImage method is:
1535 % UnregisterMETAImage(void)
1538 ModuleExport void UnregisterMETAImage(void)
1540 (void) UnregisterMagickInfo("8BIM");
1541 (void) UnregisterMagickInfo("8BIMTEXT");
1542 (void) UnregisterMagickInfo("8BIMWTEXT");
1543 (void) UnregisterMagickInfo("EXIF");
1544 (void) UnregisterMagickInfo("APP1");
1545 (void) UnregisterMagickInfo("APP1JPEG");
1546 (void) UnregisterMagickInfo("ICCTEXT");
1547 (void) UnregisterMagickInfo("ICM");
1548 (void) UnregisterMagickInfo("ICC");
1549 (void) UnregisterMagickInfo("IPTC");
1550 (void) UnregisterMagickInfo("IPTCTEXT");
1551 (void) UnregisterMagickInfo("IPTCWTEXT");
1552 (void) UnregisterMagickInfo("XMP");
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 % W r i t e M E T A I m a g e %
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 % WriteMETAImage() writes a META image to a file.
1568 % The format of the WriteMETAImage method is:
1570 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1571 % Image *image,ExceptionInfo *exception)
1573 % Compression code contributed by Kyle Shorter.
1575 % A description of each parameter follows:
1577 % o image_info: Specifies a pointer to an ImageInfo structure.
1579 % o image: A pointer to a Image structure.
1581 % o exception: return any errors or warnings in this structure.
1585 static size_t GetIPTCStream(unsigned char **info,size_t length)
1593 register unsigned char
1608 if ((*p == 0x1c) && (*(p+1) == 0x02))
1611 Extract IPTC from 8BIM resource block.
1613 while (extent >= 12)
1615 if (strncmp((const char *) p,"8BIM",4))
1619 marker=(unsigned int) (*p) << 8 | *(p+1);
1625 if ((size_t) c >= extent)
1631 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
1632 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
1635 if (tag_length > extent)
1637 if (marker == IPTC_ID)
1642 if ((tag_length & 0x01) != 0)
1648 Find the beginning of the IPTC info.
1664 *info=p; /* let the caller know were it is */
1669 Determine the length of the IPTC info.
1686 Found the 0x1c tag; skip the dataset and record number tags.
1688 c=(*p++); /* should be 2 */
1692 if ((info_length == 1) && (c != 2))
1695 c=(*p++); /* should be 0 */
1699 if ((info_length == 2) && (c != 0))
1703 Decode the length of the block that follows - ssize_t or short format.
1710 if ((c & 0x80) != 0)
1716 for (i=0; i < 4; i++)
1731 tag_length=((long) c) << 8;
1737 tag_length|=(long) c;
1739 if (tag_length > (length+1))
1745 info_length+=tag_length;
1747 return(info_length);
1750 static void formatString(Image *ofile, const char *s, int len)
1753 temp[MagickPathExtent];
1755 (void) WriteBlobByte(ofile,'"');
1756 for (; len > 0; len--, s++) {
1760 (void) WriteBlobString(ofile,"&");
1764 (void) WriteBlobString(ofile,"<");
1767 (void) WriteBlobString(ofile,">");
1771 (void) WriteBlobString(ofile,""");
1775 (void) WriteBlobByte(ofile,(unsigned char) *s);
1778 (void) FormatLocaleString(temp,MagickPathExtent,"&#%d;", c & 255);
1779 (void) WriteBlobString(ofile,temp);
1784 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1785 (void) WriteBlobString(ofile,"\"\r\n");
1787 #if defined(macintosh)
1788 (void) WriteBlobString(ofile,"\"\r");
1790 (void) WriteBlobString(ofile,"\"\n");
1795 typedef struct _tag_spec
1804 static const tag_spec tags[] = {
1805 { 5, "Image Name" },
1806 { 7, "Edit Status" },
1809 { 20, "Supplemental Category" },
1810 { 22, "Fixture Identifier" },
1812 { 30, "Release Date" },
1813 { 35, "Release Time" },
1814 { 40, "Special Instructions" },
1815 { 45, "Reference Service" },
1816 { 47, "Reference Date" },
1817 { 50, "Reference Number" },
1818 { 55, "Created Date" },
1819 { 60, "Created Time" },
1820 { 65, "Originating Program" },
1821 { 70, "Program Version" },
1822 { 75, "Object Cycle" },
1824 { 85, "Byline Title" },
1826 { 92, "Sub-Location" },
1827 { 95, "Province State" },
1828 { 100, "Country Code" },
1830 { 103, "Original Transmission Reference" },
1831 { 105, "Headline" },
1834 { 116, "Copyright String" },
1836 { 121, "Image Orientation" },
1837 { 122, "Caption Writer" },
1838 { 131, "Local Caption" },
1839 { 200, "Custom Field 1" },
1840 { 201, "Custom Field 2" },
1841 { 202, "Custom Field 3" },
1842 { 203, "Custom Field 4" },
1843 { 204, "Custom Field 5" },
1844 { 205, "Custom Field 6" },
1845 { 206, "Custom Field 7" },
1846 { 207, "Custom Field 8" },
1847 { 208, "Custom Field 9" },
1848 { 209, "Custom Field 10" },
1849 { 210, "Custom Field 11" },
1850 { 211, "Custom Field 12" },
1851 { 212, "Custom Field 13" },
1852 { 213, "Custom Field 14" },
1853 { 214, "Custom Field 15" },
1854 { 215, "Custom Field 16" },
1855 { 216, "Custom Field 17" },
1856 { 217, "Custom Field 18" },
1857 { 218, "Custom Field 19" },
1858 { 219, "Custom Field 20" }
1861 static int formatIPTC(Image *ifile, Image *ofile)
1864 temp[MagickPathExtent];
1884 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1889 foundiptc = 0; /* found the IPTC-Header */
1890 tagsfound = 0; /* number of tags found */
1892 c = ReadBlobByte(ifile);
1908 /* we found the 0x1c tag and now grab the dataset and record number tags */
1909 c = ReadBlobByte(ifile);
1912 dataset = (unsigned char) c;
1913 c = ReadBlobByte(ifile);
1916 recnum = (unsigned char) c;
1917 /* try to match this record to one of the ones in our named table */
1918 for (i=0; i< tagcount; i++)
1920 if (tags[i].id == (short) recnum)
1924 readable = (unsigned char *) tags[i].name;
1926 readable = (unsigned char *) "";
1928 We decode the length of the block that follows - ssize_t or short fmt.
1930 c=ReadBlobByte(ifile);
1933 if (c & (unsigned char) 0x80)
1940 c0=ReadBlobByte(ifile);
1943 taglen = (c << 8) | c0;
1947 /* make a buffer to hold the tag datand snag it from the input stream */
1948 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MagickPathExtent),
1950 if (str == (unsigned char *) NULL)
1952 for (tagindx=0; tagindx<taglen; tagindx++)
1954 c=ReadBlobByte(ifile);
1957 str=(unsigned char *) RelinquishMagickMemory(str);
1960 str[tagindx] = (unsigned char) c;
1964 /* now finish up by formatting this binary data into ASCII equivalent */
1965 if (strlen((char *)readable) > 0)
1966 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
1967 (unsigned int) dataset, (unsigned int) recnum, readable);
1969 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
1970 (unsigned int) dataset,(unsigned int) recnum);
1971 (void) WriteBlobString(ofile,temp);
1972 formatString( ofile, (char *)str, taglen );
1973 str=(unsigned char *) RelinquishMagickMemory(str);
1977 c=ReadBlobByte(ifile);
1979 return((int) tagsfound);
1982 static int readWordFromBuffer(char **s, ssize_t *len)
1993 c = *(*s)++; (*len)--;
1994 if (*len < 0) return -1;
1995 buffer[i] = (unsigned char) c;
1997 return (((int) buffer[ 0 ]) << 8) |
1998 (((int) buffer[ 1 ]));
2001 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
2004 temp[MagickPathExtent];
2024 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
2029 foundiptc = 0; /* found the IPTC-Header */
2030 tagsfound = 0; /* number of tags found */
2045 We found the 0x1c tag and now grab the dataset and record number tags.
2048 if (len < 0) return -1;
2049 dataset = (unsigned char) c;
2051 if (len < 0) return -1;
2052 recnum = (unsigned char) c;
2053 /* try to match this record to one of the ones in our named table */
2054 for (i=0; i< tagcount; i++)
2055 if (tags[i].id == (short) recnum)
2058 readable=(unsigned char *) tags[i].name;
2060 readable=(unsigned char *) "";
2062 We decode the length of the block that follows - ssize_t or short fmt.
2068 if (c & (unsigned char) 0x80)
2074 taglen=readWordFromBuffer(&s, &len);
2080 /* make a buffer to hold the tag datand snag it from the input stream */
2081 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+MagickPathExtent),
2083 if (str == (unsigned char *) NULL)
2084 printf("MemoryAllocationFailed");
2085 for (tagindx=0; tagindx<taglen; tagindx++)
2090 str[tagindx]=(unsigned char) c;
2094 /* now finish up by formatting this binary data into ASCII equivalent */
2095 if (strlen((char *)readable) > 0)
2096 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
2097 (unsigned int) dataset,(unsigned int) recnum, readable);
2099 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
2100 (unsigned int) dataset,(unsigned int) recnum);
2101 (void) WriteBlobString(ofile,temp);
2102 formatString( ofile, (char *)str, taglen );
2103 str=(unsigned char *) RelinquishMagickMemory(str);
2107 return ((int) tagsfound);
2110 static int format8BIM(Image *ifile, Image *ofile)
2113 temp[MagickPathExtent];
2132 foundOSType=0; /* found the OSType */
2134 c=ReadBlobByte(ifile);
2142 buffer[0]=(unsigned char) c;
2145 c=ReadBlobByte(ifile);
2148 buffer[i] = (unsigned char) c;
2151 if (strcmp((const char *)buffer, "8BIM") == 0)
2158 c=ReadBlobByte(ifile);
2162 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2164 ID=ReadBlobMSBSignedShort(ifile);
2171 c=ReadBlobByte(ifile);
2174 plen = (unsigned char) c;
2175 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2176 MagickPathExtent),sizeof(*PString));
2177 if (PString == (unsigned char *) NULL)
2179 for (i=0; i<plen; i++)
2181 c=ReadBlobByte(ifile);
2184 PString=(unsigned char *) RelinquishMagickMemory(PString);
2187 PString[i] = (unsigned char) c;
2189 PString[ plen ] = 0;
2190 if ((plen & 0x01) == 0)
2192 c=ReadBlobByte(ifile);
2195 PString=(unsigned char *) RelinquishMagickMemory(PString);
2200 count=(ssize_t) ReadBlobMSBSignedLong(ifile);
2203 PString=(unsigned char *) RelinquishMagickMemory(PString);
2206 /* make a buffer to hold the datand snag it from the input stream */
2207 str=(unsigned char *) AcquireQuantumMemory((size_t) count,sizeof(*str));
2208 if (str == (unsigned char *) NULL)
2210 PString=(unsigned char *) RelinquishMagickMemory(PString);
2213 for (i=0; i < (ssize_t) count; i++)
2215 c=ReadBlobByte(ifile);
2218 str=(unsigned char *) RelinquishMagickMemory(str);
2219 PString=(unsigned char *) RelinquishMagickMemory(PString);
2222 str[i]=(unsigned char) c;
2225 /* we currently skip thumbnails, since it does not make
2226 * any sense preserving them in a real world application
2228 if (ID != THUMBNAIL_ID)
2230 /* now finish up by formatting this binary data into
2233 if (strlen((const char *)PString) > 0)
2234 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d#%s=",ID,
2237 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d=",ID);
2238 (void) WriteBlobString(ofile,temp);
2241 formatString(ofile, "IPTC", 4);
2242 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
2245 formatString(ofile, (char *)str, (ssize_t) count);
2247 str=(unsigned char *) RelinquishMagickMemory(str);
2248 PString=(unsigned char *) RelinquishMagickMemory(PString);
2250 c=ReadBlobByte(ifile);
2255 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2256 Image *image,ExceptionInfo *exception)
2270 assert(image_info != (const ImageInfo *) NULL);
2271 assert(image_info->signature == MagickCoreSignature);
2272 assert(image != (Image *) NULL);
2273 assert(image->signature == MagickCoreSignature);
2274 if (image->debug != MagickFalse)
2275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2277 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2282 profile=GetImageProfile(image,"8bim");
2283 if (profile == (StringInfo *) NULL)
2284 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2285 assert(exception != (ExceptionInfo *) NULL);
2286 assert(exception->signature == MagickCoreSignature);
2287 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2288 if (status == MagickFalse)
2290 (void) WriteBlob(image,GetStringInfoLength(profile),
2291 GetStringInfoDatum(profile));
2292 (void) CloseBlob(image);
2295 if (LocaleCompare(image_info->magick,"iptc") == 0)
2303 profile=GetImageProfile(image,"iptc");
2304 if (profile == (StringInfo *) NULL)
2305 profile=GetImageProfile(image,"8bim");
2306 if (profile == (StringInfo *) NULL)
2307 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2308 assert(exception != (ExceptionInfo *) NULL);
2309 assert(exception->signature == MagickCoreSignature);
2310 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2311 info=GetStringInfoDatum(profile);
2312 length=GetStringInfoLength(profile);
2313 length=GetIPTCStream(&info,length);
2315 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2316 (void) WriteBlob(image,length,info);
2317 (void) CloseBlob(image);
2320 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2325 profile=GetImageProfile(image,"8bim");
2326 if (profile == (StringInfo *) NULL)
2327 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2328 assert(exception != (ExceptionInfo *) NULL);
2329 assert(exception->signature == MagickCoreSignature);
2330 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2331 if (status == MagickFalse)
2333 buff=AcquireImage((ImageInfo *) NULL,exception);
2334 if (buff == (Image *) NULL)
2335 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2336 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2337 GetStringInfoLength(profile));
2338 format8BIM(buff,image);
2339 (void) DetachBlob(buff->blob);
2340 buff=DestroyImage(buff);
2341 (void) CloseBlob(image);
2344 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2345 return(MagickFalse);
2346 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2354 profile=GetImageProfile(image,"8bim");
2355 if (profile == (StringInfo *) NULL)
2356 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2357 info=GetStringInfoDatum(profile);
2358 length=GetStringInfoLength(profile);
2359 length=GetIPTCStream(&info,length);
2361 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2362 assert(exception != (ExceptionInfo *) NULL);
2363 assert(exception->signature == MagickCoreSignature);
2364 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2365 if (status == MagickFalse)
2367 buff=AcquireImage((ImageInfo *) NULL,exception);
2368 if (buff == (Image *) NULL)
2369 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2370 AttachBlob(buff->blob,info,length);
2371 formatIPTC(buff,image);
2372 (void) DetachBlob(buff->blob);
2373 buff=DestroyImage(buff);
2374 (void) CloseBlob(image);
2377 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2378 return(MagickFalse);
2379 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2380 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2381 (LocaleCompare(image_info->magick,"XMP") == 0))
2384 (void) Write APP1 image.
2386 profile=GetImageProfile(image,image_info->magick);
2387 if (profile == (StringInfo *) NULL)
2388 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2389 assert(exception != (ExceptionInfo *) NULL);
2390 assert(exception->signature == MagickCoreSignature);
2391 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2392 if (status == MagickFalse)
2394 (void) WriteBlob(image,GetStringInfoLength(profile),
2395 GetStringInfoDatum(profile));
2396 (void) CloseBlob(image);
2399 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2400 (LocaleCompare(image_info->magick,"ICM") == 0))
2405 profile=GetImageProfile(image,"icc");
2406 if (profile == (StringInfo *) NULL)
2407 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2408 assert(exception != (ExceptionInfo *) NULL);
2409 assert(exception->signature == MagickCoreSignature);
2410 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2411 if (status == MagickFalse)
2413 (void) WriteBlob(image,GetStringInfoLength(profile),
2414 GetStringInfoDatum(profile));
2415 (void) CloseBlob(image);
2418 return(MagickFalse);