diff --git a/bin/resampler.exe b/bin/resampler.exe index fc16246..f83595d 100644 Binary files a/bin/resampler.exe and b/bin/resampler.exe differ diff --git a/resampler.cpp b/resampler.cpp index 1bb23fb..d3b94b4 100644 --- a/resampler.cpp +++ b/resampler.cpp @@ -1,10 +1,14 @@ -// resampler.cpp, Separable filtering image rescaler v2.2, public domain, Rich Geldreich - richgel99@gmail.com +// resampler.cpp, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com +// See unlicense at the bottom of resampler.h, or at http://unlicense.org/ +// // Feb. 1996: Creation, losely based on a heavily bugfixed version of Schumacher's resampler in Graphics Gems 3. // Oct. 2000: Ported to C++, tweaks. // May 2001: Continous to discrete mapping, box filter tweaks. // March 9, 2002: Kaiser filter grabbed from Jonathan Blow's GD magazine mipmap sample code. // Sept. 8, 2002: Comments cleaned up a bit. -// Dec. 31, 2008: Bit more cleanup, released as public domain. +// Dec. 31, 2008: v2.2: Bit more cleanup, released as public domain. +// June 4, 2012: v2.21: Switched to unlicense.org, integrated GCC fixes supplied by Peter Nagy , Anteru at anteru.net, and clay@coge.net, +// added Codeblocks project (for testing with MinGW and GCC), VS2008 static code analysis pass. #include #include #include @@ -14,7 +18,7 @@ #define resampler_assert assert -static inline int resampler_range_check(int v, int h) { resampler_assert((v >= 0) && (v < h)); return v; } +static inline int resampler_range_check(int v, int h) { (void)h; resampler_assert((v >= 0) && (v < h)); return v; } #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) @@ -58,15 +62,15 @@ static inline int posmod(int x, int y) } } -// To add your own filter, insert the new function below and update the filter table. -// There is no need to make the filter function particularly fast, because it's +// To add your own filter, insert the new function below and update the filter table. +// There is no need to make the filter function particularly fast, because it's // only called during initializing to create the X and Y axis contributor tables. #define BOX_FILTER_SUPPORT (0.5f) static Resample_Real box_filter(Resample_Real t) /* pulse/Fourier window */ { // make_clist() calls the filter function with t inverted (pos = left, neg = right) - if ((t >= -0.5f) && (t < 0.5f)) + if ((t >= -0.5f) && (t < 0.5f)) return 1.0f; else return 0.0f; @@ -124,18 +128,18 @@ static Resample_Real B_spline_filter(Resample_Real t) /* box (*) box (*) box (* return (0.0f); } -// Dodgson, N., "Quadratic Interpolation for Image Resampling" +// Dodgson, N., "Quadratic Interpolation for Image Resampling" #define QUADRATIC_SUPPORT 1.5f static Resample_Real quadratic(Resample_Real t, const Resample_Real R) { if (t < 0.0f) - t = -t; + t = -t; if (t < QUADRATIC_SUPPORT) { Resample_Real tt = t * t; if (t <= .5f) return (-2.0f * R) * tt + .5f * (R + 1.0f); - else + else return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f); } else @@ -157,10 +161,10 @@ static Resample_Real quadratic_mix_filter(Resample_Real t) return quadratic(t, .8f); } -// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics." +// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics." // Computer Graphics, Vol. 22, No. 4, pp. 221-228. // (B, C) -// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali +// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali // (1, 0) - Equivalent to the Cubic B-Spline // (0, 0.5) - Equivalent to the Catmull-Rom Spline // (0, C) - The family of Cardinal Cubic Splines @@ -226,7 +230,7 @@ static Resample_Real clean(double t) } //static double blackman_window(double x) -//{ +//{ // return .42f + .50f * cos(M_PI*x) + .08f * cos(2.0f*M_PI*x); //} @@ -308,7 +312,7 @@ static Resample_Real lanczos12_filter(Resample_Real t) return (0.0f); } -static double bessel0(double x) +static double bessel0(double x) { const double EPSILON_RATIO = 1E-16; double xh, sum, pow, ds; @@ -331,7 +335,7 @@ static double bessel0(double x) } static const Resample_Real KAISER_ALPHA = 4.0; -static double kaiser(double alpha, double half_width, double x) +static double kaiser(double alpha, double half_width, double x) { const double ratio = (x / half_width); return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha); @@ -346,14 +350,14 @@ static Resample_Real kaiser_filter(Resample_Real t) if (t < KAISER_SUPPORT) { // db atten - const Resample_Real att = 40.0f; + const Resample_Real att = 40.0f; const Resample_Real alpha = (Resample_Real)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96)); //const Resample_Real alpha = KAISER_ALPHA; return (Resample_Real)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t)); } return 0.0f; -} +} // filters[] is a list of all the available filter functions. static struct @@ -424,7 +428,7 @@ int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_ return n; } -// The make_clist() method generates, for all destination samples, +// The make_clist() method generates, for all destination samples, // the list of all source samples with non-zero weighted contributions. Resampler::Contrib_List* Resampler::make_clist( int src_x, int dst_x, Boundary_Op boundary_op, @@ -465,7 +469,7 @@ Resampler::Contrib_List* Resampler::make_clist( if (xscale < 1.0f) { - int total; + int total; (void)total; /* Handle case when there are fewer destination * samples than source samples (downsampling/minification). @@ -554,7 +558,7 @@ Resampler::Contrib_List* Resampler::make_clist( k = Pcontrib[i].n++; - Pcontrib[i].p[k].pixel = unsigned short(n); /* store src sample number */ + Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */ Pcontrib[i].p[k].weight = weight; /* store src sample weight */ total_weight += weight; /* total weight of all contributors */ @@ -572,13 +576,13 @@ Resampler::Contrib_List* Resampler::make_clist( //resampler_assert(Pcontrib[i].n); //resampler_assert(max_k != -1); - if ((max_k == -1) || (Pcontrib[i].n == 0)) + if ((max_k == -1) || (Pcontrib[i].n == 0)) { free(Pcpool); free(Pcontrib); free(Pcontrib_bounds); return NULL; - } + } if (total_weight != 1.0f) Pcontrib[i].p[max_k].weight += 1.0f - total_weight; @@ -662,7 +666,7 @@ Resampler::Contrib_List* Resampler::make_clist( n = reflect(j, src_x, boundary_op); -#if RESAMPLER_DEBUG +#if RESAMPLER_DEBUG printf("%i(%f), ", n, weight); #endif @@ -673,7 +677,7 @@ Resampler::Contrib_List* Resampler::make_clist( k = Pcontrib[i].n++; - Pcontrib[i].p[k].pixel = unsigned short(n); /* store src sample number */ + Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */ Pcontrib[i].p[k].weight = weight; /* store src sample weight */ total_weight += weight; /* total weight of all contributors */ @@ -692,13 +696,13 @@ Resampler::Contrib_List* Resampler::make_clist( //resampler_assert(Pcontrib[i].n); //resampler_assert(max_k != -1); - if ((max_k == -1) || (Pcontrib[i].n == 0)) + if ((max_k == -1) || (Pcontrib[i].n == 0)) { free(Pcpool); free(Pcontrib); free(Pcontrib_bounds); return NULL; - } + } if (total_weight != 1.0f) Pcontrib[i].p[max_k].weight += 1.0f - total_weight; @@ -764,7 +768,8 @@ void Resampler::clamp(Sample* Pdst, int n) { while (n > 0) { - *Pdst++ = clamp_sample(*Pdst); + *Pdst = clamp_sample(*Pdst); + ++Pdst; n--; } } @@ -931,12 +936,12 @@ Resampler::~Resampler() printf("actual ops: %i\n", total_ops); #endif - free(m_Pdst_buf); + free(m_Pdst_buf); m_Pdst_buf = NULL; if (m_Ptmp_buf) { - free(m_Ptmp_buf); + free(m_Ptmp_buf); m_Ptmp_buf = NULL; } @@ -979,7 +984,7 @@ void Resampler::restart() if (STATUS_OKAY != m_status) return; - m_cur_src_y = m_cur_dst_y = 0; + m_cur_src_y = m_cur_dst_y = 0; int i, j; for (i = 0; i < m_resample_src_y; i++) @@ -1010,7 +1015,7 @@ Resampler::Resampler(int src_x, int src_y, const char* Pfilter_name, Contrib_List* Pclist_x, Contrib_List* Pclist_y, - Resample_Real filter_x_scale, + Resample_Real filter_x_scale, Resample_Real filter_y_scale, Resample_Real src_x_ofs, Resample_Real src_y_ofs) diff --git a/resampler.h b/resampler.h index 018c5ed..76eeb23 100644 --- a/resampler.h +++ b/resampler.h @@ -1,4 +1,5 @@ -// resampler.h, Separable filtering image rescaler v2.2, public domain, Rich Geldreich - richgel99@gmail.com +// resampler.h, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com +// See unlicense.org text at the bottom of this file. #ifndef __RESAMPLER_H__ #define __RESAMPLER_H__ @@ -167,4 +168,29 @@ class Resampler } }; -#endif __RESAMPLER_H__ +#endif // __RESAMPLER_H__ + +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to diff --git a/stb_image.c b/stb_image.c index 0d2c666..d48e12e 100644 --- a/stb_image.c +++ b/stb_image.c @@ -14,10 +14,10 @@ writes BMP,TGA (define STBI_NO_WRITE to remove code) decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) - + TODO: stbi_info_* - + history: 1.18 fix a threading bug (local mutable static) 1.17 support interlaced PNG @@ -81,7 +81,7 @@ // Basic usage (see HDR discussion below): // int x,y,n; // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... +// // ... process data if not NULL ... // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // stbi_image_free(data) @@ -142,7 +142,7 @@ // (linear) floats to preserve the full dynamic range: // // float *data = stbi_loadf(filename, &x, &y, &n, 0); -// +// // If you load LDR images through this interface, those images will // be promoted to floating point values, run through the inverse of // constants corresponding to the above: @@ -217,7 +217,7 @@ extern void stbi_ldr_to_hdr_scale(float scale); // get a VERY brief reason for failure // NOT THREADSAFE -extern char *stbi_failure_reason (void); +extern char *stbi_failure_reason (void); // free the loaded image -- this is just free() extern void stbi_image_free (void *retval_from_stbi_load); @@ -370,9 +370,10 @@ extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); #ifndef _MSC_VER #ifdef __cplusplus - #define __forceinline inline + #define __forceinline inline #else - #define __forceinline + #undef __forceinline + #define __forceinline #endif #endif @@ -672,7 +673,7 @@ __forceinline static int at_eof(stbi *s) if (s->img_file) return feof(s->img_file); #endif - return s->img_buffer >= s->img_buffer_end; + return s->img_buffer >= s->img_buffer_end; } __forceinline static uint8 get8u(stbi *s) @@ -1713,7 +1714,7 @@ typedef struct resample_row_func resample; uint8 *line0,*line1; int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion + int w_lores; // horizontal pixels pre-expansion int ystep; // how far through vertical expansion we are int ypos; // which pre-expansion row we're on } stbi_resample; @@ -1891,7 +1892,7 @@ typedef struct int maxcode[17]; uint16 firstsymbol[16]; uint8 size[288]; - uint16 value[288]; + uint16 value[288]; } zhuffman; __forceinline static int bitreverse16(int n) @@ -1919,7 +1920,7 @@ static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); memset(z->fast, 255, sizeof(z->fast)); - for (i=0; i < num; ++i) + for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; for (i=1; i < 16; ++i) @@ -1998,7 +1999,7 @@ __forceinline static unsigned int zreceive(zbuf *z, int n) k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; - return k; + return k; } __forceinline static int zhuffman_decode(zbuf *a, zhuffman *z) @@ -2050,7 +2051,7 @@ static int length_base[31] = { 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static int length_extra[31]= +static int length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, @@ -3017,7 +3018,7 @@ static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) out[z++] = shiftsigned(v & mg, gshift, gcount); out[z++] = shiftsigned(v & mb, bshift, bcount); a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = a; + if (target == 4) out[z++] = a; } } skip(s, pad); @@ -3413,7 +3414,7 @@ static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) // Read the rows and columns of the image. h = get32(s); w = get32(s); - + // Make sure the depth is 8 bits. if (get16(s) != 8) return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); @@ -3455,7 +3456,7 @@ static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) // Initialize the data to zero. //memset( out, 0, pixelCount * 4 ); - + // Finally, the image data. if (compression) { // RLE as used by .PSD and .TIFF @@ -3473,7 +3474,7 @@ static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) // Read the RLE data by channel. for (channel = 0; channel < 4; channel++) { uint8 *p; - + p = out+channel; if (channel >= channelCount) { // Fill this channel with default data. @@ -3511,15 +3512,15 @@ static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) } } } - + } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) // where each channel consists of an 8-bit value for each pixel in the image. - + // Read the data by channel. for (channel = 0; channel < 4; channel++) { uint8 *p; - + p = out + channel; if (channel > channelCount) { // Fill this channel with default data. @@ -3541,7 +3542,7 @@ static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) if (comp) *comp = channelCount; *y = h; *x = w; - + return out; } @@ -3672,7 +3673,7 @@ static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) // Check identifier if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) return epf("not HDR", "Corrupt HDR image"); - + // Parse header while(1) { token = hdr_gettoken(s,buffer); @@ -3736,7 +3737,7 @@ static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) len |= get8(s); if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); - + for (k = 0; k < 4; ++k) { i = 0; while (i < width) { @@ -3817,7 +3818,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, uint32 zero = 0; int i,j,k, j_end; - if (vdir < 0) + if (vdir < 0) j_end = -1, j = y-1; else j_end = y, j = 0; diff --git a/test.cpp b/test.cpp index 22dac77..aeadcf6 100644 --- a/test.cpp +++ b/test.cpp @@ -1,4 +1,5 @@ -// resampler test, public domain, Rich Geldreich - richgel99@gmail.com +// resampler test, Rich Geldreich - richgel99@gmail.com +// See unlicense.org text at the bottom of resampler.h // Example usage: resampler.exe input.tga output.tga width height #include #include @@ -80,6 +81,8 @@ int main(int arg_c, char** arg_v) Resampler* resamplers[max_components]; std::vector samples[max_components]; + // Now create a Resampler instance for each component to process. The first instance will create new contributor tables, which are shared by the resamplers + // used for the other components (a memory and slight cache efficiency optimization). resamplers[0] = new Resampler(src_width, src_height, dst_width, dst_height, Resampler::BOUNDARY_CLAMP, 0.0f, 1.0f, pFilter, NULL, NULL, filter_scale, filter_scale); samples[0].resize(src_width); for (int i = 1; i < n; i++) @@ -122,16 +125,16 @@ int main(int arg_c, char** arg_v) for ( ; ; ) { - int c; - for (c = 0; c < n; c++) + int comp_index; + for (comp_index = 0; comp_index < n; comp_index++) { - const float* pOutput_samples = resamplers[c]->get_line(); + const float* pOutput_samples = resamplers[comp_index]->get_line(); if (!pOutput_samples) break; - const bool alpha_channel = (c == 3) || ((n == 2) && (c == 1)); + const bool alpha_channel = (comp_index == 3) || ((n == 2) && (comp_index == 1)); assert(dst_y < dst_height); - unsigned char* pDst = &dst_image[dst_y * dst_pitch + c]; + unsigned char* pDst = &dst_image[dst_y * dst_pitch + comp_index]; for (int x = 0; x < dst_width; x++) { @@ -151,7 +154,7 @@ int main(int arg_c, char** arg_v) pDst += n; } } - if (c < n) + if (comp_index < n) break; dst_y++; @@ -167,6 +170,10 @@ int main(int arg_c, char** arg_v) } stbi_image_free(pSrc_image); + + // Delete the resamplers. + for (int i = 0; i < n; i++) + delete resamplers[i]; return EXIT_SUCCESS; }