1 // resampler.cpp, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com
2 // See unlicense at the bottom of resampler.h, or at http://unlicense.org/
4 // Feb. 1996: Creation, losely based on a heavily bugfixed version of Schumacher's resampler in Graphics Gems 3.
5 // Oct. 2000: Ported to C++, tweaks.
6 // May 2001: Continous to discrete mapping, box filter tweaks.
7 // March 9, 2002: Kaiser filter grabbed from Jonathan Blow's GD magazine mipmap sample code.
8 // Sept. 8, 2002: Comments cleaned up a bit.
9 // Dec. 31, 2008: v2.2: Bit more cleanup, released as public domain.
10 // June 4, 2012: v2.21: Switched to unlicense.org, integrated GCC fixes supplied by Peter Nagy <petern@crytek.com>, Anteru at anteru.net, and clay@coge.net,
11 // added Codeblocks project (for testing with MinGW and GCC), VS2008 static code analysis pass.
18 // resampler is written using C style casts
19 #pragma GCC diagnostic push
20 #pragma GCC diagnostic ignored "-Wold-style-cast"
22 #include "resampler.h"
24 #define resampler_assert assert
26 static inline int resampler_range_check(int v, int h) { (void)h; resampler_assert((v >= 0) && (v < h)); return v; }
29 #define max(a,b) (((a) > (b)) ? (a) : (b))
33 #define min(a,b) (((a) < (b)) ? (a) : (b))
44 #define RESAMPLER_DEBUG 0
46 #define M_PI 3.14159265358979323846
48 // Float to int cast with truncation.
49 static inline int cast_to_int(Resample_Real i)
54 // (x mod y) with special handling for negative x values.
55 static inline int posmod(int x, int y)
70 // To add your own filter, insert the new function below and update the filter table.
71 // There is no need to make the filter function particularly fast, because it's
72 // only called during initializing to create the X and Y axis contributor tables.
74 #define BOX_FILTER_SUPPORT (0.5f)
75 static Resample_Real box_filter(Resample_Real t) /* pulse/Fourier window */
77 // make_clist() calls the filter function with t inverted (pos = left, neg = right)
78 if ((t >= -0.5f) && (t < 0.5f))
84 #define TENT_FILTER_SUPPORT (1.0f)
85 static Resample_Real tent_filter(Resample_Real t) /* box (*) box, bilinear/triangle */
96 #define BELL_SUPPORT (1.5f)
97 static Resample_Real bell_filter(Resample_Real t) /* box (*) box (*) box */
103 return (.75f - (t * t));
108 return (.5f * (t * t));
114 #define B_SPLINE_SUPPORT (2.0f)
115 static Resample_Real B_spline_filter(Resample_Real t) /* box (*) box (*) box (*) box */
125 return ((.5f * tt * t) - tt + (2.0f / 3.0f));
130 return ((1.0f / 6.0f) * (t * t * t));
136 // Dodgson, N., "Quadratic Interpolation for Image Resampling"
137 #define QUADRATIC_SUPPORT 1.5f
138 static Resample_Real quadratic(Resample_Real t, const Resample_Real R)
142 if (t < QUADRATIC_SUPPORT)
144 Resample_Real tt = t * t;
146 return (-2.0f * R) * tt + .5f * (R + 1.0f);
148 return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f);
154 static Resample_Real quadratic_interp_filter(Resample_Real t)
156 return quadratic(t, 1.0f);
159 static Resample_Real quadratic_approx_filter(Resample_Real t)
161 return quadratic(t, .5f);
164 static Resample_Real quadratic_mix_filter(Resample_Real t)
166 return quadratic(t, .8f);
169 // Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics."
170 // Computer Graphics, Vol. 22, No. 4, pp. 221-228.
172 // (1/3, 1/3) - Defaults recommended by Mitchell and Netravali
173 // (1, 0) - Equivalent to the Cubic B-Spline
174 // (0, 0.5) - Equivalent to the Catmull-Rom Spline
175 // (0, C) - The family of Cardinal Cubic Splines
176 // (B, 0) - Duff's tensioned B-Splines.
177 static Resample_Real mitchell(Resample_Real t, const Resample_Real B, const Resample_Real C)
188 t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
189 + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
190 + (6.0f - 2.0f * B));
196 t = (((-1.0f * B - 6.0f * C) * (t * tt))
197 + ((6.0f * B + 30.0f * C) * tt)
198 + ((-12.0f * B - 48.0f * C) * t)
199 + (8.0f * B + 24.0f * C));
207 #define MITCHELL_SUPPORT (2.0f)
208 static Resample_Real mitchell_filter(Resample_Real t)
210 return mitchell(t, 1.0f / 3.0f, 1.0f / 3.0f);
213 #define CATMULL_ROM_SUPPORT (2.0f)
214 static Resample_Real catmull_rom_filter(Resample_Real t)
216 return mitchell(t, 0.0f, .5f);
219 static double sinc(double x)
223 if ((x < 0.01f) && (x > -0.01f))
224 return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
229 static Resample_Real clean(double t)
231 const Resample_Real EPSILON = .0000125f;
232 if (fabs(t) < EPSILON)
234 return (Resample_Real)t;
237 static double blackman_exact_window(double x)
239 return 0.42659071f + 0.49656062f * cos(M_PI*x) + 0.07684867f * cos(2.0f*M_PI*x);
242 #define BLACKMAN_SUPPORT (3.0f)
243 static Resample_Real blackman_filter(Resample_Real t)
249 //return clean(sinc(t) * blackman_window(t / 3.0f));
250 return clean(sinc(t) * blackman_exact_window(t / 3.0f));
255 #define GAUSSIAN_SUPPORT (1.25f)
256 static Resample_Real gaussian_filter(Resample_Real t) // with blackman window
260 if (t < GAUSSIAN_SUPPORT)
261 return clean(exp(-2.0f * t * t) * sqrt(2.0f / M_PI) * blackman_exact_window(t / GAUSSIAN_SUPPORT));
266 // Windowed sinc -- see "Jimm Blinn's Corner: Dirty Pixels" pg. 26.
267 #define LANCZOS3_SUPPORT (3.0f)
268 static Resample_Real lanczos3_filter(Resample_Real t)
274 return clean(sinc(t) * sinc(t / 3.0f));
279 #define LANCZOS4_SUPPORT (4.0f)
280 static Resample_Real lanczos4_filter(Resample_Real t)
286 return clean(sinc(t) * sinc(t / 4.0f));
291 #define LANCZOS6_SUPPORT (6.0f)
292 static Resample_Real lanczos6_filter(Resample_Real t)
298 return clean(sinc(t) * sinc(t / 6.0f));
303 #define LANCZOS12_SUPPORT (12.0f)
304 static Resample_Real lanczos12_filter(Resample_Real t)
310 return clean(sinc(t) * sinc(t / 12.0f));
315 static double bessel0(double x)
317 const double EPSILON_RATIO = 1E-16;
318 double xh, sum, pow, ds;
326 while (ds > sum * EPSILON_RATIO) // FIXME: Shouldn't this stop after X iterations for max. safety?
329 pow = pow * (xh / k);
337 static const Resample_Real KAISER_ALPHA = 4.0;
338 static double kaiser(double alpha, double half_width, double x)
340 const double ratio = (x / half_width);
341 return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
344 #define KAISER_SUPPORT 3
345 static Resample_Real kaiser_filter(Resample_Real t)
350 if (t < KAISER_SUPPORT)
353 const Resample_Real att = 40.0f;
354 const Resample_Real alpha = (Resample_Real)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96));
355 //const Resample_Real alpha = KAISER_ALPHA;
356 return (Resample_Real)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t));
362 // filters[] is a list of all the available filter functions.
365 Resampler::Filter name;
366 Resample_Real (*func)(Resample_Real t);
367 Resample_Real support;
370 { Resampler::BOX, box_filter, BOX_FILTER_SUPPORT },
371 { Resampler::TENT, tent_filter, TENT_FILTER_SUPPORT },
372 { Resampler::BELL, bell_filter, BELL_SUPPORT },
373 { Resampler::B_SPLINE, B_spline_filter, B_SPLINE_SUPPORT },
374 { Resampler::MITCHELL, mitchell_filter, MITCHELL_SUPPORT },
375 { Resampler::LANCZOS3, lanczos3_filter, LANCZOS3_SUPPORT },
376 { Resampler::BLACKMAN, blackman_filter, BLACKMAN_SUPPORT },
377 { Resampler::LANCZOS4, lanczos4_filter, LANCZOS4_SUPPORT },
378 { Resampler::LANCZOS6, lanczos6_filter, LANCZOS6_SUPPORT },
379 { Resampler::LANCZOS12, lanczos12_filter, LANCZOS12_SUPPORT },
380 { Resampler::KAISER, kaiser_filter, KAISER_SUPPORT },
381 { Resampler::GAUSSIAN, gaussian_filter, GAUSSIAN_SUPPORT },
382 { Resampler::CATMULLROM, catmull_rom_filter, CATMULL_ROM_SUPPORT },
383 { Resampler::QUADRATIC_INTERPOLATION, quadratic_interp_filter, QUADRATIC_SUPPORT },
384 { Resampler::QUADRATIC_APPROXIMATION, quadratic_approx_filter, QUADRATIC_SUPPORT },
385 { Resampler::QUADRATIC_MIX, quadratic_mix_filter, QUADRATIC_SUPPORT },
388 static const int NUM_FILTERS = sizeof(g_filters) / sizeof(g_filters[0]);
390 /* Ensure that the contributing source sample is
391 * within bounds. If not, reflect, clamp, or wrap.
393 int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_op)
399 if (boundary_op == BOUNDARY_REFLECT)
406 else if (boundary_op == BOUNDARY_WRAP)
407 n = posmod(j, src_x);
413 if (boundary_op == BOUNDARY_REFLECT)
415 n = (src_x - j) + (src_x - 1);
420 else if (boundary_op == BOUNDARY_WRAP)
421 n = posmod(j, src_x);
431 // The make_clist() method generates, for all destination samples,
432 // the list of all source samples with non-zero weighted contributions.
433 Resampler::Contrib_List* Resampler::make_clist(
434 int src_x, int dst_x, Boundary_Op boundary_op,
435 Resample_Real (*Pfilter)(Resample_Real),
436 Resample_Real filter_support,
437 Resample_Real filter_scale,
438 Resample_Real src_ofs)
442 // The center of the range in DISCRETE coordinates (pixel center = 0.0f).
443 Resample_Real center;
447 int i, j, k, n, left, right;
448 Resample_Real total_weight;
449 Resample_Real xscale, center, half_width, weight;
450 Contrib_List* Pcontrib;
452 Contrib* Pcpool_next;
453 Contrib_Bounds* Pcontrib_bounds;
455 if ((Pcontrib = (Contrib_List*)calloc(dst_x, sizeof(Contrib_List))) == NULL)
458 Pcontrib_bounds = (Contrib_Bounds*)calloc(dst_x, sizeof(Contrib_Bounds));
459 if (!Pcontrib_bounds)
465 const Resample_Real oo_filter_scale = 1.0f / filter_scale;
467 const Resample_Real NUDGE = 0.5f;
468 xscale = dst_x / (Resample_Real)src_x;
472 int total; (void)total;
474 /* Handle case when there are fewer destination
475 * samples than source samples (downsampling/minification).
478 // stretched half width of filter
479 half_width = (filter_support / xscale) * filter_scale;
481 // Find the range of source sample(s) that will contribute to each destination sample.
483 for (i = 0, n = 0; i < dst_x; i++)
485 // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
486 center = ((Resample_Real)i + NUDGE) / xscale;
490 left = cast_to_int((Resample_Real)floor(center - half_width));
491 right = cast_to_int((Resample_Real)ceil(center + half_width));
493 Pcontrib_bounds[i].center = center;
494 Pcontrib_bounds[i].left = left;
495 Pcontrib_bounds[i].right = right;
497 n += (right - left + 1);
500 /* Allocate memory for contributors. */
502 if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL))
505 free(Pcontrib_bounds);
510 Pcpool_next = Pcpool;
512 /* Create the list of source samples which
513 * contribute to each destination sample.
516 for (i = 0; i < dst_x; i++)
519 Resample_Real max_w = -1e+20f;
521 center = Pcontrib_bounds[i].center;
522 left = Pcontrib_bounds[i].left;
523 right = Pcontrib_bounds[i].right;
526 Pcontrib[i].p = Pcpool_next;
527 Pcpool_next += (right - left + 1);
528 resampler_assert ((Pcpool_next - Pcpool) <= total);
532 for (j = left; j <= right; j++)
533 total_weight += (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale);
534 const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
542 for (j = left; j <= right; j++)
544 weight = (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale) * norm;
548 n = reflect(j, src_x, boundary_op);
551 printf("%i(%f), ", n, weight);
554 /* Increment the number of source
555 * samples which contribute to the
556 * current destination sample.
561 Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */
562 Pcontrib[i].p[k].weight = weight; /* store src sample weight */
564 total_weight += weight; /* total weight of all contributors */
577 //resampler_assert(Pcontrib[i].n);
578 //resampler_assert(max_k != -1);
579 if ((max_k == -1) || (Pcontrib[i].n == 0))
583 free(Pcontrib_bounds);
587 if (total_weight != 1.0f)
588 Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
593 /* Handle case when there are more
594 * destination samples than source
595 * samples (upsampling).
598 half_width = filter_support * filter_scale;
600 // Find the source sample(s) that contribute to each destination sample.
602 for (i = 0, n = 0; i < dst_x; i++)
604 // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
605 center = ((Resample_Real)i + NUDGE) / xscale;
609 left = cast_to_int((Resample_Real)floor(center - half_width));
610 right = cast_to_int((Resample_Real)ceil(center + half_width));
612 Pcontrib_bounds[i].center = center;
613 Pcontrib_bounds[i].left = left;
614 Pcontrib_bounds[i].right = right;
616 n += (right - left + 1);
619 /* Allocate memory for contributors. */
622 if ((total == 0) || ((Pcpool = (Contrib*)calloc(total, sizeof(Contrib))) == NULL))
625 free(Pcontrib_bounds);
629 Pcpool_next = Pcpool;
631 /* Create the list of source samples which
632 * contribute to each destination sample.
635 for (i = 0; i < dst_x; i++)
638 Resample_Real max_w = -1e+20f;
640 center = Pcontrib_bounds[i].center;
641 left = Pcontrib_bounds[i].left;
642 right = Pcontrib_bounds[i].right;
645 Pcontrib[i].p = Pcpool_next;
646 Pcpool_next += (right - left + 1);
647 resampler_assert((Pcpool_next - Pcpool) <= total);
650 for (j = left; j <= right; j++)
651 total_weight += (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale);
653 const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
661 for (j = left; j <= right; j++)
663 weight = (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale) * norm;
667 n = reflect(j, src_x, boundary_op);
670 printf("%i(%f), ", n, weight);
673 /* Increment the number of source
674 * samples which contribute to the
675 * current destination sample.
680 Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */
681 Pcontrib[i].p[k].weight = weight; /* store src sample weight */
683 total_weight += weight; /* total weight of all contributors */
696 //resampler_assert(Pcontrib[i].n);
697 //resampler_assert(max_k != -1);
699 if ((max_k == -1) || (Pcontrib[i].n == 0))
703 free(Pcontrib_bounds);
707 if (total_weight != 1.0f)
708 Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
716 free(Pcontrib_bounds);
721 void Resampler::resample_x(Sample* Pdst, const Sample* Psrc)
723 resampler_assert(Pdst);
724 resampler_assert(Psrc);
728 Contrib_List *Pclist = m_Pclist_x;
731 for (i = m_resample_dst_x; i > 0; i--, Pclist++)
733 #if RESAMPLER_DEBUG_OPS
734 total_ops += Pclist->n;
737 for (j = Pclist->n, p = Pclist->p, total = 0; j > 0; j--, p++)
738 total += Psrc[p->pixel] * p->weight;
744 void Resampler::scale_y_mov(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x)
748 #if RESAMPLER_DEBUG_OPS
752 // Not += because temp buf wasn't cleared.
753 for (i = dst_x; i > 0; i--)
754 *Ptmp++ = *Psrc++ * weight;
757 void Resampler::scale_y_add(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x)
759 #if RESAMPLER_DEBUG_OPS
763 for (int i = dst_x; i > 0; i--)
764 (*Ptmp++) += *Psrc++ * weight;
767 void Resampler::clamp(Sample* Pdst, int n)
771 *Pdst = clamp_sample(*Pdst);
777 void Resampler::resample_y(Sample* Pdst)
781 Contrib_List* Pclist = &m_Pclist_y[m_cur_dst_y];
783 Sample* Ptmp = m_delay_x_resample ? m_Ptmp_buf : Pdst;
784 resampler_assert(Ptmp);
786 /* Process each contributor. */
788 for (i = 0; i < Pclist->n; i++)
790 /* locate the contributor's location in the scan
791 * buffer -- the contributor must always be found!
794 for (j = 0; j < MAX_SCAN_BUF_SIZE; j++)
795 if (m_Pscan_buf->scan_buf_y[j] == Pclist->p[i].pixel)
798 resampler_assert(j < MAX_SCAN_BUF_SIZE);
800 Psrc = m_Pscan_buf->scan_buf_l[j];
803 scale_y_mov(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
805 scale_y_add(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
807 /* If this source line doesn't contribute to any
808 * more destination lines then mark the scanline buffer slot
809 * which holds this source line as free.
810 * (The max. number of slots used depends on the Y
811 * axis sampling factor and the scaled filter width.)
814 if (--m_Psrc_y_count[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] == 0)
816 m_Psrc_y_flag[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] = FALSE;
817 m_Pscan_buf->scan_buf_y[j] = -1;
821 /* Now generate the destination line */
823 if (m_delay_x_resample) // Was X resampling delayed until after Y resampling?
825 resampler_assert(Pdst != Ptmp);
826 resample_x(Pdst, Ptmp);
830 resampler_assert(Pdst == Ptmp);
834 clamp(Pdst, m_resample_dst_x);
837 bool Resampler::put_line(const Sample* Psrc)
841 if (m_cur_src_y >= m_resample_src_y)
844 /* Does this source line contribute
845 * to any destination line? if not,
849 if (!m_Psrc_y_count[resampler_range_check(m_cur_src_y, m_resample_src_y)])
855 /* Find an empty slot in the scanline buffer. (FIXME: Perf. is terrible here with extreme scaling ratios.) */
857 for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
858 if (m_Pscan_buf->scan_buf_y[i] == -1)
861 /* If the buffer is full, exit with an error. */
863 if (i == MAX_SCAN_BUF_SIZE)
865 m_status = STATUS_SCAN_BUFFER_FULL;
869 m_Psrc_y_flag[resampler_range_check(m_cur_src_y, m_resample_src_y)] = TRUE;
870 m_Pscan_buf->scan_buf_y[i] = m_cur_src_y;
872 /* Does this slot have any memory allocated to it? */
874 if (!m_Pscan_buf->scan_buf_l[i])
876 if ((m_Pscan_buf->scan_buf_l[i] = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
878 m_status = STATUS_OUT_OF_MEMORY;
883 // Resampling on the X axis first?
884 if (m_delay_x_resample)
886 resampler_assert(m_intermediate_x == m_resample_src_x);
888 // Y-X resampling order
889 memcpy(m_Pscan_buf->scan_buf_l[i], Psrc, m_intermediate_x * sizeof(Sample));
893 resampler_assert(m_intermediate_x == m_resample_dst_x);
895 // X-Y resampling order
896 resample_x(m_Pscan_buf->scan_buf_l[i], Psrc);
904 const Resampler::Sample* Resampler::get_line()
908 /* If all the destination lines have been
909 * generated, then always return NULL.
912 if (m_cur_dst_y == m_resample_dst_y)
915 /* Check to see if all the required
916 * contributors are present, if not,
920 for (i = 0; i < m_Pclist_y[m_cur_dst_y].n; i++)
921 if (!m_Psrc_y_flag[resampler_range_check(m_Pclist_y[m_cur_dst_y].p[i].pixel, m_resample_src_y)])
924 resample_y(m_Pdst_buf);
931 Resampler::~Resampler()
935 #if RESAMPLER_DEBUG_OPS
936 printf("actual ops: %i\n", total_ops);
948 /* Don't deallocate a contibutor list
949 * if the user passed us one of their own.
952 if ((m_Pclist_x) && (!m_clist_x_forced))
959 if ((m_Pclist_y) && (!m_clist_y_forced))
966 free(m_Psrc_y_count);
967 m_Psrc_y_count = NULL;
970 m_Psrc_y_flag = NULL;
974 for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
975 free(m_Pscan_buf->scan_buf_l[i]);
982 void Resampler::restart()
984 if (STATUS_OKAY != m_status)
987 m_cur_src_y = m_cur_dst_y = 0;
990 for (i = 0; i < m_resample_src_y; i++)
992 m_Psrc_y_count[i] = 0;
993 m_Psrc_y_flag[i] = FALSE;
996 for (i = 0; i < m_resample_dst_y; i++)
998 for (j = 0; j < m_Pclist_y[i].n; j++)
999 m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
1002 for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
1004 m_Pscan_buf->scan_buf_y[i] = -1;
1006 free(m_Pscan_buf->scan_buf_l[i]);
1007 m_Pscan_buf->scan_buf_l[i] = NULL;
1011 Resampler::Resampler(int src_x, int src_y,
1012 int dst_x, int dst_y,
1013 Boundary_Op boundary_op,
1014 Resample_Real sample_low, Resample_Real sample_high,
1015 Resampler::Filter filter,
1016 Contrib_List* Pclist_x,
1017 Contrib_List* Pclist_y,
1018 Resample_Real filter_x_scale,
1019 Resample_Real filter_y_scale,
1020 Resample_Real src_x_ofs,
1021 Resample_Real src_y_ofs)
1024 Resample_Real support, (*func)(Resample_Real);
1026 resampler_assert(src_x > 0);
1027 resampler_assert(src_y > 0);
1028 resampler_assert(dst_x > 0);
1029 resampler_assert(dst_y > 0);
1031 #if RESAMPLER_DEBUG_OPS
1038 m_delay_x_resample = false;
1039 m_intermediate_x = 0;
1042 m_clist_x_forced = false;
1044 m_clist_y_forced = false;
1046 m_Psrc_y_count = NULL;
1047 m_Psrc_y_flag = NULL;
1049 m_status = STATUS_OKAY;
1051 m_resample_src_x = src_x;
1052 m_resample_src_y = src_y;
1053 m_resample_dst_x = dst_x;
1054 m_resample_dst_y = dst_y;
1056 m_boundary_op = boundary_op;
1058 if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL)
1060 m_status = STATUS_OUT_OF_MEMORY;
1064 // Find the specified filter.
1065 for (i = 0; i < NUM_FILTERS; i++)
1066 if ( filter == g_filters[i].name )
1069 if (i == NUM_FILTERS)
1071 m_status = STATUS_BAD_FILTER_TYPE;
1075 func = g_filters[i].func;
1076 support = g_filters[i].support;
1078 /* Create contributor lists, unless the user supplied custom lists. */
1082 m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs);
1085 m_status = STATUS_OUT_OF_MEMORY;
1091 m_Pclist_x = Pclist_x;
1092 m_clist_x_forced = true;
1097 m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs);
1100 m_status = STATUS_OUT_OF_MEMORY;
1106 m_Pclist_y = Pclist_y;
1107 m_clist_y_forced = true;
1110 if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL)
1112 m_status = STATUS_OUT_OF_MEMORY;
1116 if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL)
1118 m_status = STATUS_OUT_OF_MEMORY;
1122 /* Count how many times each source line
1123 * contributes to a destination line.
1126 for (i = 0; i < m_resample_dst_y; i++)
1127 for (j = 0; j < m_Pclist_y[i].n; j++)
1128 m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
1130 if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL)
1132 m_status = STATUS_OUT_OF_MEMORY;
1136 for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
1138 m_Pscan_buf->scan_buf_y[i] = -1;
1139 m_Pscan_buf->scan_buf_l[i] = NULL;
1142 m_cur_src_y = m_cur_dst_y = 0;
1144 // Determine which axis to resample first by comparing the number of multiplies required
1145 // for each possibility.
1146 int x_ops = count_ops(m_Pclist_x, m_resample_dst_x);
1147 int y_ops = count_ops(m_Pclist_y, m_resample_dst_y);
1149 // Hack 10/2000: Weight Y axis ops a little more than X axis ops.
1150 // (Y axis ops use more cache resources.)
1151 int xy_ops = x_ops * m_resample_src_y +
1152 (4 * y_ops * m_resample_dst_x)/3;
1154 int yx_ops = (4 * y_ops * m_resample_src_x)/3 +
1155 x_ops * m_resample_dst_y;
1157 #if RESAMPLER_DEBUG_OPS
1158 printf("src: %i %i\n", m_resample_src_x, m_resample_src_y);
1159 printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y);
1160 printf("x_ops: %i\n", x_ops);
1161 printf("y_ops: %i\n", y_ops);
1162 printf("xy_ops: %i\n", xy_ops);
1163 printf("yx_ops: %i\n", yx_ops);
1166 // Now check which resample order is better. In case of a tie, choose the order
1167 // which buffers the least amount of data.
1168 if ((xy_ops > yx_ops) ||
1169 ((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x))
1172 m_delay_x_resample = true;
1173 m_intermediate_x = m_resample_src_x;
1177 m_delay_x_resample = false;
1178 m_intermediate_x = m_resample_dst_x;
1180 #if RESAMPLER_DEBUG_OPS
1181 printf("delaying: %i\n", m_delay_x_resample);
1185 if (m_delay_x_resample)
1187 if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
1189 m_status = STATUS_OUT_OF_MEMORY;
1195 void Resampler::get_clists(Contrib_List** ptr_clist_x, Contrib_List** ptr_clist_y)
1198 *ptr_clist_x = m_Pclist_x;
1201 *ptr_clist_y = m_Pclist_y;
1204 #pragma GCC diagnostic pop