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