mirror of
https://github.com/nothings/stb
synced 2024-12-15 12:22:55 +03:00
Merge branch 'stb-image-writer-memory' of https://github.com/callidus/stb into work2
This commit is contained in:
commit
019236a624
@ -1,4 +1,4 @@
|
|||||||
/* stb_image_write - v0.97 - public domain - http://nothings.org/stb/stb_image_write.h
|
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
@ -9,6 +9,10 @@
|
|||||||
|
|
||||||
in the file that you want to have the implementation.
|
in the file that you want to have the implementation.
|
||||||
|
|
||||||
|
You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
|
||||||
|
And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
|
||||||
|
You can optionally define STBI_MEMMOVE and STBI_MEMCPY if the default semantics of
|
||||||
|
memmove and memcpy would be incompatible with your choice of malloc et al.
|
||||||
|
|
||||||
Will probably not work correctly with strict-aliasing optimizations.
|
Will probably not work correctly with strict-aliasing optimizations.
|
||||||
|
|
||||||
@ -32,7 +36,7 @@ USAGE:
|
|||||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
|
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
|
||||||
Each function returns 0 on failure and non-0 on success.
|
Each function returns 0 on failure and non-0 on success.
|
||||||
|
|
||||||
The functions create an image file defined by the parameters. The image
|
The functions create an image file defined by the parameters. The image
|
||||||
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
||||||
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
||||||
@ -45,7 +49,7 @@ USAGE:
|
|||||||
PNG creates output files with the same number of components as the input.
|
PNG creates output files with the same number of components as the input.
|
||||||
The BMP format expands Y to RGB in the file format and does not
|
The BMP format expands Y to RGB in the file format and does not
|
||||||
output alpha.
|
output alpha.
|
||||||
|
|
||||||
PNG supports writing rectangles of data even when the bytes storing rows of
|
PNG supports writing rectangles of data even when the bytes storing rows of
|
||||||
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
||||||
by supplying the stride between the beginning of adjacent rows. The other
|
by supplying the stride between the beginning of adjacent rows. The other
|
||||||
@ -67,6 +71,8 @@ CREDITS:
|
|||||||
Jean-Sebastien Guay
|
Jean-Sebastien Guay
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
Chribba@github
|
Chribba@github
|
||||||
|
STBI_MALLOC etc:
|
||||||
|
callidus@github
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||||
@ -93,9 +99,29 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC)
|
||||||
|
// ok
|
||||||
|
#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC)
|
||||||
|
// ok
|
||||||
|
#else
|
||||||
|
#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBI_MALLOC
|
||||||
|
#define STBI_MALLOC(sz) malloc(sz)
|
||||||
|
#define STBI_REALLOC(p,sz) realloc(p,sz)
|
||||||
|
#define STBI_FREE(p) free(p)
|
||||||
|
#define STBI_MEMMOVE(a,b,sz) memmove(a,b,sz)
|
||||||
|
#define STBI_MEMCPY(a,b,sz) memcpy(a,b,sz)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBI_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBI_ASSERT(x) assert(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef unsigned int stbiw_uint32;
|
typedef unsigned int stbiw_uint32;
|
||||||
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
||||||
|
|
||||||
@ -113,7 +139,7 @@ static void writefv(FILE *f, const char *fmt, va_list v)
|
|||||||
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
||||||
fwrite(b,4,1,f); break; }
|
fwrite(b,4,1,f); break; }
|
||||||
default:
|
default:
|
||||||
assert(0);
|
STBI_ASSERT(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +161,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
|||||||
if (y <= 0)
|
if (y <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (vdir < 0)
|
if (vdir < 0)
|
||||||
j_end = -1, j = y-1;
|
j_end = -1, j = y-1;
|
||||||
else
|
else
|
||||||
j_end = y, j = 0;
|
j_end = y, j = 0;
|
||||||
@ -232,7 +258,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
|||||||
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
||||||
{
|
{
|
||||||
unsigned char lengthbyte = (unsigned char) (length+128);
|
unsigned char lengthbyte = (unsigned char) (length+128);
|
||||||
assert(length+128 <= 255);
|
STBI_ASSERT(length+128 <= 255);
|
||||||
fwrite(&lengthbyte, 1, 1, f);
|
fwrite(&lengthbyte, 1, 1, f);
|
||||||
fwrite(&databyte, 1, 1, f);
|
fwrite(&databyte, 1, 1, f);
|
||||||
}
|
}
|
||||||
@ -240,7 +266,7 @@ void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
|||||||
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
|
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
|
||||||
{
|
{
|
||||||
unsigned char lengthbyte = (unsigned char )(length & 0xff);
|
unsigned char lengthbyte = (unsigned char )(length & 0xff);
|
||||||
assert(length <= 128); // inconsistent with spec but consistent with official code
|
STBI_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
|
||||||
fwrite(&lengthbyte, 1, 1, f);
|
fwrite(&lengthbyte, 1, 1, f);
|
||||||
fwrite(data, length, 1, f);
|
fwrite(data, length, 1, f);
|
||||||
}
|
}
|
||||||
@ -320,7 +346,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||||||
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
|
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
|
||||||
// find next byte after run
|
// find next byte after run
|
||||||
while (r < width && comp[r] == comp[x])
|
while (r < width && comp[r] == comp[x])
|
||||||
++r;
|
++r;
|
||||||
// output run up to r
|
// output run up to r
|
||||||
while (x < r) {
|
while (x < r) {
|
||||||
int len = r-x;
|
int len = r-x;
|
||||||
@ -342,12 +368,12 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
|
|||||||
f = fopen(filename, "wb");
|
f = fopen(filename, "wb");
|
||||||
if (f) {
|
if (f) {
|
||||||
/* Each component is stored separately. Allocate scratch space for full output scanline. */
|
/* Each component is stored separately. Allocate scratch space for full output scanline. */
|
||||||
unsigned char *scratch = (unsigned char *) malloc(x*4);
|
unsigned char *scratch = (unsigned char *) STBI_MALLOC(x*4);
|
||||||
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
|
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
|
||||||
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
|
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
|
||||||
for(i=0; i < y; i++)
|
for(i=0; i < y; i++)
|
||||||
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
|
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
|
||||||
free(scratch);
|
STBI_FREE(scratch);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
return f != NULL;
|
return f != NULL;
|
||||||
@ -367,13 +393,13 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
|
|||||||
|
|
||||||
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
|
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
|
||||||
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
|
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
|
||||||
#define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
|
#define stbiw__sbfree(a) ((a) ? STBI_FREE(stbiw__sbraw(a)),0 : 0)
|
||||||
|
|
||||||
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
||||||
{
|
{
|
||||||
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
||||||
void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
void *p = STBI_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||||
assert(p);
|
STBI_ASSERT(p);
|
||||||
if (p) {
|
if (p) {
|
||||||
if (!*arr) ((int *) p)[1] = 0;
|
if (!*arr) ((int *) p)[1] = 0;
|
||||||
*arr = (void *) ((int *) p + 2);
|
*arr = (void *) ((int *) p + 2);
|
||||||
@ -458,7 +484,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
|
|
||||||
i=0;
|
i=0;
|
||||||
while (i < data_len-3) {
|
while (i < data_len-3) {
|
||||||
// hash next 3 bytes of data to be compressed
|
// hash next 3 bytes of data to be compressed
|
||||||
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
|
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
|
||||||
unsigned char *bestloc = 0;
|
unsigned char *bestloc = 0;
|
||||||
unsigned char **hlist = hash_table[h];
|
unsigned char **hlist = hash_table[h];
|
||||||
@ -471,7 +497,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
}
|
}
|
||||||
// when hash table entry is too long, delete half the entries
|
// when hash table entry is too long, delete half the entries
|
||||||
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
|
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
|
||||||
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
STBI_MEMCPY(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
||||||
stbiw__sbn(hash_table[h]) = quality;
|
stbiw__sbn(hash_table[h]) = quality;
|
||||||
}
|
}
|
||||||
stbiw__sbpush(hash_table[h],data+i);
|
stbiw__sbpush(hash_table[h],data+i);
|
||||||
@ -494,7 +520,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
|
|
||||||
if (bestloc) {
|
if (bestloc) {
|
||||||
int d = (int) (data+i - bestloc); // distance back
|
int d = (int) (data+i - bestloc); // distance back
|
||||||
assert(d <= 32767 && best <= 258);
|
STBI_ASSERT(d <= 32767 && best <= 258);
|
||||||
for (j=0; best > lengthc[j+1]-1; ++j);
|
for (j=0; best > lengthc[j+1]-1; ++j);
|
||||||
stbiw__zlib_huff(j+257);
|
stbiw__zlib_huff(j+257);
|
||||||
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
|
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
|
||||||
@ -535,7 +561,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||||||
}
|
}
|
||||||
*out_len = stbiw__sbn(out);
|
*out_len = stbiw__sbn(out);
|
||||||
// make returned pointer freeable
|
// make returned pointer freeable
|
||||||
memmove(stbiw__sbraw(out), out, *out_len);
|
STBI_MEMMOVE(stbiw__sbraw(out), out, *out_len);
|
||||||
return (unsigned char *) stbiw__sbraw(out);
|
return (unsigned char *) stbiw__sbraw(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,8 +608,8 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
if (stride_bytes == 0)
|
if (stride_bytes == 0)
|
||||||
stride_bytes = x * n;
|
stride_bytes = x * n;
|
||||||
|
|
||||||
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
|
filt = (unsigned char *) STBI_MALLOC((x*n+1) * y); if (!filt) return 0;
|
||||||
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
|
line_buffer = (signed char *) STBI_MALLOC(x * n); if (!line_buffer) { STBI_FREE(filt); return 0; }
|
||||||
for (j=0; j < y; ++j) {
|
for (j=0; j < y; ++j) {
|
||||||
static int mapping[] = { 0,1,2,3,4 };
|
static int mapping[] = { 0,1,2,3,4 };
|
||||||
static int firstmap[] = { 0,1,0,5,6 };
|
static int firstmap[] = { 0,1,0,5,6 };
|
||||||
@ -622,20 +648,20 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
}
|
}
|
||||||
// when we get here, best contains the filter type, and line_buffer contains the data
|
// when we get here, best contains the filter type, and line_buffer contains the data
|
||||||
filt[j*(x*n+1)] = (unsigned char) best;
|
filt[j*(x*n+1)] = (unsigned char) best;
|
||||||
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
|
STBI_MEMCPY(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||||
}
|
}
|
||||||
free(line_buffer);
|
STBI_FREE(line_buffer);
|
||||||
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
||||||
free(filt);
|
STBI_FREE(filt);
|
||||||
if (!zlib) return 0;
|
if (!zlib) return 0;
|
||||||
|
|
||||||
// each tag requires 12 bytes of overhead
|
// each tag requires 12 bytes of overhead
|
||||||
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
|
out = (unsigned char *) STBI_MALLOC(8 + 12+13 + 12+zlen + 12);
|
||||||
if (!out) return 0;
|
if (!out) return 0;
|
||||||
*out_len = 8 + 12+13 + 12+zlen + 12;
|
*out_len = 8 + 12+13 + 12+zlen + 12;
|
||||||
|
|
||||||
o=out;
|
o=out;
|
||||||
memcpy(o,sig,8); o+= 8;
|
STBI_MEMCPY(o,sig,8); o+= 8;
|
||||||
stbiw__wp32(o, 13); // header length
|
stbiw__wp32(o, 13); // header length
|
||||||
stbiw__wptag(o, "IHDR");
|
stbiw__wptag(o, "IHDR");
|
||||||
stbiw__wp32(o, x);
|
stbiw__wp32(o, x);
|
||||||
@ -649,14 +675,14 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||||||
|
|
||||||
stbiw__wp32(o, zlen);
|
stbiw__wp32(o, zlen);
|
||||||
stbiw__wptag(o, "IDAT");
|
stbiw__wptag(o, "IDAT");
|
||||||
memcpy(o, zlib, zlen); o += zlen; free(zlib);
|
STBI_MEMCPY(o, zlib, zlen); o += zlen; STBI_FREE(zlib);
|
||||||
stbiw__wpcrc(&o, zlen);
|
stbiw__wpcrc(&o, zlen);
|
||||||
|
|
||||||
stbiw__wp32(o,0);
|
stbiw__wp32(o,0);
|
||||||
stbiw__wptag(o, "IEND");
|
stbiw__wptag(o, "IEND");
|
||||||
stbiw__wpcrc(&o,0);
|
stbiw__wpcrc(&o,0);
|
||||||
|
|
||||||
assert(o == out + *out_len);
|
STBI_ASSERT(o == out + *out_len);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -668,16 +694,17 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
|
|||||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||||
if (!png) return 0;
|
if (!png) return 0;
|
||||||
f = fopen(filename, "wb");
|
f = fopen(filename, "wb");
|
||||||
if (!f) { free(png); return 0; }
|
if (!f) { STBI_FREE(png); return 0; }
|
||||||
fwrite(png, 1, len, f);
|
fwrite(png, 1, len, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
free(png);
|
STBI_FREE(png);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
/* Revision history
|
/* Revision history
|
||||||
|
0.98 (2015-04-08)
|
||||||
|
added STBI_MALLOC, STBI_ASSERT etc
|
||||||
0.97 (2015-01-18)
|
0.97 (2015-01-18)
|
||||||
fixed HDR asserts, rewrote HDR rle logic
|
fixed HDR asserts, rewrote HDR rle logic
|
||||||
0.96 (2015-01-17)
|
0.96 (2015-01-17)
|
||||||
|
Loading…
Reference in New Issue
Block a user