00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "magick/studio.h"
00043 #include "magick/attribute.h"
00044 #include "magick/cache.h"
00045 #include "magick/cache-view.h"
00046 #include "magick/color.h"
00047 #include "magick/color-private.h"
00048 #include "magick/colorspace-private.h"
00049 #include "magick/composite.h"
00050 #include "magick/draw.h"
00051 #include "magick/effect.h"
00052 #include "magick/exception.h"
00053 #include "magick/exception-private.h"
00054 #include "magick/geometry.h"
00055 #include "magick/image.h"
00056 #include "magick/memory_.h"
00057 #include "magick/layer.h"
00058 #include "magick/list.h"
00059 #include "magick/monitor.h"
00060 #include "magick/monitor-private.h"
00061 #include "magick/pixel-private.h"
00062 #include "magick/resource_.h"
00063 #include "magick/resize.h"
00064 #include "magick/statistic.h"
00065 #include "magick/string_.h"
00066 #include "magick/transform.h"
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
00097 ExceptionInfo *exception)
00098 {
00099 #define ChopImageTag "Chop/Image"
00100
00101 CacheView
00102 *chop_view,
00103 *image_view;
00104
00105 Image
00106 *chop_image;
00107
00108 long
00109 j,
00110 y;
00111
00112 MagickBooleanType
00113 proceed,
00114 status;
00115
00116 RectangleInfo
00117 extent;
00118
00119 register long
00120 i;
00121
00122
00123
00124
00125 assert(image != (const Image *) NULL);
00126 assert(image->signature == MagickSignature);
00127 if (image->debug != MagickFalse)
00128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00129 assert(exception != (ExceptionInfo *) NULL);
00130 assert(exception->signature == MagickSignature);
00131 assert(chop_info != (RectangleInfo *) NULL);
00132 if (((chop_info->x+(long) chop_info->width) < 0) ||
00133 ((chop_info->y+(long) chop_info->height) < 0) ||
00134 (chop_info->x > (long) image->columns) ||
00135 (chop_info->y > (long) image->rows))
00136 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
00137 extent=(*chop_info);
00138 if ((extent.x+(long) extent.width) > (long) image->columns)
00139 extent.width=(unsigned long) ((long) image->columns-extent.x);
00140 if ((extent.y+(long) extent.height) > (long) image->rows)
00141 extent.height=(unsigned long) ((long) image->rows-extent.y);
00142 if (extent.x < 0)
00143 {
00144 extent.width-=(unsigned long) (-extent.x);
00145 extent.x=0;
00146 }
00147 if (extent.y < 0)
00148 {
00149 extent.height-=(unsigned long) (-extent.y);
00150 extent.y=0;
00151 }
00152 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
00153 extent.height,MagickTrue,exception);
00154 if (chop_image == (Image *) NULL)
00155 return((Image *) NULL);
00156
00157
00158
00159 status=MagickTrue;
00160 i=0;
00161 j=0;
00162 image_view=AcquireCacheView(image);
00163 chop_view=AcquireCacheView(chop_image);
00164 for (y=0; y < (long) extent.y; y++)
00165 {
00166 register const PixelPacket
00167 *restrict p;
00168
00169 register IndexPacket
00170 *restrict chop_indexes,
00171 *restrict indexes;
00172
00173 register long
00174 x;
00175
00176 register PixelPacket
00177 *restrict q;
00178
00179 if (status == MagickFalse)
00180 continue;
00181 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
00182 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
00183 exception);
00184 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00185 {
00186 status=MagickFalse;
00187 continue;
00188 }
00189 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00190 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
00191 for (x=0; x < (long) image->columns; x++)
00192 {
00193 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
00194 {
00195 *q=(*p);
00196 if (indexes != (IndexPacket *) NULL)
00197 {
00198 if (chop_indexes != (IndexPacket *) NULL)
00199 *chop_indexes++=indexes[x];
00200 }
00201 q++;
00202 }
00203 p++;
00204 }
00205 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00206 status=MagickFalse;
00207 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
00208 if (proceed == MagickFalse)
00209 status=MagickFalse;
00210 }
00211
00212
00213
00214 i+=extent.height;
00215 for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
00216 {
00217 register const PixelPacket
00218 *restrict p;
00219
00220 register IndexPacket
00221 *restrict chop_indexes,
00222 *restrict indexes;
00223
00224 register long
00225 x;
00226
00227 register PixelPacket
00228 *restrict q;
00229
00230 if (status == MagickFalse)
00231 continue;
00232 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
00233 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
00234 exception);
00235 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00236 {
00237 status=MagickFalse;
00238 continue;
00239 }
00240 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00241 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
00242 for (x=0; x < (long) image->columns; x++)
00243 {
00244 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
00245 {
00246 *q=(*p);
00247 if (indexes != (IndexPacket *) NULL)
00248 {
00249 if (chop_indexes != (IndexPacket *) NULL)
00250 *chop_indexes++=indexes[x];
00251 }
00252 q++;
00253 }
00254 p++;
00255 }
00256 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00257 status=MagickFalse;
00258 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
00259 if (proceed == MagickFalse)
00260 status=MagickFalse;
00261 }
00262 chop_view=DestroyCacheView(chop_view);
00263 image_view=DestroyCacheView(image_view);
00264 chop_image->type=image->type;
00265 return(chop_image);
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 MagickExport Image *ConsolidateCMYKImages(const Image *images,
00294 ExceptionInfo *exception)
00295 {
00296 Image
00297 *cmyk_image,
00298 *cmyk_images;
00299
00300 long
00301 y;
00302
00303 register long
00304 i;
00305
00306
00307
00308
00309 assert(images != (Image *) NULL);
00310 assert(images->signature == MagickSignature);
00311 if (images->debug != MagickFalse)
00312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00313 assert(exception != (ExceptionInfo *) NULL);
00314 assert(exception->signature == MagickSignature);
00315 cmyk_images=NewImageList();
00316 for (i=0; i < (long) GetImageListLength(images); i+=4)
00317 {
00318 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
00319 exception);
00320 if (cmyk_image == (Image *) NULL)
00321 break;
00322 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
00323 break;
00324 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
00325 for (y=0; y < (long) images->rows; y++)
00326 {
00327 register const PixelPacket
00328 *restrict p;
00329
00330 register long
00331 x;
00332
00333 register PixelPacket
00334 *restrict q;
00335
00336 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00337 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00338 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00339 break;
00340 for (x=0; x < (long) images->columns; x++)
00341 {
00342 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00343 p++;
00344 q++;
00345 }
00346 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00347 break;
00348 }
00349 images=GetNextImageInList(images);
00350 if (images == (Image *) NULL)
00351 break;
00352 for (y=0; y < (long) images->rows; y++)
00353 {
00354 register const PixelPacket
00355 *restrict p;
00356
00357 register long
00358 x;
00359
00360 register PixelPacket
00361 *restrict q;
00362
00363 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00364 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00365 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00366 break;
00367 for (x=0; x < (long) images->columns; x++)
00368 {
00369 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00370 p++;
00371 q++;
00372 }
00373 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00374 break;
00375 }
00376 images=GetNextImageInList(images);
00377 if (images == (Image *) NULL)
00378 break;
00379 for (y=0; y < (long) images->rows; y++)
00380 {
00381 register const PixelPacket
00382 *restrict p;
00383
00384 register long
00385 x;
00386
00387 register PixelPacket
00388 *restrict q;
00389
00390 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00391 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00392 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00393 break;
00394 for (x=0; x < (long) images->columns; x++)
00395 {
00396 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00397 p++;
00398 q++;
00399 }
00400 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00401 break;
00402 }
00403 images=GetNextImageInList(images);
00404 if (images == (Image *) NULL)
00405 break;
00406 for (y=0; y < (long) images->rows; y++)
00407 {
00408 register const PixelPacket
00409 *restrict p;
00410
00411 register IndexPacket
00412 *restrict indexes;
00413
00414 register long
00415 x;
00416
00417 register PixelPacket
00418 *restrict q;
00419
00420 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00421 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00422 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00423 break;
00424 indexes=GetAuthenticIndexQueue(cmyk_image);
00425 for (x=0; x < (long) images->columns; x++)
00426 {
00427 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
00428 p++;
00429 }
00430 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00431 break;
00432 }
00433 AppendImageToList(&cmyk_images,cmyk_image);
00434 images=GetNextImageInList(images);
00435 if (images == (Image *) NULL)
00436 break;
00437 }
00438 return(cmyk_images);
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
00471 ExceptionInfo *exception)
00472 {
00473 #define CropImageTag "Crop/Image"
00474
00475 CacheView
00476 *crop_view,
00477 *image_view;
00478
00479 Image
00480 *crop_image;
00481
00482 long
00483 progress,
00484 y;
00485
00486 MagickBooleanType
00487 status;
00488
00489 RectangleInfo
00490 bounding_box,
00491 page;
00492
00493
00494
00495
00496 assert(image != (const Image *) NULL);
00497 assert(image->signature == MagickSignature);
00498 if (image->debug != MagickFalse)
00499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00500 assert(geometry != (const RectangleInfo *) NULL);
00501 assert(exception != (ExceptionInfo *) NULL);
00502 assert(exception->signature == MagickSignature);
00503 bounding_box=image->page;
00504 if ((bounding_box.width == 0) || (bounding_box.height == 0))
00505 {
00506 bounding_box.width=image->columns;
00507 bounding_box.height=image->rows;
00508 }
00509 page=(*geometry);
00510 if (page.width == 0)
00511 page.width=bounding_box.width;
00512 if (page.height == 0)
00513 page.height=bounding_box.height;
00514 if (((bounding_box.x-page.x) >= (long) page.width) ||
00515 ((bounding_box.y-page.y) >= (long) page.height) ||
00516 ((page.x-bounding_box.x) > (long) image->columns) ||
00517 ((page.y-bounding_box.y) > (long) image->rows))
00518 {
00519
00520
00521
00522 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00523 "GeometryDoesNotContainImage","`%s'",image->filename);
00524 crop_image=CloneImage(image,1,1,MagickTrue,exception);
00525 if (crop_image == (Image *) NULL)
00526 return((Image *) NULL);
00527 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
00528 (void) SetImageBackgroundColor(crop_image);
00529 crop_image->page=bounding_box;
00530 crop_image->page.x=(-1);
00531 crop_image->page.y=(-1);
00532 if (crop_image->dispose == BackgroundDispose)
00533 crop_image->dispose=NoneDispose;
00534 return(crop_image);
00535 }
00536 if ((page.x < 0) && (bounding_box.x >= 0))
00537 {
00538 page.width+=page.x-bounding_box.x;
00539 page.x=0;
00540 }
00541 else
00542 {
00543 page.width-=bounding_box.x-page.x;
00544 page.x-=bounding_box.x;
00545 if (page.x < 0)
00546 page.x=0;
00547 }
00548 if ((page.y < 0) && (bounding_box.y >= 0))
00549 {
00550 page.height+=page.y-bounding_box.y;
00551 page.y=0;
00552 }
00553 else
00554 {
00555 page.height-=bounding_box.y-page.y;
00556 page.y-=bounding_box.y;
00557 if (page.y < 0)
00558 page.y=0;
00559 }
00560 if ((unsigned long) (page.x+page.width) > image->columns)
00561 page.width=image->columns-page.x;
00562 if ((geometry->width != 0) && (page.width > geometry->width))
00563 page.width=geometry->width;
00564 if ((unsigned long) (page.y+page.height) > image->rows)
00565 page.height=image->rows-page.y;
00566 if ((geometry->height != 0) && (page.height > geometry->height))
00567 page.height=geometry->height;
00568 bounding_box.x+=page.x;
00569 bounding_box.y+=page.y;
00570 if ((page.width == 0) || (page.height == 0))
00571 {
00572 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00573 "GeometryDoesNotContainImage","`%s'",image->filename);
00574 return((Image *) NULL);
00575 }
00576
00577
00578
00579 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
00580 if (crop_image == (Image *) NULL)
00581 return((Image *) NULL);
00582 crop_image->page.width=image->page.width;
00583 crop_image->page.height=image->page.height;
00584 if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
00585 ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
00586 {
00587 crop_image->page.width=bounding_box.width;
00588 crop_image->page.height=bounding_box.height;
00589 }
00590 crop_image->page.x=bounding_box.x;
00591 crop_image->page.y=bounding_box.y;
00592
00593
00594
00595 status=MagickTrue;
00596 progress=0;
00597 image_view=AcquireCacheView(image);
00598 crop_view=AcquireCacheView(crop_image);
00599 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
00600 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00601 #endif
00602 for (y=0; y < (long) crop_image->rows; y++)
00603 {
00604 register const IndexPacket
00605 *restrict indexes;
00606
00607 register const PixelPacket
00608 *restrict p;
00609
00610 register IndexPacket
00611 *restrict crop_indexes;
00612
00613 register PixelPacket
00614 *restrict q;
00615
00616 if (status == MagickFalse)
00617 continue;
00618 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
00619 1,exception);
00620 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
00621 exception);
00622 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00623 {
00624 status=MagickFalse;
00625 continue;
00626 }
00627 indexes=GetCacheViewVirtualIndexQueue(image_view);
00628 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
00629 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
00630 if ((indexes != (IndexPacket *) NULL) &&
00631 (crop_indexes != (IndexPacket *) NULL))
00632 (void) CopyMagickMemory(crop_indexes,indexes,(size_t) crop_image->columns*
00633 sizeof(*crop_indexes));
00634 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
00635 status=MagickFalse;
00636 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00637 {
00638 MagickBooleanType
00639 proceed;
00640
00641 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
00642 #pragma omp critical (MagickCore_CropImage)
00643 #endif
00644 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
00645 if (proceed == MagickFalse)
00646 status=MagickFalse;
00647 }
00648 }
00649 crop_view=DestroyCacheView(crop_view);
00650 image_view=DestroyCacheView(image_view);
00651 crop_image->type=image->type;
00652 if (status == MagickFalse)
00653 crop_image=DestroyImage(crop_image);
00654 return(crop_image);
00655 }
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685 MagickExport Image *ExcerptImage(const Image *image,
00686 const RectangleInfo *geometry,ExceptionInfo *exception)
00687 {
00688 #define ExcerptImageTag "Excerpt/Image"
00689
00690 CacheView
00691 *excerpt_view,
00692 *image_view;
00693
00694 Image
00695 *excerpt_image;
00696
00697 long
00698 progress,
00699 y;
00700
00701 MagickBooleanType
00702 status;
00703
00704
00705
00706
00707 assert(image != (const Image *) NULL);
00708 assert(image->signature == MagickSignature);
00709 if (image->debug != MagickFalse)
00710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00711 assert(geometry != (const RectangleInfo *) NULL);
00712 assert(exception != (ExceptionInfo *) NULL);
00713 assert(exception->signature == MagickSignature);
00714 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
00715 exception);
00716 if (excerpt_image == (Image *) NULL)
00717 return((Image *) NULL);
00718
00719
00720
00721 status=MagickTrue;
00722 progress=0;
00723 image_view=AcquireCacheView(image);
00724 excerpt_view=AcquireCacheView(excerpt_image);
00725 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00726 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00727 #endif
00728 for (y=0; y < (long) excerpt_image->rows; y++)
00729 {
00730 register const PixelPacket
00731 *restrict p;
00732
00733 register IndexPacket
00734 *restrict excerpt_indexes,
00735 *restrict indexes;
00736
00737 register PixelPacket
00738 *restrict q;
00739
00740 if (status == MagickFalse)
00741 continue;
00742 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
00743 geometry->width,1,exception);
00744 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
00745 exception);
00746 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00747 {
00748 status=MagickFalse;
00749 continue;
00750 }
00751 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
00752 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00753 if (indexes != (IndexPacket *) NULL)
00754 {
00755 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
00756 if (excerpt_indexes != (IndexPacket *) NULL)
00757 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
00758 excerpt_image->columns*sizeof(*excerpt_indexes));
00759 }
00760 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
00761 status=MagickFalse;
00762 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00763 {
00764 MagickBooleanType
00765 proceed;
00766
00767 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00768 #pragma omp critical (MagickCore_ExcerptImage)
00769 #endif
00770 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
00771 if (proceed == MagickFalse)
00772 status=MagickFalse;
00773 }
00774 }
00775 excerpt_view=DestroyCacheView(excerpt_view);
00776 image_view=DestroyCacheView(image_view);
00777 excerpt_image->type=image->type;
00778 if (status == MagickFalse)
00779 excerpt_image=DestroyImage(excerpt_image);
00780 return(excerpt_image);
00781 }
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813 MagickExport Image *ExtentImage(const Image *image,
00814 const RectangleInfo *geometry,ExceptionInfo *exception)
00815 {
00816 Image
00817 *extent_image;
00818
00819
00820
00821
00822 assert(image != (const Image *) NULL);
00823 assert(image->signature == MagickSignature);
00824 if (image->debug != MagickFalse)
00825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00826 assert(geometry != (const RectangleInfo *) NULL);
00827 assert(exception != (ExceptionInfo *) NULL);
00828 assert(exception->signature == MagickSignature);
00829 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
00830 exception);
00831 if (extent_image == (Image *) NULL)
00832 return((Image *) NULL);
00833 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
00834 {
00835 InheritException(exception,&extent_image->exception);
00836 extent_image=DestroyImage(extent_image);
00837 return((Image *) NULL);
00838 }
00839 if (extent_image->background_color.opacity != OpaqueOpacity)
00840 extent_image->matte=MagickTrue;
00841 (void) SetImageBackgroundColor(extent_image);
00842 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
00843 geometry->y);
00844 return(extent_image);
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
00873 {
00874 #define FlipImageTag "Flip/Image"
00875
00876 CacheView
00877 *flip_view,
00878 *image_view;
00879
00880 Image
00881 *flip_image;
00882
00883 long
00884 progress,
00885 y;
00886
00887 MagickBooleanType
00888 status;
00889
00890 assert(image != (const Image *) NULL);
00891 assert(image->signature == MagickSignature);
00892 if (image->debug != MagickFalse)
00893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00894 assert(exception != (ExceptionInfo *) NULL);
00895 assert(exception->signature == MagickSignature);
00896 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00897 if (flip_image == (Image *) NULL)
00898 return((Image *) NULL);
00899
00900
00901
00902 status=MagickTrue;
00903 progress=0;
00904 image_view=AcquireCacheView(image);
00905 flip_view=AcquireCacheView(flip_image);
00906 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
00907 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00908 #endif
00909 for (y=0; y < (long) flip_image->rows; y++)
00910 {
00911 register const IndexPacket
00912 *restrict indexes;
00913
00914 register const PixelPacket
00915 *restrict p;
00916
00917 register IndexPacket
00918 *restrict flip_indexes;
00919
00920 register PixelPacket
00921 *restrict q;
00922
00923 if (status == MagickFalse)
00924 continue;
00925 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00926 q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
00927 flip_image->columns,1,exception);
00928 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00929 {
00930 status=MagickFalse;
00931 continue;
00932 }
00933 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
00934 indexes=GetCacheViewVirtualIndexQueue(image_view);
00935 if (indexes != (const IndexPacket *) NULL)
00936 {
00937 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
00938 if (flip_indexes != (IndexPacket *) NULL)
00939 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
00940 sizeof(*flip_indexes));
00941 }
00942 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
00943 status=MagickFalse;
00944 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00945 {
00946 MagickBooleanType
00947 proceed;
00948
00949 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
00950 #pragma omp critical (MagickCore_FlipImage)
00951 #endif
00952 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
00953 if (proceed == MagickFalse)
00954 status=MagickFalse;
00955 }
00956 }
00957 flip_view=DestroyCacheView(flip_view);
00958 image_view=DestroyCacheView(image_view);
00959 flip_image->type=image->type;
00960 if (status == MagickFalse)
00961 flip_image=DestroyImage(flip_image);
00962 return(flip_image);
00963 }
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
00991 {
00992 #define FlopImageTag "Flop/Image"
00993
00994 CacheView
00995 *flop_view,
00996 *image_view;
00997
00998 Image
00999 *flop_image;
01000
01001 long
01002 progress,
01003 y;
01004
01005 MagickBooleanType
01006 status;
01007
01008 assert(image != (const Image *) NULL);
01009 assert(image->signature == MagickSignature);
01010 if (image->debug != MagickFalse)
01011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01012 assert(exception != (ExceptionInfo *) NULL);
01013 assert(exception->signature == MagickSignature);
01014 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
01015 if (flop_image == (Image *) NULL)
01016 return((Image *) NULL);
01017
01018
01019
01020 status=MagickTrue;
01021 progress=0;
01022 image_view=AcquireCacheView(image);
01023 flop_view=AcquireCacheView(flop_image);
01024 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
01025 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01026 #endif
01027 for (y=0; y < (long) flop_image->rows; y++)
01028 {
01029 register const IndexPacket
01030 *restrict indexes;
01031
01032 register const PixelPacket
01033 *restrict p;
01034
01035 register IndexPacket
01036 *restrict flop_indexes;
01037
01038 register long
01039 x;
01040
01041 register PixelPacket
01042 *restrict q;
01043
01044 if (status == MagickFalse)
01045 continue;
01046 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
01047 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
01048 exception);
01049 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01050 {
01051 status=MagickFalse;
01052 continue;
01053 }
01054 q+=flop_image->columns;
01055 indexes=GetCacheViewVirtualIndexQueue(image_view);
01056 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
01057 for (x=0; x < (long) flop_image->columns; x++)
01058 {
01059 (*--q)=(*p++);
01060 if ((indexes != (const IndexPacket *) NULL) &&
01061 (flop_indexes != (IndexPacket *) NULL))
01062 flop_indexes[flop_image->columns-x-1]=indexes[x];
01063 }
01064 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
01065 status=MagickFalse;
01066 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01067 {
01068 MagickBooleanType
01069 proceed;
01070
01071 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01072 #pragma omp critical (MagickCore_FlopImage)
01073 #endif
01074 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
01075 if (proceed == MagickFalse)
01076 status=MagickFalse;
01077 }
01078 }
01079 flop_view=DestroyCacheView(flop_view);
01080 image_view=DestroyCacheView(image_view);
01081 flop_image->type=image->type;
01082 if (status == MagickFalse)
01083 flop_image=DestroyImage(flop_image);
01084 return(flop_image);
01085 }
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117 static inline MagickBooleanType CopyImageRegion(Image *destination,
01118 const Image *source,const unsigned long columns,const unsigned long rows,
01119 const long sx,const long sy,const long dx,const long dy,
01120 ExceptionInfo *exception)
01121 {
01122 CacheView
01123 *source_view,
01124 *destination_view;
01125
01126 long
01127 y;
01128
01129 MagickBooleanType
01130 status;
01131
01132 status=MagickTrue;
01133 source_view=AcquireCacheView(source);
01134 destination_view=AcquireCacheView(destination);
01135 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01136 #pragma omp parallel for schedule(dynamic,4) shared(status)
01137 #endif
01138 for (y=0; y < (long) rows; y++)
01139 {
01140 MagickBooleanType
01141 sync;
01142
01143 register const IndexPacket
01144 *restrict indexes;
01145
01146 register const PixelPacket
01147 *restrict p;
01148
01149 register IndexPacket
01150 *restrict destination_indexes;
01151
01152 register PixelPacket
01153 *restrict q;
01154
01155
01156
01157
01158 if (status == MagickFalse)
01159 continue;
01160 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
01161 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
01162 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01163 {
01164 status=MagickFalse;
01165 continue;
01166 }
01167 indexes=GetCacheViewVirtualIndexQueue(source_view);
01168 (void) CopyMagickMemory(q,p,(size_t) columns*sizeof(*p));
01169 if (indexes != (IndexPacket *) NULL)
01170 {
01171 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
01172 if (destination_indexes != (IndexPacket *) NULL)
01173 (void) CopyMagickMemory(destination_indexes,indexes,(size_t)
01174 columns*sizeof(*indexes));
01175 }
01176 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
01177 if (sync == MagickFalse)
01178 status=MagickFalse;
01179 }
01180 destination_view=DestroyCacheView(destination_view);
01181 source_view=DestroyCacheView(source_view);
01182 return(status);
01183 }
01184
01185 MagickExport Image *RollImage(const Image *image,const long x_offset,
01186 const long y_offset,ExceptionInfo *exception)
01187 {
01188 #define RollImageTag "Roll/Image"
01189
01190 Image
01191 *roll_image;
01192
01193 MagickStatusType
01194 status;
01195
01196 RectangleInfo
01197 offset;
01198
01199
01200
01201
01202 assert(image != (const Image *) NULL);
01203 assert(image->signature == MagickSignature);
01204 if (image->debug != MagickFalse)
01205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01206 assert(exception != (ExceptionInfo *) NULL);
01207 assert(exception->signature == MagickSignature);
01208 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
01209 if (roll_image == (Image *) NULL)
01210 return((Image *) NULL);
01211 offset.x=x_offset;
01212 offset.y=y_offset;
01213 while (offset.x < 0)
01214 offset.x+=image->columns;
01215 while (offset.x >= (long) image->columns)
01216 offset.x-=image->columns;
01217 while (offset.y < 0)
01218 offset.y+=image->rows;
01219 while (offset.y >= (long) image->rows)
01220 offset.y-=image->rows;
01221
01222
01223
01224 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
01225 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
01226 offset.y,0,0,exception);
01227 (void) SetImageProgress(image,RollImageTag,0,3);
01228 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
01229 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
01230 exception);
01231 (void) SetImageProgress(image,RollImageTag,1,3);
01232 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
01233 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
01234 (void) SetImageProgress(image,RollImageTag,2,3);
01235 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
01236 offset.y,0,0,offset.x,offset.y,exception);
01237 (void) SetImageProgress(image,RollImageTag,3,3);
01238 roll_image->type=image->type;
01239 if (status == MagickFalse)
01240 roll_image=DestroyImage(roll_image);
01241 return(roll_image);
01242 }
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278 MagickExport Image *ShaveImage(const Image *image,
01279 const RectangleInfo *shave_info,ExceptionInfo *exception)
01280 {
01281 Image
01282 *shave_image;
01283
01284 RectangleInfo
01285 geometry;
01286
01287 assert(image != (const Image *) NULL);
01288 assert(image->signature == MagickSignature);
01289 if (image->debug != MagickFalse)
01290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01291 if (((2*shave_info->width) >= image->columns) ||
01292 ((2*shave_info->height) >= image->rows))
01293 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
01294 SetGeometry(image,&geometry);
01295 geometry.width-=2*shave_info->width;
01296 geometry.height-=2*shave_info->height;
01297 geometry.x=(long) shave_info->width+image->page.x;
01298 geometry.y=(long) shave_info->height+image->page.y;
01299 shave_image=CropImage(image,&geometry,exception);
01300 if (shave_image == (Image *) NULL)
01301 return((Image *) NULL);
01302 shave_image->page.width-=2*shave_info->width;
01303 shave_image->page.height-=2*shave_info->height;
01304 shave_image->page.x-=shave_info->width;
01305 shave_image->page.y-=shave_info->height;
01306 return(shave_image);
01307 }
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338 MagickExport Image *SpliceImage(const Image *image,
01339 const RectangleInfo *geometry,ExceptionInfo *exception)
01340 {
01341 #define SpliceImageTag "Splice/Image"
01342
01343 CacheView
01344 *image_view,
01345 *splice_view;
01346
01347 Image
01348 *splice_image;
01349
01350 long
01351 progress,
01352 y;
01353
01354 MagickBooleanType
01355 proceed,
01356 status;
01357
01358 RectangleInfo
01359 splice_geometry;
01360
01361 register long
01362 i;
01363
01364
01365
01366
01367 assert(image != (const Image *) NULL);
01368 assert(image->signature == MagickSignature);
01369 if (image->debug != MagickFalse)
01370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01371 assert(geometry != (const RectangleInfo *) NULL);
01372 assert(exception != (ExceptionInfo *) NULL);
01373 assert(exception->signature == MagickSignature);
01374 splice_geometry=(*geometry);
01375 splice_image=CloneImage(image,image->columns+splice_geometry.width,
01376 image->rows+splice_geometry.height,MagickTrue,exception);
01377 if (splice_image == (Image *) NULL)
01378 return((Image *) NULL);
01379 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
01380 {
01381 InheritException(exception,&splice_image->exception);
01382 splice_image=DestroyImage(splice_image);
01383 return((Image *) NULL);
01384 }
01385 (void) SetImageBackgroundColor(splice_image);
01386
01387
01388
01389 switch (image->gravity)
01390 {
01391 default:
01392 case UndefinedGravity:
01393 case NorthWestGravity:
01394 break;
01395 case NorthGravity:
01396 {
01397 splice_geometry.x+=splice_geometry.width/2;
01398 break;
01399 }
01400 case NorthEastGravity:
01401 {
01402 splice_geometry.x+=splice_geometry.width;
01403 break;
01404 }
01405 case WestGravity:
01406 {
01407 splice_geometry.y+=splice_geometry.width/2;
01408 break;
01409 }
01410 case StaticGravity:
01411 case CenterGravity:
01412 {
01413 splice_geometry.x+=splice_geometry.width/2;
01414 splice_geometry.y+=splice_geometry.height/2;
01415 break;
01416 }
01417 case EastGravity:
01418 {
01419 splice_geometry.x+=splice_geometry.width;
01420 splice_geometry.y+=splice_geometry.height/2;
01421 break;
01422 }
01423 case SouthWestGravity:
01424 {
01425 splice_geometry.y+=splice_geometry.height;
01426 break;
01427 }
01428 case SouthGravity:
01429 {
01430 splice_geometry.x+=splice_geometry.width/2;
01431 splice_geometry.y+=splice_geometry.height;
01432 break;
01433 }
01434 case SouthEastGravity:
01435 {
01436 splice_geometry.x+=splice_geometry.width;
01437 splice_geometry.y+=splice_geometry.height;
01438 break;
01439 }
01440 }
01441
01442
01443
01444 status=MagickTrue;
01445 i=0;
01446 progress=0;
01447 image_view=AcquireCacheView(image);
01448 splice_view=AcquireCacheView(splice_image);
01449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01450 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01451 #endif
01452 for (y=0; y < (long) splice_geometry.y; y++)
01453 {
01454 register const PixelPacket
01455 *restrict p;
01456
01457 register IndexPacket
01458 *restrict indexes,
01459 *restrict splice_indexes;
01460
01461 register long
01462 x;
01463
01464 register PixelPacket
01465 *restrict q;
01466
01467 if (status == MagickFalse)
01468 continue;
01469 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
01470 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
01471 exception);
01472 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01473 {
01474 status=MagickFalse;
01475 continue;
01476 }
01477 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01478 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
01479 for (x=0; x < splice_geometry.x; x++)
01480 {
01481 SetRedPixelComponent(q,GetRedPixelComponent(p));
01482 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
01483 SetBluePixelComponent(q,GetBluePixelComponent(p));
01484 SetOpacityPixelComponent(q,OpaqueOpacity);
01485 if (image->matte != MagickFalse)
01486 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
01487 if (image->colorspace == CMYKColorspace)
01488 splice_indexes[x]=(*indexes++);
01489 p++;
01490 q++;
01491 }
01492 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
01493 q++;
01494 for ( ; x < (long) splice_image->columns; x++)
01495 {
01496 SetRedPixelComponent(q,GetRedPixelComponent(p));
01497 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
01498 SetBluePixelComponent(q,GetBluePixelComponent(p));
01499 SetOpacityPixelComponent(q,OpaqueOpacity);
01500 if (image->matte != MagickFalse)
01501 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
01502 if (image->colorspace == CMYKColorspace)
01503 splice_indexes[x]=(*indexes++);
01504 p++;
01505 q++;
01506 }
01507 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
01508 status=MagickFalse;
01509 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
01510 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01511 {
01512 MagickBooleanType
01513 proceed;
01514
01515 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01516 #pragma omp critical (MagickCore_TransposeImage)
01517 #endif
01518 proceed=SetImageProgress(image,SpliceImageTag,progress++,
01519 splice_image->rows);
01520 if (proceed == MagickFalse)
01521 status=MagickFalse;
01522 }
01523 }
01524 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01525 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01526 #endif
01527 for (y=(long) (splice_geometry.y+splice_geometry.height);
01528 y < (long) splice_image->rows; y++)
01529 {
01530 register const PixelPacket
01531 *restrict p;
01532
01533 register IndexPacket
01534 *restrict indexes,
01535 *restrict splice_indexes;
01536
01537 register long
01538 x;
01539
01540 register PixelPacket
01541 *restrict q;
01542
01543 if (status == MagickFalse)
01544 continue;
01545 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
01546 image->columns,1,exception);
01547 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
01548 exception);
01549 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01550 {
01551 status=MagickFalse;
01552 continue;
01553 }
01554 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01555 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
01556 for (x=0; x < splice_geometry.x; x++)
01557 {
01558 SetRedPixelComponent(q,GetRedPixelComponent(p));
01559 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
01560 SetBluePixelComponent(q,GetBluePixelComponent(p));
01561 SetOpacityPixelComponent(q,OpaqueOpacity);
01562 if (image->matte != MagickFalse)
01563 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
01564 if (image->colorspace == CMYKColorspace)
01565 splice_indexes[x]=(*indexes++);
01566 p++;
01567 q++;
01568 }
01569 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
01570 q++;
01571 for ( ; x < (long) splice_image->columns; x++)
01572 {
01573 SetRedPixelComponent(q,GetRedPixelComponent(p));
01574 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
01575 SetBluePixelComponent(q,GetBluePixelComponent(p));
01576 SetOpacityPixelComponent(q,OpaqueOpacity);
01577 if (image->matte != MagickFalse)
01578 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
01579 if (image->colorspace == CMYKColorspace)
01580 splice_indexes[x]=(*indexes++);
01581 p++;
01582 q++;
01583 }
01584 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
01585 status=MagickFalse;
01586 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01587 {
01588 MagickBooleanType
01589 proceed;
01590
01591 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01592 #pragma omp critical (MagickCore_TransposeImage)
01593 #endif
01594 proceed=SetImageProgress(image,SpliceImageTag,progress++,
01595 splice_image->rows);
01596 if (proceed == MagickFalse)
01597 status=MagickFalse;
01598 }
01599 }
01600 splice_view=DestroyCacheView(splice_view);
01601 image_view=DestroyCacheView(image_view);
01602 if (status == MagickFalse)
01603 splice_image=DestroyImage(splice_image);
01604 return(splice_image);
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639 static inline long MagickRound(MagickRealType x)
01640 {
01641
01642
01643
01644 if (x >= 0.0)
01645 return((long) (x+0.5));
01646 return((long) (x-0.5));
01647 }
01648
01649 MagickExport MagickBooleanType TransformImage(Image **image,
01650 const char *crop_geometry,const char *image_geometry)
01651 {
01652 Image
01653 *next,
01654 *resize_image,
01655 *transform_image;
01656
01657 long
01658 x,
01659 y;
01660
01661 MagickStatusType
01662 flags;
01663
01664 RectangleInfo
01665 geometry;
01666
01667 unsigned long
01668 height,
01669 width;
01670
01671 assert(image != (Image **) NULL);
01672 assert((*image)->signature == MagickSignature);
01673 if ((*image)->debug != MagickFalse)
01674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
01675 transform_image=(*image);
01676 if (crop_geometry != (const char *) NULL)
01677 {
01678 Image
01679 *crop_image;
01680
01681 RectangleInfo
01682 geometry;
01683
01684
01685
01686
01687 crop_image=NewImageList();
01688 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
01689 &(*image)->exception);
01690 if ((flags & AreaValue) != 0)
01691 {
01692 PointInfo
01693 delta,
01694 offset;
01695
01696 RectangleInfo
01697 crop;
01698
01699
01700
01701
01702 if (geometry.width == 0)
01703 geometry.width=1;
01704 if (geometry.height == 0)
01705 geometry.height=1;
01706 width=transform_image->columns;
01707 height=transform_image->rows;
01708 if ((flags & AspectValue) == 0)
01709 {
01710 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
01711 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
01712 }
01713 else
01714 {
01715 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
01716 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
01717 }
01718 delta.x=(double) width/geometry.width;
01719 delta.y=(double) height/geometry.height;
01720 next=NewImageList();
01721 for (offset.y=0; offset.y < (double) height; )
01722 {
01723 if ((flags & AspectValue) == 0)
01724 {
01725 crop.y=(long) MagickRound((MagickRealType) (offset.y-
01726 (geometry.y > 0 ? 0 : geometry.y)));
01727 offset.y+=delta.y;
01728 crop.height=(unsigned long) MagickRound((MagickRealType)
01729 (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
01730 }
01731 else
01732 {
01733 crop.y=(long) MagickRound((MagickRealType) (offset.y-
01734 (geometry.y > 0 ? geometry.y : 0)));
01735 offset.y+=delta.y;
01736 crop.height=(unsigned long) MagickRound((MagickRealType)
01737 (offset.y+(geometry.y < 0 ? geometry.y : 0)));
01738 }
01739 crop.height-=crop.y;
01740 for (offset.x=0; offset.x < (double) width; )
01741 {
01742 if ((flags & AspectValue) == 0)
01743 {
01744 crop.x=(long) MagickRound((MagickRealType) (offset.x-
01745 (geometry.x > 0 ? 0 : geometry.x)));
01746 offset.x+=+delta.x;
01747 crop.width=(unsigned long) MagickRound((MagickRealType)
01748 (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
01749 }
01750 else
01751 {
01752 crop.x=(long) MagickRound((MagickRealType) (offset.x-
01753 (geometry.x > 0 ? geometry.x : 0)));
01754 offset.x+=+delta.x;
01755 crop.width=(unsigned long) MagickRound((MagickRealType)
01756 (offset.x+(geometry.x < 0 ? geometry.x : 0)));
01757 }
01758 crop.width-=crop.x;
01759 next=CropImage(transform_image,&crop,&(*image)->exception);
01760 if (next == (Image *) NULL)
01761 break;
01762 AppendImageToList(&crop_image,next);
01763 }
01764 if (next == (Image *) NULL)
01765 break;
01766 }
01767 }
01768 else
01769 if (((geometry.width == 0) && (geometry.height == 0)) ||
01770 ((flags & XValue) != 0) || ((flags & YValue) != 0))
01771 {
01772
01773
01774
01775 crop_image=CropImage(transform_image,&geometry,
01776 &(*image)->exception);
01777 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
01778 {
01779 crop_image->page.width=geometry.width;
01780 crop_image->page.height=geometry.height;
01781 crop_image->page.x-=geometry.x;
01782 crop_image->page.y-=geometry.y;
01783 }
01784 }
01785 else
01786 if ((transform_image->columns > geometry.width) ||
01787 (transform_image->rows > geometry.height))
01788 {
01789 MagickBooleanType
01790 proceed;
01791
01792 MagickProgressMonitor
01793 progress_monitor;
01794
01795 MagickOffsetType
01796 i;
01797
01798 MagickSizeType
01799 number_images;
01800
01801
01802
01803
01804 if (transform_image->page.width == 0)
01805 transform_image->page.width=transform_image->columns;
01806 if (transform_image->page.height == 0)
01807 transform_image->page.height=transform_image->rows;
01808 width=geometry.width;
01809 if (width == 0)
01810 width=transform_image->page.width;
01811 height=geometry.height;
01812 if (height == 0)
01813 height=transform_image->page.height;
01814 next=NewImageList();
01815 proceed=MagickTrue;
01816 i=0;
01817 number_images=0;
01818 for (y=0; y < (long) transform_image->page.height; y+=height)
01819 for (x=0; x < (long) transform_image->page.width; x+=width)
01820 number_images++;
01821 for (y=0; y < (long) transform_image->page.height; y+=height)
01822 {
01823 for (x=0; x < (long) transform_image->page.width; x+=width)
01824 {
01825 progress_monitor=SetImageProgressMonitor(transform_image,
01826 (MagickProgressMonitor) NULL,transform_image->client_data);
01827 geometry.width=width;
01828 geometry.height=height;
01829 geometry.x=x;
01830 geometry.y=y;
01831 next=CropImage(transform_image,&geometry,&(*image)->exception);
01832 (void) SetImageProgressMonitor(transform_image,
01833 progress_monitor,transform_image->client_data);
01834 proceed=SetImageProgress(transform_image,CropImageTag,i++,
01835 number_images);
01836 if (proceed == MagickFalse)
01837 break;
01838 if (next == (Image *) NULL)
01839 break;
01840 (void) SetImageProgressMonitor(next,progress_monitor,
01841 next->client_data);
01842 if (crop_image == (Image *) NULL)
01843 crop_image=next;
01844 else
01845 {
01846 next->previous=crop_image;
01847 crop_image->next=next;
01848 crop_image=crop_image->next;
01849 }
01850 }
01851 if (next == (Image *) NULL)
01852 break;
01853 if (proceed == MagickFalse)
01854 break;
01855 }
01856 }
01857 if (crop_image == (Image *) NULL)
01858 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
01859 else
01860 {
01861 transform_image=DestroyImage(transform_image);
01862 transform_image=GetFirstImageInList(crop_image);
01863 }
01864 *image=transform_image;
01865 }
01866 if (image_geometry == (const char *) NULL)
01867 return(MagickTrue);
01868
01869
01870
01871 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
01872 &(*image)->exception);
01873 if ((transform_image->columns == geometry.width) &&
01874 (transform_image->rows == geometry.height))
01875 return(MagickTrue);
01876 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
01877 &(*image)->exception);
01878 if (resize_image == (Image *) NULL)
01879 return(MagickFalse);
01880 transform_image=DestroyImage(transform_image);
01881 transform_image=resize_image;
01882 *image=transform_image;
01883 return(MagickTrue);
01884 }
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 MagickExport MagickBooleanType TransformImages(Image **images,
01915 const char *crop_geometry,const char *image_geometry)
01916 {
01917 Image
01918 *image,
01919 **image_list,
01920 *transform_images;
01921
01922 MagickStatusType
01923 status;
01924
01925 register long
01926 i;
01927
01928 assert(images != (Image **) NULL);
01929 assert((*images)->signature == MagickSignature);
01930 if ((*images)->debug != MagickFalse)
01931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01932 (*images)->filename);
01933 image_list=ImageListToArray(*images,&(*images)->exception);
01934 if (image_list == (Image **) NULL)
01935 return(MagickFalse);
01936 status=MagickTrue;
01937 transform_images=NewImageList();
01938 for (i=0; image_list[i] != (Image *) NULL; i++)
01939 {
01940 image=image_list[i];
01941 status|=TransformImage(&image,crop_geometry,image_geometry);
01942 AppendImageToList(&transform_images,image);
01943 }
01944 *images=transform_images;
01945 image_list=(Image **) RelinquishMagickMemory(image_list);
01946 return(status != 0 ? MagickTrue : MagickFalse);
01947 }
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
01975 {
01976 #define TransposeImageTag "Transpose/Image"
01977
01978 CacheView
01979 *image_view,
01980 *transpose_view;
01981
01982 Image
01983 *transpose_image;
01984
01985 long
01986 progress,
01987 y;
01988
01989 MagickBooleanType
01990 status;
01991
01992 RectangleInfo
01993 page;
01994
01995 assert(image != (const Image *) NULL);
01996 assert(image->signature == MagickSignature);
01997 if (image->debug != MagickFalse)
01998 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01999 assert(exception != (ExceptionInfo *) NULL);
02000 assert(exception->signature == MagickSignature);
02001 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
02002 exception);
02003 if (transpose_image == (Image *) NULL)
02004 return((Image *) NULL);
02005
02006
02007
02008 status=MagickTrue;
02009 progress=0;
02010 image_view=AcquireCacheView(image);
02011 transpose_view=AcquireCacheView(transpose_image);
02012 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02013 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
02014 #endif
02015 for (y=0; y < (long) image->rows; y++)
02016 {
02017 register const PixelPacket
02018 *restrict p;
02019
02020 register IndexPacket
02021 *restrict transpose_indexes,
02022 *restrict indexes;
02023
02024 register PixelPacket
02025 *restrict q;
02026
02027 if (status == MagickFalse)
02028 continue;
02029 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
02030 image->columns,1,exception);
02031 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
02032 1,transpose_image->rows,exception);
02033 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
02034 {
02035 status=MagickFalse;
02036 continue;
02037 }
02038 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
02039 indexes=GetCacheViewAuthenticIndexQueue(image_view);
02040 if (indexes != (IndexPacket *) NULL)
02041 {
02042 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
02043 if (transpose_indexes != (IndexPacket *) NULL)
02044 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
02045 image->columns*sizeof(*transpose_indexes));
02046 }
02047 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
02048 status=MagickFalse;
02049 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02050 {
02051 MagickBooleanType
02052 proceed;
02053
02054 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02055 #pragma omp critical (MagickCore_TransposeImage)
02056 #endif
02057 proceed=SetImageProgress(image,TransposeImageTag,progress++,
02058 image->rows);
02059 if (proceed == MagickFalse)
02060 status=MagickFalse;
02061 }
02062 }
02063 transpose_view=DestroyCacheView(transpose_view);
02064 image_view=DestroyCacheView(image_view);
02065 transpose_image->type=image->type;
02066 page=transpose_image->page;
02067 Swap(page.width,page.height);
02068 Swap(page.x,page.y);
02069 if (page.width != 0)
02070 page.x=(long) (page.width-transpose_image->columns-page.x);
02071 transpose_image->page=page;
02072 if (status == MagickFalse)
02073 transpose_image=DestroyImage(transpose_image);
02074 return(transpose_image);
02075 }
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
02103 {
02104 #define TransverseImageTag "Transverse/Image"
02105
02106 CacheView
02107 *image_view,
02108 *transverse_view;
02109
02110 Image
02111 *transverse_image;
02112
02113 long
02114 progress,
02115 y;
02116
02117 MagickBooleanType
02118 status;
02119
02120 RectangleInfo
02121 page;
02122
02123 assert(image != (const Image *) NULL);
02124 assert(image->signature == MagickSignature);
02125 if (image->debug != MagickFalse)
02126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02127 assert(exception != (ExceptionInfo *) NULL);
02128 assert(exception->signature == MagickSignature);
02129 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
02130 exception);
02131 if (transverse_image == (Image *) NULL)
02132 return((Image *) NULL);
02133
02134
02135
02136 status=MagickTrue;
02137 progress=0;
02138 image_view=AcquireCacheView(image);
02139 transverse_view=AcquireCacheView(transverse_image);
02140 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02141 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
02142 #endif
02143 for (y=0; y < (long) image->rows; y++)
02144 {
02145 MagickBooleanType
02146 sync;
02147
02148 register const PixelPacket
02149 *restrict p;
02150
02151 register IndexPacket
02152 *restrict transverse_indexes,
02153 *restrict indexes;
02154
02155 register long
02156 x;
02157
02158 register PixelPacket
02159 *restrict q;
02160
02161 if (status == MagickFalse)
02162 continue;
02163 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
02164 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
02165 1),0,1,transverse_image->rows,exception);
02166 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
02167 {
02168 status=MagickFalse;
02169 continue;
02170 }
02171 q+=image->columns;
02172 for (x=0; x < (long) image->columns; x++)
02173 *--q=(*p++);
02174 indexes=GetCacheViewAuthenticIndexQueue(image_view);
02175 if (indexes != (IndexPacket *) NULL)
02176 {
02177 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
02178 if (transverse_indexes != (IndexPacket *) NULL)
02179 for (x=0; x < (long) image->columns; x++)
02180 transverse_indexes[image->columns-x-1]=indexes[x];
02181 }
02182 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
02183 if (sync == MagickFalse)
02184 status=MagickFalse;
02185 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02186 {
02187 MagickBooleanType
02188 proceed;
02189
02190 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02191 #pragma omp critical (MagickCore_TransverseImage)
02192 #endif
02193 proceed=SetImageProgress(image,TransverseImageTag,progress++,
02194 image->rows);
02195 if (proceed == MagickFalse)
02196 status=MagickFalse;
02197 }
02198 }
02199 transverse_view=DestroyCacheView(transverse_view);
02200 image_view=DestroyCacheView(image_view);
02201 transverse_image->type=image->type;
02202 page=transverse_image->page;
02203 Swap(page.width,page.height);
02204 Swap(page.x,page.y);
02205 if (page.height != 0)
02206 page.y=(long) (page.height-transverse_image->rows-page.y);
02207 transverse_image->page=page;
02208 if (status == MagickFalse)
02209 transverse_image=DestroyImage(transverse_image);
02210 return(transverse_image);
02211 }
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
02240 {
02241 RectangleInfo
02242 geometry;
02243
02244 assert(image != (const Image *) NULL);
02245 assert(image->signature == MagickSignature);
02246 if (image->debug != MagickFalse)
02247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02248 geometry=GetImageBoundingBox(image,exception);
02249 if ((geometry.width == 0) || (geometry.height == 0))
02250 {
02251 Image
02252 *crop_image;
02253
02254 crop_image=CloneImage(image,1,1,MagickTrue,exception);
02255 if (crop_image == (Image *) NULL)
02256 return((Image *) NULL);
02257 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
02258 (void) SetImageBackgroundColor(crop_image);
02259 crop_image->page=image->page;
02260 crop_image->page.x=(-1);
02261 crop_image->page.y=(-1);
02262 return(crop_image);
02263 }
02264 geometry.x+=image->page.x;
02265 geometry.y+=image->page.y;
02266 return(CropImage(image,&geometry,exception));
02267 }