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/artifact.h"
00045 #include "magick/cache-view.h"
00046 #include "magick/client.h"
00047 #include "magick/color.h"
00048 #include "magick/color-private.h"
00049 #include "magick/colorspace.h"
00050 #include "magick/colorspace-private.h"
00051 #include "magick/composite.h"
00052 #include "magick/composite-private.h"
00053 #include "magick/constitute.h"
00054 #include "magick/draw.h"
00055 #include "magick/fx.h"
00056 #include "magick/gem.h"
00057 #include "magick/geometry.h"
00058 #include "magick/image.h"
00059 #include "magick/image-private.h"
00060 #include "magick/list.h"
00061 #include "magick/log.h"
00062 #include "magick/monitor.h"
00063 #include "magick/monitor-private.h"
00064 #include "magick/memory_.h"
00065 #include "magick/option.h"
00066 #include "magick/pixel-private.h"
00067 #include "magick/property.h"
00068 #include "magick/quantum.h"
00069 #include "magick/resample.h"
00070 #include "magick/resource_.h"
00071 #include "magick/string_.h"
00072 #include "magick/utility.h"
00073 #include "magick/version.h"
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
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 static inline double MagickMin(const double x,const double y)
00138 {
00139 if (x < y)
00140 return(x);
00141 return(y);
00142 }
00143 static inline double MagickMax(const double x,const double y)
00144 {
00145 if (x > y)
00146 return(x);
00147 return(y);
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 static inline MagickRealType Add(const MagickRealType p,const MagickRealType q)
00179 {
00180 MagickRealType
00181 pixel;
00182
00183 pixel=p+q;
00184 if (pixel > QuantumRange)
00185 pixel-=(QuantumRange+1.0);
00186 return(pixel);
00187 }
00188
00189 static inline void CompositeAdd(const MagickPixelPacket *p,
00190 const MagickRealType alpha,const MagickPixelPacket *q,
00191 const MagickRealType beta,MagickPixelPacket *composite)
00192 {
00193 composite->red=Add(p->red,q->red);
00194 composite->green=Add(p->green,q->green);
00195 composite->blue=Add(p->blue,q->blue);
00196 composite->opacity=Add(alpha,beta);
00197 if (q->colorspace == CMYKColorspace)
00198 composite->index=Add(p->index,q->index);
00199 }
00200
00201 static inline MagickRealType Atop(const MagickRealType p,
00202 const MagickRealType Sa,const MagickRealType q,
00203 const MagickRealType magick_unused(Da))
00204 {
00205 return(p*Sa+q*(1.0-Sa));
00206 }
00207
00208 static inline void CompositeAtop(const MagickPixelPacket *p,
00209 const MagickRealType alpha,const MagickPixelPacket *q,
00210 const MagickRealType beta,MagickPixelPacket *composite)
00211 {
00212 MagickRealType
00213 Sa;
00214
00215 Sa=1.0-QuantumScale*alpha;
00216 composite->opacity=beta;
00217 composite->red=Atop(p->red,Sa,q->red,1.0);
00218 composite->green=Atop(p->green,Sa,q->green,1.0);
00219 composite->blue=Atop(p->blue,Sa,q->blue,1.0);
00220 if (q->colorspace == CMYKColorspace)
00221 composite->index=Atop(p->index,Sa,q->index,1.0);
00222 }
00223
00224
00225
00226
00227
00228 static inline void CompositeBumpmap(const MagickPixelPacket *p,
00229 const MagickRealType magick_unused(alpha),const MagickPixelPacket *q,
00230 const MagickRealType magick_unused(beta),MagickPixelPacket *composite)
00231 {
00232 MagickRealType
00233 intensity;
00234
00235 intensity=MagickPixelIntensity(p);
00236 composite->red=QuantumScale*intensity*q->red;
00237 composite->green=QuantumScale*intensity*q->green;
00238 composite->blue=QuantumScale*intensity*q->blue;
00239 composite->opacity=(MagickRealType) QuantumScale*intensity*
00240 GetOpacityPixelComponent(p);
00241 if (q->colorspace == CMYKColorspace)
00242 composite->index=QuantumScale*intensity*q->index;
00243 }
00244
00245 static inline void CompositeClear(const MagickPixelPacket *q,
00246 MagickPixelPacket *composite)
00247 {
00248 composite->opacity=(MagickRealType) TransparentOpacity;
00249 composite->red=0.0;
00250 composite->green=0.0;
00251 composite->blue=0.0;
00252 if (q->colorspace == CMYKColorspace)
00253 composite->index=0.0;
00254 }
00255
00256 static MagickRealType ColorBurn(const MagickRealType Sca,
00257 const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
00258 {
00259 #if 0
00260
00261
00262
00263 if (Sca*Da + Dca*Sa <= Sa*Da)
00264 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
00265 return(Sa*(Sca*Da+Dca*Sa-Sa*Da)/Sca + Sca*(1.0-Da) + Dca*(1.0-Sa));
00266 #else
00267
00268
00269
00270 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
00271 return(Sa*Da+Dca*(1.0-Sa));
00272 if (Sca < MagickEpsilon)
00273 return(Dca*(1.0-Sa));
00274 return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
00275 #endif
00276 }
00277
00278 static inline void CompositeColorBurn(const MagickPixelPacket *p,
00279 const MagickRealType alpha,const MagickPixelPacket *q,
00280 const MagickRealType beta,MagickPixelPacket *composite)
00281 {
00282 MagickRealType
00283 Da,
00284 gamma,
00285 Sa;
00286
00287 Sa=1.0-QuantumScale*alpha;
00288 Da=1.0-QuantumScale*beta;
00289 gamma=RoundToUnity(Sa+Da-Sa*Da);
00290 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00291 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00292 composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
00293 q->red*Da,Da);
00294 composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
00295 q->green*Da,Da);
00296 composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00297 q->blue*Da,Da);
00298 if (q->colorspace == CMYKColorspace)
00299 composite->index=gamma*ColorBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
00300 q->index*Da,Da);
00301 }
00302
00303
00304 static MagickRealType ColorDodge(const MagickRealType Sca,
00305 const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
00306 {
00307 #if 0
00308
00309
00310
00311 if ((Sca*Da+Dca*Sa) >= Sa*Da)
00312 return( Sa*Da + Sca*(1.0-Da) + Dca*(1.0-Sa) );
00313 return( Dca*Sa*Sa/(Sa-Sca) + Sca*(1.0-Da) + Dca*(1.0-Sa) );
00314 #endif
00315 #if 0
00316
00317
00318
00319
00320 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
00321 return(Sca*(1.0-Da));
00322 if (fabs(Sca-Sa) < MagickEpsilon)
00323 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
00324 return(Sa*MagickMin(Da,Dca*Sa/(Sa-Sca)));
00325 #endif
00326
00327
00328
00329
00330
00331
00332
00333
00334 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
00335 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
00336 if (fabs(Sca-Sa) < MagickEpsilon)
00337 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
00338 return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
00339 }
00340
00341 static inline void CompositeColorDodge(const MagickPixelPacket *p,
00342 const MagickRealType alpha,const MagickPixelPacket *q,
00343 const MagickRealType beta,MagickPixelPacket *composite)
00344 {
00345 MagickRealType
00346 Da,
00347 gamma,
00348 Sa;
00349
00350 Sa=1.0-QuantumScale*alpha;
00351 Da=1.0-QuantumScale*beta;
00352 gamma=RoundToUnity(Sa+Da-Sa*Da);
00353 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00354 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00355 composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
00356 q->red*Da,Da);
00357 composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
00358 q->green*Da,Da);
00359 composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00360 q->blue*Da,Da);
00361 if (q->colorspace == CMYKColorspace)
00362 composite->index=gamma*ColorDodge(QuantumScale*p->index*Sa,Sa,QuantumScale*
00363 q->index*Da,Da);
00364 }
00365
00366 static inline MagickRealType Darken(const MagickRealType p,
00367 const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
00368 {
00369 if (p < q)
00370 return(MagickOver_(p,alpha,q,beta));
00371 return(MagickOver_(q,beta,p,alpha));
00372 }
00373
00374 static inline void CompositeDarken(const MagickPixelPacket *p,
00375 const MagickRealType alpha,const MagickPixelPacket *q,
00376 const MagickRealType beta,MagickPixelPacket *composite)
00377 {
00378 MagickRealType
00379 gamma;
00380
00381 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
00382 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00383 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00384 composite->red=gamma*Darken(p->red,alpha,q->red,beta);
00385 composite->green=gamma*Darken(p->green,alpha,q->green,beta);
00386 composite->blue=gamma*Darken(p->blue,alpha,q->blue,beta);
00387 if (q->colorspace == CMYKColorspace)
00388 composite->index=gamma*Darken(p->index,alpha,q->index,beta);
00389 }
00390
00391 static inline MagickRealType Difference(const MagickRealType p,
00392 const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
00393 {
00394
00395
00396
00397 return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
00398 }
00399
00400 static inline void CompositeDifference(const MagickPixelPacket *p,
00401 const MagickRealType alpha,const MagickPixelPacket *q,
00402 const MagickRealType beta,MagickPixelPacket *composite)
00403 {
00404 MagickRealType
00405 Da,
00406 gamma,
00407 Sa;
00408
00409 Sa=1.0-QuantumScale*alpha;
00410 Da=1.0-QuantumScale*beta;
00411 gamma=RoundToUnity(Sa+Da-Sa*Da);
00412 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00413
00414
00415
00416 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00417 composite->red=gamma*Difference(p->red,Sa,q->red,Da);
00418 composite->green=gamma*Difference(p->green,Sa,q->green,Da);
00419 composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
00420 if (q->colorspace == CMYKColorspace)
00421 composite->index=gamma*Difference(p->index,Sa,q->index,Da);
00422 }
00423
00424 static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
00425 const MagickRealType Dca,const MagickRealType Da)
00426 {
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
00438 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
00439 if (fabs(Dca) < MagickEpsilon)
00440 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
00441 return(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
00442 }
00443
00444 static inline void CompositeDivide(const MagickPixelPacket *p,
00445 const MagickRealType alpha,const MagickPixelPacket *q,
00446 const MagickRealType beta,MagickPixelPacket *composite)
00447 {
00448 MagickRealType
00449 Da,
00450 gamma,
00451 Sa;
00452
00453 Sa=1.0-QuantumScale*alpha;
00454 Da=1.0-QuantumScale*beta;
00455 gamma=RoundToUnity(Sa+Da-Sa*Da);
00456 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00457 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00458 composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
00459 q->red*Da,Da);
00460 composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
00461 q->green*Da,Da);
00462 composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00463 q->blue*Da,Da);
00464 if (q->colorspace == CMYKColorspace)
00465 composite->index=gamma*Divide(QuantumScale*p->index*Sa,Sa,QuantumScale*
00466 q->index*Da,Da);
00467 }
00468
00469 static MagickRealType Exclusion(const MagickRealType Sca,
00470 const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
00471 {
00472 return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
00473 }
00474
00475 static inline void CompositeExclusion(const MagickPixelPacket *p,
00476 const MagickRealType alpha,const MagickPixelPacket *q,
00477 const MagickRealType beta,MagickPixelPacket *composite)
00478 {
00479 MagickRealType
00480 gamma,
00481 Sa,
00482 Da;
00483
00484 Sa=1.0-QuantumScale*alpha;
00485 Da=1.0-QuantumScale*beta;
00486 gamma=RoundToUnity(Sa+Da-Sa*Da);
00487 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00488 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00489 composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
00490 q->red*Da,Da);
00491 composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
00492 q->green*Da,Da);
00493 composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00494 q->blue*Da,Da);
00495 if (q->colorspace == CMYKColorspace)
00496 composite->index=gamma*Exclusion(QuantumScale*p->index*Sa,Sa,QuantumScale*
00497 q->index*Da,Da);
00498 }
00499
00500 static MagickRealType HardLight(const MagickRealType Sca,
00501 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00502 {
00503 if ((2.0*Sca) < Sa)
00504 return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
00505 return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
00506 }
00507
00508 static inline void CompositeHardLight(const MagickPixelPacket *p,
00509 const MagickRealType alpha,const MagickPixelPacket *q,
00510 const MagickRealType beta,MagickPixelPacket *composite)
00511 {
00512 MagickRealType
00513 Da,
00514 gamma,
00515 Sa;
00516
00517 Sa=1.0-QuantumScale*alpha;
00518 Da=1.0-QuantumScale*beta;
00519 gamma=RoundToUnity(Sa+Da-Sa*Da);
00520 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00521 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00522 composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
00523 q->red*Da,Da);
00524 composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
00525 q->green*Da,Da);
00526 composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00527 q->blue*Da,Da);
00528 if (q->colorspace == CMYKColorspace)
00529 composite->index=gamma*HardLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
00530 q->index*Da,Da);
00531 }
00532
00533 static void CompositeHSB(const MagickRealType red,const MagickRealType green,
00534 const MagickRealType blue,double *hue,double *saturation,double *brightness)
00535 {
00536 MagickRealType
00537 delta,
00538 max,
00539 min;
00540
00541
00542
00543
00544 assert(hue != (double *) NULL);
00545 assert(saturation != (double *) NULL);
00546 assert(brightness != (double *) NULL);
00547 max=(red > green ? red : green);
00548 if (blue > max)
00549 max=blue;
00550 min=(red < green ? red : green);
00551 if (blue < min)
00552 min=blue;
00553 *hue=0.0;
00554 *saturation=0.0;
00555 *brightness=(double) (QuantumScale*max);
00556 if (max == 0.0)
00557 return;
00558 *saturation=(double) (1.0-min/max);
00559 delta=max-min;
00560 if (delta == 0.0)
00561 return;
00562 if (red == max)
00563 *hue=(double) ((green-blue)/delta);
00564 else
00565 if (green == max)
00566 *hue=(double) (2.0+(blue-red)/delta);
00567 else
00568 if (blue == max)
00569 *hue=(double) (4.0+(red-green)/delta);
00570 *hue/=6.0;
00571 if (*hue < 0.0)
00572 *hue+=1.0;
00573 }
00574
00575 static inline MagickRealType In(const MagickRealType p,
00576 const MagickRealType alpha,const MagickRealType magick_unused(q),
00577 const MagickRealType beta)
00578 {
00579 return((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta));
00580 }
00581
00582 static inline void CompositeIn(const MagickPixelPacket *p,
00583 const MagickRealType alpha,const MagickPixelPacket *q,
00584 const MagickRealType beta,MagickPixelPacket *composite)
00585 {
00586 MagickRealType
00587 gamma;
00588
00589 gamma=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta);
00590 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00591 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00592 composite->red=gamma*In(p->red,alpha,q->red,beta);
00593 composite->green=gamma*In(p->green,alpha,q->green,beta);
00594 composite->blue=gamma*In(p->blue,alpha,q->blue,beta);
00595 if (q->colorspace == CMYKColorspace)
00596 composite->index=gamma*In(p->index,alpha,q->index,beta);
00597 }
00598
00599 static inline MagickRealType Lighten(const MagickRealType p,
00600 const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
00601 {
00602 if (p > q)
00603 return(MagickOver_(p,alpha,q,beta));
00604 return(MagickOver_(q,beta,p,alpha));
00605 }
00606
00607 static inline void CompositeLighten(const MagickPixelPacket *p,
00608 const MagickRealType alpha,const MagickPixelPacket *q,
00609 const MagickRealType beta,MagickPixelPacket *composite)
00610 {
00611 MagickRealType
00612 gamma;
00613
00614 composite->opacity=QuantumScale*alpha*beta;
00615 gamma=1.0-QuantumScale*composite->opacity;
00616 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00617 composite->red=gamma*Lighten(p->red,alpha,q->red,beta);
00618 composite->green=gamma*Lighten(p->green,alpha,q->green,beta);
00619 composite->blue=gamma*Lighten(p->blue,alpha,q->blue,beta);
00620 if (q->colorspace == CMYKColorspace)
00621 composite->index=gamma*Lighten(p->index,alpha,q->index,beta);
00622 }
00623
00624 static inline void CompositeLinearDodge(const MagickPixelPacket *p,
00625 const MagickRealType alpha,const MagickPixelPacket *q,
00626 const MagickRealType beta,MagickPixelPacket *composite)
00627 {
00628 MagickRealType
00629 Da,
00630 gamma,
00631 Sa;
00632
00633 Sa=1.0-QuantumScale*alpha;
00634 Da=1.0-QuantumScale*beta;
00635 gamma=RoundToUnity(Sa+Da-Sa*Da);
00636 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00637
00638
00639
00640 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00641 composite->red=gamma*(p->red*Sa+q->red*Da);
00642 composite->green=gamma*(p->green*Sa+q->green*Da);
00643 composite->blue=gamma*(p->blue*Sa+q->blue*Da);
00644 if (q->colorspace == CMYKColorspace)
00645 composite->index=gamma*(p->index*Sa+q->index*Da);
00646 }
00647
00648
00649 static inline MagickRealType LinearBurn(const MagickRealType Sca,
00650 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00651 {
00652
00653
00654
00655
00656
00657
00658 return(Sca+Dca-Sa*Da);
00659 }
00660
00661 static inline void CompositeLinearBurn(const MagickPixelPacket *p,
00662 const MagickRealType alpha,const MagickPixelPacket *q,
00663 const MagickRealType beta,MagickPixelPacket *composite)
00664 {
00665 MagickRealType
00666 Da,
00667 gamma,
00668 Sa;
00669
00670 Sa=1.0-QuantumScale*alpha;
00671 Da=1.0-QuantumScale*beta;
00672 gamma=RoundToUnity(Sa+Da-Sa*Da);
00673 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00674 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00675 composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
00676 q->red*Da,Da);
00677 composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
00678 q->green*Da,Da);
00679 composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00680 q->blue*Da,Da);
00681 if (q->colorspace == CMYKColorspace)
00682 composite->index=gamma*LinearBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
00683 q->index*Da,Da);
00684 }
00685
00686 static inline MagickRealType LinearLight(const MagickRealType Sca,
00687 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00688 {
00689 #if 0
00690
00691
00692
00693 return(Dca+2*Sca-1.0);
00694 #else
00695
00696
00697
00698
00699
00700
00701 return((Sca-Sa)*Da+Sca+Dca);
00702 #endif
00703 }
00704
00705 static inline void CompositeLinearLight(const MagickPixelPacket *p,
00706 const MagickRealType alpha,const MagickPixelPacket *q,
00707 const MagickRealType beta,MagickPixelPacket *composite)
00708 {
00709 MagickRealType
00710 Da,
00711 gamma,
00712 Sa;
00713
00714 Sa=1.0-QuantumScale*alpha;
00715 Da=1.0-QuantumScale*beta;
00716 gamma=RoundToUnity(Sa+Da-Sa*Da);
00717 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00718 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00719 composite->red=gamma*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
00720 q->red*Da,Da);
00721 composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
00722 q->green*Da,Da);
00723 composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00724 q->blue*Da,Da);
00725 if (q->colorspace == CMYKColorspace)
00726 composite->index=gamma*LinearLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
00727 q->index*Da,Da);
00728 }
00729
00730 static inline MagickRealType Mathematics(const MagickRealType Sca,
00731 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
00732 const GeometryInfo *geometry_info)
00733 {
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 return(geometry_info->rho*Sca*Dca+geometry_info->sigma*Sca*Da+
00753 geometry_info->xi*Dca*Sa+geometry_info->psi*Sa*Da+Sca*(1.0-Da)+
00754 Dca*(1.0-Sa));
00755 }
00756
00757 static inline void CompositeMathematics(const MagickPixelPacket *p,
00758 const MagickPixelPacket *q,const GeometryInfo *args,
00759 MagickPixelPacket *composite)
00760 {
00761 MagickRealType
00762 Da,
00763 gamma,
00764 Sa;
00765
00766 Sa=1.0-QuantumScale*GetOpacityPixelComponent(p);
00767 Da=1.0-QuantumScale*q->opacity;
00768 gamma=RoundToUnity(Sa+Da-Sa*Da);
00769 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00770 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00771 composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
00772 q->red*Da,Da,args);
00773 composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,QuantumScale*
00774 q->green*Da,Da,args);
00775 composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00776 q->blue*Da,Da,args);
00777 if (q->colorspace == CMYKColorspace)
00778 composite->index=gamma*Mathematics(QuantumScale*p->index*Sa,Sa,QuantumScale*
00779 q->index*Da,Da,args);
00780 }
00781
00782 static inline MagickRealType Minus(const MagickRealType Sca,
00783 const MagickRealType Dca)
00784 {
00785 return(Sca-Dca);
00786 }
00787
00788 static inline void CompositeMinus(const MagickPixelPacket *p,
00789 const MagickRealType alpha,const MagickPixelPacket *q,
00790 const MagickRealType beta,MagickPixelPacket *composite)
00791 {
00792 MagickRealType
00793 Da,
00794 gamma,
00795 Sa;
00796
00797 Sa=1.0-QuantumScale*alpha;
00798 Da=1.0-QuantumScale*beta;
00799 gamma=RoundToUnity(Sa-Da);
00800 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00801 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00802 composite->red=gamma*Minus(p->red*Sa,q->red*Da);
00803 composite->green=gamma*Minus(p->green*Sa,q->green*Da);
00804 composite->blue=gamma*Minus(p->blue*Sa,q->blue*Da);
00805 if (q->colorspace == CMYKColorspace)
00806 composite->index=gamma*Minus(p->index*Sa,q->index*Da);
00807 }
00808
00809 static inline MagickRealType Multiply(const MagickRealType Sca,
00810 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00811 {
00812 return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
00813 }
00814
00815 static inline void CompositeMultiply(const MagickPixelPacket *p,
00816 const MagickRealType alpha,const MagickPixelPacket *q,
00817 const MagickRealType beta,MagickPixelPacket *composite)
00818 {
00819 MagickRealType
00820 Da,
00821 gamma,
00822 Sa;
00823
00824 Sa=1.0-QuantumScale*alpha;
00825 Da=1.0-QuantumScale*beta;
00826 gamma=RoundToUnity(Sa+Da-Sa*Da);
00827 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00828 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00829 composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
00830 q->red*Da,Da);
00831 composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
00832 q->green*Da,Da);
00833 composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00834 q->blue*Da,Da);
00835 if (q->colorspace == CMYKColorspace)
00836 composite->index=gamma*Multiply(QuantumScale*p->index*Sa,Sa,QuantumScale*
00837 q->index*Da,Da);
00838 }
00839
00840 static inline MagickRealType Out(const MagickRealType p,
00841 const MagickRealType alpha,const MagickRealType magick_unused(q),
00842 const MagickRealType beta)
00843 {
00844 return((1.0-QuantumScale*alpha)*p*QuantumScale*beta);
00845 }
00846
00847 static inline void CompositeOut(const MagickPixelPacket *p,
00848 const MagickRealType alpha,const MagickPixelPacket *q,
00849 const MagickRealType beta,MagickPixelPacket *composite)
00850 {
00851 MagickRealType
00852 gamma;
00853
00854 gamma=(1.0-QuantumScale*alpha)*QuantumScale*beta;
00855 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00856 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00857 composite->red=gamma*Out(p->red,alpha,q->red,beta);
00858 composite->green=gamma*Out(p->green,alpha,q->green,beta);
00859 composite->blue=gamma*Out(p->blue,alpha,q->blue,beta);
00860 if (q->colorspace == CMYKColorspace)
00861 composite->index=gamma*Out(p->index,alpha,q->index,beta);
00862 }
00863
00864 static inline void CompositeOver(const MagickPixelPacket *p,
00865 const MagickRealType alpha,const MagickPixelPacket *q,
00866 const MagickRealType beta,MagickPixelPacket *composite)
00867 {
00868 MagickPixelCompositeOver(p,alpha,q,beta,composite);
00869 }
00870
00871 static MagickRealType PegtopLight(const MagickRealType Sca,
00872 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00873 {
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 if (fabs(Da) < MagickEpsilon)
00884 return(Sca);
00885 return(Dca*Dca*(Sa-2*Sca)/Da+Sca*(2*Dca+1-Da)+Dca*(1-Sa));
00886 }
00887
00888 static inline void CompositePegtopLight(const MagickPixelPacket *p,
00889 const MagickRealType alpha,const MagickPixelPacket *q,
00890 const MagickRealType beta,MagickPixelPacket *composite)
00891 {
00892 MagickRealType
00893 Da,
00894 gamma,
00895 Sa;
00896
00897 Sa=1.0-QuantumScale*alpha;
00898 Da=1.0-QuantumScale*beta;
00899 gamma=RoundToUnity(Sa+Da-Sa*Da);
00900 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00901 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00902 composite->red=gamma*PegtopLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
00903 q->red*Da,Da);
00904 composite->green=gamma*PegtopLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
00905 q->green*Da,Da);
00906 composite->blue=gamma*PegtopLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00907 q->blue*Da,Da);
00908 if (q->colorspace == CMYKColorspace)
00909 composite->index=gamma*PegtopLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
00910 q->index*Da,Da);
00911 }
00912
00913 static MagickRealType PinLight(const MagickRealType Sca,
00914 const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
00915 {
00916
00917
00918
00919
00920
00921
00922 if (Dca*Sa < Da*(2*Sca-Sa))
00923 return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
00924 if ((Dca*Sa) > (2*Sca*Da))
00925 return(Sca*Da+Sca+Dca*(1.0-Sa));
00926 return(Sca*(1.0-Da)+Dca);
00927 }
00928
00929 static inline void CompositePinLight(const MagickPixelPacket *p,
00930 const MagickRealType alpha,const MagickPixelPacket *q,
00931 const MagickRealType beta,MagickPixelPacket *composite)
00932 {
00933 MagickRealType
00934 Da,
00935 gamma,
00936 Sa;
00937
00938 Sa=1.0-QuantumScale*alpha;
00939 Da=1.0-QuantumScale*beta;
00940 gamma=RoundToUnity(Sa+Da-Sa*Da);
00941 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00942 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00943 composite->red=gamma*PinLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
00944 q->red*Da,Da);
00945 composite->green=gamma*PinLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
00946 q->green*Da,Da);
00947 composite->blue=gamma*PinLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
00948 q->blue*Da,Da);
00949 if (q->colorspace == CMYKColorspace)
00950 composite->index=gamma*PinLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
00951 q->index*Da,Da);
00952 }
00953
00954 static inline void CompositePlus(const MagickPixelPacket *p,
00955 const MagickRealType alpha,const MagickPixelPacket *q,
00956 const MagickRealType beta,MagickPixelPacket *composite)
00957 {
00958 MagickPixelCompositePlus(p,alpha,q,beta,composite);
00959 }
00960
00961 static inline MagickRealType Screen(const MagickRealType Sca,
00962 const MagickRealType Dca)
00963 {
00964 return(Sca+Dca-Sca*Dca);
00965 }
00966
00967 static inline void CompositeScreen(const MagickPixelPacket *p,
00968 const MagickRealType alpha,const MagickPixelPacket *q,
00969 const MagickRealType beta,MagickPixelPacket *composite)
00970 {
00971 MagickRealType
00972 Da,
00973 gamma,
00974 Sa;
00975
00976 Sa=1.0-QuantumScale*alpha;
00977 Da=1.0-QuantumScale*beta;
00978 gamma=RoundToUnity(Sa+Da-Sa*Da);
00979 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00980 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
00981 composite->red=gamma*Screen(QuantumScale*p->red*Sa,QuantumScale*
00982 q->red*Da);
00983 composite->green=gamma*Screen(QuantumScale*p->green*Sa,QuantumScale*
00984 q->green*Da);
00985 composite->blue=gamma*Screen(QuantumScale*p->blue*Sa,QuantumScale*
00986 q->blue*Da);
00987 if (q->colorspace == CMYKColorspace)
00988 composite->index=gamma*Screen(QuantumScale*p->index*Sa,QuantumScale*
00989 q->index*Da);
00990 }
00991
00992 static MagickRealType SoftLight(const MagickRealType Sca,
00993 const MagickRealType Sa, const MagickRealType Dca, const MagickRealType Da)
00994 {
00995 #if 0
00996
00997
00998
00999
01000 if (2.0*Sca < Sa)
01001 return(Dca*(Sa-(1.0-Dca/Da)*(2.0*Sca-Sa))+Sca*(1.0-Da)+Dca*(1.0-Sa));
01002 if (8.0*Dca <= Da)
01003 return(Dca*(Sa-(1.0-Dca/Da)*(2.0*Sca-Sa)*(3.0-8.0*Dca/Da))+
01004 Sca*(1.0-Da)+Dca*(1.0-Sa));
01005 return((Dca*Sa+(pow(Dca/Da,0.5)*Da-Dca)*(2.0*Sca-Sa))+Sca*(1.0-Da)+
01006 Dca*(1.0-Sa));
01007 #else
01008 MagickRealType
01009 alpha,
01010 beta;
01011
01012
01013
01014
01015 alpha=Dca/Da;
01016 if ((2.0*Sca) < Sa)
01017 return(Dca*(Sa+(2.0*Sca-Sa)*(1.0-alpha))+Sca*(1.0-Da)+Dca*(1.0-Sa));
01018 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
01019 {
01020 beta=Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*alpha*(4.0*alpha+1.0)*(alpha-1.0)+7.0*
01021 alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
01022 return(beta);
01023 }
01024 beta=Dca*Sa+Da*(2.0*Sca-Sa)*(pow(alpha,0.5)-alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
01025 return(beta);
01026 #endif
01027 }
01028
01029 static inline void CompositeSoftLight(const MagickPixelPacket *p,
01030 const MagickRealType alpha,const MagickPixelPacket *q,
01031 const MagickRealType beta,MagickPixelPacket *composite)
01032 {
01033 MagickRealType
01034 Da,
01035 gamma,
01036 Sa;
01037
01038 Sa=1.0-QuantumScale*alpha;
01039 Da=1.0-QuantumScale*beta;
01040 gamma=RoundToUnity(Sa+Da-Sa*Da);
01041 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
01042 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
01043 composite->red=gamma*SoftLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
01044 q->red*Da,Da);
01045 composite->green=gamma*SoftLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
01046 q->green*Da,Da);
01047 composite->blue=gamma*SoftLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
01048 q->blue*Da,Da);
01049 if (q->colorspace == CMYKColorspace)
01050 composite->index=gamma*SoftLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
01051 q->index*Da,Da);
01052 }
01053
01054 static inline MagickRealType Subtract(const MagickRealType p,
01055 const MagickRealType magick_unused(alpha),const MagickRealType q,
01056 const MagickRealType magick_unused(beta))
01057 {
01058 MagickRealType
01059 pixel;
01060
01061 pixel=p-q;
01062 if (pixel < 0.0)
01063 pixel+=(QuantumRange+1.0);
01064 return(pixel);
01065 }
01066
01067 static inline void CompositeSubtract(const MagickPixelPacket *p,
01068 const MagickRealType alpha,const MagickPixelPacket *q,
01069 const MagickRealType beta,MagickPixelPacket *composite)
01070 {
01071 composite->red=Subtract(p->red,alpha,q->red,beta);
01072 composite->green=Subtract(p->green,alpha,q->green,beta);
01073 composite->blue=Subtract(p->blue,alpha,q->blue,beta);
01074 if (q->colorspace == CMYKColorspace)
01075 composite->index=Subtract(p->index,alpha,q->index,beta);
01076 }
01077
01078 static inline MagickRealType Threshold(const MagickRealType p,
01079 const MagickRealType magick_unused(alpha),const MagickRealType q,
01080 const MagickRealType magick_unused(beta),const MagickRealType threshold,
01081 const MagickRealType amount)
01082 {
01083 MagickRealType
01084 delta;
01085
01086 delta=p-q;
01087 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
01088 return(q);
01089 return(q+delta*amount);
01090 }
01091
01092 static inline void CompositeThreshold(const MagickPixelPacket *p,
01093 const MagickRealType alpha,const MagickPixelPacket *q,
01094 const MagickRealType beta,const MagickRealType threshold,
01095 const MagickRealType amount,MagickPixelPacket *composite)
01096 {
01097 composite->red=Threshold(p->red,alpha,q->red,beta,threshold,amount);
01098 composite->green=Threshold(p->green,alpha,q->green,beta,threshold,amount);
01099 composite->blue=Threshold(p->blue,alpha,q->blue,beta,threshold,amount);
01100 composite->opacity=(MagickRealType) QuantumRange-
01101 Threshold(p->opacity,alpha,q->opacity,beta,threshold,amount);
01102 if (q->colorspace == CMYKColorspace)
01103 composite->index=Threshold(p->index,alpha,q->index,beta,threshold,amount);
01104 }
01105
01106 static MagickRealType VividLight(const MagickRealType Sca,
01107 const MagickRealType Sa, const MagickRealType Dca, const MagickRealType Da)
01108 {
01109
01110
01111
01112
01113
01114
01115 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
01116 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
01117 if ((2*Sca) <= Sa)
01118 return(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
01119 return(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
01120 }
01121
01122 static inline void CompositeVividLight(const MagickPixelPacket *p,
01123 const MagickRealType alpha,const MagickPixelPacket *q,
01124 const MagickRealType beta,MagickPixelPacket *composite)
01125 {
01126 MagickRealType
01127 Da,
01128 gamma,
01129 Sa;
01130
01131 Sa=1.0-QuantumScale*alpha;
01132 Da=1.0-QuantumScale*beta;
01133 gamma=RoundToUnity(Sa+Da-Sa*Da);
01134 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
01135 gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
01136 composite->red=gamma*VividLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
01137 q->red*Da,Da);
01138 composite->green=gamma*VividLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
01139 q->green*Da,Da);
01140 composite->blue=gamma*VividLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
01141 q->blue*Da,Da);
01142 if (q->colorspace == CMYKColorspace)
01143 composite->index=gamma*VividLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
01144 q->index*Da,Da);
01145 }
01146
01147 static MagickRealType Xor(const MagickRealType Sca,const MagickRealType Sa,
01148 const MagickRealType Dca,const MagickRealType Da)
01149 {
01150 return(Sca*(1-Da)+Dca*(1-Sa));
01151 }
01152
01153 static inline void CompositeXor(const MagickPixelPacket *p,
01154 const MagickRealType alpha,const MagickPixelPacket *q,
01155 const MagickRealType beta,MagickPixelPacket *composite)
01156 {
01157 MagickRealType
01158 Da,
01159 gamma,
01160 Sa;
01161
01162 Sa=1.0-QuantumScale*alpha;
01163 Da=1.0-QuantumScale*beta;
01164 gamma=Sa+Da-2*Sa*Da;
01165 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
01166
01167
01168
01169 gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
01170 composite->red=gamma*Xor(p->red*Sa,Sa,q->red*Da,Da);
01171 composite->green=gamma*Xor(p->green*Sa,Sa,q->green*Da,Da);
01172 composite->blue=gamma*Xor(p->blue*Sa,Sa,q->blue*Da,Da);
01173 if (q->colorspace == CMYKColorspace)
01174 composite->index=gamma*Xor(p->index*Sa,Sa,q->index*Da,Da);
01175 }
01176
01177 static void HSBComposite(const double hue,const double saturation,
01178 const double brightness,MagickRealType *red,MagickRealType *green,
01179 MagickRealType *blue)
01180 {
01181 MagickRealType
01182 f,
01183 h,
01184 p,
01185 q,
01186 t;
01187
01188
01189
01190
01191 assert(red != (MagickRealType *) NULL);
01192 assert(green != (MagickRealType *) NULL);
01193 assert(blue != (MagickRealType *) NULL);
01194 if (saturation == 0.0)
01195 {
01196 *red=(MagickRealType) QuantumRange*brightness;
01197 *green=(*red);
01198 *blue=(*red);
01199 return;
01200 }
01201 h=6.0*(hue-floor(hue));
01202 f=h-floor((double) h);
01203 p=brightness*(1.0-saturation);
01204 q=brightness*(1.0-saturation*f);
01205 t=brightness*(1.0-saturation*(1.0-f));
01206 switch ((int) h)
01207 {
01208 case 0:
01209 default:
01210 {
01211 *red=(MagickRealType) QuantumRange*brightness;
01212 *green=(MagickRealType) QuantumRange*t;
01213 *blue=(MagickRealType) QuantumRange*p;
01214 break;
01215 }
01216 case 1:
01217 {
01218 *red=(MagickRealType) QuantumRange*q;
01219 *green=(MagickRealType) QuantumRange*brightness;
01220 *blue=(MagickRealType) QuantumRange*p;
01221 break;
01222 }
01223 case 2:
01224 {
01225 *red=(MagickRealType) QuantumRange*p;
01226 *green=(MagickRealType) QuantumRange*brightness;
01227 *blue=(MagickRealType) QuantumRange*t;
01228 break;
01229 }
01230 case 3:
01231 {
01232 *red=(MagickRealType) QuantumRange*p;
01233 *green=(MagickRealType) QuantumRange*q;
01234 *blue=(MagickRealType) QuantumRange*brightness;
01235 break;
01236 }
01237 case 4:
01238 {
01239 *red=(MagickRealType) QuantumRange*t;
01240 *green=(MagickRealType) QuantumRange*p;
01241 *blue=(MagickRealType) QuantumRange*brightness;
01242 break;
01243 }
01244 case 5:
01245 {
01246 *red=(MagickRealType) QuantumRange*brightness;
01247 *green=(MagickRealType) QuantumRange*p;
01248 *blue=(MagickRealType) QuantumRange*q;
01249 break;
01250 }
01251 }
01252 }
01253
01254 MagickExport MagickBooleanType CompositeImage(Image *image,
01255 const CompositeOperator compose,const Image *composite_image,
01256 const long x_offset,const long y_offset)
01257 {
01258 MagickBooleanType
01259 status;
01260
01261 status=CompositeImageChannel(image,DefaultChannels,compose,composite_image,
01262 x_offset,y_offset);
01263 return(status);
01264 }
01265
01266 MagickExport MagickBooleanType CompositeImageChannel(Image *image,
01267 const ChannelType magick_unused(channel),const CompositeOperator compose,
01268 const Image *composite_image,const long x_offset,const long y_offset)
01269 {
01270 #define CompositeImageTag "Composite/Image"
01271
01272 CacheView
01273 *composite_view,
01274 *image_view;
01275
01276 const char
01277 *value;
01278
01279 double
01280 sans;
01281
01282 ExceptionInfo
01283 *exception;
01284
01285 GeometryInfo
01286 geometry_info;
01287
01288 Image
01289 *destination_image;
01290
01291 long
01292 progress,
01293 y;
01294
01295 MagickBooleanType
01296 modify_outside_overlay,
01297 status;
01298
01299 MagickPixelPacket
01300 zero;
01301
01302 MagickRealType
01303 amount,
01304 destination_dissolve,
01305 midpoint,
01306 percent_brightness,
01307 percent_saturation,
01308 source_dissolve,
01309 threshold;
01310
01311 MagickStatusType
01312 flags;
01313
01314
01315
01316
01317 assert(image != (Image *) NULL);
01318 assert(image->signature == MagickSignature);
01319 if (image->debug != MagickFalse)
01320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01321 assert(composite_image != (Image *) NULL);
01322 assert(composite_image->signature == MagickSignature);
01323 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01324 return(MagickFalse);
01325 GetMagickPixelPacket(image,&zero);
01326 destination_image=(Image *) NULL;
01327 amount=0.5;
01328 destination_dissolve=1.0;
01329 modify_outside_overlay=MagickFalse;
01330 percent_brightness=100.0;
01331 percent_saturation=100.0;
01332 source_dissolve=1.0;
01333 threshold=0.05f;
01334 switch (compose)
01335 {
01336 case ClearCompositeOp:
01337 case SrcCompositeOp:
01338 case InCompositeOp:
01339 case SrcInCompositeOp:
01340 case OutCompositeOp:
01341 case SrcOutCompositeOp:
01342 case DstInCompositeOp:
01343 case DstAtopCompositeOp:
01344 {
01345
01346
01347
01348 modify_outside_overlay=MagickTrue;
01349 break;
01350 }
01351 case OverCompositeOp:
01352 {
01353 if (image->matte != MagickFalse)
01354 break;
01355 if (composite_image->matte != MagickFalse)
01356 break;
01357 }
01358 case CopyCompositeOp:
01359 {
01360 if ((x_offset < 0) || (y_offset < 0))
01361 break;
01362 if ((x_offset+(long) composite_image->columns) >= (long) image->columns)
01363 break;
01364 if ((y_offset+(long) composite_image->rows) >= (long) image->rows)
01365 break;
01366 status=MagickTrue;
01367 exception=(&image->exception);
01368 image_view=AcquireCacheView(image);
01369 composite_view=AcquireCacheView(composite_image);
01370 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01371 #pragma omp parallel for schedule(dynamic,4) shared(status)
01372 #endif
01373 for (y=0; y < (long) composite_image->rows; y++)
01374 {
01375 MagickBooleanType
01376 sync;
01377
01378 register const IndexPacket
01379 *composite_indexes;
01380
01381 register const PixelPacket
01382 *p;
01383
01384 register IndexPacket
01385 *indexes;
01386
01387 register PixelPacket
01388 *q;
01389
01390 if (status == MagickFalse)
01391 continue;
01392 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
01393 1,exception);
01394 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
01395 composite_image->columns,1,exception);
01396 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01397 {
01398 status=MagickFalse;
01399 continue;
01400 }
01401 composite_indexes=GetCacheViewVirtualIndexQueue(composite_view);
01402 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01403 (void) CopyMagickMemory(q,p,composite_image->columns*sizeof(*p));
01404 if ((indexes != (IndexPacket *) NULL) &&
01405 (composite_indexes != (const IndexPacket *) NULL))
01406 (void) CopyMagickMemory(indexes,composite_indexes,
01407 composite_image->columns*sizeof(*indexes));
01408 sync=SyncCacheViewAuthenticPixels(image_view,exception);
01409 if (sync == MagickFalse)
01410 status=MagickFalse;
01411 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01412 {
01413 MagickBooleanType
01414 proceed;
01415
01416 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01417 #pragma omp critical (MagickCore_CompositeImage)
01418 #endif
01419 proceed=SetImageProgress(image,CompositeImageTag,y,image->rows);
01420 if (proceed == MagickFalse)
01421 status=MagickFalse;
01422 }
01423 }
01424 composite_view=DestroyCacheView(composite_view);
01425 image_view=DestroyCacheView(image_view);
01426 return(status);
01427 }
01428 case CopyOpacityCompositeOp:
01429 case ChangeMaskCompositeOp:
01430 {
01431
01432
01433
01434
01435 if (image->matte == MagickFalse)
01436 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
01437 modify_outside_overlay=MagickTrue;
01438 break;
01439 }
01440 case BlurCompositeOp:
01441 {
01442 CacheView
01443 *composite_view,
01444 *destination_view;
01445
01446 MagickPixelPacket
01447 pixel;
01448
01449 MagickRealType
01450 angle_range,
01451 angle_start,
01452 height,
01453 width;
01454
01455 ResampleFilter
01456 *resample_filter;
01457
01458 SegmentInfo
01459 blur;
01460
01461
01462
01463
01464
01465 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
01466 &image->exception);
01467 if (destination_image == (Image *) NULL)
01468 return(MagickFalse);
01469
01470
01471
01472 SetGeometryInfo(&geometry_info);
01473 flags=NoValue;
01474 value=GetImageArtifact(composite_image,"compose:args");
01475 if (value != (char *) NULL)
01476 flags=ParseGeometry(value,&geometry_info);
01477 if ((flags & WidthValue) == 0 )
01478 {
01479 destination_image=DestroyImage(destination_image);
01480 return(MagickFalse);
01481 }
01482 width=geometry_info.rho;
01483 height=geometry_info.sigma;
01484 blur.x1=geometry_info.rho;
01485 blur.x2=0.0;
01486 blur.y1=0.0;
01487 blur.y2=geometry_info.sigma;
01488 angle_start=0.0;
01489 angle_range=0.0;
01490 if ((flags & HeightValue) == 0)
01491 blur.y2=blur.x1;
01492 if ((flags & XValue) != 0 )
01493 {
01494 MagickRealType
01495 angle;
01496
01497 angle=DegreesToRadians(geometry_info.xi);
01498 blur.x1=width*cos(angle);
01499 blur.x2=width*sin(angle);
01500 blur.y1=(-height*sin(angle));
01501 blur.y2=height*cos(angle);
01502 }
01503 if ((flags & YValue) != 0 )
01504 {
01505 angle_start=DegreesToRadians(geometry_info.xi);
01506 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
01507 }
01508
01509
01510
01511 pixel=zero;
01512 exception=(&image->exception);
01513 resample_filter=AcquireResampleFilter(image,&image->exception);
01514 SetResampleFilter(resample_filter,GaussianFilter,1.0);
01515 destination_view=AcquireCacheView(destination_image);
01516 composite_view=AcquireCacheView(composite_image);
01517 for (y=0; y < (long) composite_image->rows; y++)
01518 {
01519 MagickBooleanType
01520 sync;
01521
01522 register const PixelPacket
01523 *restrict p;
01524
01525 register PixelPacket
01526 *restrict r;
01527
01528 register IndexPacket
01529 *restrict destination_indexes;
01530
01531 register long
01532 x;
01533
01534 if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
01535 continue;
01536 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
01537 1,exception);
01538 r=QueueCacheViewAuthenticPixels(destination_view,0,y,
01539 destination_image->columns,1,&image->exception);
01540 if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
01541 break;
01542 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
01543 for (x=0; x < (long) composite_image->columns; x++)
01544 {
01545 if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
01546 {
01547 p++;
01548 continue;
01549 }
01550 if (fabs(angle_range) > MagickEpsilon)
01551 {
01552 MagickRealType
01553 angle;
01554
01555 angle=angle_start+angle_range*QuantumScale*
01556 GetBluePixelComponent(p);
01557 blur.x1=width*cos(angle);
01558 blur.x2=width*sin(angle);
01559 blur.y1=(-height*sin(angle));
01560 blur.y2=height*cos(angle);
01561 }
01562 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*p->red,
01563 blur.y1*QuantumScale*p->green,blur.x2*QuantumScale*p->red,
01564 blur.y2*QuantumScale*GetGreenPixelComponent(p));
01565 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
01566 (double) y_offset+y,&pixel);
01567 SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
01568 p++;
01569 r++;
01570 }
01571 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
01572 if (sync == MagickFalse)
01573 break;
01574 }
01575 resample_filter=DestroyResampleFilter(resample_filter);
01576 composite_view=DestroyCacheView(composite_view);
01577 destination_view=DestroyCacheView(destination_view);
01578 composite_image=destination_image;
01579 break;
01580 }
01581 case DisplaceCompositeOp:
01582 case DistortCompositeOp:
01583 {
01584 CacheView
01585 *composite_view,
01586 *destination_view;
01587
01588 MagickPixelPacket
01589 pixel;
01590
01591 MagickRealType
01592 horizontal_scale,
01593 vertical_scale;
01594
01595 PointInfo
01596 center,
01597 offset;
01598
01599 register IndexPacket
01600 *restrict destination_indexes;
01601
01602 register PixelPacket
01603 *restrict r;
01604
01605 ResampleFilter
01606 *resample_filter;
01607
01608
01609
01610
01611
01612
01613 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
01614 &image->exception);
01615 if (destination_image == (Image *) NULL)
01616 return(MagickFalse);
01617 SetGeometryInfo(&geometry_info);
01618 flags=NoValue;
01619 value=GetImageArtifact(composite_image,"compose:args");
01620 if (value != (char *) NULL)
01621 flags=ParseGeometry(value,&geometry_info);
01622 if ((flags & (WidthValue|HeightValue)) == 0 )
01623 {
01624 if ((flags & AspectValue) == 0)
01625 {
01626 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
01627 2.0;
01628 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
01629 }
01630 else
01631 {
01632 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
01633 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
01634 }
01635 }
01636 else
01637 {
01638 horizontal_scale=geometry_info.rho;
01639 vertical_scale=geometry_info.sigma;
01640 if ((flags & PercentValue) != 0)
01641 {
01642 if ((flags & AspectValue) == 0)
01643 {
01644 horizontal_scale*=(composite_image->columns-1.0)/200.0;
01645 vertical_scale*=(composite_image->rows-1.0)/200.0;
01646 }
01647 else
01648 {
01649 horizontal_scale*=(image->columns-1.0)/200.0;
01650 vertical_scale*=(image->rows-1.0)/200.0;
01651 }
01652 }
01653 if ((flags & HeightValue) == 0)
01654 vertical_scale=horizontal_scale;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664 center.x=(MagickRealType) x_offset;
01665 center.y=(MagickRealType) y_offset;
01666 if (compose == DistortCompositeOp)
01667 {
01668 if ((flags & XValue) == 0)
01669 if ((flags & AspectValue) == 0)
01670 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
01671 2.0;
01672 else
01673 center.x=((MagickRealType) image->columns-1)/2.0;
01674 else
01675 if ((flags & AspectValue) == 0)
01676 center.x=(MagickRealType) x_offset+geometry_info.xi;
01677 else
01678 center.x=geometry_info.xi;
01679 if ((flags & YValue) == 0)
01680 if ((flags & AspectValue) == 0)
01681 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
01682 else
01683 center.y=((MagickRealType) image->rows-1)/2.0;
01684 else
01685 if ((flags & AspectValue) == 0)
01686 center.y=(MagickRealType) y_offset+geometry_info.psi;
01687 else
01688 center.y=geometry_info.psi;
01689 }
01690
01691
01692
01693
01694 pixel=zero;
01695 exception=(&image->exception);
01696 resample_filter=AcquireResampleFilter(image,&image->exception);
01697 destination_view=AcquireCacheView(destination_image);
01698 composite_view=AcquireCacheView(composite_image);
01699 for (y=0; y < (long) composite_image->rows; y++)
01700 {
01701 MagickBooleanType
01702 sync;
01703
01704 register const PixelPacket
01705 *restrict p;
01706
01707 register long
01708 x;
01709
01710 if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
01711 continue;
01712 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
01713 1,exception);
01714 r=QueueCacheViewAuthenticPixels(destination_view,0,y,
01715 destination_image->columns,1,&image->exception);
01716 if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
01717 break;
01718 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
01719 for (x=0; x < (long) composite_image->columns; x++)
01720 {
01721 if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
01722 {
01723 p++;
01724 continue;
01725 }
01726
01727
01728
01729 offset.x=(horizontal_scale*(p->red-(((MagickRealType) QuantumRange+
01730 1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
01731 center.x+((compose == DisplaceCompositeOp) ? x : 0);
01732 offset.y=(vertical_scale*(p->green-(((MagickRealType) QuantumRange+
01733 1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
01734 center.y+((compose == DisplaceCompositeOp) ? y : 0);
01735 (void) ResamplePixelColor(resample_filter,(double) offset.x,
01736 (double) offset.y,&pixel);
01737
01738
01739
01740 pixel.opacity=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
01741 pixel.opacity)*(1.0-QuantumScale*GetOpacityPixelComponent(p)));
01742 SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
01743 p++;
01744 r++;
01745 }
01746 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
01747 if (sync == MagickFalse)
01748 break;
01749 }
01750 resample_filter=DestroyResampleFilter(resample_filter);
01751 composite_view=DestroyCacheView(composite_view);
01752 destination_view=DestroyCacheView(destination_view);
01753 composite_image=destination_image;
01754 break;
01755 }
01756 case DissolveCompositeOp:
01757 {
01758
01759
01760
01761 value=GetImageArtifact(composite_image,"compose:args");
01762 if (value != (char *) NULL)
01763 {
01764 flags=ParseGeometry(value,&geometry_info);
01765 source_dissolve=geometry_info.rho/100.0;
01766 destination_dissolve=1.0;
01767 if ((source_dissolve-MagickEpsilon) < 0.0)
01768 source_dissolve=0.0;
01769 if ((source_dissolve+MagickEpsilon) > 1.0)
01770 {
01771 destination_dissolve=2.0-source_dissolve;
01772 source_dissolve=1.0;
01773 }
01774 if ((flags & SigmaValue) != 0)
01775 destination_dissolve=geometry_info.sigma/100.0;
01776 if ((destination_dissolve-MagickEpsilon) < 0.0)
01777 destination_dissolve=0.0;
01778 modify_outside_overlay=MagickTrue;
01779 if ((destination_dissolve+MagickEpsilon) > 1.0 )
01780 {
01781 destination_dissolve=1.0;
01782 modify_outside_overlay=MagickFalse;
01783 }
01784 }
01785 break;
01786 }
01787 case BlendCompositeOp:
01788 {
01789 value=GetImageArtifact(composite_image,"compose:args");
01790 if (value != (char *) NULL)
01791 {
01792 flags=ParseGeometry(value,&geometry_info);
01793 source_dissolve=geometry_info.rho/100.0;
01794 destination_dissolve=1.0-source_dissolve;
01795 if ((flags & SigmaValue) != 0)
01796 destination_dissolve=geometry_info.sigma/100.0;
01797 modify_outside_overlay=MagickTrue;
01798 if ((destination_dissolve+MagickEpsilon) > 1.0)
01799 modify_outside_overlay=MagickFalse;
01800 }
01801 break;
01802 }
01803 case MathematicsCompositeOp:
01804 {
01805
01806
01807
01808
01809
01810
01811
01812
01813 SetGeometryInfo(&geometry_info);
01814 value=GetImageArtifact(composite_image,"compose:args");
01815 if (value != (char *) NULL)
01816 (void) ParseGeometry(value,&geometry_info);
01817 break;
01818 }
01819 case ModulateCompositeOp:
01820 {
01821
01822
01823
01824 value=GetImageArtifact(composite_image,"compose:args");
01825 if (value != (char *) NULL)
01826 {
01827 flags=ParseGeometry(value,&geometry_info);
01828 percent_brightness=geometry_info.rho;
01829 if ((flags & SigmaValue) != 0)
01830 percent_saturation=geometry_info.sigma;
01831 }
01832 break;
01833 }
01834 case ThresholdCompositeOp:
01835 {
01836
01837
01838
01839 value=GetImageArtifact(composite_image,"compose:args");
01840 if (value != (char *) NULL)
01841 {
01842 flags=ParseGeometry(value,&geometry_info);
01843 amount=geometry_info.rho;
01844 threshold=geometry_info.sigma;
01845 if ((flags & SigmaValue) == 0)
01846 threshold=0.05f;
01847 }
01848 threshold*=QuantumRange;
01849 break;
01850 }
01851 default:
01852 break;
01853 }
01854 value=GetImageArtifact(composite_image,"compose:outside-overlay");
01855 if (value != (const char *) NULL)
01856 modify_outside_overlay=IsMagickTrue(value);
01857
01858
01859
01860 status=MagickTrue;
01861 progress=0;
01862 midpoint=((MagickRealType) QuantumRange+1.0)/2;
01863 GetMagickPixelPacket(composite_image,&zero);
01864 exception=(&image->exception);
01865 image_view=AcquireCacheView(image);
01866 composite_view=AcquireCacheView(composite_image);
01867 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01868 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01869 #endif
01870 for (y=0; y < (long) image->rows; y++)
01871 {
01872 const PixelPacket
01873 *pixels;
01874
01875 double
01876 brightness,
01877 hue,
01878 saturation;
01879
01880 MagickPixelPacket
01881 composite,
01882 destination,
01883 source;
01884
01885 register const IndexPacket
01886 *restrict composite_indexes;
01887
01888 register const PixelPacket
01889 *restrict p;
01890
01891 register IndexPacket
01892 *restrict indexes;
01893
01894 register long
01895 x;
01896
01897 register PixelPacket
01898 *restrict q;
01899
01900 if (status == MagickFalse)
01901 continue;
01902 if (modify_outside_overlay == MagickFalse)
01903 {
01904 if (y < y_offset)
01905 continue;
01906 if ((y-y_offset) >= (long) composite_image->rows)
01907 continue;
01908 }
01909
01910
01911
01912 pixels=(PixelPacket *) NULL;
01913 p=(PixelPacket *) NULL;
01914 if ((y >= y_offset) && ((y-y_offset) < (long) composite_image->rows))
01915 {
01916 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
01917 composite_image->columns,1,exception);
01918 if (p == (const PixelPacket *) NULL)
01919 {
01920 status=MagickFalse;
01921 continue;
01922 }
01923 pixels=p;
01924 if (x_offset < 0)
01925 p-=x_offset;
01926 }
01927 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01928 exception);
01929 if (q == (PixelPacket *) NULL)
01930 {
01931 status=MagickFalse;
01932 continue;
01933 }
01934 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01935 composite_indexes=GetCacheViewVirtualIndexQueue(composite_view);
01936 source=zero;
01937 destination=zero;
01938 hue=0.0;
01939 saturation=0.0;
01940 brightness=0.0;
01941 for (x=0; x < (long) image->columns; x++)
01942 {
01943 if (modify_outside_overlay == MagickFalse)
01944 {
01945 if (x < x_offset)
01946 {
01947 q++;
01948 continue;
01949 }
01950 if ((x-x_offset) >= (long) composite_image->columns)
01951 break;
01952 }
01953 destination.red=(MagickRealType) q->red;
01954 destination.green=(MagickRealType) q->green;
01955 destination.blue=(MagickRealType) q->blue;
01956 if (image->matte != MagickFalse)
01957 destination.opacity=(MagickRealType) q->opacity;
01958 if (image->colorspace == CMYKColorspace)
01959 {
01960 destination.red=(MagickRealType) QuantumRange-destination.red;
01961 destination.green=(MagickRealType) QuantumRange-destination.green;
01962 destination.blue=(MagickRealType) QuantumRange-destination.blue;
01963 destination.index=(MagickRealType) (QuantumRange-indexes[x]);
01964 }
01965
01966
01967
01968 composite=destination;
01969 if ((pixels == (PixelPacket *) NULL) || (x < x_offset) ||
01970 ((x-x_offset) >= (long) composite_image->columns))
01971 {
01972 switch (compose)
01973 {
01974 case DissolveCompositeOp:
01975 case BlendCompositeOp:
01976 {
01977 composite.opacity=(MagickRealType) (QuantumRange-
01978 destination_dissolve*(QuantumRange-composite.opacity));
01979 break;
01980 }
01981 case ClearCompositeOp:
01982 case SrcCompositeOp:
01983 {
01984 CompositeClear(&destination,&composite);
01985 break;
01986 }
01987 case InCompositeOp:
01988 case SrcInCompositeOp:
01989 case OutCompositeOp:
01990 case SrcOutCompositeOp:
01991 case DstInCompositeOp:
01992 case DstAtopCompositeOp:
01993 case CopyOpacityCompositeOp:
01994 case ChangeMaskCompositeOp:
01995 {
01996 composite.opacity=(MagickRealType) TransparentOpacity;
01997 break;
01998 }
01999 default:
02000 {
02001 (void) GetOneVirtualMagickPixel(composite_image,x-x_offset,
02002 y-y_offset,&composite,exception);
02003 break;
02004 }
02005 }
02006 if (image->colorspace == CMYKColorspace)
02007 {
02008 composite.red=(MagickRealType) QuantumRange-composite.red;
02009 composite.green=(MagickRealType) QuantumRange-composite.green;
02010 composite.blue=(MagickRealType) QuantumRange-composite.blue;
02011 composite.index=(MagickRealType) QuantumRange-composite.index;
02012 }
02013 q->red=ClampToQuantum(composite.red);
02014 q->green=ClampToQuantum(composite.green);
02015 q->blue=ClampToQuantum(composite.blue);
02016 if (image->matte != MagickFalse)
02017 q->opacity=ClampToQuantum(composite.opacity);
02018 if (image->colorspace == CMYKColorspace)
02019 indexes[x]=ClampToQuantum(composite.index);
02020 q++;
02021 continue;
02022 }
02023
02024
02025
02026 source.red=(MagickRealType) GetRedPixelComponent(p);
02027 source.green=(MagickRealType) GetGreenPixelComponent(p);
02028 source.blue=(MagickRealType) GetBluePixelComponent(p);
02029 if (composite_image->matte != MagickFalse)
02030 source.opacity=(MagickRealType) GetOpacityPixelComponent(p);
02031 if (composite_image->colorspace == CMYKColorspace)
02032 {
02033 source.red=(MagickRealType) QuantumRange-source.red;
02034 source.green=(MagickRealType) QuantumRange-source.green;
02035 source.blue=(MagickRealType) QuantumRange-source.blue;
02036 source.index=(MagickRealType) QuantumRange-(MagickRealType)
02037 composite_indexes[x-x_offset];
02038 }
02039 switch (compose)
02040 {
02041 case AddCompositeOp:
02042 {
02043 CompositeAdd(&source,source.opacity,&destination,destination.opacity,
02044 &composite);
02045 break;
02046 }
02047 case ClearCompositeOp:
02048 {
02049 CompositeClear(&destination,&composite);
02050 break;
02051 }
02052 case SrcCompositeOp:
02053 case CopyCompositeOp:
02054 case ReplaceCompositeOp:
02055 {
02056 composite=source;
02057 break;
02058 }
02059 case ChangeMaskCompositeOp:
02060 {
02061 if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
02062 (IsMagickColorSimilar(&source,&destination) != MagickFalse))
02063 composite.opacity=(MagickRealType) TransparentOpacity;
02064 else
02065 composite.opacity=(MagickRealType) OpaqueOpacity;
02066 break;
02067 }
02068 case DivideCompositeOp:
02069 {
02070 CompositeDivide(&source,source.opacity,&destination,
02071 destination.opacity,&composite);
02072 break;
02073 }
02074 case DstCompositeOp:
02075 break;
02076 case OverCompositeOp:
02077 case SrcOverCompositeOp:
02078 {
02079 CompositeOver(&source,source.opacity,&destination,destination.opacity,
02080 &composite);
02081 break;
02082 }
02083 case DstOverCompositeOp:
02084 {
02085 CompositeOver(&destination,destination.opacity,&source,source.opacity,
02086 &composite);
02087 break;
02088 }
02089 case SrcInCompositeOp:
02090 case InCompositeOp:
02091 {
02092 CompositeIn(&source,source.opacity,&destination,destination.opacity,
02093 &composite);
02094 break;
02095 }
02096 case DstInCompositeOp:
02097 {
02098 CompositeIn(&destination,destination.opacity,&source,source.opacity,
02099 &composite);
02100 break;
02101 }
02102 case OutCompositeOp:
02103 case SrcOutCompositeOp:
02104 {
02105 CompositeOut(&source,source.opacity,&destination,destination.opacity,
02106 &composite);
02107 break;
02108 }
02109 case DstOutCompositeOp:
02110 {
02111 CompositeOut(&destination,destination.opacity,&source,source.opacity,
02112 &composite);
02113 break;
02114 }
02115 case AtopCompositeOp:
02116 case SrcAtopCompositeOp:
02117 {
02118 CompositeAtop(&source,source.opacity,&destination,destination.opacity,
02119 &composite);
02120 break;
02121 }
02122 case DstAtopCompositeOp:
02123 {
02124 CompositeAtop(&destination,destination.opacity,&source,source.opacity,
02125 &composite);
02126 break;
02127 }
02128 case XorCompositeOp:
02129 {
02130 CompositeXor(&source,source.opacity,&destination,destination.opacity,
02131 &composite);
02132 break;
02133 }
02134 case PlusCompositeOp:
02135 {
02136 CompositePlus(&source,source.opacity,&destination,destination.opacity,
02137 &composite);
02138 break;
02139 }
02140 case MultiplyCompositeOp:
02141 {
02142 CompositeMultiply(&source,source.opacity,&destination,
02143 destination.opacity,&composite);
02144 break;
02145 }
02146 case ScreenCompositeOp:
02147 {
02148 CompositeScreen(&source,source.opacity,&destination,
02149 destination.opacity,&composite);
02150 break;
02151 }
02152 case DarkenCompositeOp:
02153 {
02154 CompositeDarken(&source,source.opacity,&destination,
02155 destination.opacity,&composite);
02156 break;
02157 }
02158 case LightenCompositeOp:
02159 {
02160 CompositeLighten(&source,source.opacity,&destination,
02161 destination.opacity,&composite);
02162 break;
02163 }
02164 case ColorDodgeCompositeOp:
02165 {
02166 CompositeColorDodge(&source,source.opacity,&destination,
02167 destination.opacity,&composite);
02168 break;
02169 }
02170 case ColorBurnCompositeOp:
02171 {
02172 CompositeColorBurn(&source,source.opacity,&destination,
02173 destination.opacity,&composite);
02174 break;
02175 }
02176 case LinearDodgeCompositeOp:
02177 {
02178 CompositeLinearDodge(&source,source.opacity,&destination,
02179 destination.opacity,&composite);
02180 break;
02181 }
02182 case LinearBurnCompositeOp:
02183 {
02184 CompositeLinearBurn(&source,source.opacity,&destination,
02185 destination.opacity,&composite);
02186 break;
02187 }
02188 case HardLightCompositeOp:
02189 {
02190 CompositeHardLight(&source,source.opacity,&destination,
02191 destination.opacity,&composite);
02192 break;
02193 }
02194 case OverlayCompositeOp:
02195 {
02196
02197
02198
02199 CompositeHardLight(&destination,destination.opacity,&source,
02200 source.opacity,&composite);
02201 break;
02202 }
02203 case SoftLightCompositeOp:
02204 {
02205 CompositeSoftLight(&source,source.opacity,&destination,
02206 destination.opacity,&composite);
02207 break;
02208 }
02209 case LinearLightCompositeOp:
02210 {
02211 CompositeLinearLight(&source,source.opacity,&destination,
02212 destination.opacity,&composite);
02213 break;
02214 }
02215 case PegtopLightCompositeOp:
02216 {
02217 CompositePegtopLight(&source,source.opacity,&destination,
02218 destination.opacity,&composite);
02219 break;
02220 }
02221 case VividLightCompositeOp:
02222 {
02223 CompositeVividLight(&source,source.opacity,&destination,
02224 destination.opacity,&composite);
02225 break;
02226 }
02227 case PinLightCompositeOp:
02228 {
02229 CompositePinLight(&source,source.opacity,&destination,
02230 destination.opacity,&composite);
02231 break;
02232 }
02233 case DifferenceCompositeOp:
02234 {
02235 CompositeDifference(&source,source.opacity,&destination,
02236 destination.opacity,&composite);
02237 break;
02238 }
02239 case ExclusionCompositeOp:
02240 {
02241 CompositeExclusion(&source,source.opacity,&destination,
02242 destination.opacity,&composite);
02243 break;
02244 }
02245 case MinusCompositeOp:
02246 {
02247 CompositeMinus(&source,source.opacity,&destination,
02248 destination.opacity,&composite);
02249 break;
02250 }
02251 case BumpmapCompositeOp:
02252 {
02253 if (source.opacity == TransparentOpacity)
02254 break;
02255 CompositeBumpmap(&source,source.opacity,&destination,
02256 destination.opacity,&composite);
02257 break;
02258 }
02259 case DissolveCompositeOp:
02260 {
02261 CompositeOver(&source,(MagickRealType) (QuantumRange-source_dissolve*
02262 (QuantumRange-source.opacity)),&destination,(MagickRealType)
02263 (QuantumRange-destination_dissolve*(QuantumRange-
02264 destination.opacity)),&composite);
02265 break;
02266 }
02267 case BlendCompositeOp:
02268 {
02269 MagickPixelCompositeBlend(&source,source_dissolve,&destination,
02270 destination_dissolve,&composite);
02271 break;
02272 }
02273 case MathematicsCompositeOp:
02274 {
02275 CompositeMathematics(&source,&destination,&geometry_info,&composite);
02276 break;
02277 }
02278 case BlurCompositeOp:
02279 case DisplaceCompositeOp:
02280 case DistortCompositeOp:
02281 {
02282 composite=source;
02283 break;
02284 }
02285 case ThresholdCompositeOp:
02286 {
02287 CompositeThreshold(&source,source.opacity,&destination,
02288 destination.opacity,threshold,amount,&composite);
02289 break;
02290 }
02291 case ModulateCompositeOp:
02292 {
02293 long
02294 offset;
02295
02296 if (source.opacity == TransparentOpacity)
02297 break;
02298 offset=(long) (MagickPixelIntensityToQuantum(&source)-midpoint);
02299 if (offset == 0)
02300 break;
02301 CompositeHSB(destination.red,destination.green,destination.blue,&hue,
02302 &saturation,&brightness);
02303 brightness+=(0.01*percent_brightness*offset)/midpoint;
02304 saturation*=0.01*percent_saturation;
02305 HSBComposite(hue,saturation,brightness,&composite.red,
02306 &composite.green,&composite.blue);
02307 break;
02308 }
02309 case HueCompositeOp:
02310 {
02311 if (source.opacity == TransparentOpacity)
02312 break;
02313 if (destination.opacity == TransparentOpacity)
02314 {
02315 composite=source;
02316 break;
02317 }
02318 CompositeHSB(destination.red,destination.green,destination.blue,&hue,
02319 &saturation,&brightness);
02320 CompositeHSB(source.red,source.green,source.blue,&hue,&sans,&sans);
02321 HSBComposite(hue,saturation,brightness,&composite.red,
02322 &composite.green,&composite.blue);
02323 if (source.opacity < destination.opacity)
02324 composite.opacity=source.opacity;
02325 break;
02326 }
02327 case SaturateCompositeOp:
02328 {
02329 if (source.opacity == TransparentOpacity)
02330 break;
02331 if (destination.opacity == TransparentOpacity)
02332 {
02333 composite=source;
02334 break;
02335 }
02336 CompositeHSB(destination.red,destination.green,destination.blue,&hue,
02337 &saturation,&brightness);
02338 CompositeHSB(source.red,source.green,source.blue,&sans,&saturation,
02339 &sans);
02340 HSBComposite(hue,saturation,brightness,&composite.red,
02341 &composite.green,&composite.blue);
02342 if (source.opacity < destination.opacity)
02343 composite.opacity=source.opacity;
02344 break;
02345 }
02346 case SubtractCompositeOp:
02347 {
02348 CompositeSubtract(&source,source.opacity,&destination,
02349 destination.opacity,&composite);
02350 break;
02351 }
02352 case LuminizeCompositeOp:
02353 {
02354 if (source.opacity == TransparentOpacity)
02355 break;
02356 if (destination.opacity == TransparentOpacity)
02357 {
02358 composite=source;
02359 break;
02360 }
02361 CompositeHSB(destination.red,destination.green,destination.blue,&hue,
02362 &saturation,&brightness);
02363 CompositeHSB(source.red,source.green,source.blue,&sans,&sans,
02364 &brightness);
02365 HSBComposite(hue,saturation,brightness,&composite.red,
02366 &composite.green,&composite.blue);
02367 if (source.opacity < destination.opacity)
02368 composite.opacity=source.opacity;
02369 break;
02370 }
02371 case ColorizeCompositeOp:
02372 {
02373 if (source.opacity == TransparentOpacity)
02374 break;
02375 if (destination.opacity == TransparentOpacity)
02376 {
02377 composite=source;
02378 break;
02379 }
02380 CompositeHSB(destination.red,destination.green,destination.blue,&sans,
02381 &sans,&brightness);
02382 CompositeHSB(source.red,source.green,source.blue,&hue,&saturation,
02383 &sans);
02384 HSBComposite(hue,saturation,brightness,&composite.red,
02385 &composite.green,&composite.blue);
02386 if (source.opacity < destination.opacity)
02387 composite.opacity=source.opacity;
02388 break;
02389 }
02390 case CopyRedCompositeOp:
02391 case CopyCyanCompositeOp:
02392 {
02393 composite.red=source.red;
02394 break;
02395 }
02396 case CopyGreenCompositeOp:
02397 case CopyMagentaCompositeOp:
02398 {
02399 composite.green=source.green;
02400 break;
02401 }
02402 case CopyBlueCompositeOp:
02403 case CopyYellowCompositeOp:
02404 {
02405 composite.blue=source.blue;
02406 break;
02407 }
02408 case CopyOpacityCompositeOp:
02409 {
02410 if (source.matte == MagickFalse)
02411 {
02412 composite.opacity=(MagickRealType) (QuantumRange-
02413 MagickPixelIntensityToQuantum(&source));
02414 break;
02415 }
02416 composite.opacity=source.opacity;
02417 break;
02418 }
02419 case CopyBlackCompositeOp:
02420 {
02421 if (source.colorspace != CMYKColorspace)
02422 ConvertRGBToCMYK(&source);
02423 composite.index=source.index;
02424 break;
02425 }
02426 default:
02427 break;
02428 }
02429 if (image->colorspace == CMYKColorspace)
02430 {
02431 composite.red=(MagickRealType) QuantumRange-composite.red;
02432 composite.green=(MagickRealType) QuantumRange-composite.green;
02433 composite.blue=(MagickRealType) QuantumRange-composite.blue;
02434 composite.index=(MagickRealType) QuantumRange-composite.index;
02435 }
02436 q->red=ClampToQuantum(composite.red);
02437 q->green=ClampToQuantum(composite.green);
02438 q->blue=ClampToQuantum(composite.blue);
02439 q->opacity=ClampToQuantum(composite.opacity);
02440 if (image->colorspace == CMYKColorspace)
02441 indexes[x]=ClampToQuantum(composite.index);
02442 p++;
02443 if (p >= (pixels+composite_image->columns))
02444 p=pixels;
02445 q++;
02446 }
02447 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
02448 status=MagickFalse;
02449 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02450 {
02451 MagickBooleanType
02452 proceed;
02453
02454 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02455 #pragma omp critical (MagickCore_CompositeImageChannel)
02456 #endif
02457 proceed=SetImageProgress(image,CompositeImageTag,progress++,
02458 image->rows);
02459 if (proceed == MagickFalse)
02460 status=MagickFalse;
02461 }
02462 }
02463 composite_view=DestroyCacheView(composite_view);
02464 image_view=DestroyCacheView(image_view);
02465 if (destination_image != (Image * ) NULL)
02466 destination_image=DestroyImage(destination_image);
02467 return(status);
02468 }
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture)
02496 {
02497 #define TextureImageTag "Texture/Image"
02498
02499 CacheView
02500 *image_view,
02501 *texture_view;
02502
02503 ExceptionInfo
02504 *exception;
02505
02506 long
02507 y;
02508
02509 MagickBooleanType
02510 status;
02511
02512 assert(image != (Image *) NULL);
02513 if (image->debug != MagickFalse)
02514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
02515 assert(image->signature == MagickSignature);
02516 if (texture == (const Image *) NULL)
02517 return(MagickFalse);
02518 (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
02519 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
02520 return(MagickFalse);
02521 status=MagickTrue;
02522 if ((image->compose != CopyCompositeOp) &&
02523 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
02524 (texture->matte != MagickFalse)))
02525 {
02526
02527
02528
02529 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
02530 #pragma omp parallel for schedule(dynamic,4) shared(status)
02531 #endif
02532 for (y=0; y < (long) image->rows; y+=texture->rows)
02533 {
02534 register long
02535 x;
02536
02537 if (status == MagickFalse)
02538 continue;
02539 for (x=0; x < (long) image->columns; x+=texture->columns)
02540 {
02541 MagickBooleanType
02542 thread_status;
02543
02544 thread_status=CompositeImage(image,image->compose,texture,x+
02545 texture->tile_offset.x,y+texture->tile_offset.y);
02546 if (thread_status == MagickFalse)
02547 {
02548 status=thread_status;
02549 break;
02550 }
02551 }
02552 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02553 {
02554 MagickBooleanType
02555 proceed;
02556
02557 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP > 202001)
02558 #pragma omp critical (MagickCore_TextureImage)
02559 #endif
02560 proceed=SetImageProgress(image,TextureImageTag,y,image->rows);
02561 if (proceed == MagickFalse)
02562 status=MagickFalse;
02563 }
02564 }
02565 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
02566 image->rows,image->rows);
02567 return(status);
02568 }
02569
02570
02571
02572 status=MagickTrue;
02573 exception=(&image->exception);
02574 image_view=AcquireCacheView(image);
02575 texture_view=AcquireCacheView(texture);
02576 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02577 #pragma omp parallel for schedule(dynamic,4) shared(status)
02578 #endif
02579 for (y=0; y < (long) image->rows; y++)
02580 {
02581 MagickBooleanType
02582 sync;
02583
02584 register const IndexPacket
02585 *texture_indexes;
02586
02587 register const PixelPacket
02588 *p;
02589
02590 register IndexPacket
02591 *indexes;
02592
02593 register long
02594 x;
02595
02596 register PixelPacket
02597 *q;
02598
02599 unsigned long
02600 width;
02601
02602 if (status == MagickFalse)
02603 continue;
02604 p=GetCacheViewVirtualPixels(texture_view,texture->tile_offset.x,(y+
02605 texture->tile_offset.y) % texture->rows,texture->columns,1,exception);
02606 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
02607 exception);
02608 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
02609 {
02610 status=MagickFalse;
02611 continue;
02612 }
02613 texture_indexes=GetCacheViewVirtualIndexQueue(texture_view);
02614 indexes=GetCacheViewAuthenticIndexQueue(image_view);
02615 for (x=0; x < (long) image->columns; x+=texture->columns)
02616 {
02617 width=texture->columns;
02618 if ((x+(long) width) > (long) image->columns)
02619 width=image->columns-x;
02620 (void) CopyMagickMemory(q,p,width*sizeof(*p));
02621 if ((image->colorspace == CMYKColorspace) &&
02622 (texture->colorspace == CMYKColorspace))
02623 {
02624 (void) CopyMagickMemory(indexes,texture_indexes,width*
02625 sizeof(*indexes));
02626 indexes+=width;
02627 }
02628 q+=width;
02629 }
02630 sync=SyncCacheViewAuthenticPixels(image_view,exception);
02631 if (sync == MagickFalse)
02632 status=MagickFalse;
02633 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02634 {
02635 MagickBooleanType
02636 proceed;
02637
02638 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02639 #pragma omp critical (MagickCore_TextureImage)
02640 #endif
02641 proceed=SetImageProgress(image,TextureImageTag,y,image->rows);
02642 if (proceed == MagickFalse)
02643 status=MagickFalse;
02644 }
02645 }
02646 texture_view=DestroyCacheView(texture_view);
02647 image_view=DestroyCacheView(image_view);
02648 return(status);
02649 }