|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M % 00007 % T R R A A NN N SS F O O R R MM MM % 00008 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M % 00009 % T R R A A N NN SS F O O R R M M % 00010 % T R R A A N N SSSSS F OOO R R M M % 00011 % % 00012 % % 00013 % MagickCore Image Transform Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % July 1992 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "MagickCore/studio.h" 00043 #include "MagickCore/attribute.h" 00044 #include "MagickCore/cache.h" 00045 #include "MagickCore/cache-view.h" 00046 #include "MagickCore/color.h" 00047 #include "MagickCore/color-private.h" 00048 #include "MagickCore/colorspace-private.h" 00049 #include "MagickCore/composite.h" 00050 #include "MagickCore/draw.h" 00051 #include "MagickCore/effect.h" 00052 #include "MagickCore/exception.h" 00053 #include "MagickCore/exception-private.h" 00054 #include "MagickCore/geometry.h" 00055 #include "MagickCore/image.h" 00056 #include "MagickCore/memory_.h" 00057 #include "MagickCore/layer.h" 00058 #include "MagickCore/list.h" 00059 #include "MagickCore/monitor.h" 00060 #include "MagickCore/monitor-private.h" 00061 #include "MagickCore/pixel-accessor.h" 00062 #include "MagickCore/resource_.h" 00063 #include "MagickCore/resize.h" 00064 #include "MagickCore/statistic.h" 00065 #include "MagickCore/string_.h" 00066 #include "MagickCore/thread-private.h" 00067 #include "MagickCore/transform.h" 00068 00069 /* 00070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00071 % % 00072 % % 00073 % % 00074 % C h o p I m a g e % 00075 % % 00076 % % 00077 % % 00078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00079 % 00080 % ChopImage() removes a region of an image and collapses the image to occupy 00081 % the removed portion. 00082 % 00083 % The format of the ChopImage method is: 00084 % 00085 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info) 00086 % ExceptionInfo *exception) 00087 % 00088 % A description of each parameter follows: 00089 % 00090 % o image: the image. 00091 % 00092 % o chop_info: Define the region of the image to chop. 00093 % 00094 % o exception: return any errors or warnings in this structure. 00095 % 00096 */ 00097 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info, 00098 ExceptionInfo *exception) 00099 { 00100 #define ChopImageTag "Chop/Image" 00101 00102 CacheView 00103 *chop_view, 00104 *image_view; 00105 00106 Image 00107 *chop_image; 00108 00109 MagickBooleanType 00110 status; 00111 00112 MagickOffsetType 00113 progress; 00114 00115 RectangleInfo 00116 extent; 00117 00118 ssize_t 00119 y; 00120 00121 /* 00122 Check chop geometry. 00123 */ 00124 assert(image != (const Image *) NULL); 00125 assert(image->signature == MagickSignature); 00126 if (image->debug != MagickFalse) 00127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00128 assert(exception != (ExceptionInfo *) NULL); 00129 assert(exception->signature == MagickSignature); 00130 assert(chop_info != (RectangleInfo *) NULL); 00131 if (((chop_info->x+(ssize_t) chop_info->width) < 0) || 00132 ((chop_info->y+(ssize_t) chop_info->height) < 0) || 00133 (chop_info->x > (ssize_t) image->columns) || 00134 (chop_info->y > (ssize_t) image->rows)) 00135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage"); 00136 extent=(*chop_info); 00137 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns) 00138 extent.width=(size_t) ((ssize_t) image->columns-extent.x); 00139 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows) 00140 extent.height=(size_t) ((ssize_t) image->rows-extent.y); 00141 if (extent.x < 0) 00142 { 00143 extent.width-=(size_t) (-extent.x); 00144 extent.x=0; 00145 } 00146 if (extent.y < 0) 00147 { 00148 extent.height-=(size_t) (-extent.y); 00149 extent.y=0; 00150 } 00151 chop_image=CloneImage(image,image->columns-extent.width,image->rows- 00152 extent.height,MagickTrue,exception); 00153 if (chop_image == (Image *) NULL) 00154 return((Image *) NULL); 00155 /* 00156 Extract chop image. 00157 */ 00158 status=MagickTrue; 00159 progress=0; 00160 image_view=AcquireCacheView(image); 00161 chop_view=AcquireCacheView(chop_image); 00162 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00163 #pragma omp parallel for schedule(static) shared(progress,status) 00164 #endif 00165 for (y=0; y < (ssize_t) extent.y; y++) 00166 { 00167 register const Quantum 00168 *restrict p; 00169 00170 register ssize_t 00171 x; 00172 00173 register Quantum 00174 *restrict q; 00175 00176 if (status == MagickFalse) 00177 continue; 00178 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 00179 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1, 00180 exception); 00181 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00182 { 00183 status=MagickFalse; 00184 continue; 00185 } 00186 for (x=0; x < (ssize_t) image->columns; x++) 00187 { 00188 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width))) 00189 { 00190 register ssize_t 00191 i; 00192 00193 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00194 { 00195 PixelChannel 00196 channel; 00197 00198 PixelTrait 00199 chop_traits, 00200 traits; 00201 00202 channel=GetPixelChannelMapChannel(image,i); 00203 traits=GetPixelChannelMapTraits(image,channel); 00204 chop_traits=GetPixelChannelMapTraits(chop_image,channel); 00205 if ((traits == UndefinedPixelTrait) || 00206 (chop_traits == UndefinedPixelTrait)) 00207 continue; 00208 SetPixelChannel(chop_image,channel,p[i],q); 00209 } 00210 q+=GetPixelChannels(chop_image); 00211 } 00212 p+=GetPixelChannels(image); 00213 } 00214 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse) 00215 status=MagickFalse; 00216 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00217 { 00218 MagickBooleanType 00219 proceed; 00220 00221 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00222 #pragma omp critical (MagickCore_ChopImage) 00223 #endif 00224 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows); 00225 if (proceed == MagickFalse) 00226 status=MagickFalse; 00227 } 00228 } 00229 /* 00230 Extract chop image. 00231 */ 00232 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00233 #pragma omp parallel for schedule(static) shared(progress,status) 00234 #endif 00235 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++) 00236 { 00237 register const Quantum 00238 *restrict p; 00239 00240 register ssize_t 00241 x; 00242 00243 register Quantum 00244 *restrict q; 00245 00246 if (status == MagickFalse) 00247 continue; 00248 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y, 00249 image->columns,1,exception); 00250 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns, 00251 1,exception); 00252 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00253 { 00254 status=MagickFalse; 00255 continue; 00256 } 00257 for (x=0; x < (ssize_t) image->columns; x++) 00258 { 00259 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width))) 00260 { 00261 register ssize_t 00262 i; 00263 00264 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00265 { 00266 PixelChannel 00267 channel; 00268 00269 PixelTrait 00270 chop_traits, 00271 traits; 00272 00273 channel=GetPixelChannelMapChannel(image,i); 00274 traits=GetPixelChannelMapTraits(image,channel); 00275 chop_traits=GetPixelChannelMapTraits(chop_image,channel); 00276 if ((traits == UndefinedPixelTrait) || 00277 (chop_traits == UndefinedPixelTrait)) 00278 continue; 00279 SetPixelChannel(chop_image,channel,p[i],q); 00280 } 00281 p+=GetPixelChannels(chop_image); 00282 q+=GetPixelChannels(chop_image); 00283 } 00284 p+=GetPixelChannels(image); 00285 } 00286 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse) 00287 status=MagickFalse; 00288 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00289 { 00290 MagickBooleanType 00291 proceed; 00292 00293 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00294 #pragma omp critical (MagickCore_ChopImage) 00295 #endif 00296 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows); 00297 if (proceed == MagickFalse) 00298 status=MagickFalse; 00299 } 00300 } 00301 chop_view=DestroyCacheView(chop_view); 00302 image_view=DestroyCacheView(image_view); 00303 chop_image->type=image->type; 00304 return(chop_image); 00305 } 00306 00307 /* 00308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00309 % % 00310 % % 00311 % % 00312 + C o n s o l i d a t e C M Y K I m a g e % 00313 % % 00314 % % 00315 % % 00316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00317 % 00318 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a 00319 % single image. 00320 % 00321 % The format of the ConsolidateCMYKImage method is: 00322 % 00323 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception) 00324 % 00325 % A description of each parameter follows: 00326 % 00327 % o image: the image sequence. 00328 % 00329 % o exception: return any errors or warnings in this structure. 00330 % 00331 */ 00332 MagickExport Image *ConsolidateCMYKImages(const Image *images, 00333 ExceptionInfo *exception) 00334 { 00335 CacheView 00336 *cmyk_view, 00337 *image_view; 00338 00339 Image 00340 *cmyk_image, 00341 *cmyk_images; 00342 00343 register ssize_t 00344 j; 00345 00346 ssize_t 00347 y; 00348 00349 /* 00350 Consolidate separate C, M, Y, and K planes into a single image. 00351 */ 00352 assert(images != (Image *) NULL); 00353 assert(images->signature == MagickSignature); 00354 if (images->debug != MagickFalse) 00355 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 00356 assert(exception != (ExceptionInfo *) NULL); 00357 assert(exception->signature == MagickSignature); 00358 cmyk_images=NewImageList(); 00359 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4) 00360 { 00361 register ssize_t 00362 i; 00363 00364 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue, 00365 exception); 00366 if (cmyk_image == (Image *) NULL) 00367 break; 00368 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse) 00369 break; 00370 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception); 00371 for (i=0; i < 4; i++) 00372 { 00373 image_view=AcquireCacheView(images); 00374 cmyk_view=AcquireCacheView(cmyk_image); 00375 for (y=0; y < (ssize_t) images->rows; y++) 00376 { 00377 register const Quantum 00378 *restrict p; 00379 00380 register ssize_t 00381 x; 00382 00383 register Quantum 00384 *restrict q; 00385 00386 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception); 00387 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1, 00388 exception); 00389 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00390 break; 00391 for (x=0; x < (ssize_t) images->columns; x++) 00392 { 00393 Quantum 00394 pixel; 00395 00396 pixel=QuantumRange-GetPixelIntensity(images,p); 00397 switch (i) 00398 { 00399 case 0: SetPixelCyan(cmyk_image,pixel,q); break; 00400 case 1: SetPixelMagenta(cmyk_image,pixel,q); break; 00401 case 2: SetPixelYellow(cmyk_image,pixel,q); break; 00402 case 3: SetPixelBlack(cmyk_image,pixel,q); break; 00403 default: break; 00404 } 00405 p+=GetPixelChannels(images); 00406 q+=GetPixelChannels(cmyk_image); 00407 } 00408 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse) 00409 break; 00410 } 00411 cmyk_view=DestroyCacheView(cmyk_view); 00412 image_view=DestroyCacheView(image_view); 00413 images=GetNextImageInList(images); 00414 if (images == (Image *) NULL) 00415 break; 00416 } 00417 AppendImageToList(&cmyk_images,cmyk_image); 00418 } 00419 return(cmyk_images); 00420 } 00421 00422 /* 00423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00424 % % 00425 % % 00426 % % 00427 % C r o p I m a g e % 00428 % % 00429 % % 00430 % % 00431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00432 % 00433 % CropImage() extracts a region of the image starting at the offset defined 00434 % by geometry. Region must be fully defined, and no special handling of 00435 % geometry flags is performed. 00436 % 00437 % The format of the CropImage method is: 00438 % 00439 % Image *CropImage(const Image *image,const RectangleInfo *geometry, 00440 % ExceptionInfo *exception) 00441 % 00442 % A description of each parameter follows: 00443 % 00444 % o image: the image. 00445 % 00446 % o geometry: Define the region of the image to crop with members 00447 % x, y, width, and height. 00448 % 00449 % o exception: return any errors or warnings in this structure. 00450 % 00451 */ 00452 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry, 00453 ExceptionInfo *exception) 00454 { 00455 #define CropImageTag "Crop/Image" 00456 00457 CacheView 00458 *crop_view, 00459 *image_view; 00460 00461 Image 00462 *crop_image; 00463 00464 MagickBooleanType 00465 status; 00466 00467 MagickOffsetType 00468 progress; 00469 00470 OffsetInfo 00471 offset; 00472 00473 RectangleInfo 00474 bounding_box, 00475 page; 00476 00477 ssize_t 00478 y; 00479 00480 /* 00481 Check crop geometry. 00482 */ 00483 assert(image != (const Image *) NULL); 00484 assert(image->signature == MagickSignature); 00485 if (image->debug != MagickFalse) 00486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00487 assert(geometry != (const RectangleInfo *) NULL); 00488 assert(exception != (ExceptionInfo *) NULL); 00489 assert(exception->signature == MagickSignature); 00490 bounding_box=image->page; 00491 if ((bounding_box.width == 0) || (bounding_box.height == 0)) 00492 { 00493 bounding_box.width=image->columns; 00494 bounding_box.height=image->rows; 00495 } 00496 page=(*geometry); 00497 if (page.width == 0) 00498 page.width=bounding_box.width; 00499 if (page.height == 0) 00500 page.height=bounding_box.height; 00501 if (((bounding_box.x-page.x) >= (ssize_t) page.width) || 00502 ((bounding_box.y-page.y) >= (ssize_t) page.height) || 00503 ((page.x-bounding_box.x) > (ssize_t) image->columns) || 00504 ((page.y-bounding_box.y) > (ssize_t) image->rows)) 00505 { 00506 /* 00507 Crop is not within virtual canvas, return 1 pixel transparent image. 00508 */ 00509 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 00510 "GeometryDoesNotContainImage","`%s'",image->filename); 00511 crop_image=CloneImage(image,1,1,MagickTrue,exception); 00512 if (crop_image == (Image *) NULL) 00513 return((Image *) NULL); 00514 crop_image->background_color.alpha=(Quantum) TransparentAlpha; 00515 (void) SetImageBackgroundColor(crop_image,exception); 00516 crop_image->page=bounding_box; 00517 crop_image->page.x=(-1); 00518 crop_image->page.y=(-1); 00519 if (crop_image->dispose == BackgroundDispose) 00520 crop_image->dispose=NoneDispose; 00521 return(crop_image); 00522 } 00523 if ((page.x < 0) && (bounding_box.x >= 0)) 00524 { 00525 page.width+=page.x-bounding_box.x; 00526 page.x=0; 00527 } 00528 else 00529 { 00530 page.width-=bounding_box.x-page.x; 00531 page.x-=bounding_box.x; 00532 if (page.x < 0) 00533 page.x=0; 00534 } 00535 if ((page.y < 0) && (bounding_box.y >= 0)) 00536 { 00537 page.height+=page.y-bounding_box.y; 00538 page.y=0; 00539 } 00540 else 00541 { 00542 page.height-=bounding_box.y-page.y; 00543 page.y-=bounding_box.y; 00544 if (page.y < 0) 00545 page.y=0; 00546 } 00547 if ((size_t) (page.x+page.width) > image->columns) 00548 page.width=image->columns-page.x; 00549 if ((geometry->width != 0) && (page.width > geometry->width)) 00550 page.width=geometry->width; 00551 if ((size_t) (page.y+page.height) > image->rows) 00552 page.height=image->rows-page.y; 00553 if ((geometry->height != 0) && (page.height > geometry->height)) 00554 page.height=geometry->height; 00555 bounding_box.x+=page.x; 00556 bounding_box.y+=page.y; 00557 if ((page.width == 0) || (page.height == 0)) 00558 { 00559 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 00560 "GeometryDoesNotContainImage","`%s'",image->filename); 00561 return((Image *) NULL); 00562 } 00563 /* 00564 Initialize crop image attributes. 00565 */ 00566 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception); 00567 if (crop_image == (Image *) NULL) 00568 return((Image *) NULL); 00569 crop_image->page.width=image->page.width; 00570 crop_image->page.height=image->page.height; 00571 offset.x=(ssize_t) (bounding_box.x+bounding_box.width); 00572 offset.y=(ssize_t) (bounding_box.y+bounding_box.height); 00573 if ((offset.x > (ssize_t) image->page.width) || 00574 (offset.y > (ssize_t) image->page.height)) 00575 { 00576 crop_image->page.width=bounding_box.width; 00577 crop_image->page.height=bounding_box.height; 00578 } 00579 crop_image->page.x=bounding_box.x; 00580 crop_image->page.y=bounding_box.y; 00581 /* 00582 Crop image. 00583 */ 00584 status=MagickTrue; 00585 progress=0; 00586 image_view=AcquireCacheView(image); 00587 crop_view=AcquireCacheView(crop_image); 00588 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00589 #pragma omp parallel for schedule(static) shared(progress,status) 00590 #endif 00591 for (y=0; y < (ssize_t) crop_image->rows; y++) 00592 { 00593 register const Quantum 00594 *restrict p; 00595 00596 register Quantum 00597 *restrict q; 00598 00599 register ssize_t 00600 x; 00601 00602 if (status == MagickFalse) 00603 continue; 00604 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns, 00605 1,exception); 00606 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1, 00607 exception); 00608 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00609 { 00610 status=MagickFalse; 00611 continue; 00612 } 00613 for (x=0; x < (ssize_t) crop_image->columns; x++) 00614 { 00615 register ssize_t 00616 i; 00617 00618 if (GetPixelMask(image,p) != 0) 00619 { 00620 p+=GetPixelChannels(image); 00621 q+=GetPixelChannels(crop_image); 00622 continue; 00623 } 00624 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00625 { 00626 PixelChannel 00627 channel; 00628 00629 PixelTrait 00630 crop_traits, 00631 traits; 00632 00633 channel=GetPixelChannelMapChannel(image,i); 00634 traits=GetPixelChannelMapTraits(image,channel); 00635 crop_traits=GetPixelChannelMapTraits(crop_image,channel); 00636 if ((traits == UndefinedPixelTrait) || 00637 (crop_traits == UndefinedPixelTrait)) 00638 continue; 00639 SetPixelChannel(crop_image,channel,p[i],q); 00640 } 00641 p+=GetPixelChannels(image); 00642 q+=GetPixelChannels(crop_image); 00643 } 00644 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse) 00645 status=MagickFalse; 00646 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00647 { 00648 MagickBooleanType 00649 proceed; 00650 00651 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00652 #pragma omp critical (MagickCore_CropImage) 00653 #endif 00654 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows); 00655 if (proceed == MagickFalse) 00656 status=MagickFalse; 00657 } 00658 } 00659 crop_view=DestroyCacheView(crop_view); 00660 image_view=DestroyCacheView(image_view); 00661 crop_image->type=image->type; 00662 if (status == MagickFalse) 00663 crop_image=DestroyImage(crop_image); 00664 return(crop_image); 00665 } 00666 00667 /* 00668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00669 % % 00670 % % 00671 % % 00672 % C r o p I m a g e T o T i l e s % 00673 % % 00674 % % 00675 % % 00676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00677 % 00678 % CropImageToTiles() crops a single image, into a possible list of tiles. 00679 % This may include a single sub-region of the image. This basically applies 00680 % all the normal geometry flags for Crop. 00681 % 00682 % Image *CropImageToTiles(const Image *image, 00683 % const RectangleInfo *crop_geometry, ExceptionInfo *exception) 00684 % 00685 % A description of each parameter follows: 00686 % 00687 % o image: the image The transformed image is returned as this parameter. 00688 % 00689 % o crop_geometry: A crop geometry string. 00690 % 00691 % o exception: return any errors or warnings in this structure. 00692 % 00693 */ 00694 00695 static inline ssize_t MagickRound(MagickRealType x) 00696 { 00697 /* 00698 Round the fraction to nearest integer. 00699 */ 00700 if (x >= 0.0) 00701 return((ssize_t) (x+0.5)); 00702 return((ssize_t) (x-0.5)); 00703 } 00704 00705 MagickExport Image *CropImageToTiles(const Image *image, 00706 const char *crop_geometry, ExceptionInfo *exception) 00707 { 00708 Image 00709 *next, 00710 *crop_image; 00711 00712 MagickStatusType 00713 flags; 00714 00715 RectangleInfo 00716 geometry; 00717 00718 assert(image != (Image *) NULL); 00719 assert(image->signature == MagickSignature); 00720 if (image->debug != MagickFalse) 00721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00722 crop_image=NewImageList(); 00723 next=NewImageList(); 00724 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception); 00725 if ((flags & AreaValue) != 0) 00726 { 00727 PointInfo 00728 delta, 00729 offset; 00730 00731 RectangleInfo 00732 crop; 00733 00734 size_t 00735 height, 00736 width; 00737 00738 /* 00739 Crop into NxM tiles (@ flag). 00740 */ 00741 width=image->columns; 00742 height=image->rows; 00743 if (geometry.width == 0) 00744 geometry.width=1; 00745 if (geometry.height == 0) 00746 geometry.height=1; 00747 if ((flags & AspectValue) == 0) 00748 { 00749 width-=(geometry.x < 0 ? -1 : 1)*geometry.x; 00750 height-=(geometry.y < 0 ? -1 : 1)*geometry.y; 00751 } 00752 else 00753 { 00754 width+=(geometry.x < 0 ? -1 : 1)*geometry.x; 00755 height+=(geometry.y < 0 ? -1 : 1)*geometry.y; 00756 } 00757 delta.x=(double) width/geometry.width; 00758 delta.y=(double) height/geometry.height; 00759 if ( delta.x < 1.0 ) delta.x = 1.0; 00760 if ( delta.y < 1.0 ) delta.y = 1.0; 00761 for (offset.y=0; offset.y < (double) height; ) 00762 { 00763 if ((flags & AspectValue) == 0) 00764 { 00765 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- 00766 (geometry.y > 0 ? 0 : geometry.y))); 00767 offset.y+=delta.y; /* increment now to find width */ 00768 crop.height=(size_t) MagickRound((MagickRealType) (offset.y+ 00769 (geometry.y < 0 ? 0 : geometry.y))); 00770 } 00771 else 00772 { 00773 crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y- 00774 (geometry.y > 0 ? geometry.y : 0))); 00775 offset.y+=delta.y; /* increment now to find width */ 00776 crop.height=(size_t) MagickRound((MagickRealType) 00777 (offset.y+(geometry.y < -1 ? geometry.y : 0))); 00778 } 00779 crop.height-=crop.y; 00780 crop.y+=image->page.y; 00781 for (offset.x=0; offset.x < (double) width; ) 00782 { 00783 if ((flags & AspectValue) == 0) 00784 { 00785 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- 00786 (geometry.x > 0 ? 0 : geometry.x))); 00787 offset.x+=delta.x; /* increment now to find height */ 00788 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+ 00789 (geometry.x < 0 ? 0 : geometry.x))); 00790 } 00791 else 00792 { 00793 crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x- 00794 (geometry.x > 0 ? geometry.x : 0))); 00795 offset.x+=delta.x; /* increment now to find height */ 00796 crop.width=(size_t) MagickRound((MagickRealType) (offset.x+ 00797 (geometry.x < 0 ? geometry.x : 0))); 00798 } 00799 crop.width-=crop.x; 00800 crop.x+=image->page.x; 00801 next=CropImage(image,&crop,exception); 00802 if (next == (Image *) NULL) 00803 break; 00804 AppendImageToList(&crop_image,next); 00805 } 00806 if (next == (Image *) NULL) 00807 break; 00808 } 00809 ClearMagickException(exception); 00810 return(crop_image); 00811 } 00812 00813 if (((geometry.width == 0) && (geometry.height == 0)) || 00814 ((flags & XValue) != 0) || ((flags & YValue) != 0)) 00815 { 00816 /* 00817 Crop a single region at +X+Y. 00818 */ 00819 crop_image=CropImage(image,&geometry,exception); 00820 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0)) 00821 { 00822 crop_image->page.width=geometry.width; 00823 crop_image->page.height=geometry.height; 00824 crop_image->page.x-=geometry.x; 00825 crop_image->page.y-=geometry.y; 00826 } 00827 return(crop_image); 00828 } 00829 if ((image->columns > geometry.width) || (image->rows > geometry.height)) 00830 { 00831 RectangleInfo 00832 page; 00833 00834 size_t 00835 height, 00836 width; 00837 00838 ssize_t 00839 x, 00840 y; 00841 00842 /* 00843 Crop into tiles of fixed size WxH. 00844 */ 00845 page=image->page; 00846 if (page.width == 0) 00847 page.width=image->columns; 00848 if (page.height == 0) 00849 page.height=image->rows; 00850 width=geometry.width; 00851 if (width == 0) 00852 width=page.width; 00853 height=geometry.height; 00854 if (height == 0) 00855 height=page.height; 00856 next=NewImageList(); 00857 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height) 00858 { 00859 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width) 00860 { 00861 geometry.width=width; 00862 geometry.height=height; 00863 geometry.x=x; 00864 geometry.y=y; 00865 next=CropImage(image,&geometry,exception); 00866 if (next == (Image *) NULL) 00867 break; 00868 AppendImageToList(&crop_image,next); 00869 } 00870 if (next == (Image *) NULL) 00871 break; 00872 } 00873 return(crop_image); 00874 } 00875 return(CloneImage(image,0,0,MagickTrue,exception)); 00876 } 00877 00878 /* 00879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00880 % % 00881 % % 00882 % % 00883 % E x c e r p t I m a g e % 00884 % % 00885 % % 00886 % % 00887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00888 % 00889 % ExcerptImage() returns a excerpt of the image as defined by the geometry. 00890 % 00891 % The format of the ExcerptImage method is: 00892 % 00893 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry, 00894 % ExceptionInfo *exception) 00895 % 00896 % A description of each parameter follows: 00897 % 00898 % o image: the image. 00899 % 00900 % o geometry: Define the region of the image to extend with members 00901 % x, y, width, and height. 00902 % 00903 % o exception: return any errors or warnings in this structure. 00904 % 00905 */ 00906 MagickExport Image *ExcerptImage(const Image *image, 00907 const RectangleInfo *geometry,ExceptionInfo *exception) 00908 { 00909 #define ExcerptImageTag "Excerpt/Image" 00910 00911 CacheView 00912 *excerpt_view, 00913 *image_view; 00914 00915 Image 00916 *excerpt_image; 00917 00918 MagickBooleanType 00919 status; 00920 00921 MagickOffsetType 00922 progress; 00923 00924 ssize_t 00925 y; 00926 00927 /* 00928 Allocate excerpt image. 00929 */ 00930 assert(image != (const Image *) NULL); 00931 assert(image->signature == MagickSignature); 00932 if (image->debug != MagickFalse) 00933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00934 assert(geometry != (const RectangleInfo *) NULL); 00935 assert(exception != (ExceptionInfo *) NULL); 00936 assert(exception->signature == MagickSignature); 00937 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue, 00938 exception); 00939 if (excerpt_image == (Image *) NULL) 00940 return((Image *) NULL); 00941 /* 00942 Excerpt each row. 00943 */ 00944 status=MagickTrue; 00945 progress=0; 00946 image_view=AcquireCacheView(image); 00947 excerpt_view=AcquireCacheView(excerpt_image); 00948 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00949 #pragma omp parallel for schedule(static,4) shared(progress,status) 00950 #endif 00951 for (y=0; y < (ssize_t) excerpt_image->rows; y++) 00952 { 00953 register const Quantum 00954 *restrict p; 00955 00956 register Quantum 00957 *restrict q; 00958 00959 register ssize_t 00960 x; 00961 00962 if (status == MagickFalse) 00963 continue; 00964 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y, 00965 geometry->width,1,exception); 00966 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1, 00967 exception); 00968 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00969 { 00970 status=MagickFalse; 00971 continue; 00972 } 00973 for (x=0; x < (ssize_t) excerpt_image->columns; x++) 00974 { 00975 register ssize_t 00976 i; 00977 00978 if (GetPixelMask(image,p) != 0) 00979 { 00980 p+=GetPixelChannels(image); 00981 q+=GetPixelChannels(excerpt_image); 00982 continue; 00983 } 00984 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00985 { 00986 PixelChannel 00987 channel; 00988 00989 PixelTrait 00990 excerpt_traits, 00991 traits; 00992 00993 channel=GetPixelChannelMapChannel(image,i); 00994 traits=GetPixelChannelMapTraits(image,channel); 00995 excerpt_traits=GetPixelChannelMapTraits(excerpt_image,channel); 00996 if ((traits == UndefinedPixelTrait) || 00997 (excerpt_traits == UndefinedPixelTrait)) 00998 continue; 00999 SetPixelChannel(excerpt_image,channel,p[i],q); 01000 } 01001 p+=GetPixelChannels(image); 01002 q+=GetPixelChannels(excerpt_image); 01003 } 01004 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse) 01005 status=MagickFalse; 01006 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01007 { 01008 MagickBooleanType 01009 proceed; 01010 01011 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01012 #pragma omp critical (MagickCore_ExcerptImage) 01013 #endif 01014 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows); 01015 if (proceed == MagickFalse) 01016 status=MagickFalse; 01017 } 01018 } 01019 excerpt_view=DestroyCacheView(excerpt_view); 01020 image_view=DestroyCacheView(image_view); 01021 excerpt_image->type=image->type; 01022 if (status == MagickFalse) 01023 excerpt_image=DestroyImage(excerpt_image); 01024 return(excerpt_image); 01025 } 01026 01027 /* 01028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01029 % % 01030 % % 01031 % % 01032 % E x t e n t I m a g e % 01033 % % 01034 % % 01035 % % 01036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01037 % 01038 % ExtentImage() extends the image as defined by the geometry, gravity, and 01039 % image background color. Set the (x,y) offset of the geometry to move the 01040 % original image relative to the extended image. 01041 % 01042 % The format of the ExtentImage method is: 01043 % 01044 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry, 01045 % ExceptionInfo *exception) 01046 % 01047 % A description of each parameter follows: 01048 % 01049 % o image: the image. 01050 % 01051 % o geometry: Define the region of the image to extend with members 01052 % x, y, width, and height. 01053 % 01054 % o exception: return any errors or warnings in this structure. 01055 % 01056 */ 01057 MagickExport Image *ExtentImage(const Image *image, 01058 const RectangleInfo *geometry,ExceptionInfo *exception) 01059 { 01060 Image 01061 *extent_image; 01062 01063 /* 01064 Allocate extent image. 01065 */ 01066 assert(image != (const Image *) NULL); 01067 assert(image->signature == MagickSignature); 01068 if (image->debug != MagickFalse) 01069 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01070 assert(geometry != (const RectangleInfo *) NULL); 01071 assert(exception != (ExceptionInfo *) NULL); 01072 assert(exception->signature == MagickSignature); 01073 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue, 01074 exception); 01075 if (extent_image == (Image *) NULL) 01076 return((Image *) NULL); 01077 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse) 01078 { 01079 extent_image=DestroyImage(extent_image); 01080 return((Image *) NULL); 01081 } 01082 if (extent_image->background_color.alpha != OpaqueAlpha) 01083 extent_image->matte=MagickTrue; 01084 (void) SetImageBackgroundColor(extent_image,exception); 01085 (void) CompositeImage(extent_image,image->compose,image,-geometry->x, 01086 -geometry->y,exception); 01087 return(extent_image); 01088 } 01089 01090 /* 01091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01092 % % 01093 % % 01094 % % 01095 % F l i p I m a g e % 01096 % % 01097 % % 01098 % % 01099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01100 % 01101 % FlipImage() creates a vertical mirror image by reflecting the pixels 01102 % around the central x-axis. 01103 % 01104 % The format of the FlipImage method is: 01105 % 01106 % Image *FlipImage(const Image *image,ExceptionInfo *exception) 01107 % 01108 % A description of each parameter follows: 01109 % 01110 % o image: the image. 01111 % 01112 % o exception: return any errors or warnings in this structure. 01113 % 01114 */ 01115 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception) 01116 { 01117 #define FlipImageTag "Flip/Image" 01118 01119 CacheView 01120 *flip_view, 01121 *image_view; 01122 01123 Image 01124 *flip_image; 01125 01126 MagickBooleanType 01127 status; 01128 01129 MagickOffsetType 01130 progress; 01131 01132 RectangleInfo 01133 page; 01134 01135 ssize_t 01136 y; 01137 01138 assert(image != (const Image *) NULL); 01139 assert(image->signature == MagickSignature); 01140 if (image->debug != MagickFalse) 01141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01142 assert(exception != (ExceptionInfo *) NULL); 01143 assert(exception->signature == MagickSignature); 01144 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 01145 if (flip_image == (Image *) NULL) 01146 return((Image *) NULL); 01147 /* 01148 Flip image. 01149 */ 01150 status=MagickTrue; 01151 progress=0; 01152 page=image->page; 01153 image_view=AcquireCacheView(image); 01154 flip_view=AcquireCacheView(flip_image); 01155 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01156 #pragma omp parallel for schedule(static) shared(progress,status) 01157 #endif 01158 for (y=0; y < (ssize_t) flip_image->rows; y++) 01159 { 01160 register const Quantum 01161 *restrict p; 01162 01163 register Quantum 01164 *restrict q; 01165 01166 register ssize_t 01167 x; 01168 01169 if (status == MagickFalse) 01170 continue; 01171 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 01172 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y- 01173 1),flip_image->columns,1,exception); 01174 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01175 { 01176 status=MagickFalse; 01177 continue; 01178 } 01179 for (x=0; x < (ssize_t) flip_image->columns; x++) 01180 { 01181 register ssize_t 01182 i; 01183 01184 if (GetPixelMask(image,p) != 0) 01185 { 01186 p+=GetPixelChannels(image); 01187 q+=GetPixelChannels(flip_image); 01188 continue; 01189 } 01190 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01191 { 01192 PixelChannel 01193 channel; 01194 01195 PixelTrait 01196 flip_traits, 01197 traits; 01198 01199 channel=GetPixelChannelMapChannel(image,i); 01200 traits=GetPixelChannelMapTraits(image,channel); 01201 flip_traits=GetPixelChannelMapTraits(flip_image,channel); 01202 if ((traits == UndefinedPixelTrait) || 01203 (flip_traits == UndefinedPixelTrait)) 01204 continue; 01205 SetPixelChannel(flip_image,channel,p[i],q); 01206 } 01207 p+=GetPixelChannels(image); 01208 q+=GetPixelChannels(flip_image); 01209 } 01210 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse) 01211 status=MagickFalse; 01212 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01213 { 01214 MagickBooleanType 01215 proceed; 01216 01217 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01218 #pragma omp critical (MagickCore_FlipImage) 01219 #endif 01220 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows); 01221 if (proceed == MagickFalse) 01222 status=MagickFalse; 01223 } 01224 } 01225 flip_view=DestroyCacheView(flip_view); 01226 image_view=DestroyCacheView(image_view); 01227 flip_image->type=image->type; 01228 if (page.height != 0) 01229 page.y=(ssize_t) (page.height-flip_image->rows-page.y); 01230 flip_image->page=page; 01231 if (status == MagickFalse) 01232 flip_image=DestroyImage(flip_image); 01233 return(flip_image); 01234 } 01235 01236 /* 01237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01238 % % 01239 % % 01240 % % 01241 % F l o p I m a g e % 01242 % % 01243 % % 01244 % % 01245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01246 % 01247 % FlopImage() creates a horizontal mirror image by reflecting the pixels 01248 % around the central y-axis. 01249 % 01250 % The format of the FlopImage method is: 01251 % 01252 % Image *FlopImage(const Image *image,ExceptionInfo *exception) 01253 % 01254 % A description of each parameter follows: 01255 % 01256 % o image: the image. 01257 % 01258 % o exception: return any errors or warnings in this structure. 01259 % 01260 */ 01261 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception) 01262 { 01263 #define FlopImageTag "Flop/Image" 01264 01265 CacheView 01266 *flop_view, 01267 *image_view; 01268 01269 Image 01270 *flop_image; 01271 01272 MagickBooleanType 01273 status; 01274 01275 MagickOffsetType 01276 progress; 01277 01278 RectangleInfo 01279 page; 01280 01281 ssize_t 01282 y; 01283 01284 assert(image != (const Image *) NULL); 01285 assert(image->signature == MagickSignature); 01286 if (image->debug != MagickFalse) 01287 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01288 assert(exception != (ExceptionInfo *) NULL); 01289 assert(exception->signature == MagickSignature); 01290 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 01291 if (flop_image == (Image *) NULL) 01292 return((Image *) NULL); 01293 /* 01294 Flop each row. 01295 */ 01296 status=MagickTrue; 01297 progress=0; 01298 page=image->page; 01299 image_view=AcquireCacheView(image); 01300 flop_view=AcquireCacheView(flop_image); 01301 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01302 #pragma omp parallel for schedule(static) shared(progress,status) 01303 #endif 01304 for (y=0; y < (ssize_t) flop_image->rows; y++) 01305 { 01306 register const Quantum 01307 *restrict p; 01308 01309 register ssize_t 01310 x; 01311 01312 register Quantum 01313 *restrict q; 01314 01315 if (status == MagickFalse) 01316 continue; 01317 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 01318 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1, 01319 exception); 01320 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01321 { 01322 status=MagickFalse; 01323 continue; 01324 } 01325 q+=GetPixelChannels(flop_image)*flop_image->columns; 01326 for (x=0; x < (ssize_t) flop_image->columns; x++) 01327 { 01328 register ssize_t 01329 i; 01330 01331 q-=GetPixelChannels(flop_image); 01332 if (GetPixelMask(image,p) != 0) 01333 { 01334 p+=GetPixelChannels(image); 01335 continue; 01336 } 01337 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01338 { 01339 PixelChannel 01340 channel; 01341 01342 PixelTrait 01343 flop_traits, 01344 traits; 01345 01346 channel=GetPixelChannelMapChannel(image,i); 01347 traits=GetPixelChannelMapTraits(image,channel); 01348 flop_traits=GetPixelChannelMapTraits(flop_image,channel); 01349 if ((traits == UndefinedPixelTrait) || 01350 (flop_traits == UndefinedPixelTrait)) 01351 continue; 01352 SetPixelChannel(flop_image,channel,p[i],q); 01353 } 01354 p+=GetPixelChannels(image); 01355 } 01356 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse) 01357 status=MagickFalse; 01358 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01359 { 01360 MagickBooleanType 01361 proceed; 01362 01363 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01364 #pragma omp critical (MagickCore_FlopImage) 01365 #endif 01366 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows); 01367 if (proceed == MagickFalse) 01368 status=MagickFalse; 01369 } 01370 } 01371 flop_view=DestroyCacheView(flop_view); 01372 image_view=DestroyCacheView(image_view); 01373 flop_image->type=image->type; 01374 if (page.width != 0) 01375 page.x=(ssize_t) (page.width-flop_image->columns-page.x); 01376 flop_image->page=page; 01377 if (status == MagickFalse) 01378 flop_image=DestroyImage(flop_image); 01379 return(flop_image); 01380 } 01381 01382 /* 01383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01384 % % 01385 % % 01386 % % 01387 % R o l l I m a g e % 01388 % % 01389 % % 01390 % % 01391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01392 % 01393 % RollImage() offsets an image as defined by x_offset and y_offset. 01394 % 01395 % The format of the RollImage method is: 01396 % 01397 % Image *RollImage(const Image *image,const ssize_t x_offset, 01398 % const ssize_t y_offset,ExceptionInfo *exception) 01399 % 01400 % A description of each parameter follows: 01401 % 01402 % o image: the image. 01403 % 01404 % o x_offset: the number of columns to roll in the horizontal direction. 01405 % 01406 % o y_offset: the number of rows to roll in the vertical direction. 01407 % 01408 % o exception: return any errors or warnings in this structure. 01409 % 01410 */ 01411 01412 static inline MagickBooleanType CopyImageRegion(Image *destination, 01413 const Image *source,const size_t columns,const size_t rows, 01414 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy, 01415 ExceptionInfo *exception) 01416 { 01417 CacheView 01418 *source_view, 01419 *destination_view; 01420 01421 MagickBooleanType 01422 status; 01423 01424 ssize_t 01425 y; 01426 01427 status=MagickTrue; 01428 source_view=AcquireCacheView(source); 01429 destination_view=AcquireCacheView(destination); 01430 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01431 #pragma omp parallel for schedule(static) shared(status) 01432 #endif 01433 for (y=0; y < (ssize_t) rows; y++) 01434 { 01435 MagickBooleanType 01436 sync; 01437 01438 register const Quantum 01439 *restrict p; 01440 01441 register Quantum 01442 *restrict q; 01443 01444 register ssize_t 01445 x; 01446 01447 /* 01448 Transfer scanline. 01449 */ 01450 if (status == MagickFalse) 01451 continue; 01452 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception); 01453 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception); 01454 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01455 { 01456 status=MagickFalse; 01457 continue; 01458 } 01459 for (x=0; x < (ssize_t) columns; x++) 01460 { 01461 register ssize_t 01462 i; 01463 01464 if (GetPixelMask(source,p) != 0) 01465 { 01466 p+=GetPixelChannels(source); 01467 q+=GetPixelChannels(destination); 01468 continue; 01469 } 01470 for (i=0; i < (ssize_t) GetPixelChannels(source); i++) 01471 { 01472 PixelChannel 01473 channel; 01474 01475 PixelTrait 01476 destination_traits, 01477 source_traits; 01478 01479 channel=GetPixelChannelMapChannel(source,i); 01480 source_traits=GetPixelChannelMapTraits(source,channel); 01481 destination_traits=GetPixelChannelMapTraits(destination,channel); 01482 if ((source_traits == UndefinedPixelTrait) || 01483 (destination_traits == UndefinedPixelTrait)) 01484 continue; 01485 SetPixelChannel(destination,channel,p[i],q); 01486 } 01487 p+=GetPixelChannels(source); 01488 q+=GetPixelChannels(destination); 01489 } 01490 sync=SyncCacheViewAuthenticPixels(destination_view,exception); 01491 if (sync == MagickFalse) 01492 status=MagickFalse; 01493 } 01494 destination_view=DestroyCacheView(destination_view); 01495 source_view=DestroyCacheView(source_view); 01496 return(status); 01497 } 01498 01499 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset, 01500 const ssize_t y_offset,ExceptionInfo *exception) 01501 { 01502 #define RollImageTag "Roll/Image" 01503 01504 Image 01505 *roll_image; 01506 01507 MagickStatusType 01508 status; 01509 01510 RectangleInfo 01511 offset; 01512 01513 /* 01514 Initialize roll image attributes. 01515 */ 01516 assert(image != (const Image *) NULL); 01517 assert(image->signature == MagickSignature); 01518 if (image->debug != MagickFalse) 01519 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01520 assert(exception != (ExceptionInfo *) NULL); 01521 assert(exception->signature == MagickSignature); 01522 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 01523 if (roll_image == (Image *) NULL) 01524 return((Image *) NULL); 01525 offset.x=x_offset; 01526 offset.y=y_offset; 01527 while (offset.x < 0) 01528 offset.x+=(ssize_t) image->columns; 01529 while (offset.x >= (ssize_t) image->columns) 01530 offset.x-=(ssize_t) image->columns; 01531 while (offset.y < 0) 01532 offset.y+=(ssize_t) image->rows; 01533 while (offset.y >= (ssize_t) image->rows) 01534 offset.y-=(ssize_t) image->rows; 01535 /* 01536 Roll image. 01537 */ 01538 status=CopyImageRegion(roll_image,image,(size_t) offset.x, 01539 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows- 01540 offset.y,0,0,exception); 01541 (void) SetImageProgress(image,RollImageTag,0,3); 01542 status|=CopyImageRegion(roll_image,image,image->columns-offset.x, 01543 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0, 01544 exception); 01545 (void) SetImageProgress(image,RollImageTag,1,3); 01546 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows- 01547 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception); 01548 (void) SetImageProgress(image,RollImageTag,2,3); 01549 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows- 01550 offset.y,0,0,offset.x,offset.y,exception); 01551 (void) SetImageProgress(image,RollImageTag,3,3); 01552 roll_image->type=image->type; 01553 if (status == MagickFalse) 01554 roll_image=DestroyImage(roll_image); 01555 return(roll_image); 01556 } 01557 01558 /* 01559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01560 % % 01561 % % 01562 % % 01563 % S h a v e I m a g e % 01564 % % 01565 % % 01566 % % 01567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01568 % 01569 % ShaveImage() shaves pixels from the image edges. It allocates the memory 01570 % necessary for the new Image structure and returns a pointer to the new 01571 % image. 01572 % 01573 % The format of the ShaveImage method is: 01574 % 01575 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info, 01576 % ExceptionInfo *exception) 01577 % 01578 % A description of each parameter follows: 01579 % 01580 % o shave_image: Method ShaveImage returns a pointer to the shaved 01581 % image. A null image is returned if there is a memory shortage or 01582 % if the image width or height is zero. 01583 % 01584 % o image: the image. 01585 % 01586 % o shave_info: Specifies a pointer to a RectangleInfo which defines the 01587 % region of the image to crop. 01588 % 01589 % o exception: return any errors or warnings in this structure. 01590 % 01591 */ 01592 MagickExport Image *ShaveImage(const Image *image, 01593 const RectangleInfo *shave_info,ExceptionInfo *exception) 01594 { 01595 Image 01596 *shave_image; 01597 01598 RectangleInfo 01599 geometry; 01600 01601 assert(image != (const Image *) NULL); 01602 assert(image->signature == MagickSignature); 01603 if (image->debug != MagickFalse) 01604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01605 if (((2*shave_info->width) >= image->columns) || 01606 ((2*shave_info->height) >= image->rows)) 01607 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage"); 01608 SetGeometry(image,&geometry); 01609 geometry.width-=2*shave_info->width; 01610 geometry.height-=2*shave_info->height; 01611 geometry.x=(ssize_t) shave_info->width+image->page.x; 01612 geometry.y=(ssize_t) shave_info->height+image->page.y; 01613 shave_image=CropImage(image,&geometry,exception); 01614 if (shave_image == (Image *) NULL) 01615 return((Image *) NULL); 01616 shave_image->page.width-=2*shave_info->width; 01617 shave_image->page.height-=2*shave_info->height; 01618 shave_image->page.x-=(ssize_t) shave_info->width; 01619 shave_image->page.y-=(ssize_t) shave_info->height; 01620 return(shave_image); 01621 } 01622 01623 /* 01624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01625 % % 01626 % % 01627 % % 01628 % S p l i c e I m a g e % 01629 % % 01630 % % 01631 % % 01632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01633 % 01634 % SpliceImage() splices a solid color into the image as defined by the 01635 % geometry. 01636 % 01637 % The format of the SpliceImage method is: 01638 % 01639 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry, 01640 % ExceptionInfo *exception) 01641 % 01642 % A description of each parameter follows: 01643 % 01644 % o image: the image. 01645 % 01646 % o geometry: Define the region of the image to splice with members 01647 % x, y, width, and height. 01648 % 01649 % o exception: return any errors or warnings in this structure. 01650 % 01651 */ 01652 MagickExport Image *SpliceImage(const Image *image, 01653 const RectangleInfo *geometry,ExceptionInfo *exception) 01654 { 01655 #define SpliceImageTag "Splice/Image" 01656 01657 CacheView 01658 *image_view, 01659 *splice_view; 01660 01661 Image 01662 *splice_image; 01663 01664 MagickBooleanType 01665 status; 01666 01667 MagickOffsetType 01668 progress; 01669 01670 RectangleInfo 01671 splice_geometry; 01672 01673 ssize_t 01674 y; 01675 01676 /* 01677 Allocate splice image. 01678 */ 01679 assert(image != (const Image *) NULL); 01680 assert(image->signature == MagickSignature); 01681 if (image->debug != MagickFalse) 01682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01683 assert(geometry != (const RectangleInfo *) NULL); 01684 assert(exception != (ExceptionInfo *) NULL); 01685 assert(exception->signature == MagickSignature); 01686 splice_geometry=(*geometry); 01687 splice_image=CloneImage(image,image->columns+splice_geometry.width, 01688 image->rows+splice_geometry.height,MagickTrue,exception); 01689 if (splice_image == (Image *) NULL) 01690 return((Image *) NULL); 01691 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse) 01692 { 01693 splice_image=DestroyImage(splice_image); 01694 return((Image *) NULL); 01695 } 01696 (void) SetImageBackgroundColor(splice_image,exception); 01697 /* 01698 Respect image geometry. 01699 */ 01700 switch (image->gravity) 01701 { 01702 default: 01703 case UndefinedGravity: 01704 case NorthWestGravity: 01705 break; 01706 case NorthGravity: 01707 { 01708 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 01709 break; 01710 } 01711 case NorthEastGravity: 01712 { 01713 splice_geometry.x+=(ssize_t) splice_geometry.width; 01714 break; 01715 } 01716 case WestGravity: 01717 { 01718 splice_geometry.y+=(ssize_t) splice_geometry.width/2; 01719 break; 01720 } 01721 case StaticGravity: 01722 case CenterGravity: 01723 { 01724 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 01725 splice_geometry.y+=(ssize_t) splice_geometry.height/2; 01726 break; 01727 } 01728 case EastGravity: 01729 { 01730 splice_geometry.x+=(ssize_t) splice_geometry.width; 01731 splice_geometry.y+=(ssize_t) splice_geometry.height/2; 01732 break; 01733 } 01734 case SouthWestGravity: 01735 { 01736 splice_geometry.y+=(ssize_t) splice_geometry.height; 01737 break; 01738 } 01739 case SouthGravity: 01740 { 01741 splice_geometry.x+=(ssize_t) splice_geometry.width/2; 01742 splice_geometry.y+=(ssize_t) splice_geometry.height; 01743 break; 01744 } 01745 case SouthEastGravity: 01746 { 01747 splice_geometry.x+=(ssize_t) splice_geometry.width; 01748 splice_geometry.y+=(ssize_t) splice_geometry.height; 01749 break; 01750 } 01751 } 01752 /* 01753 Splice image. 01754 */ 01755 status=MagickTrue; 01756 progress=0; 01757 image_view=AcquireCacheView(image); 01758 splice_view=AcquireCacheView(splice_image); 01759 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01760 #pragma omp parallel for schedule(static,4) shared(progress,status) 01761 #endif 01762 for (y=0; y < (ssize_t) splice_geometry.y; y++) 01763 { 01764 register const Quantum 01765 *restrict p; 01766 01767 register ssize_t 01768 x; 01769 01770 register Quantum 01771 *restrict q; 01772 01773 if (status == MagickFalse) 01774 continue; 01775 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 01776 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1, 01777 exception); 01778 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01779 { 01780 status=MagickFalse; 01781 continue; 01782 } 01783 for (x=0; x < splice_geometry.x; x++) 01784 { 01785 register ssize_t 01786 i; 01787 01788 if (GetPixelMask(image,p) != 0) 01789 { 01790 p+=GetPixelChannels(image); 01791 q+=GetPixelChannels(splice_image); 01792 continue; 01793 } 01794 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01795 { 01796 PixelChannel 01797 channel; 01798 01799 PixelTrait 01800 splice_traits, 01801 traits; 01802 01803 channel=GetPixelChannelMapChannel(image,i); 01804 traits=GetPixelChannelMapTraits(image,channel); 01805 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 01806 if ((traits == UndefinedPixelTrait) || 01807 (splice_traits == UndefinedPixelTrait)) 01808 continue; 01809 SetPixelChannel(splice_image,channel,p[i],q); 01810 } 01811 p+=GetPixelChannels(image); 01812 q+=GetPixelChannels(splice_image); 01813 } 01814 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++) 01815 q+=GetPixelChannels(splice_image); 01816 for ( ; x < (ssize_t) splice_image->columns; x++) 01817 { 01818 register ssize_t 01819 i; 01820 01821 if (GetPixelMask(image,p) != 0) 01822 { 01823 p+=GetPixelChannels(image); 01824 q+=GetPixelChannels(splice_image); 01825 continue; 01826 } 01827 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01828 { 01829 PixelChannel 01830 channel; 01831 01832 PixelTrait 01833 traits, 01834 splice_traits; 01835 01836 channel=GetPixelChannelMapChannel(image,i); 01837 traits=GetPixelChannelMapTraits(image,channel); 01838 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 01839 if ((traits == UndefinedPixelTrait) || 01840 (splice_traits == UndefinedPixelTrait)) 01841 continue; 01842 SetPixelChannel(splice_image,channel,p[i],q); 01843 } 01844 p+=GetPixelChannels(image); 01845 q+=GetPixelChannels(splice_image); 01846 } 01847 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse) 01848 status=MagickFalse; 01849 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01850 { 01851 MagickBooleanType 01852 proceed; 01853 01854 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01855 #pragma omp critical (MagickCore_TransposeImage) 01856 #endif 01857 proceed=SetImageProgress(image,SpliceImageTag,progress++, 01858 splice_image->rows); 01859 if (proceed == MagickFalse) 01860 status=MagickFalse; 01861 } 01862 } 01863 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01864 #pragma omp parallel for schedule(static,4) shared(progress,status) 01865 #endif 01866 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height); 01867 y < (ssize_t) splice_image->rows; y++) 01868 { 01869 register const Quantum 01870 *restrict p; 01871 01872 register ssize_t 01873 x; 01874 01875 register Quantum 01876 *restrict q; 01877 01878 if (status == MagickFalse) 01879 continue; 01880 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height, 01881 image->columns,1,exception); 01882 if ((y < 0) || (y >= (ssize_t) splice_image->rows)) 01883 continue; 01884 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1, 01885 exception); 01886 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01887 { 01888 status=MagickFalse; 01889 continue; 01890 } 01891 for (x=0; x < splice_geometry.x; x++) 01892 { 01893 register ssize_t 01894 i; 01895 01896 if (GetPixelMask(image,q) != 0) 01897 { 01898 p+=GetPixelChannels(image); 01899 q+=GetPixelChannels(splice_image); 01900 continue; 01901 } 01902 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01903 { 01904 PixelChannel 01905 channel; 01906 01907 PixelTrait 01908 traits, 01909 splice_traits; 01910 01911 channel=GetPixelChannelMapChannel(image,i); 01912 traits=GetPixelChannelMapTraits(image,channel); 01913 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 01914 if ((traits == UndefinedPixelTrait) || 01915 (splice_traits == UndefinedPixelTrait)) 01916 continue; 01917 SetPixelChannel(splice_image,channel,p[i],q); 01918 } 01919 p+=GetPixelChannels(image); 01920 q+=GetPixelChannels(splice_image); 01921 } 01922 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++) 01923 q+=GetPixelChannels(splice_image); 01924 for ( ; x < (ssize_t) splice_image->columns; x++) 01925 { 01926 register ssize_t 01927 i; 01928 01929 if (GetPixelMask(image,q) != 0) 01930 { 01931 p+=GetPixelChannels(image); 01932 q+=GetPixelChannels(splice_image); 01933 continue; 01934 } 01935 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01936 { 01937 PixelChannel 01938 channel; 01939 01940 PixelTrait 01941 traits, 01942 splice_traits; 01943 01944 channel=GetPixelChannelMapChannel(image,i); 01945 traits=GetPixelChannelMapTraits(image,channel); 01946 splice_traits=GetPixelChannelMapTraits(splice_image,channel); 01947 if ((traits == UndefinedPixelTrait) || 01948 (splice_traits == UndefinedPixelTrait)) 01949 continue; 01950 SetPixelChannel(splice_image,channel,p[i],q); 01951 } 01952 p+=GetPixelChannels(image); 01953 q+=GetPixelChannels(splice_image); 01954 } 01955 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse) 01956 status=MagickFalse; 01957 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01958 { 01959 MagickBooleanType 01960 proceed; 01961 01962 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01963 #pragma omp critical (MagickCore_TransposeImage) 01964 #endif 01965 proceed=SetImageProgress(image,SpliceImageTag,progress++, 01966 splice_image->rows); 01967 if (proceed == MagickFalse) 01968 status=MagickFalse; 01969 } 01970 } 01971 splice_view=DestroyCacheView(splice_view); 01972 image_view=DestroyCacheView(image_view); 01973 if (status == MagickFalse) 01974 splice_image=DestroyImage(splice_image); 01975 return(splice_image); 01976 } 01977 01978 /* 01979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01980 % % 01981 % % 01982 % % 01983 % T r a n s f o r m I m a g e % 01984 % % 01985 % % 01986 % % 01987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01988 % 01989 % TransformImage() is a convenience method that behaves like ResizeImage() or 01990 % CropImage() but accepts scaling and/or cropping information as a region 01991 % geometry specification. If the operation fails, the original image handle 01992 % is left as is. 01993 % 01994 % This should only be used for single images. 01995 % 01996 % This function destroys what it assumes to be a single image list. 01997 % If the input image is part of a larger list, all other images in that list 01998 % will be simply 'lost', not destroyed. 01999 % 02000 % Also if the crop generates a list of images only the first image is resized. 02001 % And finally if the crop succeeds and the resize failed, you will get a 02002 % cropped image, as well as a 'false' or 'failed' report. 02003 % 02004 % This function and should probably be depreciated in favor of direct calls 02005 % to CropImageToTiles() or ResizeImage(), as appropriate. 02006 % 02007 % The format of the TransformImage method is: 02008 % 02009 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry, 02010 % const char *image_geometry,ExceptionInfo *exception) 02011 % 02012 % A description of each parameter follows: 02013 % 02014 % o image: the image The transformed image is returned as this parameter. 02015 % 02016 % o crop_geometry: A crop geometry string. This geometry defines a 02017 % subregion of the image to crop. 02018 % 02019 % o image_geometry: An image geometry string. This geometry defines the 02020 % final size of the image. 02021 % 02022 % o exception: return any errors or warnings in this structure. 02023 % 02024 */ 02025 MagickExport MagickBooleanType TransformImage(Image **image, 02026 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception) 02027 { 02028 Image 02029 *resize_image, 02030 *transform_image; 02031 02032 MagickStatusType 02033 flags; 02034 02035 RectangleInfo 02036 geometry; 02037 02038 assert(image != (Image **) NULL); 02039 assert((*image)->signature == MagickSignature); 02040 if ((*image)->debug != MagickFalse) 02041 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 02042 transform_image=(*image); 02043 if (crop_geometry != (const char *) NULL) 02044 { 02045 Image 02046 *crop_image; 02047 02048 /* 02049 Crop image to a user specified size. 02050 */ 02051 crop_image=CropImageToTiles(*image,crop_geometry,exception); 02052 if (crop_image == (Image *) NULL) 02053 transform_image=CloneImage(*image,0,0,MagickTrue,exception); 02054 else 02055 { 02056 transform_image=DestroyImage(transform_image); 02057 transform_image=GetFirstImageInList(crop_image); 02058 } 02059 *image=transform_image; 02060 } 02061 if (image_geometry == (const char *) NULL) 02062 return(MagickTrue); 02063 02064 /* 02065 Scale image to a user specified size. 02066 */ 02067 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception); 02068 (void) flags; 02069 if ((transform_image->columns == geometry.width) && 02070 (transform_image->rows == geometry.height)) 02071 return(MagickTrue); 02072 resize_image=ResizeImage(transform_image,geometry.width,geometry.height, 02073 transform_image->filter,transform_image->blur,exception); 02074 if (resize_image == (Image *) NULL) 02075 return(MagickFalse); 02076 transform_image=DestroyImage(transform_image); 02077 transform_image=resize_image; 02078 *image=transform_image; 02079 return(MagickTrue); 02080 } 02081 02082 /* 02083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02084 % % 02085 % % 02086 % % 02087 % T r a n s f o r m I m a g e s % 02088 % % 02089 % % 02090 % % 02091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02092 % 02093 % TransformImages() calls TransformImage() on each image of a sequence. 02094 % 02095 % The format of the TransformImage method is: 02096 % 02097 % MagickBooleanType TransformImages(Image **image, 02098 % const char *crop_geometry,const char *image_geometry, 02099 % ExceptionInfo *exception) 02100 % 02101 % A description of each parameter follows: 02102 % 02103 % o image: the image The transformed image is returned as this parameter. 02104 % 02105 % o crop_geometry: A crop geometry string. This geometry defines a 02106 % subregion of the image to crop. 02107 % 02108 % o image_geometry: An image geometry string. This geometry defines the 02109 % final size of the image. 02110 % 02111 % o exception: return any errors or warnings in this structure. 02112 % 02113 */ 02114 MagickExport MagickBooleanType TransformImages(Image **images, 02115 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception) 02116 { 02117 Image 02118 *image, 02119 **image_list, 02120 *transform_images; 02121 02122 MagickStatusType 02123 status; 02124 02125 register ssize_t 02126 i; 02127 02128 assert(images != (Image **) NULL); 02129 assert((*images)->signature == MagickSignature); 02130 if ((*images)->debug != MagickFalse) 02131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 02132 (*images)->filename); 02133 image_list=ImageListToArray(*images,exception); 02134 if (image_list == (Image **) NULL) 02135 return(MagickFalse); 02136 status=MagickTrue; 02137 transform_images=NewImageList(); 02138 for (i=0; image_list[i] != (Image *) NULL; i++) 02139 { 02140 image=image_list[i]; 02141 status|=TransformImage(&image,crop_geometry,image_geometry,exception); 02142 AppendImageToList(&transform_images,image); 02143 } 02144 *images=transform_images; 02145 image_list=(Image **) RelinquishMagickMemory(image_list); 02146 return(status != 0 ? MagickTrue : MagickFalse); 02147 } 02148 02149 /* 02150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02151 % % 02152 % % 02153 % % 02154 % T r a n s p o s e I m a g e % 02155 % % 02156 % % 02157 % % 02158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02159 % 02160 % TransposeImage() creates a horizontal mirror image by reflecting the pixels 02161 % around the central y-axis while rotating them by 90 degrees. 02162 % 02163 % The format of the TransposeImage method is: 02164 % 02165 % Image *TransposeImage(const Image *image,ExceptionInfo *exception) 02166 % 02167 % A description of each parameter follows: 02168 % 02169 % o image: the image. 02170 % 02171 % o exception: return any errors or warnings in this structure. 02172 % 02173 */ 02174 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception) 02175 { 02176 #define TransposeImageTag "Transpose/Image" 02177 02178 CacheView 02179 *image_view, 02180 *transpose_view; 02181 02182 Image 02183 *transpose_image; 02184 02185 MagickBooleanType 02186 status; 02187 02188 MagickOffsetType 02189 progress; 02190 02191 RectangleInfo 02192 page; 02193 02194 ssize_t 02195 y; 02196 02197 assert(image != (const Image *) NULL); 02198 assert(image->signature == MagickSignature); 02199 if (image->debug != MagickFalse) 02200 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 02201 assert(exception != (ExceptionInfo *) NULL); 02202 assert(exception->signature == MagickSignature); 02203 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue, 02204 exception); 02205 if (transpose_image == (Image *) NULL) 02206 return((Image *) NULL); 02207 /* 02208 Transpose image. 02209 */ 02210 status=MagickTrue; 02211 progress=0; 02212 image_view=AcquireCacheView(image); 02213 transpose_view=AcquireCacheView(transpose_image); 02214 #if defined(MAGICKCORE_OPENMP_SUPPORT) 02215 #pragma omp parallel for schedule(static,4) shared(progress,status) 02216 #endif 02217 for (y=0; y < (ssize_t) image->rows; y++) 02218 { 02219 register const Quantum 02220 *restrict p; 02221 02222 register Quantum 02223 *restrict q; 02224 02225 register ssize_t 02226 x; 02227 02228 if (status == MagickFalse) 02229 continue; 02230 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1, 02231 image->columns,1,exception); 02232 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1), 02233 0,1,transpose_image->rows,exception); 02234 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 02235 { 02236 status=MagickFalse; 02237 continue; 02238 } 02239 for (x=0; x < (ssize_t) image->columns; x++) 02240 { 02241 register ssize_t 02242 i; 02243 02244 if (GetPixelMask(image,q) != 0) 02245 { 02246 p+=GetPixelChannels(image); 02247 q+=GetPixelChannels(transpose_image); 02248 continue; 02249 } 02250 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02251 { 02252 PixelChannel 02253 channel; 02254 02255 PixelTrait 02256 traits, 02257 transpose_traits; 02258 02259 channel=GetPixelChannelMapChannel(image,i); 02260 traits=GetPixelChannelMapTraits(image,channel); 02261 transpose_traits=GetPixelChannelMapTraits(transpose_image,channel); 02262 if ((traits == UndefinedPixelTrait) || 02263 (transpose_traits == UndefinedPixelTrait)) 02264 continue; 02265 SetPixelChannel(transpose_image,channel,p[i],q); 02266 } 02267 p+=GetPixelChannels(image); 02268 q+=GetPixelChannels(transpose_image); 02269 } 02270 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse) 02271 status=MagickFalse; 02272 if (image->progress_monitor != (MagickProgressMonitor) NULL) 02273 { 02274 MagickBooleanType 02275 proceed; 02276 02277 #if defined(MAGICKCORE_OPENMP_SUPPORT) 02278 #pragma omp critical (MagickCore_TransposeImage) 02279 #endif 02280 proceed=SetImageProgress(image,TransposeImageTag,progress++, 02281 image->rows); 02282 if (proceed == MagickFalse) 02283 status=MagickFalse; 02284 } 02285 } 02286 transpose_view=DestroyCacheView(transpose_view); 02287 image_view=DestroyCacheView(image_view); 02288 transpose_image->type=image->type; 02289 page=transpose_image->page; 02290 Swap(page.width,page.height); 02291 Swap(page.x,page.y); 02292 transpose_image->page=page; 02293 if (status == MagickFalse) 02294 transpose_image=DestroyImage(transpose_image); 02295 return(transpose_image); 02296 } 02297 02298 /* 02299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02300 % % 02301 % % 02302 % % 02303 % T r a n s v e r s e I m a g e % 02304 % % 02305 % % 02306 % % 02307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02308 % 02309 % TransverseImage() creates a vertical mirror image by reflecting the pixels 02310 % around the central x-axis while rotating them by 270 degrees. 02311 % 02312 % The format of the TransverseImage method is: 02313 % 02314 % Image *TransverseImage(const Image *image,ExceptionInfo *exception) 02315 % 02316 % A description of each parameter follows: 02317 % 02318 % o image: the image. 02319 % 02320 % o exception: return any errors or warnings in this structure. 02321 % 02322 */ 02323 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception) 02324 { 02325 #define TransverseImageTag "Transverse/Image" 02326 02327 CacheView 02328 *image_view, 02329 *transverse_view; 02330 02331 Image 02332 *transverse_image; 02333 02334 MagickBooleanType 02335 status; 02336 02337 MagickOffsetType 02338 progress; 02339 02340 RectangleInfo 02341 page; 02342 02343 ssize_t 02344 y; 02345 02346 assert(image != (const Image *) NULL); 02347 assert(image->signature == MagickSignature); 02348 if (image->debug != MagickFalse) 02349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 02350 assert(exception != (ExceptionInfo *) NULL); 02351 assert(exception->signature == MagickSignature); 02352 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue, 02353 exception); 02354 if (transverse_image == (Image *) NULL) 02355 return((Image *) NULL); 02356 /* 02357 Transverse image. 02358 */ 02359 status=MagickTrue; 02360 progress=0; 02361 image_view=AcquireCacheView(image); 02362 transverse_view=AcquireCacheView(transverse_image); 02363 #if defined(MAGICKCORE_OPENMP_SUPPORT) 02364 #pragma omp parallel for schedule(static,4) shared(progress,status) 02365 #endif 02366 for (y=0; y < (ssize_t) image->rows; y++) 02367 { 02368 MagickBooleanType 02369 sync; 02370 02371 register const Quantum 02372 *restrict p; 02373 02374 register Quantum 02375 *restrict q; 02376 02377 register ssize_t 02378 x; 02379 02380 if (status == MagickFalse) 02381 continue; 02382 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 02383 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1), 02384 0,1,transverse_image->rows,exception); 02385 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 02386 { 02387 status=MagickFalse; 02388 continue; 02389 } 02390 q+=GetPixelChannels(transverse_image)*image->columns; 02391 for (x=0; x < (ssize_t) image->columns; x++) 02392 { 02393 register ssize_t 02394 i; 02395 02396 q-=GetPixelChannels(transverse_image); 02397 if (GetPixelMask(image,p) != 0) 02398 { 02399 p+=GetPixelChannels(image); 02400 continue; 02401 } 02402 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 02403 { 02404 PixelChannel 02405 channel; 02406 02407 PixelTrait 02408 traits, 02409 transverse_traits; 02410 02411 channel=GetPixelChannelMapChannel(image,i); 02412 traits=GetPixelChannelMapTraits(image,channel); 02413 transverse_traits=GetPixelChannelMapTraits(transverse_image,channel); 02414 if ((traits == UndefinedPixelTrait) || 02415 (transverse_traits == UndefinedPixelTrait)) 02416 continue; 02417 SetPixelChannel(transverse_image,channel,p[i],q); 02418 } 02419 p+=GetPixelChannels(image); 02420 } 02421 sync=SyncCacheViewAuthenticPixels(transverse_view,exception); 02422 if (sync == MagickFalse) 02423 status=MagickFalse; 02424 if (image->progress_monitor != (MagickProgressMonitor) NULL) 02425 { 02426 MagickBooleanType 02427 proceed; 02428 02429 #if defined(MAGICKCORE_OPENMP_SUPPORT) 02430 #pragma omp critical (MagickCore_TransverseImage) 02431 #endif 02432 proceed=SetImageProgress(image,TransverseImageTag,progress++, 02433 image->rows); 02434 if (proceed == MagickFalse) 02435 status=MagickFalse; 02436 } 02437 } 02438 transverse_view=DestroyCacheView(transverse_view); 02439 image_view=DestroyCacheView(image_view); 02440 transverse_image->type=image->type; 02441 page=transverse_image->page; 02442 Swap(page.width,page.height); 02443 Swap(page.x,page.y); 02444 if (page.width != 0) 02445 page.x=(ssize_t) (page.width-transverse_image->columns-page.x); 02446 if (page.height != 0) 02447 page.y=(ssize_t) (page.height-transverse_image->rows-page.y); 02448 transverse_image->page=page; 02449 if (status == MagickFalse) 02450 transverse_image=DestroyImage(transverse_image); 02451 return(transverse_image); 02452 } 02453 02454 /* 02455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02456 % % 02457 % % 02458 % % 02459 % T r i m I m a g e % 02460 % % 02461 % % 02462 % % 02463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02464 % 02465 % TrimImage() trims pixels from the image edges. It allocates the memory 02466 % necessary for the new Image structure and returns a pointer to the new 02467 % image. 02468 % 02469 % The format of the TrimImage method is: 02470 % 02471 % Image *TrimImage(const Image *image,ExceptionInfo *exception) 02472 % 02473 % A description of each parameter follows: 02474 % 02475 % o image: the image. 02476 % 02477 % o exception: return any errors or warnings in this structure. 02478 % 02479 */ 02480 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception) 02481 { 02482 RectangleInfo 02483 geometry; 02484 02485 assert(image != (const Image *) NULL); 02486 assert(image->signature == MagickSignature); 02487 if (image->debug != MagickFalse) 02488 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 02489 geometry=GetImageBoundingBox(image,exception); 02490 if ((geometry.width == 0) || (geometry.height == 0)) 02491 { 02492 Image 02493 *crop_image; 02494 02495 crop_image=CloneImage(image,1,1,MagickTrue,exception); 02496 if (crop_image == (Image *) NULL) 02497 return((Image *) NULL); 02498 crop_image->background_color.alpha=(Quantum) TransparentAlpha; 02499 (void) SetImageBackgroundColor(crop_image,exception); 02500 crop_image->page=image->page; 02501 crop_image->page.x=(-1); 02502 crop_image->page.y=(-1); 02503 return(crop_image); 02504 } 02505 geometry.x+=image->page.x; 02506 geometry.y+=image->page.y; 02507 return(CropImage(image,&geometry,exception)); 02508 }