00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
#include "magick/studio.h"
00044
#include "magick/attribute.h"
00045
#include "magick/blob.h"
00046
#include "magick/color.h"
00047
#include "magick/color_private.h"
00048
#include "magick/constitute.h"
00049
#include "magick/decorate.h"
00050
#include "magick/draw.h"
00051
#include "magick/enhance.h"
00052
#include "magick/error.h"
00053
#include "magick/error_private.h"
00054
#include "magick/effect.h"
00055
#include "magick/fx.h"
00056
#include "magick/gem.h"
00057
#include "magick/geometry.h"
00058
#include "magick/image_private.h"
00059
#include "magick/list.h"
00060
#include "magick/log.h"
00061
#include "magick/memory_.h"
00062
#include "magick/monitor.h"
00063
#include "magick/montage.h"
00064
#include "magick/quantize.h"
00065
#include "magick/random.h"
00066
#include "magick/resize.h"
00067
#include "magick/resource_.h"
00068
#include "magick/segment.h"
00069
#include "magick/shear.h"
00070
#include "magick/signature.h"
00071
#include "magick/string_.h"
00072
#include "magick/transform.h"
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 MagickExport Image *
AdaptiveThresholdImage(
const Image *image,
00110
const unsigned long width,
const unsigned long height,
const long offset,
00111
ExceptionInfo *
exception)
00112 {
00113
#define ThresholdImageTag "Threshold/Image"
00114
00115
Image
00116 *threshold_image;
00117
00118
IndexPacket
00119 *indexes,
00120 *threshold_indexes;
00121
00122
long
00123 y;
00124
00125
MagickBooleanType
00126 status;
00127
00128
MagickPixelPacket
00129 aggregate,
00130 mean,
00131 zero;
00132
00133
MagickRealType
00134 number_pixels;
00135
00136
register const PixelPacket
00137 *p,
00138 *r;
00139
00140
register long
00141 x,
00142 u,
00143 v;
00144
00145
register PixelPacket
00146 *q;
00147
00148
00149
00150
00151
assert(image != (
const Image *) NULL);
00152
assert(image->
signature ==
MagickSignature);
00153
if (image->
debug !=
MagickFalse)
00154 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00155
assert(exception != (
ExceptionInfo *) NULL);
00156
assert(exception->
signature ==
MagickSignature);
00157
if ((image->
columns < width) || (image->
rows < height))
00158
ThrowImageException(
OptionError,
"ImageSmallerThanRadius");
00159 threshold_image=
CloneImage(image,0,0,
MagickTrue,exception);
00160
if (threshold_image == (
Image *) NULL)
00161
return((
Image *) NULL);
00162 threshold_image->
storage_class=
DirectClass;
00163
00164
00165
00166
GetMagickPixelPacket(image,&mean);
00167 (
void)
ResetMagickMemory(&zero,0,
sizeof(zero));
00168 number_pixels=(
MagickRealType) (width*height);
00169
for (y=0; y < (
long) image->
rows; y++)
00170 {
00171 p=
AcquireImagePixels(image,-(
long) width/2,y-height/2,image->
columns+width,
00172 height,exception);
00173 q=
SetImagePixels(threshold_image,0,y,threshold_image->
columns,1);
00174
if ((p == (
const PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
00175
break;
00176 indexes=
GetIndexes(image);
00177 threshold_indexes=
GetIndexes(threshold_image);
00178
for (x=0; x < (
long) image->
columns; x++)
00179 {
00180 aggregate=zero;
00181 r=p;
00182
for (v=0; v < (
long) height; v++)
00183 {
00184
for (u=0; u < (
long) width; u++)
00185 {
00186 aggregate.
red+=r[u].
red;
00187 aggregate.
green+=r[u].
green;
00188 aggregate.
blue+=r[u].
blue;
00189
if (image->
matte !=
MagickFalse)
00190 aggregate.
opacity+=r[u].
opacity;
00191
if (image->
colorspace ==
CMYKColorspace)
00192 aggregate.
index=(
MagickRealType) indexes[x+(r-p)+u];
00193 }
00194 r+=image->
columns+width;
00195 }
00196 mean.
red=(
MagickRealType) (aggregate.
red/number_pixels+offset);
00197 mean.
green=(
MagickRealType) (aggregate.
green/number_pixels+offset);
00198 mean.
blue=(
MagickRealType) (aggregate.
blue/number_pixels+offset);
00199
if (image->
matte !=
MagickFalse)
00200 mean.
opacity=(
MagickRealType) (aggregate.
opacity/number_pixels+offset);
00201
if (image->
colorspace ==
CMYKColorspace)
00202 mean.
index=(
MagickRealType) (aggregate.
index/number_pixels+offset);
00203 q->
red=(
Quantum) (((
MagickRealType) q->
red <= mean.
red) ? 0 :
MaxRGB);
00204 q->
green=(
Quantum)
00205 (((
MagickRealType) q->
green <= mean.
green) ? 0 :
MaxRGB);
00206 q->
blue=(
Quantum) (((
MagickRealType) q->
blue <= mean.
blue) ? 0 :
MaxRGB);
00207
if (image->
matte !=
MagickFalse)
00208 q->
opacity=(
Quantum)
00209 (((
MagickRealType) q->
opacity <= mean.
opacity) ? 0 :
MaxRGB);
00210
if (image->
colorspace ==
CMYKColorspace)
00211 threshold_indexes[x]=(
IndexPacket)
00212 (((
MagickRealType) threshold_indexes[x] <= mean.
index) ? 0 :
MaxRGB);
00213 p++;
00214 q++;
00215 }
00216
if (
SyncImagePixels(threshold_image) ==
MagickFalse)
00217
break;
00218
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00219 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00220 {
00221 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
00222 image->
client_data);
00223
if (status ==
MagickFalse)
00224
break;
00225 }
00226 }
00227
return(threshold_image);
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 static inline Quantum GenerateNoise(
const Quantum pixel,
00260
const NoiseType noise_type)
00261 {
00262
#define NoiseEpsilon 1.0e-5
00263
#define SigmaUniform ScaleCharToQuantum(4)
00264
#define SigmaGaussian ScaleCharToQuantum(4)
00265
#define SigmaImpulse 0.10
00266
#define SigmaLaplacian ScaleCharToQuantum(10)
00267
#define SigmaMultiplicativeGaussian ScaleCharToQuantum(1)
00268
#define SigmaPoisson 0.05
00269
#define TauGaussian ScaleCharToQuantum(20)
00270
00271
MagickRealType
00272 alpha,
00273 beta,
00274 noise,
00275 sigma;
00276
00277 alpha=
GetRandomValue();
00278
if (alpha == 0.0)
00279 alpha=1.0;
00280
switch (noise_type)
00281 {
00282
case UniformNoise:
00283
default:
00284 {
00285 noise=(
MagickRealType) pixel+
SigmaUniform*(alpha-0.5);
00286
break;
00287 }
00288
case GaussianNoise:
00289 {
00290
MagickRealType
00291 tau;
00292
00293 beta=
GetRandomValue();
00294 sigma=sqrt(-2.0*log(alpha))*cos(2.0*
MagickPI*beta);
00295 tau=sqrt(-2.0*log(alpha))*sin(2.0*
MagickPI*beta);
00296 noise=(
MagickRealType) pixel+sqrt((
double) pixel)*
SigmaGaussian*sigma+
00297
TauGaussian*tau;
00298
break;
00299 }
00300
case MultiplicativeGaussianNoise:
00301 {
00302
if (alpha <=
NoiseEpsilon)
00303 sigma=(
MagickRealType)
MaxRGB;
00304
else
00305 sigma=sqrt(-2.0*log(alpha));
00306 beta=
GetRandomValue();
00307 noise=(
MagickRealType) pixel+pixel*
SigmaMultiplicativeGaussian*sigma/2.0*
00308 cos(2.0*
MagickPI*beta);
00309
break;
00310 }
00311
case ImpulseNoise:
00312 {
00313
if (alpha < (
SigmaImpulse/2.0))
00314 noise=0.0;
00315
else
00316
if (alpha >= (1.0-(
SigmaImpulse/2.0)))
00317 noise=(
MagickRealType)
MaxRGB;
00318
else
00319 noise=(
MagickRealType) pixel;
00320
break;
00321 }
00322
case LaplacianNoise:
00323 {
00324
if (alpha <= 0.5)
00325 {
00326
if (alpha <=
NoiseEpsilon)
00327 noise=(
MagickRealType) pixel-(
MagickRealType)
MaxRGB;
00328
else
00329 noise=(
MagickRealType) pixel+
00330
ScaleCharToQuantum(
SigmaLaplacian*log(2.0*alpha)+0.5);
00331
break;
00332 }
00333 beta=1.0-alpha;
00334
if (beta <= (0.5*
NoiseEpsilon))
00335 noise=(
MagickRealType) pixel+
MaxRGB;
00336
else
00337 noise=(
MagickRealType) pixel-
00338
ScaleCharToQuantum(
SigmaLaplacian*log(2.0*beta)+0.5);
00339
break;
00340 }
00341
case PoissonNoise:
00342 {
00343
MagickRealType
00344 poisson;
00345
00346
register long
00347 i;
00348
00349 poisson=exp(-
SigmaPoisson*(
MagickRealType)
ScaleQuantumToChar(pixel));
00350
for (i=0; alpha > poisson; i++)
00351 {
00352 beta=
GetRandomValue();
00353 alpha=alpha*beta;
00354 }
00355 noise=(
MagickRealType)
ScaleCharToQuantum(i/
SigmaPoisson);
00356
break;
00357 }
00358 }
00359
return(
RoundToQuantum(noise));
00360 }
00361
00362 MagickExport Image *
AddNoiseImage(
const Image *image,
const NoiseType noise_type,
00363
ExceptionInfo *
exception)
00364 {
00365
#define AddNoiseImageTag "AddNoise/Image"
00366
00367
Image
00368 *noise_image;
00369
00370
long
00371 y;
00372
00373
MagickBooleanType
00374 status;
00375
00376
register const PixelPacket
00377 *p;
00378
00379
register long
00380 x;
00381
00382
register PixelPacket
00383 *q;
00384
00385
00386
00387
00388
assert(image != (
const Image *) NULL);
00389
assert(image->
signature ==
MagickSignature);
00390
if (image->
debug !=
MagickFalse)
00391 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00392
assert(exception != (
ExceptionInfo *) NULL);
00393
assert(exception->
signature ==
MagickSignature);
00394 noise_image=
CloneImage(image,0,0,
MagickTrue,exception);
00395
if (noise_image == (
Image *) NULL)
00396
return((
Image *) NULL);
00397 noise_image->
storage_class=
DirectClass;
00398
00399
00400
00401
for (y=0; y < (
long) image->
rows; y++)
00402 {
00403 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
00404 q=
GetImagePixels(noise_image,0,y,noise_image->
columns,1);
00405
if ((p == (
PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
00406
break;
00407
for (x=0; x < (
long) image->
columns; x++)
00408 {
00409 q->
red=
GenerateNoise(p->
red,noise_type);
00410 q->
green=
GenerateNoise(p->
green,noise_type);
00411 q->
blue=
GenerateNoise(p->
blue,noise_type);
00412 p++;
00413 q++;
00414 }
00415
if (
SyncImagePixels(noise_image) ==
MagickFalse)
00416
break;
00417
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00418 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00419 {
00420 status=image->
progress_monitor(
AddNoiseImageTag,y,image->
rows,
00421 image->
client_data);
00422
if (status ==
MagickFalse)
00423
break;
00424 }
00425 }
00426
return(noise_image);
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 MagickExport MagickBooleanType BilevelImage(
Image *image,
const double threshold)
00459 {
00460
MagickBooleanType
00461 status;
00462
00463 status=
BilevelImageChannel(image,(
ChannelType) ((
long)
AllChannels &~
00464 (
long)
OpacityChannel),threshold);
00465
return(status);
00466 }
00467
00468 MagickExport MagickBooleanType BilevelImageChannel(
Image *image,
00469
const ChannelType channel,
const double threshold)
00470 {
00471
#define ThresholdImageTag "Threshold/Image"
00472
00473
long
00474 y;
00475
00476
MagickBooleanType
00477 status;
00478
00479
register IndexPacket
00480 *indexes;
00481
00482
register long
00483 x;
00484
00485
register PixelPacket
00486 *q;
00487
00488
00489
00490
00491
assert(image != (
Image *) NULL);
00492
assert(image->
signature ==
MagickSignature);
00493
if (image->
debug !=
MagickFalse)
00494 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00495 image->
storage_class=
DirectClass;
00496
for (y=0; y < (
long) image->
rows; y++)
00497 {
00498 q=
GetImagePixels(image,0,y,image->
columns,1);
00499
if (q == (
PixelPacket *) NULL)
00500
break;
00501 indexes=
GetIndexes(image);
00502
for (x=0; x < (
long) image->
columns; x++)
00503 {
00504
if ((channel &
RedChannel) != 0)
00505 q->
red=(
Quantum) ((
MagickRealType) q->
red <= threshold ? 0 :
MaxRGB);
00506
if ((channel &
GreenChannel) != 0)
00507 q->
green=(
Quantum)
00508 ((
MagickRealType) q->
green <= threshold ? 0 :
MaxRGB);
00509
if ((channel &
BlueChannel) != 0)
00510 q->
blue=(
Quantum) ((
MagickRealType) q->
blue <= threshold ? 0 :
MaxRGB);
00511
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00512 q->
opacity=(
Quantum)
00513 ((
MagickRealType) q->
opacity <= threshold ? 0 :
MaxRGB);
00514
if (((channel &
IndexChannel) != 0) &&
00515 (image->
colorspace ==
CMYKColorspace))
00516 indexes[x]=(
IndexPacket)
00517 ((
MagickRealType) indexes[x] <= threshold ? 0 :
MaxRGB);
00518 q++;
00519 }
00520
if (
SyncImagePixels(image) ==
MagickFalse)
00521
break;
00522
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00523 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00524 {
00525 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
00526 image->
client_data);
00527
if (status ==
MagickFalse)
00528
break;
00529 }
00530 }
00531
if (
IsGrayImage(image,&image->
exception) !=
MagickFalse)
00532 (
void)
SetImageType(image,
BilevelType);
00533
return(
MagickTrue);
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 MagickExport MagickBooleanType BlackThresholdImage(
Image *image,
00563
const char *threshold)
00564 {
00565
#define ThresholdImageTag "Threshold/Image"
00566
00567
GeometryInfo
00568 geometry_info;
00569
00570
long
00571 y;
00572
00573
MagickBooleanType
00574 status;
00575
00576
MagickPixelPacket
00577 pixel;
00578
00579
MagickStatusType
00580 flags;
00581
00582
register long
00583 x;
00584
00585
register PixelPacket
00586 *q;
00587
00588
00589
00590
00591
assert(image != (
Image *) NULL);
00592
assert(image->
signature ==
MagickSignature);
00593
if (image->
debug !=
MagickFalse)
00594 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00595
if (threshold == (
const char *) NULL)
00596
return(
MagickTrue);
00597 image->
storage_class=
DirectClass;
00598 flags=
ParseGeometry(threshold,&geometry_info);
00599 pixel.
red=geometry_info.
rho;
00600 pixel.
green=geometry_info.
sigma;
00601
if ((flags &
SigmaValue) == 0)
00602 pixel.
green=pixel.
red;
00603 pixel.
blue=geometry_info.
xi;
00604
if ((flags &
XiValue) == 0)
00605 pixel.
blue=pixel.
red;
00606 pixel.
opacity=geometry_info.
psi;
00607
if ((flags &
PsiValue) == 0)
00608 pixel.
opacity=(
MagickRealType)
OpaqueOpacity;
00609
if ((flags &
PercentValue) != 0)
00610 {
00611 pixel.
red*=
MaxRGB/100.0f;
00612 pixel.
green*=
MaxRGB/100.0f;
00613 pixel.
blue*=
MaxRGB/100.0f;
00614 pixel.
opacity*=
MaxRGB/100.0f;
00615 }
00616
for (y=0; y < (
long) image->
rows; y++)
00617 {
00618 q=
GetImagePixels(image,0,y,image->
columns,1);
00619
if (q == (
PixelPacket *) NULL)
00620
break;
00621
if (
IsGray(pixel) !=
MagickFalse)
00622
for (x=(
long) image->
columns-1; x >= 0; x--)
00623 {
00624
if ((
MagickRealType)
PixelIntensityToQuantum(q) < pixel.
red)
00625 {
00626 q->
red=0;
00627 q->
green=0;
00628 q->
blue=0;
00629 }
00630 q++;
00631 }
00632
else
00633
for (x=(
long) image->
columns-1; x >= 0; x--)
00634 {
00635
if ((
MagickRealType) q->
red < pixel.
red)
00636 q->
red=0;
00637
if ((
MagickRealType) q->
green < pixel.
green)
00638 q->
green=0;
00639
if ((
MagickRealType) q->
blue < pixel.
blue)
00640 q->
blue=0;
00641
if ((
MagickRealType) q->
opacity < pixel.
opacity)
00642 q->
opacity=0;
00643 q++;
00644 }
00645
if (
SyncImagePixels(image) ==
MagickFalse)
00646
break;
00647
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00648 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00649 {
00650 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
00651 image->
client_data);
00652
if (status ==
MagickFalse)
00653
break;
00654 }
00655 }
00656
return(
MagickTrue);
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 static void BlurScanline(
const Image *image,
const ChannelType channel,
00700
const MagickRealType *kernel,
const unsigned long width,
00701
const PixelPacket *source,
PixelPacket *destination,
00702
const unsigned long columns)
00703 {
00704
MagickRealType
00705 scale;
00706
00707
MagickPixelPacket
00708 aggregate,
00709 zero;
00710
00711
register const MagickRealType
00712 *p;
00713
00714
register const PixelPacket
00715 *q;
00716
00717
register long
00718 i,
00719 x;
00720
00721 (
void)
ResetMagickMemory(&zero,0,
sizeof(zero));
00722
if (width > columns)
00723 {
00724
for (x=0; x < (
long) columns; x++)
00725 {
00726 aggregate=zero;
00727 scale=0.0;
00728 p=kernel;
00729 q=source;
00730
for (i=0; i < (
long) columns; i++)
00731 {
00732
if ((i >= (x-(
long) width/2)) && (i <= (x+(
long) width/2)))
00733 {
00734
if ((channel &
RedChannel) != 0)
00735 aggregate.
red+=(*p)*q->
red;
00736
if ((channel &
GreenChannel) != 0)
00737 aggregate.
green+=(*p)*q->
green;
00738
if ((channel &
BlueChannel) != 0)
00739 aggregate.
blue+=(*p)*q->
blue;
00740
if (((channel &
OpacityChannel) != 0) &&
00741 (image->
matte !=
MagickFalse))
00742 aggregate.
opacity+=(*p)*q->
opacity;
00743 }
00744
if (((i+(
long) width/2-x) >= 0) &&
00745 ((i+(
long) width/2-x) < (
long) width))
00746 scale+=kernel[i+width/2-x];
00747 p++;
00748 q++;
00749 }
00750
if ((channel &
RedChannel) != 0)
00751 destination[x].
red=(
Quantum) (scale*aggregate.
red+0.5);
00752
if ((channel &
GreenChannel) != 0)
00753 destination[x].
green=(
Quantum) (scale*aggregate.
green+0.5);
00754
if ((channel &
BlueChannel) != 0)
00755 destination[x].
blue=(
Quantum) (scale*aggregate.
blue+0.5);
00756
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00757 destination[x].
opacity=(
Quantum) (scale*aggregate.
opacity+0.5);
00758 }
00759
return;
00760 }
00761
00762
00763
00764
for (x=0; x < (
long) (width/2); x++)
00765 {
00766 aggregate=zero;
00767 scale=0.0;
00768 p=kernel+width/2-x;
00769 q=source;
00770
for (i=(
long) width/2-x; i < (
long) width; i++)
00771 {
00772
if ((channel &
RedChannel) != 0)
00773 aggregate.
red+=(*p)*q->
red;
00774
if ((channel &
GreenChannel) != 0)
00775 aggregate.
green+=(*p)*q->
green;
00776
if ((channel &
BlueChannel) != 0)
00777 aggregate.
blue+=(*p)*q->
blue;
00778
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00779 aggregate.
opacity+=(*p)*q->
opacity;
00780 scale+=(*p);
00781 p++;
00782 q++;
00783 }
00784 scale=1.0/scale;
00785
if ((channel &
RedChannel) != 0)
00786 destination[x].
red=(
Quantum) (scale*aggregate.
red+0.5);
00787
if ((channel &
GreenChannel) != 0)
00788 destination[x].
green=(
Quantum) (scale*aggregate.
green+0.5);
00789
if ((channel &
BlueChannel) != 0)
00790 destination[x].
blue=(
Quantum) (scale*aggregate.
blue+0.5);
00791
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00792 destination[x].
opacity=(
Quantum) (scale*aggregate.
opacity+0.5);
00793 }
00794
for ( ; x < (
long) (columns-width/2); x++)
00795 {
00796 aggregate=zero;
00797 p=kernel;
00798 q=source+(x-(
long) width/2);
00799
for (i=0; i < (
long) width; i++)
00800 {
00801
if ((channel &
RedChannel) != 0)
00802 aggregate.
red+=(*p)*q->
red;
00803
if ((channel &
GreenChannel) != 0)
00804 aggregate.
green+=(*p)*q->
green;
00805
if ((channel &
BlueChannel) != 0)
00806 aggregate.
blue+=(*p)*q->
blue;
00807
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00808 aggregate.
opacity+=(*p)*q->
opacity;
00809 p++;
00810 q++;
00811 }
00812
if ((channel &
RedChannel) != 0)
00813 destination[x].
red=(
Quantum) (aggregate.
red+0.5);
00814
if ((channel &
GreenChannel) != 0)
00815 destination[x].
green=(
Quantum) (aggregate.
green+0.5);
00816
if ((channel &
BlueChannel) != 0)
00817 destination[x].
blue=(
Quantum) (aggregate.
blue+0.5);
00818
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00819 destination[x].
opacity=(
Quantum) (aggregate.
opacity+0.5);
00820 }
00821
for ( ; x < (
long) columns; x++)
00822 {
00823 aggregate=zero;
00824 scale=0.0;
00825 p=kernel;
00826 q=source+(x-(
long) width/2);
00827
for (i=0; i < (
long) (columns-x+width/2); i++)
00828 {
00829
if ((channel &
RedChannel) != 0)
00830 aggregate.
red+=(*p)*q->
red;
00831
if ((channel &
GreenChannel) != 0)
00832 aggregate.
green+=(*p)*q->
green;
00833
if ((channel &
BlueChannel) != 0)
00834 aggregate.
blue+=(*p)*q->
blue;
00835
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00836 aggregate.
opacity+=(*p)*q->
opacity;
00837 scale+=(*p);
00838 p++;
00839 q++;
00840 }
00841 scale=1.0/scale;
00842
if ((channel &
RedChannel) != 0)
00843 destination[x].
red=(
Quantum) (scale*aggregate.
red+0.5);
00844
if ((channel &
GreenChannel) != 0)
00845 destination[x].
green=(
Quantum) (scale*aggregate.
green+0.5);
00846
if ((channel &
BlueChannel) != 0)
00847 destination[x].
blue=(
Quantum) (scale*aggregate.
blue+0.5);
00848
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00849 destination[x].
opacity=(
Quantum) (scale*aggregate.
opacity+0.5);
00850 }
00851 }
00852
00853 static unsigned long GetBlurKernel(
unsigned long width,
00854
const MagickRealType sigma,MagickRealType **kernel)
00855 {
00856
#define KernelRank 3
00857
00858
long
00859 bias;
00860
00861
MagickRealType
00862 alpha,
00863 normalize;
00864
00865
register long
00866 i;
00867
00868
00869
00870
00871
00872
00873 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),
"...");
00874
assert(sigma != 0.0);
00875
if (width < 3)
00876 width=3;
00877
if ((width & 0x01) == 0)
00878 width++;
00879 *kernel=(
MagickRealType *)
00880
AcquireMagickMemory((size_t) width*
sizeof(**kernel));
00881
if (*kernel == (
MagickRealType *) NULL)
00882
return(0);
00883 (
void)
ResetMagickMemory(*kernel,0,(size_t) width*
sizeof(**kernel));
00884 bias=
KernelRank*(
long) width/2;
00885
for (i=(-bias); i <= bias; i++)
00886 {
00887 alpha=exp(-((
MagickRealType) (i*i))/
00888 (2.0*
KernelRank*
KernelRank*sigma*sigma));
00889 (*kernel)[(i+bias)/
KernelRank]+=alpha/(
MagickSQ2PI*sigma);
00890 }
00891 normalize=0.0;
00892
for (i=0; i < (
long) width; i++)
00893 normalize+=(*kernel)[i];
00894
for (i=0; i < (
long) width; i++)
00895 (*kernel)[i]/=normalize;
00896
return(width);
00897 }
00898
00899 MagickExport Image *
BlurImage(
const Image *image,
const double radius,
00900
const double sigma,
ExceptionInfo *
exception)
00901 {
00902
Image
00903 *blur_image;
00904
00905 blur_image=
BlurImageChannel(image,(
ChannelType) ((
long)
AllChannels &~
00906 (
long)
OpacityChannel),radius,sigma,exception);
00907
return(blur_image);
00908 }
00909
00910 MagickExport Image *
BlurImageChannel(
const Image *image,
00911
const ChannelType channel,
const double radius,
const double sigma,
00912
ExceptionInfo *
exception)
00913 {
00914
#define BlurImageTag "Blur/Image"
00915
00916
Image
00917 *blur_image;
00918
00919
long
00920 y;
00921
00922
MagickBooleanType
00923 status;
00924
00925
MagickRealType
00926 *kernel;
00927
00928
PixelPacket
00929 *scanline;
00930
00931
register const PixelPacket
00932 *p;
00933
00934
register long
00935 x;
00936
00937
register PixelPacket
00938 *q;
00939
00940
unsigned long
00941 width;
00942
00943
00944
00945
00946
assert(image != (
Image *) NULL);
00947
assert(image->
signature ==
MagickSignature);
00948
if (image->
debug !=
MagickFalse)
00949 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00950
assert(exception != (
ExceptionInfo *) NULL);
00951
assert(exception->
signature ==
MagickSignature);
00952
if (sigma == 0.0)
00953
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
00954 kernel=(
MagickRealType *) NULL;
00955
if (radius > 0.0)
00956 width=
GetBlurKernel(2*((
unsigned long) radius)+1,sigma,&kernel);
00957
else
00958 {
00959
MagickRealType
00960 *last_kernel;
00961
00962 last_kernel=(
MagickRealType *) NULL;
00963 width=
GetBlurKernel(3,sigma,&kernel);
00964
while ((
long) (
MaxRGB*kernel[0]) > 0)
00965 {
00966
if (last_kernel != (
MagickRealType *)NULL)
00967 last_kernel=(
MagickRealType *)
RelinquishMagickMemory(last_kernel);
00968 last_kernel=kernel;
00969 kernel=(
MagickRealType *) NULL;
00970 width=
GetBlurKernel(width+2,sigma,&kernel);
00971 }
00972
if (last_kernel != (
MagickRealType *) NULL)
00973 {
00974 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
00975 width-=2;
00976 kernel=last_kernel;
00977 }
00978 }
00979
00980
00981
00982 blur_image=
CloneImage(image,0,0,
MagickTrue,exception);
00983
if (blur_image == (
Image *) NULL)
00984 {
00985 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
00986
return((
Image *) NULL);
00987 }
00988 blur_image->
storage_class=
DirectClass;
00989 scanline=(
PixelPacket *)
00990
AcquireMagickMemory((size_t) image->
rows*
sizeof(*scanline));
00991
if (scanline == (
PixelPacket *) NULL)
00992 {
00993 blur_image=
DestroyImage(blur_image);
00994
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
00995 }
00996
00997
00998
00999
for (y=0; y < (
long) image->
rows; y++)
01000 {
01001 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
01002 q=
GetImagePixels(blur_image,0,y,image->
columns,1);
01003
if ((p == (
PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
01004
break;
01005
BlurScanline(image,channel,kernel,width,p,q,image->
columns);
01006
if (
SyncImagePixels(blur_image) ==
MagickFalse)
01007
break;
01008
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01009 (
QuantumTick(y,blur_image->
rows+blur_image->
columns) !=
MagickFalse))
01010 {
01011 status=image->
progress_monitor(
BlurImageTag,y,blur_image->
rows+
01012 blur_image->
columns,image->
client_data);
01013
if (status ==
MagickFalse)
01014
break;
01015 }
01016 }
01017
01018
01019
01020
for (x=0; x < (
long) image->
columns; x++)
01021 {
01022 q=
GetImagePixels(blur_image,x,0,1,image->
rows);
01023
if (q == (
PixelPacket *) NULL)
01024
break;
01025 (
void)
CopyMagickMemory(scanline,q,(size_t) image->
rows*
sizeof(*scanline));
01026
BlurScanline(image,channel,kernel,width,scanline,q,image->
rows);
01027
if (
SyncImagePixels(blur_image) ==
MagickFalse)
01028
break;
01029 status=
QuantumTick(blur_image->
rows+x,blur_image->
rows+blur_image->
columns);
01030
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01031 (
QuantumTick(x,blur_image->
columns) !=
MagickFalse))
01032 {
01033 status=image->
progress_monitor(
BlurImageTag,(
MagickOffsetType)
01034 blur_image->
rows+x,blur_image->
rows+blur_image->
columns,
01035 image->
client_data);
01036
if (status ==
MagickFalse)
01037
break;
01038 }
01039 }
01040 scanline=(
PixelPacket *)
RelinquishMagickMemory(scanline);
01041 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
01042
return(blur_image);
01043 }
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070 MagickExport Image *
DespeckleImage(
const Image *image,
ExceptionInfo *
exception)
01071 {
01072
#define DespeckleImageTag "Despeckle/Image"
01073
01074
Image
01075 *despeckle_image;
01076
01077
int
01078 layer;
01079
01080
long
01081 j,
01082 y;
01083
01084
MagickBooleanType
01085 status;
01086
01087
Quantum
01088 *buffer,
01089 *pixels;
01090
01091
register const PixelPacket
01092 *p;
01093
01094
register long
01095 i,
01096 x;
01097
01098
register PixelPacket
01099 *q;
01100
01101 size_t
01102 length;
01103
01104
static const int
01105
X[4]= {0, 1, 1,-1},
01106
Y[4]= {1, 0, 1, 1};
01107
01108
01109
01110
01111
assert(image != (
const Image *) NULL);
01112
assert(image->
signature ==
MagickSignature);
01113
if (image->
debug !=
MagickFalse)
01114 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01115
assert(exception != (
ExceptionInfo *) NULL);
01116
assert(exception->
signature ==
MagickSignature);
01117 despeckle_image=
CloneImage(image,0,0,
MagickTrue,exception);
01118
if (despeckle_image == (
Image *) NULL)
01119
return((
Image *) NULL);
01120 despeckle_image->
storage_class=
DirectClass;
01121
01122
01123
01124 length=(size_t) (image->
columns+2)*(image->
rows+2)*
sizeof(*pixels);
01125 pixels=(
Quantum *)
AcquireMagickMemory(length);
01126 buffer=(
Quantum *)
AcquireMagickMemory(length);
01127
if ((buffer == (
Quantum *) NULL) || (pixels == (
Quantum *) NULL))
01128 {
01129 despeckle_image=
DestroyImage(despeckle_image);
01130
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01131 }
01132
01133
01134
01135
for (layer=0; layer <= 3; layer++)
01136 {
01137 (
void)
ResetMagickMemory(pixels,0,length);
01138 j=(
long) image->
columns+2;
01139
for (y=0; y < (
long) image->
rows; y++)
01140 {
01141 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
01142
if (p == (
const PixelPacket *) NULL)
01143
break;
01144 j++;
01145
for (x=(
long) image->
columns-1; x >= 0; x--)
01146 {
01147
switch (layer)
01148 {
01149
case 0: pixels[j]=p->
red;
break;
01150
case 1: pixels[j]=p->
green;
break;
01151
case 2: pixels[j]=p->
blue;
break;
01152
case 3: pixels[j]=p->
opacity;
break;
01153
default:
break;
01154 }
01155 p++;
01156 j++;
01157 }
01158 j++;
01159 }
01160 (
void)
ResetMagickMemory(buffer,0,length);
01161
for (i=0; i < 4; i++)
01162 {
01163
Hull(
X[i],
Y[i],image->
columns,image->
rows,pixels,buffer,1);
01164
Hull(-
X[i],-
Y[i],image->
columns,image->
rows,pixels,buffer,1);
01165
Hull(-
X[i],-
Y[i],image->
columns,image->
rows,pixels,buffer,-1);
01166
Hull(
X[i],
Y[i],image->
columns,image->
rows,pixels,buffer,-1);
01167 }
01168 j=(
long) image->
columns+2;
01169
for (y=0; y < (
long) image->
rows; y++)
01170 {
01171 q=
GetImagePixels(despeckle_image,0,y,despeckle_image->
columns,1);
01172
if (q == (
PixelPacket *) NULL)
01173
break;
01174 j++;
01175
for (x=(
long) image->
columns-1; x >= 0; x--)
01176 {
01177
switch (layer)
01178 {
01179
case 0: q->
red=pixels[j];
break;
01180
case 1: q->
green=pixels[j];
break;
01181
case 2: q->
blue=pixels[j];
break;
01182
case 3: q->
opacity=pixels[j];
break;
01183
default:
break;
01184 }
01185 q++;
01186 j++;
01187 }
01188
if (
SyncImagePixels(despeckle_image) ==
MagickFalse)
01189
break;
01190 j++;
01191 }
01192
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01193 (
QuantumTick(layer,3) !=
MagickFalse))
01194 {
01195 status=image->
progress_monitor(
DespeckleImageTag,layer,3,
01196 image->
client_data);
01197
if (status ==
MagickFalse)
01198
break;
01199 }
01200 }
01201
01202
01203
01204 buffer=(
Quantum *)
RelinquishMagickMemory(buffer);
01205 pixels=(
Quantum *)
RelinquishMagickMemory(pixels);
01206
return(despeckle_image);
01207 }
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238 MagickExport Image *
EdgeImage(
const Image *image,
const double radius,
01239
ExceptionInfo *
exception)
01240 {
01241
Image
01242 *edge_image;
01243
01244
double
01245 *kernel;
01246
01247
register long
01248 i;
01249
01250
unsigned long
01251 width;
01252
01253
assert(image != (
const Image *) NULL);
01254
assert(image->
signature ==
MagickSignature);
01255
if (image->
debug !=
MagickFalse)
01256 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01257
assert(exception != (
ExceptionInfo *) NULL);
01258
assert(exception->
signature ==
MagickSignature);
01259 width=
GetOptimalKernelWidth(radius,0.5);
01260
if ((image->
columns < width) || (image->
rows < width))
01261
ThrowImageException(
OptionError,
"ImageSmallerThanRadius");
01262 kernel=(
double *)
AcquireMagickMemory((size_t) width*width*
sizeof(*kernel));
01263
if (kernel == (
double *) NULL)
01264
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01265
for (i=0; i < (
long) (width*width); i++)
01266 kernel[i]=(-1.0);
01267 kernel[i/2]=(
double) width*width-1.0;
01268 edge_image=
ConvolveImage(image,width,kernel,exception);
01269 kernel=(
double *)
RelinquishMagickMemory(kernel);
01270
return(edge_image);
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306 MagickExport Image *
EmbossImage(
const Image *image,
const double radius,
01307
const double sigma,
ExceptionInfo *
exception)
01308 {
01309
double
01310 *kernel;
01311
01312
Image
01313 *emboss_image;
01314
01315
long
01316 j;
01317
01318
MagickRealType
01319 alpha;
01320
01321
register long
01322 i,
01323 u,
01324 v;
01325
01326
unsigned long
01327 width;
01328
01329
assert(image != (
Image *) NULL);
01330
assert(image->
signature ==
MagickSignature);
01331
if (image->
debug !=
MagickFalse)
01332 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01333
assert(exception != (
ExceptionInfo *) NULL);
01334
assert(exception->
signature ==
MagickSignature);
01335
if (sigma == 0.0)
01336
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
01337 width=
GetOptimalKernelWidth(radius,sigma);
01338 kernel=(
double *)
AcquireMagickMemory((size_t) width*width*
sizeof(*kernel));
01339
if (kernel == (
double *) NULL)
01340
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01341 i=0;
01342 j=(
long) width/2;
01343
for (v=(-((
long) width/2)); v <= (
long) (width/2); v++)
01344 {
01345
for (u=(-((
long) width/2)); u <= (
long) (width/2); u++)
01346 {
01347 alpha=exp(-((
double) u*u+v*v)/(2.0*sigma*sigma));
01348 kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
01349 (2.0*
MagickPI*sigma*sigma);
01350
if (u == j)
01351 kernel[i]=0.0;
01352 i++;
01353 }
01354 j--;
01355 }
01356 emboss_image=
ConvolveImage(image,width,kernel,exception);
01357
if (emboss_image != (
Image *) NULL)
01358 (
void)
EqualizeImage(emboss_image);
01359 kernel=(
double *)
RelinquishMagickMemory(kernel);
01360
return(emboss_image);
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398 MagickExport Image *
GaussianBlurImage(
const Image *image,
const double radius,
01399
const double sigma,
ExceptionInfo *
exception)
01400 {
01401
Image
01402 *blur_image;
01403
01404 blur_image=
GaussianBlurImageChannel(image,(
ChannelType) ((
long)
AllChannels &~
01405 (
long)
OpacityChannel),radius,sigma,exception);
01406
return(blur_image);
01407 }
01408
01409 MagickExport Image *
GaussianBlurImageChannel(
const Image *image,
01410
const ChannelType channel,
const double radius,
const double sigma,
01411
ExceptionInfo *
exception)
01412 {
01413
double
01414 *kernel;
01415
01416
Image
01417 *blur_image;
01418
01419
MagickRealType
01420 alpha;
01421
01422
register long
01423 i,
01424 u,
01425 v;
01426
01427
unsigned long
01428 width;
01429
01430
assert(image != (
const Image *) NULL);
01431
assert(image->
signature ==
MagickSignature);
01432
if (image->
debug !=
MagickFalse)
01433 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01434
assert(exception != (
ExceptionInfo *) NULL);
01435
assert(exception->
signature ==
MagickSignature);
01436
if (sigma == 0.0)
01437
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
01438 width=
GetOptimalKernelWidth2D(radius,sigma);
01439
if ((image->
columns < width) || (image->
rows < width))
01440
ThrowImageException(
OptionError,
"ImageSmallerThanRadius");
01441 kernel=(
double *)
AcquireMagickMemory((size_t) width*width*
sizeof(*kernel));
01442
if (kernel == (
double *) NULL)
01443
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01444 i=0;
01445
for (v=(-((
long) width/2)); v <= (
long) (width/2); v++)
01446 {
01447
for (u=(-((
long) width/2)); u <= (
long) (width/2); u++)
01448 {
01449 alpha=exp(-((
double) u*u+v*v)/(2.0*sigma*sigma));
01450 kernel[i]=alpha/(2.0*
MagickPI*sigma*sigma);
01451 i++;
01452 }
01453 }
01454 blur_image=
ConvolveImageChannel(image,channel,width,kernel,exception);
01455 kernel=(
double *)
RelinquishMagickMemory(kernel);
01456
return(blur_image);
01457 }
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494 typedef struct _MedianListNode
01495 {
01496
unsigned long
01497 next[9],
01498
count,
01499
signature;
01500 }
MedianListNode;
01501
01502 typedef struct _MedianSkipList
01503 {
01504
long
01505 level;
01506
01507
MedianListNode
01508 nodes[65537];
01509 }
MedianSkipList;
01510
01511 typedef struct _MedianPixelList
01512 {
01513
unsigned long
01514 center,
01515
seed,
01516
signature;
01517
01518
MedianSkipList
01519 lists[5];
01520 }
MedianPixelList;
01521
01522 static void AddNodeMedianList(
MedianPixelList *pixel_list,
int channel,
01523
unsigned long color)
01524 {
01525
register long
01526 level;
01527
01528
register MedianSkipList
01529 *list;
01530
01531
unsigned long
01532 search,
01533 update[9];
01534
01535
01536
01537
01538 list=pixel_list->
lists+channel;
01539 list->
nodes[color].
signature=pixel_list->
signature;
01540 list->
nodes[color].
count=1;
01541
01542
01543
01544 search=65536UL;
01545
for (level=list->
level; level >= 0; level--)
01546 {
01547
while (list->
nodes[search].
next[level] < color)
01548 search=list->
nodes[search].
next[level];
01549 update[level]=search;
01550 }
01551
01552
01553
01554
for (level=0; ; level++)
01555 {
01556 pixel_list->
seed=(pixel_list->
seed*42893621L)+1L;
01557
if ((pixel_list->
seed & 0x300) != 0x300)
01558
break;
01559 }
01560
if (level > 8)
01561 level=8;
01562
if (level > (list->
level+2))
01563 level=list->
level+2;
01564
01565
01566
01567
while (level > list->
level)
01568 {
01569 list->
level++;
01570 update[list->
level]=65536UL;
01571 }
01572
01573
01574
01575
do
01576 {
01577 list->
nodes[color].
next[level]=list->
nodes[update[level]].
next[level];
01578 list->
nodes[update[level]].
next[level]=color;
01579 }
01580
while (level-- > 0);
01581 }
01582
01583 static MagickPixelPacket GetMedianList(
MedianPixelList *pixel_list)
01584 {
01585
MagickPixelPacket
01586 pixel;
01587
01588
register long
01589 channel;
01590
01591
register MedianSkipList
01592 *list;
01593
01594
unsigned long
01595 center,
01596 channels[5],
01597 color,
01598 count;
01599
01600
01601
01602
01603 center=pixel_list->
center;
01604
for (channel=0; channel < 5; channel++)
01605 {
01606 list=pixel_list->
lists+channel;
01607 color=65536UL;
01608 count=0;
01609
do
01610 {
01611 color=list->
nodes[color].
next[0];
01612 count+=list->
nodes[color].
count;
01613 }
01614
while (count <= center);
01615 channels[channel]=color;
01616 }
01617
GetMagickPixelPacket((
const Image *) NULL,&pixel);
01618 pixel.
red=(
MagickRealType)
ScaleShortToQuantum(channels[0]);
01619 pixel.
green=(
MagickRealType)
ScaleShortToQuantum(channels[1]);
01620 pixel.
blue=(
MagickRealType)
ScaleShortToQuantum(channels[2]);
01621 pixel.
opacity=(
MagickRealType)
ScaleShortToQuantum(channels[3]);
01622 pixel.
index=(
MagickRealType)
ScaleShortToQuantum(channels[4]);
01623
return(pixel);
01624 }
01625
01626 static void InitializeMedianList(
MedianPixelList *pixel_list,
01627
unsigned long width)
01628 {
01629 pixel_list->
center=width*width/2;
01630 pixel_list->
signature=
MagickSignature;
01631 (
void)
ResetMagickMemory((
void *) pixel_list->
lists,0,
01632 5*
sizeof(*pixel_list->
lists));
01633 }
01634
01635 static inline void InsertMedianList(
const Image *image,
const PixelPacket *pixel,
01636
const IndexPacket *indexes,
MedianPixelList *pixel_list)
01637 {
01638
unsigned long
01639 signature;
01640
01641
unsigned short
01642 index;
01643
01644 index=
ScaleQuantumToShort(pixel->
red);
01645 signature=pixel_list->
lists[0].
nodes[index].
signature;
01646
if (signature == pixel_list->
signature)
01647 pixel_list->
lists[0].
nodes[index].
count++;
01648
else
01649
AddNodeMedianList(pixel_list,0,index);
01650 index=
ScaleQuantumToShort(pixel->
green);
01651 signature=pixel_list->
lists[1].
nodes[index].
signature;
01652
if (signature == pixel_list->
signature)
01653 pixel_list->
lists[1].
nodes[index].
count++;
01654
else
01655
AddNodeMedianList(pixel_list,1,index);
01656 index=
ScaleQuantumToShort(pixel->
blue);
01657 signature=pixel_list->
lists[2].
nodes[index].
signature;
01658
if (signature == pixel_list->
signature)
01659 pixel_list->
lists[2].
nodes[index].
count++;
01660
else
01661
AddNodeMedianList(pixel_list,2,index);
01662 index=
ScaleQuantumToShort(pixel->
opacity);
01663 signature=pixel_list->
lists[3].
nodes[index].
signature;
01664
if (signature == pixel_list->
signature)
01665 pixel_list->
lists[3].
nodes[index].
count++;
01666
else
01667
AddNodeMedianList(pixel_list,3,index);
01668
if (image->
colorspace ==
CMYKColorspace)
01669 index=
ScaleQuantumToShort(*indexes);
01670 signature=pixel_list->
lists[4].
nodes[index].
signature;
01671
if (signature == pixel_list->
signature)
01672 pixel_list->
lists[4].
nodes[index].
count++;
01673
else
01674
AddNodeMedianList(pixel_list,4,index);
01675 }
01676
01677 static void ResetMedianList(
MedianPixelList *pixel_list)
01678 {
01679
int
01680 level;
01681
01682
register long
01683 channel;
01684
01685
register MedianListNode
01686 *root;
01687
01688
register MedianSkipList
01689 *list;
01690
01691
01692
01693
01694
for (channel=0; channel < 5; channel++)
01695 {
01696 list=pixel_list->
lists+channel;
01697 root=list->
nodes+65536UL;
01698 list->
level=0;
01699
for (level=0; level < 9; level++)
01700 root->
next[level]=65536UL;
01701 }
01702 pixel_list->
seed=pixel_list->
signature++;
01703 }
01704
01705 MagickExport Image *
MedianFilterImage(
const Image *image,
const double radius,
01706
ExceptionInfo *
exception)
01707 {
01708
#define MedianFilterImageTag "MedianFilter/Image"
01709
01710
Image
01711 *median_image;
01712
01713
long
01714 x,
01715 y;
01716
01717
MagickBooleanType
01718 status;
01719
01720
MagickPixelPacket
01721 pixel;
01722
01723
MedianPixelList
01724 *skiplist;
01725
01726
register const PixelPacket
01727 *p,
01728 *r;
01729
01730
register IndexPacket
01731 *indexes,
01732 *median_indexes,
01733 *s;
01734
01735
register long
01736 u,
01737 v;
01738
01739
register PixelPacket
01740 *q;
01741
01742
unsigned long
01743 width;
01744
01745
01746
01747
01748
assert(image != (
Image *) NULL);
01749
assert(image->
signature ==
MagickSignature);
01750
if (image->
debug !=
MagickFalse)
01751 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01752
assert(exception != (
ExceptionInfo *) NULL);
01753
assert(exception->
signature ==
MagickSignature);
01754 width=
GetOptimalKernelWidth(radius,0.5);
01755
if ((image->
columns < width) || (image->
rows < width))
01756
ThrowImageException(
OptionError,
"ImageSmallerThanKernelRadius");
01757 median_image=
CloneImage(image,0,0,
MagickTrue,exception);
01758
if (median_image == (
Image *) NULL)
01759
return((
Image *) NULL);
01760 median_image->
storage_class=
DirectClass;
01761
01762
01763
01764 skiplist=(
MedianPixelList *)
AcquireMagickMemory(
sizeof(*skiplist));
01765
if (skiplist == (
MedianPixelList *) NULL)
01766 {
01767 median_image=
DestroyImage(median_image);
01768
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01769 }
01770
01771
01772
01773
InitializeMedianList(skiplist,width);
01774
for (y=0; y < (
long) median_image->
rows; y++)
01775 {
01776 p=
AcquireImagePixels(image,-((
long) width/2),y-(
long) width/2,
01777 image->
columns+width,width,exception);
01778 q=
GetImagePixels(median_image,0,y,median_image->
columns,1);
01779
if ((p == (
const PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
01780
break;
01781 indexes=
GetIndexes(image);
01782 median_indexes=
GetIndexes(median_image);
01783
for (x=0; x < (
long) median_image->
columns; x++)
01784 {
01785 r=p;
01786 s=indexes+x;
01787
ResetMedianList(skiplist);
01788
for (v=0; v < (
long) width; v++)
01789 {
01790
for (u=0; u < (
long) width; u++)
01791
InsertMedianList(image,r+u,s+u,skiplist);
01792 r+=image->
columns+width;
01793 s+=image->
columns+width;
01794 }
01795 pixel=
GetMedianList(skiplist);
01796
SetPixelPacket(&pixel,q,median_indexes+x);
01797 p++;
01798 q++;
01799 }
01800
if (
SyncImagePixels(median_image) ==
MagickFalse)
01801
break;
01802
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01803 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01804 {
01805 status=image->
progress_monitor(
MedianFilterImageTag,y,image->
rows,
01806 image->
client_data);
01807
if (status ==
MagickFalse)
01808
break;
01809 }
01810 }
01811 skiplist=(
MedianPixelList *)
RelinquishMagickMemory(skiplist);
01812
return(median_image);
01813 }
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854 static unsigned long GetMotionBlurKernel(
unsigned long width,
01855
const MagickRealType sigma,MagickRealType **kernel)
01856 {
01857
#define KernelRank 3
01858
01859
MagickRealType
01860 alpha,
01861 normalize;
01862
01863
register long
01864 i;
01865
01866
unsigned long
01867 bias;
01868
01869
01870
01871
01872
01873
01874
if (width < 3)
01875 width=3;
01876 *kernel=(
MagickRealType *)
AcquireMagickMemory(width*
sizeof(**kernel));
01877
if (*kernel == (
MagickRealType *) NULL)
01878
return(0);
01879
for (i=0; i < (
long) width; i++)
01880 (*kernel)[i]=0.0;
01881 bias=
KernelRank*width;
01882
for (i=0; i < (
long) bias; i++)
01883 {
01884 alpha=exp(-((
double) i*i)/(2.0*
KernelRank*
KernelRank*sigma*sigma));
01885 (*kernel)[i/
KernelRank]+=alpha/(
MagickSQ2PI*sigma);
01886 }
01887 normalize=0.0;
01888
for (i=0; i < (
long) width; i++)
01889 normalize+=(*kernel)[i];
01890
for (i=0; i < (
long) width; i++)
01891 (*kernel)[i]/=normalize;
01892
return(width);
01893 }
01894
01895 MagickExport Image *
MotionBlurImage(
const Image *image,
const double radius,
01896
const double sigma,
const double angle,
ExceptionInfo *
exception)
01897 {
01898
MagickRealType
01899 *kernel;
01900
01901
Image
01902 *blur_image;
01903
01904
long
01905 y;
01906
01907
MagickBooleanType
01908 status;
01909
01910
PixelPacket
01911 pixel;
01912
01913
PointInfo
01914 *offsets;
01915
01916
MagickPixelPacket
01917 aggregate,
01918 zero;
01919
01920
register long
01921 i,
01922 x,
01923 u,
01924 v;
01925
01926
register PixelPacket
01927 *q;
01928
01929
unsigned long
01930 width;
01931
01932
assert(image != (
Image *) NULL);
01933
assert(image->
signature ==
MagickSignature);
01934
if (image->
debug !=
MagickFalse)
01935 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01936
assert(exception != (
ExceptionInfo *) NULL);
01937
if (sigma == 0.0)
01938
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
01939 kernel=(
MagickRealType *) NULL;
01940
if (radius > 0)
01941 width=
GetMotionBlurKernel(2*((
unsigned long) radius)+1,sigma,&kernel);
01942
else
01943 {
01944
MagickRealType
01945 *last_kernel;
01946
01947 last_kernel=(
MagickRealType *) NULL;
01948 width=
GetMotionBlurKernel(3,sigma,&kernel);
01949
while ((
MaxRGB*kernel[width-1]) > 0.0)
01950 {
01951
if (last_kernel != (
MagickRealType *)NULL)
01952 last_kernel=(
MagickRealType *)
RelinquishMagickMemory(last_kernel);
01953 last_kernel=kernel;
01954 kernel=(
MagickRealType *) NULL;
01955 width=
GetMotionBlurKernel(width+2,sigma,&kernel);
01956 }
01957
if (last_kernel != (
MagickRealType *) NULL)
01958 {
01959 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
01960 width-=2;
01961 kernel=last_kernel;
01962 }
01963 }
01964 offsets=(
PointInfo *)
AcquireMagickMemory(width*
sizeof(*offsets));
01965
if (offsets == (
PointInfo *) NULL)
01966
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
01967
01968
01969
01970 blur_image=
CloneImage(image,0,0,
MagickTrue,exception);
01971
if (blur_image == (
Image *) NULL)
01972 {
01973 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
01974 offsets=(
PointInfo *)
RelinquishMagickMemory(offsets);
01975
return((
Image *) NULL);
01976 }
01977 blur_image->
storage_class=
DirectClass;
01978 x=(
long) (width*sin(
DegreesToRadians(angle)));
01979 y=(
long) (width*cos(
DegreesToRadians(angle)));
01980
for (i=0; i < (
long) width; i++)
01981 {
01982 offsets[i].x=(
MagickRealType) (i*x)/sqrt((
double) x*x+y*y);
01983 offsets[i].y=(
MagickRealType) (i*y)/sqrt((
double) x*x+y*y);
01984 }
01985 (
void)
ResetMagickMemory(&zero,0,
sizeof(zero));
01986
for (y=0; y < (
long) image->
rows; y++)
01987 {
01988 q=
GetImagePixels(blur_image,0,y,blur_image->
columns,1);
01989
if (q == (
PixelPacket *) NULL)
01990
break;
01991
for (x=0; x < (
long) image->
columns; x++)
01992 {
01993 aggregate=zero;
01994
for (i=0; i < (
long) width; i++)
01995 {
01996 u=x+(
long) offsets[i].x;
01997 v=y+(
long) offsets[i].y;
01998
if ((u < 0) || (u >= (
long) image->
columns) ||
01999 (v < 0) || (v >= (
long) image->
rows))
02000
continue;
02001 pixel=
AcquireOnePixel(image,u,v,exception);
02002 aggregate.
red+=kernel[i]*pixel.
red;
02003 aggregate.
green+=kernel[i]*pixel.
green;
02004 aggregate.
blue+=kernel[i]*pixel.
blue;
02005 aggregate.
opacity+=kernel[i]*pixel.
opacity;
02006 }
02007 q->
red=(
Quantum) aggregate.
red;
02008 q->
green=(
Quantum) aggregate.
green;
02009 q->
blue=(
Quantum) aggregate.
blue;
02010 q->
opacity=(
Quantum) aggregate.
opacity;
02011 q++;
02012 }
02013
if (
SyncImagePixels(blur_image) ==
MagickFalse)
02014
break;
02015
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
02016 (
QuantumTick(y,image->
rows) !=
MagickFalse))
02017 {
02018 status=image->
progress_monitor(
BlurImageTag,y,image->
rows,
02019 image->
client_data);
02020
if (status ==
MagickFalse)
02021
break;
02022 }
02023 }
02024 kernel=(
MagickRealType *)
RelinquishMagickMemory(kernel);
02025 offsets=(
PointInfo *)
RelinquishMagickMemory(offsets);
02026
return(blur_image);
02027 }
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060 MagickExport Image *
PreviewImage(
const Image *image,
const PreviewType preview,
02061
ExceptionInfo *
exception)
02062 {
02063
#define NumberTiles 9
02064
#define PreviewImageTag "Preview/Image"
02065
#define DefaultPreviewGeometry "204x204+10+10"
02066
02067
char
02068 factor[
MaxTextExtent],
02069 label[
MaxTextExtent];
02070
02071
Image
02072 *images,
02073 *montage_image,
02074 *preview_image,
02075 *thumbnail;
02076
02077
ImageInfo
02078 *preview_info;
02079
02080
long
02081 y;
02082
02083
MagickBooleanType
02084 status;
02085
02086
MagickRealType
02087 degrees,
02088 gamma,
02089 percentage,
02090 radius,
02091 sigma,
02092 threshold;
02093
02094
MontageInfo
02095 *montage_info;
02096
02097
QuantizeInfo
02098 quantize_info;
02099
02100
RectangleInfo
02101 geometry;
02102
02103
register long
02104 i,
02105 x;
02106
02107
unsigned long
02108 colors;
02109
02110
02111
02112
02113
assert(image != (
Image *) NULL);
02114
assert(image->
signature ==
MagickSignature);
02115
if (image->
debug !=
MagickFalse)
02116 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
02117 colors=2;
02118 degrees=0.0;
02119 gamma=(-0.2f);
02120 preview_info=
CloneImageInfo((
ImageInfo *) NULL);
02121
SetGeometry(image,&geometry);
02122 (
void)
ParseMetaGeometry(
DefaultPreviewGeometry,&geometry.
x,&geometry.
y,
02123 &geometry.
width,&geometry.
height);
02124 images=
NewImageList();
02125 percentage=12.5;
02126
GetQuantizeInfo(&quantize_info);
02127 radius=0.0;
02128 sigma=1.0;
02129 threshold=0.0;
02130 x=0;
02131 y=0;
02132
for (i=0; i <
NumberTiles; i++)
02133 {
02134 thumbnail=
ZoomImage(image,geometry.
width,geometry.
height,exception);
02135
if (thumbnail == (
Image *) NULL)
02136
break;
02137 (
void)
SetImageProgressMonitor(thumbnail,(
MagickProgressMonitor) NULL,
02138 (
void *) NULL);
02139 (
void)
SetImageAttribute(thumbnail,
"label",
DefaultTileLabel);
02140
if (i == (
NumberTiles >> 1))
02141 {
02142 (
void)
QueryColorDatabase(
"#dfdfdf",&thumbnail->
matte_color,exception);
02143
AppendImageToList(&images,thumbnail);
02144
continue;
02145 }
02146
switch (preview)
02147 {
02148
case RotatePreview:
02149 {
02150 degrees+=45.0;
02151 preview_image=
RotateImage(thumbnail,degrees,exception);
02152 (
void)
FormatMagickString(label,
MaxTextExtent,
"rotate %g",degrees);
02153
break;
02154 }
02155
case ShearPreview:
02156 {
02157 degrees+=15.0;
02158 preview_image=
ShearImage(thumbnail,degrees,degrees,exception);
02159 (
void)
FormatMagickString(label,
MaxTextExtent,
"shear %gx%g",degrees,
02160 degrees);
02161
break;
02162 }
02163
case RollPreview:
02164 {
02165 x=(
long) ((i+1)*thumbnail->
columns)/
NumberTiles;
02166 y=(
long) ((i+1)*thumbnail->
rows)/
NumberTiles;
02167 preview_image=
RollImage(thumbnail,x,y,exception);
02168 (
void)
FormatMagickString(label,
MaxTextExtent,
"roll %ldx%ld",x,y);
02169
break;
02170 }
02171
case HuePreview:
02172 {
02173 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02174
if (preview_image == (
Image *) NULL)
02175
break;
02176 (
void)
FormatMagickString(factor,
MaxTextExtent,
"100,100,%g",
02177 2.0*percentage);
02178 (
void)
ModulateImage(preview_image,factor);
02179 (
void)
FormatMagickString(label,
MaxTextExtent,
"modulate %s",factor);
02180
break;
02181 }
02182
case SaturationPreview:
02183 {
02184 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02185
if (preview_image == (
Image *) NULL)
02186
break;
02187 (
void)
FormatMagickString(factor,
MaxTextExtent,
"100,%g",2.0*percentage);
02188 (
void)
ModulateImage(preview_image,factor);
02189 (
void)
FormatMagickString(label,
MaxTextExtent,
"modulate %s",factor);
02190
break;
02191 }
02192
case BrightnessPreview:
02193 {
02194 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02195
if (preview_image == (
Image *) NULL)
02196
break;
02197 (
void)
FormatMagickString(factor,
MaxTextExtent,
"%g",2.0*percentage);
02198 (
void)
ModulateImage(preview_image,factor);
02199 (
void)
FormatMagickString(label,
MaxTextExtent,
"modulate %s",factor);
02200
break;
02201 }
02202
case GammaPreview:
02203
default:
02204 {
02205 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02206
if (preview_image == (
Image *) NULL)
02207
break;
02208 gamma+=0.4f;
02209 (
void)
GammaImageChannel(preview_image,(
ChannelType)
02210 ((
long)
AllChannels &~ (
long)
OpacityChannel),gamma);
02211 (
void)
FormatMagickString(label,
MaxTextExtent,
"gamma %g",gamma);
02212
break;
02213 }
02214
case SpiffPreview:
02215 {
02216 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02217
if (preview_image != (
Image *) NULL)
02218
for (x=0; x < i; x++)
02219 (
void)
ContrastImage(preview_image,
MagickTrue);
02220 (
void)
FormatMagickString(label,
MaxTextExtent,
"contrast (%ld)",i+1);
02221
break;
02222 }
02223
case DullPreview:
02224 {
02225 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02226
if (preview_image == (
Image *) NULL)
02227
break;
02228
for (x=0; x < i; x++)
02229 (
void)
ContrastImage(preview_image,
MagickFalse);
02230 (
void)
FormatMagickString(label,
MaxTextExtent,
"+contrast (%ld)",i+1);
02231
break;
02232 }
02233
case GrayscalePreview:
02234 {
02235 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02236
if (preview_image == (
Image *) NULL)
02237
break;
02238 colors<<=1;
02239 quantize_info.
number_colors=colors;
02240 quantize_info.
colorspace=
GRAYColorspace;
02241 (
void)
QuantizeImage(&quantize_info,preview_image);
02242 (
void)
FormatMagickString(label,
MaxTextExtent,
02243
"-colorspace gray -colors %ld",colors);
02244
break;
02245 }
02246
case QuantizePreview:
02247 {
02248 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02249
if (preview_image == (
Image *) NULL)
02250
break;
02251 colors<<=1;
02252 quantize_info.
number_colors=colors;
02253 (
void)
QuantizeImage(&quantize_info,preview_image);
02254 (
void)
FormatMagickString(label,
MaxTextExtent,
"colors %ld",colors);
02255
break;
02256 }
02257
case DespecklePreview:
02258 {
02259
for (x=0; x < (i-1); x++)
02260 {
02261 preview_image=
DespeckleImage(thumbnail,exception);
02262
if (preview_image == (
Image *) NULL)
02263
break;
02264 thumbnail=
DestroyImage(thumbnail);
02265 thumbnail=preview_image;
02266 }
02267 preview_image=
DespeckleImage(thumbnail,exception);
02268
if (preview_image == (
Image *) NULL)
02269
break;
02270 (
void)
FormatMagickString(label,
MaxTextExtent,
"despeckle (%ld)",i+1);
02271
break;
02272 }
02273
case ReduceNoisePreview:
02274 {
02275 preview_image=
ReduceNoiseImage(thumbnail,radius,exception);
02276 (
void)
FormatMagickString(label,
MaxTextExtent,
"noise %g",radius);
02277
break;
02278 }
02279
case AddNoisePreview:
02280 {
02281
switch ((
int) i)
02282 {
02283
case 0: (
void) strcpy(factor,
"uniform");
break;
02284
case 1: (
void) strcpy(factor,
"gaussian");
break;
02285
case 2: (
void) strcpy(factor,
"multiplicative");
break;
02286
case 3: (
void) strcpy(factor,
"impulse");
break;
02287
case 4: (
void) strcpy(factor,
"laplacian");
break;
02288
case 5: (
void) strcpy(factor,
"Poisson");
break;
02289
default: (
void) strcpy(thumbnail->
magick,
"NULL");
break;
02290 }
02291 preview_image=
ReduceNoiseImage(thumbnail,(
double) i,exception);
02292 (
void)
FormatMagickString(label,
MaxTextExtent,
"+noise %s",factor);
02293
break;
02294 }
02295
case SharpenPreview:
02296 {
02297 preview_image=
SharpenImage(thumbnail,radius,sigma,exception);
02298 (
void)
FormatMagickString(label,
MaxTextExtent,
"sharpen %gx%g",radius,
02299 sigma);
02300
break;
02301 }
02302
case BlurPreview:
02303 {
02304 preview_image=
BlurImage(thumbnail,radius,sigma,exception);
02305 (
void)
FormatMagickString(label,
MaxTextExtent,
"blur %gx%g",radius,
02306 sigma);
02307
break;
02308 }
02309
case ThresholdPreview:
02310 {
02311 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02312
if (preview_image == (
Image *) NULL)
02313
break;
02314 (
void)
BilevelImage(thumbnail,
02315 (percentage*((
MagickRealType)
MaxRGB+1.0))/100);
02316 (
void)
FormatMagickString(label,
MaxTextExtent,
"threshold %g",
02317 (percentage*((
MagickRealType)
MaxRGB+1.0))/100);
02318
break;
02319 }
02320
case EdgeDetectPreview:
02321 {
02322 preview_image=
EdgeImage(thumbnail,radius,exception);
02323 (
void)
FormatMagickString(label,
MaxTextExtent,
"edge %g",radius);
02324
break;
02325 }
02326
case SpreadPreview:
02327 {
02328 preview_image=
SpreadImage(thumbnail,radius,exception);
02329 (
void)
FormatMagickString(label,
MaxTextExtent,
"spread %g",radius+0.5);
02330
break;
02331 }
02332
case SolarizePreview:
02333 {
02334 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02335
if (preview_image == (
Image *) NULL)
02336
break;
02337 (
void)
SolarizeImage(preview_image,
MaxRGB*percentage/100.0);
02338 (
void)
FormatMagickString(label,
MaxTextExtent,
"solarize %g",
02339
MaxRGB*percentage/100.0);
02340
break;
02341 }
02342
case ShadePreview:
02343 {
02344 degrees+=10.0;
02345 preview_image=
ShadeImage(thumbnail,
MagickTrue,degrees,degrees,
02346 exception);
02347 (
void)
FormatMagickString(label,
MaxTextExtent,
"shade %gx%g",
02348 degrees,degrees);
02349
break;
02350 }
02351
case RaisePreview:
02352 {
02353 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02354
if (preview_image == (
Image *) NULL)
02355
break;
02356 geometry.
width=(
unsigned long) (2*i+2);
02357 geometry.
height=(
unsigned long) (2*i+2);
02358 geometry.
x=i/2;
02359 geometry.
y=i/2;
02360 (
void)
RaiseImage(preview_image,&geometry,
MagickTrue);
02361 (
void)
FormatMagickString(label,
MaxTextExtent,
"raise %lux%lu%+ld%+ld",
02362 geometry.
width,geometry.
height,geometry.
x,geometry.
y);
02363
break;
02364 }
02365
case SegmentPreview:
02366 {
02367 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02368
if (preview_image == (
Image *) NULL)
02369
break;
02370 threshold+=0.4f;
02371 (
void)
SegmentImage(preview_image,
RGBColorspace,
MagickFalse,threshold,
02372 threshold);
02373 (
void)
FormatMagickString(label,
MaxTextExtent,
"segment %gx%g",
02374 threshold,threshold);
02375
break;
02376 }
02377
case SwirlPreview:
02378 {
02379 preview_image=
SwirlImage(thumbnail,degrees,exception);
02380 (
void)
FormatMagickString(label,
MaxTextExtent,
"swirl %g",degrees);
02381 degrees+=45.0;
02382
break;
02383 }
02384
case ImplodePreview:
02385 {
02386 degrees+=0.1f;
02387 preview_image=
ImplodeImage(thumbnail,degrees,exception);
02388 (
void)
FormatMagickString(label,
MaxTextExtent,
"implode %g",degrees);
02389
break;
02390 }
02391
case WavePreview:
02392 {
02393 degrees+=5.0f;
02394 preview_image=
WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
02395 (
void)
FormatMagickString(label,
MaxTextExtent,
"wave %gx%g",
02396 0.5*degrees,2.0*degrees);
02397
break;
02398 }
02399
case OilPaintPreview:
02400 {
02401 preview_image=
OilPaintImage(thumbnail,radius,exception);
02402 (
void)
FormatMagickString(label,
MaxTextExtent,
"paint %g",radius);
02403
break;
02404 }
02405
case CharcoalDrawingPreview:
02406 {
02407 preview_image=
CharcoalImage(thumbnail,radius,sigma,exception);
02408 (
void)
FormatMagickString(label,
MaxTextExtent,
"charcoal %gx%g",
02409 radius,sigma);
02410
break;
02411 }
02412
case JPEGPreview:
02413 {
02414
char
02415 filename[
MaxTextExtent];
02416
02417
int
02418 file;
02419
02420
MagickBooleanType
02421 status;
02422
02423 preview_image=
CloneImage(thumbnail,0,0,
MagickTrue,exception);
02424
if (preview_image == (
Image *) NULL)
02425
break;
02426 preview_info->
quality=(
unsigned long) percentage;
02427 (
void)
FormatMagickString(factor,
MaxTextExtent,
"%lu",
02428 preview_info->
quality);
02429 puts(factor);
02430 file=
AcquireUniqueFileResource(filename);
02431
if (file != -1)
02432 (
void) close(file);
02433 (
void)
FormatMagickString(preview_image->
filename,
MaxTextExtent,
02434
"jpeg:%s",filename);
02435 status=
WriteImage(preview_info,preview_image);
02436
if (status !=
MagickFalse)
02437 {
02438
Image
02439 *quality_image;
02440
02441 (
void)
CopyMagickString(preview_info->
filename,
02442 preview_image->
filename,
MaxTextExtent);
02443 quality_image=
ReadImage(preview_info,exception);
02444
if (quality_image != (
Image *) NULL)
02445 {
02446 preview_image=
DestroyImage(preview_image);
02447 preview_image=quality_image;
02448 }
02449 }
02450 (
void)
RelinquishUniqueFileResource(preview_image->
filename);
02451
if ((
GetBlobSize(preview_image)/1024) >= 1024)
02452 (
void)
FormatMagickString(label,
MaxTextExtent,
"quality %s\n%gmb ",
02453 factor,(
double) ((
MagickOffsetType)
GetBlobSize(preview_image))/
02454 1024.0/1024.0);
02455
else
02456
if (
GetBlobSize(preview_image) >= 1024)
02457 (
void)
FormatMagickString(label,
MaxTextExtent,
"quality %s\n%gkb ",
02458 factor,(
double) ((
MagickOffsetType)
GetBlobSize(preview_image))/
02459 1024.0);
02460
else
02461 (
void)
FormatMagickString(label,
MaxTextExtent,
"quality %s\n%lub ",
02462 factor,(
unsigned long)
GetBlobSize(thumbnail));
02463
break;
02464 }
02465 }
02466 thumbnail=
DestroyImage(thumbnail);
02467 percentage+=12.5;
02468 radius+=0.5;
02469 sigma+=0.25;
02470
if (preview_image == (
Image *) NULL)
02471
break;
02472 (
void)
SetImageAttribute(preview_image,
"label",(
char *) NULL);
02473 (
void)
SetImageAttribute(preview_image,
"label",label);
02474
AppendImageToList(&images,preview_image);
02475
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
02476 (
QuantumTick(i,
NumberTiles) !=
MagickFalse))
02477 {
02478 status=image->
progress_monitor(
PreviewImageTag,i,
NumberTiles,
02479 image->
client_data);
02480
if (status ==
MagickFalse)
02481
break;
02482 }
02483 }
02484
if (images == (
Image *) NULL)
02485 {
02486 preview_info=
DestroyImageInfo(preview_info);
02487
return((
Image *) NULL);
02488 }
02489
02490
02491
02492 montage_info=
CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
02493 (
void)
CopyMagickString(montage_info->
filename,image->
filename,
MaxTextExtent);
02494 montage_info->
shadow=
MagickTrue;
02495 (
void)
CloneString(&montage_info->
tile,
"3x3");
02496 (
void)
CloneString(&montage_info->
geometry,
DefaultPreviewGeometry);
02497 (
void)
CloneString(&montage_info->
frame,
DefaultTileFrame);
02498 montage_image=
MontageImages(images,montage_info,exception);
02499 montage_info=
DestroyMontageInfo(montage_info);
02500
DestroyImageList(images);
02501
if (montage_image == (
Image *) NULL)
02502
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
02503
if (montage_image->
montage != (
char *) NULL)
02504 {
02505
02506
02507
02508 montage_image->
montage=(
char *)
02509
RelinquishMagickMemory(montage_image->
montage);
02510
if (image->
directory != (
char *) NULL)
02511 montage_image->
directory=(
char *)
02512
RelinquishMagickMemory(montage_image->
directory);
02513 }
02514 preview_info=
DestroyImageInfo(preview_info);
02515
return(montage_image);
02516 }
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547 MagickExport Image *
RadialBlurImage(
const Image *image,
const double angle,
02548
ExceptionInfo *
exception)
02549 {
02550
Image
02551 *blur_image;
02552
02553
long
02554 y;
02555
02556
PointInfo
02557 blur_center,
02558 center;
02559
02560
MagickBooleanType
02561 status;
02562
02563
MagickRealType
02564 blur_radius,
02565 *cos_theta,
02566 offset,
02567 radius,
02568 *sin_theta,
02569 theta;
02570
02571
PixelPacket
02572 pixel;
02573
02574
MagickPixelPacket
02575 arc,
02576 zero;
02577
02578 size_t
02579 count;
02580
02581
register long
02582 i,
02583 x;
02584
02585
register PixelPacket
02586 *q;
02587
02588
unsigned long
02589 n,
02590 step;
02591
02592
02593
02594
02595
assert(image != (
Image *) NULL);
02596
assert(image->
signature ==
MagickSignature);
02597
if (image->
debug !=
MagickFalse)
02598 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
02599
assert(exception != (
ExceptionInfo *) NULL);
02600
assert(exception->
signature ==
MagickSignature);
02601 blur_image=
CloneImage(image,0,0,
MagickTrue,exception);
02602
if (blur_image == (
Image *) NULL)
02603
return((
Image *) NULL);
02604 blur_image->
storage_class=
DirectClass;
02605 blur_center.
x=(
MagickRealType) image->
columns/2.0;
02606 blur_center.
y=(
MagickRealType) image->
rows/2.0;
02607 blur_radius=sqrt(blur_center.
x*blur_center.
x+blur_center.
y*blur_center.
y);
02608 n=(
unsigned long)
02609
AbsoluteValue(4*
DegreesToRadians(angle)*sqrt(blur_radius)+2);
02610 theta=
DegreesToRadians(angle)/(
MagickRealType) (n-1);
02611 cos_theta=(
MagickRealType *)
02612
AcquireMagickMemory((size_t) n*
sizeof(*cos_theta));
02613 sin_theta=(
MagickRealType *)
02614
AcquireMagickMemory((size_t) n*
sizeof(*sin_theta));
02615
if ((cos_theta == (
MagickRealType *) NULL) ||
02616 (sin_theta == (
MagickRealType *) NULL))
02617 {
02618 blur_image=
DestroyImage(blur_image);
02619
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
02620 }
02621 offset=theta*(
MagickRealType) (n-1)/2.0;
02622
for (i=0; i < (
long) n; i++)
02623 {
02624 cos_theta[i]=cos((
double) (theta*i-offset));
02625 sin_theta[i]=sin((
double) (theta*i-offset));
02626 }
02627
02628
02629
02630 (
void)
ResetMagickMemory(&zero,0,
sizeof(zero));
02631
for (y=0; y < (
long) image->
rows; y++)
02632 {
02633 q=
GetImagePixels(blur_image,0,y,blur_image->
columns,1);
02634
if (q == (
PixelPacket *) NULL)
02635
break;
02636
for (x=0; x < (
long) image->
columns; x++)
02637 {
02638 center.
x=(
MagickRealType) x-blur_center.
x;
02639 center.
y=(
MagickRealType) y-blur_center.
y;
02640 radius=sqrt(center.
x*center.
x+center.
y*center.
y);
02641
if (radius == 0)
02642 step=1;
02643
else
02644 {
02645 step=(
unsigned long) (blur_radius/radius);
02646
if (step == 0)
02647 step=1;
02648
else
02649
if (step >= n)
02650 step=n-1;
02651 }
02652 count=0;
02653 arc=zero;
02654
for (i=0; i < (
long) n; i+=step)
02655 {
02656 pixel=
AcquireOnePixel(image,
02657 (
long)(blur_center.
x+center.
x*cos_theta[i]-center.
y*sin_theta[i]+0.5),
02658 (
long)(blur_center.
y+center.
x*sin_theta[i]+center.
y*cos_theta[i]+0.5),
02659 exception);
02660 arc.
red+=pixel.
red;
02661 arc.
green+=pixel.
green;
02662 arc.
blue+=pixel.
blue;
02663 if (image->
matte !=
MagickFalse)
02664 arc.
opacity+=pixel.
opacity;
02665 count++;
02666 }
02667
if (count != 0)
02668 {
02669 q->
red=(
Quantum) (arc.
red/count);
02670 q->
green=(
Quantum) (arc.
green/count);
02671 q->
blue=(
Quantum) (arc.
blue/count);
02672
if (image->
matte !=
MagickFalse)
02673 q->
opacity=(
Quantum) (arc.
opacity/count);
02674 }
02675 q++;
02676 }
02677
if (
SyncImagePixels(blur_image) ==
MagickFalse)
02678
break;
02679
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
02680 (
QuantumTick(y,image->
rows) !=
MagickFalse))
02681 {
02682 status=image->
progress_monitor(
BlurImageTag,y,image->
rows,
02683 image->
client_data);
02684
if (status ==
MagickFalse)
02685
break;
02686 }
02687 }
02688 cos_theta=(
MagickRealType *)
RelinquishMagickMemory(cos_theta);
02689 sin_theta=(
MagickRealType *)
RelinquishMagickMemory(sin_theta);
02690
return(blur_image);
02691 }
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727 MagickExport MagickBooleanType RandomThresholdImage(
Image *image,
02728
const char *thresholds,
ExceptionInfo *
exception)
02729 {
02730
MagickBooleanType
02731 status;
02732
02733 status=
RandomThresholdImageChannel(image,(
ChannelType) ((
long)
AllChannels &~
02734 (
long)
OpacityChannel),thresholds,exception);
02735
return(status);
02736 }
02737
02738 MagickExport MagickBooleanType RandomThresholdImageChannel(
Image *image,
02739
const ChannelType channel,
const char *thresholds,
ExceptionInfo *
exception)
02740 {
02741
long
02742 y;
02743
02744
MagickBooleanType
02745 status;
02746
02747
MagickPixelPacket
02748 threshold;
02749
02750
MagickRealType
02751 min_threshold,
02752 max_threshold;
02753
02754
register long
02755 x;
02756
02757
register IndexPacket
02758 *indexes;
02759
02760
register PixelPacket
02761 *q;
02762
02763
static MagickRealType
02764 o2[4] = { 0.2f, 0.6f, 0.8f, 0.4f },
02765 o3[9] = { 0.1f, 0.6f, 0.3f, 0.7f, 0.5f, 0.8f, 0.4f, 0.9f, 0.2f },
02766 o4[16] = { 0.1f, 0.7f, 1.1f, 0.3f, 1.0f, 0.5f, 1.5f, 0.8f,
02767 1.4f, 1.6f, 0.6f, 1.2f, 0.4f, 0.9f, 1.3f, 0.2f };
02768
02769
unsigned long
02770 order;
02771
02772
02773
02774
02775
assert(image != (
Image *) NULL);
02776
assert(image->
signature ==
MagickSignature);
02777
if (image->
debug !=
MagickFalse)
02778 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
02779
assert(exception != (
ExceptionInfo *) NULL);
02780
assert(exception->
signature ==
MagickSignature);
02781
if (thresholds == (
const char *) NULL)
02782
return(
MagickTrue);
02783
GetMagickPixelPacket(image,&threshold);
02784 min_threshold=0.0;
02785 max_threshold=(
MagickRealType)
MaxRGB;
02786 order=1;
02787
if (
LocaleCompare(thresholds,
"2x2") == 0)
02788 order=2;
02789
else
02790
if (
LocaleCompare(thresholds,
"3x3") == 0)
02791 order=3;
02792
else
02793
if (
LocaleCompare(thresholds,
"4x4") == 0)
02794 order=4;
02795
else
02796 {
02797
GeometryInfo
02798 geometry_info;
02799
02800
MagickStatusType
02801 flags;
02802
02803 flags=
ParseGeometry(thresholds,&geometry_info);
02804 min_threshold=geometry_info.
rho;
02805 max_threshold=geometry_info.
sigma;
02806
if ((flags &
SigmaValue) == 0)
02807 max_threshold=min_threshold;
02808
if (
strchr(thresholds,
'%') != (
char *) NULL)
02809 {
02810 max_threshold*=(0.01f*
MaxRGB);
02811 min_threshold*=(0.01f*
MaxRGB);
02812 }
02813 }
02814
if (channel ==
AllChannels)
02815 {
02816
IndexPacket
02817 index;
02818
02819
MagickRealType
02820 intensity;
02821
02822
if (
AllocateImageColormap(image,2) ==
MagickFalse)
02823
ThrowBinaryException(
ResourceLimitError,
"MemoryAllocationFailed",
02824 image->
filename);
02825
for (y=0; y < (
long) image->
rows; y++)
02826 {
02827 q=
GetImagePixels(image,0,y,image->
columns,1);
02828
if (q == (
PixelPacket *) NULL)
02829
break;
02830 indexes=
GetIndexes(image);
02831
for (x=0; x < (
long) image->
columns; x++)
02832 {
02833 intensity=(
MagickRealType)
PixelIntensityToQuantum(q);
02834
switch (order)
02835 {
02836
case 1:
02837 {
02838
if (intensity < min_threshold)
02839 threshold.
index=min_threshold;
02840
else
02841
if (intensity > max_threshold)
02842 threshold.
index=max_threshold;
02843
else
02844 threshold.
index=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02845
break;
02846 }
02847
case 2:
02848 {
02849 threshold.
index=(
MagickRealType)
MaxRGB*o2[(x % 2)+2*(y % 2)];
02850
break;
02851 }
02852
case 3:
02853 {
02854 threshold.
index=(
MagickRealType)
MaxRGB*o3[(x % 3)+3*(y % 3)];
02855
break;
02856 }
02857
case 4:
02858 {
02859 threshold.
index=(
MagickRealType)
MaxRGB*o4[(x % 4)+4*(y % 4)]/1.7;
02860
break;
02861 }
02862 }
02863 index=(
IndexPacket)
02864 ((
MagickRealType) intensity < threshold.
index ? 0 : 1);
02865 indexes[x]=index;
02866 *q++=image->
colormap[index];
02867 }
02868
if (
SyncImagePixels(image) ==
MagickFalse)
02869
break;
02870
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
02871 (
QuantumTick(y,image->
rows) !=
MagickFalse))
02872 {
02873 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
02874 image->
client_data);
02875
if (status ==
MagickFalse)
02876
break;
02877 }
02878 }
02879
return(
MagickTrue);
02880 }
02881 image->
storage_class=
DirectClass;
02882
for (y=0; y < (
long) image->
rows; y++)
02883 {
02884 q=
GetImagePixels(image,0,y,image->
columns,1);
02885
if (q == (
PixelPacket *) NULL)
02886
break;
02887 indexes=
GetIndexes(image);
02888
for (x=0; x < (
long) image->
columns; x++)
02889 {
02890
switch (order)
02891 {
02892
case 1:
02893 {
02894
if ((channel &
RedChannel) != 0)
02895 {
02896
if ((
MagickRealType) q->
red < min_threshold)
02897 threshold.
red=min_threshold;
02898
else
02899
if ((
MagickRealType) q->
red > max_threshold)
02900 threshold.
red=max_threshold;
02901
else
02902 threshold.
red=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02903 }
02904
if ((channel &
GreenChannel) != 0)
02905 {
02906
if ((
MagickRealType) q->
green < min_threshold)
02907 threshold.
green=min_threshold;
02908
else
02909
if ((
MagickRealType) q->
green > max_threshold)
02910 threshold.
green=max_threshold;
02911
else
02912 threshold.
green=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02913 }
02914
if ((channel &
BlueChannel) != 0)
02915 {
02916
if ((
MagickRealType) q->
blue < min_threshold)
02917 threshold.
blue=min_threshold;
02918
else
02919
if ((
MagickRealType) q->
blue > max_threshold)
02920 threshold.
blue=max_threshold;
02921
else
02922 threshold.
blue=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02923 }
02924
if (((channel &
OpacityChannel) != 0) &&
02925 (image->
matte !=
MagickFalse))
02926 {
02927
if ((
MagickRealType) q->
opacity < min_threshold)
02928 threshold.
opacity=min_threshold;
02929
else
02930
if ((
MagickRealType) q->
opacity > max_threshold)
02931 threshold.
opacity=max_threshold;
02932
else
02933 threshold.
opacity=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02934 }
02935
if (((channel &
IndexChannel) != 0) &&
02936 (image->
colorspace ==
CMYKColorspace))
02937 {
02938
if ((
MagickRealType) indexes[x] < min_threshold)
02939 threshold.
index=min_threshold;
02940
else
02941
if ((
MagickRealType) indexes[x] > max_threshold)
02942 threshold.
index=max_threshold;
02943
else
02944 threshold.
index=(
MagickRealType) (
MaxRGB*
GetRandomValue());
02945 }
02946
break;
02947 }
02948
case 2:
02949 {
02950 threshold.
red=(
MagickRealType)
MaxRGB*o2[(x % 2)+2*(y % 2)];
02951 threshold.
green=threshold.
red;
02952 threshold.
blue=threshold.
red;
02953 threshold.
opacity=threshold.
red;
02954 threshold.
index=threshold.
red;
02955
break;
02956 }
02957
case 3:
02958 {
02959 threshold.
red=(
MagickRealType)
MaxRGB*o3[(x % 3)+3*(y % 3)];
02960 threshold.
green=threshold.
red;
02961 threshold.
blue=threshold.
red;
02962 threshold.
opacity=threshold.
red;
02963 threshold.
index=threshold.
red;
02964
break;
02965 }
02966
case 4:
02967 {
02968 threshold.
red=(
MagickRealType)
MaxRGB*o4[(x % 4)+4*(y % 4)]/1.7;
02969 threshold.
green=threshold.
red;
02970 threshold.
blue=threshold.
red;
02971 threshold.
opacity=threshold.
red;
02972 threshold.
index=threshold.
red;
02973
break;
02974 }
02975 }
02976
if ((channel &
RedChannel) != 0)
02977 q->
red=(
Quantum)
02978 ((
MagickRealType) q->
red <= threshold.
red ? 0 :
MaxRGB);
02979
if ((channel &
GreenChannel) != 0)
02980 q->
green=(
Quantum)
02981 ((
MagickRealType) q->
green <= threshold.
green ? 0 :
MaxRGB);
02982
if ((channel &
BlueChannel) != 0)
02983 q->
blue=(
Quantum)
02984 ((
MagickRealType) q->
blue <= threshold.
blue ? 0 :
MaxRGB);
02985
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
02986 q->
opacity=(
Quantum)
02987 ((
MagickRealType) q->
opacity <= threshold.
opacity ? 0 :
MaxRGB);
02988
if (((channel &
IndexChannel) != 0) &&
02989 (image->
colorspace ==
CMYKColorspace))
02990 indexes[x]=(
IndexPacket)
02991 ((
MagickRealType) indexes[x] <= threshold.
index ? 0 :
MaxRGB);
02992 q++;
02993 }
02994
if (
SyncImagePixels(image) ==
MagickFalse)
02995
break;
02996
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
02997 (
QuantumTick(y,image->
rows) !=
MagickFalse))
02998 {
02999 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
03000 image->
client_data);
03001
if (status ==
MagickFalse)
03002
break;
03003 }
03004 }
03005
return(
MagickTrue);
03006 }
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039 static MagickPixelPacket GetNonpeakMedianList(
MedianPixelList *pixel_list)
03040 {
03041
MagickPixelPacket
03042 pixel;
03043
03044
register MedianSkipList
03045 *list;
03046
03047
register long
03048 channel;
03049
03050
unsigned long
03051 channels[5],
03052 center,
03053 color,
03054 count,
03055 previous,
03056 next;
03057
03058
03059
03060
03061 center=pixel_list->
center;
03062
for (channel=0; channel < 5; channel++)
03063 {
03064 list=pixel_list->
lists+channel;
03065 color=65536UL;
03066 next=list->
nodes[color].
next[0];
03067 count=0;
03068
do
03069 {
03070 previous=color;
03071 color=next;
03072 next=list->
nodes[color].
next[0];
03073 count+=list->
nodes[color].
count;
03074 }
03075
while (count <= center);
03076
if ((previous == 65536UL) && (next != 65536UL))
03077 color=next;
03078
else
03079
if ((previous != 65536UL) && (next == 65536UL))
03080 color=previous;
03081 channels[channel]=color;
03082 }
03083
GetMagickPixelPacket((
const Image *) NULL,&pixel);
03084 pixel.
red=(
MagickRealType)
ScaleShortToQuantum(channels[0]);
03085 pixel.
green=(
MagickRealType)
ScaleShortToQuantum(channels[1]);
03086 pixel.
blue=(
MagickRealType)
ScaleShortToQuantum(channels[2]);
03087 pixel.
opacity=(
MagickRealType)
ScaleShortToQuantum(channels[3]);
03088 pixel.
index=(
MagickRealType)
ScaleShortToQuantum(channels[4]);
03089
return(pixel);
03090 }
03091
03092 MagickExport Image *
ReduceNoiseImage(
const Image *image,
const double radius,
03093
ExceptionInfo *
exception)
03094 {
03095
#define ReduceNoiseImageTag "ReduceNoise/Image"
03096
03097
Image
03098 *noise_image;
03099
03100
long
03101 x,
03102 y;
03103
03104
MagickBooleanType
03105 status;
03106
03107
MagickPixelPacket
03108 pixel;
03109
03110
MedianPixelList
03111 *skiplist;
03112
03113
register const PixelPacket
03114 *p,
03115 *r;
03116
03117
register IndexPacket
03118 *indexes,
03119 *noise_indexes,
03120 *s;
03121
03122
register long
03123 u,
03124 v;
03125
03126
register PixelPacket
03127 *q;
03128
03129
unsigned long
03130 width;
03131
03132
03133
03134
03135
assert(image != (
Image *) NULL);
03136
assert(image->
signature ==
MagickSignature);
03137
if (image->
debug !=
MagickFalse)
03138 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03139
assert(exception != (
ExceptionInfo *) NULL);
03140
assert(exception->
signature ==
MagickSignature);
03141 width=
GetOptimalKernelWidth(radius,0.5);
03142
if ((image->
columns < width) || (image->
rows < width))
03143
ThrowImageException(
OptionError,
"ImageSmallerThanKernelRadius");
03144 noise_image=
CloneImage(image,0,0,
MagickTrue,exception);
03145
if (noise_image == (
Image *) NULL)
03146
return((
Image *) NULL);
03147 noise_image->
storage_class=
DirectClass;
03148
03149
03150
03151 skiplist=(
MedianPixelList *)
AcquireMagickMemory(
sizeof(*skiplist));
03152
if (skiplist == (
MedianPixelList *) NULL)
03153 {
03154 noise_image=
DestroyImage(noise_image);
03155
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
03156 }
03157
03158
03159
03160
InitializeMedianList(skiplist,width);
03161
for (y=0; y < (
long) noise_image->
rows; y++)
03162 {
03163 p=
AcquireImagePixels(image,-((
long) width/2),y-(
long) width/2,
03164 image->
columns+width,width,exception);
03165 q=
GetImagePixels(noise_image,0,y,noise_image->
columns,1);
03166
if ((p == (
const PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
03167
break;
03168 indexes=
GetIndexes(image);
03169 noise_indexes=
GetIndexes(noise_image);
03170
for (x=0; x < (
long) noise_image->
columns; x++)
03171 {
03172 r=p;
03173 s=indexes+x;
03174
ResetMedianList(skiplist);
03175
for (v=0; v < (
long) width; v++)
03176 {
03177
for (u=0; u < (
long) width; u++)
03178
InsertMedianList(image,r+u,s+u,skiplist);
03179 r+=image->
columns+width;
03180 s+=image->
columns+width;
03181 }
03182 pixel=
GetNonpeakMedianList(skiplist);
03183
SetPixelPacket(&pixel,q,noise_indexes+x);
03184 p++;
03185 q++;
03186 }
03187
if (
SyncImagePixels(noise_image) ==
MagickFalse)
03188
break;
03189
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
03190 (
QuantumTick(y,image->
rows) !=
MagickFalse))
03191 {
03192 status=image->
progress_monitor(
ReduceNoiseImageTag,y,image->
rows,
03193 image->
client_data);
03194
if (status ==
MagickFalse)
03195
break;
03196 }
03197 }
03198 skiplist=(
MedianPixelList *)
RelinquishMagickMemory(skiplist);
03199
return(noise_image);
03200 }
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234 MagickExport Image *
ShadeImage(
const Image *image,
const MagickBooleanType gray,
03235
const double azimuth,
const double elevation,
ExceptionInfo *
exception)
03236 {
03237
#define ShadeImageTag "Shade/Image"
03238
03239
Image
03240 *shade_image;
03241
03242
long
03243 y;
03244
03245
MagickBooleanType
03246 status;
03247
03248
MagickRealType
03249 distance,
03250 normal_distance,
03251 shade;
03252
03253
PrimaryInfo
03254 light,
03255 normal;
03256
03257
register const PixelPacket
03258 *p,
03259 *s0,
03260 *s1,
03261 *s2;
03262
03263
register long
03264 x;
03265
03266
register PixelPacket
03267 *q;
03268
03269
03270
03271
03272
assert(image != (
const Image *) NULL);
03273
assert(image->
signature ==
MagickSignature);
03274
if (image->
debug !=
MagickFalse)
03275 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03276
assert(exception != (
ExceptionInfo *) NULL);
03277
assert(exception->
signature ==
MagickSignature);
03278 shade_image=
CloneImage(image,0,0,
MagickTrue,exception);
03279
if (shade_image == (
Image *) NULL)
03280
return((
Image *) NULL);
03281 shade_image->
storage_class=
DirectClass;
03282
03283
03284
03285 light.
x=(
double)
MaxRGB*cos(
DegreesToRadians(azimuth))*
03286 cos(
DegreesToRadians(elevation));
03287 light.
y=(
double)
MaxRGB*sin(
DegreesToRadians(azimuth))*
03288 cos(
DegreesToRadians(elevation));
03289 light.
z=(
double)
MaxRGB*sin(
DegreesToRadians(elevation));
03290 normal.
z=2.0*
MaxRGB;
03291
03292
03293
03294
for (y=0; y < (
long) image->
rows; y++)
03295 {
03296 p=
AcquireImagePixels(image,-1,y-1,image->
columns+2,3,exception);
03297 q=
GetImagePixels(shade_image,0,y,shade_image->
columns,1);
03298
if ((p == (
PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
03299
break;
03300
03301
03302
03303 s0=p+1;
03304 s1=s0+image->
columns+2;
03305 s2=s1+image->
columns+2;
03306
for (x=0; x < (
long) image->
columns; x++)
03307 {
03308
03309
03310
03311 normal.
x=
PixelIntensity(s0-1)+
PixelIntensity(s1-1)+
PixelIntensity(s2-1)-
03312
PixelIntensity(s0+1)-
PixelIntensity(s1+1)-
PixelIntensity(s2+1);
03313 normal.
y=
PixelIntensity(s2-1)+
PixelIntensity(s2)+
PixelIntensity(s2+1)-
03314
PixelIntensity(s0-1)-
PixelIntensity(s0)-
PixelIntensity(s0+1);
03315
if ((normal.
x == 0.0) && (normal.
y == 0.0))
03316 shade=light.
z;
03317
else
03318 {
03319 shade=0.0;
03320 distance=normal.
x*light.
x+normal.
y*light.
y+normal.
z*light.
z;
03321
if (distance >
MagickEpsilon)
03322 {
03323 normal_distance=
03324 normal.
x*normal.
x+normal.
y*normal.
y+normal.
z*normal.
z;
03325
if (normal_distance > (
MagickEpsilon*
MagickEpsilon))
03326 shade=distance/sqrt(normal_distance);
03327 }
03328 }
03329
if (gray !=
MagickFalse)
03330 {
03331 q->
red=(
Quantum) shade;
03332 q->
green=(
Quantum) shade;
03333 q->
blue=(
Quantum) shade;
03334 }
03335
else
03336 {
03337 q->
red=(
Quantum) (
QuantumScale*shade*s1->
red+0.5);
03338 q->
green=(
Quantum) (
QuantumScale*shade*s1->
green+0.5);
03339 q->
blue=(
Quantum) (
QuantumScale*shade*s1->
blue+0.5);
03340 }
03341 q->
opacity=s1->
opacity;
03342 s0++;
03343 s1++;
03344 s2++;
03345 q++;
03346 }
03347
if (
SyncImagePixels(shade_image) ==
MagickFalse)
03348
break;
03349
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
03350 (
QuantumTick(y,image->
rows) !=
MagickFalse))
03351 {
03352 status=image->
progress_monitor(
ShadeImageTag,y,image->
rows,
03353 image->
client_data);
03354
if (status ==
MagickFalse)
03355
break;
03356 }
03357 }
03358
return(shade_image);
03359 }
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402 MagickExport Image *
SharpenImage(
const Image *image,
const double radius,
03403
const double sigma,
ExceptionInfo *
exception)
03404 {
03405
Image
03406 *sharp_image;
03407
03408 sharp_image=
SharpenImageChannel(image,(
ChannelType) ((
long)
AllChannels &~
03409 (
long)
OpacityChannel),radius,sigma,exception);
03410
return(sharp_image);
03411 }
03412
03413 MagickExport Image *
SharpenImageChannel(
const Image *image,
03414
const ChannelType channel,
const double radius,
const double sigma,
03415
ExceptionInfo *
exception)
03416 {
03417
double
03418 *kernel;
03419
03420
Image
03421 *sharp_image;
03422
03423
MagickRealType
03424 alpha,
03425 normalize;
03426
03427
register long
03428 i,
03429 u,
03430 v;
03431
03432
unsigned long
03433 width;
03434
03435
assert(image != (
const Image *) NULL);
03436
assert(image->
signature ==
MagickSignature);
03437
if (image->
debug !=
MagickFalse)
03438 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03439
assert(exception != (
ExceptionInfo *) NULL);
03440
assert(exception->
signature ==
MagickSignature);
03441
if (sigma == 0.0)
03442
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
03443 width=
GetOptimalKernelWidth(radius,sigma);
03444
if ((image->
columns < width) || (image->
rows < width))
03445
ThrowImageException(
OptionError,
"ImageSmallerThanRadius");
03446 kernel=(
double *)
AcquireMagickMemory((size_t) width*width*
sizeof(*kernel));
03447
if (kernel == (
double *) NULL)
03448
ThrowImageException(
ResourceLimitError,
"MemoryAllocationFailed");
03449 i=0;
03450 normalize=0.0;
03451
for (v=(-((
long) width/2)); v <= (
long) (width/2); v++)
03452 {
03453
for (u=(-((
long) width/2)); u <= (
long) (width/2); u++)
03454 {
03455 alpha=exp(-((
double) u*u+v*v)/(2.0*sigma*sigma));
03456 kernel[i]=alpha/(2.0*
MagickPI*sigma*sigma);
03457 normalize+=kernel[i];
03458 i++;
03459 }
03460 }
03461 kernel[i/2]=(-2.0)*normalize;
03462 sharp_image=
ConvolveImageChannel(image,channel,width,kernel,exception);
03463 kernel=(
double *)
RelinquishMagickMemory(kernel);
03464
return(sharp_image);
03465 }
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495 MagickExport Image *
SpreadImage(
const Image *image,
const double radius,
03496
ExceptionInfo *
exception)
03497 {
03498
#define SpreadImageTag "Spread/Image"
03499
03500
Image
03501 *spread_image;
03502
03503
long
03504 x_distance,
03505 y,
03506 y_distance;
03507
03508
MagickBooleanType
03509 status;
03510
03511
register const PixelPacket
03512 *p;
03513
03514
register long
03515 x;
03516
03517
register PixelPacket
03518 *q;
03519
03520
unsigned long
03521 width;
03522
03523
assert(image != (
const Image *) NULL);
03524
assert(image->
signature ==
MagickSignature);
03525
if (image->
debug !=
MagickFalse)
03526 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03527
assert(exception != (
ExceptionInfo *) NULL);
03528
assert(exception->
signature ==
MagickSignature);
03529
if ((image->
columns < 3) || (image->
rows < 3))
03530
return((
Image *) NULL);
03531
03532
03533
03534 spread_image=
CloneImage(image,0,0,
MagickTrue,exception);
03535
if (spread_image == (
Image *) NULL)
03536
return((
Image *) NULL);
03537 spread_image->
storage_class=
DirectClass;
03538
03539
03540
03541 width=2*((
unsigned long) radius)+1;
03542
for (y=0; y < (
long) image->
rows; y++)
03543 {
03544 p=
AcquireImagePixels(image,-(
long) width/2,y-(
long) width/2,image->
columns+
03545 width,width,exception);
03546 q=
GetImagePixels(spread_image,0,y,spread_image->
columns,1);
03547
if ((p == (
const PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
03548
break;
03549
for (x=0; x < (
long) image->
columns; x++)
03550 {
03551 x_distance=(
long) ((
MagickRealType) width*
GetRandomValue());
03552 y_distance=(
long) ((
MagickRealType) width*
GetRandomValue());
03553 *q++=(*(p+(image->
columns+width)*y_distance+x+x_distance));
03554 }
03555
if (
SyncImagePixels(spread_image) ==
MagickFalse)
03556
break;
03557
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
03558 (
QuantumTick(y,image->
rows) !=
MagickFalse))
03559 {
03560 status=image->
progress_monitor(
SpreadImageTag,y,image->
rows,
03561 image->
client_data);
03562
if (status ==
MagickFalse)
03563
break;
03564 }
03565 }
03566
return(spread_image);
03567 }
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608
03609
03610
03611 MagickExport Image *
UnsharpMaskImage(
const Image *image,
const double radius,
03612
const double sigma,
const double amount,
const double threshold,
03613
ExceptionInfo *
exception)
03614 {
03615
Image
03616 *sharp_image;
03617
03618 sharp_image=
UnsharpMaskImageChannel(image,(
ChannelType) ((
long)
03619
AllChannels &~ (
long)
OpacityChannel),radius,sigma,amount,threshold,
03620 exception);
03621
return(sharp_image);
03622 }
03623
03624 MagickExport Image *
UnsharpMaskImageChannel(
const Image *image,
03625
const ChannelType channel,
const double radius,
const double sigma,
03626
const double amount,
const double threshold,
ExceptionInfo *
exception)
03627 {
03628
#define SharpenImageTag "Sharpen/Image"
03629
03630
Image
03631 *sharp_image;
03632
03633
long
03634 y;
03635
03636
MagickBooleanType
03637 status;
03638
03639
MagickPixelPacket
03640 pixel;
03641
03642
register const PixelPacket
03643 *p;
03644
03645
register IndexPacket
03646 *indexes,
03647 *sharp_indexes;
03648
03649
register long
03650 x;
03651
03652
register PixelPacket
03653 *q;
03654
03655
assert(image != (
const Image *) NULL);
03656
assert(image->
signature ==
MagickSignature);
03657
if (image->
debug !=
MagickFalse)
03658 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03659
assert(exception != (
ExceptionInfo *) NULL);
03660
if (sigma == 0.0)
03661
ThrowImageException(
OptionError,
"ZeroSigmaNotPermitted");
03662 sharp_image=
BlurImageChannel(image,channel,radius,sigma,exception);
03663
if (sharp_image == (
Image *) NULL)
03664
return((
Image *) NULL);
03665
for (y=0; y < (
long) image->
rows; y++)
03666 {
03667 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
03668 q=
GetImagePixels(sharp_image,0,y,sharp_image->
columns,1);
03669
if ((p == (
const PixelPacket *) NULL) || (q == (
PixelPacket *) NULL))
03670
break;
03671 indexes=
GetIndexes(image);
03672 sharp_indexes=
GetIndexes(sharp_image);
03673
for (x=0; x < (
long) image->
columns; x++)
03674 {
03675
if ((channel &
RedChannel) != 0)
03676 {
03677 pixel.
red=p->
red-(
MagickRealType) q->
red;
03678
if (
AbsoluteValue(2.0*pixel.
red) < (
MaxRGB*threshold))
03679 pixel.
red=(
MagickRealType) p->
red;
03680
else
03681 pixel.
red=p->
red+(pixel.
red*amount);
03682 q->
red=
RoundToQuantum(pixel.
red);
03683 }
03684
if ((channel &
GreenChannel) != 0)
03685 {
03686 pixel.
green=p->
green-(
MagickRealType) q->
green;
03687
if (
AbsoluteValue(2.0*pixel.
green) < (
MaxRGB*threshold))
03688 pixel.
green=(
MagickRealType) p->
green;
03689
else
03690 pixel.
green=p->
green+(pixel.
green*amount);
03691 q->
green=
RoundToQuantum(pixel.
green);
03692 }
03693
if ((channel &
BlueChannel) != 0)
03694 {
03695 pixel.
blue=p->
blue-(
MagickRealType) q->
blue;
03696
if (
AbsoluteValue(2.0*pixel.
blue) < (
MaxRGB*threshold))
03697 pixel.
blue=(
MagickRealType) p->
blue;
03698
else
03699 pixel.
blue=p->
blue+(pixel.
blue*amount);
03700 q->
blue=
RoundToQuantum(pixel.
blue);
03701 }
03702
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
03703 {
03704 pixel.
opacity=p->
opacity-(
MagickRealType) q->
opacity;
03705
if (
AbsoluteValue(2.0*pixel.
opacity) < (
MaxRGB*threshold))
03706 pixel.
opacity=(
MagickRealType) p->
opacity;
03707
else
03708 pixel.
opacity=p->
opacity+(pixel.
opacity*amount);
03709 q->
opacity=
RoundToQuantum(pixel.
opacity);
03710 }
03711
if (((channel &
IndexChannel) != 0) &&
03712 (image->
colorspace ==
CMYKColorspace))
03713 {
03714 pixel.
index=sharp_indexes[x]-(
MagickRealType) indexes[x];
03715
if (
AbsoluteValue(2.0*pixel.
index) < (
MaxRGB*threshold))
03716 pixel.
index=(
MagickRealType) sharp_indexes[x];
03717
else
03718 pixel.
index=sharp_indexes[x]+(pixel.
index*amount);
03719 indexes[x]=
RoundToQuantum(pixel.
index);
03720 }
03721 p++;
03722 q++;
03723 }
03724
if (
SyncImagePixels(sharp_image) ==
MagickFalse)
03725
break;
03726
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
03727 (
QuantumTick(y,image->
rows) !=
MagickFalse))
03728 {
03729 status=image->
progress_monitor(
SharpenImageTag,y,image->
rows,
03730 image->
client_data);
03731
if (status ==
MagickFalse)
03732
break;
03733 }
03734 }
03735
return(sharp_image);
03736 }
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764 MagickExport MagickBooleanType WhiteThresholdImage(
Image *image,
03765
const char *threshold)
03766 {
03767
#define ThresholdImageTag "Threshold/Image"
03768
03769
GeometryInfo
03770 geometry_info;
03771
03772
long
03773 y;
03774
03775
MagickBooleanType
03776 status;
03777
03778
MagickPixelPacket
03779 pixel;
03780
03781
MagickStatusType
03782 flags;
03783
03784
register long
03785 x;
03786
03787
register PixelPacket
03788 *q;
03789
03790
03791
03792
03793
assert(image != (
Image *) NULL);
03794
assert(image->
signature ==
MagickSignature);
03795
if (image->
debug !=
MagickFalse)
03796 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
03797
if (threshold == (
const char *) NULL)
03798
return(
MagickTrue);
03799 image->
storage_class=
DirectClass;
03800 flags=
ParseGeometry(threshold,&geometry_info);
03801 pixel.
red=geometry_info.
rho;
03802 pixel.
green=geometry_info.
sigma;
03803
if ((flags &
SigmaValue) == 0)
03804 pixel.
green=pixel.
red;
03805 pixel.
blue=geometry_info.
xi;
03806
if ((flags &
XiValue) == 0)
03807 pixel.
blue=pixel.
red;
03808 pixel.
opacity=geometry_info.
psi;
03809
if ((flags &
PsiValue) == 0)
03810 pixel.
opacity=(
MagickRealType)
OpaqueOpacity;
03811
if ((flags &
PercentValue) != 0)
03812 {
03813 pixel.
red*=
MaxRGB/100.0f;
03814 pixel.
green*=
MaxRGB/100.0f;
03815 pixel.
blue*=
MaxRGB/100.0f;
03816 pixel.
opacity*=
MaxRGB/100.0f;
03817 }
03818
for (y=0; y < (
long) image->
rows; y++)
03819 {
03820 q=
GetImagePixels(image,0,y,image->
columns,1);
03821
if (q == (
PixelPacket *) NULL)
03822
break;
03823
if (
IsGray(pixel) !=
MagickFalse)
03824
for (x=(
long) image->
columns-1; x >= 0; x--)
03825 {
03826
if ((
MagickRealType)
PixelIntensityToQuantum(q) > pixel.
red)
03827 {
03828 q->
red=
MaxRGB;
03829 q->
green=
MaxRGB;
03830 q->
blue=
MaxRGB;
03831 }
03832 q++;
03833 }
03834
else
03835
for (x=(
long) image->
columns-1; x >= 0; x--)
03836 {
03837
if ((
MagickRealType) q->
red > pixel.
red)
03838 q->
red=
MaxRGB;
03839
if ((
MagickRealType) q->
green > pixel.
green)
03840 q->
green=
MaxRGB;
03841
if ((
MagickRealType) q->
blue > pixel.
blue)
03842 q->
blue=
MaxRGB;
03843
if ((
MagickRealType) q->
opacity > pixel.
opacity)
03844 q->
opacity=
MaxRGB;
03845 q++;
03846 }
03847
if (
SyncImagePixels(image) ==
MagickFalse)
03848
break;
03849
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
03850 (
QuantumTick(y,image->
rows) !=
MagickFalse))
03851 {
03852 status=image->
progress_monitor(
ThresholdImageTag,y,image->
rows,
03853 image->
client_data);
03854
if (status ==
MagickFalse)
03855
break;
03856 }
03857 }
03858
return(
MagickTrue);
03859 }