Merge remote-tracking branch 'remotes/nothings/resample' into resample

pull/43/head
Jorge Rodriguez 2014-09-11 10:00:57 -07:00
commit a25c1d2bbd
2 changed files with 241 additions and 142 deletions

View File

@ -1,37 +1,132 @@
/* stb_image_resize - v0.50 - public domain image resampling
no warranty implied; use at your own risk
/* stb_image_resize - v0.90 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
Do this:
#define STB_IMAGE_RESIZE_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
Written with emphasis on usage and speed. Only scaling is
currently supported, no rotations or translations.
#define STBIR_ASSERT(x) to avoid using assert.h.
DOCUMENTATION
#define STBIR_MALLOC(size,context) and STBIR_FREE(ptr,context) to avoid using stdlib.h malloc.
Each function makes exactly one call to malloc/free, so to avoid allocations,
pass in a temp memory block as context and return that from MALLOC.
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.
QUICK NOTES:
Written with emphasis on usage and speed. Only the resize operation is
currently supported, no rotations or translations.
API
See the "header file" section of the source for API documentation.
Supports arbitrary resize for separable filters. 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.
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:
STBIR_MAX_CHANNELS: defaults to 16, if you need more, bump it up
#define STBIR_MALLOC(size,context) ...
#define STBIR_FREE(ptr,context) ...
Revisions:
0.50 (2014-??-??) first released version
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.
TODO:
Installable filters
Specify wrap and filter modes independently for each axis
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 )
ASSERT
Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
Initial implementation by Jorge L Rodriguez, @VinoBS
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
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.
PROGRESS
For interactive use with slow resize operations, you can install
a progress-report callback:
#define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
The parameter val is a float which goes from 0 to 1 as progress is made.
For example:
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:
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.)
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.
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.
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 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
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
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
@ -95,9 +190,9 @@ STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , i
#define STBIR_ALPHA_CHANNEL_NONE -1
// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
// use alpha-correct resampling by multiplying the the specified alpha channel
// into all other channels before resampling, then dividing back out after.
#define STBIR_FLAG_PREMULTIPLIED_ALPHA (1 << 0)
// use alpha-weighted resampling (effectively premultiplying, resampling,
// then unpremultiplying).
#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
// The specified alpha channel should be handled as gamma-corrected value even
// when doing sRGB operations.
#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
@ -130,7 +225,7 @@ STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
// * Alpha-channel can be processed separately
// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
// * Filters can be weighted by alpha channel (if flags&STBIR_FLAG_NONPREMUL_ALPHA)
// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
// * Filter can be selected explicitly
// * uint16 image type
// * sRGB colorspace available for all types
@ -227,29 +322,6 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
float s0, float t0, float s1, float t1);
// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
// Define this if you want a progress report.
// Example:
// void my_progress_report(float progress)
// {
// printf("Progress: %f%%\n", progress*100);
// }
//
// #define STBIR_PROGRESS_REPORT my_progress_report
#ifndef STBIR_PROGRESS_REPORT
#define STBIR_PROGRESS_REPORT(float_0_to_1)
#endif
// This value is added to alpha just before premultiplication to avoid
// zeroing out color values. It is equivalent to 2^-80. If you don't want
// that behavior (it may interfere if you have floating point images with
// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
// disable it.
#ifndef STBIR_EPSILON
#define STBIR_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
#endif
//
//
//// end header file /////////////////////////////////////////////////////
@ -282,9 +354,8 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
#ifndef STBIR_MALLOC
#include <stdlib.h>
#define STBIR_MALLOC(x,c) malloc(x)
#define STBIR_FREE(x,c) free(x)
#define STBIR_MALLOC(size,c) malloc(size)
#define STBIR_FREE(ptr,c) free(ptr)
#endif
#ifndef _MSC_VER
@ -317,10 +388,21 @@ typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
#endif
#ifndef STBIR_MAX_CHANNELS
#define STBIR_MAX_CHANNELS 16
#ifndef STBIR_PROGRESS_REPORT
#define STBIR_PROGRESS_REPORT(float_0_to_1)
#endif
// This value is added to alpha just before premultiplication to avoid
// zeroing out color values. It is equivalent to 2^-80. If you don't want
// that behavior (it may interfere if you have floating point images with
// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
// disable it.
#ifndef STBIR_ALPHA_EPSILON
#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
#endif
#define STBIR__UNUSED_PARAM(s) s=s;
// must match stbir_datatype
@ -457,38 +539,38 @@ static float stbir__srgb_uchar_to_linear_float[256] = {
// sRGB transition values, scaled by 1<<28
static int stbir__srgb_offset_to_linear_scaled[256] =
{
40579, 121738, 202897, 284056, 365216, 446375, 527534, 608693,
689852, 771011, 852421, 938035, 1028466, 1123787, 1224073, 1329393,
1439819, 1555418, 1676257, 1802402, 1933917, 2070867, 2213313, 2361317,
2514938, 2674237, 2839271, 3010099, 3186776, 3369359, 3557903, 3752463,
3953090, 4159840, 4372764, 4591913, 4817339, 5049091, 5287220, 5531775,
5782804, 6040356, 6304477, 6575216, 6852618, 7136729, 7427596, 7725263,
8029775, 8341176, 8659511, 8984821, 9317151, 9656544, 10003040, 10356683,
10717513, 11085572, 11460901, 11843540, 12233529, 12630908, 13035717, 13447994,
13867779, 14295110, 14730025, 15172563, 15622760, 16080655, 16546285, 17019686,
17500894, 17989948, 18486882, 18991734, 19504536, 20025326, 20554138, 21091010,
21635972, 22189062, 22750312, 23319758, 23897432, 24483368, 25077600, 25680162,
26291086, 26910406, 27538152, 28174360, 28819058, 29472282, 30134062, 30804430,
31483418, 32171058, 32867378, 33572412, 34286192, 35008744, 35740104, 36480296,
37229356, 37987316, 38754196, 39530036, 40314860, 41108700, 41911584, 42723540,
43544600, 44374792, 45214140, 46062680, 46920440, 47787444, 48663720, 49549300,
50444212, 51348480, 52262136, 53185204, 54117712, 55059688, 56011160, 56972156,
57942704, 58922824, 59912552, 60911908, 61920920, 62939616, 63968024, 65006168,
66054072, 67111760, 68179272, 69256616, 70343832, 71440936, 72547952, 73664920,
74791848, 75928776, 77075720, 78232704, 79399760, 80576904, 81764168, 82961576,
84169152, 85386920, 86614904, 87853120, 89101608, 90360384, 91629480, 92908904,
94198688, 95498864, 96809440, 98130456, 99461928, 100803872, 102156320, 103519296,
104892824, 106276920, 107671616, 109076928, 110492880, 111919504, 113356808, 114804824,
116263576, 117733080, 119213360, 120704448, 122206352, 123719104, 125242720, 126777232,
128322648, 129879000, 131446312, 133024600, 134613888, 136214192, 137825552, 139447968,
141081456, 142726080, 144381808, 146048704, 147726768, 149416016, 151116496, 152828192,
154551168, 156285408, 158030944, 159787808, 161556000, 163335568, 165126512, 166928864,
168742640, 170567856, 172404544, 174252704, 176112384, 177983568, 179866320, 181760640,
183666528, 185584032, 187513168, 189453952, 191406400, 193370544, 195346384, 197333952,
199333264, 201344352, 203367216, 205401904, 207448400, 209506752, 211576960, 213659056,
215753056, 217858976, 219976832, 222106656, 224248464, 226402272, 228568096, 230745952,
232935872, 235137872, 237351968, 239578176, 241816512, 244066992, 246329648, 248604512,
250891568, 253190848, 255502368, 257826160, 260162240, 262510608, 264871312, 267244336,
0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
};
static float stbir__srgb_to_linear(float f)
@ -513,32 +595,25 @@ static unsigned char stbir__linear_to_srgb_uchar(float f)
int v = 0;
int i;
// Everything below 128 is off by 1. This fixes that.
int fix = 0;
i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
// Adding 1 to 0 with the fix gives incorrect results for input 0. This fixes that.
if (x < 81000)
return 0;
i = 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; else fix = 1;
i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
return (unsigned char)v + fix;
return (unsigned char) v;
}
static float stbir__filter_trapezoid(float x, float scale)
{
STBIR__DEBUG_ASSERT(scale <= 1);
x = (float)fabs(x);
float halfscale = scale / 2;
float t = 0.5f + halfscale;
STBIR__DEBUG_ASSERT(scale <= 1);
x = (float)fabs(x);
if (x >= t)
return 0;
@ -917,6 +992,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
for (i = 0; i < stbir_info->output_w; i++)
{
float scale;
float total = 0;
for (j = 0; j < num_contributors; j++)
@ -933,7 +1009,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
STBIR__DEBUG_ASSERT(total > 0.9f);
STBIR__DEBUG_ASSERT(total < 1.1f);
float scale = 1 / total;
scale = 1 / total;
for (j = 0; j < num_contributors; j++)
{
@ -1168,14 +1244,18 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
}
#ifndef STBIR_NO_ALPHA_EPSILON
if (!(stbir_info->flags & STBIR_FLAG_PREMULTIPLIED_ALPHA))
if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
{
for (x = -stbir__get_filter_pixel_margin_horizontal(stbir_info); x < max_x; x++)
{
int decode_pixel_index = x * channels;
// If the alpha value is 0 it will clobber the color values. Make sure it's not.
float alpha = (decode_buffer[decode_pixel_index + alpha_channel] += STBIR_EPSILON);
float alpha = decode_buffer[decode_pixel_index + alpha_channel];
if (stbir_info->type != STBIR_TYPE_FLOAT) {
alpha += STBIR_ALPHA_EPSILON;
decode_buffer[decode_pixel_index + alpha_channel] = alpha;
}
for (c = 0; c < channels; c++)
{
@ -1351,28 +1431,27 @@ static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buff
}
// @OPTIMIZE: embed stbir__encode_pixel and move switch out of per-pixel loop
static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
{
int x;
int n;
#ifndef STBIR_NO_ALPHA_EPSILON
if (!(stbir_info->flags&STBIR_FLAG_PREMULTIPLIED_ALPHA))
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
{
for (x=0; x < num_pixels; ++x)
{
int pixel_index = x*channels;
float alpha = encode_buffer[pixel_index + alpha_channel];
STBIR__DEBUG_ASSERT(alpha > 0);
float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
for (n = 0; n < channels; n++)
if (n != alpha_channel)
encode_buffer[pixel_index + n] *= reciprocal_alpha;
// We added in a small epsilon to prevent the color channel from being deleted with zero alpha. Remove it now.
encode_buffer[pixel_index + alpha_channel] -= STBIR_EPSILON;
// We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
// Because we only add it for integer types, it will automatically be discarded on integer
// conversion.
}
}
#endif
@ -1387,7 +1466,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned char*)output_buffer)[index] = (unsigned char)(round(stbir__saturate(encode_buffer[index]) * 255));
((unsigned char*)output_buffer)[index] = (unsigned char)(floor(stbir__saturate(encode_buffer[index]) * 255 + 0.5f));
}
}
break;
@ -1404,7 +1483,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
}
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
((unsigned char*)output_buffer)[pixel_index + alpha_channel] = (unsigned char)(round(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 255));
((unsigned char*)output_buffer)[pixel_index + alpha_channel] = (unsigned char)(floor(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 255+0.5f));
}
break;
@ -1416,7 +1495,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned short*)output_buffer)[index] = (unsigned short)(round(stbir__saturate(encode_buffer[index]) * 65535));
((unsigned short*)output_buffer)[index] = (unsigned short)(floor(stbir__saturate(encode_buffer[index]) * 65535+0.5f));
}
}
break;
@ -1429,11 +1508,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned short*)output_buffer)[index] = (unsigned short)(round(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535));
((unsigned short*)output_buffer)[index] = (unsigned short)(floor(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535 + 0.5f));
}
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
((unsigned short*)output_buffer)[pixel_index + alpha_channel] = (unsigned short)(round(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 65535));
((unsigned short*)output_buffer)[pixel_index + alpha_channel] = (unsigned short)(floor(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 65535 + 0.5f));
}
break;
@ -1446,7 +1525,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned int*)output_buffer)[index] = (unsigned int)(round(((double)stbir__saturate(encode_buffer[index])) * 4294967295));
((unsigned int*)output_buffer)[index] = (unsigned int)(floor(((double)stbir__saturate(encode_buffer[index])) * 4294967295 + 0.5f));
}
}
break;
@ -1459,11 +1538,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned int*)output_buffer)[index] = (unsigned int)(round(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295));
((unsigned int*)output_buffer)[index] = (unsigned int)(floor(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295 + 0.5f));
}
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)(round(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295));
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)(floor(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295 + 0.5f));
}
break;
@ -1848,10 +1927,9 @@ static int stbir__resize_allocated(stbir__info *info,
memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
#endif
STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
STBIR_ASSERT(info->channels >= 0);
if (info->channels > STBIR_MAX_CHANNELS || info->channels < 0)
if (info->channels < 0)
return 0;
STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
@ -1863,9 +1941,9 @@ static int stbir__resize_allocated(stbir__info *info,
return 0;
if (alpha_channel < 0)
flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_PREMULTIPLIED_ALPHA;
flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_PREMULTIPLIED_ALPHA))
if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
if (alpha_channel >= info->channels)

View File

@ -45,7 +45,7 @@ void* stbir_malloc(size_t size, void* context)
void stbir_free(void* memory, void* context)
{
if (!context)
return free(memory);
free(memory);
}
//#include <stdio.h>
@ -425,10 +425,10 @@ void test_premul()
float ga = (float)25 / 4294967296;
float a = (ra + ga) / 2;
STBIR_ASSERT(output[0] == (int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232
STBIR_ASSERT(output[1] == (int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23
STBIR_ASSERT(output[0] == (unsigned int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232
STBIR_ASSERT(output[1] == (unsigned int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23
STBIR_ASSERT(output[2] == 0);
STBIR_ASSERT(output[3] == (int)(a * 4294967296 + 0.5f)); // 140
STBIR_ASSERT(output[3] == (unsigned int)(a * 4294967296 + 0.5f)); // 140
// Now a test to make sure it doesn't clobber existing values.
@ -606,7 +606,7 @@ void verify_box(void)
STBIR_ASSERT(output11[0][0] == ((t+32)>>6));
}
void verify_filter_normalized(stbir_filter filter, int output_size, int value)
void verify_filter_normalized(stbir_filter filter, int output_size, unsigned int value)
{
int i, j;
unsigned int output[64];
@ -618,6 +618,11 @@ void verify_filter_normalized(stbir_filter filter, int output_size, int value)
STBIR_ASSERT(value == output[j*output_size + i]);
}
float round2(float f)
{
return (float) floor(f+0.5f); // round() isn't C standard pre-C99
}
void test_filters(void)
{
int i,j;
@ -673,7 +678,7 @@ void test_filters(void)
{
// This test is designed to produce coefficients that are very badly denormalized.
int v = 556;
unsigned int v = 556;
unsigned int input[100 * 100];
unsigned int output[11 * 11];
@ -698,13 +703,13 @@ void test_filters(void)
stbir_resize(input, 3, 1, 0, output, 2, 1, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL);
STBIR_ASSERT(output[0] == (int)round((float)(input[0] * 2 + input[1]) / 3));
STBIR_ASSERT(output[1] == (int)round((float)(input[2] * 2 + input[1]) / 3));
STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3));
STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3));
stbir_resize(input, 1, 3, 0, output, 1, 2, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL);
STBIR_ASSERT(output[0] == (int)round((float)(input[0] * 2 + input[1]) / 3));
STBIR_ASSERT(output[1] == (int)round((float)(input[2] * 2 + input[1]) / 3));
STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3));
STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3));
}
{
@ -767,6 +772,7 @@ void test_suite(int argc, char **argv)
else
barbara = "barbara.png";
// check what cases we need normalization for
#if 1
{
float x, y;
@ -804,18 +810,33 @@ void test_suite(int argc, char **argv)
}
#endif
for (i = 0; i < 256; i++)
STBIR_ASSERT(stbir__linear_to_srgb_uchar(stbir__srgb_to_linear(float(i) / 255)) == i);
#if 0 // linear_to_srgb_uchar table
for (i=0; i < 256; ++i) {
float f = stbir__srgb_to_linear((i+0.5f)/256.0f);
float f = stbir__srgb_to_linear((i-0.5f)/255.0f);
printf("%9d, ", (int) ((f) * (1<<28)));
if ((i & 7) == 7)
printf("\n");
}
#endif
// old tests that hacky fix worked on - test that
// every uint8 maps to itself
for (i = 0; i < 256; i++) {
float f = stbir__srgb_to_linear(float(i) / 255);
int n = stbir__linear_to_srgb_uchar(f);
STBIR_ASSERT(n == i);
}
// new tests that hacky fix failed for - test that
// values adjacent to uint8 round to nearest uint8
for (i = 0; i < 256; i++) {
for (float y = -0.49f; y <= 0.491f; y += 0.01f) {
float f = stbir__srgb_to_linear((i+y) / 255.0f);
int n = stbir__linear_to_srgb_uchar(f);
STBIR_ASSERT(n == i);
}
}
test_filters();
test_subpixel_1();