|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % TTTTT H H RRRR EEEEE SSSSS H H OOO L DDDD % 00007 % T H H R R E SS H H O O L D D % 00008 % T HHHHH RRRR EEE SSS HHHHH O O L D D % 00009 % T H H R R E SS H H O O L D D % 00010 % T H H R R EEEEE SSSSS H H OOO LLLLL DDDD % 00011 % % 00012 % % 00013 % MagickCore Image Threshold Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % October 1996 % 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 /* 00041 Include declarations. 00042 */ 00043 #include "MagickCore/studio.h" 00044 #include "MagickCore/property.h" 00045 #include "MagickCore/blob.h" 00046 #include "MagickCore/cache-view.h" 00047 #include "MagickCore/color.h" 00048 #include "MagickCore/color-private.h" 00049 #include "MagickCore/colormap.h" 00050 #include "MagickCore/colorspace.h" 00051 #include "MagickCore/configure.h" 00052 #include "MagickCore/constitute.h" 00053 #include "MagickCore/decorate.h" 00054 #include "MagickCore/draw.h" 00055 #include "MagickCore/enhance.h" 00056 #include "MagickCore/exception.h" 00057 #include "MagickCore/exception-private.h" 00058 #include "MagickCore/effect.h" 00059 #include "MagickCore/fx.h" 00060 #include "MagickCore/gem.h" 00061 #include "MagickCore/geometry.h" 00062 #include "MagickCore/image-private.h" 00063 #include "MagickCore/list.h" 00064 #include "MagickCore/log.h" 00065 #include "MagickCore/memory_.h" 00066 #include "MagickCore/monitor.h" 00067 #include "MagickCore/monitor-private.h" 00068 #include "MagickCore/montage.h" 00069 #include "MagickCore/option.h" 00070 #include "MagickCore/pixel-accessor.h" 00071 #include "MagickCore/quantize.h" 00072 #include "MagickCore/quantum.h" 00073 #include "MagickCore/random_.h" 00074 #include "MagickCore/random-private.h" 00075 #include "MagickCore/resize.h" 00076 #include "MagickCore/resource_.h" 00077 #include "MagickCore/segment.h" 00078 #include "MagickCore/shear.h" 00079 #include "MagickCore/signature-private.h" 00080 #include "MagickCore/string_.h" 00081 #include "MagickCore/string-private.h" 00082 #include "MagickCore/thread-private.h" 00083 #include "MagickCore/threshold.h" 00084 #include "MagickCore/token.h" 00085 #include "MagickCore/transform.h" 00086 #include "MagickCore/xml-tree.h" 00087 #include "MagickCore/xml-tree-private.h" 00088 00089 /* 00090 Define declarations. 00091 */ 00092 #define ThresholdsFilename "thresholds.xml" 00093 00094 /* 00095 Typedef declarations. 00096 */ 00097 struct _ThresholdMap 00098 { 00099 char 00100 *map_id, 00101 *description; 00102 00103 size_t 00104 width, 00105 height; 00106 00107 ssize_t 00108 divisor, 00109 *levels; 00110 }; 00111 00112 /* 00113 Forward declarations. 00114 */ 00115 static ThresholdMap 00116 *GetThresholdMapFile(const char *,const char *,const char *,ExceptionInfo *); 00117 00118 /* 00119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00120 % % 00121 % % 00122 % % 00123 % A d a p t i v e T h r e s h o l d I m a g e % 00124 % % 00125 % % 00126 % % 00127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00128 % 00129 % AdaptiveThresholdImage() selects an individual threshold for each pixel 00130 % based on the range of intensity values in its local neighborhood. This 00131 % allows for thresholding of an image whose global intensity histogram 00132 % doesn't contain distinctive peaks. 00133 % 00134 % The format of the AdaptiveThresholdImage method is: 00135 % 00136 % Image *AdaptiveThresholdImage(const Image *image,const size_t width, 00137 % const size_t height,const double bias,ExceptionInfo *exception) 00138 % 00139 % A description of each parameter follows: 00140 % 00141 % o image: the image. 00142 % 00143 % o width: the width of the local neighborhood. 00144 % 00145 % o height: the height of the local neighborhood. 00146 % 00147 % o bias: the mean bias. 00148 % 00149 % o exception: return any errors or warnings in this structure. 00150 % 00151 */ 00152 MagickExport Image *AdaptiveThresholdImage(const Image *image, 00153 const size_t width,const size_t height,const double bias, 00154 ExceptionInfo *exception) 00155 { 00156 #define AdaptiveThresholdImageTag "AdaptiveThreshold/Image" 00157 00158 CacheView 00159 *image_view, 00160 *threshold_view; 00161 00162 Image 00163 *threshold_image; 00164 00165 MagickBooleanType 00166 status; 00167 00168 MagickOffsetType 00169 progress; 00170 00171 MagickSizeType 00172 number_pixels; 00173 00174 ssize_t 00175 y; 00176 00177 /* 00178 Initialize threshold image attributes. 00179 */ 00180 assert(image != (Image *) NULL); 00181 assert(image->signature == MagickSignature); 00182 if (image->debug != MagickFalse) 00183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00184 assert(exception != (ExceptionInfo *) NULL); 00185 assert(exception->signature == MagickSignature); 00186 if ((width % 2) == 0) 00187 ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber"); 00188 threshold_image=CloneImage(image,image->columns,image->rows,MagickTrue, 00189 exception); 00190 if (threshold_image == (Image *) NULL) 00191 return((Image *) NULL); 00192 status=SetImageStorageClass(threshold_image,DirectClass,exception); 00193 if (status == MagickFalse) 00194 { 00195 threshold_image=DestroyImage(threshold_image); 00196 return((Image *) NULL); 00197 } 00198 /* 00199 Threshold image. 00200 */ 00201 status=MagickTrue; 00202 progress=0; 00203 number_pixels=(MagickSizeType) width*height; 00204 image_view=AcquireCacheView(image); 00205 threshold_view=AcquireCacheView(threshold_image); 00206 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00207 #pragma omp parallel for schedule(static,4) shared(progress,status) 00208 #endif 00209 for (y=0; y < (ssize_t) image->rows; y++) 00210 { 00211 register const Quantum 00212 *restrict p; 00213 00214 register Quantum 00215 *restrict q; 00216 00217 register ssize_t 00218 x; 00219 00220 ssize_t 00221 center; 00222 00223 if (status == MagickFalse) 00224 continue; 00225 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) 00226 (height/2L),image->columns+width,height,exception); 00227 q=QueueCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns, 00228 1,exception); 00229 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00230 { 00231 status=MagickFalse; 00232 continue; 00233 } 00234 center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(height/2L)+ 00235 GetPixelChannels(image)*(width/2); 00236 for (x=0; x < (ssize_t) image->columns; x++) 00237 { 00238 register ssize_t 00239 i; 00240 00241 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00242 { 00243 MagickRealType 00244 mean, 00245 pixel; 00246 00247 PixelChannel 00248 channel; 00249 00250 PixelTrait 00251 threshold_traits, 00252 traits; 00253 00254 register const Quantum 00255 *restrict pixels; 00256 00257 register ssize_t 00258 u; 00259 00260 ssize_t 00261 v; 00262 00263 channel=GetPixelChannelMapChannel(image,i); 00264 traits=GetPixelChannelMapTraits(image,channel); 00265 threshold_traits=GetPixelChannelMapTraits(threshold_image,channel); 00266 if ((traits == UndefinedPixelTrait) || 00267 (threshold_traits == UndefinedPixelTrait)) 00268 continue; 00269 if (((threshold_traits & CopyPixelTrait) != 0) || 00270 (GetPixelMask(image,p) != 0)) 00271 { 00272 SetPixelChannel(threshold_image,channel,p[center+i],q); 00273 continue; 00274 } 00275 pixels=p; 00276 pixel=0.0; 00277 for (v=0; v < (ssize_t) height; v++) 00278 { 00279 for (u=0; u < (ssize_t) width; u++) 00280 { 00281 pixel+=pixels[i]; 00282 pixels+=GetPixelChannels(image); 00283 } 00284 pixels+=image->columns*GetPixelChannels(image); 00285 } 00286 mean=(MagickRealType) (pixel/number_pixels+bias); 00287 SetPixelChannel(threshold_image,channel,(Quantum) ((MagickRealType) 00288 p[center+i] <= mean ? 0 : QuantumRange),q); 00289 } 00290 p+=GetPixelChannels(image); 00291 q+=GetPixelChannels(threshold_image); 00292 } 00293 if (SyncCacheViewAuthenticPixels(threshold_view,exception) == MagickFalse) 00294 status=MagickFalse; 00295 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00296 { 00297 MagickBooleanType 00298 proceed; 00299 00300 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00301 #pragma omp critical (MagickCore_AdaptiveThresholdImage) 00302 #endif 00303 proceed=SetImageProgress(image,AdaptiveThresholdImageTag,progress++, 00304 image->rows); 00305 if (proceed == MagickFalse) 00306 status=MagickFalse; 00307 } 00308 } 00309 threshold_image->type=image->type; 00310 threshold_view=DestroyCacheView(threshold_view); 00311 image_view=DestroyCacheView(image_view); 00312 if (status == MagickFalse) 00313 threshold_image=DestroyImage(threshold_image); 00314 return(threshold_image); 00315 } 00316 00317 /* 00318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00319 % % 00320 % % 00321 % % 00322 % B i l e v e l I m a g e % 00323 % % 00324 % % 00325 % % 00326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00327 % 00328 % BilevelImage() changes the value of individual pixels based on the 00329 % intensity of each pixel channel. The result is a high-contrast image. 00330 % 00331 % More precisely each channel value of the image is 'thresholded' so that if 00332 % it is equal to or less than the given value it is set to zero, while any 00333 % value greater than that give is set to it maximum or QuantumRange. 00334 % 00335 % This function is what is used to implement the "-threshold" operator for 00336 % the command line API. 00337 % 00338 % If the default channel setting is given the image is thresholded using just 00339 % the gray 'intensity' of the image, rather than the individual channels. 00340 % 00341 % The format of the BilevelImage method is: 00342 % 00343 % MagickBooleanType BilevelImage(Image *image,const double threshold, 00344 % ExceptionInfo *exception) 00345 % 00346 % A description of each parameter follows: 00347 % 00348 % o image: the image. 00349 % 00350 % o threshold: define the threshold values. 00351 % 00352 % o exception: return any errors or warnings in this structure. 00353 % 00354 % Aside: You can get the same results as operator using LevelImages() 00355 % with the 'threshold' value for both the black_point and the white_point. 00356 % 00357 */ 00358 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold, 00359 ExceptionInfo *exception) 00360 { 00361 #define ThresholdImageTag "Threshold/Image" 00362 00363 CacheView 00364 *image_view; 00365 00366 MagickBooleanType 00367 status; 00368 00369 MagickOffsetType 00370 progress; 00371 00372 ssize_t 00373 y; 00374 00375 assert(image != (Image *) NULL); 00376 assert(image->signature == MagickSignature); 00377 if (image->debug != MagickFalse) 00378 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00379 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 00380 return(MagickFalse); 00381 /* 00382 Bilevel threshold image. 00383 */ 00384 status=MagickTrue; 00385 progress=0; 00386 image_view=AcquireCacheView(image); 00387 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00388 #pragma omp parallel for schedule(static,8) shared(progress,status) 00389 #endif 00390 for (y=0; y < (ssize_t) image->rows; y++) 00391 { 00392 register ssize_t 00393 x; 00394 00395 register Quantum 00396 *restrict q; 00397 00398 if (status == MagickFalse) 00399 continue; 00400 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 00401 if (q == (Quantum *) NULL) 00402 { 00403 status=MagickFalse; 00404 continue; 00405 } 00406 for (x=0; x < (ssize_t) image->columns; x++) 00407 { 00408 register ssize_t 00409 i; 00410 00411 if (GetPixelMask(image,q) != 0) 00412 { 00413 q+=GetPixelChannels(image); 00414 continue; 00415 } 00416 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00417 { 00418 PixelChannel 00419 channel; 00420 00421 PixelTrait 00422 traits; 00423 00424 channel=GetPixelChannelMapChannel(image,i); 00425 traits=GetPixelChannelMapTraits(image,channel); 00426 if ((traits & UpdatePixelTrait) == 0) 00427 continue; 00428 q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 : QuantumRange); 00429 } 00430 q+=GetPixelChannels(image); 00431 } 00432 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 00433 status=MagickFalse; 00434 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00435 { 00436 MagickBooleanType 00437 proceed; 00438 00439 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00440 #pragma omp critical (MagickCore_BilevelImage) 00441 #endif 00442 proceed=SetImageProgress(image,ThresholdImageTag,progress++, 00443 image->rows); 00444 if (proceed == MagickFalse) 00445 status=MagickFalse; 00446 } 00447 } 00448 image_view=DestroyCacheView(image_view); 00449 return(status); 00450 } 00451 00452 /* 00453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00454 % % 00455 % % 00456 % % 00457 % B l a c k T h r e s h o l d I m a g e % 00458 % % 00459 % % 00460 % % 00461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00462 % 00463 % BlackThresholdImage() is like ThresholdImage() but forces all pixels below 00464 % the threshold into black while leaving all pixels at or above the threshold 00465 % unchanged. 00466 % 00467 % The format of the BlackThresholdImage method is: 00468 % 00469 % MagickBooleanType BlackThresholdImage(Image *image, 00470 % const char *threshold,ExceptionInfo *exception) 00471 % 00472 % A description of each parameter follows: 00473 % 00474 % o image: the image. 00475 % 00476 % o threshold: define the threshold value. 00477 % 00478 % o exception: return any errors or warnings in this structure. 00479 % 00480 */ 00481 MagickExport MagickBooleanType BlackThresholdImage(Image *image, 00482 const char *thresholds,ExceptionInfo *exception) 00483 { 00484 #define ThresholdImageTag "Threshold/Image" 00485 00486 CacheView 00487 *image_view; 00488 00489 GeometryInfo 00490 geometry_info; 00491 00492 MagickBooleanType 00493 status; 00494 00495 MagickOffsetType 00496 progress; 00497 00498 MagickRealType 00499 threshold[5]; 00500 00501 MagickStatusType 00502 flags; 00503 00504 register ssize_t 00505 i; 00506 00507 ssize_t 00508 y; 00509 00510 assert(image != (Image *) NULL); 00511 assert(image->signature == MagickSignature); 00512 if (image->debug != MagickFalse) 00513 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00514 if (thresholds == (const char *) NULL) 00515 return(MagickTrue); 00516 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 00517 return(MagickFalse); 00518 flags=ParseGeometry(thresholds,&geometry_info); 00519 for (i=0; i < 5; i++) 00520 threshold[i]=geometry_info.rho; 00521 if ((flags & SigmaValue) != 0) 00522 threshold[1]=geometry_info.sigma; 00523 if ((flags & XiValue) != 0) 00524 threshold[2]=geometry_info.xi; 00525 if ((flags & PsiValue) != 0) 00526 threshold[3]=geometry_info.psi; 00527 if ((flags & ChiValue) != 0) 00528 threshold[4]=geometry_info.chi; 00529 if ((flags & PercentValue) != 0) 00530 for (i=0; i < 5; i++) 00531 threshold[i]*=(QuantumRange/100.0); 00532 /* 00533 White threshold image. 00534 */ 00535 status=MagickTrue; 00536 progress=0; 00537 image_view=AcquireCacheView(image); 00538 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00539 #pragma omp parallel for schedule(static,8) shared(progress,status) 00540 #endif 00541 for (y=0; y < (ssize_t) image->rows; y++) 00542 { 00543 register ssize_t 00544 x; 00545 00546 register Quantum 00547 *restrict q; 00548 00549 if (status == MagickFalse) 00550 continue; 00551 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 00552 if (q == (Quantum *) NULL) 00553 { 00554 status=MagickFalse; 00555 continue; 00556 } 00557 for (x=0; x < (ssize_t) image->columns; x++) 00558 { 00559 register ssize_t 00560 i; 00561 00562 ssize_t 00563 n; 00564 00565 if (GetPixelMask(image,q) != 0) 00566 { 00567 q+=GetPixelChannels(image); 00568 continue; 00569 } 00570 n=0; 00571 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00572 { 00573 PixelChannel 00574 channel; 00575 00576 PixelTrait 00577 traits; 00578 00579 channel=GetPixelChannelMapChannel(image,i); 00580 traits=GetPixelChannelMapTraits(image,channel); 00581 if ((traits & UpdatePixelTrait) == 0) 00582 continue; 00583 if ((MagickRealType) q[i] < threshold[n++ % 5]) 00584 q[i]=QuantumRange; 00585 } 00586 q+=GetPixelChannels(image); 00587 } 00588 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 00589 status=MagickFalse; 00590 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00591 { 00592 MagickBooleanType 00593 proceed; 00594 00595 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00596 #pragma omp critical (MagickCore_WhiteThresholdImage) 00597 #endif 00598 proceed=SetImageProgress(image,ThresholdImageTag,progress++, 00599 image->rows); 00600 if (proceed == MagickFalse) 00601 status=MagickFalse; 00602 } 00603 } 00604 image_view=DestroyCacheView(image_view); 00605 return(status); 00606 } 00607 00608 /* 00609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00610 % % 00611 % % 00612 % % 00613 % C l a m p I m a g e % 00614 % % 00615 % % 00616 % % 00617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00618 % 00619 % ClampImage() restricts the color range from 0 to the quantum depth. 00620 % 00621 % The format of the ClampImage method is: 00622 % 00623 % MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception) 00624 % 00625 % A description of each parameter follows: 00626 % 00627 % o image: the image. 00628 % 00629 % o exception: return any errors or warnings in this structure. 00630 % 00631 */ 00632 00633 static inline Quantum ClampToUnsignedQuantum(const Quantum quantum) 00634 { 00635 #if defined(MAGICKCORE_HDRI_SUPPORT) 00636 if (quantum <= 0) 00637 return(0); 00638 if (quantum >= QuantumRange) 00639 return(QuantumRange); 00640 return(quantum); 00641 #else 00642 return(quantum); 00643 #endif 00644 } 00645 00646 MagickExport MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception) 00647 { 00648 #define ClampImageTag "Clamp/Image" 00649 00650 CacheView 00651 *image_view; 00652 00653 MagickBooleanType 00654 status; 00655 00656 MagickOffsetType 00657 progress; 00658 00659 ssize_t 00660 y; 00661 00662 assert(image != (Image *) NULL); 00663 assert(image->signature == MagickSignature); 00664 if (image->debug != MagickFalse) 00665 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00666 if (image->storage_class == PseudoClass) 00667 { 00668 register ssize_t 00669 i; 00670 00671 register PixelInfo 00672 *restrict q; 00673 00674 q=image->colormap; 00675 for (i=0; i < (ssize_t) image->colors; i++) 00676 { 00677 q->red=ClampToUnsignedQuantum(q->red); 00678 q->green=ClampToUnsignedQuantum(q->green); 00679 q->blue=ClampToUnsignedQuantum(q->blue); 00680 q->alpha=ClampToUnsignedQuantum(q->alpha); 00681 q++; 00682 } 00683 return(SyncImage(image,exception)); 00684 } 00685 /* 00686 Clamp image. 00687 */ 00688 status=MagickTrue; 00689 progress=0; 00690 image_view=AcquireCacheView(image); 00691 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00692 #pragma omp parallel for schedule(static,8) shared(progress,status) 00693 #endif 00694 for (y=0; y < (ssize_t) image->rows; y++) 00695 { 00696 register ssize_t 00697 x; 00698 00699 register Quantum 00700 *restrict q; 00701 00702 if (status == MagickFalse) 00703 continue; 00704 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 00705 if (q == (Quantum *) NULL) 00706 { 00707 status=MagickFalse; 00708 continue; 00709 } 00710 for (x=0; x < (ssize_t) image->columns; x++) 00711 { 00712 register ssize_t 00713 i; 00714 00715 if (GetPixelMask(image,q) != 0) 00716 { 00717 q+=GetPixelChannels(image); 00718 continue; 00719 } 00720 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00721 { 00722 PixelChannel 00723 channel; 00724 00725 PixelTrait 00726 traits; 00727 00728 channel=GetPixelChannelMapChannel(image,i); 00729 traits=GetPixelChannelMapTraits(image,channel); 00730 if (traits == UndefinedPixelTrait) 00731 continue; 00732 q[i]=ClampToUnsignedQuantum(q[i]); 00733 } 00734 q+=GetPixelChannels(image); 00735 } 00736 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 00737 status=MagickFalse; 00738 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00739 { 00740 MagickBooleanType 00741 proceed; 00742 00743 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00744 #pragma omp critical (MagickCore_ClampImage) 00745 #endif 00746 proceed=SetImageProgress(image,ClampImageTag,progress++, 00747 image->rows); 00748 if (proceed == MagickFalse) 00749 status=MagickFalse; 00750 } 00751 } 00752 image_view=DestroyCacheView(image_view); 00753 return(status); 00754 } 00755 00756 /* 00757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00758 % % 00759 % % 00760 % % 00761 % D e s t r o y T h r e s h o l d M a p % 00762 % % 00763 % % 00764 % % 00765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00766 % 00767 % DestroyThresholdMap() de-allocate the given ThresholdMap 00768 % 00769 % The format of the ListThresholdMaps method is: 00770 % 00771 % ThresholdMap *DestroyThresholdMap(Threshold *map) 00772 % 00773 % A description of each parameter follows. 00774 % 00775 % o map: Pointer to the Threshold map to destroy 00776 % 00777 */ 00778 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map) 00779 { 00780 assert(map != (ThresholdMap *) NULL); 00781 if (map->map_id != (char *) NULL) 00782 map->map_id=DestroyString(map->map_id); 00783 if (map->description != (char *) NULL) 00784 map->description=DestroyString(map->description); 00785 if (map->levels != (ssize_t *) NULL) 00786 map->levels=(ssize_t *) RelinquishMagickMemory(map->levels); 00787 map=(ThresholdMap *) RelinquishMagickMemory(map); 00788 return(map); 00789 } 00790 00791 /* 00792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00793 % % 00794 % % 00795 % % 00796 % G e t T h r e s h o l d M a p % 00797 % % 00798 % % 00799 % % 00800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00801 % 00802 % GetThresholdMap() loads and searches one or more threshold map files for the 00803 % map matching the given name or alias. 00804 % 00805 % The format of the GetThresholdMap method is: 00806 % 00807 % ThresholdMap *GetThresholdMap(const char *map_id, 00808 % ExceptionInfo *exception) 00809 % 00810 % A description of each parameter follows. 00811 % 00812 % o map_id: ID of the map to look for. 00813 % 00814 % o exception: return any errors or warnings in this structure. 00815 % 00816 */ 00817 MagickExport ThresholdMap *GetThresholdMap(const char *map_id, 00818 ExceptionInfo *exception) 00819 { 00820 const StringInfo 00821 *option; 00822 00823 LinkedListInfo 00824 *options; 00825 00826 ThresholdMap 00827 *map; 00828 00829 map=(ThresholdMap *)NULL; 00830 options=GetConfigureOptions(ThresholdsFilename,exception); 00831 while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) != 00832 (const StringInfo *) NULL && (map == (ThresholdMap *) NULL)) 00833 map=GetThresholdMapFile((const char *) GetStringInfoDatum(option), 00834 GetStringInfoPath(option),map_id,exception); 00835 options=DestroyConfigureOptions(options); 00836 return(map); 00837 } 00838 00839 /* 00840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00841 % % 00842 % % 00843 % % 00844 + G e t T h r e s h o l d M a p F i l e % 00845 % % 00846 % % 00847 % % 00848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00849 % 00850 % GetThresholdMapFile() look for a given threshold map name or alias in the 00851 % given XML file data, and return the allocated the map when found. 00852 % 00853 % The format of the ListThresholdMaps method is: 00854 % 00855 % ThresholdMap *GetThresholdMap(const char *xml,const char *filename, 00856 % const char *map_id,ExceptionInfo *exception) 00857 % 00858 % A description of each parameter follows. 00859 % 00860 % o xml: The threshold map list in XML format. 00861 % 00862 % o filename: The threshold map XML filename. 00863 % 00864 % o map_id: ID of the map to look for in XML list. 00865 % 00866 % o exception: return any errors or warnings in this structure. 00867 % 00868 */ 00869 static ThresholdMap *GetThresholdMapFile(const char *xml, 00870 const char *filename,const char *map_id,ExceptionInfo *exception) 00871 { 00872 char 00873 *p; 00874 00875 const char 00876 *attribute, 00877 *content; 00878 00879 double 00880 value; 00881 00882 register ssize_t 00883 i; 00884 00885 ThresholdMap 00886 *map; 00887 00888 XMLTreeInfo 00889 *description, 00890 *levels, 00891 *threshold, 00892 *thresholds; 00893 00894 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 00895 "Loading threshold map file \"%s\" ...",filename); 00896 map=(ThresholdMap *) NULL; 00897 thresholds=NewXMLTree(xml,exception); 00898 if (thresholds == (XMLTreeInfo *) NULL) 00899 return(map); 00900 for (threshold=GetXMLTreeChild(thresholds,"threshold"); 00901 threshold != (XMLTreeInfo *) NULL; 00902 threshold=GetNextXMLTreeTag(threshold)) 00903 { 00904 attribute=GetXMLTreeAttribute(threshold,"map"); 00905 if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0)) 00906 break; 00907 attribute=GetXMLTreeAttribute(threshold,"alias"); 00908 if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0)) 00909 break; 00910 } 00911 if (threshold == (XMLTreeInfo *) NULL) 00912 return(map); 00913 description=GetXMLTreeChild(threshold,"description"); 00914 if (description == (XMLTreeInfo *) NULL) 00915 { 00916 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00917 "XmlMissingElement", "<description>, map \"%s\"",map_id); 00918 thresholds=DestroyXMLTree(thresholds); 00919 return(map); 00920 } 00921 levels=GetXMLTreeChild(threshold,"levels"); 00922 if (levels == (XMLTreeInfo *) NULL) 00923 { 00924 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00925 "XmlMissingElement", "<levels>, map \"%s\"", map_id); 00926 thresholds=DestroyXMLTree(thresholds); 00927 return(map); 00928 } 00929 map=(ThresholdMap *) AcquireMagickMemory(sizeof(ThresholdMap)); 00930 if (map == (ThresholdMap *) NULL) 00931 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap"); 00932 map->map_id=(char *) NULL; 00933 map->description=(char *) NULL; 00934 map->levels=(ssize_t *) NULL; 00935 attribute=GetXMLTreeAttribute(threshold,"map"); 00936 if (attribute != (char *) NULL) 00937 map->map_id=ConstantString(attribute); 00938 content=GetXMLTreeContent(description); 00939 if (content != (char *) NULL) 00940 map->description=ConstantString(content); 00941 attribute=GetXMLTreeAttribute(levels,"width"); 00942 if (attribute == (char *) NULL) 00943 { 00944 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00945 "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id); 00946 thresholds=DestroyXMLTree(thresholds); 00947 map=DestroyThresholdMap(map); 00948 return(map); 00949 } 00950 map->width=StringToUnsignedLong(attribute); 00951 if (map->width == 0) 00952 { 00953 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00954 "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id); 00955 thresholds=DestroyXMLTree(thresholds); 00956 map=DestroyThresholdMap(map); 00957 return(map); 00958 } 00959 attribute=GetXMLTreeAttribute(levels,"height"); 00960 if (attribute == (char *) NULL) 00961 { 00962 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00963 "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id); 00964 thresholds=DestroyXMLTree(thresholds); 00965 map=DestroyThresholdMap(map); 00966 return(map); 00967 } 00968 map->height=StringToUnsignedLong(attribute); 00969 if (map->height == 0) 00970 { 00971 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00972 "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id); 00973 thresholds=DestroyXMLTree(thresholds); 00974 map=DestroyThresholdMap(map); 00975 return(map); 00976 } 00977 attribute=GetXMLTreeAttribute(levels,"divisor"); 00978 if (attribute == (char *) NULL) 00979 { 00980 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00981 "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id); 00982 thresholds=DestroyXMLTree(thresholds); 00983 map=DestroyThresholdMap(map); 00984 return(map); 00985 } 00986 map->divisor=(ssize_t) StringToLong(attribute); 00987 if (map->divisor < 2) 00988 { 00989 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00990 "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id); 00991 thresholds=DestroyXMLTree(thresholds); 00992 map=DestroyThresholdMap(map); 00993 return(map); 00994 } 00995 content=GetXMLTreeContent(levels); 00996 if (content == (char *) NULL) 00997 { 00998 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 00999 "XmlMissingContent", "<levels>, map \"%s\"",map_id); 01000 thresholds=DestroyXMLTree(thresholds); 01001 map=DestroyThresholdMap(map); 01002 return(map); 01003 } 01004 map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height* 01005 sizeof(*map->levels)); 01006 if (map->levels == (ssize_t *) NULL) 01007 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap"); 01008 for (i=0; i < (ssize_t) (map->width*map->height); i++) 01009 { 01010 map->levels[i]=(ssize_t) strtol(content,&p,10); 01011 if (p == content) 01012 { 01013 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01014 "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id); 01015 thresholds=DestroyXMLTree(thresholds); 01016 map=DestroyThresholdMap(map); 01017 return(map); 01018 } 01019 if ((map->levels[i] < 0) || (map->levels[i] > map->divisor)) 01020 { 01021 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01022 "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"", 01023 (double) map->levels[i],map_id); 01024 thresholds=DestroyXMLTree(thresholds); 01025 map=DestroyThresholdMap(map); 01026 return(map); 01027 } 01028 content=p; 01029 } 01030 value=(double) strtol(content,&p,10); 01031 (void) value; 01032 if (p != content) 01033 { 01034 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01035 "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id); 01036 thresholds=DestroyXMLTree(thresholds); 01037 map=DestroyThresholdMap(map); 01038 return(map); 01039 } 01040 thresholds=DestroyXMLTree(thresholds); 01041 return(map); 01042 } 01043 01044 /* 01045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01046 % % 01047 % % 01048 % % 01049 + L i s t T h r e s h o l d M a p F i l e % 01050 % % 01051 % % 01052 % % 01053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01054 % 01055 % ListThresholdMapFile() lists the threshold maps and their descriptions 01056 % in the given XML file data. 01057 % 01058 % The format of the ListThresholdMaps method is: 01059 % 01060 % MagickBooleanType ListThresholdMaps(FILE *file,const char*xml, 01061 % const char *filename,ExceptionInfo *exception) 01062 % 01063 % A description of each parameter follows. 01064 % 01065 % o file: An pointer to the output FILE. 01066 % 01067 % o xml: The threshold map list in XML format. 01068 % 01069 % o filename: The threshold map XML filename. 01070 % 01071 % o exception: return any errors or warnings in this structure. 01072 % 01073 */ 01074 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml, 01075 const char *filename,ExceptionInfo *exception) 01076 { 01077 const char 01078 *alias, 01079 *content, 01080 *map; 01081 01082 XMLTreeInfo 01083 *description, 01084 *threshold, 01085 *thresholds; 01086 01087 assert( xml != (char *)NULL ); 01088 assert( file != (FILE *)NULL ); 01089 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 01090 "Loading threshold map file \"%s\" ...",filename); 01091 thresholds=NewXMLTree(xml,exception); 01092 if ( thresholds == (XMLTreeInfo *)NULL ) 01093 return(MagickFalse); 01094 (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description"); 01095 (void) FormatLocaleFile(file, 01096 "----------------------------------------------------\n"); 01097 threshold=GetXMLTreeChild(thresholds,"threshold"); 01098 for ( ; threshold != (XMLTreeInfo *) NULL; 01099 threshold=GetNextXMLTreeTag(threshold)) 01100 { 01101 map=GetXMLTreeAttribute(threshold,"map"); 01102 if (map == (char *) NULL) 01103 { 01104 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01105 "XmlMissingAttribute", "<map>"); 01106 thresholds=DestroyXMLTree(thresholds); 01107 return(MagickFalse); 01108 } 01109 alias=GetXMLTreeAttribute(threshold,"alias"); 01110 description=GetXMLTreeChild(threshold,"description"); 01111 if (description == (XMLTreeInfo *) NULL) 01112 { 01113 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01114 "XmlMissingElement", "<description>, map \"%s\"",map); 01115 thresholds=DestroyXMLTree(thresholds); 01116 return(MagickFalse); 01117 } 01118 content=GetXMLTreeContent(description); 01119 if (content == (char *) NULL) 01120 { 01121 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01122 "XmlMissingContent", "<description>, map \"%s\"", map); 01123 thresholds=DestroyXMLTree(thresholds); 01124 return(MagickFalse); 01125 } 01126 (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "", 01127 content); 01128 } 01129 thresholds=DestroyXMLTree(thresholds); 01130 return(MagickTrue); 01131 } 01132 01133 /* 01134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01135 % % 01136 % % 01137 % % 01138 % L i s t T h r e s h o l d M a p s % 01139 % % 01140 % % 01141 % % 01142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01143 % 01144 % ListThresholdMaps() lists the threshold maps and their descriptions 01145 % as defined by "threshold.xml" to a file. 01146 % 01147 % The format of the ListThresholdMaps method is: 01148 % 01149 % MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception) 01150 % 01151 % A description of each parameter follows. 01152 % 01153 % o file: An pointer to the output FILE. 01154 % 01155 % o exception: return any errors or warnings in this structure. 01156 % 01157 */ 01158 MagickExport MagickBooleanType ListThresholdMaps(FILE *file, 01159 ExceptionInfo *exception) 01160 { 01161 const StringInfo 01162 *option; 01163 01164 LinkedListInfo 01165 *options; 01166 01167 MagickStatusType 01168 status; 01169 01170 status=MagickFalse; 01171 if (file == (FILE *) NULL) 01172 file=stdout; 01173 options=GetConfigureOptions(ThresholdsFilename,exception); 01174 (void) FormatLocaleFile(file, 01175 "\n Threshold Maps for Ordered Dither Operations\n"); 01176 while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) != 01177 (const StringInfo *) NULL) 01178 { 01179 (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option)); 01180 status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option), 01181 GetStringInfoPath(option),exception); 01182 } 01183 options=DestroyConfigureOptions(options); 01184 return(status != 0 ? MagickTrue : MagickFalse); 01185 } 01186 01187 /* 01188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01189 % % 01190 % % 01191 % % 01192 % O r d e r e d P o s t e r i z e I m a g e % 01193 % % 01194 % % 01195 % % 01196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01197 % 01198 % OrderedPosterizeImage() will perform a ordered dither based on a number 01199 % of pre-defined dithering threshold maps, but over multiple intensity 01200 % levels, which can be different for different channels, according to the 01201 % input argument. 01202 % 01203 % The format of the OrderedPosterizeImage method is: 01204 % 01205 % MagickBooleanType OrderedPosterizeImage(Image *image, 01206 % const char *threshold_map,ExceptionInfo *exception) 01207 % 01208 % A description of each parameter follows: 01209 % 01210 % o image: the image. 01211 % 01212 % o threshold_map: A string containing the name of the threshold dither 01213 % map to use, followed by zero or more numbers representing the number 01214 % of color levels tho dither between. 01215 % 01216 % Any level number less than 2 will be equivalent to 2, and means only 01217 % binary dithering will be applied to each color channel. 01218 % 01219 % No numbers also means a 2 level (bitmap) dither will be applied to all 01220 % channels, while a single number is the number of levels applied to each 01221 % channel in sequence. More numbers will be applied in turn to each of 01222 % the color channels. 01223 % 01224 % For example: "o3x3,6" will generate a 6 level posterization of the 01225 % image with a ordered 3x3 diffused pixel dither being applied between 01226 % each level. While checker,8,8,4 will produce a 332 colormaped image 01227 % with only a single checkerboard hash pattern (50% grey) between each 01228 % color level, to basically double the number of color levels with 01229 % a bare minimim of dithering. 01230 % 01231 % o exception: return any errors or warnings in this structure. 01232 % 01233 */ 01234 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image, 01235 const char *threshold_map,ExceptionInfo *exception) 01236 { 01237 #define DitherImageTag "Dither/Image" 01238 01239 CacheView 01240 *image_view; 01241 01242 char 01243 token[MaxTextExtent]; 01244 01245 const char 01246 *p; 01247 01248 MagickBooleanType 01249 status; 01250 01251 MagickOffsetType 01252 progress; 01253 01254 MagickRealType 01255 levels[CompositePixelChannel]; 01256 01257 register ssize_t 01258 i; 01259 01260 ssize_t 01261 y; 01262 01263 ThresholdMap 01264 *map; 01265 01266 assert(image != (Image *) NULL); 01267 assert(image->signature == MagickSignature); 01268 if (image->debug != MagickFalse) 01269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01270 assert(exception != (ExceptionInfo *) NULL); 01271 assert(exception->signature == MagickSignature); 01272 if (threshold_map == (const char *) NULL) 01273 return(MagickTrue); 01274 p=(char *) threshold_map; 01275 while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) && 01276 (*p != '\0')) 01277 p++; 01278 threshold_map=p; 01279 while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) && 01280 (*p != '\0')) 01281 { 01282 if ((p-threshold_map) >= (MaxTextExtent-1)) 01283 break; 01284 token[p-threshold_map]=(*p); 01285 p++; 01286 } 01287 token[p-threshold_map]='\0'; 01288 map=GetThresholdMap(token,exception); 01289 if (map == (ThresholdMap *) NULL) 01290 { 01291 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01292 "InvalidArgument","%s : '%s'","ordered-dither",threshold_map); 01293 return(MagickFalse); 01294 } 01295 for (i=0; i < MaxPixelChannels; i++) 01296 levels[i]=2.0; 01297 p=strchr((char *) threshold_map,','); 01298 if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0)) 01299 for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++) 01300 { 01301 GetMagickToken(p,&p,token); 01302 if (*token == ',') 01303 GetMagickToken(p,&p,token); 01304 levels[i]=StringToDouble(token,(char **) NULL); 01305 } 01306 for (i=0; i < MaxPixelChannels; i++) 01307 if (fabs(levels[i]) >= 1) 01308 levels[i]-=1.0; 01309 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 01310 return(MagickFalse); 01311 status=MagickTrue; 01312 progress=0; 01313 image_view=AcquireCacheView(image); 01314 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01315 #pragma omp parallel for schedule(static,8) shared(progress,status) 01316 #endif 01317 for (y=0; y < (ssize_t) image->rows; y++) 01318 { 01319 register ssize_t 01320 x; 01321 01322 register Quantum 01323 *restrict q; 01324 01325 if (status == MagickFalse) 01326 continue; 01327 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 01328 if (q == (Quantum *) NULL) 01329 { 01330 status=MagickFalse; 01331 continue; 01332 } 01333 for (x=0; x < (ssize_t) image->columns; x++) 01334 { 01335 register ssize_t 01336 i; 01337 01338 ssize_t 01339 n; 01340 01341 n=0; 01342 if (GetPixelMask(image,q) != 0) 01343 { 01344 q+=GetPixelChannels(image); 01345 continue; 01346 } 01347 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01348 { 01349 PixelChannel 01350 channel; 01351 01352 PixelTrait 01353 traits; 01354 01355 ssize_t 01356 level, 01357 threshold; 01358 01359 channel=GetPixelChannelMapChannel(image,i); 01360 traits=GetPixelChannelMapTraits(image,channel); 01361 if ((traits & UpdatePixelTrait) == 0) 01362 continue; 01363 if (fabs(levels[n++]) < MagickEpsilon) 01364 continue; 01365 threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1)); 01366 level=threshold/(map->divisor-1); 01367 threshold-=level*(map->divisor-1); 01368 q[i]=RoundToQuantum((level+(threshold >= map->levels[(x % map->width)+ 01369 map->width*(y % map->height)]))*QuantumRange/levels[n]); 01370 n++; 01371 } 01372 q+=GetPixelChannels(image); 01373 } 01374 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 01375 status=MagickFalse; 01376 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01377 { 01378 MagickBooleanType 01379 proceed; 01380 01381 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01382 #pragma omp critical (MagickCore_OrderedPosterizeImage) 01383 #endif 01384 proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows); 01385 if (proceed == MagickFalse) 01386 status=MagickFalse; 01387 } 01388 } 01389 image_view=DestroyCacheView(image_view); 01390 map=DestroyThresholdMap(map); 01391 return(MagickTrue); 01392 } 01393 01394 /* 01395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01396 % % 01397 % % 01398 % % 01399 % R a n d o m T h r e s h o l d I m a g e % 01400 % % 01401 % % 01402 % % 01403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01404 % 01405 % RandomThresholdImage() changes the value of individual pixels based on the 01406 % intensity of each pixel compared to a random threshold. The result is a 01407 % low-contrast, two color image. 01408 % 01409 % The format of the RandomThresholdImage method is: 01410 % 01411 % MagickBooleanType RandomThresholdImage(Image *image, 01412 % const char *thresholds,ExceptionInfo *exception) 01413 % 01414 % A description of each parameter follows: 01415 % 01416 % o image: the image. 01417 % 01418 % o thresholds: a geometry string containing low,high thresholds. If the 01419 % string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4 01420 % is performed instead. 01421 % 01422 % o exception: return any errors or warnings in this structure. 01423 % 01424 */ 01425 MagickExport MagickBooleanType RandomThresholdImage(Image *image, 01426 const char *thresholds,ExceptionInfo *exception) 01427 { 01428 #define ThresholdImageTag "Threshold/Image" 01429 01430 CacheView 01431 *image_view; 01432 01433 GeometryInfo 01434 geometry_info; 01435 01436 MagickStatusType 01437 flags; 01438 01439 MagickBooleanType 01440 status; 01441 01442 MagickOffsetType 01443 progress; 01444 01445 PixelInfo 01446 threshold; 01447 01448 MagickRealType 01449 min_threshold, 01450 max_threshold; 01451 01452 RandomInfo 01453 **restrict random_info; 01454 01455 ssize_t 01456 y; 01457 01458 assert(image != (Image *) NULL); 01459 assert(image->signature == MagickSignature); 01460 if (image->debug != MagickFalse) 01461 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01462 assert(exception != (ExceptionInfo *) NULL); 01463 assert(exception->signature == MagickSignature); 01464 if (thresholds == (const char *) NULL) 01465 return(MagickTrue); 01466 GetPixelInfo(image,&threshold); 01467 min_threshold=0.0; 01468 max_threshold=(MagickRealType) QuantumRange; 01469 flags=ParseGeometry(thresholds,&geometry_info); 01470 min_threshold=geometry_info.rho; 01471 max_threshold=geometry_info.sigma; 01472 if ((flags & SigmaValue) == 0) 01473 max_threshold=min_threshold; 01474 if (strchr(thresholds,'%') != (char *) NULL) 01475 { 01476 max_threshold*=(MagickRealType) (0.01*QuantumRange); 01477 min_threshold*=(MagickRealType) (0.01*QuantumRange); 01478 } 01479 /* 01480 Random threshold image. 01481 */ 01482 status=MagickTrue; 01483 progress=0; 01484 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 01485 return(MagickFalse); 01486 random_info=AcquireRandomInfoThreadSet(); 01487 image_view=AcquireCacheView(image); 01488 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01489 #pragma omp parallel for schedule(static,8) shared(progress,status) 01490 #endif 01491 for (y=0; y < (ssize_t) image->rows; y++) 01492 { 01493 const int 01494 id = GetOpenMPThreadId(); 01495 01496 register Quantum 01497 *restrict q; 01498 01499 register ssize_t 01500 x; 01501 01502 if (status == MagickFalse) 01503 continue; 01504 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 01505 if (q == (Quantum *) NULL) 01506 { 01507 status=MagickFalse; 01508 continue; 01509 } 01510 for (x=0; x < (ssize_t) image->columns; x++) 01511 { 01512 register ssize_t 01513 i; 01514 01515 if (GetPixelMask(image,q) != 0) 01516 { 01517 q+=GetPixelChannels(image); 01518 continue; 01519 } 01520 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01521 { 01522 MagickRealType 01523 threshold; 01524 01525 PixelChannel 01526 channel; 01527 01528 PixelTrait 01529 traits; 01530 01531 channel=GetPixelChannelMapChannel(image,i); 01532 traits=GetPixelChannelMapTraits(image,channel); 01533 if ((traits & UpdatePixelTrait) == 0) 01534 continue; 01535 if ((MagickRealType) q[i] < min_threshold) 01536 threshold=min_threshold; 01537 else 01538 if ((MagickRealType) q[i] > max_threshold) 01539 threshold=max_threshold; 01540 else 01541 threshold=(MagickRealType) (QuantumRange* 01542 GetPseudoRandomValue(random_info[id])); 01543 q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 : 01544 QuantumRange); 01545 } 01546 q+=GetPixelChannels(image); 01547 } 01548 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 01549 status=MagickFalse; 01550 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01551 { 01552 MagickBooleanType 01553 proceed; 01554 01555 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01556 #pragma omp critical (MagickCore_RandomThresholdImage) 01557 #endif 01558 proceed=SetImageProgress(image,ThresholdImageTag,progress++, 01559 image->rows); 01560 if (proceed == MagickFalse) 01561 status=MagickFalse; 01562 } 01563 } 01564 image_view=DestroyCacheView(image_view); 01565 random_info=DestroyRandomInfoThreadSet(random_info); 01566 return(status); 01567 } 01568 01569 /* 01570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01571 % % 01572 % % 01573 % % 01574 % W h i t e T h r e s h o l d I m a g e % 01575 % % 01576 % % 01577 % % 01578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01579 % 01580 % WhiteThresholdImage() is like ThresholdImage() but forces all pixels above 01581 % the threshold into white while leaving all pixels at or below the threshold 01582 % unchanged. 01583 % 01584 % The format of the WhiteThresholdImage method is: 01585 % 01586 % MagickBooleanType WhiteThresholdImage(Image *image, 01587 % const char *threshold,ExceptionInfo *exception) 01588 % 01589 % A description of each parameter follows: 01590 % 01591 % o image: the image. 01592 % 01593 % o threshold: Define the threshold value. 01594 % 01595 % o exception: return any errors or warnings in this structure. 01596 % 01597 */ 01598 MagickExport MagickBooleanType WhiteThresholdImage(Image *image, 01599 const char *thresholds,ExceptionInfo *exception) 01600 { 01601 #define ThresholdImageTag "Threshold/Image" 01602 01603 CacheView 01604 *image_view; 01605 01606 GeometryInfo 01607 geometry_info; 01608 01609 MagickBooleanType 01610 status; 01611 01612 MagickOffsetType 01613 progress; 01614 01615 MagickRealType 01616 threshold[5]; 01617 01618 MagickStatusType 01619 flags; 01620 01621 register ssize_t 01622 i; 01623 01624 ssize_t 01625 y; 01626 01627 assert(image != (Image *) NULL); 01628 assert(image->signature == MagickSignature); 01629 if (image->debug != MagickFalse) 01630 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 01631 if (thresholds == (const char *) NULL) 01632 return(MagickTrue); 01633 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 01634 return(MagickFalse); 01635 flags=ParseGeometry(thresholds,&geometry_info); 01636 for (i=0; i < 5; i++) 01637 threshold[i]=geometry_info.rho; 01638 if ((flags & SigmaValue) != 0) 01639 threshold[1]=geometry_info.sigma; 01640 if ((flags & XiValue) != 0) 01641 threshold[2]=geometry_info.xi; 01642 if ((flags & PsiValue) != 0) 01643 threshold[3]=geometry_info.psi; 01644 if ((flags & ChiValue) != 0) 01645 threshold[4]=geometry_info.chi; 01646 if ((flags & PercentValue) != 0) 01647 for (i=0; i < 5; i++) 01648 threshold[i]*=(QuantumRange/100.0); 01649 /* 01650 White threshold image. 01651 */ 01652 status=MagickTrue; 01653 progress=0; 01654 image_view=AcquireCacheView(image); 01655 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01656 #pragma omp parallel for schedule(static,8) shared(progress,status) 01657 #endif 01658 for (y=0; y < (ssize_t) image->rows; y++) 01659 { 01660 register ssize_t 01661 x; 01662 01663 register Quantum 01664 *restrict q; 01665 01666 if (status == MagickFalse) 01667 continue; 01668 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 01669 if (q == (Quantum *) NULL) 01670 { 01671 status=MagickFalse; 01672 continue; 01673 } 01674 for (x=0; x < (ssize_t) image->columns; x++) 01675 { 01676 register ssize_t 01677 i; 01678 01679 ssize_t 01680 n; 01681 01682 if (GetPixelMask(image,q) != 0) 01683 { 01684 q+=GetPixelChannels(image); 01685 continue; 01686 } 01687 n=0; 01688 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 01689 { 01690 PixelChannel 01691 channel; 01692 01693 PixelTrait 01694 traits; 01695 01696 channel=GetPixelChannelMapChannel(image,i); 01697 traits=GetPixelChannelMapTraits(image,channel); 01698 if ((traits & UpdatePixelTrait) == 0) 01699 continue; 01700 if ((MagickRealType) q[i] > threshold[n++ % 5]) 01701 q[i]=QuantumRange; 01702 } 01703 q+=GetPixelChannels(image); 01704 } 01705 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 01706 status=MagickFalse; 01707 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01708 { 01709 MagickBooleanType 01710 proceed; 01711 01712 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01713 #pragma omp critical (MagickCore_WhiteThresholdImage) 01714 #endif 01715 proceed=SetImageProgress(image,ThresholdImageTag,progress++, 01716 image->rows); 01717 if (proceed == MagickFalse) 01718 status=MagickFalse; 01719 } 01720 } 01721 image_view=DestroyCacheView(image_view); 01722 return(status); 01723 }