transform.c revision 195938723ce0d7e6780967dd2ada36aec15fe4bf
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M % 7% T R R A A NN N SS F O O R R MM MM % 8% T RRRR AAAAA N N N SSS FFF O O RRRR M M M % 9% T R R A A N NN SS F O O R R M M % 10% T R R A A N N SSSSS F OOO R R M M % 11% % 12% % 13% MagickCore Image Transform Methods % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2012 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/attribute.h" 44#include "MagickCore/cache.h" 45#include "MagickCore/cache-view.h" 46#include "MagickCore/color.h" 47#include "MagickCore/color-private.h" 48#include "MagickCore/colorspace-private.h" 49#include "MagickCore/composite.h" 50#include "MagickCore/draw.h" 51#include "MagickCore/effect.h" 52#include "MagickCore/exception.h" 53#include "MagickCore/exception-private.h" 54#include "MagickCore/geometry.h" 55#include "MagickCore/image.h" 56#include "MagickCore/memory_.h" 57#include "MagickCore/layer.h" 58#include "MagickCore/list.h" 59#include "MagickCore/monitor.h" 60#include "MagickCore/monitor-private.h" 61#include "MagickCore/pixel-accessor.h" 62#include "MagickCore/resource_.h" 63#include "MagickCore/resize.h" 64#include "MagickCore/statistic.h" 65#include "MagickCore/string_.h" 66#include "MagickCore/thread-private.h" 67#include "MagickCore/transform.h" 68 69/* 70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 71% % 72% % 73% % 74% C h o p I m a g e % 75% % 76% % 77% % 78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 79% 80% ChopImage() removes a region of an image and collapses the image to occupy 81% the removed portion. 82% 83% The format of the ChopImage method is: 84% 85% Image *ChopImage(const Image *image,const RectangleInfo *chop_info) 86% ExceptionInfo *exception) 87% 88% A description of each parameter follows: 89% 90% o image: the image. 91% 92% o chop_info: Define the region of the image to chop. 93% 94% o exception: return any errors or warnings in this structure. 95% 96*/ 97MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info, 98 ExceptionInfo *exception) 99{ 100#define ChopImageTag "Chop/Image" 101 102 CacheView 103 *chop_view, 104 *image_view; 105 106 Image 107 *chop_image; 108 109 MagickBooleanType 110 status; 111 112 MagickOffsetType 113 progress; 114 115 RectangleInfo 116 extent; 117 118 ssize_t 119 y; 120 121 /* 122 Check chop geometry. 123 */ 124 assert(image != (const Image *) NULL); 125 assert(image->signature == MagickSignature); 126 if (image->debug != MagickFalse) 127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 128 assert(exception != (ExceptionInfo *) NULL); 129 assert(exception->signature == MagickSignature); 130 assert(chop_info != (RectangleInfo *) NULL); 131 if (((chop_info->x+(ssize_t) chop_info->width) < 0) || 132 ((chop_info->y+(ssize_t) chop_info->height) < 0) || 133 (chop_info->x > (ssize_t) image->columns) || 134 (chop_info->y > (ssize_t) image->rows)) 135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage"); 136 extent=(*chop_info); 137 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns) 138 extent.width=(size_t) ((ssize_t) image->columns-extent.x); 139 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows) 140 extent.height=(size_t) ((ssize_t) image->rows-extent.y); 141 if (extent.x < 0) 142 { 143 extent.width-=(size_t) (-extent.x); 144 extent.x=0; 145 } 146 if (extent.y < 0) 147 { 148 extent.height-=(size_t) (-extent.y); 149 extent.y=0; 150 } 151 chop_image=CloneImage(image,image->columns-extent.width,image->rows- 152 extent.height,MagickTrue,exception); 153 if (chop_image == (Image *) NULL) 154 return((Image *) NULL); 155 /* 156 Extract chop image. 157 */ 158 status=MagickTrue; 159 progress=0; 160 image_view=AcquireCacheView(image); 161 chop_view=AcquireCacheView(chop_image); 162#if defined(MAGICKCORE_OPENMP_SUPPORT) 163 #pragma omp parallel for schedule(static) shared(progress,status) 164#endif 165 for (y=0; y < (ssize_t) extent.y; y++) 166 { 167 register const Quantum 168 *restrict p; 169 170 register ssize_t 171 x; 172 173 register Quantum 174 *restrict q; 175 176 if (status == MagickFalse) 177 continue; 178 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 179 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1, 180 exception); 181 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 182 { 183 status=MagickFalse; 184 continue; 185 } 186 for (x=0; x < (ssize_t) image->columns; x++) 187 { 188 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width))) 189 { 190 register ssize_t 191 i; 192 193 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 194 { 195 PixelChannel 196 channel; 197 198 PixelTrait 199 chop_traits, 200 traits; 201 202 channel=GetPixelChannelMapChannel(image,i); 203 traits=GetPixelChannelMapTraits(image,channel); 204 chop_traits=GetPixelChannelMapTraits(chop_image,channel); 205 if ((traits == UndefinedPixelTrait) || 206 (chop_traits == UndefinedPixelTrait)) 207 continue; 208 SetPixelChannel(chop_image,channel,p[i],q); 209 } 210 q+=GetPixelChannels(chop_image); 211 } 212 p+=GetPixelChannels(image); 213 } 214 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse) 215 status=MagickFalse; 216 if (image->progress_monitor != (MagickProgressMonitor) NULL) 217 { 218 MagickBooleanType 219 proceed; 220 221#if defined(MAGICKCORE_OPENMP_SUPPORT) 222 #pragma omp critical (MagickCore_ChopImage) 223#endif 224 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows); 225 if (proceed == MagickFalse) 226 status=MagickFalse; 227 } 228 } 229 /* 230 Extract chop image. 231 */ 232#if defined(MAGICKCORE_OPENMP_SUPPORT) 233 #pragma omp parallel for schedule(static) shared(progress,status) 234#endif 235 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++) 236 { 237 register const Quantum 238 *restrict p; 239 240 register ssize_t 241 x; 242 243 register Quantum 244 *restrict q; 245 246 if (status == MagickFalse) 247 continue; 248 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y, 249 image->columns,1,exception); 250 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns, 251 1,exception); 252 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 253 { 254 status=MagickFalse; 255 continue; 256 } 257 for (x=0; x < (ssize_t) image->columns; x++) 258 { 259 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width))) 260 { 261 register ssize_t 262 i; 263 264 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 265 { 266 PixelChannel 267 channel; 268 269 PixelTrait 270 chop_traits, 271 traits; 272 273 channel=GetPixelChannelMapChannel(image,i); 274 traits=GetPixelChannelMapTraits(image,channel); 275 chop_traits=GetPixelChannelMapTraits(chop_image,channel); 276 if ((traits == UndefinedPixelTrait) || 277 (chop_traits == UndefinedPixelTrait)) 278 continue; 279 SetPixelChannel(chop_image,channel,p[i],q); 280 } 281 q+=GetPixelChannels(chop_image); 282 } 283 p+=GetPixelChannels(image); 284 } 285 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse) 286 status=MagickFalse; 287 if (image->progress_monitor != (MagickProgressMonitor) NULL) 288 { 289 MagickBooleanType 290 proceed; 291 292#if defined(MAGICKCORE_OPENMP_SUPPORT) 293 #pragma omp critical (MagickCore_ChopImage) 294#endif 295 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows); 296 if (proceed == MagickFalse) 297 status=MagickFalse; 298 } 299 } 300 chop_view=DestroyCacheView(chop_view); 301 image_view=DestroyCacheView(image_view); 302 chop_image->type=image->type; 303 return(chop_image); 304} 305 306/* 307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 308% % 309% % 310% % 311+ C o n s o l i d a t e C M Y K I m a g e % 312% % 313% % 314% % 315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 316% 317% ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a 318% single image. 319% 320% The format of the ConsolidateCMYKImage method is: 321% 322% Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception) 323% 324% A description of each parameter follows: 325% 326% o image: the image sequence. 327% 328% o exception: return any errors or warnings in this structure. 329% 330*/ 331MagickExport Image *ConsolidateCMYKImages(const Image *images, 332 ExceptionInfo *exception) 333{ 334 CacheView 335 *cmyk_view, 336 *image_view; 337 338 Image 339 *cmyk_image, 340 *cmyk_images; 341 342 register ssize_t 343 j; 344 345 ssize_t 346 y; 347 348 /* 349 Consolidate separate C, M, Y, and K planes into a single image. 350 */ 351 assert(images != (Image *) NULL); 352 assert(images->signature == MagickSignature); 353 if (images->debug != MagickFalse) 354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 355 assert(exception != (ExceptionInfo *) NULL); 356 assert(exception->signature == MagickSignature); 357 cmyk_images=NewImageList(); 358 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4) 359 { 360 register ssize_t 361 i; 362 363 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue, 364 exception); 365 if (cmyk_image == (Image *) NULL) 366 break; 367 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse) 368 break; 369 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception); 370 for (i=0; i < 4; i++) 371 { 372 image_view=AcquireCacheView(images); 373 cmyk_view=AcquireCacheView(cmyk_image); 374 for (y=0; y < (ssize_t) images->rows; y++) 375 { 376 register const Quantum 377 *restrict p; 378 379 register ssize_t 380 x; 381 382 register Quantum 383 *restrict q; 384 385 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception); 386 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1, 387 exception); 388 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 389 break; 390 for (x=0; x < (ssize_t) images->columns; x++) 391 { 392 Quantum 393 pixel; 394 395 pixel=QuantumRange-GetPixelIntensity(images,p); 396 switch (i) 397 { 398 case 0: SetPixelCyan(cmyk_image,pixel,q); break; 399 case 1: SetPixelMagenta(cmyk_image,pixel,q); break; 400 case 2: SetPixelYellow(cmyk_image,pixel,q); break; 401 case 3: SetPixelBlack(cmyk_image,pixel,q); break; 402 default: break; 403 } 404 p+=GetPixelChannels(images); 405 q+=GetPixelChannels(cmyk_image); 406 } 407 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse) 408 break; 409 } 410 cmyk_view=DestroyCacheView(cmyk_view); 411 image_view=DestroyCacheView(image_view); 412 images=GetNextImageInList(images); 413 if (images == (Image *) NULL) 414 break; 415 } 416 AppendImageToList(&cmyk_images,cmyk_image); 417 } 418 return(cmyk_images); 419} 420 421/* 422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 423% % 424% % 425% % 426% C r o p I m a g e % 427% % 428% % 429% % 430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 431% 432% CropImage() extracts a region of the image starting at the offset defined 433% by geometry. Region must be fully defined, and no special handling of 434% geometry flags is performed. 435% 436% The format of the CropImage method is: 437% 438% Image *CropImage(const Image *image,const RectangleInfo *geometry, 439% ExceptionInfo *exception) 440% 441% A description of each parameter follows: 442% 443% o image: the image. 444% 445% o geometry: Define the region of the image to crop with members 446% x, y, width, and height. 447% 448% o exception: return any errors or warnings in this structure. 449% 450*/ 451MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry, 452 ExceptionInfo *exception) 453{ 454#define CropImageTag "Crop/Image" 455 456 CacheView 457 *crop_view, 458 *image_view; 459 460 Image 461 *crop_image; 462 463 MagickBooleanType 464 status; 465 466 MagickOffsetType 467 progress; 468 469 OffsetInfo 470 offset; 471 472 RectangleInfo 473 bounding_box, 474 page; 475 476 ssize_t 477 y; 478 479 /* 480 Check crop geometry. 481 */ 482 assert(image != (const Image *) NULL); 483 assert(image->signature == MagickSignature); 484 if (image->debug != MagickFalse) 485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 486 assert(geometry != (const RectangleInfo *) NULL); 487 assert(exception != (ExceptionInfo *) NULL); 488 assert(exception->signature == MagickSignature); 489 bounding_box=image->page; 490 if ((bounding_box.width == 0) || (bounding_box.height == 0)) 491 { 492 bounding_box.width=image->columns; 493 bounding_box.height=image->rows; 494 } 495 page=(*geometry); 496 if (page.width == 0) 497 page.width=bounding_box.width; 498 if (page.height == 0) 499 page.height=bounding_box.height; 500 if (((bounding_box.x-page.x) >= (ssize_t) page.width) || 501 ((bounding_box.y-page.y) >= (ssize_t) page.height) || 502 ((page.x-bounding_box.x) > (ssize_t) image->columns) || 503 ((page.y-bounding_box.y) > (ssize_t) image->rows)) 504 { 505 /* 506 Crop is not within virtual canvas, return 1 pixel transparent image. 507 */ 508 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 509 "GeometryDoesNotContainImage","`%s'",image->filename); 510 crop_image=CloneImage(image,1,1,MagickTrue,exception); 511 if (crop_image == (Image *) NULL) 512 return((Image *) NULL); 513 crop_image->background_color.alpha=(Quantum) TransparentAlpha; 514 (void) SetImageBackgroundColor(crop_image,exception); 515 crop_image->page=bounding_box; 516 crop_image->page.x=(-1); 517 crop_image->page.y=(-1); 518 if (crop_image->dispose == BackgroundDispose) 519 crop_image->dispose=NoneDispose; 520 return(crop_image); 521 } 522 if ((page.x < 0) && (bounding_box.x >= 0)) 523 { 524 page.width+=page.x-bounding_box.x; 525 page.x=0; 526 } 527 else 528 { 529 page.width-=bounding_box.x-page.x; 530 page.x-=bounding_box.x; 531 if (page.x < 0) 532 page.x=0; 533 } 534 if ((page.y < 0) && (bounding_box.y >= 0)) 535 { 536 page.height+=page.y-bounding_box.y; 537 page.y=0; 538 } 539 else 540 { 541 page.height-=bounding_box.y-page.y; 542 page.y-=bounding_box.y; 543 if (page.y < 0) 544 page.y=0; 545 } 546 if ((size_t) (page.x+page.width) > image->columns) 547 page.width=image->columns-page.x; 548 if ((geometry->width != 0) && (page.width > geometry->width)) 549 page.width=geometry->width; 550 if ((size_t) (page.y+page.height) > image->rows) 551 page.height=image->rows-page.y; 552 if ((geometry->height != 0) && (page.height > geometry->height)) 553 page.height=geometry->height; 554 bounding_box.x+=page.x; 555 bounding_box.y+=page.y; 556 if ((page.width == 0) || (page.height == 0)) 557 { 558 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 559 "GeometryDoesNotContainImage","`%s'",image->filename); 560 return((Image *) NULL); 561 } 562 /* 563 Initialize crop image attributes. 564 */ 565 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception); 566 if (crop_image == (Image *) NULL) 567 return((Image *) NULL); 568 crop_image->page.width=image->page.width; 569 crop_image->page.height=image->page.height; 570 offset.x=(ssize_t) (bounding_box.x+bounding_box.width); 571 offset.y=(ssize_t) (bounding_box.y+bounding_box.height); 572 if ((offset.x > (ssize_t) image->page.width) || 573 (offset.y > (ssize_t) image->page.height)) 574 { 575 crop_image->page.width=bounding_box.width; 576 crop_image->page.height=bounding_box.height; 577 } 578 crop_image->page.x=bounding_box.x; 579 crop_image->page.y=bounding_box.y; 580 /* 581 Crop image. 582 */ 583 status=MagickTrue; 584 progress=0; 585 image_view=AcquireCacheView(image); 586 crop_view=AcquireCacheView(crop_image); 587#if defined(MAGICKCORE_OPENMP_SUPPORT) 588 #pragma omp parallel for schedule(static) shared(progress,status) 589#endif 590 for (y=0; y < (ssize_t) crop_image->rows; y++) 591 { 592 register const Quantum 593 *restrict p; 594 595 register Quantum 596 *restrict q; 597 598 register ssize_t 599 x; 600 601 if (status == MagickFalse) 602 continue; 603 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns, 604 1,exception); 605 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1, 606 exception); 607 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 608 { 609 status=MagickFalse; 610 continue; 611 } 612 for (x=0; x < (ssize_t) crop_image->columns; x++) 613 { 614 register ssize_t 615 i; 616 617 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 618 { 619 PixelChannel 620 channel; 621 622 PixelTrait 623 crop_traits, 624 traits; 625 626 channel=GetPixelChannelMapChannel(image,i); 627 traits=GetPixelChannelMapTraits(image,channel); 628 crop_traits=GetPixelChannelMapTraits(crop_image,channel); 629 if ((traits == UndefinedPixelTrait) || 630 (crop_traits == UndefinedPixelTrait)) 631 continue; 632 SetPixelChannel(crop_image,channel,p[i],q); 633 } 634 p+=GetPixelChannels(image); 635 q+=GetPixelChannels(crop_image); 636 } 637 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse) 638 status=MagickFalse; 639 if (image->progress_monitor != (MagickProgressMonitor) NULL) 640 { 641 MagickBooleanType 642 proceed; 643 644#if defined(MAGICKCORE_OPENMP_SUPPORT) 645 #pragma omp critical (MagickCore_CropImage) 646#endif 647 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows); 648 if (proceed == MagickFalse) 649 status=MagickFalse; 650 } 651 } 652 crop_view=DestroyCacheView(crop_view); 653 image_view=DestroyCacheView(image_view); 654 crop_image->type=image->type; 655 if (status == MagickFalse) 656 crop_image=DestroyImage(crop_image); 657 return(crop_image); 658} 659 660/* 661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 662% % 663% % 664% % 665% C r o p I m a g e T o T i l e s % 666% % 667% % 668% % 669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 670% 671% CropImageToTiles() crops a single image, into a possible list of tiles. 672% This may include a single sub-region of the image. This basically applies 673% all the normal geometry flags for Crop. 674% 675% Image *CropImageToTiles(const Image *image, 676% const RectangleInfo *crop_geometry, ExceptionInfo *exception) 677% 678% A description of each parameter follows: 679% 680% o image: the image The transformed image is returned as this parameter. 681% 682% o crop_geometry: A crop geometry string. 683% 684% o exception: return any errors or warnings in this structure. 685% 686*/ 687 688static inline ssize_t MagickRound(MagickRealType x) 689{ 690 /* 691 Round the fraction to nearest integer. 692 */ 693 if (x >= 0.0) 694 return((ssize_t) (x+0.5)); 695 return((ssize_t) (x-0.5)); 696} 697 698MagickExport Image *CropImageToTiles(const Image *image, 699 const char *crop_geometry, ExceptionInfo *exception) 700{ 701 Image 702 *next, 703 *crop_image; 704 705 MagickStatusType 706 flags; 707 708 RectangleInfo 709 geometry; 710 711 assert(image != (Image *) NULL); 712 assert(image->signature == MagickSignature); 713 if (image->debug != MagickFalse) 714 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 715 crop_image=NewImageList(); 716 next=NewImageList(); 717 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception); 718 if ((flags & AreaValue) != 0) 719 { 720 PointInfo 721 delta, 722 offset; 723 724 RectangleInfo 725 crop; 726 727 size_t 728 height, 729 width; 730 731 /* 732 Crop into NxM tiles (@ flag). 733 */ 734 width=image->columns; 735 height=image->rows; 736 if (geometry.width == 0) 737 geometry.width=1; 738 if (geometry.height == 0) 739 geometry.height=1; 740 if ((flags & AspectValue) == 0) 741 { 742 width-=(geometry.x < 0 ? -1 : 1)*geometry.x; 743 height-=(geometry.y < 0 ? -1 : 1)*geometry.y; 744 } 745 else 746 { 747 width+=(geometry.x < 0 ? -1 : 1)*geometry.x; 748 height+=(geometry.y < 0 ? -1 : 1)*geometry.y; 749 } 750 delta.x=(double) width/geometry.width; 751 delta.y=(double) height/geometry.height; 752 if ( delta.x < 1.0 ) delta.x = 1.0; 753 if ( delta.y < 1.0 ) delta.y = 1.0; 754 for (offset.y=0; offset.y < (double) height; ) 755 { 756 if ((flags & AspectValue) == 0) 757 { 758 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- 759 (geometry.y > 0 ? 0 : geometry.y))); 760 offset.y+=delta.y; /* increment now to find width */ 761 crop.height=(size_t) MagickRound((MagickRealType) (offset.y+ 762 (geometry.y < 0 ? 0 : geometry.y))); 763 } 764 else 765 { 766 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- 767 (geometry.y > 0 ? geometry.y : 0))); 768 offset.y+=delta.y; /* increment now to find width */ 769 crop.height=(size_t) MagickRound((MagickRealType) 770 (offset.y+(geometry.y < -1 ? geometry.y : 0))); 771 } 772 crop.height-=crop.y; 773 crop.y+=image->page.y; 774 for (offset.x=0; offset.x < (double) width; ) 775 { 776 if ((flags & AspectValue) == 0) 777 { 778 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- 779 (geometry.x > 0 ? 0 : geometry.x))); 780 offset.x+=delta.x; /* increment now to find height */ 781 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+ 782 (geometry.x < 0 ? 0 : geometry.x))); 783 } 784 else 785 { 786 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- 787 (geometry.x > 0 ? geometry.x : 0))); 788 offset.x+=delta.x; /* increment now to find height */ 789 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+ 790 (geometry.x < 0 ? geometry.x : 0))); 791 } 792 crop.width-=crop.x; 793 crop.x+=image->page.x; 794 next=CropImage(image,&crop,exception); 795 if (next == (Image *) NULL) 796 break; 797 AppendImageToList(&crop_image,next); 798 } 799 if (next == (Image *) NULL) 800 break; 801 } 802 ClearMagickException(exception); 803 return(crop_image); 804 } 805 806 if (((geometry.width == 0) && (geometry.height == 0)) || 807 ((flags & XValue) != 0) || ((flags & YValue) != 0)) 808 { 809 /* 810 Crop a single region at +X+Y. 811 */ 812 crop_image=CropImage(image,&geometry,exception); 813 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0)) 814 { 815 crop_image->page.width=geometry.width; 816 crop_image->page.height=geometry.height; 817 crop_image->page.x-=geometry.x; 818 crop_image->page.y-=geometry.y; 819 } 820 return(crop_image); 821 } 822 if ((image->columns > geometry.width) || (image->rows > geometry.height)) 823 { 824 RectangleInfo 825 page; 826 827 size_t 828 height, 829 width; 830 831 ssize_t 832 x, 833 y; 834 835 /* 836 Crop into tiles of fixed size WxH. 837 */ 838 page=image->page; 839 if (page.width == 0) 840 page.width=image->columns; 841 if (page.height == 0) 842 page.height=image->rows; 843 width=geometry.width; 844 if (width == 0) 845 width=page.width; 846 height=geometry.height; 847 if (height == 0) 848 height=page.height; 849 next=NewImageList(); 850 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) 851 { 852 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) 853 { 854 geometry.width=width; 855 geometry.height=height; 856 geometry.x=x; 857 geometry.y=y; 858 next=CropImage(image,&geometry,exception); 859 if (next == (Image *) NULL) 860 break; 861 AppendImageToList(&crop_image,next); 862 } 863 if (next == (Image *) NULL) 864 break; 865 } 866 return(crop_image); 867 } 868 return(CloneImage(image,0,0,MagickTrue,exception)); 869} 870 871/* 872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 873% % 874% % 875% % 876% E x c e r p t I m a g e % 877% % 878% % 879% % 880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 881% 882% ExcerptImage() returns a excerpt of the image as defined by the geometry. 883% 884% The format of the ExcerptImage method is: 885% 886% Image *ExcerptImage(const Image *image,const RectangleInfo *geometry, 887% ExceptionInfo *exception) 888% 889% A description of each parameter follows: 890% 891% o image: the image. 892% 893% o geometry: Define the region of the image to extend with members 894% x, y, width, and height. 895% 896% o exception: return any errors or warnings in this structure. 897% 898*/ 899MagickExport Image *ExcerptImage(const Image *image, 900 const RectangleInfo *geometry,ExceptionInfo *exception) 901{ 902#define ExcerptImageTag "Excerpt/Image" 903 904 CacheView 905 *excerpt_view, 906 *image_view; 907 908 Image 909 *excerpt_image; 910 911 MagickBooleanType 912 status; 913 914 MagickOffsetType 915 progress; 916 917 ssize_t 918 y; 919 920 /* 921 Allocate excerpt image. 922 */ 923 assert(image != (const Image *) NULL); 924 assert(image->signature == MagickSignature); 925 if (image->debug != MagickFalse) 926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 927 assert(geometry != (const RectangleInfo *) NULL); 928 assert(exception != (ExceptionInfo *) NULL); 929 assert(exception->signature == MagickSignature); 930 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue, 931 exception); 932 if (excerpt_image == (Image *) NULL) 933 return((Image *) NULL); 934 /* 935 Excerpt each row. 936 */ 937 status=MagickTrue; 938 progress=0; 939 image_view=AcquireCacheView(image); 940 excerpt_view=AcquireCacheView(excerpt_image); 941#if defined(MAGICKCORE_OPENMP_SUPPORT) 942 #pragma omp parallel for schedule(static,4) shared(progress,status) 943#endif 944 for (y=0; y < (ssize_t) excerpt_image->rows; y++) 945 { 946 register const Quantum 947 *restrict p; 948 949 register Quantum 950 *restrict q; 951 952 register ssize_t 953 x; 954 955 if (status == MagickFalse) 956 continue; 957 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y, 958 geometry->width,1,exception); 959 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1, 960 exception); 961 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 962 { 963 status=MagickFalse; 964 continue; 965 } 966 for (x=0; x < (ssize_t) excerpt_image->columns; x++) 967 { 968 register ssize_t 969 i; 970 971 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 972 { 973 PixelChannel 974 channel; 975 976 PixelTrait 977 excerpt_traits, 978 traits; 979 980 channel=GetPixelChannelMapChannel(image,i); 981 traits=GetPixelChannelMapTraits(image,channel); 982 excerpt_traits=GetPixelChannelMapTraits(excerpt_image,channel); 983 if ((traits == UndefinedPixelTrait) || 984 (excerpt_traits == UndefinedPixelTrait)) 985 continue; 986 SetPixelChannel(excerpt_image,channel,p[i],q); 987 } 988 p+=GetPixelChannels(image); 989 q+=GetPixelChannels(excerpt_image); 990 } 991 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse) 992 status=MagickFalse; 993 if (image->progress_monitor != (MagickProgressMonitor) NULL) 994 { 995 MagickBooleanType 996 proceed; 997 998#if defined(MAGICKCORE_OPENMP_SUPPORT) 999 #pragma omp critical (MagickCore_ExcerptImage) 1000#endif 1001 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows); 1002 if (proceed == MagickFalse) 1003 status=MagickFalse; 1004 } 1005 } 1006 excerpt_view=DestroyCacheView(excerpt_view); 1007 image_view=DestroyCacheView(image_view); 1008 excerpt_image->type=image->type; 1009 if (status == MagickFalse) 1010 excerpt_image=DestroyImage(excerpt_image); 1011 return(excerpt_image); 1012} 1013 1014/* 1015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1016% % 1017% % 1018% % 1019% E x t e n t I m a g e % 1020% % 1021% % 1022% % 1023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1024% 1025% ExtentImage() extends the image as defined by the geometry, gravity, and 1026% image background color. Set the (x,y) offset of the geometry to move the 1027% original image relative to the extended image. 1028% 1029% The format of the ExtentImage method is: 1030% 1031% Image *ExtentImage(const Image *image,const RectangleInfo *geometry, 1032% ExceptionInfo *exception) 1033% 1034% A description of each parameter follows: 1035% 1036% o image: the image. 1037% 1038% o geometry: Define the region of the image to extend with members 1039% x, y, width, and height. 1040% 1041% o exception: return any errors or warnings in this structure. 1042% 1043*/ 1044MagickExport Image *ExtentImage(const Image *image, 1045 const RectangleInfo *geometry,ExceptionInfo *exception) 1046{ 1047 Image 1048 *extent_image; 1049 1050 /* 1051 Allocate extent image. 1052 */ 1053 assert(image != (const Image *) NULL); 1054 assert(image->signature == MagickSignature); 1055 if (image->debug != MagickFalse) 1056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1057 assert(geometry != (const RectangleInfo *) NULL); 1058 assert(exception != (ExceptionInfo *) NULL); 1059 assert(exception->signature == MagickSignature); 1060 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue, 1061 exception); 1062 if (extent_image == (Image *) NULL) 1063 return((Image *) NULL); 1064 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse) 1065 { 1066 extent_image=DestroyImage(extent_image); 1067 return((Image *) NULL); 1068 } 1069 if (extent_image->background_color.alpha != OpaqueAlpha) 1070 extent_image->matte=MagickTrue; 1071 (void) SetImageBackgroundColor(extent_image,exception); 1072 (void) CompositeImage(extent_image,image->compose,image,-geometry->x, 1073 -geometry->y,exception); 1074 return(extent_image); 1075} 1076 1077/* 1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1079% % 1080% % 1081% % 1082% F l i p I m a g e % 1083% % 1084% % 1085% % 1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1087% 1088% FlipImage() creates a vertical mirror image by reflecting the pixels 1089% around the central x-axis. 1090% 1091% The format of the FlipImage method is: 1092% 1093% Image *FlipImage(const Image *image,ExceptionInfo *exception) 1094% 1095% A description of each parameter follows: 1096% 1097% o image: the image. 1098% 1099% o exception: return any errors or warnings in this structure. 1100% 1101*/ 1102MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception) 1103{ 1104#define FlipImageTag "Flip/Image" 1105 1106 CacheView 1107 *flip_view, 1108 *image_view; 1109 1110 Image 1111 *flip_image; 1112 1113 MagickBooleanType 1114 status; 1115 1116 MagickOffsetType 1117 progress; 1118 1119 RectangleInfo 1120 page; 1121 1122 ssize_t 1123 y; 1124 1125 assert(image != (const Image *) NULL); 1126 assert(image->signature == MagickSignature); 1127 if (image->debug != MagickFalse) 1128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1129 assert(exception != (ExceptionInfo *) NULL); 1130 assert(exception->signature == MagickSignature); 1131 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 1132 if (flip_image == (Image *) NULL) 1133 return((Image *) NULL); 1134 /* 1135 Flip image. 1136 */ 1137 status=MagickTrue; 1138 progress=0; 1139 page=image->page; 1140 image_view=AcquireCacheView(image); 1141 flip_view=AcquireCacheView(flip_image); 1142#if defined(MAGICKCORE_OPENMP_SUPPORT) 1143 #pragma omp parallel for schedule(static) shared(progress,status) 1144#endif 1145 for (y=0; y < (ssize_t) flip_image->rows; y++) 1146 { 1147 register const Quantum 1148 *restrict p; 1149 1150 register Quantum 1151 *restrict q; 1152 1153 register ssize_t 1154 x; 1155 1156 if (status == MagickFalse) 1157 continue; 1158 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 1159 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y- 1160 1),flip_image->columns,1,exception); 1161 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 1162 { 1163 status=MagickFalse; 1164 continue; 1165 } 1166 for (x=0; x < (ssize_t) flip_image->columns; x++) 1167 { 1168 register ssize_t 1169 i; 1170 1171 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1172 { 1173 PixelChannel 1174 channel; 1175 1176 PixelTrait 1177 flip_traits, 1178 traits; 1179 1180 channel=GetPixelChannelMapChannel(image,i); 1181 traits=GetPixelChannelMapTraits(image,channel); 1182 flip_traits=GetPixelChannelMapTraits(flip_image,channel); 1183 if ((traits == UndefinedPixelTrait) || 1184 (flip_traits == UndefinedPixelTrait)) 1185 continue; 1186 SetPixelChannel(flip_image,channel,p[i],q); 1187 } 1188 p+=GetPixelChannels(image); 1189 q+=GetPixelChannels(flip_image); 1190 } 1191 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse) 1192 status=MagickFalse; 1193 if (image->progress_monitor != (MagickProgressMonitor) NULL) 1194 { 1195 MagickBooleanType 1196 proceed; 1197 1198#if defined(MAGICKCORE_OPENMP_SUPPORT) 1199 #pragma omp critical (MagickCore_FlipImage) 1200#endif 1201 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows); 1202 if (proceed == MagickFalse) 1203 status=MagickFalse; 1204 } 1205 } 1206 flip_view=DestroyCacheView(flip_view); 1207 image_view=DestroyCacheView(image_view); 1208 flip_image->type=image->type; 1209 if (page.height != 0) 1210 page.y=(ssize_t) (page.height-flip_image->rows-page.y); 1211 flip_image->page=page; 1212 if (status == MagickFalse) 1213 flip_image=DestroyImage(flip_image); 1214 return(flip_image); 1215} 1216 1217/* 1218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1219% % 1220% % 1221% % 1222% F l o p I m a g e % 1223% % 1224% % 1225% % 1226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1227% 1228% FlopImage() creates a horizontal mirror image by reflecting the pixels 1229% around the central y-axis. 1230% 1231% The format of the FlopImage method is: 1232% 1233% Image *FlopImage(const Image *image,ExceptionInfo *exception) 1234% 1235% A description of each parameter follows: 1236% 1237% o image: the image. 1238% 1239% o exception: return any errors or warnings in this structure. 1240% 1241*/ 1242MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception) 1243{ 1244#define FlopImageTag "Flop/Image" 1245 1246 CacheView 1247 *flop_view, 1248 *image_view; 1249 1250 Image 1251 *flop_image; 1252 1253 MagickBooleanType 1254 status; 1255 1256 MagickOffsetType 1257 progress; 1258 1259 RectangleInfo 1260 page; 1261 1262 ssize_t 1263 y; 1264 1265 assert(image != (const Image *) NULL); 1266 assert(image->signature == MagickSignature); 1267 if (image->debug != MagickFalse) 1268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1269 assert(exception != (ExceptionInfo *) NULL); 1270 assert(exception->signature == MagickSignature); 1271 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 1272 if (flop_image == (Image *) NULL) 1273 return((Image *) NULL); 1274 /* 1275 Flop each row. 1276 */ 1277 status=MagickTrue; 1278 progress=0; 1279 page=image->page; 1280 image_view=AcquireCacheView(image); 1281 flop_view=AcquireCacheView(flop_image); 1282#if defined(MAGICKCORE_OPENMP_SUPPORT) 1283 #pragma omp parallel for schedule(static) shared(progress,status) 1284#endif 1285 for (y=0; y < (ssize_t) flop_image->rows; y++) 1286 { 1287 register const Quantum 1288 *restrict p; 1289 1290 register ssize_t 1291 x; 1292 1293 register Quantum 1294 *restrict q; 1295 1296 if (status == MagickFalse) 1297 continue; 1298 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 1299 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1, 1300 exception); 1301 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 1302 { 1303 status=MagickFalse; 1304 continue; 1305 } 1306 q+=GetPixelChannels(flop_image)*flop_image->columns; 1307 for (x=0; x < (ssize_t) flop_image->columns; x++) 1308 { 1309 register ssize_t 1310 i; 1311 1312 q-=GetPixelChannels(flop_image); 1313 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1314 { 1315 PixelChannel 1316 channel; 1317 1318 PixelTrait 1319 flop_traits, 1320 traits; 1321 1322 channel=GetPixelChannelMapChannel(image,i); 1323 traits=GetPixelChannelMapTraits(image,channel); 1324 flop_traits=GetPixelChannelMapTraits(flop_image,channel); 1325 if ((traits == UndefinedPixelTrait) || 1326 (flop_traits == UndefinedPixelTrait)) 1327 continue; 1328 SetPixelChannel(flop_image,channel,p[i],q); 1329 } 1330 p+=GetPixelChannels(image); 1331 } 1332 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse) 1333 status=MagickFalse; 1334 if (image->progress_monitor != (MagickProgressMonitor) NULL) 1335 { 1336 MagickBooleanType 1337 proceed; 1338 1339#if defined(MAGICKCORE_OPENMP_SUPPORT) 1340 #pragma omp critical (MagickCore_FlopImage) 1341#endif 1342 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows); 1343 if (proceed == MagickFalse) 1344 status=MagickFalse; 1345 } 1346 } 1347 flop_view=DestroyCacheView(flop_view); 1348 image_view=DestroyCacheView(image_view); 1349 flop_image->type=image->type; 1350 if (page.width != 0) 1351 page.x=(ssize_t) (page.width-flop_image->columns-page.x); 1352 flop_image->page=page; 1353 if (status == MagickFalse) 1354 flop_image=DestroyImage(flop_image); 1355 return(flop_image); 1356} 1357 1358/* 1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1360% % 1361% % 1362% % 1363% R o l l I m a g e % 1364% % 1365% % 1366% % 1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1368% 1369% RollImage() offsets an image as defined by x_offset and y_offset. 1370% 1371% The format of the RollImage method is: 1372% 1373% Image *RollImage(const Image *image,const ssize_t x_offset, 1374% const ssize_t y_offset,ExceptionInfo *exception) 1375% 1376% A description of each parameter follows: 1377% 1378% o image: the image. 1379% 1380% o x_offset: the number of columns to roll in the horizontal direction. 1381% 1382% o y_offset: the number of rows to roll in the vertical direction. 1383% 1384% o exception: return any errors or warnings in this structure. 1385% 1386*/ 1387 1388static inline MagickBooleanType CopyImageRegion(Image *destination, 1389 const Image *source,const size_t columns,const size_t rows, 1390 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy, 1391 ExceptionInfo *exception) 1392{ 1393 CacheView 1394 *source_view, 1395 *destination_view; 1396 1397 MagickBooleanType 1398 status; 1399 1400 ssize_t 1401 y; 1402 1403 status=MagickTrue; 1404 source_view=AcquireCacheView(source); 1405 destination_view=AcquireCacheView(destination); 1406#if defined(MAGICKCORE_OPENMP_SUPPORT) 1407 #pragma omp parallel for schedule(static,4) shared(status) 1408#endif 1409 for (y=0; y < (ssize_t) rows; y++) 1410 { 1411 MagickBooleanType 1412 sync; 1413 1414 register const Quantum 1415 *restrict p; 1416 1417 register Quantum 1418 *restrict q; 1419 1420 register ssize_t 1421 x; 1422 1423 /* 1424 Transfer scanline. 1425 */ 1426 if (status == MagickFalse) 1427 continue; 1428 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception); 1429 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception); 1430 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 1431 { 1432 status=MagickFalse; 1433 continue; 1434 } 1435 for (x=0; x < (ssize_t) columns; x++) 1436 { 1437 register ssize_t 1438 i; 1439 1440 for (i=0; i < (ssize_t) GetPixelChannels(source); i++) 1441 { 1442 PixelChannel 1443 channel; 1444 1445 PixelTrait 1446 destination_traits, 1447 source_traits; 1448 1449 channel=GetPixelChannelMapChannel(source,i); 1450 source_traits=GetPixelChannelMapTraits(source,channel); 1451 destination_traits=GetPixelChannelMapTraits(destination,channel); 1452 if ((source_traits == UndefinedPixelTrait) || 1453 (destination_traits == UndefinedPixelTrait)) 1454 continue; 1455 SetPixelChannel(destination,channel,p[i],q); 1456 } 1457 p+=GetPixelChannels(source); 1458 q+=GetPixelChannels(destination); 1459 } 1460 sync=SyncCacheViewAuthenticPixels(destination_view,exception); 1461 if (sync == MagickFalse) 1462 status=MagickFalse; 1463 } 1464 destination_view=DestroyCacheView(destination_view); 1465 source_view=DestroyCacheView(source_view); 1466 return(status); 1467} 1468 1469MagickExport Image *RollImage(const Image *image,const ssize_t x_offset, 1470 const ssize_t y_offset,ExceptionInfo *exception) 1471{ 1472#define RollImageTag "Roll/Image" 1473 1474 Image 1475 *roll_image; 1476 1477 MagickStatusType 1478 status; 1479 1480 RectangleInfo 1481 offset; 1482 1483 /* 1484 Initialize roll image attributes. 1485 */ 1486 assert(image != (const Image *) NULL); 1487 assert(image->signature == MagickSignature); 1488 if (image->debug != MagickFalse) 1489 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1490 assert(exception != (ExceptionInfo *) NULL); 1491 assert(exception->signature == MagickSignature); 1492 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 1493 if (roll_image == (Image *) NULL) 1494 return((Image *) NULL); 1495 offset.x=x_offset; 1496 offset.y=y_offset; 1497 while (offset.x < 0) 1498 offset.x+=(ssize_t) image->columns; 1499 while (offset.x >= (ssize_t) image->columns) 1500 offset.x-=(ssize_t) image->columns; 1501 while (offset.y < 0) 1502 offset.y+=(ssize_t) image->rows; 1503 while (offset.y >= (ssize_t) image->rows) 1504 offset.y-=(ssize_t) image->rows; 1505 /* 1506 Roll image. 1507 */ 1508 status=CopyImageRegion(roll_image,image,(size_t) offset.x, 1509 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows- 1510 offset.y,0,0,exception); 1511 (void) SetImageProgress(image,RollImageTag,0,3); 1512 status|=CopyImageRegion(roll_image,image,image->columns-offset.x, 1513 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0, 1514 exception); 1515 (void) SetImageProgress(image,RollImageTag,1,3); 1516 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows- 1517 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception); 1518 (void) SetImageProgress(image,RollImageTag,2,3); 1519 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows- 1520 offset.y,0,0,offset.x,offset.y,exception); 1521 (void) SetImageProgress(image,RollImageTag,3,3); 1522 roll_image->type=image->type; 1523 if (status == MagickFalse) 1524 roll_image=DestroyImage(roll_image); 1525 return(roll_image); 1526} 1527 1528/* 1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1530% % 1531% % 1532% % 1533% S h a v e I m a g e % 1534% % 1535% % 1536% % 1537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1538% 1539% ShaveImage() shaves pixels from the image edges. It allocates the memory 1540% necessary for the new Image structure and returns a pointer to the new 1541% image. 1542% 1543% The format of the ShaveImage method is: 1544% 1545% Image *ShaveImage(const Image *image,const RectangleInfo *shave_info, 1546% ExceptionInfo *exception) 1547% 1548% A description of each parameter follows: 1549% 1550% o shave_image: Method ShaveImage returns a pointer to the shaved 1551% image. A null image is returned if there is a memory shortage or 1552% if the image width or height is zero. 1553% 1554% o image: the image. 1555% 1556% o shave_info: Specifies a pointer to a RectangleInfo which defines the 1557% region of the image to crop. 1558% 1559% o exception: return any errors or warnings in this structure. 1560% 1561*/ 1562MagickExport Image *ShaveImage(const Image *image, 1563 const RectangleInfo *shave_info,ExceptionInfo *exception) 1564{ 1565 Image 1566 *shave_image; 1567 1568 RectangleInfo 1569 geometry; 1570 1571 assert(image != (const Image *) NULL); 1572 assert(image->signature == MagickSignature); 1573 if (image->debug != MagickFalse) 1574 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1575 if (((2*shave_info->width) >= image->columns) || 1576 ((2*shave_info->height) >= image->rows)) 1577 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage"); 1578 SetGeometry(image,&geometry); 1579 geometry.width-=2*shave_info->width; 1580 geometry.height-=2*shave_info->height; 1581 geometry.x=(ssize_t) shave_info->width+image->page.x; 1582 geometry.y=(ssize_t) shave_info->height+image->page.y; 1583 shave_image=CropImage(image,&geometry,exception); 1584 if (shave_image == (Image *) NULL) 1585 return((Image *) NULL); 1586 shave_image->page.width-=2*shave_info->width; 1587 shave_image->page.height-=2*shave_info->height; 1588 shave_image->page.x-=(ssize_t) shave_info->width; 1589 shave_image->page.y-=(ssize_t) shave_info->height; 1590 return(shave_image); 1591} 1592 1593/* 1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1595% % 1596% % 1597% % 1598% S p l i c e I m a g e % 1599% % 1600% % 1601% % 1602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1603% 1604% SpliceImage() splices a solid color into the image as defined by the 1605% geometry. 1606% 1607% The format of the SpliceImage method is: 1608% 1609% Image *SpliceImage(const Image *image,const RectangleInfo *geometry, 1610% ExceptionInfo *exception) 1611% 1612% A description of each parameter follows: 1613% 1614% o image: the image. 1615% 1616% o geometry: Define the region of the image to splice with members 1617% x, y, width, and height. 1618% 1619% o exception: return any errors or warnings in this structure. 1620% 1621*/ 1622MagickExport Image *SpliceImage(const Image *image, 1623 const RectangleInfo *geometry,ExceptionInfo *exception) 1624{ 1625#define SpliceImageTag "Splice/Image" 1626 1627 CacheView 1628 *image_view, 1629 *splice_view; 1630 1631 Image 1632 *splice_image; 1633 1634 MagickBooleanType 1635 status; 1636 1637 MagickOffsetType 1638 progress; 1639 1640 RectangleInfo 1641 splice_geometry; 1642 1643 ssize_t 1644 y; 1645 1646 /* 1647 Allocate splice image. 1648 */ 1649 assert(image != (const Image *) NULL); 1650 assert(image->signature == MagickSignature); 1651 if (image->debug != MagickFalse) 1652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1653 assert(geometry != (const RectangleInfo *) NULL); 1654 assert(exception != (ExceptionInfo *) NULL); 1655 assert(exception->signature == MagickSignature); 1656 splice_geometry=(*geometry); 1657 splice_image=CloneImage(image,image->columns+splice_geometry.width, 1658 image->rows+splice_geometry.height,MagickTrue,exception); 1659 if (splice_image == (Image *) NULL) 1660 return((Image *) NULL); 1661 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse) 1662 { 1663 splice_image=DestroyImage(splice_image); 1664 return((Image *) NULL); 1665 } 1666 (void) SetImageBackgroundColor(splice_image,exception); 1667 /* 1668 Respect image geometry. 1669 */ 1670 switch (image->gravity) 1671 { 1672 default: 1673 case UndefinedGravity: 1674 case NorthWestGravity: 1675 break; 1676 case NorthGravity: 1677 { 1678 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 1679 break; 1680 } 1681 case NorthEastGravity: 1682 { 1683 splice_geometry.x+=(ssize_t) splice_geometry.width; 1684 break; 1685 } 1686 case WestGravity: 1687 { 1688 splice_geometry.y+=(ssize_t) splice_geometry.width/2; 1689 break; 1690 } 1691 case StaticGravity: 1692 case CenterGravity: 1693 { 1694 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 1695 splice_geometry.y+=(ssize_t) splice_geometry.height/2; 1696 break; 1697 } 1698 case EastGravity: 1699 { 1700 splice_geometry.x+=(ssize_t) splice_geometry.width; 1701 splice_geometry.y+=(ssize_t) splice_geometry.height/2; 1702 break; 1703 } 1704 case SouthWestGravity: 1705 { 1706 splice_geometry.y+=(ssize_t) splice_geometry.height; 1707 break; 1708 } 1709 case SouthGravity: 1710 { 1711 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 1712 splice_geometry.y+=(ssize_t) splice_geometry.height; 1713 break; 1714 } 1715 case SouthEastGravity: 1716 { 1717 splice_geometry.x+=(ssize_t) splice_geometry.width; 1718 splice_geometry.y+=(ssize_t) splice_geometry.height; 1719 break; 1720 } 1721 } 1722 /* 1723 Splice image. 1724 */ 1725 status=MagickTrue; 1726 progress=0; 1727 image_view=AcquireCacheView(image); 1728 splice_view=AcquireCacheView(splice_image); 1729#if defined(MAGICKCORE_OPENMP_SUPPORT) 1730 #pragma omp parallel for schedule(static,4) shared(progress,status) 1731#endif 1732 for (y=0; y < (ssize_t) splice_geometry.y; y++) 1733 { 1734 register const Quantum 1735 *restrict p; 1736 1737 register ssize_t 1738 x; 1739 1740 register Quantum 1741 *restrict q; 1742 1743 if (status == MagickFalse) 1744 continue; 1745 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 1746 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1, 1747 exception); 1748 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 1749 { 1750 status=MagickFalse; 1751 continue; 1752 } 1753 for (x=0; x < splice_geometry.x; x++) 1754 { 1755 register ssize_t 1756 i; 1757 1758 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1759 { 1760 PixelChannel 1761 channel; 1762 1763 PixelTrait 1764 splice_traits, 1765 traits; 1766 1767 channel=GetPixelChannelMapChannel(image,i); 1768 traits=GetPixelChannelMapTraits(image,channel); 1769 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 1770 if ((traits == UndefinedPixelTrait) || 1771 (splice_traits == UndefinedPixelTrait)) 1772 continue; 1773 SetPixelChannel(splice_image,channel,p[i],q); 1774 } 1775 p+=GetPixelChannels(image); 1776 q+=GetPixelChannels(splice_image); 1777 } 1778 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++) 1779 q+=GetPixelChannels(splice_image); 1780 for ( ; x < (ssize_t) splice_image->columns; x++) 1781 { 1782 register ssize_t 1783 i; 1784 1785 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1786 { 1787 PixelChannel 1788 channel; 1789 1790 PixelTrait 1791 traits, 1792 splice_traits; 1793 1794 channel=GetPixelChannelMapChannel(image,i); 1795 traits=GetPixelChannelMapTraits(image,channel); 1796 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 1797 if ((traits == UndefinedPixelTrait) || 1798 (splice_traits == UndefinedPixelTrait)) 1799 continue; 1800 SetPixelChannel(splice_image,channel,p[i],q); 1801 } 1802 p+=GetPixelChannels(image); 1803 q+=GetPixelChannels(splice_image); 1804 } 1805 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse) 1806 status=MagickFalse; 1807 if (image->progress_monitor != (MagickProgressMonitor) NULL) 1808 { 1809 MagickBooleanType 1810 proceed; 1811 1812#if defined(MAGICKCORE_OPENMP_SUPPORT) 1813 #pragma omp critical (MagickCore_TransposeImage) 1814#endif 1815 proceed=SetImageProgress(image,SpliceImageTag,progress++, 1816 splice_image->rows); 1817 if (proceed == MagickFalse) 1818 status=MagickFalse; 1819 } 1820 } 1821#if defined(MAGICKCORE_OPENMP_SUPPORT) 1822 #pragma omp parallel for schedule(static,4) shared(progress,status) 1823#endif 1824 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height); 1825 y < (ssize_t) splice_image->rows; y++) 1826 { 1827 register const Quantum 1828 *restrict p; 1829 1830 register ssize_t 1831 x; 1832 1833 register Quantum 1834 *restrict q; 1835 1836 if (status == MagickFalse) 1837 continue; 1838 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height, 1839 image->columns,1,exception); 1840 if ((y < 0) || (y >= (ssize_t) splice_image->rows)) 1841 continue; 1842 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1, 1843 exception); 1844 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 1845 { 1846 status=MagickFalse; 1847 continue; 1848 } 1849 for (x=0; x < splice_geometry.x; x++) 1850 { 1851 register ssize_t 1852 i; 1853 1854 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1855 { 1856 PixelChannel 1857 channel; 1858 1859 PixelTrait 1860 traits, 1861 splice_traits; 1862 1863 channel=GetPixelChannelMapChannel(image,i); 1864 traits=GetPixelChannelMapTraits(image,channel); 1865 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 1866 if ((traits == UndefinedPixelTrait) || 1867 (splice_traits == UndefinedPixelTrait)) 1868 continue; 1869 SetPixelChannel(splice_image,channel,p[i],q); 1870 } 1871 p+=GetPixelChannels(image); 1872 q+=GetPixelChannels(splice_image); 1873 } 1874 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++) 1875 q+=GetPixelChannels(splice_image); 1876 for ( ; x < (ssize_t) splice_image->columns; x++) 1877 { 1878 register ssize_t 1879 i; 1880 1881 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 1882 { 1883 PixelChannel 1884 channel; 1885 1886 PixelTrait 1887 traits, 1888 splice_traits; 1889 1890 channel=GetPixelChannelMapChannel(image,i); 1891 traits=GetPixelChannelMapTraits(image,channel); 1892 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 1893 if ((traits == UndefinedPixelTrait) || 1894 (splice_traits == UndefinedPixelTrait)) 1895 continue; 1896 SetPixelChannel(splice_image,channel,p[i],q); 1897 } 1898 p+=GetPixelChannels(image); 1899 q+=GetPixelChannels(splice_image); 1900 } 1901 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse) 1902 status=MagickFalse; 1903 if (image->progress_monitor != (MagickProgressMonitor) NULL) 1904 { 1905 MagickBooleanType 1906 proceed; 1907 1908#if defined(MAGICKCORE_OPENMP_SUPPORT) 1909 #pragma omp critical (MagickCore_TransposeImage) 1910#endif 1911 proceed=SetImageProgress(image,SpliceImageTag,progress++, 1912 splice_image->rows); 1913 if (proceed == MagickFalse) 1914 status=MagickFalse; 1915 } 1916 } 1917 splice_view=DestroyCacheView(splice_view); 1918 image_view=DestroyCacheView(image_view); 1919 if (status == MagickFalse) 1920 splice_image=DestroyImage(splice_image); 1921 return(splice_image); 1922} 1923 1924/* 1925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1926% % 1927% % 1928% % 1929% T r a n s f o r m I m a g e % 1930% % 1931% % 1932% % 1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1934% 1935% TransformImage() is a convenience method that behaves like ResizeImage() or 1936% CropImage() but accepts scaling and/or cropping information as a region 1937% geometry specification. If the operation fails, the original image handle 1938% is left as is. 1939% 1940% This should only be used for single images. 1941% 1942% This function destroys what it assumes to be a single image list. 1943% If the input image is part of a larger list, all other images in that list 1944% will be simply 'lost', not destroyed. 1945% 1946% Also if the crop generates a list of images only the first image is resized. 1947% And finally if the crop succeeds and the resize failed, you will get a 1948% cropped image, as well as a 'false' or 'failed' report. 1949% 1950% This function and should probably be depreciated in favor of direct calls 1951% to CropImageToTiles() or ResizeImage(), as appropriate. 1952% 1953% The format of the TransformImage method is: 1954% 1955% MagickBooleanType TransformImage(Image **image,const char *crop_geometry, 1956% const char *image_geometry,ExceptionInfo *exception) 1957% 1958% A description of each parameter follows: 1959% 1960% o image: the image The transformed image is returned as this parameter. 1961% 1962% o crop_geometry: A crop geometry string. This geometry defines a 1963% subregion of the image to crop. 1964% 1965% o image_geometry: An image geometry string. This geometry defines the 1966% final size of the image. 1967% 1968% o exception: return any errors or warnings in this structure. 1969% 1970*/ 1971MagickExport MagickBooleanType TransformImage(Image **image, 1972 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception) 1973{ 1974 Image 1975 *resize_image, 1976 *transform_image; 1977 1978 MagickStatusType 1979 flags; 1980 1981 RectangleInfo 1982 geometry; 1983 1984 assert(image != (Image **) NULL); 1985 assert((*image)->signature == MagickSignature); 1986 if ((*image)->debug != MagickFalse) 1987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 1988 transform_image=(*image); 1989 if (crop_geometry != (const char *) NULL) 1990 { 1991 Image 1992 *crop_image; 1993 1994 /* 1995 Crop image to a user specified size. 1996 */ 1997 crop_image=CropImageToTiles(*image,crop_geometry,exception); 1998 if (crop_image == (Image *) NULL) 1999 transform_image=CloneImage(*image,0,0,MagickTrue,exception); 2000 else 2001 { 2002 transform_image=DestroyImage(transform_image); 2003 transform_image=GetFirstImageInList(crop_image); 2004 } 2005 *image=transform_image; 2006 } 2007 if (image_geometry == (const char *) NULL) 2008 return(MagickTrue); 2009 2010 /* 2011 Scale image to a user specified size. 2012 */ 2013 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception); 2014 (void) flags; 2015 if ((transform_image->columns == geometry.width) && 2016 (transform_image->rows == geometry.height)) 2017 return(MagickTrue); 2018 resize_image=ResizeImage(transform_image,geometry.width,geometry.height, 2019 transform_image->filter,transform_image->blur,exception); 2020 if (resize_image == (Image *) NULL) 2021 return(MagickFalse); 2022 transform_image=DestroyImage(transform_image); 2023 transform_image=resize_image; 2024 *image=transform_image; 2025 return(MagickTrue); 2026} 2027 2028/* 2029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2030% % 2031% % 2032% % 2033% T r a n s f o r m I m a g e s % 2034% % 2035% % 2036% % 2037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2038% 2039% TransformImages() calls TransformImage() on each image of a sequence. 2040% 2041% The format of the TransformImage method is: 2042% 2043% MagickBooleanType TransformImages(Image **image, 2044% const char *crop_geometry,const char *image_geometry, 2045% ExceptionInfo *exception) 2046% 2047% A description of each parameter follows: 2048% 2049% o image: the image The transformed image is returned as this parameter. 2050% 2051% o crop_geometry: A crop geometry string. This geometry defines a 2052% subregion of the image to crop. 2053% 2054% o image_geometry: An image geometry string. This geometry defines the 2055% final size of the image. 2056% 2057% o exception: return any errors or warnings in this structure. 2058% 2059*/ 2060MagickExport MagickBooleanType TransformImages(Image **images, 2061 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception) 2062{ 2063 Image 2064 *image, 2065 **image_list, 2066 *transform_images; 2067 2068 MagickStatusType 2069 status; 2070 2071 register ssize_t 2072 i; 2073 2074 assert(images != (Image **) NULL); 2075 assert((*images)->signature == MagickSignature); 2076 if ((*images)->debug != MagickFalse) 2077 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 2078 (*images)->filename); 2079 image_list=ImageListToArray(*images,exception); 2080 if (image_list == (Image **) NULL) 2081 return(MagickFalse); 2082 status=MagickTrue; 2083 transform_images=NewImageList(); 2084 for (i=0; image_list[i] != (Image *) NULL; i++) 2085 { 2086 image=image_list[i]; 2087 status|=TransformImage(&image,crop_geometry,image_geometry,exception); 2088 AppendImageToList(&transform_images,image); 2089 } 2090 *images=transform_images; 2091 image_list=(Image **) RelinquishMagickMemory(image_list); 2092 return(status != 0 ? MagickTrue : MagickFalse); 2093} 2094 2095/* 2096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2097% % 2098% % 2099% % 2100% T r a n s p o s e I m a g e % 2101% % 2102% % 2103% % 2104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2105% 2106% TransposeImage() creates a horizontal mirror image by reflecting the pixels 2107% around the central y-axis while rotating them by 90 degrees. 2108% 2109% The format of the TransposeImage method is: 2110% 2111% Image *TransposeImage(const Image *image,ExceptionInfo *exception) 2112% 2113% A description of each parameter follows: 2114% 2115% o image: the image. 2116% 2117% o exception: return any errors or warnings in this structure. 2118% 2119*/ 2120MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception) 2121{ 2122#define TransposeImageTag "Transpose/Image" 2123 2124 CacheView 2125 *image_view, 2126 *transpose_view; 2127 2128 Image 2129 *transpose_image; 2130 2131 MagickBooleanType 2132 status; 2133 2134 MagickOffsetType 2135 progress; 2136 2137 RectangleInfo 2138 page; 2139 2140 ssize_t 2141 y; 2142 2143 assert(image != (const Image *) NULL); 2144 assert(image->signature == MagickSignature); 2145 if (image->debug != MagickFalse) 2146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2147 assert(exception != (ExceptionInfo *) NULL); 2148 assert(exception->signature == MagickSignature); 2149 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue, 2150 exception); 2151 if (transpose_image == (Image *) NULL) 2152 return((Image *) NULL); 2153 /* 2154 Transpose image. 2155 */ 2156 status=MagickTrue; 2157 progress=0; 2158 image_view=AcquireCacheView(image); 2159 transpose_view=AcquireCacheView(transpose_image); 2160#if defined(MAGICKCORE_OPENMP_SUPPORT) 2161 #pragma omp parallel for schedule(static,4) shared(progress,status) 2162#endif 2163 for (y=0; y < (ssize_t) image->rows; y++) 2164 { 2165 register const Quantum 2166 *restrict p; 2167 2168 register Quantum 2169 *restrict q; 2170 2171 register ssize_t 2172 x; 2173 2174 if (status == MagickFalse) 2175 continue; 2176 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1, 2177 image->columns,1,exception); 2178 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1), 2179 0,1,transpose_image->rows,exception); 2180 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2181 { 2182 status=MagickFalse; 2183 continue; 2184 } 2185 for (x=0; x < (ssize_t) image->columns; x++) 2186 { 2187 register ssize_t 2188 i; 2189 2190 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2191 { 2192 PixelChannel 2193 channel; 2194 2195 PixelTrait 2196 traits, 2197 transpose_traits; 2198 2199 channel=GetPixelChannelMapChannel(image,i); 2200 traits=GetPixelChannelMapTraits(image,channel); 2201 transpose_traits=GetPixelChannelMapTraits(transpose_image,channel); 2202 if ((traits == UndefinedPixelTrait) || 2203 (transpose_traits == UndefinedPixelTrait)) 2204 continue; 2205 SetPixelChannel(transpose_image,channel,p[i],q); 2206 } 2207 p+=GetPixelChannels(image); 2208 q+=GetPixelChannels(transpose_image); 2209 } 2210 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse) 2211 status=MagickFalse; 2212 if (image->progress_monitor != (MagickProgressMonitor) NULL) 2213 { 2214 MagickBooleanType 2215 proceed; 2216 2217#if defined(MAGICKCORE_OPENMP_SUPPORT) 2218 #pragma omp critical (MagickCore_TransposeImage) 2219#endif 2220 proceed=SetImageProgress(image,TransposeImageTag,progress++, 2221 image->rows); 2222 if (proceed == MagickFalse) 2223 status=MagickFalse; 2224 } 2225 } 2226 transpose_view=DestroyCacheView(transpose_view); 2227 image_view=DestroyCacheView(image_view); 2228 transpose_image->type=image->type; 2229 page=transpose_image->page; 2230 Swap(page.width,page.height); 2231 Swap(page.x,page.y); 2232 transpose_image->page=page; 2233 if (status == MagickFalse) 2234 transpose_image=DestroyImage(transpose_image); 2235 return(transpose_image); 2236} 2237 2238/* 2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2240% % 2241% % 2242% % 2243% T r a n s v e r s e I m a g e % 2244% % 2245% % 2246% % 2247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2248% 2249% TransverseImage() creates a vertical mirror image by reflecting the pixels 2250% around the central x-axis while rotating them by 270 degrees. 2251% 2252% The format of the TransverseImage method is: 2253% 2254% Image *TransverseImage(const Image *image,ExceptionInfo *exception) 2255% 2256% A description of each parameter follows: 2257% 2258% o image: the image. 2259% 2260% o exception: return any errors or warnings in this structure. 2261% 2262*/ 2263MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception) 2264{ 2265#define TransverseImageTag "Transverse/Image" 2266 2267 CacheView 2268 *image_view, 2269 *transverse_view; 2270 2271 Image 2272 *transverse_image; 2273 2274 MagickBooleanType 2275 status; 2276 2277 MagickOffsetType 2278 progress; 2279 2280 RectangleInfo 2281 page; 2282 2283 ssize_t 2284 y; 2285 2286 assert(image != (const Image *) NULL); 2287 assert(image->signature == MagickSignature); 2288 if (image->debug != MagickFalse) 2289 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2290 assert(exception != (ExceptionInfo *) NULL); 2291 assert(exception->signature == MagickSignature); 2292 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue, 2293 exception); 2294 if (transverse_image == (Image *) NULL) 2295 return((Image *) NULL); 2296 /* 2297 Transverse image. 2298 */ 2299 status=MagickTrue; 2300 progress=0; 2301 image_view=AcquireCacheView(image); 2302 transverse_view=AcquireCacheView(transverse_image); 2303#if defined(MAGICKCORE_OPENMP_SUPPORT) 2304 #pragma omp parallel for schedule(static,4) shared(progress,status) 2305#endif 2306 for (y=0; y < (ssize_t) image->rows; y++) 2307 { 2308 MagickBooleanType 2309 sync; 2310 2311 register const Quantum 2312 *restrict p; 2313 2314 register Quantum 2315 *restrict q; 2316 2317 register ssize_t 2318 x; 2319 2320 if (status == MagickFalse) 2321 continue; 2322 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 2323 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1), 2324 0,1,transverse_image->rows,exception); 2325 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 2326 { 2327 status=MagickFalse; 2328 continue; 2329 } 2330 q+=GetPixelChannels(transverse_image)*image->columns; 2331 for (x=0; x < (ssize_t) image->columns; x++) 2332 { 2333 register ssize_t 2334 i; 2335 2336 q-=GetPixelChannels(transverse_image); 2337 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 2338 { 2339 PixelChannel 2340 channel; 2341 2342 PixelTrait 2343 traits, 2344 transverse_traits; 2345 2346 channel=GetPixelChannelMapChannel(image,i); 2347 traits=GetPixelChannelMapTraits(image,channel); 2348 transverse_traits=GetPixelChannelMapTraits(transverse_image,channel); 2349 if ((traits == UndefinedPixelTrait) || 2350 (transverse_traits == UndefinedPixelTrait)) 2351 continue; 2352 SetPixelChannel(transverse_image,channel,p[i],q); 2353 } 2354 p+=GetPixelChannels(image); 2355 } 2356 sync=SyncCacheViewAuthenticPixels(transverse_view,exception); 2357 if (sync == MagickFalse) 2358 status=MagickFalse; 2359 if (image->progress_monitor != (MagickProgressMonitor) NULL) 2360 { 2361 MagickBooleanType 2362 proceed; 2363 2364#if defined(MAGICKCORE_OPENMP_SUPPORT) 2365 #pragma omp critical (MagickCore_TransverseImage) 2366#endif 2367 proceed=SetImageProgress(image,TransverseImageTag,progress++, 2368 image->rows); 2369 if (proceed == MagickFalse) 2370 status=MagickFalse; 2371 } 2372 } 2373 transverse_view=DestroyCacheView(transverse_view); 2374 image_view=DestroyCacheView(image_view); 2375 transverse_image->type=image->type; 2376 page=transverse_image->page; 2377 Swap(page.width,page.height); 2378 Swap(page.x,page.y); 2379 if (page.width != 0) 2380 page.x=(ssize_t) (page.width-transverse_image->columns-page.x); 2381 if (page.height != 0) 2382 page.y=(ssize_t) (page.height-transverse_image->rows-page.y); 2383 transverse_image->page=page; 2384 if (status == MagickFalse) 2385 transverse_image=DestroyImage(transverse_image); 2386 return(transverse_image); 2387} 2388 2389/* 2390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2391% % 2392% % 2393% % 2394% T r i m I m a g e % 2395% % 2396% % 2397% % 2398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2399% 2400% TrimImage() trims pixels from the image edges. It allocates the memory 2401% necessary for the new Image structure and returns a pointer to the new 2402% image. 2403% 2404% The format of the TrimImage method is: 2405% 2406% Image *TrimImage(const Image *image,ExceptionInfo *exception) 2407% 2408% A description of each parameter follows: 2409% 2410% o image: the image. 2411% 2412% o exception: return any errors or warnings in this structure. 2413% 2414*/ 2415MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception) 2416{ 2417 RectangleInfo 2418 geometry; 2419 2420 assert(image != (const Image *) NULL); 2421 assert(image->signature == MagickSignature); 2422 if (image->debug != MagickFalse) 2423 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2424 geometry=GetImageBoundingBox(image,exception); 2425 if ((geometry.width == 0) || (geometry.height == 0)) 2426 { 2427 Image 2428 *crop_image; 2429 2430 crop_image=CloneImage(image,1,1,MagickTrue,exception); 2431 if (crop_image == (Image *) NULL) 2432 return((Image *) NULL); 2433 crop_image->background_color.alpha=(Quantum) TransparentAlpha; 2434 (void) SetImageBackgroundColor(crop_image,exception); 2435 crop_image->page=image->page; 2436 crop_image->page.x=(-1); 2437 crop_image->page.y=(-1); 2438 return(crop_image); 2439 } 2440 geometry.x+=image->page.x; 2441 geometry.y+=image->page.y; 2442 return(CropImage(image,&geometry,exception)); 2443} 2444