summaryrefslogtreecommitdiff
path: root/source/fitz
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2017-03-11 17:15:50 -0600
committerRobin Watts <robin.watts@artifex.com>2017-03-14 16:49:42 +0000
commit4c8f6f696882cb4a924c483dfe5a734c7b41de0f (patch)
treeb79a5237908a78663568dab6bda73af8b4a61e78 /source/fitz
parentdcb24ee85ff4b2c6061801e39f5a46c11f74167b (diff)
downloadmupdf-4c8f6f696882cb4a924c483dfe5a734c7b41de0f.tar.xz
Recast TGA output as a band writer.
Annoyingly TGA requires lines to be written from bottom to top, so require callers to flip the image. Also fix TGA to cope with alpha or not. Update mutool draw to use band writer interface for TGA.
Diffstat (limited to 'source/fitz')
-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;
+}