This source file includes following definitions.
- KernelBessel_J1
- KernelBessel_P1
- KernelBessel_Q1
- KernelBessel_Order1
- filter_bessel
- filter_blackman
- filter_bicubic
- filter_generalized_cubic
- filter_cubic_spline
- filter_cubic_convolution
- filter_box
- filter_catmullrom
- filter_filter
- filter_lanczos8
- filter_lanczos3
- filter_hermite
- filter_triangle
- filter_bell
- filter_mitchell
- filter_cosine
- filter_quadratic
- filter_bspline
- filter_quadratic_bspline
- filter_gaussian
- filter_hanning
- filter_hamming
- filter_power
- filter_sinc
- filter_welsh
- _color_blend
- _setEdgePixel
- getPixelOverflowTC
- getPixelOverflowPalette
- getPixelInterpolateWeight
- getPixelInterpolated
- _gdContributionsAlloc
- _gdContributionsFree
- _gdContributionsCalc
- _gdScaleRow
- _gdScaleHoriz
- _gdScaleCol
- _gdScaleVert
- gdImageScaleTwoPass
- Scale
- gdImageScaleNearestNeighbour
- getPixelOverflowColorTC
- gdImageScaleBilinearPalette
- gdImageScaleBilinearTC
- gdImageScaleBilinear
- gdImageScaleBicubicFixed
- gdImageScale
- gdImageRotateNearestNeighbour
- gdImageRotateGeneric
- gdImageRotateBilinear
- gdImageRotateBicubicFixed
- gdImageRotateInterpolated
- gdImageClipRectangle
- gdDumpRect
- gdTransformAffineGetImage
- gdTransformAffineCopy
- gdTransformAffineBoundingBox
- gdImageSetInterpolationMethod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
81
82 typedef long gdFixed;
83
84 #define gd_itofx(x) ((x) << 8)
85
86
87 #define gd_ftofx(x) (long)((x) * 256)
88
89
90 #define gd_dtofx(x) (long)((x) * 256)
91
92
93 #define gd_fxtoi(x) ((x) >> 8)
94
95
96 # define gd_fxtof(x) ((float)(x) / 256)
97
98
99 #define gd_fxtod(x) ((double)(x) / 256)
100
101
102 #define gd_mulfx(x,y) (((x) * (y)) >> 8)
103
104
105 #define gd_divfx(x,y) (((x) << 8) / (y))
106
107 typedef struct
108 {
109 double *Weights;
110 int Left,Right;
111 } ContributionType;
112
113 typedef struct
114 {
115 ContributionType *ContribRow;
116 unsigned int WindowSize,
117 LineLength;
118 } LineContribType;
119
120
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
320
321
322
323
324
325
326
327
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
340
341
342
343
344
345
346
347
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
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
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
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
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
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
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
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
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
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
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
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
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
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
559 return (double)(exp(-2.0f * x * x) * 0.79788456080287f);
560 }
561
562 static double filter_hanning(const double x)
563 {
564
565 return(0.5 + 0.5 * cos(M_PI * x));
566 }
567
568 static double filter_hamming(const double x)
569 {
570
571
572
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
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
599 if (x < 1.0)
600 return(1 - x*x);
601 return(0.0);
602 }
603
604
605
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
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
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
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
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
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
791
792
793
794
795
796
797
798
799
800
801
802
803
804
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
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
843
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
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
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
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
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
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
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
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
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
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
1105
1106
1107
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
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
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
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
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
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
1416
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
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
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
2170
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
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
2217
2218
2219
2220
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
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
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
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
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
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
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
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
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
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
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
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
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