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