summaryrefslogtreecommitdiff
path: root/source/fitz/output-tga.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/fitz/output-tga.c')
-rw-r--r--source/fitz/output-tga.c105
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;
+}