diff options
Diffstat (limited to 'source/fitz/output-tga.c')
-rw-r--r-- | source/fitz/output-tga.c | 105 |
1 files changed, 76 insertions, 29 deletions
diff --git a/source/fitz/output-tga.c b/source/fitz/output-tga.c index 8a595265..0e3cf3c5 100644 --- a/source/fitz/output-tga.c +++ b/source/fitz/output-tga.c @@ -4,7 +4,12 @@ * Write pixmap to TGA file (with or without alpha channel) */ -static inline void tga_put_pixel(fz_context *ctx, fz_output *out, unsigned char *data, int n, int is_bgr) +typedef struct { + fz_band_writer super; + int is_bgr; +} tga_band_writer; + +static inline void tga_put_pixel(fz_context *ctx, fz_output *out, const unsigned char *data, int n, int is_bgr) { switch(n) { @@ -30,7 +35,6 @@ static inline void tga_put_pixel(fz_context *ctx, fz_output *out, unsigned char fz_putc(ctx, out, data[1]); fz_putc(ctx, out, data[2]); } - fz_putc(ctx, out, 255); break; case 2: /* GA */ fz_putc(ctx, out, data[0]); @@ -38,11 +42,8 @@ static inline void tga_put_pixel(fz_context *ctx, fz_output *out, unsigned char fz_putc(ctx, out, data[0]); fz_putc(ctx, out, data[1]); break; - case 1: /* GA */ - fz_putc(ctx, out, data[0]); + case 1: /* G */ fz_putc(ctx, out, data[0]); - fz_putc(ctx, out, data[0]); - fz_putc(ctx, out, 255); break; } } @@ -62,50 +63,96 @@ fz_save_pixmap_as_tga(fz_context *ctx, fz_pixmap *pixmap, const char *filename) void fz_write_pixmap_as_tga(fz_context *ctx, fz_output *out, fz_pixmap *pixmap) { - unsigned char head[18]; - int n = pixmap->n; - int d = pixmap->alpha || n == 1 ? n : n - 1; - int is_bgr = pixmap->colorspace == fz_device_bgr(ctx); - int k; + fz_band_writer *writer = fz_new_tga_band_writer(ctx, out, pixmap->colorspace == fz_device_bgr(ctx)); - if (pixmap->colorspace && pixmap->colorspace != fz_device_gray(ctx) && - pixmap->colorspace != fz_device_rgb(ctx) && pixmap->colorspace != fz_device_bgr(ctx)) + fz_try(ctx) { - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as tga"); + fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0); + fz_write_band(ctx, writer, -pixmap->stride, pixmap->h, pixmap->samples + pixmap->stride * (pixmap->h-1)); } + fz_always(ctx) + fz_drop_band_writer(ctx, writer); + fz_catch(ctx) + fz_rethrow(ctx); +} +static void +tga_write_header(fz_context *ctx, fz_band_writer *writer_) +{ + tga_band_writer *writer = (tga_band_writer *)writer_; + fz_output *out = writer->super.out; + int w = writer->super.w; + int h = writer->super.h; + int n = writer->super.n; + int alpha = writer->super.alpha; + unsigned char head[18]; + int d = (alpha && n > 1) ? 4 : (n == 1 ? 1 : 3); + + if (n-alpha > 1 && n != 3+alpha) + fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale/rgb/rgba (with or without alpha) to write as tga"); memset(head, 0, sizeof(head)); - head[2] = n == 4 ? 10 : 11; - head[12] = pixmap->w & 0xFF; head[13] = (pixmap->w >> 8) & 0xFF; - head[14] = pixmap->h & 0xFF; head[15] = (pixmap->h >> 8) & 0xFF; - head[16] = d * 8; - head[17] = pixmap->alpha && n > 1 ? 8 : 0; - if (pixmap->alpha && d == 2) - head[16] = 32; + head[2] = n > 1 ? 10 /* RGB or RGBA or GA */ : 11 /* G */; + head[12] = w & 0xFF; head[13] = (w >> 8) & 0xFF; + head[14] = h & 0xFF; head[15] = (h >> 8) & 0xFF; + head[16] = d * 8; /* BPP */ + head[17] = alpha && n > 1 ? 8 : 0; /* Alpha bpp */ fz_write(ctx, out, head, sizeof(head)); - for (k = 1; k <= pixmap->h; k++) +} + +static void +tga_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_start, int band_height, const unsigned char *samples) +{ + tga_band_writer *writer = (tga_band_writer *)writer_; + fz_output *out = writer->super.out; + int w = writer->super.w; + int h = writer->super.h; + int n = writer->super.n; + int d = (writer->super.alpha && n > 1) ? 4 : (n == 1 ? 1 : 3); + int is_bgr = writer->is_bgr; + int k; + + for (k = 0; k < h; k++) { int i, j; - unsigned char *line = pixmap->samples + pixmap->w * n * (pixmap->h - k); - for (i = 0, j = 1; i < pixmap->w; i += j, j = 1) + const unsigned char *line = samples + stride * k; + for (i = 0, j = 1; i < w; i += j, j = 1) { - for (; i + j < pixmap->w && j < 128 && !memcmp(line + i * n, line + (i + j) * n, d); j++); + for (; i + j < w && j < 128 && !memcmp(line + i * n, line + (i + j) * n, d); j++); if (j > 1) { fz_putc(ctx, out, j - 1 + 128); - tga_put_pixel(ctx, out, line + i * n, d, is_bgr); + tga_put_pixel(ctx, out, line + i * n, n, is_bgr); } else { - for (; i + j < pixmap->w && j <= 128 && memcmp(line + (i + j - 1) * n, line + (i + j) * n, d) != 0; j++); - if (i + j < pixmap->w || j > 128) + for (; i + j < w && j <= 128 && memcmp(line + (i + j - 1) * n, line + (i + j) * n, d) != 0; j++); + if (i + j < w || j > 128) j--; fz_putc(ctx, out, j - 1); for (; j > 0; j--, i++) - tga_put_pixel(ctx, out, line + i * n, d, is_bgr); + tga_put_pixel(ctx, out, line + i * n, n, is_bgr); } } } +} + +static void +tga_write_trailer(fz_context *ctx, fz_band_writer *writer) +{ + fz_output *out = writer->out; + fz_write(ctx, out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.\0", 26); } + +fz_band_writer *fz_new_tga_band_writer(fz_context *ctx, fz_output *out, int is_bgr) +{ + tga_band_writer *writer = fz_new_band_writer(ctx, tga_band_writer, out); + + writer->super.header = tga_write_header; + writer->super.band = tga_write_band; + writer->super.trailer = tga_write_trailer; + writer->is_bgr = is_bgr; + + return &writer->super; +} |