diff --git a/stb_image_resize.h b/stb_image_resize.h index 7ea2a47..9c21dc1 100644 --- a/stb_image_resize.h +++ b/stb_image_resize.h @@ -1,161 +1,171 @@ -/* stb_image_resize - v0.90 - public domain image resizing - by Jorge L Rodriguez (@VinoBS) - 2014 - http://github.com/nothings/stb +/* stb_image_resize - v0.90 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb - Written with emphasis on usage and speed. Only scaling is - currently supported, no rotations or translations. + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it will not be the fastest implementation around.) + Only scaling is supported, no rotations or translations. - DOCUMENTATION + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. - COMPILING & LINKING - In one C/C++ file that #includes this file, do this: - #define STB_IMAGE_RESIZE_IMPLEMENTATION - before the #include. That will create the implementation in that file. + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_ chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + WRAP/REFLECT/ZERO - VERY QUICK GUIDE - A typical resize of a in_w by in_h image to out_w by out_h with 4 channels where channel #3 is the alpha channel might look like: - int success = stbir_resize_uint8_srgb_edgemode(input_pixels, in_w, in_h, 0, output_pixels, out_w, out_h, 0, 4, 3, 0, STBIR_EDGE_CLAMP); + FULL API + See the "header file" section of the source for API documentation. - FULL API - See the "header file" section of the source for API documentation. + ADDITIONAL DOCUMENTATION - MEMORY ALLOCATION - The resize functions here perform a single memory allocation using - malloc. To control the memory allocation, before the #include that - triggers the implementation, do: + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: - #define STBIR_MALLOC(size,context) ... - #define STBIR_FREE(ptr,context) ... + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... - Each resize function makes exactly one call to malloc/free, so to use - temp memory, store the temp memory in the context and return that. + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. - ASSERT - Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h - DEFAULT FILTERS - For functions which don't provide explicit control over what filters - to use, you can change the compile-time defaults with + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with - #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something - #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something - See stbir_filter in the header-file section for the list of filters. + See stbir_filter in the header-file section for the list of filters. - NEW FILTERS - A number of 1D filter kernels are used. For a list of - supported filters see the stbir_filter enum. To add a new filter, - write a filter function and add it to stbir__filter_info_table. + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. - PROGRESS - For interactive use with slow resize operations, you can install - a progress-report callback: + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: - #define STBIR_PROGRESS_REPORT(val) some_func(val) + #define STBIR_PROGRESS_REPORT(val) some_func(val) - The parameter val is a float which goes from 0 to 1 as progress is made. + The parameter val is a float which goes from 0 to 1 as progress is made. - For example: + For example: - static void my_progress_report(float progress); - #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) - #define STB_IMAGE_RESIZE_IMPLEMENTATION - #include "stb_image_resize.h" + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" - static void my_progress_report(float progress) - { - printf("Progress: %f%%\n", progress*100); - } + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } - ALPHA CHANNEL - Most of the resizing functions provide the ability to control how - the alpha channel of an image is processed. The important things - to know about this: + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: - 1. The best mathematically-behaved version of alpha to use is - called "premultiplied alpha", in which the other color channels - have had the alpha value multiplied in. If you use premultiplied - alpha, linear filtering (such as image resampling done by this - library, or performed in texture units on GPUs) does the "right - thing". While premultiplied alpha is standard in the movie CGI - industry, it is still uncommon in the videogame/real-time world. + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. - If you linearly filter non-premultiplied alpha, strange effects - occur. (For example, the average of 1% opaque bright green - and 99% opaque black produces 50% transparent dark green when - non-premultiplied, whereas premultiplied it produces 50% - transparent near-black. The former introduces green energy - that doesn't exist in the source image.) + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the average of 1% opaque bright green + and 99% opaque black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) - 2. Artists should not edit premultiplied-alpha images; artists - want non-premultiplied alpha images. Thus, art tools generally output - non-premultiplied alpha images. + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. - 3. You will get best results in most cases by converting images - to premultiplied alpha before processing them mathematically. + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. - 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the - resizer does not do anything special for the alpha channel; - it is resampled identically to other channels. This produces - the correct results for premultiplied-alpha images, but produces - less-than-ideal results for non-premultiplied-alpha images. + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. - 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, - then the resizer weights the contribution of input pixels - based on their alpha values, or, equivalently, it multiplies - the alpha value into the color channels, resamples, then divides - by the resultant alpha value. Input pixels which have alpha=0 do - not contribute at all to output pixels unless _all_ of the input - pixels affecting that output pixel have alpha=0, in which case - the result for that pixel is the same as it would be without - STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for - input images in integer formats. For input images in float format, - input pixels with alpha=0 have no effect, and output pixels - which have alpha=0 will be 0 in all channels. (For float images, - you can manually achieve the same result by adding a tiny epsilon - value to the alpha channel of every image, and then subtracting - or clamping it at the end.) + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) - 6. You can suppress the behavior described in #5 and make - all-0-alpha pixels have 0 in all channels by #defining - STBIR_NO_ALPHA_EPSILON. + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. - 7. You can separately control whether the alpha channel is - interpreted as linear or affected by the colorspace. By default - it is linear; you almost never want to apply the colorspace. - (For example, graphics hardware does not apply sRGB conversion - to the alpha channel.) + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) - ADDITIONAL CONTRIBUTORS - Sean Barrett: API design, optimizations - - REVISIONS - 0.90 (2014-??-??) first released version + ADDITIONAL CONTRIBUTORS + Sean Barrett: API design, optimizations + + REVISIONS + 0.90 (2014-??-??) first released version - LICENSE - This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy - and modify this file as you see fit. + LICENSE + This software is in the public domain. Where that dedication is not + recognized, you are granted a perpetual, irrevocable license to copy + and modify this file as you see fit. - TODO - Don't decode all of the image data when only processing a partial tile - Installable filters? - Resize that respects alpha test coverage - (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: - https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) + TODO + Don't decode all of the image data when only processing a partial tile + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) */ #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H -typedef unsigned char stbir_uint8; - #ifdef _MSC_VER +typedef unsigned char stbir_uint8; typedef unsigned short stbir_uint16; typedef unsigned int stbir_uint32; #else #include +typedef uint8_t stbir_uint8; typedef uint16_t stbir_uint16; typedef uint32_t stbir_uint32; #endif @@ -372,7 +382,7 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int #ifndef STBIR_MALLOC #include #define STBIR_MALLOC(size,c) malloc(size) -#define STBIR_FREE(ptr,c) free(ptr) +#define STBIR_FREE(ptr,c) free(ptr) #endif #ifndef _MSC_VER diff --git a/tests/resample_test.cpp b/tests/resample_test.cpp index 2bca200..db38e40 100644 --- a/tests/resample_test.cpp +++ b/tests/resample_test.cpp @@ -750,6 +750,40 @@ void test_filters(void) } } +#define UMAX32 4294967295U + +static void write32(char *filename, stbir_uint32 *output, int w, int h) +{ + stbir_uint8 *data = (stbir_uint8*) malloc(w*h*3); + for (int i=0; i < w*h*3; ++i) + data[i] = output[i]>>24; + stbi_write_png(filename, w, h, 3, data, 0); + free(data); +} + +static void test_32(void) +{ + int w=100,h=120,x,y, out_w,out_h; + stbir_uint32 *input = (stbir_uint32*) malloc(4 * 3 * w * h); + stbir_uint32 *output = (stbir_uint32*) malloc(4 * 3 * 3*w * 3*h); + for (y=0; y < h; ++y) { + for (x=0; x < w; ++x) { + input[y*3*w + x*3 + 0] = x * ( UMAX32/w ); + input[y*3*w + x*3 + 1] = y * ( UMAX32/h ); + input[y*3*w + x*3 + 2] = UMAX32/2; + } + } + out_w = w*33/16; + out_h = h*33/16; + stbir_resize(input,w,h,0,output,out_w,out_h,0,STBIR_TYPE_UINT32,3,-1,0,STBIR_EDGE_CLAMP,STBIR_EDGE_CLAMP,STBIR_FILTER_DEFAULT,STBIR_FILTER_DEFAULT,STBIR_COLORSPACE_LINEAR,NULL); + write32("test-output/seantest_1.png", output,out_w,out_h); + + out_w = w*16/33; + out_h = h*16/33; + stbir_resize(input,w,h,0,output,out_w,out_h,0,STBIR_TYPE_UINT32,3,-1,0,STBIR_EDGE_CLAMP,STBIR_EDGE_CLAMP,STBIR_FILTER_DEFAULT,STBIR_FILTER_DEFAULT,STBIR_COLORSPACE_LINEAR,NULL); + write32("test-output/seantest_2.png", output,out_w,out_h); +} + void test_suite(int argc, char **argv) { @@ -758,6 +792,8 @@ void test_suite(int argc, char **argv) _mkdir("test-output"); + test_32(); + if (argc > 1) barbara = argv[1]; else