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