1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% TTTTT X X TTTTT % 7% T X X T % 8% T X T % 9% T X X T % 10% T X X T % 11% % 12% % 13% Render Text Onto A Canvas Image. % 14% % 15% Software Design % 16% Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 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. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/annotate.h" 44#include "MagickCore/attribute.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/blob-private.h" 47#include "MagickCore/cache.h" 48#include "MagickCore/color.h" 49#include "MagickCore/color-private.h" 50#include "MagickCore/colorspace.h" 51#include "MagickCore/constitute.h" 52#include "MagickCore/draw.h" 53#include "MagickCore/exception.h" 54#include "MagickCore/exception-private.h" 55#include "MagickCore/geometry.h" 56#include "MagickCore/image.h" 57#include "MagickCore/image-private.h" 58#include "MagickCore/list.h" 59#include "MagickCore/magick.h" 60#include "MagickCore/memory_.h" 61#include "MagickCore/monitor.h" 62#include "MagickCore/monitor-private.h" 63#include "MagickCore/option.h" 64#include "MagickCore/pixel-accessor.h" 65#include "MagickCore/quantum-private.h" 66#include "MagickCore/static.h" 67#include "MagickCore/statistic.h" 68#include "MagickCore/string_.h" 69#include "MagickCore/module.h" 70 71/* 72 Forward declarations. 73*/ 74static MagickBooleanType 75 WriteTXTImage(const ImageInfo *,Image *,ExceptionInfo *); 76 77/* 78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 79% % 80% % 81% % 82% I s T X T % 83% % 84% % 85% % 86%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 87% 88% IsTXT() returns MagickTrue if the image format type, identified by the magick 89% string, is TXT. 90% 91% The format of the IsTXT method is: 92% 93% MagickBooleanType IsTXT(const unsigned char *magick,const size_t length) 94% 95% A description of each parameter follows: 96% 97% o magick: compare image format pattern against these bytes. 98% 99% o length: Specifies the length of the magick string. 100% 101*/ 102static MagickBooleanType IsTXT(const unsigned char *magick,const size_t length) 103{ 104#define MagickID "# ImageMagick pixel enumeration:" 105 106 char 107 colorspace[MagickPathExtent]; 108 109 ssize_t 110 count; 111 112 unsigned long 113 columns, 114 depth, 115 rows; 116 117 if (length < 40) 118 return(MagickFalse); 119 if (LocaleNCompare((const char *) magick,MagickID,strlen(MagickID)) != 0) 120 return(MagickFalse); 121 count=(ssize_t) sscanf((const char *) magick+32,"%lu,%lu,%lu,%s",&columns, 122 &rows,&depth,colorspace); 123 if (count != 4) 124 return(MagickFalse); 125 return(MagickTrue); 126} 127 128/* 129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 130% % 131% % 132% % 133% R e a d T E X T I m a g e % 134% % 135% % 136% % 137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 138% 139% ReadTEXTImage() reads a text file and returns it as an image. It 140% allocates the memory necessary for the new Image structure and returns a 141% pointer to the new image. 142% 143% The format of the ReadTEXTImage method is: 144% 145% Image *ReadTEXTImage(const ImageInfo *image_info,Image *image, 146% char *text,ExceptionInfo *exception) 147% 148% A description of each parameter follows: 149% 150% o image_info: the image info. 151% 152% o image: the image. 153% 154% o text: the text storage buffer. 155% 156% o exception: return any errors or warnings in this structure. 157% 158*/ 159static Image *ReadTEXTImage(const ImageInfo *image_info, 160 ExceptionInfo *exception) 161{ 162 char 163 filename[MagickPathExtent], 164 geometry[MagickPathExtent], 165 *p, 166 text[MagickPathExtent]; 167 168 DrawInfo 169 *draw_info; 170 171 Image 172 *image, 173 *texture; 174 175 MagickBooleanType 176 status; 177 178 PointInfo 179 delta; 180 181 RectangleInfo 182 page; 183 184 ssize_t 185 offset; 186 187 TypeMetric 188 metrics; 189 190 /* 191 Open image file. 192 */ 193 assert(image_info != (const ImageInfo *) NULL); 194 assert(image_info->signature == MagickCoreSignature); 195 if (image_info->debug != MagickFalse) 196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 197 image_info->filename); 198 assert(exception != (ExceptionInfo *) NULL); 199 assert(exception->signature == MagickCoreSignature); 200 image=AcquireImage(image_info,exception); 201 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 202 if (status == MagickFalse) 203 { 204 image=DestroyImageList(image); 205 return((Image *) NULL); 206 } 207 (void) ResetMagickMemory(text,0,sizeof(text)); 208 (void) ReadBlobString(image,text); 209 /* 210 Set the page geometry. 211 */ 212 delta.x=DefaultResolution; 213 delta.y=DefaultResolution; 214 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) 215 { 216 GeometryInfo 217 geometry_info; 218 219 MagickStatusType 220 flags; 221 222 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 223 image->resolution.x=geometry_info.rho; 224 image->resolution.y=geometry_info.sigma; 225 if ((flags & SigmaValue) == 0) 226 image->resolution.y=image->resolution.x; 227 } 228 page.width=612; 229 page.height=792; 230 page.x=43; 231 page.y=43; 232 if (image_info->page != (char *) NULL) 233 (void) ParseAbsoluteGeometry(image_info->page,&page); 234 /* 235 Initialize Image structure. 236 */ 237 image->columns=(size_t) floor((((double) page.width*image->resolution.x)/ 238 delta.x)+0.5); 239 image->rows=(size_t) floor((((double) page.height*image->resolution.y)/ 240 delta.y)+0.5); 241 status=SetImageExtent(image,image->columns,image->rows,exception); 242 if (status == MagickFalse) 243 return(DestroyImageList(image)); 244 image->page.x=0; 245 image->page.y=0; 246 texture=(Image *) NULL; 247 if (image_info->texture != (char *) NULL) 248 { 249 ImageInfo 250 *read_info; 251 252 read_info=CloneImageInfo(image_info); 253 SetImageInfoBlob(read_info,(void *) NULL,0); 254 (void) CopyMagickString(read_info->filename,image_info->texture, 255 MagickPathExtent); 256 texture=ReadImage(read_info,exception); 257 read_info=DestroyImageInfo(read_info); 258 } 259 /* 260 Annotate the text image. 261 */ 262 (void) SetImageBackgroundColor(image,exception); 263 draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); 264 (void) CloneString(&draw_info->text,image_info->filename); 265 (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+g%+g",(double) 266 image->columns,(double) image->rows,(double) page.x,(double) page.y); 267 (void) CloneString(&draw_info->geometry,geometry); 268 status=GetTypeMetrics(image,draw_info,&metrics,exception); 269 if (status == MagickFalse) 270 ThrowReaderException(TypeError,"UnableToGetTypeMetrics"); 271 page.y=(ssize_t) ceil((double) page.y+metrics.ascent-0.5); 272 (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+g%+g",(double) 273 image->columns,(double) image->rows,(double) page.x,(double) page.y); 274 (void) CloneString(&draw_info->geometry,geometry); 275 (void) CopyMagickString(filename,image_info->filename,MagickPathExtent); 276 if (*draw_info->text != '\0') 277 *draw_info->text='\0'; 278 p=text; 279 for (offset=2*page.y; p != (char *) NULL; ) 280 { 281 /* 282 Annotate image with text. 283 */ 284 (void) ConcatenateString(&draw_info->text,text); 285 (void) ConcatenateString(&draw_info->text,"\n"); 286 offset+=(ssize_t) (metrics.ascent-metrics.descent); 287 if (image->previous == (Image *) NULL) 288 { 289 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) offset, 290 image->rows); 291 if (status == MagickFalse) 292 break; 293 } 294 p=ReadBlobString(image,text); 295 if ((offset < (ssize_t) image->rows) && (p != (char *) NULL)) 296 continue; 297 if (texture != (Image *) NULL) 298 { 299 MagickProgressMonitor 300 progress_monitor; 301 302 progress_monitor=SetImageProgressMonitor(image, 303 (MagickProgressMonitor) NULL,image->client_data); 304 (void) TextureImage(image,texture,exception); 305 (void) SetImageProgressMonitor(image,progress_monitor, 306 image->client_data); 307 } 308 (void) AnnotateImage(image,draw_info,exception); 309 if (p == (char *) NULL) 310 break; 311 /* 312 Page is full-- allocate next image structure. 313 */ 314 *draw_info->text='\0'; 315 offset=2*page.y; 316 AcquireNextImage(image_info,image,exception); 317 if (GetNextImageInList(image) == (Image *) NULL) 318 { 319 image=DestroyImageList(image); 320 return((Image *) NULL); 321 } 322 image->next->columns=image->columns; 323 image->next->rows=image->rows; 324 image=SyncNextImageInList(image); 325 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 326 (void) SetImageBackgroundColor(image,exception); 327 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 328 GetBlobSize(image)); 329 if (status == MagickFalse) 330 break; 331 } 332 if (texture != (Image *) NULL) 333 { 334 MagickProgressMonitor 335 progress_monitor; 336 337 progress_monitor=SetImageProgressMonitor(image, 338 (MagickProgressMonitor) NULL,image->client_data); 339 (void) TextureImage(image,texture,exception); 340 (void) SetImageProgressMonitor(image,progress_monitor,image->client_data); 341 } 342 (void) AnnotateImage(image,draw_info,exception); 343 if (texture != (Image *) NULL) 344 texture=DestroyImage(texture); 345 draw_info=DestroyDrawInfo(draw_info); 346 (void) CloseBlob(image); 347 return(GetFirstImageInList(image)); 348} 349 350/* 351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 352% % 353% % 354% % 355% R e a d T X T I m a g e % 356% % 357% % 358% % 359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 360% 361% ReadTXTImage() reads a text file and returns it as an image. It allocates 362% the memory necessary for the new Image structure and returns a pointer to 363% the new image. 364% 365% The format of the ReadTXTImage method is: 366% 367% Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception) 368% 369% A description of each parameter follows: 370% 371% o image_info: the image info. 372% 373% o exception: return any errors or warnings in this structure. 374% 375*/ 376static Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception) 377{ 378 char 379 colorspace[MagickPathExtent], 380 text[MagickPathExtent]; 381 382 Image 383 *image; 384 385 long 386 x_offset, 387 y_offset; 388 389 PixelInfo 390 pixel; 391 392 MagickBooleanType 393 status; 394 395 QuantumAny 396 range; 397 398 register ssize_t 399 i, 400 x; 401 402 register Quantum 403 *q; 404 405 ssize_t 406 count, 407 type, 408 y; 409 410 unsigned long 411 depth, 412 height, 413 max_value, 414 width; 415 416 /* 417 Open image file. 418 */ 419 assert(image_info != (const ImageInfo *) NULL); 420 assert(image_info->signature == MagickCoreSignature); 421 if (image_info->debug != MagickFalse) 422 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 423 image_info->filename); 424 assert(exception != (ExceptionInfo *) NULL); 425 assert(exception->signature == MagickCoreSignature); 426 image=AcquireImage(image_info,exception); 427 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 428 if (status == MagickFalse) 429 { 430 image=DestroyImageList(image); 431 return((Image *) NULL); 432 } 433 (void) ResetMagickMemory(text,0,sizeof(text)); 434 (void) ReadBlobString(image,text); 435 if (LocaleNCompare((char *) text,MagickID,strlen(MagickID)) != 0) 436 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 437 do 438 { 439 width=0; 440 height=0; 441 max_value=0; 442 *colorspace='\0'; 443 count=(ssize_t) sscanf(text+32,"%lu,%lu,%lu,%s",&width,&height,&max_value, 444 colorspace); 445 if ((count != 4) || (width == 0) || (height == 0) || (max_value == 0)) 446 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 447 image->columns=width; 448 image->rows=height; 449 for (depth=1; (GetQuantumRange(depth)+1) < max_value; depth++) ; 450 image->depth=depth; 451 status=SetImageExtent(image,image->columns,image->rows,exception); 452 if (status == MagickFalse) 453 return(DestroyImageList(image)); 454 LocaleLower(colorspace); 455 i=(ssize_t) strlen(colorspace)-1; 456 image->alpha_trait=UndefinedPixelTrait; 457 if ((i > 0) && (colorspace[i] == 'a')) 458 { 459 colorspace[i]='\0'; 460 image->alpha_trait=BlendPixelTrait; 461 } 462 type=ParseCommandOption(MagickColorspaceOptions,MagickFalse,colorspace); 463 if (type < 0) 464 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 465 (void) SetImageBackgroundColor(image,exception); 466 (void) SetImageColorspace(image,(ColorspaceType) type,exception); 467 GetPixelInfo(image,&pixel); 468 range=GetQuantumRange(image->depth); 469 for (y=0; y < (ssize_t) image->rows; y++) 470 { 471 double 472 alpha, 473 black, 474 blue, 475 green, 476 red; 477 478 red=0.0; 479 green=0.0; 480 blue=0.0; 481 black=0.0; 482 alpha=0.0; 483 for (x=0; x < (ssize_t) image->columns; x++) 484 { 485 if (ReadBlobString(image,text) == (char *) NULL) 486 break; 487 switch (image->colorspace) 488 { 489 case GRAYColorspace: 490 { 491 if (image->alpha_trait != UndefinedPixelTrait) 492 { 493 count=(ssize_t) sscanf(text,"%ld,%ld: (%lf%*[%,]%lf%*[%,]", 494 &x_offset,&y_offset,&red,&alpha); 495 green=red; 496 blue=red; 497 break; 498 } 499 count=(ssize_t) sscanf(text,"%ld,%ld: (%lf%*[%,]",&x_offset, 500 &y_offset,&red); 501 green=red; 502 blue=red; 503 break; 504 } 505 case CMYKColorspace: 506 { 507 if (image->alpha_trait != UndefinedPixelTrait) 508 { 509 count=(ssize_t) sscanf(text, 510 "%ld,%ld: (%lf%*[%,]%lf%*[%,]%lf%*[%,]%lf%*[%,]%lf%*[%,]", 511 &x_offset,&y_offset,&red,&green,&blue,&black,&alpha); 512 break; 513 } 514 count=(ssize_t) sscanf(text, 515 "%ld,%ld: (%lf%*[%,]%lf%*[%,]%lf%*[%,]%lf%*[%,]",&x_offset, 516 &y_offset,&red,&green,&blue,&black); 517 break; 518 } 519 default: 520 { 521 if (image->alpha_trait != UndefinedPixelTrait) 522 { 523 count=(ssize_t) sscanf(text, 524 "%ld,%ld: (%lf%*[%,]%lf%*[%,]%lf%*[%,]%lf%*[%,]", 525 &x_offset,&y_offset,&red,&green,&blue,&alpha); 526 break; 527 } 528 count=(ssize_t) sscanf(text, 529 "%ld,%ld: (%lf%*[%,]%lf%*[%,]%lf%*[%,]",&x_offset, 530 &y_offset,&red,&green,&blue); 531 break; 532 } 533 } 534 if (strchr(text,'%') != (char *) NULL) 535 { 536 red*=0.01*range; 537 green*=0.01*range; 538 blue*=0.01*range; 539 black*=0.01*range; 540 alpha*=0.01*range; 541 } 542 if (image->colorspace == LabColorspace) 543 { 544 green+=(range+1)/2.0; 545 blue+=(range+1)/2.0; 546 } 547 pixel.red=(MagickRealType) ScaleAnyToQuantum((QuantumAny) (red+0.5), 548 range); 549 pixel.green=(MagickRealType) ScaleAnyToQuantum((QuantumAny) (green+0.5), 550 range); 551 pixel.blue=(MagickRealType) ScaleAnyToQuantum((QuantumAny) (blue+0.5), 552 range); 553 pixel.black=(MagickRealType) ScaleAnyToQuantum((QuantumAny) (black+0.5), 554 range); 555 pixel.alpha=(MagickRealType) ScaleAnyToQuantum((QuantumAny) (alpha+0.5), 556 range); 557 q=GetAuthenticPixels(image,(ssize_t) x_offset,(ssize_t) y_offset,1,1, 558 exception); 559 if (q == (Quantum *) NULL) 560 continue; 561 SetPixelViaPixelInfo(image,&pixel,q); 562 if (SyncAuthenticPixels(image,exception) == MagickFalse) 563 break; 564 } 565 } 566 (void) ReadBlobString(image,text); 567 if (LocaleNCompare((char *) text,MagickID,strlen(MagickID)) == 0) 568 { 569 /* 570 Allocate next image structure. 571 */ 572 AcquireNextImage(image_info,image,exception); 573 if (GetNextImageInList(image) == (Image *) NULL) 574 { 575 image=DestroyImageList(image); 576 return((Image *) NULL); 577 } 578 image=SyncNextImageInList(image); 579 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 580 GetBlobSize(image)); 581 if (status == MagickFalse) 582 break; 583 } 584 } while (LocaleNCompare((char *) text,MagickID,strlen(MagickID)) == 0); 585 (void) CloseBlob(image); 586 return(GetFirstImageInList(image)); 587} 588 589/* 590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 591% % 592% % 593% % 594% R e g i s t e r T X T I m a g e % 595% % 596% % 597% % 598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 599% 600% RegisterTXTImage() adds attributes for the TXT image format to the 601% list of supported formats. The attributes include the image format 602% tag, a method to read and/or write the format, whether the format 603% supports the saving of more than one frame to the same file or blob, 604% whether the format supports native in-memory I/O, and a brief 605% description of the format. 606% 607% The format of the RegisterTXTImage method is: 608% 609% size_t RegisterTXTImage(void) 610% 611*/ 612ModuleExport size_t RegisterTXTImage(void) 613{ 614 MagickInfo 615 *entry; 616 617 entry=AcquireMagickInfo("TXT","SPARSE-COLOR","Sparse Color"); 618 entry->encoder=(EncodeImageHandler *) WriteTXTImage; 619 entry->flags|=CoderRawSupportFlag; 620 entry->flags|=CoderEndianSupportFlag; 621 (void) RegisterMagickInfo(entry); 622 entry=AcquireMagickInfo("TXT","TEXT","Text"); 623 entry->decoder=(DecodeImageHandler *) ReadTEXTImage; 624 entry->format_type=ImplicitFormatType; 625 entry->flags|=CoderRawSupportFlag; 626 entry->flags|=CoderEndianSupportFlag; 627 (void) RegisterMagickInfo(entry); 628 entry=AcquireMagickInfo("TXT","TXT","Text"); 629 entry->decoder=(DecodeImageHandler *) ReadTXTImage; 630 entry->encoder=(EncodeImageHandler *) WriteTXTImage; 631 entry->magick=(IsImageFormatHandler *) IsTXT; 632 (void) RegisterMagickInfo(entry); 633 return(MagickImageCoderSignature); 634} 635 636/* 637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 638% % 639% % 640% % 641% U n r e g i s t e r T X T I m a g e % 642% % 643% % 644% % 645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 646% 647% UnregisterTXTImage() removes format registrations made by the 648% TXT module from the list of supported format. 649% 650% The format of the UnregisterTXTImage method is: 651% 652% UnregisterTXTImage(void) 653% 654*/ 655ModuleExport void UnregisterTXTImage(void) 656{ 657 (void) UnregisterMagickInfo("SPARSE-COLOR"); 658 (void) UnregisterMagickInfo("TEXT"); 659 (void) UnregisterMagickInfo("TXT"); 660} 661 662/* 663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 664% % 665% % 666% % 667% W r i t e T X T I m a g e % 668% % 669% % 670% % 671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 672% 673% WriteTXTImage writes the pixel values as text numbers. 674% 675% The format of the WriteTXTImage method is: 676% 677% MagickBooleanType WriteTXTImage(const ImageInfo *image_info, 678% Image *image,ExceptionInfo *exception) 679% 680% A description of each parameter follows. 681% 682% o image_info: the image info. 683% 684% o image: The image. 685% 686% o exception: return any errors or warnings in this structure. 687% 688*/ 689static MagickBooleanType WriteTXTImage(const ImageInfo *image_info,Image *image, 690 ExceptionInfo *exception) 691{ 692 char 693 buffer[MagickPathExtent], 694 colorspace[MagickPathExtent], 695 tuple[MagickPathExtent]; 696 697 MagickBooleanType 698 status; 699 700 MagickOffsetType 701 scene; 702 703 PixelInfo 704 pixel; 705 706 register const Quantum 707 *p; 708 709 register ssize_t 710 x; 711 712 ssize_t 713 y; 714 715 /* 716 Open output image file. 717 */ 718 assert(image_info != (const ImageInfo *) NULL); 719 assert(image_info->signature == MagickCoreSignature); 720 assert(image != (Image *) NULL); 721 assert(image->signature == MagickCoreSignature); 722 if (image->debug != MagickFalse) 723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 724 status=OpenBlob(image_info,image,WriteBlobMode,exception); 725 if (status == MagickFalse) 726 return(status); 727 scene=0; 728 do 729 { 730 ComplianceType 731 compliance; 732 733 const char 734 *value; 735 736 (void) CopyMagickString(colorspace,CommandOptionToMnemonic( 737 MagickColorspaceOptions,(ssize_t) image->colorspace),MagickPathExtent); 738 LocaleLower(colorspace); 739 image->depth=GetImageQuantumDepth(image,MagickTrue); 740 if (image->alpha_trait != UndefinedPixelTrait) 741 (void) ConcatenateMagickString(colorspace,"a",MagickPathExtent); 742 compliance=NoCompliance; 743 value=GetImageOption(image_info,"txt:compliance"); 744 if (value != (char *) NULL) 745 compliance=(ComplianceType) ParseCommandOption(MagickComplianceOptions, 746 MagickFalse,value); 747 if (LocaleCompare(image_info->magick,"SPARSE-COLOR") != 0) 748 { 749 size_t 750 depth; 751 752 depth=compliance == SVGCompliance ? image->depth : 753 MAGICKCORE_QUANTUM_DEPTH; 754 (void) FormatLocaleString(buffer,MagickPathExtent, 755 "# ImageMagick pixel enumeration: %.20g,%.20g,%.20g,%s\n",(double) 756 image->columns,(double) image->rows,(double) ((MagickOffsetType) 757 GetQuantumRange(depth)),colorspace); 758 (void) WriteBlobString(image,buffer); 759 } 760 GetPixelInfo(image,&pixel); 761 for (y=0; y < (ssize_t) image->rows; y++) 762 { 763 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 764 if (p == (const Quantum *) NULL) 765 break; 766 for (x=0; x < (ssize_t) image->columns; x++) 767 { 768 GetPixelInfoPixel(image,p,&pixel); 769 if (pixel.colorspace == LabColorspace) 770 { 771 pixel.green-=(QuantumRange+1)/2.0; 772 pixel.blue-=(QuantumRange+1)/2.0; 773 } 774 if (LocaleCompare(image_info->magick,"SPARSE-COLOR") == 0) 775 { 776 /* 777 Sparse-color format. 778 */ 779 if (GetPixelAlpha(image,p) == (Quantum) OpaqueAlpha) 780 { 781 GetColorTuple(&pixel,MagickFalse,tuple); 782 (void) FormatLocaleString(buffer,MagickPathExtent, 783 "%.20g,%.20g,",(double) x,(double) y); 784 (void) WriteBlobString(image,buffer); 785 (void) WriteBlobString(image,tuple); 786 (void) WriteBlobString(image," "); 787 } 788 p+=GetPixelChannels(image); 789 continue; 790 } 791 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g,%.20g: ", 792 (double) x,(double) y); 793 (void) WriteBlobString(image,buffer); 794 (void) CopyMagickString(tuple,"(",MagickPathExtent); 795 if (pixel.colorspace == GRAYColorspace) 796 ConcatenateColorComponent(&pixel,GrayPixelChannel,compliance, 797 tuple); 798 else 799 { 800 ConcatenateColorComponent(&pixel,RedPixelChannel,compliance,tuple); 801 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 802 ConcatenateColorComponent(&pixel,GreenPixelChannel,compliance, 803 tuple); 804 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 805 ConcatenateColorComponent(&pixel,BluePixelChannel,compliance,tuple); 806 } 807 if (pixel.colorspace == CMYKColorspace) 808 { 809 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 810 ConcatenateColorComponent(&pixel,BlackPixelChannel,compliance, 811 tuple); 812 } 813 if (pixel.alpha_trait != UndefinedPixelTrait) 814 { 815 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 816 ConcatenateColorComponent(&pixel,AlphaPixelChannel,compliance, 817 tuple); 818 } 819 (void) ConcatenateMagickString(tuple,")",MagickPathExtent); 820 (void) WriteBlobString(image,tuple); 821 (void) WriteBlobString(image," "); 822 GetColorTuple(&pixel,MagickTrue,tuple); 823 (void) FormatLocaleString(buffer,MagickPathExtent,"%s",tuple); 824 (void) WriteBlobString(image,buffer); 825 (void) WriteBlobString(image," "); 826 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception); 827 (void) WriteBlobString(image,tuple); 828 (void) WriteBlobString(image,"\n"); 829 p+=GetPixelChannels(image); 830 } 831 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 832 image->rows); 833 if (status == MagickFalse) 834 break; 835 } 836 if (GetNextImageInList(image) == (Image *) NULL) 837 break; 838 image=SyncNextImageInList(image); 839 status=SetImageProgress(image,SaveImagesTag,scene++, 840 GetImageListLength(image)); 841 if (status == MagickFalse) 842 break; 843 } while (image_info->adjoin != MagickFalse); 844 (void) CloseBlob(image); 845 return(MagickTrue); 846} 847