xpm.c revision de984cdc3631106b1cbbb8d3972b76a0fc27e8e8
12cfd52c507bd5790457a171eb9bcb39019cc6860Chris Lattner/* 2c140c4803dc3e10e08138670829bc0494986abe9David Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 4c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 5c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 6c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% X X PPPP M M % 7c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% X X P P MM MM % 8c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% X PPPP M M M % 9c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% X X P M M % 10c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% X X P M M % 11c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 12c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 13c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% Read/Write X Windows system Pixmap Format % 14c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 15c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% Software Design % 16c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% Cristy % 17c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% July 1992 % 18c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 19c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 20c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization % 21c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% dedicated to making software imaging solutions freely available. % 22c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 23db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% You may not use this file except in compliance with the License. You may % 24c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% obtain a copy of the License at % 25c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 26c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% http://www.imagemagick.org/script/license.php % 27c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 28c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% Unless required by applicable law or agreed to in writing, software % 29c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% distributed under the License is distributed on an "AS IS" BASIS, % 30c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% See the License for the specific language governing permissions and % 32c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% limitations under the License. % 33c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 34c140c4803dc3e10e08138670829bc0494986abe9David Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 36c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 37c140c4803dc3e10e08138670829bc0494986abe9David Goodwin*/ 38c140c4803dc3e10e08138670829bc0494986abe9David Goodwin 39c140c4803dc3e10e08138670829bc0494986abe9David Goodwin/* 40c140c4803dc3e10e08138670829bc0494986abe9David Goodwin Include declarations. 41c140c4803dc3e10e08138670829bc0494986abe9David Goodwin*/ 42c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/studio.h" 43c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/attribute.h" 44c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/blob.h" 45c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/blob-private.h" 46c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/cache.h" 47c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/color.h" 48c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/color-private.h" 49db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin#include "MagickCore/colormap.h" 50c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/colorspace.h" 51c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/colorspace-private.h" 52c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/exception.h" 53c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/exception-private.h" 54c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/geometry.h" 55db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin#include "MagickCore/image.h" 56b5619f42f4fdf347380d28357549df09b9ca3946Evan Cheng#include "MagickCore/image-private.h" 57b5619f42f4fdf347380d28357549df09b9ca3946Evan Cheng#include "MagickCore/list.h" 58db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin#include "MagickCore/magick.h" 5977521f5232e679aa3de10aaaed2464aa91d7ff55David Goodwin#include "MagickCore/memory_.h" 6077521f5232e679aa3de10aaaed2464aa91d7ff55David Goodwin#include "MagickCore/monitor.h" 6177521f5232e679aa3de10aaaed2464aa91d7ff55David Goodwin#include "MagickCore/monitor-private.h" 62db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin#include "MagickCore/pixel-accessor.h" 63c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/quantize.h" 648295d99bff6f8e3dfdfdaf1871cb72adab423f20Evan Cheng#include "MagickCore/quantum-private.h" 658295d99bff6f8e3dfdfdaf1871cb72adab423f20Evan Cheng#include "MagickCore/resize.h" 668295d99bff6f8e3dfdfdaf1871cb72adab423f20Evan Cheng#include "MagickCore/resource_.h" 678295d99bff6f8e3dfdfdaf1871cb72adab423f20Evan Cheng#include "MagickCore/splay-tree.h" 68c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/static.h" 69c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/string_.h" 70c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/module.h" 71c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/threshold.h" 72c140c4803dc3e10e08138670829bc0494986abe9David Goodwin#include "MagickCore/utility.h" 73c140c4803dc3e10e08138670829bc0494986abe9David Goodwin 74c140c4803dc3e10e08138670829bc0494986abe9David Goodwin/* 75c140c4803dc3e10e08138670829bc0494986abe9David Goodwin Forward declarations. 76c140c4803dc3e10e08138670829bc0494986abe9David Goodwin*/ 772cfd52c507bd5790457a171eb9bcb39019cc6860Chris Lattnerstatic MagickBooleanType 78c140c4803dc3e10e08138670829bc0494986abe9David Goodwin WritePICONImage(const ImageInfo *,Image *,ExceptionInfo *), 79c140c4803dc3e10e08138670829bc0494986abe9David Goodwin WriteXPMImage(const ImageInfo *,Image *,ExceptionInfo *); 80c140c4803dc3e10e08138670829bc0494986abe9David Goodwin 81c140c4803dc3e10e08138670829bc0494986abe9David Goodwin/* 82c140c4803dc3e10e08138670829bc0494986abe9David Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 84c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 85c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 86c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% I s X P M % 87c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 88c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 89c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% % 90c140c4803dc3e10e08138670829bc0494986abe9David Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9198a0104014e9bb6ed89c2572f615351fd526674aEvan Cheng% 9298a0104014e9bb6ed89c2572f615351fd526674aEvan Cheng% IsXPM() returns MagickTrue if the image format type, identified by the 93c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% magick string, is XPM. 94c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 95c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% The format of the IsXPM method is: 96c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 97c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) 98c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 99c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% A description of each parameter follows: 100c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 101c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% o magick: compare image format pattern against these bytes. or 102c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% blob. 103c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 104c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% o length: Specifies the length of the magick string. 105c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 106c140c4803dc3e10e08138670829bc0494986abe9David Goodwin*/ 107c140c4803dc3e10e08138670829bc0494986abe9David Goodwinstatic MagickBooleanType IsXPM(const unsigned char *magick,const size_t length) 108c140c4803dc3e10e08138670829bc0494986abe9David Goodwin{ 109db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin if (length < 9) 110db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin return(MagickFalse); 111db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0) 112db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin return(MagickTrue); 113db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin return(MagickFalse); 11477521f5232e679aa3de10aaaed2464aa91d7ff55David Goodwin} 115378445303b10b092a898a75131141a8259cff50bEvan Cheng 116378445303b10b092a898a75131141a8259cff50bEvan Cheng/* 117db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 119db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 120db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 121db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% R e a d X P M I m a g e % 122db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 123db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 124db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% % 125db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% 127db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% ReadXPMImage() reads an X11 pixmap image file and returns it. It 128db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% allocates the memory necessary for the new Image structure and returns a 129db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% pointer to the new image. 130db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% 1316495f63945e8dbde81f03a1dc2ab421993b9a495Evan Cheng% The format of the ReadXPMImage method is: 1326495f63945e8dbde81f03a1dc2ab421993b9a495Evan Cheng% 133db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) 134db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% 135db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% A description of each parameter follows: 136db5a71a8e01ed9a0d93a19176df6ea0aea510d7bDavid Goodwin% 137c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% o image_info: the image info. 138ee42fd309ee6a8febfafb97c2f3b6f2069758c5eEvan Cheng% 139ee42fd309ee6a8febfafb97c2f3b6f2069758c5eEvan Cheng% o exception: return any errors or warnings in this structure. 140c140c4803dc3e10e08138670829bc0494986abe9David Goodwin% 141c140c4803dc3e10e08138670829bc0494986abe9David Goodwin*/ 142c140c4803dc3e10e08138670829bc0494986abe9David Goodwin 143c140c4803dc3e10e08138670829bc0494986abe9David Goodwinstatic int CompareXPMColor(const void *target,const void *source) 144c140c4803dc3e10e08138670829bc0494986abe9David Goodwin{ 145c140c4803dc3e10e08138670829bc0494986abe9David Goodwin const char 146c140c4803dc3e10e08138670829bc0494986abe9David Goodwin *p, 147c140c4803dc3e10e08138670829bc0494986abe9David Goodwin *q; 148 149 p=(const char *) target; 150 q=(const char *) source; 151 return(strcmp(p,q)); 152} 153 154static char *CopyXPMColor(char *destination,const char *source,size_t length) 155{ 156 while (length-- && (*source != '\0')) 157 *destination++=(*source++); 158 *destination='\0'; 159 return(destination-length); 160} 161 162static char *NextXPMLine(char *p) 163{ 164 assert(p != (char*)NULL); 165 p=strchr(p,'\n'); 166 if (p != (char *) NULL) 167 p++; 168 return(p); 169} 170 171static inline size_t MagickMin(const size_t x,const size_t y) 172{ 173 if (x < y) 174 return(x); 175 return(y); 176} 177 178static char *ParseXPMColor(char *color) 179{ 180#define NumberTargets 6 181 182 register char 183 *p, 184 *r; 185 186 register const char 187 *q; 188 189 register ssize_t 190 i; 191 192 static const char 193 *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " }; 194 195 for (i=0; i < NumberTargets; i++) 196 { 197 p=color; 198 for (q=targets[i]; *p != '\0'; p++) 199 { 200 if (*p == '\n') 201 break; 202 if (*p != *q) 203 continue; 204 if (isspace((int) ((unsigned char) (*(p-1)))) == 0) 205 continue; 206 r=p; 207 for ( ; ; ) 208 { 209 if (*q == '\0') 210 return(p); 211 if (*r++ != *q++) 212 break; 213 } 214 q=targets[i]; 215 } 216 } 217 return((char *) NULL); 218} 219 220static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) 221{ 222 char 223 key[MaxTextExtent], 224 target[MaxTextExtent], 225 *xpm_buffer; 226 227 Image 228 *image; 229 230 MagickBooleanType 231 active, 232 status; 233 234 register char 235 *p, 236 *q, 237 *next; 238 239 register ssize_t 240 x; 241 242 register Quantum 243 *r; 244 245 size_t 246 length; 247 248 SplayTreeInfo 249 *xpm_colors; 250 251 ssize_t 252 count, 253 j, 254 y; 255 256 unsigned long 257 colors, 258 columns, 259 rows, 260 width; 261 262 /* 263 Open image file. 264 */ 265 assert(image_info != (const ImageInfo *) NULL); 266 assert(image_info->signature == MagickSignature); 267 if (image_info->debug != MagickFalse) 268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 269 image_info->filename); 270 assert(exception != (ExceptionInfo *) NULL); 271 assert(exception->signature == MagickSignature); 272 image=AcquireImage(image_info,exception); 273 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 274 if (status == MagickFalse) 275 { 276 image=DestroyImageList(image); 277 return((Image *) NULL); 278 } 279 /* 280 Read XPM file. 281 */ 282 length=MaxTextExtent; 283 xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer)); 284 p=xpm_buffer; 285 if (xpm_buffer != (char *) NULL) 286 while (ReadBlobString(image,p) != (char *) NULL) 287 { 288 if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n'))) 289 continue; 290 if ((*p == '}') && (*(p+1) == ';')) 291 break; 292 p+=strlen(p); 293 if ((size_t) (p-xpm_buffer+MaxTextExtent) < length) 294 continue; 295 length<<=1; 296 xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent, 297 sizeof(*xpm_buffer)); 298 if (xpm_buffer == (char *) NULL) 299 break; 300 p=xpm_buffer+strlen(xpm_buffer); 301 } 302 if (xpm_buffer == (char *) NULL) 303 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 304 /* 305 Remove comments. 306 */ 307 count=0; 308 width=0; 309 for (p=xpm_buffer; *p != '\0'; p++) 310 { 311 if (*p != '"') 312 continue; 313 count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width); 314 image->columns=columns; 315 image->rows=rows; 316 image->colors=colors; 317 if (count == 4) 318 break; 319 } 320 if ((count != 4) || (width > 10) || (image->columns == 0) || 321 (image->rows == 0) || (image->colors == 0)) 322 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 323 /* 324 Remove unquoted characters. 325 */ 326 active=MagickFalse; 327 q=xpm_buffer; 328 while (*p != '\0') 329 { 330 if (*p++ == '"') 331 { 332 if (active != MagickFalse) 333 *q++='\n'; 334 active=active != MagickFalse ? MagickFalse : MagickTrue; 335 } 336 if (active != MagickFalse) 337 *q++=(*p); 338 } 339 *q='\0'; 340 /* 341 Initialize image structure. 342 */ 343 xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory, 344 (void *(*)(void *)) NULL); 345 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 346 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 347 /* 348 Read image colormap. 349 */ 350 image->depth=1; 351 next=NextXPMLine(xpm_buffer); 352 for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++) 353 { 354 p=next; 355 next=NextXPMLine(p); 356 (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent)); 357 status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j); 358 /* 359 Parse color. 360 */ 361 (void) CopyMagickString(target,"gray",MaxTextExtent); 362 q=ParseXPMColor(p+width); 363 if (q != (char *) NULL) 364 { 365 while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0')) 366 q++; 367 if (next != (char *) NULL) 368 (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q), 369 MaxTextExtent)); 370 else 371 (void) CopyMagickString(target,q,MaxTextExtent); 372 q=ParseXPMColor(target); 373 if (q != (char *) NULL) 374 *q='\0'; 375 } 376 StripString(target); 377 if (LocaleCompare(target,"none") == 0) 378 { 379 image->storage_class=DirectClass; 380 image->alpha_trait=BlendPixelTrait; 381 } 382 status=QueryColorCompliance(target,XPMCompliance,&image->colormap[j], 383 exception); 384 if (status == MagickFalse) 385 break; 386 if (image->depth < image->colormap[j].depth) 387 image->depth=image->colormap[j].depth; 388 } 389 if (j < (ssize_t) image->colors) 390 ThrowReaderException(CorruptImageError,"CorruptImage"); 391 j=0; 392 if (image_info->ping == MagickFalse) 393 { 394 /* 395 Read image pixels. 396 */ 397 for (y=0; y < (ssize_t) image->rows; y++) 398 { 399 p=NextXPMLine(p); 400 if (p == (char *) NULL) 401 break; 402 r=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 403 if (r == (Quantum *) NULL) 404 break; 405 for (x=0; x < (ssize_t) image->columns; x++) 406 { 407 (void) CopyXPMColor(key,p,(size_t) width); 408 j=(ssize_t) GetValueFromSplayTree(xpm_colors,key); 409 if (image->storage_class == PseudoClass) 410 SetPixelIndex(image,j,r); 411 SetPixelInfoPixel(image,image->colormap+j,r); 412 p+=width; 413 r+=GetPixelChannels(image); 414 } 415 if (SyncAuthenticPixels(image,exception) == MagickFalse) 416 break; 417 } 418 if (y < (ssize_t) image->rows) 419 ThrowReaderException(CorruptImageError,"NotEnoughPixelData"); 420 } 421 /* 422 Relinquish resources. 423 */ 424 xpm_colors=DestroySplayTree(xpm_colors); 425 (void) CloseBlob(image); 426 return(GetFirstImageInList(image)); 427} 428 429/* 430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 431% % 432% % 433% % 434% R e g i s t e r X P M I m a g e % 435% % 436% % 437% % 438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439% 440% RegisterXPMImage() adds attributes for the XPM image format to 441% the list of supported formats. The attributes include the image format 442% tag, a method to read and/or write the format, whether the format 443% supports the saving of more than one frame to the same file or blob, 444% whether the format supports native in-memory I/O, and a brief 445% description of the format. 446% 447% The format of the RegisterXPMImage method is: 448% 449% size_t RegisterXPMImage(void) 450% 451*/ 452ModuleExport size_t RegisterXPMImage(void) 453{ 454 MagickInfo 455 *entry; 456 457 entry=SetMagickInfo("PICON"); 458 entry->decoder=(DecodeImageHandler *) ReadXPMImage; 459 entry->encoder=(EncodeImageHandler *) WritePICONImage; 460 entry->adjoin=MagickFalse; 461 entry->description=ConstantString("Personal Icon"); 462 entry->module=ConstantString("XPM"); 463 (void) RegisterMagickInfo(entry); 464 entry=SetMagickInfo("PM"); 465 entry->decoder=(DecodeImageHandler *) ReadXPMImage; 466 entry->encoder=(EncodeImageHandler *) WriteXPMImage; 467 entry->adjoin=MagickFalse; 468 entry->stealth=MagickTrue; 469 entry->description=ConstantString("X Windows system pixmap (color)"); 470 entry->module=ConstantString("XPM"); 471 (void) RegisterMagickInfo(entry); 472 entry=SetMagickInfo("XPM"); 473 entry->decoder=(DecodeImageHandler *) ReadXPMImage; 474 entry->encoder=(EncodeImageHandler *) WriteXPMImage; 475 entry->magick=(IsImageFormatHandler *) IsXPM; 476 entry->adjoin=MagickFalse; 477 entry->description=ConstantString("X Windows system pixmap (color)"); 478 entry->module=ConstantString("XPM"); 479 (void) RegisterMagickInfo(entry); 480 return(MagickImageCoderSignature); 481} 482 483/* 484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 485% % 486% % 487% % 488% U n r e g i s t e r X P M I m a g e % 489% % 490% % 491% % 492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 493% 494% UnregisterXPMImage() removes format registrations made by the 495% XPM module from the list of supported formats. 496% 497% The format of the UnregisterXPMImage method is: 498% 499% UnregisterXPMImage(void) 500% 501*/ 502ModuleExport void UnregisterXPMImage(void) 503{ 504 (void) UnregisterMagickInfo("PICON"); 505 (void) UnregisterMagickInfo("PM"); 506 (void) UnregisterMagickInfo("XPM"); 507} 508 509/* 510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 511% % 512% % 513% % 514% W r i t e P I C O N I m a g e % 515% % 516% % 517% % 518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 519% 520% WritePICONImage() writes an image to a file in the Personal Icon format. 521% 522% The format of the WritePICONImage method is: 523% 524% MagickBooleanType WritePICONImage(const ImageInfo *image_info, 525% Image *image,ExceptionInfo *exception) 526% 527% A description of each parameter follows. 528% 529% o image_info: the image info. 530% 531% o image: The image. 532% 533% o exception: return any errors or warnings in this structure. 534% 535*/ 536static MagickBooleanType WritePICONImage(const ImageInfo *image_info, 537 Image *image,ExceptionInfo *exception) 538{ 539#define ColormapExtent 155 540#define GraymapExtent 95 541#define PiconGeometry "48x48>" 542 543 static unsigned char 544 Colormap[]= 545 { 546 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05, 547 0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e, 548 0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 549 0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff, 550 0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd, 551 0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00, 552 0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff, 553 0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4, 554 0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 555 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 556 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08, 557 0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49, 558 0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b, 559 }, 560 Graymap[]= 561 { 562 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f, 563 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33, 564 0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78, 565 0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba, 566 0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff, 567 0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 568 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31, 569 0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b, 570 }; 571 572#define MaxCixels 92 573 574 static const char 575 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 576 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 577 578 char 579 buffer[MaxTextExtent], 580 basename[MaxTextExtent], 581 name[MaxTextExtent], 582 symbol[MaxTextExtent]; 583 584 Image 585 *affinity_image, 586 *picon; 587 588 ImageInfo 589 *blob_info; 590 591 MagickBooleanType 592 status, 593 transparent; 594 595 PixelInfo 596 pixel; 597 598 QuantizeInfo 599 *quantize_info; 600 601 RectangleInfo 602 geometry; 603 604 register const Quantum 605 *p; 606 607 register ssize_t 608 i, 609 x; 610 611 register Quantum 612 *q; 613 614 size_t 615 characters_per_pixel, 616 colors; 617 618 ssize_t 619 j, 620 k, 621 y; 622 623 /* 624 Open output image file. 625 */ 626 assert(image_info != (const ImageInfo *) NULL); 627 assert(image_info->signature == MagickSignature); 628 assert(image != (Image *) NULL); 629 assert(image->signature == MagickSignature); 630 if (image->debug != MagickFalse) 631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 632 assert(exception != (ExceptionInfo *) NULL); 633 assert(exception->signature == MagickSignature); 634 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 635 if (status == MagickFalse) 636 return(status); 637 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 638 (void) TransformImageColorspace(image,sRGBColorspace,exception); 639 SetGeometry(image,&geometry); 640 (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y, 641 &geometry.width,&geometry.height); 642 picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, 643 exception); 644 blob_info=CloneImageInfo(image_info); 645 (void) AcquireUniqueFilename(blob_info->filename); 646 if ((image_info->type != TrueColorType) && 647 (IsImageGray(image,exception) != MagickFalse)) 648 affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,exception); 649 else 650 affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,exception); 651 (void) RelinquishUniqueFileResource(blob_info->filename); 652 blob_info=DestroyImageInfo(blob_info); 653 if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL)) 654 return(MagickFalse); 655 quantize_info=AcquireQuantizeInfo(image_info); 656 status=RemapImage(quantize_info,picon,affinity_image,exception); 657 quantize_info=DestroyQuantizeInfo(quantize_info); 658 affinity_image=DestroyImage(affinity_image); 659 transparent=MagickFalse; 660 if (picon->storage_class == PseudoClass) 661 { 662 (void) CompressImageColormap(picon,exception); 663 if (picon->alpha_trait == BlendPixelTrait) 664 transparent=MagickTrue; 665 } 666 else 667 { 668 /* 669 Convert DirectClass to PseudoClass picon. 670 */ 671 if (picon->alpha_trait == BlendPixelTrait) 672 { 673 /* 674 Map all the transparent pixels. 675 */ 676 for (y=0; y < (ssize_t) picon->rows; y++) 677 { 678 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 679 if (q == (Quantum *) NULL) 680 break; 681 for (x=0; x < (ssize_t) picon->columns; x++) 682 { 683 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 684 transparent=MagickTrue; 685 else 686 SetPixelAlpha(picon,OpaqueAlpha,q); 687 q+=GetPixelChannels(picon); 688 } 689 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 690 break; 691 } 692 } 693 (void) SetImageType(picon,PaletteType,exception); 694 } 695 colors=picon->colors; 696 if (transparent != MagickFalse) 697 { 698 colors++; 699 picon->colormap=(PixelInfo *) ResizeQuantumMemory((void **) 700 picon->colormap,(size_t) colors,sizeof(*picon->colormap)); 701 if (picon->colormap == (PixelInfo *) NULL) 702 ThrowWriterException(ResourceLimitError,"MemoryAllocationError"); 703 for (y=0; y < (ssize_t) picon->rows; y++) 704 { 705 q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception); 706 if (q == (Quantum *) NULL) 707 break; 708 for (x=0; x < (ssize_t) picon->columns; x++) 709 { 710 if (GetPixelAlpha(image,q) == (Quantum) TransparentAlpha) 711 SetPixelIndex(picon,picon->colors,q); 712 q+=GetPixelChannels(picon); 713 } 714 if (SyncAuthenticPixels(picon,exception) == MagickFalse) 715 break; 716 } 717 } 718 /* 719 Compute the character per pixel. 720 */ 721 characters_per_pixel=1; 722 for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels) 723 characters_per_pixel++; 724 /* 725 XPM header. 726 */ 727 (void) WriteBlobString(image,"/* XPM */\n"); 728 GetPathComponent(picon->filename,BasePath,basename); 729 (void) FormatLocaleString(buffer,MaxTextExtent, 730 "static char *%s[] = {\n",basename); 731 (void) WriteBlobString(image,buffer); 732 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); 733 (void) FormatLocaleString(buffer,MaxTextExtent, 734 "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double) 735 picon->rows,(double) colors,(double) characters_per_pixel); 736 (void) WriteBlobString(image,buffer); 737 GetPixelInfo(image,&pixel); 738 for (i=0; i < (ssize_t) colors; i++) 739 { 740 /* 741 Define XPM color. 742 */ 743 pixel=picon->colormap[i]; 744 pixel.colorspace=sRGBColorspace; 745 pixel.depth=8; 746 pixel.alpha=(double) OpaqueAlpha; 747 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 748 if (transparent != MagickFalse) 749 { 750 if (i == (ssize_t) (colors-1)) 751 (void) CopyMagickString(name,"grey75",MaxTextExtent); 752 } 753 /* 754 Write XPM color. 755 */ 756 k=i % MaxCixels; 757 symbol[0]=Cixel[k]; 758 for (j=1; j < (ssize_t) characters_per_pixel; j++) 759 { 760 k=((i-k)/MaxCixels) % MaxCixels; 761 symbol[j]=Cixel[k]; 762 } 763 symbol[j]='\0'; 764 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n", 765 symbol,name); 766 (void) WriteBlobString(image,buffer); 767 } 768 /* 769 Define XPM pixels. 770 */ 771 (void) WriteBlobString(image,"/* pixels */\n"); 772 for (y=0; y < (ssize_t) picon->rows; y++) 773 { 774 p=GetVirtualPixels(picon,0,y,picon->columns,1,exception); 775 if (p == (const Quantum *) NULL) 776 break; 777 (void) WriteBlobString(image,"\""); 778 for (x=0; x < (ssize_t) picon->columns; x++) 779 { 780 k=((ssize_t) GetPixelIndex(picon,p) % MaxCixels); 781 symbol[0]=Cixel[k]; 782 for (j=1; j < (ssize_t) characters_per_pixel; j++) 783 { 784 k=(((int) GetPixelIndex(picon,p)-k)/MaxCixels) % MaxCixels; 785 symbol[j]=Cixel[k]; 786 } 787 symbol[j]='\0'; 788 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 789 (void) WriteBlobString(image,buffer); 790 p+=GetPixelChannels(image); 791 } 792 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 793 y == (ssize_t) (picon->rows-1) ? "" : ","); 794 (void) WriteBlobString(image,buffer); 795 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 796 picon->rows); 797 if (status == MagickFalse) 798 break; 799 } 800 picon=DestroyImage(picon); 801 (void) WriteBlobString(image,"};\n"); 802 (void) CloseBlob(image); 803 return(MagickTrue); 804} 805 806/* 807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 808% % 809% % 810% % 811% W r i t e X P M I m a g e % 812% % 813% % 814% % 815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 816% 817% WriteXPMImage() writes an image to a file in the X pixmap format. 818% 819% The format of the WriteXPMImage method is: 820% 821% MagickBooleanType WriteXPMImage(const ImageInfo *image_info, 822% Image *image,ExceptionInfo *exception) 823% 824% A description of each parameter follows. 825% 826% o image_info: the image info. 827% 828% o image: The image. 829% 830% o exception: return any errors or warnings in this structure. 831% 832*/ 833static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image, 834 ExceptionInfo *exception) 835{ 836#define MaxCixels 92 837 838 static const char 839 Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" 840 "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; 841 842 char 843 buffer[MaxTextExtent], 844 basename[MaxTextExtent], 845 name[MaxTextExtent], 846 symbol[MaxTextExtent]; 847 848 MagickBooleanType 849 status; 850 851 PixelInfo 852 pixel; 853 854 register const Quantum 855 *p; 856 857 register ssize_t 858 i, 859 x; 860 861 size_t 862 characters_per_pixel; 863 864 ssize_t 865 j, 866 k, 867 opacity, 868 y; 869 870 /* 871 Open output image file. 872 */ 873 assert(image_info != (const ImageInfo *) NULL); 874 assert(image_info->signature == MagickSignature); 875 assert(image != (Image *) NULL); 876 assert(image->signature == MagickSignature); 877 if (image->debug != MagickFalse) 878 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 879 assert(exception != (ExceptionInfo *) NULL); 880 assert(exception->signature == MagickSignature); 881 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 882 if (status == MagickFalse) 883 return(status); 884 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 885 (void) TransformImageColorspace(image,sRGBColorspace,exception); 886 opacity=(-1); 887 if (image->alpha_trait != BlendPixelTrait) 888 { 889 if ((image->storage_class == DirectClass) || (image->colors > 256)) 890 (void) SetImageType(image,PaletteType,exception); 891 } 892 else 893 { 894 double 895 alpha, 896 beta; 897 898 /* 899 Identify transparent colormap index. 900 */ 901 if ((image->storage_class == DirectClass) || (image->colors > 256)) 902 (void) SetImageType(image,PaletteBilevelMatteType,exception); 903 for (i=0; i < (ssize_t) image->colors; i++) 904 if (image->colormap[i].alpha != OpaqueAlpha) 905 { 906 if (opacity < 0) 907 { 908 opacity=i; 909 continue; 910 } 911 alpha=(double) TransparentAlpha-(double) 912 image->colormap[i].alpha; 913 beta=(double) TransparentAlpha-(double) 914 image->colormap[opacity].alpha; 915 if (alpha < beta) 916 opacity=i; 917 } 918 if (opacity == -1) 919 { 920 (void) SetImageType(image,PaletteBilevelMatteType,exception); 921 for (i=0; i < (ssize_t) image->colors; i++) 922 if (image->colormap[i].alpha != OpaqueAlpha) 923 { 924 if (opacity < 0) 925 { 926 opacity=i; 927 continue; 928 } 929 alpha=(Quantum) TransparentAlpha-(double) 930 image->colormap[i].alpha; 931 beta=(Quantum) TransparentAlpha-(double) 932 image->colormap[opacity].alpha; 933 if (alpha < beta) 934 opacity=i; 935 } 936 } 937 if (opacity >= 0) 938 { 939 image->colormap[opacity].red=image->transparent_color.red; 940 image->colormap[opacity].green=image->transparent_color.green; 941 image->colormap[opacity].blue=image->transparent_color.blue; 942 } 943 } 944 /* 945 Compute the character per pixel. 946 */ 947 characters_per_pixel=1; 948 for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels) 949 characters_per_pixel++; 950 /* 951 XPM header. 952 */ 953 (void) WriteBlobString(image,"/* XPM */\n"); 954 GetPathComponent(image->filename,BasePath,basename); 955 if (isalnum((int) ((unsigned char) *basename)) == 0) 956 { 957 (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename); 958 (void) CopyMagickString(basename,buffer,MaxTextExtent); 959 } 960 if (isalpha((int) ((unsigned char) basename[0])) == 0) 961 basename[0]='_'; 962 for (i=1; basename[i] != '\0'; i++) 963 if (isalnum((int) ((unsigned char) basename[i])) == 0) 964 basename[i]='_'; 965 (void) FormatLocaleString(buffer,MaxTextExtent, 966 "static char *%s[] = {\n",basename); 967 (void) WriteBlobString(image,buffer); 968 (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n"); 969 (void) FormatLocaleString(buffer,MaxTextExtent, 970 "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double) 971 image->rows,(double) image->colors,(double) characters_per_pixel); 972 (void) WriteBlobString(image,buffer); 973 GetPixelInfo(image,&pixel); 974 for (i=0; i < (ssize_t) image->colors; i++) 975 { 976 /* 977 Define XPM color. 978 */ 979 pixel=image->colormap[i]; 980 pixel.colorspace=sRGBColorspace; 981 pixel.depth=8; 982 pixel.alpha=(double) OpaqueAlpha; 983 (void) QueryColorname(image,&pixel,XPMCompliance,name,exception); 984 if (i == opacity) 985 (void) CopyMagickString(name,"None",MaxTextExtent); 986 /* 987 Write XPM color. 988 */ 989 k=i % MaxCixels; 990 symbol[0]=Cixel[k]; 991 for (j=1; j < (ssize_t) characters_per_pixel; j++) 992 { 993 k=((i-k)/MaxCixels) % MaxCixels; 994 symbol[j]=Cixel[k]; 995 } 996 symbol[j]='\0'; 997 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol, 998 name); 999 (void) WriteBlobString(image,buffer); 1000 } 1001 /* 1002 Define XPM pixels. 1003 */ 1004 (void) WriteBlobString(image,"/* pixels */\n"); 1005 for (y=0; y < (ssize_t) image->rows; y++) 1006 { 1007 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1008 if (p == (const Quantum *) NULL) 1009 break; 1010 (void) WriteBlobString(image,"\""); 1011 for (x=0; x < (ssize_t) image->columns; x++) 1012 { 1013 k=((ssize_t) GetPixelIndex(image,p) % MaxCixels); 1014 symbol[0]=Cixel[k]; 1015 for (j=1; j < (ssize_t) characters_per_pixel; j++) 1016 { 1017 k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels; 1018 symbol[j]=Cixel[k]; 1019 } 1020 symbol[j]='\0'; 1021 (void) CopyMagickString(buffer,symbol,MaxTextExtent); 1022 (void) WriteBlobString(image,buffer); 1023 p+=GetPixelChannels(image); 1024 } 1025 (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n", 1026 (y == (ssize_t) (image->rows-1) ? "" : ",")); 1027 (void) WriteBlobString(image,buffer); 1028 if (image->previous == (Image *) NULL) 1029 { 1030 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1031 image->rows); 1032 if (status == MagickFalse) 1033 break; 1034 } 1035 } 1036 (void) WriteBlobString(image,"};\n"); 1037 (void) CloseBlob(image); 1038 return(MagickTrue); 1039} 1040