|
@@ -3,8 +3,8 @@
|
|
|
http://github.com/nothings/stb
|
|
|
|
|
|
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.
|
|
|
+ SIMD or threads, so it be easily outperformed by libs that use those.)
|
|
|
+ Only scaling and translation is supported, no rotations or shears.
|
|
|
|
|
|
COMPILING & LINKING
|
|
|
In one C/C++ file that #includes this file, do this:
|
|
@@ -43,6 +43,11 @@
|
|
|
ASSERT
|
|
|
Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
|
|
|
|
|
|
+ OPTIMIZATION
|
|
|
+ Define STBIR_SATURATE_INT to compute clamp values in-range using
|
|
|
+ integer operations instead of float operations. This may be faster
|
|
|
+ on some platforms.
|
|
|
+
|
|
|
DEFAULT FILTERS
|
|
|
For functions which don't provide explicit control over what filters
|
|
|
to use, you can change the compile-time defaults with
|
|
@@ -78,6 +83,10 @@
|
|
|
printf("Progress: %f%%\n", progress*100);
|
|
|
}
|
|
|
|
|
|
+ MAX CHANNELS
|
|
|
+ If your image has more than 64 channels, define STBIR_MAX_CHANNELS
|
|
|
+ to the max you'll have.
|
|
|
+
|
|
|
ALPHA CHANNEL
|
|
|
Most of the resizing functions provide the ability to control how
|
|
|
the alpha channel of an image is processed. The important things
|
|
@@ -419,6 +428,15 @@ typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]
|
|
|
#define STBIR_PROGRESS_REPORT(float_0_to_1)
|
|
|
#endif
|
|
|
|
|
|
+#ifndef STBIR_MAX_CHANNELS
|
|
|
+#define STBIR_MAX_CHANNELS 64
|
|
|
+#endif
|
|
|
+
|
|
|
+#if STBIR_MAX_CHANNELS > 65536
|
|
|
+#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
|
|
|
+// because we store the indices in 16-bit variables
|
|
|
+#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
|
|
@@ -551,6 +569,30 @@ static stbir__inline float stbir__saturate(float x)
|
|
|
return x;
|
|
|
}
|
|
|
|
|
|
+#ifdef STBIR_SATURATE_INT
|
|
|
+static stbir__inline stbir_uint8 stbir__saturate8(int x)
|
|
|
+{
|
|
|
+ if ((unsigned int) x <= 255)
|
|
|
+ return x;
|
|
|
+
|
|
|
+ if (x < 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return 255;
|
|
|
+}
|
|
|
+
|
|
|
+static stbir__inline stbir_uint16 stbir__saturate16(int x)
|
|
|
+{
|
|
|
+ if ((unsigned int) x <= 65535)
|
|
|
+ return x;
|
|
|
+
|
|
|
+ if (x < 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return 65535;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static float stbir__srgb_uchar_to_linear_float[256] = {
|
|
|
0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
|
|
|
0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
|
|
@@ -1594,6 +1636,8 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
{
|
|
|
int x;
|
|
|
int n;
|
|
|
+ int num_nonalpha;
|
|
|
+ stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
|
|
|
|
|
|
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
|
|
|
{
|
|
@@ -1603,19 +1647,36 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
|
|
|
float alpha = encode_buffer[pixel_index + alpha_channel];
|
|
|
float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
|
|
|
+
|
|
|
+ // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
|
|
|
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.
|
|
|
// Because we only add it for integer types, it will automatically be discarded on integer
|
|
|
- // conversion.
|
|
|
+ // conversion, so we don't need to subtract it back out (which would be problematic for
|
|
|
+ // numeric precision reasons).
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // build a table of all channels that need colorspace correction, so
|
|
|
+ // we don't perform colorspace correction on channels that don't need it.
|
|
|
+ for (x=0, num_nonalpha=0; x < channels; ++x)
|
|
|
+ if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
|
|
+ nonalpha[num_nonalpha++] = x;
|
|
|
+
|
|
|
#define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
|
|
|
#define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
|
|
|
|
|
|
+ #ifdef STBIR__SATURATE_INT
|
|
|
+ #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 ))
|
|
|
+ #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535))
|
|
|
+ #else
|
|
|
+ #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 )
|
|
|
+ #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535)
|
|
|
+ #endif
|
|
|
+
|
|
|
switch (decode)
|
|
|
{
|
|
|
case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
|
|
@@ -1626,7 +1687,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) STBIR__ROUND_INT(stbir__saturate(encode_buffer[index]) * 255);
|
|
|
+ ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
@@ -1636,14 +1697,14 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
{
|
|
|
int pixel_index = x*channels;
|
|
|
|
|
|
- for (n = 0; n < channels; n++)
|
|
|
+ for (n = 0; n < num_nonalpha; n++)
|
|
|
{
|
|
|
- int index = pixel_index + n;
|
|
|
+ int index = pixel_index + nonalpha[n];
|
|
|
((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
|
|
|
}
|
|
|
|
|
|
- if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
|
|
- ((unsigned char*)output_buffer)[pixel_index + alpha_channel] = (unsigned char) STBIR__ROUND_INT(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 255);
|
|
|
+ if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
|
|
+ ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
|
|
|
}
|
|
|
break;
|
|
|
|
|
@@ -1655,7 +1716,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)STBIR__ROUND_INT(stbir__saturate(encode_buffer[index]) * 65535);
|
|
|
+ ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
@@ -1665,14 +1726,14 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
{
|
|
|
int pixel_index = x*channels;
|
|
|
|
|
|
- for (n = 0; n < channels; n++)
|
|
|
+ for (n = 0; n < num_nonalpha; n++)
|
|
|
{
|
|
|
- int index = pixel_index + n;
|
|
|
+ int index = pixel_index + nonalpha[n];
|
|
|
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535);
|
|
|
}
|
|
|
|
|
|
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
|
|
- ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = (unsigned short)STBIR__ROUND_INT(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 65535);
|
|
|
+ ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
|
|
|
}
|
|
|
|
|
|
break;
|
|
@@ -1695,9 +1756,9 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
{
|
|
|
int pixel_index = x*channels;
|
|
|
|
|
|
- for (n = 0; n < channels; n++)
|
|
|
+ for (n = 0; n < num_nonalpha; n++)
|
|
|
{
|
|
|
- int index = pixel_index + n;
|
|
|
+ int index = pixel_index + nonalpha[n];
|
|
|
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295);
|
|
|
}
|
|
|
|
|
@@ -1724,9 +1785,9 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|
|
{
|
|
|
int pixel_index = x*channels;
|
|
|
|
|
|
- for (n = 0; n < channels; n++)
|
|
|
+ for (n = 0; n < num_nonalpha; n++)
|
|
|
{
|
|
|
- int index = pixel_index + n;
|
|
|
+ int index = pixel_index + nonalpha[n];
|
|
|
((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
|
|
|
}
|
|
|
|
|
@@ -2186,8 +2247,9 @@ static int stbir__resize_allocated(stbir__info *info,
|
|
|
#endif
|
|
|
|
|
|
STBIR_ASSERT(info->channels >= 0);
|
|
|
+ STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
|
|
|
|
|
|
- if (info->channels < 0)
|
|
|
+ if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
|
|
|
return 0;
|
|
|
|
|
|
STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
|