1
/* GIMP - The GNU Image Manipulation Program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
#include <glib-object.h>
25
#include "libgimpmath/gimpmath.h"
27
#include "paint-funcs-types.h"
29
#include "base/pixel-region.h"
31
#include "scale-funcs.h"
34
#define EPSILON (0.0001) /* arbitary small number for avoiding zero */
36
static void scale_region_no_resample (PixelRegion *srcPR,
38
static void scale_region_lanczos (PixelRegion *srcPR,
40
GimpProgressFunc progress_callback,
41
gpointer progress_data);
43
static void expand_line (gdouble *dest,
48
GimpInterpolationType interp);
49
static void shrink_line (gdouble *dest,
54
GimpInterpolationType interp);
57
/* Catmull-Rom spline - not bad
58
* basic intro http://www.mvps.org/directx/articles/catmull/
59
* This formula will calculate an interpolated point between pt1 and pt2
60
* dx=0 returns pt1; dx=1 returns pt2
64
cubic_spline_fit (gdouble dx,
71
return (gdouble) ((( ( - pt0 + 3 * pt1 - 3 * pt2 + pt3 ) * dx +
72
( 2 * pt0 - 5 * pt1 + 4 * pt2 - pt3 ) ) * dx +
73
( - pt0 + pt2 ) ) * dx + (pt1 + pt1) ) / 2.0;
79
* non-interpolating scale_region. [adam]
82
scale_region_no_resample (PixelRegion *srcPR,
85
const gint width = destPR->w;
86
const gint height = destPR->h;
87
const gint orig_width = srcPR->w;
88
const gint orig_height = srcPR->h;
89
const gint bytes = srcPR->bytes;
100
/* the data pointers... */
101
x_src_offsets = g_new (gint, width * bytes);
102
y_src_offsets = g_new (gint, height);
103
src = g_new (guchar, orig_width * bytes);
104
dest = g_new (guchar, width * bytes);
106
/* pre-calc the scale tables */
107
offset = x_src_offsets;
108
for (x = 0; x < width; x++)
109
for (b = 0; b < bytes; b++)
110
*offset++ = b + bytes * ((x * orig_width + orig_width / 2) / width);
112
offset = y_src_offsets;
113
for (y = 0; y < height; y++)
114
*offset++ = (y * orig_height + orig_height / 2) / height;
117
row_bytes = width * bytes;
120
for (y = 0; y < height; y++)
122
/* if the source of this line was the same as the source
123
* of the last line, there's no point in re-rescaling.
125
if (y_src_offsets[y] != last_src_y)
127
pixel_region_get_row (srcPR, 0, y_src_offsets[y], orig_width, src, 1);
129
for (x = 0; x < row_bytes ; x++)
130
dest[x] = src[x_src_offsets[x]];
132
last_src_y = y_src_offsets[y];
135
pixel_region_set_row (destPR, 0, y, width, dest);
138
g_free (x_src_offsets);
139
g_free (y_src_offsets);
146
get_premultiplied_double_row (PixelRegion *srcPR,
154
const gint bytes = srcPR->bytes;
157
pixel_region_get_row (srcPR, x, y, w, tmp_src, n);
159
if (pixel_region_has_alpha (srcPR))
161
/* premultiply the alpha into the double array */
162
const gint alpha = bytes - 1;
165
for (x = 0; x < w; x++)
167
gdouble mod_alpha = tmp_src[alpha] / 255.0;
169
for (b = 0; b < alpha; b++)
170
irow[b] = mod_alpha * tmp_src[b];
172
irow[b] = tmp_src[alpha];
179
for (x = 0; x < w * bytes; x++)
183
/* set the off edge pixels to their nearest neighbor */
184
for (b = 0; b < 2 * bytes; b++)
185
row[b - 2 * bytes] = row[b % bytes];
187
for (b = 0; b < 2 * bytes; b++)
188
row[b + w * bytes] = row[(w - 1) * bytes + b % bytes];
193
expand_line (gdouble *dest,
198
GimpInterpolationType interp)
201
const gdouble ratio = (gdouble) old_width / (gdouble) width; /* ie reverse scaling_factor */
206
/* we can overflow src's boundaries, so we expect our caller to have
207
allocated extra space for us to do so safely (see scale_region ()) */
211
/* -0.5 is because cubic() interpolates a position between 2nd and 3rd data points
212
* we are assigning to 2nd in dest, hence mean shift of +0.5
213
* +1, -1 ensures we dont (int) a negative; first src col only.
215
case GIMP_INTERPOLATION_CUBIC:
216
for (x = 0; x < width; x++)
218
gdouble xr = x * ratio - 0.5;
221
src_col = (gint) (xr + 1) - 1;
226
s = &src[src_col * bpp];
228
for (b = 0; b < bpp; b++)
229
dest[b] = cubic_spline_fit (frac, s[b - bpp], s[b], s[b + bpp],
237
/* -0.5 corrects the drift from averaging between adjacent points and assigning to dest[b]
238
* +1, -1 ensures we dont (int) a negative; first src col only.
240
case GIMP_INTERPOLATION_LINEAR:
241
for (x = 0; x < width; x++)
243
gdouble xr = (x * ratio + 1 - 0.5) - 1;
247
s = &src[src_col * bpp];
249
for (b = 0; b < bpp; b++)
250
dest[b] = ((s[b + bpp] - s[b]) * frac + s[b]);
256
case GIMP_INTERPOLATION_NONE:
257
case GIMP_INTERPOLATION_LANCZOS:
258
g_assert_not_reached ();
269
shrink_line (gdouble *dest,
274
GimpInterpolationType interp)
280
const gdouble avg_ratio = (gdouble) width / old_width;
281
const gdouble inv_width = 1.0 / width;
282
gint slicepos; /* slice position relative to width */
287
g_printerr ("shrink_line bytes=%d old_width=%d width=%d interp=%d "
289
bytes, old_width, width, interp, avg_ratio);
292
g_return_if_fail (bytes <= 4);
294
/* This algorithm calculates the weighted average of pixel data that
295
each output pixel must receive, taking into account that it always
296
scales down, i.e. there's always more than one input pixel per each
304
/* Initialize accum to the first pixel slice. As there is no partial
305
pixel at start, that value is 0. The source data is interleaved, so
306
we maintain BYTES accumulators at the same time to deal with that
307
many channels simultaneously. */
308
for (b = 0; b < bytes; b++)
311
for (x = 0; x < width; x++)
313
/* Accumulate whole pixels. */
316
for (b = 0; b < bytes; b++)
321
while (slicepos < old_width);
322
slicepos -= old_width;
324
if (! (slicepos < width))
325
g_warning ("Assertion (slicepos < width) failed. Please report.");
329
/* Simplest case: we have reached a whole pixel boundary. Store
330
the average value per channel and reset the accumulators for
333
The main reason to treat this case separately is to avoid an
334
access to out-of-bounds memory for the first pixel. */
335
for (b = 0; b < bytes; b++)
337
*destp++ = accum[b] * avg_ratio;
343
for (b = 0; b < bytes; b++)
345
/* We have accumulated a whole pixel per channel where just a
346
slice of it was needed. Subtract now the previous pixel's
348
slice = srcp[- bytes + b] * slicepos * inv_width;
349
*destp++ = (accum[b] - slice) * avg_ratio;
351
/* That slice is the initial value for the next round. */
357
/* Sanity check: srcp should point to the next-to-last position, and
358
slicepos should be zero. */
359
if (! (srcp - src == old_width * bytes && slicepos == 0))
360
g_warning ("Assertion (srcp - src == old_width * bytes && slicepos == 0)"
361
" failed. Please report.");
365
rotate_pointers (guchar **p,
371
for (i = 0; i < n-1; i++)
378
get_scaled_row (gdouble **src,
384
GimpInterpolationType interpolation_type)
386
/* get the necesary lines from the source image, scale them,
387
and put them into src[] */
389
rotate_pointers ((gpointer) src, 4);
396
get_premultiplied_double_row (srcPR, 0, y, srcPR->w, row, src_tmp, 1);
398
if (new_width > srcPR->w)
399
expand_line (src[3], row, srcPR->bytes,
400
srcPR->w, new_width, interpolation_type);
401
else if (srcPR->w > new_width)
402
shrink_line (src[3], row, srcPR->bytes,
403
srcPR->w, new_width, interpolation_type);
404
else /* no scailing needed */
405
memcpy (src[3], row, sizeof (gdouble) * new_width * srcPR->bytes);
409
memcpy (src[3], src[2], sizeof (gdouble) * new_width * srcPR->bytes);
414
scale_region (PixelRegion *srcPR,
416
GimpInterpolationType interpolation,
417
GimpProgressFunc progress_callback,
418
gpointer progress_data)
423
gdouble *row, *accum;
426
gint orig_width, orig_height;
433
if (interpolation == GIMP_INTERPOLATION_NONE)
435
scale_region_no_resample (srcPR, destPR);
439
orig_width = srcPR->w;
440
orig_height = srcPR->h;
445
if (interpolation == GIMP_INTERPOLATION_LANCZOS && orig_height <= height)
447
scale_region_lanczos (srcPR, destPR, progress_callback, progress_data);
452
g_printerr ("scale_region: (%d x %d) -> (%d x %d)\n",
453
orig_width, orig_height, width, height);
456
/* find the ratios of old y to new y */
457
y_ratio = (gdouble) orig_height / (gdouble) height;
459
bytes = destPR->bytes;
461
/* the data pointers... */
462
for (i = 0; i < 4; i++)
463
src[i] = g_new (gdouble, width * bytes);
465
dest = g_new (guchar, width * bytes);
467
src_tmp = g_new (guchar, orig_width * bytes);
469
/* offset the row pointer by 2*bytes so the range of the array
470
is [-2*bytes] to [(orig_width + 2)*bytes] */
471
row = g_new (gdouble, (orig_width + 2 * 2) * bytes);
474
accum = g_new (gdouble, width * bytes);
476
/* Scale the selected region */
478
for (y = 0; y < height; y++)
480
if (progress_callback && (y % 64 == 0))
481
progress_callback (0, height, y, progress_data);
483
if (height < orig_height)
485
const gdouble inv_ratio = 1.0 / y_ratio;
489
if (y == 0) /* load the first row if this is the first time through */
490
get_scaled_row (&src[0], 0, width, srcPR, row,
494
new_y = (int) (y * y_ratio);
495
frac = 1.0 - (y * y_ratio - new_y);
497
for (x = 0; x < width * bytes; x++)
498
accum[x] = src[3][x] * frac;
500
max = (int) ((y + 1) * y_ratio) - new_y - 1;
502
get_scaled_row (&src[0], ++new_y, width, srcPR, row,
508
for (x = 0; x < width * bytes; x++)
509
accum[x] += src[3][x];
511
get_scaled_row (&src[0], ++new_y, width, srcPR, row,
517
frac = (y + 1) * y_ratio - ((int) ((y + 1) * y_ratio));
519
for (x = 0; x < width * bytes; x++)
521
accum[x] += frac * src[3][x];
522
accum[x] *= inv_ratio;
525
else if (height > orig_height)
527
new_y = floor (y * y_ratio - 0.5);
529
while (old_y <= new_y)
531
/* get the necesary lines from the source image, scale them,
532
and put them into src[] */
533
get_scaled_row (&src[0], old_y + 2, width, srcPR, row,
539
switch (interpolation)
541
case GIMP_INTERPOLATION_CUBIC:
543
gdouble p0, p1, p2, p3;
544
gdouble dy = (y * y_ratio - 0.5) - new_y;
546
p0 = cubic_spline_fit (dy, 1, 0, 0, 0);
547
p1 = cubic_spline_fit (dy, 0, 1, 0, 0);
548
p2 = cubic_spline_fit (dy, 0, 0, 1, 0);
549
p3 = cubic_spline_fit (dy, 0, 0, 0, 1);
551
for (x = 0; x < width * bytes; x++)
552
accum[x] = (p0 * src[0][x] + p1 * src[1][x] +
553
p2 * src[2][x] + p3 * src[3][x]);
558
case GIMP_INTERPOLATION_LINEAR:
560
gdouble idy = (y * y_ratio - 0.5) - new_y;
561
gdouble dy = 1.0 - idy;
563
for (x = 0; x < width * bytes; x++)
564
accum[x] = dy * src[1][x] + idy * src[2][x];
569
case GIMP_INTERPOLATION_NONE:
570
case GIMP_INTERPOLATION_LANCZOS:
571
g_assert_not_reached ();
575
else /* height == orig_height */
577
get_scaled_row (&src[0], y, width, srcPR, row,
580
memcpy (accum, src[3], sizeof (gdouble) * width * bytes);
583
if (pixel_region_has_alpha (srcPR))
585
/* unmultiply the alpha */
588
gint alpha = bytes - 1;
592
for (x = 0; x < width; x++)
594
if (p[alpha] > 0.001)
596
inv_alpha = 255.0 / p[alpha];
598
for (b = 0; b < alpha; b++)
600
result = RINT (inv_alpha * p[b]);
604
else if (result > 255)
610
result = RINT (p[alpha]);
617
else /* alpha <= 0 */
619
for (b = 0; b <= alpha; b++)
629
gint w = width * bytes;
631
for (x = 0; x < w; x++)
635
else if (accum[x] > 255.0)
638
dest[x] = RINT (accum[x]);
642
pixel_region_set_row (destPR, 0, y, width, dest);
645
/* free up temporary arrays */
648
for (i = 0; i < 4; i++)
659
subsample_region (PixelRegion *srcPR,
663
const gint width = destPR->w;
664
const gint height = destPR->h;
665
const gint orig_width = srcPR->w / subsample;
666
const gint orig_height = srcPR->h / subsample;
667
const gdouble x_ratio = (gdouble) orig_width / (gdouble) width;
668
const gdouble y_ratio = (gdouble) orig_height / (gdouble) height;
669
const gint bytes = destPR->bytes;
670
const gint destwidth = destPR->rowstride;
674
gint src_row, src_col;
675
gdouble x_sum, y_sum;
676
gdouble x_last, y_last;
677
gdouble *x_frac, y_frac, tot_frac;
684
g_printerr ("subsample_region: (%d x %d) -> (%d x %d)\n",
685
orig_width, orig_height, width, height);
688
/* the data pointers... */
689
src = g_new (guchar, orig_width * bytes);
692
/* allocate an array to help with the calculations */
693
row = g_new (gdouble, width * bytes);
694
x_frac = g_new (gdouble, width + orig_width);
696
/* initialize the pre-calculated pixel fraction array */
698
x_sum = (gdouble) src_col;
701
for (i = 0; i < width + orig_width; i++)
703
if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
706
x_frac[i] = x_sum - x_last;
711
x_frac[i] = src_col - x_last;
717
/* clear the "row" array */
718
memset (row, 0, sizeof (gdouble) * width * bytes);
722
y_sum = (gdouble) src_row;
725
pixel_region_get_row (srcPR,
726
srcPR->x, srcPR->y + src_row * subsample,
727
orig_width * subsample,
730
/* Scale the selected region */
731
for (i = 0; i < height; )
734
x_sum = (gdouble) src_col;
736
/* determine the fraction of the src pixel we are using for y */
737
if (y_sum + y_ratio <= (src_row + 1 + EPSILON))
740
y_frac = y_sum - y_last;
746
y_frac = src_row - y_last;
747
advance_dest = FALSE;
760
tot_frac = x_frac[frac++] * y_frac;
762
for (b = 0; b < bytes; b++)
763
r[b] += s[b] * tot_frac;
765
/* increment the destination */
766
if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
773
/* increment the source */
783
tot_frac = 1.0 / (x_ratio * y_ratio);
785
/* copy "row" to "dest" */
795
*d++ = (guchar) (*r++ * tot_frac + 0.5);
800
/* clear the "row" array */
801
memset (row, 0, sizeof (gdouble) * destwidth);
807
pixel_region_get_row (srcPR,
809
srcPR->y + src_row * subsample,
810
orig_width * subsample,
815
/* free up temporary arrays */
823
static inline gdouble
826
gdouble y = x * G_PI;
828
if (ABS (x) < LANCZOS_MIN)
834
static inline gdouble
835
lanczos_sum (guchar *ptr,
836
const gdouble *kernel, /* 1-D kernel of transform coeffs */
844
for (i = 0; i < LANCZOS_WIDTH2 ; i++)
845
sum += kernel[i] * ptr[ (u + i - LANCZOS_WIDTH) * bytes + byte ];
850
static inline gdouble
851
lanczos_sum_mul (guchar *ptr,
852
const gdouble *kernel, /* 1-D kernel of transform coeffs */
861
for (i = 0; i < LANCZOS_WIDTH2 ; i++ )
862
sum += kernel[i] * ptr[ (u + i - LANCZOS_WIDTH) * bytes + byte ]
863
* ptr[ (u + i - LANCZOS_WIDTH) * bytes + alpha];
869
inv_lin_trans (const gdouble *t,
872
gdouble d = (t[0] * t[4]) - (t[1] * t[3]); /* determinant */
874
if (fabs(d) < EPSILON )
879
it[2] = (( t[1] * t[5]) - (t[2] * t[4])) / d;
882
it[5] = (( t[2] * t[3]) - (t[0] * t[5])) / d;
889
* allocate and fill lookup table of Lanczos windowed sinc function
890
* use gfloat since errors due to granularity of array far exceed data precision
893
create_lanczos_lookup (void)
895
const gdouble dx = LANCZOS_WIDTH / (gdouble) (LANCZOS_SAMPLES - 1);
897
gfloat *lookup = g_new (gfloat, LANCZOS_SAMPLES);
901
for (i = 0; i < LANCZOS_SAMPLES; i++)
903
lookup[i] = ((ABS (x) < LANCZOS_WIDTH) ?
904
(sinc (x) * sinc (x / LANCZOS_WIDTH)) : 0.0);
912
scale_region_lanczos (PixelRegion *srcPR,
914
GimpProgressFunc progress_callback,
915
gpointer progress_data)
918
gfloat *kernel_lookup = NULL; /* Lanczos lookup table */
919
gdouble x_kernel[LANCZOS_WIDTH2], /* 1-D kernels of Lanczos window coeffs */
920
y_kernel[LANCZOS_WIDTH2];
922
gdouble newval; /* new interpolated RGB value */
924
guchar *win_buf = NULL; /* Sliding window buffer */
925
guchar *win_ptr[LANCZOS_WIDTH2]; /* Ponters to sliding window rows */
927
guchar *dst_buf = NULL; /* Pointer to destination image data */
929
gint x, y; /* Position in destination image */
930
gint i, byte; /* loop vars */
933
gdouble trans[6], itrans[6]; /* Scale transformations */
935
const gint dst_width = dstPR->w;
936
const gint dst_height = dstPR->h;
937
const gint bytes = dstPR->bytes;
938
const gint src_width = srcPR->w;
939
const gint src_height = srcPR->h;
941
const gint src_row_span = src_width * bytes;
942
const gint dst_row_span = dst_width * bytes;
943
const gint win_row_span = (src_width + LANCZOS_WIDTH2) * bytes;
945
const gdouble scale_x = dst_width / (gdouble) src_width;
946
const gdouble scale_y = dst_height / (gdouble) src_height;
948
for (i = 0; i < 6; i++)
954
if (! inv_lin_trans (trans, itrans))
956
g_warning ("transformation matrix is not invertible");
960
/* allocate buffer for destination row */
961
dst_buf = g_new0 (guchar, dst_row_span);
963
/* if no scaling needed copy data */
964
if (dst_width == src_width && dst_height == src_height)
966
for (i = 0 ; i < src_height ; i++)
968
pixel_region_get_row (srcPR, 0, i, src_width, dst_buf, 1);
969
pixel_region_set_row (dstPR, 0, i, dst_width, dst_buf);
975
/* allocate and fill kernel_lookup lookup table */
976
kernel_lookup = create_lanczos_lookup ();
978
/* allocate buffer for source rows */
979
win_buf = g_new0 (guchar, win_row_span * LANCZOS_WIDTH2);
981
/* Set the window pointers */
982
for ( i = 0 ; i < LANCZOS_WIDTH2 ; i++ )
983
win_ptr[i] = win_buf + (win_row_span * i) + LANCZOS_WIDTH * bytes;
985
/* fill the data for the first loop */
986
for ( i = 0 ; i <= LANCZOS_WIDTH && i < src_height ; i++)
987
pixel_region_get_row (srcPR, 0, i, src_width, win_ptr[i + LANCZOS_WIDTH], 1);
989
for (row = y = 0; y < dst_height; y++)
991
if (progress_callback && (y % 64 == 0))
992
progress_callback (0, dst_height, y, progress_data);
994
pixel_region_get_row (dstPR, 0, y, dst_width, dst_buf, 1);
995
for (x = 0; x < dst_width; x++)
997
gdouble dsrc_x ,dsrc_y; /* corresponding scaled position in source image */
998
gint int_src_x, int_src_y; /* integer part of coordinates in source image */
999
gint x_shift, y_shift; /* index into Lanczos lookup */
1000
gdouble kx_sum, ky_sum; /* sums of Lanczos kernel coeffs */
1002
/* -0.5 corrects image drift.due to average offset used in lookup */
1003
dsrc_x = x / scale_x - 0.5;
1004
dsrc_y = y / scale_y - 0.5;
1006
/* avoid (int) on negative*/
1008
int_src_x = (gint) (dsrc_x);
1010
int_src_x = (gint) (dsrc_x + 1) - 1;
1013
int_src_y = (gint) (dsrc_y);
1015
int_src_y = (gint) (dsrc_y + 1) - 1;
1017
/* calc lookup offsets for non-interger remainders */
1018
x_shift = (gint) ((dsrc_x - int_src_x) * LANCZOS_SPP + 0.5);
1019
y_shift = (gint) ((dsrc_y - int_src_y) * LANCZOS_SPP + 0.5);
1021
/* Fill x_kernel[] and y_kernel[] with lanczos coeffs
1023
* kernel_lookup = Is a lookup table that contains half of the symetrical windowed-sinc func.
1025
* x_shift, y_shift = shift from kernel center due to fractional part
1028
* The for-loop creates two 1-D kernels for convolution.
1029
* - If the center position +/- LANCZOS_WIDTH is out of
1030
* the source image coordinates set the value to 0.0
1031
* FIXME => partial kernel. Define a more rigourous border mode.
1032
* - If the kernel index is out of range set value to 0.0
1033
* ( caused by offset coeff. obselete??)
1035
kx_sum = ky_sum = 0.0;
1037
for (i = LANCZOS_WIDTH; i >= -LANCZOS_WIDTH; i--)
1039
gint pos = i * LANCZOS_SPP;
1041
if ( int_src_x + i >= 0 && int_src_x + i < src_width)
1042
kx_sum += x_kernel[LANCZOS_WIDTH + i] = kernel_lookup[ABS (x_shift - pos)];
1044
x_kernel[LANCZOS_WIDTH + i] = 0.0;
1046
if ( int_src_y + i >= 0 && int_src_y + i < src_height)
1047
ky_sum += y_kernel[LANCZOS_WIDTH + i] = kernel_lookup[ABS (y_shift - pos)];
1049
y_kernel[LANCZOS_WIDTH + i] = 0.0;
1052
/* normalise the kernel arrays */
1053
for (i = -LANCZOS_WIDTH; i <= LANCZOS_WIDTH; i++)
1055
x_kernel[LANCZOS_WIDTH + i] /= kx_sum;
1056
y_kernel[LANCZOS_WIDTH + i] /= ky_sum;
1061
New determined source row is > than last read row
1062
rotate the pointers and get next source row from region.
1063
If no more source rows are available fill buffer with 0
1064
( Probably not necessary because multipliers should be 0).
1066
for ( ; row < int_src_y ; )
1069
rotate_pointers (win_ptr, LANCZOS_WIDTH2);
1070
if ( row + LANCZOS_WIDTH < src_height)
1071
pixel_region_get_row (srcPR, 0,
1072
row + LANCZOS_WIDTH, src_width,
1073
win_ptr[LANCZOS_WIDTH2 - 1], 1);
1075
memset (win_ptr[LANCZOS_WIDTH2 - 1], 0,
1076
sizeof (guchar) * src_row_span);
1081
for ( ; row > int_src_y ; )
1084
for ( i = 0 ; i < LANCZOS_WIDTH2 - 1 ; i++ )
1085
rotate_pointers (win_ptr, LANCZOS_WIDTH2);
1087
pixel_region_get_row (srcPR, 0,
1091
memset (win_ptr[0], 0,
1092
sizeof (guchar) * src_row_span);
1097
if (pixel_region_has_alpha (srcPR))
1099
const gint alpha = bytes - 1;
1105
for (i = 0; i < LANCZOS_WIDTH2 ; i++ )
1106
aval += y_kernel[i] * lanczos_sum (win_ptr[i], x_kernel,
1107
int_src_x, bytes, alpha);
1112
dst_buf[x * bytes + alpha] = 0;
1114
else if (aval > 255.0)
1116
arecip = 1.0 / aval;
1117
dst_buf[x * bytes + alpha] = 255;
1121
arecip = 1.0 / aval;
1122
dst_buf[x * bytes + alpha] = RINT (aval);
1125
for (byte = 0; byte < alpha; byte++)
1128
for (i = 0; i < LANCZOS_WIDTH2; i++ )
1129
newval += y_kernel[i] * lanczos_sum_mul (win_ptr[i], x_kernel,
1130
int_src_x, bytes, byte, alpha);
1132
dst_buf[x * bytes + byte] = CLAMP (newval, 0, 255);
1137
for (byte = 0; byte < bytes; byte++)
1139
/* Calculate new value */
1141
for (i = 0; i < LANCZOS_WIDTH2; i++ )
1142
newval += y_kernel[i] * lanczos_sum (win_ptr[i], x_kernel,
1143
int_src_x, bytes, byte);
1144
dst_buf[x * bytes + byte] = CLAMP ((gint) newval, 0, 255);
1149
pixel_region_set_row (dstPR, 0, y , dst_width, dst_buf);
1154
g_free (kernel_lookup);