From e0e4bd4d861b90282e48bd467865f8c7bb389779 Mon Sep 17 00:00:00 2001 From: fahickman Date: Mon, 11 May 2015 21:38:55 -0700 Subject: [PATCH 1/3] write TGAs with RLE compression --- stb_image_write.h | 134 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 1048970..b860a74 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -149,6 +149,14 @@ static void writefv(FILE *f, const char *fmt, va_list v) } } +static void writef(FILE *f, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + writefv(f, fmt, v); + va_end(v); +} + static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c) { unsigned char arr[3]; @@ -156,11 +164,42 @@ static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c) fwrite(arr, 3, 1, f); } -static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +static void write_pixel(FILE *f, int rgb_dir, int comp, int write_alpha, int expand_mono, const unsigned char *d) { unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + fwrite(&d[comp - 1], 1, 1, f); + switch (comp) { + case 1: fwrite(d, 1, 1, f); + break; + case 2: if (expand_mono) + write3(f, d[0], d[0], d[0]); // monochrome bmp + else + fwrite(d, 1, 1, f); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + write3(f, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + write3(f, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + fwrite(&d[comp - 1], 1, 1, f); +} + +static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ stbiw_uint32 zero = 0; - int i,j,k, j_end; + int i,j, j_end; if (y <= 0) return; @@ -173,31 +212,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { unsigned char *d = (unsigned char *) data + (j*x+i)*comp; - if (write_alpha < 0) - fwrite(&d[comp-1], 1, 1, f); - switch (comp) { - case 1: fwrite(d, 1, 1, f); - break; - case 2: if (expand_mono) - write3(f, d[0],d[0],d[0]); // monochrome bmp - else - fwrite(d, 1, 1, f); // monochrome TGA - break; - case 4: - if (!write_alpha) { - // composite against pink background - for (k=0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; - write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]); - break; - } - /* FALLTHROUGH */ - case 3: - write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]); - break; - } - if (write_alpha > 0) - fwrite(&d[comp-1], 1, 1, f); + write_pixel(f, rgb_dir, comp, write_alpha, expand_mono, d); } fwrite(&zero,scanline_pad,1,f); } @@ -232,9 +247,68 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat { int has_alpha = (comp == 2 || comp == 4); int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 - return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0, - "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8); + int format = colorbytes < 2 ? 11 : 10; // 3 color channels (RGB/RGBA) = 10, 1 color channel (Y/YA) = 11 + FILE *f; + + if (y < 0 || x < 0) return 0; + f = fopen(filename, "wb"); + if (f) { + int i,j,k; + + writef(f, "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); + + for (j = y - 1; j >= 0; --j) { + unsigned char *line = (unsigned char *) data + j * x * comp; + int run; + + for (i = 0; i < x; i += run) { + unsigned char *first = line + i * comp; + int diff = 1; + run = 1; + + if (i < x - 1) { + ++run; + diff = memcmp(first, line + (i + 1) * comp, comp); + if (diff) { + unsigned char *next = first; + for (k = i + 2; k < x && run < 128; ++k) { + if (memcmp(next, line + k * comp, comp)) { + next += comp; + ++run; + } else { + --run; + break; + } + } + } else { + for (k = i + 2; k < x && run < 128; ++k) { + if (!memcmp(first, line + k * comp, comp)) { + ++run; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = (unsigned char) (run - 1); + fwrite(&header, 1, 1, f); + for (k = 0; k < run; ++k) { + write_pixel(f, -1, comp, has_alpha, 0, first + k * comp); + } + } else { + unsigned char header = (unsigned char) (run - 1) | 0x80; + fwrite(&header, 1, 1, f); + write_pixel(f, -1, comp, has_alpha, 0, first); + } + } + } + + fclose(f); + } + + return f != NULL; } // ************************************************************************************************* From 126ec22867c88917ab3da278e0e126b104f55b00 Mon Sep 17 00:00:00 2001 From: fahickman Date: Thu, 4 Jun 2015 14:04:02 -0700 Subject: [PATCH 2/3] add missing consts --- stb_image_write.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index b860a74..5c1e5f9 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -258,32 +258,32 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat writef(f, "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); for (j = y - 1; j >= 0; --j) { - unsigned char *line = (unsigned char *) data + j * x * comp; - int run; + const unsigned char *row = (unsigned char *) data + j * x * comp; + int len; - for (i = 0; i < x; i += run) { - unsigned char *first = line + i * comp; + for (i = 0; i < x; i += len) { + const unsigned char *begin = row + i * comp; int diff = 1; - run = 1; + len = 1; if (i < x - 1) { - ++run; - diff = memcmp(first, line + (i + 1) * comp, comp); + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); if (diff) { - unsigned char *next = first; - for (k = i + 2; k < x && run < 128; ++k) { - if (memcmp(next, line + k * comp, comp)) { - next += comp; - ++run; + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; } else { - --run; + --len; break; } } } else { - for (k = i + 2; k < x && run < 128; ++k) { - if (!memcmp(first, line + k * comp, comp)) { - ++run; + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; } else { break; } @@ -292,15 +292,15 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat } if (diff) { - unsigned char header = (unsigned char) (run - 1); + unsigned char header = (unsigned char) (len - 1); fwrite(&header, 1, 1, f); - for (k = 0; k < run; ++k) { - write_pixel(f, -1, comp, has_alpha, 0, first + k * comp); + for (k = 0; k < len; ++k) { + write_pixel(f, -1, comp, has_alpha, 0, begin + k * comp); } } else { - unsigned char header = (unsigned char) (run - 1) | 0x80; + unsigned char header = (unsigned char) (len - 129); fwrite(&header, 1, 1, f); - write_pixel(f, -1, comp, has_alpha, 0, first); + write_pixel(f, -1, comp, has_alpha, 0, begin); } } } From 80a0e90d53abf30d71fe6f40e243253cbb2aadba Mon Sep 17 00:00:00 2001 From: fahickman Date: Fri, 3 Jul 2015 14:27:29 -0700 Subject: [PATCH 3/3] TGA RLE flag and regression fix Add requested flag for controlling TGA RLE compression and fix a regression when writing monochrome TGAs. --- stb_image_write.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 5c1e5f9..e5d7bd5 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -129,6 +129,8 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl typedef unsigned int stbiw_uint32; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; +static int stbi__write_tga_with_rle = 1; + static void writefv(FILE *f, const char *fmt, va_list v) { while (*fmt) { @@ -247,15 +249,20 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat { int has_alpha = (comp == 2 || comp == 4); int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 11 : 10; // 3 color channels (RGB/RGBA) = 10, 1 color channel (Y/YA) = 11 + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 FILE *f; + if (!stbi__write_tga_with_rle) { + return outfile(filename, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } + if (y < 0 || x < 0) return 0; f = fopen(filename, "wb"); if (f) { int i,j,k; - writef(f, "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); + writef(f, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); for (j = y - 1; j >= 0; --j) { const unsigned char *row = (unsigned char *) data + j * x * comp;