root/ext/gd/libgd/gd_interpolation.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. KernelBessel_J1
  2. KernelBessel_P1
  3. KernelBessel_Q1
  4. KernelBessel_Order1
  5. filter_bessel
  6. filter_blackman
  7. filter_bicubic
  8. filter_generalized_cubic
  9. filter_cubic_spline
  10. filter_cubic_convolution
  11. filter_box
  12. filter_catmullrom
  13. filter_filter
  14. filter_lanczos8
  15. filter_lanczos3
  16. filter_hermite
  17. filter_triangle
  18. filter_bell
  19. filter_mitchell
  20. filter_cosine
  21. filter_quadratic
  22. filter_bspline
  23. filter_quadratic_bspline
  24. filter_gaussian
  25. filter_hanning
  26. filter_hamming
  27. filter_power
  28. filter_sinc
  29. filter_welsh
  30. _color_blend
  31. _setEdgePixel
  32. getPixelOverflowTC
  33. getPixelOverflowPalette
  34. getPixelInterpolateWeight
  35. getPixelInterpolated
  36. _gdContributionsAlloc
  37. _gdContributionsFree
  38. _gdContributionsCalc
  39. _gdScaleRow
  40. _gdScaleHoriz
  41. _gdScaleCol
  42. _gdScaleVert
  43. gdImageScaleTwoPass
  44. Scale
  45. gdImageScaleNearestNeighbour
  46. getPixelOverflowColorTC
  47. gdImageScaleBilinearPalette
  48. gdImageScaleBilinearTC
  49. gdImageScaleBilinear
  50. gdImageScaleBicubicFixed
  51. gdImageScale
  52. gdImageRotateNearestNeighbour
  53. gdImageRotateGeneric
  54. gdImageRotateBilinear
  55. gdImageRotateBicubicFixed
  56. gdImageRotateInterpolated
  57. gdImageClipRectangle
  58. gdDumpRect
  59. gdTransformAffineGetImage
  60. gdTransformAffineCopy
  61. gdTransformAffineBoundingBox
  62. gdImageSetInterpolationMethod

   1 /*
   2  * The two pass scaling function is based on:
   3  * Filtered Image Rescaling
   4  * Based on Gems III
   5  *  - Schumacher general filtered image rescaling
   6  * (pp. 414-424)
   7  * by Dale Schumacher
   8  *
   9  *      Additional changes by Ray Gardener, Daylon Graphics Ltd.
  10  *      December 4, 1999
  11  *
  12  *      Ported to libgd by Pierre Joye. Support for multiple channels
  13  *      added (argb for now).
  14  *
  15  *      Initial sources code is avaibable in the Gems Source Code Packages:
  16  *      http://www.acm.org/pubs/tog/GraphicsGems/GGemsIII.tar.gz
  17  *
  18  */
  19 
  20 /*
  21         Summary:
  22 
  23                 - Horizontal filter contributions are calculated on the fly,
  24                   as each column is mapped from src to dst image. This lets
  25                   us omit having to allocate a temporary full horizontal stretch
  26                   of the src image.
  27 
  28                 - If none of the src pixels within a sampling region differ,
  29                   then the output pixel is forced to equal (any of) the source pixel.
  30                   This ensures that filters do not corrupt areas of constant color.
  31 
  32                 - Filter weight contribution results, after summing, are
  33                   rounded to the nearest pixel color value instead of
  34                   being casted to ILubyte (usually an int or char). Otherwise,
  35                   artifacting occurs.
  36 
  37 */
  38 
  39 /*
  40         Additional functions are available for simple rotation or up/downscaling.
  41         downscaling using the fixed point implementations are usually much faster
  42         than the existing gdImageCopyResampled while having a similar or better
  43         quality.
  44 
  45         For image rotations, the optimized versions have a lazy antialiasing for
  46         the edges of the images. For a much better antialiased result, the affine
  47         function is recommended.
  48 */
  49 
  50 /*
  51 TODO:
  52  - Optimize pixel accesses and loops once we have continuous buffer
  53  - Add scale support for a portion only of an image (equivalent of copyresized/resampled)
  54  */
  55 
  56 #include <stdio.h>
  57 #include <stdlib.h>
  58 #include <string.h>
  59 #include <math.h>
  60 
  61 #include <gd.h>
  62 #include "gdhelpers.h"
  63 
  64 #ifdef _MSC_VER
  65 # pragma optimize("t", on)
  66 # include <emmintrin.h>
  67 #endif
  68 
  69 #ifndef MIN
  70 #define MIN(a,b) ((a)<(b)?(a):(b))
  71 #endif
  72 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
  73 #ifndef MAX
  74 #define MAX(a,b) ((a)<(b)?(b):(a))
  75 #endif
  76 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
  77 
  78 #define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  79 
  80 /* only used here, let do a generic fixed point integers later if required by other
  81    part of GD */
  82 typedef long gdFixed;
  83 /* Integer to fixed point */
  84 #define gd_itofx(x) ((x) << 8)
  85 
  86 /* Float to fixed point */
  87 #define gd_ftofx(x) (long)((x) * 256)
  88 
  89 /*  Double to fixed point */
  90 #define gd_dtofx(x) (long)((x) * 256)
  91 
  92 /* Fixed point to integer */
  93 #define gd_fxtoi(x) ((x) >> 8)
  94 
  95 /* Fixed point to float */
  96 # define gd_fxtof(x) ((float)(x) / 256)
  97 
  98 /* Fixed point to double */
  99 #define gd_fxtod(x) ((double)(x) / 256)
 100 
 101 /* Multiply a fixed by a fixed */
 102 #define gd_mulfx(x,y) (((x) * (y)) >> 8)
 103 
 104 /* Divide a fixed by a fixed */
 105 #define gd_divfx(x,y) (((x) << 8) / (y))
 106 
 107 typedef struct
 108 {
 109    double *Weights;  /* Normalized weights of neighboring pixels */
 110    int Left,Right;   /* Bounds of source pixels window */
 111 } ContributionType;  /* Contirbution information for a single pixel */
 112 
 113 typedef struct
 114 {
 115    ContributionType *ContribRow; /* Row (or column) of contribution weights */
 116    unsigned int WindowSize,      /* Filter window size (of affecting source pixels) */
 117                                 LineLength;      /* Length of line (no. or rows / cols) */
 118 } LineContribType;
 119 
 120 /* Each core filter has its own radius */
 121 #define DEFAULT_FILTER_BICUBIC                          3.0
 122 #define DEFAULT_FILTER_BOX                                      0.5
 123 #define DEFAULT_FILTER_GENERALIZED_CUBIC        0.5
 124 #define DEFAULT_FILTER_RADIUS                           1.0
 125 #define DEFAULT_LANCZOS8_RADIUS                         8.0
 126 #define DEFAULT_LANCZOS3_RADIUS                         3.0
 127 #define DEFAULT_HERMITE_RADIUS                          1.0
 128 #define DEFAULT_BOX_RADIUS                                      0.5
 129 #define DEFAULT_TRIANGLE_RADIUS                         1.0
 130 #define DEFAULT_BELL_RADIUS                                     1.5
 131 #define DEFAULT_CUBICSPLINE_RADIUS                      2.0
 132 #define DEFAULT_MITCHELL_RADIUS                         2.0
 133 #define DEFAULT_COSINE_RADIUS                           1.0
 134 #define DEFAULT_CATMULLROM_RADIUS                       2.0
 135 #define DEFAULT_QUADRATIC_RADIUS                        1.5
 136 #define DEFAULT_QUADRATICBSPLINE_RADIUS         1.5
 137 #define DEFAULT_CUBICCONVOLUTION_RADIUS         3.0
 138 #define DEFAULT_GAUSSIAN_RADIUS                         1.0
 139 #define DEFAULT_HANNING_RADIUS                          1.0
 140 #define DEFAULT_HAMMING_RADIUS                          1.0
 141 #define DEFAULT_SINC_RADIUS                                     1.0
 142 #define DEFAULT_WELSH_RADIUS                            1.0
 143 
 144 enum GD_RESIZE_FILTER_TYPE{
 145         FILTER_DEFAULT          = 0,
 146         FILTER_BELL,
 147         FILTER_BESSEL,
 148         FILTER_BLACKMAN,
 149         FILTER_BOX,
 150         FILTER_BSPLINE,
 151         FILTER_CATMULLROM,
 152         FILTER_COSINE,
 153         FILTER_CUBICCONVOLUTION,
 154         FILTER_CUBICSPLINE,
 155         FILTER_HERMITE,
 156         FILTER_LANCZOS3,
 157         FILTER_LANCZOS8,
 158         FILTER_MITCHELL,
 159         FILTER_QUADRATIC,
 160         FILTER_QUADRATICBSPLINE,
 161         FILTER_TRIANGLE,
 162         FILTER_GAUSSIAN,
 163         FILTER_HANNING,
 164         FILTER_HAMMING,
 165         FILTER_SINC,
 166         FILTER_WELSH,
 167 
 168         FILTER_CALLBACK        = 999
 169 };
 170 
 171 typedef enum GD_RESIZE_FILTER_TYPE gdResizeFilterType;
 172 
 173 static double KernelBessel_J1(const double x)
 174 {
 175         double p, q;
 176 
 177         register long i;
 178 
 179         static const double
 180         Pone[] =
 181         {
 182                 0.581199354001606143928050809e+21,
 183                 -0.6672106568924916298020941484e+20,
 184                 0.2316433580634002297931815435e+19,
 185                 -0.3588817569910106050743641413e+17,
 186                 0.2908795263834775409737601689e+15,
 187                 -0.1322983480332126453125473247e+13,
 188                 0.3413234182301700539091292655e+10,
 189                 -0.4695753530642995859767162166e+7,
 190                 0.270112271089232341485679099e+4
 191         },
 192         Qone[] =
 193         {
 194                 0.11623987080032122878585294e+22,
 195                 0.1185770712190320999837113348e+20,
 196                 0.6092061398917521746105196863e+17,
 197                 0.2081661221307607351240184229e+15,
 198                 0.5243710262167649715406728642e+12,
 199                 0.1013863514358673989967045588e+10,
 200                 0.1501793594998585505921097578e+7,
 201                 0.1606931573481487801970916749e+4,
 202                 0.1e+1
 203         };
 204 
 205         p = Pone[8];
 206         q = Qone[8];
 207         for (i=7; i >= 0; i--)
 208         {
 209                 p = p*x*x+Pone[i];
 210                 q = q*x*x+Qone[i];
 211         }
 212         return (double)(p/q);
 213 }
 214 
 215 static double KernelBessel_P1(const double x)
 216 {
 217         double p, q;
 218 
 219         register long i;
 220 
 221         static const double
 222         Pone[] =
 223         {
 224                 0.352246649133679798341724373e+5,
 225                 0.62758845247161281269005675e+5,
 226                 0.313539631109159574238669888e+5,
 227                 0.49854832060594338434500455e+4,
 228                 0.2111529182853962382105718e+3,
 229                 0.12571716929145341558495e+1
 230         },
 231         Qone[] =
 232         {
 233                 0.352246649133679798068390431e+5,
 234                 0.626943469593560511888833731e+5,
 235                 0.312404063819041039923015703e+5,
 236                 0.4930396490181088979386097e+4,
 237                 0.2030775189134759322293574e+3,
 238                 0.1e+1
 239         };
 240 
 241         p = Pone[5];
 242         q = Qone[5];
 243         for (i=4; i >= 0; i--)
 244         {
 245                 p = p*(8.0/x)*(8.0/x)+Pone[i];
 246                 q = q*(8.0/x)*(8.0/x)+Qone[i];
 247         }
 248         return (double)(p/q);
 249 }
 250 
 251 static double KernelBessel_Q1(const double x)
 252 {
 253         double p, q;
 254 
 255         register long i;
 256 
 257         static const double
 258         Pone[] =
 259         {
 260                 0.3511751914303552822533318e+3,
 261                 0.7210391804904475039280863e+3,
 262                 0.4259873011654442389886993e+3,
 263                 0.831898957673850827325226e+2,
 264                 0.45681716295512267064405e+1,
 265                 0.3532840052740123642735e-1
 266         },
 267         Qone[] =
 268         {
 269                 0.74917374171809127714519505e+4,
 270                 0.154141773392650970499848051e+5,
 271                 0.91522317015169922705904727e+4,
 272                 0.18111867005523513506724158e+4,
 273                 0.1038187585462133728776636e+3,
 274                 0.1e+1
 275         };
 276 
 277         p = Pone[5];
 278         q = Qone[5];
 279         for (i=4; i >= 0; i--)
 280         {
 281                 p = p*(8.0/x)*(8.0/x)+Pone[i];
 282                 q = q*(8.0/x)*(8.0/x)+Qone[i];
 283         }
 284         return (double)(p/q);
 285 }
 286 
 287 static double KernelBessel_Order1(double x)
 288 {
 289         double p, q;
 290 
 291         if (x == 0.0)
 292                 return (0.0f);
 293         p = x;
 294         if (x < 0.0)
 295                 x=(-x);
 296         if (x < 8.0)
 297                 return (p*KernelBessel_J1(x));
 298         q = (double)sqrt(2.0f/(M_PI*x))*(double)(KernelBessel_P1(x)*(1.0f/sqrt(2.0f)*(sin(x)-cos(x)))-8.0f/x*KernelBessel_Q1(x)*
 299                 (-1.0f/sqrt(2.0f)*(sin(x)+cos(x))));
 300         if (p < 0.0f)
 301                 q = (-q);
 302         return (q);
 303 }
 304 
 305 static double filter_bessel(const double x)
 306 {
 307         if (x == 0.0f)
 308                 return (double)(M_PI/4.0f);
 309         return (KernelBessel_Order1((double)M_PI*x)/(2.0f*x));
 310 }
 311 
 312 
 313 static double filter_blackman(const double x)
 314 {
 315         return (0.42f+0.5f*(double)cos(M_PI*x)+0.08f*(double)cos(2.0f*M_PI*x));
 316 }
 317 
 318 /**
 319  * Bicubic interpolation kernel (a=-1):
 320   \verbatim
 321           /
 322          | 1-2|t|**2+|t|**3          , if |t| < 1
 323   h(t) = | 4-8|t|+5|t|**2-|t|**3     , if 1<=|t|<2
 324          | 0                         , otherwise
 325           \
 326   \endverbatim
 327  * ***bd*** 2.2004
 328  */
 329 static double filter_bicubic(const double t)
 330 {
 331   const double abs_t = (double)fabs(t);
 332   const double abs_t_sq = abs_t * abs_t;
 333   if (abs_t<1) return 1-2*abs_t_sq+abs_t_sq*abs_t;
 334   if (abs_t<2) return 4 - 8*abs_t +5*abs_t_sq - abs_t_sq*abs_t;
 335   return 0;
 336 }
 337 
 338 /**
 339  * Generalized cubic kernel (for a=-1 it is the same as BicubicKernel):
 340   \verbatim
 341           /
 342          | (a+2)|t|**3 - (a+3)|t|**2 + 1     , |t| <= 1
 343   h(t) = | a|t|**3 - 5a|t|**2 + 8a|t| - 4a   , 1 < |t| <= 2
 344          | 0                                 , otherwise
 345           \
 346   \endverbatim
 347  * Often used values for a are -1 and -1/2.
 348  */
 349 static double filter_generalized_cubic(const double t)
 350 {
 351         const double a = -DEFAULT_FILTER_GENERALIZED_CUBIC;
 352         double abs_t = (double)fabs(t);
 353         double abs_t_sq = abs_t * abs_t;
 354         if (abs_t < 1) return (a + 2) * abs_t_sq * abs_t - (a + 3) * abs_t_sq + 1;
 355         if (abs_t < 2) return a * abs_t_sq * abs_t - 5 * a * abs_t_sq + 8 * a * abs_t - 4 * a;
 356         return 0;
 357 }
 358 
 359 /* CubicSpline filter, default radius 2 */
 360 static double filter_cubic_spline(const double x1)
 361 {
 362         const double x = x1 < 0.0 ? -x1 : x1;
 363 
 364         if (x < 1.0 ) {
 365                 const double x2 = x*x;
 366 
 367                 return (0.5 * x2 * x - x2 + 2.0 / 3.0);
 368         }
 369         if (x < 2.0) {
 370                 return (pow(2.0 - x, 3.0)/6.0);
 371         }
 372         return 0;
 373 }
 374 
 375 /* CubicConvolution filter, default radius 3 */
 376 static double filter_cubic_convolution(const double x1)
 377 {
 378         const double x = x1 < 0.0 ? -x1 : x1;
 379         const double x2 = x1 * x1;
 380         const double x2_x = x2 * x;
 381 
 382         if (x <= 1.0) return ((4.0 / 3.0)* x2_x - (7.0 / 3.0) * x2 + 1.0);
 383         if (x <= 2.0) return (- (7.0 / 12.0) * x2_x + 3 * x2 - (59.0 / 12.0) * x + 2.5);
 384         if (x <= 3.0) return ( (1.0/12.0) * x2_x - (2.0 / 3.0) * x2 + 1.75 * x - 1.5);
 385         return 0;
 386 }
 387 
 388 static double filter_box(double x) {
 389         if (x < - DEFAULT_FILTER_BOX)
 390                 return 0.0f;
 391         if (x < DEFAULT_FILTER_BOX)
 392                 return 1.0f;
 393         return 0.0f;
 394 }
 395 
 396 static double filter_catmullrom(const double x)
 397 {
 398         if (x < -2.0)
 399                 return(0.0f);
 400         if (x < -1.0)
 401                 return(0.5f*(4.0f+x*(8.0f+x*(5.0f+x))));
 402         if (x < 0.0)
 403                 return(0.5f*(2.0f+x*x*(-5.0f-3.0f*x)));
 404         if (x < 1.0)
 405                 return(0.5f*(2.0f+x*x*(-5.0f+3.0f*x)));
 406         if (x < 2.0)
 407                 return(0.5f*(4.0f+x*(-8.0f+x*(5.0f-x))));
 408         return(0.0f);
 409 }
 410 
 411 static double filter_filter(double t)
 412 {
 413         /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
 414         if(t < 0.0) t = -t;
 415         if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
 416         return(0.0);
 417 }
 418 
 419 
 420 /* Lanczos8 filter, default radius 8 */
 421 static double filter_lanczos8(const double x1)
 422 {
 423         const double x = x1 < 0.0 ? -x1 : x1;
 424 #define R DEFAULT_LANCZOS8_RADIUS
 425 
 426         if ( x == 0.0) return 1;
 427 
 428         if ( x < R) {
 429                 return R * sin(x*M_PI) * sin(x * M_PI/ R) / (x * M_PI * x * M_PI);
 430         }
 431         return 0.0;
 432 #undef R
 433 }
 434 
 435 
 436 /* Lanczos3 filter, default radius 3 */
 437 static double filter_lanczos3(const double x1)
 438 {
 439         const double x = x1 < 0.0 ? -x1 : x1;
 440 #define R DEFAULT_LANCZOS3_RADIUS
 441 
 442         if ( x == 0.0) return 1;
 443 
 444         if ( x < R)
 445         {
 446                 return R * sin(x*M_PI) * sin(x * M_PI / R) / (x * M_PI * x * M_PI);
 447         }
 448         return 0.0;
 449 #undef R
 450 }
 451 
 452 /* Hermite filter, default radius 1 */
 453 static double filter_hermite(const double x1)
 454 {
 455         const double x = x1 < 0.0 ? -x1 : x1;
 456 
 457         if (x < 1.0) return ((2.0 * x - 3) * x * x + 1.0 );
 458 
 459         return 0.0;
 460 }
 461 
 462 /* Trangle filter, default radius 1 */
 463 static double filter_triangle(const double x1)
 464 {
 465         const double x = x1 < 0.0 ? -x1 : x1;
 466         if (x < 1.0) return (1.0 - x);
 467         return 0.0;
 468 }
 469 
 470 /* Bell filter, default radius 1.5 */
 471 static double filter_bell(const double x1)
 472 {
 473         const double x = x1 < 0.0 ? -x1 : x1;
 474 
 475         if (x < 0.5) return (0.75 - x*x);
 476         if (x < 1.5) return (0.5 * pow(x - 1.5, 2.0));
 477         return 0.0;
 478 }
 479 
 480 /* Mitchell filter, default radius 2.0 */
 481 static double filter_mitchell(const double x)
 482 {
 483 #define KM_B (1.0f/3.0f)
 484 #define KM_C (1.0f/3.0f)
 485 #define KM_P0 ((  6.0f - 2.0f * KM_B ) / 6.0f)
 486 #define KM_P2 ((-18.0f + 12.0f * KM_B + 6.0f * KM_C) / 6.0f)
 487 #define KM_P3 (( 12.0f - 9.0f  * KM_B - 6.0f * KM_C) / 6.0f)
 488 #define KM_Q0 ((  8.0f * KM_B + 24.0f * KM_C) / 6.0f)
 489 #define KM_Q1 ((-12.0f * KM_B - 48.0f * KM_C) / 6.0f)
 490 #define KM_Q2 ((  6.0f * KM_B + 30.0f * KM_C) / 6.0f)
 491 #define KM_Q3 (( -1.0f * KM_B -  6.0f * KM_C) / 6.0f)
 492 
 493         if (x < -2.0)
 494                 return(0.0f);
 495         if (x < -1.0)
 496                 return(KM_Q0-x*(KM_Q1-x*(KM_Q2-x*KM_Q3)));
 497         if (x < 0.0f)
 498                 return(KM_P0+x*x*(KM_P2-x*KM_P3));
 499         if (x < 1.0f)
 500                 return(KM_P0+x*x*(KM_P2+x*KM_P3));
 501         if (x < 2.0f)
 502                 return(KM_Q0+x*(KM_Q1+x*(KM_Q2+x*KM_Q3)));
 503         return(0.0f);
 504 }
 505 
 506 
 507 
 508 /* Cosine filter, default radius 1 */
 509 static double filter_cosine(const double x)
 510 {
 511         if ((x >= -1.0) && (x <= 1.0)) return ((cos(x * M_PI) + 1.0)/2.0);
 512 
 513         return 0;
 514 }
 515 
 516 /* Quadratic filter, default radius 1.5 */
 517 static double filter_quadratic(const double x1)
 518 {
 519         const double x = x1 < 0.0 ? -x1 : x1;
 520 
 521         if (x <= 0.5) return (- 2.0 * x * x + 1);
 522         if (x <= 1.5) return (x * x - 2.5* x + 1.5);
 523         return 0.0;
 524 }
 525 
 526 static double filter_bspline(const double x)
 527 {
 528         if (x>2.0f) {
 529                 return 0.0f;
 530         } else {
 531                 double a, b, c, d;
 532                 /* Was calculated anyway cause the "if((x-1.0f) < 0)" */
 533                 const double xm1 = x - 1.0f;
 534                 const double xp1 = x + 1.0f;
 535                 const double xp2 = x + 2.0f;
 536 
 537                 if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2;
 538                 if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1;
 539                 if (x <= 0) c = 0.0f; else c = x*x*x;
 540                 if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1;
 541 
 542                 return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d)));
 543         }
 544 }
 545 
 546 /* QuadraticBSpline filter, default radius 1.5 */
 547 static double filter_quadratic_bspline(const double x1)
 548 {
 549         const double x = x1 < 0.0 ? -x1 : x1;
 550 
 551         if (x <= 0.5) return (- x * x + 0.75);
 552         if (x <= 1.5) return (0.5 * x * x - 1.5 * x + 1.125);
 553         return 0.0;
 554 }
 555 
 556 static double filter_gaussian(const double x)
 557 {
 558         /* return(exp((double) (-2.0 * x * x)) * sqrt(2.0 / M_PI)); */
 559         return (double)(exp(-2.0f * x * x) * 0.79788456080287f);
 560 }
 561 
 562 static double filter_hanning(const double x)
 563 {
 564         /* A Cosine windowing function */
 565         return(0.5 + 0.5 * cos(M_PI * x));
 566 }
 567 
 568 static double filter_hamming(const double x)
 569 {
 570         /* should be
 571         (0.54+0.46*cos(M_PI*(double) x));
 572         but this approximation is sufficient */
 573         if (x < -1.0f)
 574                 return 0.0f;
 575         if (x < 0.0f)
 576                 return 0.92f*(-2.0f*x-3.0f)*x*x+1.0f;
 577         if (x < 1.0f)
 578                 return 0.92f*(2.0f*x-3.0f)*x*x+1.0f;
 579         return 0.0f;
 580 }
 581 
 582 static double filter_power(const double x)
 583 {
 584         const double a = 2.0f;
 585         if (fabs(x)>1) return 0.0f;
 586         return (1.0f - (double)fabs(pow(x,a)));
 587 }
 588 
 589 static double filter_sinc(const double x)
 590 {
 591         /* X-scaled Sinc(x) function. */
 592         if (x == 0.0) return(1.0);
 593         return (sin(M_PI * (double) x) / (M_PI * (double) x));
 594 }
 595 
 596 static double filter_welsh(const double x)
 597 {
 598         /* Welsh parabolic windowing filter */
 599         if (x <  1.0)
 600                 return(1 - x*x);
 601         return(0.0);
 602 }
 603 
 604 
 605 /* Copied from upstream's libgd */
 606 static inline int _color_blend (const int dst, const int src)
 607 {
 608     const int src_alpha = gdTrueColorGetAlpha(src);
 609 
 610     if( src_alpha == gdAlphaOpaque ) {
 611                 return src;
 612         } else {
 613                 const int dst_alpha = gdTrueColorGetAlpha(dst);
 614 
 615                 if( src_alpha == gdAlphaTransparent ) return dst;
 616                 if( dst_alpha == gdAlphaTransparent ) {
 617                         return src;
 618                 } else {
 619                         register int alpha, red, green, blue;
 620                         const int src_weight = gdAlphaTransparent - src_alpha;
 621                         const int dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
 622                         const int tot_weight = src_weight + dst_weight;
 623 
 624                         alpha = src_alpha * dst_alpha / gdAlphaMax;
 625 
 626                         red = (gdTrueColorGetRed(src) * src_weight
 627                                    + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
 628                         green = (gdTrueColorGetGreen(src) * src_weight
 629                                    + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
 630                         blue = (gdTrueColorGetBlue(src) * src_weight
 631                                    + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
 632 
 633                         return ((alpha << 24) + (red << 16) + (green << 8) + blue);
 634                 }
 635         }
 636 }
 637 
 638 static inline int _setEdgePixel(const gdImagePtr src, unsigned int x, unsigned int y, gdFixed coverage, const int bgColor)
 639 {
 640         const gdFixed f_127 = gd_itofx(127);
 641         register int c = src->tpixels[y][x];
 642         c = c | (( (int) (gd_fxtof(gd_mulfx(coverage, f_127)) + 50.5f)) << 24);
 643         return _color_blend(bgColor, c);
 644 }
 645 
 646 static inline int getPixelOverflowTC(gdImagePtr im, const int x, const int y, const int bgColor)
 647 {
 648         if (gdImageBoundsSafe(im, x, y)) {
 649                 const int c = im->tpixels[y][x];
 650                 if (c == im->transparent) {
 651                         return bgColor == -1 ? gdTrueColorAlpha(0, 0, 0, 127) : bgColor;
 652                 }
 653                 return c;
 654         } else {
 655                 register int border = 0;
 656 
 657                 if (y < im->cy1) {
 658                         border = im->tpixels[0][im->cx1];
 659                         goto processborder;
 660                 }
 661 
 662                 if (y < im->cy1) {
 663                         border = im->tpixels[0][im->cx1];
 664                         goto processborder;
 665                 }
 666 
 667                 if (y > im->cy2) {
 668                         if (x >= im->cx1 && x <= im->cx1) {
 669                                 border = im->tpixels[im->cy2][x];
 670                                 goto processborder;
 671                         } else {
 672                                 return gdTrueColorAlpha(0, 0, 0, 127);
 673                         }
 674                 }
 675 
 676                 /* y is bound safe at this point */
 677                 if (x < im->cx1) {
 678                         border = im->tpixels[y][im->cx1];
 679                         goto processborder;
 680                 }
 681 
 682                 if (x > im->cx2) {
 683                         border = im->tpixels[y][im->cx2];
 684                 }
 685 
 686 processborder:
 687                 if (border == im->transparent) {
 688                         return gdTrueColorAlpha(0, 0, 0, 127);
 689                 } else{
 690                         return gdTrueColorAlpha(gdTrueColorGetRed(border), gdTrueColorGetGreen(border), gdTrueColorGetBlue(border), 127);
 691                 }
 692         }
 693 }
 694 
 695 #define colorIndex2RGBA(c) gdTrueColorAlpha(im->red[(c)], im->green[(c)], im->blue[(c)], im->alpha[(c)])
 696 #define colorIndex2RGBcustomA(c, a) gdTrueColorAlpha(im->red[(c)], im->green[(c)], im->blue[(c)], im->alpha[(a)])
 697 static inline int getPixelOverflowPalette(gdImagePtr im, const int x, const int y, const int bgColor)
 698 {
 699         if (gdImageBoundsSafe(im, x, y)) {
 700                 const int c = im->pixels[y][x];
 701                 if (c == im->transparent) {
 702                         return bgColor == -1 ? gdTrueColorAlpha(0, 0, 0, 127) : bgColor;
 703                 }
 704                 return colorIndex2RGBA(c);
 705         } else {
 706                 register int border = 0;
 707                 if (y < im->cy1) {
 708                         border = gdImageGetPixel(im, im->cx1, 0);
 709                         goto processborder;
 710                 }
 711 
 712                 if (y < im->cy1) {
 713                         border = gdImageGetPixel(im, im->cx1, 0);
 714                         goto processborder;
 715                 }
 716 
 717                 if (y > im->cy2) {
 718                         if (x >= im->cx1 && x <= im->cx1) {
 719                                 border = gdImageGetPixel(im, x,  im->cy2);
 720                                 goto processborder;
 721                         } else {
 722                                 return gdTrueColorAlpha(0, 0, 0, 127);
 723                         }
 724                 }
 725 
 726                 /* y is bound safe at this point */
 727                 if (x < im->cx1) {
 728                         border = gdImageGetPixel(im, im->cx1, y);
 729                         goto processborder;
 730                 }
 731 
 732                 if (x > im->cx2) {
 733                         border = gdImageGetPixel(im, im->cx2, y);
 734                 }
 735 
 736 processborder:
 737                 if (border == im->transparent) {
 738                         return gdTrueColorAlpha(0, 0, 0, 127);
 739                 } else{
 740                         return colorIndex2RGBcustomA(border, 127);
 741                 }
 742         }
 743 }
 744 
 745 static int getPixelInterpolateWeight(gdImagePtr im, const double x, const double y, const int bgColor)
 746 {
 747         /* Closest pixel <= (xf,yf) */
 748         int sx = (int)(x);
 749         int sy = (int)(y);
 750         const double xf = x - (double)sx;
 751         const double yf = y - (double)sy;
 752         const double nxf = (double) 1.0 - xf;
 753         const double nyf = (double) 1.0 - yf;
 754         const double m1 = xf * yf;
 755         const double m2 = nxf * yf;
 756         const double m3 = xf * nyf;
 757         const double m4 = nxf * nyf;
 758 
 759         /* get color values of neighbouring pixels */
 760         const int c1 = im->trueColor == 1 ? getPixelOverflowTC(im, sx, sy, bgColor)         : getPixelOverflowPalette(im, sx, sy, bgColor);
 761         const int c2 = im->trueColor == 1 ? getPixelOverflowTC(im, sx - 1, sy, bgColor)     : getPixelOverflowPalette(im, sx - 1, sy, bgColor);
 762         const int c3 = im->trueColor == 1 ? getPixelOverflowTC(im, sx, sy - 1, bgColor)     : getPixelOverflowPalette(im, sx, sy - 1, bgColor);
 763         const int c4 = im->trueColor == 1 ? getPixelOverflowTC(im, sx - 1, sy - 1, bgColor) : getPixelOverflowPalette(im, sx, sy - 1, bgColor);
 764         int r, g, b, a;
 765 
 766         if (x < 0) sx--;
 767         if (y < 0) sy--;
 768 
 769         /* component-wise summing-up of color values */
 770         if (im->trueColor) {
 771                 r = (int)(m1*gdTrueColorGetRed(c1)   + m2*gdTrueColorGetRed(c2)   + m3*gdTrueColorGetRed(c3)   + m4*gdTrueColorGetRed(c4));
 772                 g = (int)(m1*gdTrueColorGetGreen(c1) + m2*gdTrueColorGetGreen(c2) + m3*gdTrueColorGetGreen(c3) + m4*gdTrueColorGetGreen(c4));
 773                 b = (int)(m1*gdTrueColorGetBlue(c1)  + m2*gdTrueColorGetBlue(c2)  + m3*gdTrueColorGetBlue(c3)  + m4*gdTrueColorGetBlue(c4));
 774                 a = (int)(m1*gdTrueColorGetAlpha(c1) + m2*gdTrueColorGetAlpha(c2) + m3*gdTrueColorGetAlpha(c3) + m4*gdTrueColorGetAlpha(c4));
 775         } else {
 776                 r = (int)(m1*im->red[(c1)]   + m2*im->red[(c2)]   + m3*im->red[(c3)]   + m4*im->red[(c4)]);
 777                 g = (int)(m1*im->green[(c1)] + m2*im->green[(c2)] + m3*im->green[(c3)] + m4*im->green[(c4)]);
 778                 b = (int)(m1*im->blue[(c1)]  + m2*im->blue[(c2)]  + m3*im->blue[(c3)]  + m4*im->blue[(c4)]);
 779                 a = (int)(m1*im->alpha[(c1)] + m2*im->alpha[(c2)] + m3*im->alpha[(c3)] + m4*im->alpha[(c4)]);
 780         }
 781 
 782         r = CLAMP(r, 0, 255);
 783         g = CLAMP(g, 0, 255);
 784         b = CLAMP(b, 0, 255);
 785         a = CLAMP(a, 0, gdAlphaMax);
 786         return gdTrueColorAlpha(r, g, b, a);
 787 }
 788 
 789 /**
 790  * Function: getPixelInterpolated
 791  *  Returns the interpolated color value using the default interpolation
 792  *  method. The returned color is always in the ARGB format (truecolor).
 793  *
 794  * Parameters:
 795  *      im - Image to set the default interpolation method
 796  *  y - X value of the ideal position
 797  *  y - Y value of the ideal position
 798  *  method - Interpolation method <gdInterpolationMethod>
 799  *
 800  * Returns:
 801  *  GD_TRUE if the affine is rectilinear or GD_FALSE
 802  *
 803  * See also:
 804  *  <gdSetInterpolationMethod>
 805  */
 806 int getPixelInterpolated(gdImagePtr im, const double x, const double y, const int bgColor)
 807 {
 808         const int xi=(int)((x) < 0 ? x - 1: x);
 809         const int yi=(int)((y) < 0 ? y - 1: y);
 810         int yii;
 811         int i;
 812         double kernel, kernel_cache_y;
 813         double kernel_x[12], kernel_y[4];
 814         double new_r = 0.0f, new_g = 0.0f, new_b = 0.0f, new_a = 0.0f;
 815 
 816         /* These methods use special implementations */
 817         if (im->interpolation_id == GD_BILINEAR_FIXED || im->interpolation_id == GD_BICUBIC_FIXED || im->interpolation_id == GD_NEAREST_NEIGHBOUR) {
 818                 return -1;
 819         }
 820 
 821         if (im->interpolation_id == GD_WEIGHTED4) {
 822                 return getPixelInterpolateWeight(im, x, y, bgColor);
 823         }
 824 
 825         if (im->interpolation_id == GD_NEAREST_NEIGHBOUR) {
 826                 if (im->trueColor == 1) {
 827                         return getPixelOverflowTC(im, xi, yi, bgColor);
 828                 } else {
 829                         return getPixelOverflowPalette(im, xi, yi, bgColor);
 830                 }
 831         }
 832         if (im->interpolation) {
 833                 for (i=0; i<4; i++) {
 834                         kernel_x[i] = (double) im->interpolation((double)(xi+i-1-x));
 835                         kernel_y[i] = (double) im->interpolation((double)(yi+i-1-y));
 836                 }
 837         } else {
 838                 return -1;
 839         }
 840 
 841         /*
 842          * TODO: use the known fast rgba multiplication implementation once
 843          * the new formats are in place
 844          */
 845         for (yii = yi-1; yii < yi+3; yii++) {
 846                 int xii;
 847                 kernel_cache_y = kernel_y[yii-(yi-1)];
 848                 if (im->trueColor) {
 849                         for (xii=xi-1; xii<xi+3; xii++) {
 850                                 const int rgbs = getPixelOverflowTC(im, xii, yii, bgColor);
 851 
 852                                 kernel = kernel_cache_y * kernel_x[xii-(xi-1)];
 853                                 new_r += kernel * gdTrueColorGetRed(rgbs);
 854                                 new_g += kernel * gdTrueColorGetGreen(rgbs);
 855                                 new_b += kernel * gdTrueColorGetBlue(rgbs);
 856                                 new_a += kernel * gdTrueColorGetAlpha(rgbs);
 857                         }
 858                 } else {
 859                         for (xii=xi-1; xii<xi+3; xii++) {
 860                                 const int rgbs = getPixelOverflowPalette(im, xii, yii, bgColor);
 861 
 862                                 kernel = kernel_cache_y * kernel_x[xii-(xi-1)];
 863                                 new_r += kernel * gdTrueColorGetRed(rgbs);
 864                                 new_g += kernel * gdTrueColorGetGreen(rgbs);
 865                                 new_b += kernel * gdTrueColorGetBlue(rgbs);
 866                                 new_a += kernel * gdTrueColorGetAlpha(rgbs);
 867                         }
 868                 }
 869         }
 870 
 871         new_r = CLAMP(new_r, 0, 255);
 872         new_g = CLAMP(new_g, 0, 255);
 873         new_b = CLAMP(new_b, 0, 255);
 874         new_a = CLAMP(new_a, 0, gdAlphaMax);
 875 
 876         return gdTrueColorAlpha(((int)new_r), ((int)new_g), ((int)new_b), ((int)new_a));
 877 }
 878 
 879 static inline LineContribType * _gdContributionsAlloc(unsigned int line_length, unsigned int windows_size)
 880 {
 881         unsigned int u = 0;
 882     LineContribType *res;
 883 
 884         res = (LineContribType *) gdMalloc(sizeof(LineContribType));
 885         if (!res) {
 886                 return NULL;
 887         }
 888     res->WindowSize = windows_size;
 889     res->LineLength = line_length;
 890     res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
 891 
 892     for (u = 0 ; u < line_length ; u++) {
 893         res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
 894     }
 895     return res;
 896 }
 897 
 898 static inline void _gdContributionsFree(LineContribType * p)
 899 {
 900         unsigned int u;
 901         for (u = 0; u < p->LineLength; u++)  {
 902                 gdFree(p->ContribRow[u].Weights);
 903         }
 904         gdFree(p->ContribRow);
 905         gdFree(p);
 906 }
 907 
 908 static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsigned int src_size, double scale_d,  const interpolation_method pFilter)
 909 {
 910     double width_d;
 911     double scale_f_d = 1.0;
 912     const double filter_width_d = DEFAULT_BOX_RADIUS;
 913         int windows_size;
 914         unsigned int u;
 915         LineContribType *res;
 916 
 917     if (scale_d < 1.0) {
 918         width_d = filter_width_d / scale_d;
 919         scale_f_d = scale_d;
 920     }  else {
 921         width_d= filter_width_d;
 922     }
 923 
 924     windows_size = 2 * (int)ceil(width_d) + 1;
 925     res = _gdContributionsAlloc(line_size, windows_size);
 926 
 927     for (u = 0; u < line_size; u++) {
 928         const double dCenter = (double)u / scale_d;
 929         /* get the significant edge points affecting the pixel */
 930         register int iLeft = MAX(0, (int)floor (dCenter - width_d));
 931         int iRight = MIN((int)ceil(dCenter + width_d), (int)src_size - 1);
 932         double dTotalWeight = 0.0;
 933                 int iSrc;
 934 
 935         res->ContribRow[u].Left = iLeft;
 936         res->ContribRow[u].Right = iRight;
 937 
 938         /* Cut edge points to fit in filter window in case of spill-off */
 939         if (iRight - iLeft + 1 > windows_size)  {
 940             if (iLeft < ((int)src_size - 1 / 2))  {
 941                 iLeft++;
 942             } else {
 943                 iRight--;
 944             }
 945         }
 946 
 947         for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
 948             dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] =  scale_f_d * (*pFilter)(scale_f_d * (dCenter - (double)iSrc)));
 949         }
 950 
 951                 if (dTotalWeight < 0.0) {
 952                         _gdContributionsFree(res);
 953                         return NULL;
 954                 }
 955 
 956         if (dTotalWeight > 0.0) {
 957             for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
 958                 res->ContribRow[u].Weights[iSrc-iLeft] /= dTotalWeight;
 959             }
 960         }
 961    }
 962    return res;
 963 }
 964 
 965 static inline void _gdScaleRow(gdImagePtr pSrc,  unsigned int src_width, gdImagePtr dst, unsigned int dst_width, unsigned int row, LineContribType *contrib)
 966 {
 967     int *p_src_row = pSrc->tpixels[row];
 968     int *p_dst_row = dst->tpixels[row];
 969         unsigned int x;
 970 
 971     for (x = 0; x < dst_width - 1; x++) {
 972                 register unsigned char r = 0, g = 0, b = 0, a = 0;
 973         const int left = contrib->ContribRow[x].Left;
 974         const int right = contrib->ContribRow[x].Right;
 975                 int i;
 976 
 977                 /* Accumulate each channel */
 978         for (i = left; i <= right; i++) {
 979                         const int left_channel = i - left;
 980             r += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetRed(p_src_row[i])));
 981             g += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetGreen(p_src_row[i])));
 982             b += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetBlue(p_src_row[i])));
 983                         a += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetAlpha(p_src_row[i])));
 984         }
 985         p_dst_row[x] = gdTrueColorAlpha(r, g, b, a);
 986     }
 987 }
 988 
 989 static inline void _gdScaleHoriz(gdImagePtr pSrc, unsigned int src_width, unsigned int src_height, gdImagePtr pDst,  unsigned int dst_width, unsigned int dst_height)
 990 {
 991         unsigned int u;
 992         LineContribType * contrib;
 993 
 994         /* same width, just copy it */
 995         if (dst_width == src_width) {
 996                 unsigned int y;
 997                 for (y = 0; y < src_height - 1; ++y) {
 998                         memcpy(pDst->tpixels[y], pSrc->tpixels[y], src_width);
 999                 }
1000         }
1001 
1002         contrib = _gdContributionsCalc(dst_width, src_width, (double)dst_width / (double)src_width, pSrc->interpolation);
1003         if (contrib == NULL) {
1004                 return;
1005         }
1006         /* Scale each row */
1007         for (u = 0; u < dst_height - 1; u++) {
1008                 _gdScaleRow(pSrc, src_width, pDst, dst_width, u, contrib);
1009         }
1010         _gdContributionsFree (contrib);
1011 }
1012 
1013 static inline void _gdScaleCol (gdImagePtr pSrc,  unsigned int src_width, gdImagePtr pRes, unsigned int dst_width, unsigned int dst_height, unsigned int uCol, LineContribType *contrib)
1014 {
1015         unsigned int y;
1016         for (y = 0; y < dst_height - 1; y++) {
1017                 register unsigned char r = 0, g = 0, b = 0, a = 0;
1018                 const int iLeft = contrib->ContribRow[y].Left;
1019                 const int iRight = contrib->ContribRow[y].Right;
1020                 int i;
1021                 int *row = pRes->tpixels[y];
1022 
1023                 /* Accumulate each channel */
1024                 for (i = iLeft; i <= iRight; i++) {
1025                         const int pCurSrc = pSrc->tpixels[i][uCol];
1026                         const int i_iLeft = i - iLeft;
1027                         r += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetRed(pCurSrc)));
1028                         g += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetGreen(pCurSrc)));
1029                         b += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetBlue(pCurSrc)));
1030                         a += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetAlpha(pCurSrc)));
1031                 }
1032                 pRes->tpixels[y][uCol] = gdTrueColorAlpha(r, g, b, a);
1033         }
1034 }
1035 
1036 static inline void _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_width, const unsigned int src_height, const gdImagePtr pDst, const unsigned int dst_width, const unsigned int dst_height)
1037 {
1038         unsigned int u;
1039         LineContribType * contrib;
1040 
1041         /* same height, copy it */
1042         if (src_height == dst_height) {
1043                 unsigned int y;
1044                 for (y = 0; y < src_height - 1; ++y) {
1045                         memcpy(pDst->tpixels[y], pSrc->tpixels[y], src_width);
1046                 }
1047         }
1048 
1049         contrib = _gdContributionsCalc(dst_height, src_height, (double)(dst_height) / (double)(src_height), pSrc->interpolation);
1050         /* scale each column */
1051         for (u = 0; u < dst_width - 1; u++) {
1052                 _gdScaleCol(pSrc, src_width, pDst, dst_width, dst_height, u, contrib);
1053         }
1054         _gdContributionsFree(contrib);
1055 }
1056 
1057 gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_width, const unsigned int src_height, const unsigned int new_width, const unsigned int new_height)
1058 {
1059         gdImagePtr tmp_im;
1060         gdImagePtr dst;
1061 
1062         /* Convert to truecolor if it isn't; this code requires it. */
1063         if (!src->trueColor) {
1064                 gdImagePaletteToTrueColor(src);
1065         }
1066 
1067         tmp_im = gdImageCreateTrueColor(new_width, src_height);
1068         if (tmp_im == NULL) {
1069                 return NULL;
1070         }
1071         gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
1072         _gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
1073 
1074         dst = gdImageCreateTrueColor(new_width, new_height);
1075         if (dst == NULL) {
1076                 gdImageDestroy(tmp_im);
1077                 return NULL;
1078         }
1079         gdImageSetInterpolationMethod(dst, src->interpolation_id);
1080         _gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
1081         gdImageDestroy(tmp_im);
1082 
1083         return dst;
1084 }
1085 
1086 gdImagePtr Scale(const gdImagePtr src, const unsigned int src_width, const unsigned int src_height, const gdImagePtr dst, const unsigned int new_width, const unsigned int new_height)
1087 {
1088         gdImagePtr tmp_im;
1089 
1090         tmp_im = gdImageCreateTrueColor(new_width, src_height);
1091         if (tmp_im == NULL) {
1092                 return NULL;
1093         }
1094         gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
1095 
1096         _gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
1097         _gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
1098 
1099         gdFree(tmp_im);
1100         return dst;
1101 }
1102 
1103 /*
1104         BilinearFixed, BicubicFixed and nearest implementations are rewamped versions of the implementation in CBitmapEx
1105         http://www.codeproject.com/Articles/29121/CBitmapEx-Free-C-Bitmap-Manipulation-Class
1106         Integer only implementation, good to have for common usages like pre scale very large
1107         images before using another interpolation methods for the last step.
1108 */
1109 gdImagePtr gdImageScaleNearestNeighbour(gdImagePtr im, const unsigned int width, const unsigned int height)
1110 {
1111         const unsigned long new_width = MAX(1, width);
1112         const unsigned long new_height = MAX(1, height);
1113         const float dx = (float)im->sx / (float)new_width;
1114         const float dy = (float)im->sy / (float)new_height;
1115         const gdFixed f_dx = gd_ftofx(dx);
1116         const gdFixed f_dy = gd_ftofx(dy);
1117 
1118         gdImagePtr dst_img;
1119         unsigned long  dst_offset_x;
1120         unsigned long  dst_offset_y = 0;
1121         unsigned int i;
1122 
1123         dst_img = gdImageCreateTrueColor(new_width, new_height);
1124 
1125         if (dst_img == NULL) {
1126                 return NULL;
1127         }
1128 
1129         for (i=0; i<new_height; i++) {
1130                 unsigned int j;
1131                 dst_offset_x = 0;
1132                 if (im->trueColor) {
1133                         for (j=0; j<new_width; j++) {
1134                                 const gdFixed f_i = gd_itofx(i);
1135                                 const gdFixed f_j = gd_itofx(j);
1136                                 const gdFixed f_a = gd_mulfx(f_i, f_dy);
1137                                 const gdFixed f_b = gd_mulfx(f_j, f_dx);
1138                                 const long m = gd_fxtoi(f_a);
1139                                 const long n = gd_fxtoi(f_b);
1140 
1141                                 dst_img->tpixels[dst_offset_y][dst_offset_x++] = im->tpixels[m][n];
1142                         }
1143                 } else {
1144                         for (j=0; j<new_width; j++) {
1145                                 const gdFixed f_i = gd_itofx(i);
1146                                 const gdFixed f_j = gd_itofx(j);
1147                                 const gdFixed f_a = gd_mulfx(f_i, f_dy);
1148                                 const gdFixed f_b = gd_mulfx(f_j, f_dx);
1149                                 const long m = gd_fxtoi(f_a);
1150                                 const long n = gd_fxtoi(f_b);
1151 
1152                                 dst_img->tpixels[dst_offset_y][dst_offset_x++] = colorIndex2RGBA(im->pixels[m][n]);
1153                         }
1154                 }
1155                 dst_offset_y++;
1156         }
1157         return dst_img;
1158 }
1159 
1160 static inline int getPixelOverflowColorTC(gdImagePtr im, const int x, const int y, const int color)
1161 {
1162         if (gdImageBoundsSafe(im, x, y)) {
1163                 const int c = im->tpixels[y][x];
1164                 if (c == im->transparent) {
1165                         return gdTrueColorAlpha(0, 0, 0, 127);
1166                 }
1167                 return c;
1168         } else {
1169                 register int border = 0;
1170                 if (y < im->cy1) {
1171                         border = im->tpixels[0][im->cx1];
1172                         goto processborder;
1173                 }
1174 
1175                 if (y < im->cy1) {
1176                         border = im->tpixels[0][im->cx1];
1177                         goto processborder;
1178                 }
1179 
1180                 if (y > im->cy2) {
1181                         if (x >= im->cx1 && x <= im->cx1) {
1182                                 border = im->tpixels[im->cy2][x];
1183                                 goto processborder;
1184                         } else {
1185                                 return gdTrueColorAlpha(0, 0, 0, 127);
1186                         }
1187                 }
1188 
1189                 /* y is bound safe at this point */
1190                 if (x < im->cx1) {
1191                         border = im->tpixels[y][im->cx1];
1192                         goto processborder;
1193                 }
1194 
1195                 if (x > im->cx2) {
1196                         border = im->tpixels[y][im->cx2];
1197                 }
1198 
1199 processborder:
1200                 if (border == im->transparent) {
1201                         return gdTrueColorAlpha(0, 0, 0, 127);
1202                 } else{
1203                         return gdTrueColorAlpha(gdTrueColorGetRed(border), gdTrueColorGetGreen(border), gdTrueColorGetBlue(border), 127);
1204                 }
1205         }
1206 }
1207 
1208 static gdImagePtr gdImageScaleBilinearPalette(gdImagePtr im, const unsigned int new_width, const unsigned int new_height)
1209 {
1210         long _width = MAX(1, new_width);
1211         long _height = MAX(1, new_height);
1212         float dx = (float)gdImageSX(im) / (float)_width;
1213         float dy = (float)gdImageSY(im) / (float)_height;
1214         gdFixed f_dx = gd_ftofx(dx);
1215         gdFixed f_dy = gd_ftofx(dy);
1216         gdFixed f_1 = gd_itofx(1);
1217 
1218         int dst_offset_h;
1219         int dst_offset_v = 0;
1220         long i;
1221         gdImagePtr new_img;
1222         const int transparent = im->transparent;
1223 
1224         new_img = gdImageCreateTrueColor(new_width, new_height);
1225         if (new_img == NULL) {
1226                 return NULL;
1227         }
1228         new_img->transparent = gdTrueColorAlpha(im->red[transparent], im->green[transparent], im->blue[transparent], im->alpha[transparent]);
1229 
1230         for (i=0; i < _height; i++) {
1231                 long j;
1232                 const gdFixed f_i = gd_itofx(i);
1233                 const gdFixed f_a = gd_mulfx(f_i, f_dy);
1234                 register long m = gd_fxtoi(f_a);
1235 
1236                 dst_offset_h = 0;
1237 
1238                 for (j=0; j < _width; j++) {
1239                         /* Update bitmap */
1240                         gdFixed f_j = gd_itofx(j);
1241                         gdFixed f_b = gd_mulfx(f_j, f_dx);
1242 
1243                         const long n = gd_fxtoi(f_b);
1244                         gdFixed f_f = f_a - gd_itofx(m);
1245                         gdFixed f_g = f_b - gd_itofx(n);
1246 
1247                         const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
1248                         const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g);
1249                         const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
1250                         const gdFixed f_w4 = gd_mulfx(f_f, f_g);
1251                         unsigned int pixel1;
1252                         unsigned int pixel2;
1253                         unsigned int pixel3;
1254                         unsigned int pixel4;
1255                         register gdFixed f_r1, f_r2, f_r3, f_r4,
1256                                         f_g1, f_g2, f_g3, f_g4,
1257                                         f_b1, f_b2, f_b3, f_b4,
1258                                         f_a1, f_a2, f_a3, f_a4;
1259 
1260                         /* zero for the background color, nothig gets outside anyway */
1261                         pixel1 = getPixelOverflowPalette(im, n, m, 0);
1262                         pixel2 = getPixelOverflowPalette(im, n + 1, m, 0);
1263                         pixel3 = getPixelOverflowPalette(im, n, m + 1, 0);
1264                         pixel4 = getPixelOverflowPalette(im, n + 1, m + 1, 0);
1265 
1266                         f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
1267                         f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
1268                         f_r3 = gd_itofx(gdTrueColorGetRed(pixel3));
1269                         f_r4 = gd_itofx(gdTrueColorGetRed(pixel4));
1270                         f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1));
1271                         f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2));
1272                         f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3));
1273                         f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4));
1274                         f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1));
1275                         f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2));
1276                         f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3));
1277                         f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4));
1278                         f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1));
1279                         f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2));
1280                         f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3));
1281                         f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4));
1282 
1283                         {
1284                                 const char red = (char) gd_fxtoi(gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4));
1285                                 const char green = (char) gd_fxtoi(gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4));
1286                                 const char blue = (char) gd_fxtoi(gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4));
1287                                 const char alpha = (char) gd_fxtoi(gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4));
1288 
1289                                 new_img->tpixels[dst_offset_v][dst_offset_h] = gdTrueColorAlpha(red, green, blue, alpha);
1290                         }
1291 
1292                         dst_offset_h++;
1293                 }
1294 
1295                 dst_offset_v++;
1296         }
1297         return new_img;
1298 }
1299 
1300 static gdImagePtr gdImageScaleBilinearTC(gdImagePtr im, const unsigned int new_width, const unsigned int new_height)
1301 {
1302         long dst_w = MAX(1, new_width);
1303         long dst_h = MAX(1, new_height);
1304         float dx = (float)gdImageSX(im) / (float)dst_w;
1305         float dy = (float)gdImageSY(im) / (float)dst_h;
1306         gdFixed f_dx = gd_ftofx(dx);
1307         gdFixed f_dy = gd_ftofx(dy);
1308         gdFixed f_1 = gd_itofx(1);
1309 
1310         int dst_offset_h;
1311         int dst_offset_v = 0;
1312         int dwSrcTotalOffset;
1313         long i;
1314         gdImagePtr new_img;
1315 
1316         new_img = gdImageCreateTrueColor(new_width, new_height);
1317         if (!new_img){
1318                 return NULL;
1319         }
1320 
1321         for (i=0; i < dst_h; i++) {
1322                 long j;
1323                 dst_offset_h = 0;
1324                 for (j=0; j < dst_w; j++) {
1325                         /* Update bitmap */
1326                         gdFixed f_i = gd_itofx(i);
1327                         gdFixed f_j = gd_itofx(j);
1328                         gdFixed f_a = gd_mulfx(f_i, f_dy);
1329                         gdFixed f_b = gd_mulfx(f_j, f_dx);
1330                         const gdFixed m = gd_fxtoi(f_a);
1331                         const gdFixed n = gd_fxtoi(f_b);
1332                         gdFixed f_f = f_a - gd_itofx(m);
1333                         gdFixed f_g = f_b - gd_itofx(n);
1334 
1335                         const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
1336                         const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g);
1337                         const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
1338                         const gdFixed f_w4 = gd_mulfx(f_f, f_g);
1339                         unsigned int pixel1;
1340                         unsigned int pixel2;
1341                         unsigned int pixel3;
1342                         unsigned int pixel4;
1343                         register gdFixed f_r1, f_r2, f_r3, f_r4,
1344                                         f_g1, f_g2, f_g3, f_g4,
1345                                         f_b1, f_b2, f_b3, f_b4,
1346                                         f_a1, f_a2, f_a3, f_a4;
1347                         dwSrcTotalOffset = m + n;
1348                         /* 0 for bgColor, nothing gets outside anyway */
1349                         pixel1 = getPixelOverflowTC(im, n, m, 0);
1350                         pixel2 = getPixelOverflowTC(im, n + 1, m, 0);
1351                         pixel3 = getPixelOverflowTC(im, n, m + 1, 0);
1352                         pixel4 = getPixelOverflowTC(im, n + 1, m + 1, 0);
1353 
1354                         f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
1355                         f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
1356                         f_r3 = gd_itofx(gdTrueColorGetRed(pixel3));
1357                         f_r4 = gd_itofx(gdTrueColorGetRed(pixel4));
1358                         f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1));
1359                         f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2));
1360                         f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3));
1361                         f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4));
1362                         f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1));
1363                         f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2));
1364                         f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3));
1365                         f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4));
1366                         f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1));
1367                         f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2));
1368                         f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3));
1369                         f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4));
1370                         {
1371                                 const unsigned char red   = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4));
1372                                 const unsigned char green = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4));
1373                                 const unsigned char blue  = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4));
1374                                 const unsigned char alpha = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4));
1375 
1376                                 new_img->tpixels[dst_offset_v][dst_offset_h] = gdTrueColorAlpha(red, green, blue, alpha);
1377                         }
1378 
1379                         dst_offset_h++;
1380                 }
1381 
1382                 dst_offset_v++;
1383         }
1384         return new_img;
1385 }
1386 
1387 gdImagePtr gdImageScaleBilinear(gdImagePtr im, const unsigned int new_width, const unsigned int new_height)
1388 {
1389         if (im->trueColor) {
1390                 return gdImageScaleBilinearTC(im, new_width, new_height);
1391         } else {
1392                 return gdImageScaleBilinearPalette(im, new_width, new_height);
1393         }
1394 }
1395 
1396 gdImagePtr gdImageScaleBicubicFixed(gdImagePtr src, const unsigned int width, const unsigned int height)
1397 {
1398         const long new_width = MAX(1, width);
1399         const long new_height = MAX(1, height);
1400         const int src_w = gdImageSX(src);
1401         const int src_h = gdImageSY(src);
1402         const gdFixed f_dx = gd_ftofx((float)src_w / (float)new_width);
1403         const gdFixed f_dy = gd_ftofx((float)src_h / (float)new_height);
1404         const gdFixed f_1 = gd_itofx(1);
1405         const gdFixed f_2 = gd_itofx(2);
1406         const gdFixed f_4 = gd_itofx(4);
1407         const gdFixed f_6 = gd_itofx(6);
1408         const gdFixed f_gamma = gd_ftofx(1.04f);
1409         gdImagePtr dst;
1410 
1411         unsigned int dst_offset_x;
1412         unsigned int dst_offset_y = 0;
1413         long i;
1414 
1415         /* impact perf a bit, but not that much. Implementation for palette
1416            images can be done at a later point.
1417         */
1418         if (src->trueColor == 0) {
1419                 gdImagePaletteToTrueColor(src);
1420         }
1421 
1422         dst = gdImageCreateTrueColor(new_width, new_height);
1423         if (!dst) {
1424                 return NULL;
1425         }
1426 
1427         dst->saveAlphaFlag = 1;
1428 
1429         for (i=0; i < new_height; i++) {
1430                 long j;
1431                 dst_offset_x = 0;
1432 
1433                 for (j=0; j < new_width; j++) {
1434                         const gdFixed f_a = gd_mulfx(gd_itofx(i), f_dy);
1435                         const gdFixed f_b = gd_mulfx(gd_itofx(j), f_dx);
1436                         const long m = gd_fxtoi(f_a);
1437                         const long n = gd_fxtoi(f_b);
1438                         const gdFixed f_f = f_a - gd_itofx(m);
1439                         const gdFixed f_g = f_b - gd_itofx(n);
1440                         unsigned int src_offset_x[16], src_offset_y[16];
1441                         long k;
1442                         register gdFixed f_red = 0, f_green = 0, f_blue = 0, f_alpha = 0;
1443                         unsigned char red, green, blue, alpha = 0;
1444                         int *dst_row = dst->tpixels[dst_offset_y];
1445 
1446                         if ((m < 1) || (n < 1)) {
1447                                 src_offset_x[0] = n;
1448                                 src_offset_y[0] = m;
1449                         } else {
1450                                 src_offset_x[0] = n - 1;
1451                                 src_offset_y[0] = m;
1452                         }
1453 
1454                         if (m < 1) {
1455                                 src_offset_x[1] = n;
1456                                 src_offset_y[1] = m;
1457                         } else {
1458                                 src_offset_x[1] = n;
1459                                 src_offset_y[1] = m;
1460                         }
1461 
1462                         if ((m < 1) || (n >= src_w - 1)) {
1463                                 src_offset_x[2] = n;
1464                                 src_offset_y[2] = m;
1465                         } else {
1466                                 src_offset_x[2] = n + 1;
1467                                 src_offset_y[2] = m;
1468                         }
1469 
1470                         if ((m < 1) || (n >= src_w - 2)) {
1471                                 src_offset_x[3] = n;
1472                                 src_offset_y[3] = m;
1473                         } else {
1474                                 src_offset_x[3] = n + 1 + 1;
1475                                 src_offset_y[3] = m;
1476                         }
1477 
1478                         if (n < 1) {
1479                                 src_offset_x[4] = n;
1480                                 src_offset_y[4] = m;
1481                         } else {
1482                                 src_offset_x[4] = n - 1;
1483                                 src_offset_y[4] = m;
1484                         }
1485 
1486                         src_offset_x[5] = n;
1487                         src_offset_y[5] = m;
1488                         if (n >= src_w-1) {
1489                                 src_offset_x[6] = n;
1490                                 src_offset_y[6] = m;
1491                         } else {
1492                                 src_offset_x[6] = n + 1;
1493                                 src_offset_y[6] = m;
1494                         }
1495 
1496                         if (n >= src_w - 2) {
1497                                 src_offset_x[7] = n;
1498                                 src_offset_y[7] = m;
1499                         } else {
1500                                 src_offset_x[7] = n + 1 + 1;
1501                                 src_offset_y[7] = m;
1502                         }
1503 
1504                         if ((m >= src_h - 1) || (n < 1)) {
1505                                 src_offset_x[8] = n;
1506                                 src_offset_y[8] = m;
1507                         } else {
1508                                 src_offset_x[8] = n - 1;
1509                                 src_offset_y[8] = m;
1510                         }
1511 
1512                         if (m >= src_h - 1) {
1513                                 src_offset_x[8] = n;
1514                                 src_offset_y[8] = m;
1515                         } else {
1516                                 src_offset_x[9] = n;
1517                                 src_offset_y[9] = m;
1518                         }
1519 
1520                         if ((m >= src_h-1) || (n >= src_w-1)) {
1521                                 src_offset_x[10] = n;
1522                                 src_offset_y[10] = m;
1523                         } else {
1524                                 src_offset_x[10] = n + 1;
1525                                 src_offset_y[10] = m;
1526                         }
1527 
1528                         if ((m >= src_h - 1) || (n >= src_w - 2)) {
1529                                 src_offset_x[11] = n;
1530                                 src_offset_y[11] = m;
1531                         } else {
1532                                 src_offset_x[11] = n + 1 + 1;
1533                                 src_offset_y[11] = m;
1534                         }
1535 
1536                         if ((m >= src_h - 2) || (n < 1)) {
1537                                 src_offset_x[12] = n;
1538                                 src_offset_y[12] = m;
1539                         } else {
1540                                 src_offset_x[12] = n - 1;
1541                                 src_offset_y[12] = m;
1542                         }
1543 
1544                         if (m >= src_h - 2) {
1545                                 src_offset_x[13] = n;
1546                                 src_offset_y[13] = m;
1547                         } else {
1548                                 src_offset_x[13] = n;
1549                                 src_offset_y[13] = m;
1550                         }
1551 
1552                         if ((m >= src_h - 2) || (n >= src_w - 1)) {
1553                                 src_offset_x[14] = n;
1554                                 src_offset_y[14] = m;
1555                         } else {
1556                                 src_offset_x[14] = n + 1;
1557                                 src_offset_y[14] = m;
1558                         }
1559 
1560                         if ((m >= src_h - 2) || (n >= src_w - 2)) {
1561                                 src_offset_x[15] = n;
1562                                 src_offset_y[15] = m;
1563                         } else {
1564                                 src_offset_x[15] = n  + 1 + 1;
1565                                 src_offset_y[15] = m;
1566                         }
1567 
1568                         for (k = -1; k < 3; k++) {
1569                                 const gdFixed f = gd_itofx(k)-f_f;
1570                                 const gdFixed f_fm1 = f - f_1;
1571                                 const gdFixed f_fp1 = f + f_1;
1572                                 const gdFixed f_fp2 = f + f_2;
1573                                 register gdFixed f_a = 0, f_b = 0, f_d = 0, f_c = 0;
1574                                 register gdFixed f_RY;
1575                                 int l;
1576 
1577                                 if (f_fp2 > 0) f_a = gd_mulfx(f_fp2, gd_mulfx(f_fp2,f_fp2));
1578                                 if (f_fp1 > 0) f_b = gd_mulfx(f_fp1, gd_mulfx(f_fp1,f_fp1));
1579                                 if (f > 0)     f_c = gd_mulfx(f, gd_mulfx(f,f));
1580                                 if (f_fm1 > 0) f_d = gd_mulfx(f_fm1, gd_mulfx(f_fm1,f_fm1));
1581 
1582                                 f_RY = gd_divfx((f_a - gd_mulfx(f_4,f_b) + gd_mulfx(f_6,f_c) - gd_mulfx(f_4,f_d)),f_6);
1583 
1584                                 for (l = -1; l < 3; l++) {
1585                                         const gdFixed f = gd_itofx(l) - f_g;
1586                                         const gdFixed f_fm1 = f - f_1;
1587                                         const gdFixed f_fp1 = f + f_1;
1588                                         const gdFixed f_fp2 = f + f_2;
1589                                         register gdFixed f_a = 0, f_b = 0, f_c = 0, f_d = 0;
1590                                         register gdFixed f_RX, f_R, f_rs, f_gs, f_bs, f_ba;
1591                                         register int c;
1592                                         const int _k = ((k+1)*4) + (l+1);
1593 
1594                                         if (f_fp2 > 0) f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2));
1595 
1596                                         if (f_fp1 > 0) f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1));
1597 
1598                                         if (f > 0) f_c = gd_mulfx(f,gd_mulfx(f,f));
1599 
1600                                         if (f_fm1 > 0) f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1));
1601 
1602                                         f_RX = gd_divfx((f_a-gd_mulfx(f_4,f_b)+gd_mulfx(f_6,f_c)-gd_mulfx(f_4,f_d)),f_6);
1603                                         f_R = gd_mulfx(f_RY,f_RX);
1604 
1605                                         c = src->tpixels[*(src_offset_y + _k)][*(src_offset_x + _k)];
1606                                         f_rs = gd_itofx(gdTrueColorGetRed(c));
1607                                         f_gs = gd_itofx(gdTrueColorGetGreen(c));
1608                                         f_bs = gd_itofx(gdTrueColorGetBlue(c));
1609                                         f_ba = gd_itofx(gdTrueColorGetAlpha(c));
1610 
1611                                         f_red += gd_mulfx(f_rs,f_R);
1612                                         f_green += gd_mulfx(f_gs,f_R);
1613                                         f_blue += gd_mulfx(f_bs,f_R);
1614                                         f_alpha += gd_mulfx(f_ba,f_R);
1615                                 }
1616                         }
1617 
1618                         red    = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_red,   f_gamma)),  0, 255);
1619                         green  = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_green, f_gamma)),  0, 255);
1620                         blue   = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_blue,  f_gamma)),  0, 255);
1621                         alpha  = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_alpha,  f_gamma)), 0, 127);
1622 
1623                         *(dst_row + dst_offset_x) = gdTrueColorAlpha(red, green, blue, alpha);
1624 
1625                         dst_offset_x++;
1626                 }
1627                 dst_offset_y++;
1628         }
1629         return dst;
1630 }
1631 
1632 gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height)
1633 {
1634         gdImagePtr im_scaled = NULL;
1635 
1636         if (src == NULL || src->interpolation_id < 0 || src->interpolation_id > GD_METHOD_COUNT) {
1637                 return 0;
1638         }
1639 
1640         switch (src->interpolation_id) {
1641                 /*Special cases, optimized implementations */
1642                 case GD_NEAREST_NEIGHBOUR:
1643                         im_scaled = gdImageScaleNearestNeighbour(src, new_width, new_height);
1644                         break;
1645 
1646                 case GD_BILINEAR_FIXED:
1647                         im_scaled = gdImageScaleBilinear(src, new_width, new_height);
1648                         break;
1649 
1650                 case GD_BICUBIC_FIXED:
1651                         im_scaled = gdImageScaleBicubicFixed(src, new_width, new_height);
1652                         break;
1653 
1654                 /* generic */
1655                 default:
1656                         if (src->interpolation == NULL) {
1657                                 return NULL;
1658                         }
1659                         im_scaled = gdImageScaleTwoPass(src, src->sx, src->sy, new_width, new_height);
1660                         break;
1661         }
1662         return im_scaled;
1663 }
1664 
1665 gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, const int bgColor)
1666 {
1667         float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
1668         const int src_w  = gdImageSX(src);
1669         const int src_h = gdImageSY(src);
1670         const unsigned int new_width = (unsigned int)(abs((int)(src_w * cos(_angle))) + abs((int)(src_h * sin(_angle))) + 0.5f);
1671         const unsigned int new_height = (unsigned int)(abs((int)(src_w * sin(_angle))) + abs((int)(src_h * cos(_angle))) + 0.5f);
1672         const gdFixed f_0_5 = gd_ftofx(0.5f);
1673         const gdFixed f_H = gd_itofx(src_h/2);
1674         const gdFixed f_W = gd_itofx(src_w/2);
1675         const gdFixed f_cos = gd_ftofx(cos(-_angle));
1676         const gdFixed f_sin = gd_ftofx(sin(-_angle));
1677 
1678         unsigned int dst_offset_x;
1679         unsigned int dst_offset_y = 0;
1680         unsigned int i;
1681         gdImagePtr dst;
1682 
1683         dst = gdImageCreateTrueColor(new_width, new_height);
1684         if (!dst) {
1685                 return NULL;
1686         }
1687         dst->saveAlphaFlag = 1;
1688         for (i = 0; i < new_height; i++) {
1689                 unsigned int j;
1690                 dst_offset_x = 0;
1691                 for (j = 0; j < new_width; j++) {
1692                         gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
1693                         gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
1694                         gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
1695                         gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
1696                         long m = gd_fxtoi(f_m);
1697                         long n = gd_fxtoi(f_n);
1698 
1699                         if ((m > 0) && (m < src_h-1) && (n > 0) && (n < src_w-1)) {
1700                                 if (dst_offset_y < new_height) {
1701                                         dst->tpixels[dst_offset_y][dst_offset_x++] = src->tpixels[m][n];
1702                                 }
1703                         } else {
1704                                 if (dst_offset_y < new_height) {
1705                                         dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor;
1706                                 }
1707                         }
1708                 }
1709                 dst_offset_y++;
1710         }
1711         return dst;
1712 }
1713 
1714 gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor)
1715 {
1716         float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
1717         const int angle_rounded = (int)floor(degrees * 100);
1718         const int src_w  = gdImageSX(src);
1719         const int src_h = gdImageSY(src);
1720         const unsigned int new_width = (unsigned int)(abs((int)(src_w * cos(_angle))) + abs((int)(src_h * sin(_angle))) + 0.5f);
1721         const unsigned int new_height = (unsigned int)(abs((int)(src_w * sin(_angle))) + abs((int)(src_h * cos(_angle))) + 0.5f);
1722         const gdFixed f_0_5 = gd_ftofx(0.5f);
1723         const gdFixed f_H = gd_itofx(src_h/2);
1724         const gdFixed f_W = gd_itofx(src_w/2);
1725         const gdFixed f_cos = gd_ftofx(cos(-_angle));
1726         const gdFixed f_sin = gd_ftofx(sin(-_angle));
1727 
1728         unsigned int dst_offset_x;
1729         unsigned int dst_offset_y = 0;
1730         unsigned int i;
1731         gdImagePtr dst;
1732 
1733         const gdFixed f_slop_y = f_sin;
1734         const gdFixed f_slop_x = f_cos;
1735         const gdFixed f_slop = f_slop_x > 0 && f_slop_x > 0 ?
1736                                                         f_slop_x > f_slop_y ? gd_divfx(f_slop_y, f_slop_x) : gd_divfx(f_slop_x, f_slop_y)
1737                                                 : 0;
1738 
1739 
1740         if (bgColor < 0) {
1741                 return NULL;
1742         }
1743 
1744         dst = gdImageCreateTrueColor(new_width, new_height);
1745         if (!dst) {
1746                 return NULL;
1747         }
1748         dst->saveAlphaFlag = 1;
1749 
1750         for (i = 0; i < new_height; i++) {
1751                 unsigned int j;
1752                 dst_offset_x = 0;
1753                 for (j = 0; j < new_width; j++) {
1754                         gdFixed f_i = gd_itofx((int)i - (int)new_height/ 2);
1755                         gdFixed f_j = gd_itofx((int)j - (int)new_width / 2);
1756                         gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
1757                         gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
1758                         long m = gd_fxtoi(f_m);
1759                         long n = gd_fxtoi(f_n);
1760 
1761                         if ((n <= 0) || (m <= 0) || (m >= src_h) || (n >= src_w)) {
1762                                 dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor;
1763                         } else if ((n <= 1) || (m <= 1) || (m >= src_h - 1) || (n >= src_w - 1)) {
1764                                 gdFixed f_127 = gd_itofx(127);
1765                                 register int c = getPixelInterpolated(src, n, m, bgColor);
1766                                 c = c | (( gdTrueColorGetAlpha(c) + ((int)(127* gd_fxtof(f_slop)))) << 24);
1767 
1768                                 dst->tpixels[dst_offset_y][dst_offset_x++] = _color_blend(bgColor, c);
1769                         } else {
1770                                 dst->tpixels[dst_offset_y][dst_offset_x++] = getPixelInterpolated(src, n, m, bgColor);
1771                         }
1772                 }
1773                 dst_offset_y++;
1774         }
1775         return dst;
1776 }
1777 
1778 gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int bgColor)
1779 {
1780         float _angle = (float)((- degrees / 180.0f) * M_PI);
1781         const unsigned int src_w = gdImageSX(src);
1782         const unsigned int src_h = gdImageSY(src);
1783         unsigned int new_width = abs((int)(src_w*cos(_angle))) + abs((int)(src_h*sin(_angle) + 0.5f));
1784         unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
1785         const gdFixed f_0_5 = gd_ftofx(0.5f);
1786         const gdFixed f_H = gd_itofx(src_h/2);
1787         const gdFixed f_W = gd_itofx(src_w/2);
1788         const gdFixed f_cos = gd_ftofx(cos(-_angle));
1789         const gdFixed f_sin = gd_ftofx(sin(-_angle));
1790         const gdFixed f_1 = gd_itofx(1);
1791         unsigned int i;
1792         unsigned int dst_offset_x;
1793         unsigned int dst_offset_y = 0;
1794         unsigned int src_offset_x, src_offset_y;
1795         gdImagePtr dst;
1796 
1797         dst = gdImageCreateTrueColor(new_width, new_height);
1798         if (dst == NULL) {
1799                 return NULL;
1800         }
1801         dst->saveAlphaFlag = 1;
1802 
1803         for (i = 0; i < new_height; i++) {
1804                 unsigned int j;
1805                 dst_offset_x = 0;
1806 
1807                 for (j=0; j < new_width; j++) {
1808                         const gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
1809                         const gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
1810                         const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
1811                         const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
1812                         const unsigned int m = gd_fxtoi(f_m);
1813                         const unsigned int n = gd_fxtoi(f_n);
1814 
1815                         if ((m > 0) && (m < src_h - 1) && (n > 0) && (n < src_w - 1)) {
1816                                 const gdFixed f_f = f_m - gd_itofx(m);
1817                                 const gdFixed f_g = f_n - gd_itofx(n);
1818                                 const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
1819                                 const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g);
1820                                 const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
1821                                 const gdFixed f_w4 = gd_mulfx(f_f, f_g);
1822 
1823                                 if (n < src_w - 1) {
1824                                         src_offset_x = n + 1;
1825                                         src_offset_y = m;
1826                                 }
1827 
1828                                 if (m < src_h-1) {
1829                                         src_offset_x = n;
1830                                         src_offset_y = m + 1;
1831                                 }
1832 
1833                                 if (!((n >= src_w-1) || (m >= src_h-1))) {
1834                                         src_offset_x = n + 1;
1835                                         src_offset_y = m + 1;
1836                                 }
1837                                 {
1838                                         const int pixel1 = src->tpixels[src_offset_y][src_offset_x];
1839                                         register int pixel2, pixel3, pixel4;
1840 
1841                                         if (src_offset_y + 1 >= src_h) {
1842                                                 pixel2 = bgColor;
1843                                                 pixel3 = bgColor;
1844                                                 pixel4 = bgColor;
1845                                         } else if (src_offset_x + 1 >= src_w) {
1846                                                 pixel2 = bgColor;
1847                                                 pixel3 = bgColor;
1848                                                 pixel4 = bgColor;
1849                                         } else {
1850                                             pixel2 = src->tpixels[src_offset_y][src_offset_x + 1];
1851                                                 pixel3 = src->tpixels[src_offset_y + 1][src_offset_x];
1852                                                 pixel4 = src->tpixels[src_offset_y + 1][src_offset_x + 1];
1853                                         }
1854                                         {
1855                                                 const gdFixed f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
1856                                                 const gdFixed f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
1857                                                 const gdFixed f_r3 = gd_itofx(gdTrueColorGetRed(pixel3));
1858                                                 const gdFixed f_r4 = gd_itofx(gdTrueColorGetRed(pixel4));
1859                                                 const gdFixed f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1));
1860                                                 const gdFixed f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2));
1861                                                 const gdFixed f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3));
1862                                                 const gdFixed f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4));
1863                                                 const gdFixed f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1));
1864                                                 const gdFixed f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2));
1865                                                 const gdFixed f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3));
1866                                                 const gdFixed f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4));
1867                                                 const gdFixed f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1));
1868                                                 const gdFixed f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2));
1869                                                 const gdFixed f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3));
1870                                                 const gdFixed f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4));
1871                                                 const gdFixed f_red = gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4);
1872                                                 const gdFixed f_green = gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4);
1873                                                 const gdFixed f_blue = gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4);
1874                                                 const gdFixed f_alpha = gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4);
1875 
1876                                                 const unsigned char red   = (unsigned char) CLAMP(gd_fxtoi(f_red),   0, 255);
1877                                                 const unsigned char green = (unsigned char) CLAMP(gd_fxtoi(f_green), 0, 255);
1878                                                 const unsigned char blue  = (unsigned char) CLAMP(gd_fxtoi(f_blue),  0, 255);
1879                                                 const unsigned char alpha = (unsigned char) CLAMP(gd_fxtoi(f_alpha), 0, 127);
1880 
1881                                                 dst->tpixels[dst_offset_y][dst_offset_x++] = gdTrueColorAlpha(red, green, blue, alpha);
1882                                         }
1883                                 }
1884                         } else {
1885                                 dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor;
1886                         }
1887                 }
1888                 dst_offset_y++;
1889         }
1890         return dst;
1891 }
1892 
1893 gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const int bgColor)
1894 {
1895         const float _angle = (float)((- degrees / 180.0f) * M_PI);
1896         const int src_w = gdImageSX(src);
1897         const int src_h = gdImageSY(src);
1898         const unsigned int new_width = abs((int)(src_w*cos(_angle))) + abs((int)(src_h*sin(_angle) + 0.5f));
1899         const unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
1900         const gdFixed f_0_5 = gd_ftofx(0.5f);
1901         const gdFixed f_H = gd_itofx(src_h/2);
1902         const gdFixed f_W = gd_itofx(src_w/2);
1903         const gdFixed f_cos = gd_ftofx(cos(-_angle));
1904         const gdFixed f_sin = gd_ftofx(sin(-_angle));
1905         const gdFixed f_1 = gd_itofx(1);
1906         const gdFixed f_2 = gd_itofx(2);
1907         const gdFixed f_4 = gd_itofx(4);
1908         const gdFixed f_6 = gd_itofx(6);
1909         const gdFixed f_gama = gd_ftofx(1.04f);
1910 
1911         unsigned int dst_offset_x;
1912         unsigned int dst_offset_y = 0;
1913         unsigned int i;
1914         gdImagePtr dst;
1915 
1916         dst = gdImageCreateTrueColor(new_width, new_height);
1917 
1918         if (dst == NULL) {
1919                 return NULL;
1920         }
1921         dst->saveAlphaFlag = 1;
1922 
1923         for (i=0; i < new_height; i++) {
1924                 unsigned int j;
1925                 dst_offset_x = 0;
1926 
1927                 for (j=0; j < new_width; j++) {
1928                         const gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
1929                         const gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
1930                         const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
1931                         const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
1932                         const int m = gd_fxtoi(f_m);
1933                         const int n = gd_fxtoi(f_n);
1934 
1935                         if ((m > 0) && (m < src_h - 1) && (n > 0) && (n < src_w-1)) {
1936                                 const gdFixed f_f = f_m - gd_itofx(m);
1937                                 const gdFixed f_g = f_n - gd_itofx(n);
1938                                 unsigned int src_offset_x[16], src_offset_y[16];
1939                                 unsigned char red, green, blue, alpha;
1940                                 gdFixed f_red=0, f_green=0, f_blue=0, f_alpha=0;
1941                                 int k;
1942 
1943                                 if ((m < 1) || (n < 1)) {
1944                                         src_offset_x[0] = n;
1945                                         src_offset_y[0] = m;
1946                                 } else {
1947                                         src_offset_x[0] = n - 1;
1948                                         src_offset_y[0] = m;
1949                                 }
1950 
1951                                 if (m < 1) {
1952                                         src_offset_x[1] = n;
1953                                         src_offset_y[1] = m;
1954                                 } else {
1955                                         src_offset_x[1] = n;
1956                                         src_offset_y[1] = m ;
1957                                 }
1958 
1959                                 if ((m < 1) || (n >= src_w-1)) {
1960                                         src_offset_x[2] = - 1;
1961                                         src_offset_y[2] = - 1;
1962                                 } else {
1963                                         src_offset_x[2] = n + 1;
1964                                         src_offset_y[2] = m ;
1965                                 }
1966 
1967                                 if ((m < 1) || (n >= src_w-2)) {
1968                                         src_offset_x[3] = - 1;
1969                                         src_offset_y[3] = - 1;
1970                                 } else {
1971                                         src_offset_x[3] = n + 1 + 1;
1972                                         src_offset_y[3] = m ;
1973                                 }
1974 
1975                                 if (n < 1) {
1976                                         src_offset_x[4] = - 1;
1977                                         src_offset_y[4] = - 1;
1978                                 } else {
1979                                         src_offset_x[4] = n - 1;
1980                                         src_offset_y[4] = m;
1981                                 }
1982 
1983                                 src_offset_x[5] = n;
1984                                 src_offset_y[5] = m;
1985                                 if (n >= src_w-1) {
1986                                         src_offset_x[6] = - 1;
1987                                         src_offset_y[6] = - 1;
1988                                 } else {
1989                                         src_offset_x[6] = n + 1;
1990                                         src_offset_y[6] = m;
1991                                 }
1992 
1993                                 if (n >= src_w-2) {
1994                                         src_offset_x[7] = - 1;
1995                                         src_offset_y[7] = - 1;
1996                                 } else {
1997                                         src_offset_x[7] = n + 1 + 1;
1998                                         src_offset_y[7] = m;
1999                                 }
2000 
2001                                 if ((m >= src_h-1) || (n < 1)) {
2002                                         src_offset_x[8] = - 1;
2003                                         src_offset_y[8] = - 1;
2004                                 } else {
2005                                         src_offset_x[8] = n - 1;
2006                                         src_offset_y[8] = m;
2007                                 }
2008 
2009                                 if (m >= src_h-1) {
2010                                         src_offset_x[8] = - 1;
2011                                         src_offset_y[8] = - 1;
2012                                 } else {
2013                                         src_offset_x[9] = n;
2014                                         src_offset_y[9] = m;
2015                                 }
2016 
2017                                 if ((m >= src_h-1) || (n >= src_w-1)) {
2018                                         src_offset_x[10] = - 1;
2019                                         src_offset_y[10] = - 1;
2020                                 } else {
2021                                         src_offset_x[10] = n + 1;
2022                                         src_offset_y[10] = m;
2023                                 }
2024 
2025                                 if ((m >= src_h-1) || (n >= src_w-2)) {
2026                                         src_offset_x[11] = - 1;
2027                                         src_offset_y[11] = - 1;
2028                                 } else {
2029                                         src_offset_x[11] = n + 1 + 1;
2030                                         src_offset_y[11] = m;
2031                                 }
2032 
2033                                 if ((m >= src_h-2) || (n < 1)) {
2034                                         src_offset_x[12] = - 1;
2035                                         src_offset_y[12] = - 1;
2036                                 } else {
2037                                         src_offset_x[12] = n - 1;
2038                                         src_offset_y[12] = m;
2039                                 }
2040 
2041                                 if (m >= src_h-2) {
2042                                         src_offset_x[13] = - 1;
2043                                         src_offset_y[13] = - 1;
2044                                 } else {
2045                                         src_offset_x[13] = n;
2046                                         src_offset_y[13] = m;
2047                                 }
2048 
2049                                 if ((m >= src_h-2) || (n >= src_w - 1)) {
2050                                         src_offset_x[14] = - 1;
2051                                         src_offset_y[14] = - 1;
2052                                 } else {
2053                                         src_offset_x[14] = n + 1;
2054                                         src_offset_y[14] = m;
2055                                 }
2056 
2057                                 if ((m >= src_h-2) || (n >= src_w-2)) {
2058                                         src_offset_x[15] = - 1;
2059                                         src_offset_y[15] = - 1;
2060                                 } else {
2061                                         src_offset_x[15] = n  + 1 + 1;
2062                                         src_offset_y[15] = m;
2063                                 }
2064 
2065                                 for (k=-1; k<3; k++) {
2066                                         const gdFixed f = gd_itofx(k)-f_f;
2067                                         const gdFixed f_fm1 = f - f_1;
2068                                         const gdFixed f_fp1 = f + f_1;
2069                                         const gdFixed f_fp2 = f + f_2;
2070                                         gdFixed f_a = 0, f_b = 0,f_c = 0, f_d = 0;
2071                                         gdFixed f_RY;
2072                                         int l;
2073 
2074                                         if (f_fp2 > 0) {
2075                                                 f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2));
2076                                         }
2077 
2078                                         if (f_fp1 > 0) {
2079                                                 f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1));
2080                                         }
2081 
2082                                         if (f > 0) {
2083                                                 f_c = gd_mulfx(f,gd_mulfx(f,f));
2084                                         }
2085 
2086                                         if (f_fm1 > 0) {
2087                                                 f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1));
2088                                         }
2089                                         f_RY = gd_divfx((f_a-gd_mulfx(f_4,f_b)+gd_mulfx(f_6,f_c)-gd_mulfx(f_4,f_d)),f_6);
2090 
2091                                         for (l=-1;  l< 3; l++) {
2092                                                 const gdFixed f = gd_itofx(l) - f_g;
2093                                                 const gdFixed f_fm1 = f - f_1;
2094                                                 const gdFixed f_fp1 = f + f_1;
2095                                                 const gdFixed f_fp2 = f + f_2;
2096                                                 gdFixed f_a = 0, f_b = 0, f_c = 0, f_d = 0;
2097                                                 gdFixed f_RX, f_R;
2098                                                 const int _k = ((k + 1) * 4) + (l + 1);
2099                                                 register gdFixed f_rs, f_gs, f_bs, f_as;
2100                                                 register int c;
2101 
2102                                                 if (f_fp2 > 0) {
2103                                                         f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2));
2104                                                 }
2105 
2106                                                 if (f_fp1 > 0) {
2107                                                         f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1));
2108                                                 }
2109 
2110                                                 if (f > 0) {
2111                                                         f_c = gd_mulfx(f,gd_mulfx(f,f));
2112                                                 }
2113 
2114                                                 if (f_fm1 > 0) {
2115                                                         f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1));
2116                                                 }
2117 
2118                                                 f_RX = gd_divfx((f_a - gd_mulfx(f_4, f_b) + gd_mulfx(f_6, f_c) - gd_mulfx(f_4, f_d)), f_6);
2119                                                 f_R = gd_mulfx(f_RY, f_RX);
2120 
2121                                                 if ((src_offset_x[_k] <= 0) || (src_offset_y[_k] <= 0) || (src_offset_y[_k] >= src_h) || (src_offset_x[_k] >= src_w)) {
2122                                                         c = bgColor;
2123                                                 } else if ((src_offset_x[_k] <= 1) || (src_offset_y[_k] <= 1) || (src_offset_y[_k] >= (int)src_h - 1) || (src_offset_x[_k] >= (int)src_w - 1)) {
2124                                                         gdFixed f_127 = gd_itofx(127);
2125                                                         c = src->tpixels[src_offset_y[_k]][src_offset_x[_k]];
2126                                                         c = c | (( (int) (gd_fxtof(gd_mulfx(f_R, f_127)) + 50.5f)) << 24);
2127                                                         c = _color_blend(bgColor, c);
2128                                                 } else {
2129                                                         c = src->tpixels[src_offset_y[_k]][src_offset_x[_k]];
2130                                                 }
2131 
2132                                                 f_rs = gd_itofx(gdTrueColorGetRed(c));
2133                                                 f_gs = gd_itofx(gdTrueColorGetGreen(c));
2134                                                 f_bs = gd_itofx(gdTrueColorGetBlue(c));
2135                                                 f_as = gd_itofx(gdTrueColorGetAlpha(c));
2136 
2137                                                 f_red   += gd_mulfx(f_rs, f_R);
2138                                                 f_green += gd_mulfx(f_gs, f_R);
2139                                                 f_blue  += gd_mulfx(f_bs, f_R);
2140                                                 f_alpha += gd_mulfx(f_as, f_R);
2141                                         }
2142                                 }
2143 
2144                                 red   = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_red, f_gama)),   0, 255);
2145                                 green = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_green, f_gama)), 0, 255);
2146                                 blue  = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_blue, f_gama)),  0, 255);
2147                                 alpha = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_alpha, f_gama)), 0, 127);
2148 
2149                                 dst->tpixels[dst_offset_y][dst_offset_x] =  gdTrueColorAlpha(red, green, blue, alpha);
2150                         } else {
2151                                 dst->tpixels[dst_offset_y][dst_offset_x] =  bgColor;
2152                         }
2153                         dst_offset_x++;
2154                 }
2155 
2156                 dst_offset_y++;
2157         }
2158         return dst;
2159 }
2160 
2161 gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor)
2162 {
2163         const int angle_rounded = (int)floor(angle * 100);
2164 
2165         if (bgcolor < 0) {
2166                 return NULL;
2167         }
2168 
2169         /* impact perf a bit, but not that much. Implementation for palette
2170            images can be done at a later point.
2171         */
2172         if (src->trueColor == 0) {
2173                 if (bgcolor < gdMaxColors) {
2174                         bgcolor =  gdTrueColorAlpha(src->red[bgcolor], src->green[bgcolor], src->blue[bgcolor], src->alpha[bgcolor]);
2175                 }
2176                 gdImagePaletteToTrueColor(src);
2177         }
2178 
2179         /* no interpolation needed here */
2180         switch (angle_rounded) {
2181                 case -27000:
2182                 case   9000:
2183                         return gdImageRotate90(src, 0);
2184                 case -18000:
2185                 case  18000:
2186                         return gdImageRotate180(src, 0);
2187                 case -9000:
2188                 case 27000:
2189                         return gdImageRotate270(src, 0);
2190         }
2191 
2192         if (src == NULL || src->interpolation_id < 1 || src->interpolation_id > GD_METHOD_COUNT) {
2193                 return NULL;
2194         }
2195 
2196         switch (src->interpolation_id) {
2197                 case GD_NEAREST_NEIGHBOUR:
2198                         return gdImageRotateNearestNeighbour(src, angle, bgcolor);
2199                         break;
2200 
2201                 case GD_BILINEAR_FIXED:
2202                         return gdImageRotateBilinear(src, angle, bgcolor);
2203                         break;
2204 
2205                 case GD_BICUBIC_FIXED:
2206                         return gdImageRotateBicubicFixed(src, angle, bgcolor);
2207                         break;
2208 
2209                 default:
2210                         return gdImageRotateGeneric(src, angle, bgcolor);
2211         }
2212         return NULL;
2213 }
2214 
2215 /**
2216  * Title: Affine transformation
2217  **/
2218 
2219 /**
2220  * Group: Transform
2221  **/
2222 
2223  static void gdImageClipRectangle(gdImagePtr im, gdRectPtr r)
2224 {
2225         int c1x, c1y, c2x, c2y;
2226         int x1,y1;
2227 
2228         gdImageGetClip(im, &c1x, &c1y, &c2x, &c2y);
2229         x1 = r->x + r->width - 1;
2230         y1 = r->y + r->height - 1;
2231         r->x = CLAMP(r->x, c1x, c2x);
2232         r->y = CLAMP(r->y, c1y, c2y);
2233         r->width = CLAMP(x1, c1x, c2x) - r->x + 1;
2234         r->height = CLAMP(y1, c1y, c2y) - r->y + 1;
2235 }
2236 
2237 void gdDumpRect(const char *msg, gdRectPtr r)
2238 {
2239         printf("%s (%i, %i) (%i, %i)\n", msg, r->x, r->y, r->width, r->height);
2240 }
2241 
2242 /**
2243  * Function: gdTransformAffineGetImage
2244  *  Applies an affine transformation to a region and return an image
2245  *  containing the complete transformation.
2246  *
2247  * Parameters:
2248  *      dst - Pointer to a gdImagePtr to store the created image, NULL when
2249  *        the creation or the transformation failed
2250  *  src - Source image
2251  *  src_area - rectangle defining the source region to transform
2252  *  dstY - Y position in the destination image
2253  *  affine - The desired affine transformation
2254  *
2255  * Returns:
2256  *  GD_TRUE if the affine is rectilinear or GD_FALSE
2257  */
2258 int gdTransformAffineGetImage(gdImagePtr *dst,
2259                   const gdImagePtr src,
2260                   gdRectPtr src_area,
2261                   const double affine[6])
2262 {
2263         int res;
2264         double m[6];
2265         gdRect bbox;
2266         gdRect area_full;
2267 
2268         if (src_area == NULL) {
2269                 area_full.x = 0;
2270                 area_full.y = 0;
2271                 area_full.width  = gdImageSX(src);
2272                 area_full.height = gdImageSY(src);
2273                 src_area = &area_full;
2274         }
2275 
2276         gdTransformAffineBoundingBox(src_area, affine, &bbox);
2277 
2278         *dst = gdImageCreateTrueColor(bbox.width, bbox.height);
2279         if (*dst == NULL) {
2280                 return GD_FALSE;
2281         }
2282         (*dst)->saveAlphaFlag = 1;
2283 
2284         if (!src->trueColor) {
2285                 gdImagePaletteToTrueColor(src);
2286         }
2287 
2288         /* Translate to dst origin (0,0) */
2289         gdAffineTranslate(m, -bbox.x, -bbox.y);
2290         gdAffineConcat(m, affine, m);
2291 
2292         gdImageAlphaBlending(*dst, 0);
2293 
2294         res = gdTransformAffineCopy(*dst,
2295                   0,0,
2296                   src,
2297                   src_area,
2298                   m);
2299 
2300         if (res != GD_TRUE) {
2301                 gdImageDestroy(*dst);
2302                 dst = NULL;
2303                 return GD_FALSE;
2304         } else {
2305                 return GD_TRUE;
2306         }
2307 }
2308 
2309 /**
2310  * Function: gdTransformAffineCopy
2311  *  Applies an affine transformation to a region and copy the result
2312  *  in a destination to the given position.
2313  *
2314  * Parameters:
2315  *      dst - Image to draw the transformed image
2316  *  src - Source image
2317  *  dstX - X position in the destination image
2318  *  dstY - Y position in the destination image
2319  *  src_area - Rectangular region to rotate in the src image
2320  *
2321  * Returns:
2322  *  GD_TRUE if the affine is rectilinear or GD_FALSE
2323  */
2324 int gdTransformAffineCopy(gdImagePtr dst,
2325                   int dst_x, int dst_y,
2326                   const gdImagePtr src,
2327                   gdRectPtr src_region,
2328                   const double affine[6])
2329 {
2330         int c1x,c1y,c2x,c2y;
2331         int backclip = 0;
2332         int backup_clipx1, backup_clipy1, backup_clipx2, backup_clipy2;
2333         register int x, y, src_offset_x, src_offset_y;
2334         double inv[6];
2335         int *dst_p;
2336         gdPointF pt, src_pt;
2337         gdRect bbox;
2338         int end_x, end_y;
2339         gdInterpolationMethod interpolation_id_bak = GD_DEFAULT;
2340         interpolation_method interpolation_bak;
2341 
2342         /* These methods use special implementations */
2343         if (src->interpolation_id == GD_BILINEAR_FIXED || src->interpolation_id == GD_BICUBIC_FIXED || src->interpolation_id == GD_NEAREST_NEIGHBOUR) {
2344                 interpolation_id_bak = src->interpolation_id;
2345                 interpolation_bak = src->interpolation;
2346 
2347                 gdImageSetInterpolationMethod(src, GD_BICUBIC);
2348         }
2349 
2350 
2351         gdImageClipRectangle(src, src_region);
2352 
2353         if (src_region->x > 0 || src_region->y > 0
2354                 || src_region->width < gdImageSX(src)
2355                 || src_region->height < gdImageSY(src)) {
2356                 backclip = 1;
2357 
2358                 gdImageGetClip(src, &backup_clipx1, &backup_clipy1,
2359                 &backup_clipx2, &backup_clipy2);
2360 
2361                 gdImageSetClip(src, src_region->x, src_region->y,
2362                         src_region->x + src_region->width - 1,
2363                         src_region->y + src_region->height - 1);
2364         }
2365 
2366         if (!gdTransformAffineBoundingBox(src_region, affine, &bbox)) {
2367                 if (backclip) {
2368                         gdImageSetClip(src, backup_clipx1, backup_clipy1,
2369                                         backup_clipx2, backup_clipy2);
2370                 }
2371                 gdImageSetInterpolationMethod(src, interpolation_id_bak);
2372                 return GD_FALSE;
2373         }
2374 
2375         gdImageGetClip(dst, &c1x, &c1y, &c2x, &c2y);
2376 
2377         end_x = bbox.width  + (int) fabs(bbox.x);
2378         end_y = bbox.height + (int) fabs(bbox.y);
2379 
2380         /* Get inverse affine to let us work with destination -> source */
2381         gdAffineInvert(inv, affine);
2382 
2383         src_offset_x =  src_region->x;
2384         src_offset_y =  src_region->y;
2385 
2386         if (dst->alphaBlendingFlag) {
2387                 for (y = bbox.y; y <= end_y; y++) {
2388                         pt.y = y + 0.5;
2389                         for (x = 0; x <= end_x; x++) {
2390                                 pt.x = x + 0.5;
2391                                 gdAffineApplyToPointF(&src_pt, &pt, inv);
2392                                 gdImageSetPixel(dst, dst_x + x, dst_y + y, getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, 0));
2393                         }
2394                 }
2395         } else {
2396                 for (y = 0; y <= end_y; y++) {
2397                         pt.y = y + 0.5 + bbox.y;
2398                         if ((dst_y + y) < 0 || ((dst_y + y) > gdImageSY(dst) -1)) {
2399                                 continue;
2400                         }
2401                         dst_p = dst->tpixels[dst_y + y] + dst_x;
2402 
2403                         for (x = 0; x <= end_x; x++) {
2404                                 pt.x = x + 0.5 + bbox.x;
2405                                 gdAffineApplyToPointF(&src_pt, &pt, inv);
2406 
2407                                 if ((dst_x + x) < 0 || (dst_x + x) > (gdImageSX(dst) - 1)) {
2408                                         break;
2409                                 }
2410                                 *(dst_p++) = getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, -1);
2411                         }
2412                 }
2413         }
2414 
2415         /* Restore clip if required */
2416         if (backclip) {
2417                 gdImageSetClip(src, backup_clipx1, backup_clipy1,
2418                                 backup_clipx2, backup_clipy2);
2419         }
2420 
2421         gdImageSetInterpolationMethod(src, interpolation_id_bak);
2422         return GD_TRUE;
2423 }
2424 
2425 /**
2426  * Function: gdTransformAffineBoundingBox
2427  *  Returns the bounding box of an affine transformation applied to a
2428  *  rectangular area <gdRect>
2429  *
2430  * Parameters:
2431  *      src - Rectangular source area for the affine transformation
2432  *  affine - the affine transformation
2433  *  bbox - the resulting bounding box
2434  *
2435  * Returns:
2436  *  GD_TRUE if the affine is rectilinear or GD_FALSE
2437  */
2438 int gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox)
2439 {
2440         gdPointF extent[4], min, max, point;
2441         int i;
2442 
2443         extent[0].x=0.0;
2444         extent[0].y=0.0;
2445         extent[1].x=(double) src->width;
2446         extent[1].y=0.0;
2447         extent[2].x=(double) src->width;
2448         extent[2].y=(double) src->height;
2449         extent[3].x=0.0;
2450         extent[3].y=(double) src->height;
2451 
2452         for (i=0; i < 4; i++) {
2453                 point=extent[i];
2454                 if (gdAffineApplyToPointF(&extent[i], &point, affine) != GD_TRUE) {
2455                         return GD_FALSE;
2456                 }
2457         }
2458         min=extent[0];
2459         max=extent[0];
2460 
2461         for (i=1; i < 4; i++) {
2462                 if (min.x > extent[i].x)
2463                         min.x=extent[i].x;
2464                 if (min.y > extent[i].y)
2465                         min.y=extent[i].y;
2466                 if (max.x < extent[i].x)
2467                         max.x=extent[i].x;
2468                 if (max.y < extent[i].y)
2469                         max.y=extent[i].y;
2470         }
2471         bbox->x = (int) min.x;
2472         bbox->y = (int) min.y;
2473         bbox->width  = (int) floor(max.x - min.x) - 1;
2474         bbox->height = (int) floor(max.y - min.y);
2475         return GD_TRUE;
2476 }
2477 
2478 int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id)
2479 {
2480         if (im == NULL || id < 0 || id > GD_METHOD_COUNT) {
2481                 return 0;
2482         }
2483 
2484         switch (id) {
2485                 case GD_DEFAULT:
2486                         id = GD_BILINEAR_FIXED;
2487                 /* Optimized versions */
2488                 case GD_BILINEAR_FIXED:
2489                 case GD_BICUBIC_FIXED:
2490                 case GD_NEAREST_NEIGHBOUR:
2491                 case GD_WEIGHTED4:
2492                         im->interpolation = NULL;
2493                         break;
2494 
2495                 /* generic versions*/
2496                 case GD_BELL:
2497                         im->interpolation = filter_bell;
2498                         break;
2499                 case GD_BESSEL:
2500                         im->interpolation = filter_bessel;
2501                         break;
2502                 case GD_BICUBIC:
2503                         im->interpolation = filter_bicubic;
2504                         break;
2505                 case GD_BLACKMAN:
2506                         im->interpolation = filter_blackman;
2507                         break;
2508                 case GD_BOX:
2509                         im->interpolation = filter_box;
2510                         break;
2511                 case GD_BSPLINE:
2512                         im->interpolation = filter_bspline;
2513                         break;
2514                 case GD_CATMULLROM:
2515                         im->interpolation = filter_catmullrom;
2516                         break;
2517                 case GD_GAUSSIAN:
2518                         im->interpolation = filter_gaussian;
2519                         break;
2520                 case GD_GENERALIZED_CUBIC:
2521                         im->interpolation = filter_generalized_cubic;
2522                         break;
2523                 case GD_HERMITE:
2524                         im->interpolation = filter_hermite;
2525                         break;
2526                 case GD_HAMMING:
2527                         im->interpolation = filter_hamming;
2528                         break;
2529                 case GD_HANNING:
2530                         im->interpolation = filter_hanning;
2531                         break;
2532                 case GD_MITCHELL:
2533                         im->interpolation = filter_mitchell;
2534                         break;
2535                 case GD_POWER:
2536                         im->interpolation = filter_power;
2537                         break;
2538                 case GD_QUADRATIC:
2539                         im->interpolation = filter_quadratic;
2540                         break;
2541                 case GD_SINC:
2542                         im->interpolation = filter_sinc;
2543                         break;
2544                 case GD_TRIANGLE:
2545                         im->interpolation = filter_triangle;
2546                         break;
2547 
2548                 default:
2549                         return 0;
2550                         break;
2551         }
2552         im->interpolation_id = id;
2553         return 1;
2554 }
2555 
2556 #ifdef _MSC_VER
2557 # pragma optimize("", on)
2558 #endif

/* [<][>][^][v][top][bottom][index][help] */