From e0e4bd4d861b90282e48bd467865f8c7bb389779 Mon Sep 17 00:00:00 2001 From: fahickman Date: Mon, 11 May 2015 21:38:55 -0700 Subject: [PATCH] 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; } // *************************************************************************************************