summaryrefslogtreecommitdiff
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
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.
-rw-r--r--include/mupdf/fitz/output-tga.h24
-rw-r--r--source/fitz/output-tga.c105
-rw-r--r--source/tools/mudraw.c10
3 files changed, 108 insertions, 31 deletions
diff --git a/include/mupdf/fitz/output-tga.h b/include/mupdf/fitz/output-tga.h
index e9af03b3..ad98c1c1 100644
--- a/include/mupdf/fitz/output-tga.h
+++ b/include/mupdf/fitz/output-tga.h
@@ -5,7 +5,31 @@
#include "mupdf/fitz/context.h"
#include "mupdf/fitz/pixmap.h"
+/*
+ fz_save_pixmap_as_tga: Save a pixmap as a TGA image file.
+ Can accept RGB, BGR or Grayscale pixmaps, with or without
+ alpha.
+*/
void fz_save_pixmap_as_tga(fz_context *ctx, fz_pixmap *pixmap, const char *filename);
+
+/*
+ Write a pixmap to an output stream in TGA format.
+ Can accept RGB, BGR or Grayscale pixmaps, with or without
+ alpha.
+*/
void fz_write_pixmap_as_tga(fz_context *ctx, fz_output *out, fz_pixmap *pixmap);
+/*
+ fz_new_tga_band_writer: Generate a new band writer for TGA
+ format images. Note that image must be generated vertically
+ flipped for use with this writer!
+
+ Can accept RGB, BGR or Grayscale pixmaps, with or without
+ alpha.
+
+ is_bgr: True, if the image is generated in bgr format.
+*/
+fz_band_writer *fz_new_tga_band_writer(fz_context *ctx, fz_output *out, int is_bgr);
+
+
#endif
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;
+}
diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c
index 74d7c3e2..46609542 100644
--- a/source/tools/mudraw.c
+++ b/source/tools/mudraw.c
@@ -636,6 +636,12 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in
fz_bound_page(ctx, page, &bounds);
zoom = resolution / 72;
fz_pre_scale(fz_rotate(&ctm, rotation), zoom, zoom);
+
+ if (output_format == OUT_TGA)
+ {
+ fz_pre_scale(fz_pre_translate(&ctm, 0, -height), 1, -1);
+ }
+
tbounds = bounds;
fz_round_rect(&ibounds, fz_transform_rect(&tbounds, &ctm));
@@ -749,6 +755,8 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in
bander = fz_new_pkm_band_writer(ctx, out);
else if (output_format == OUT_PS)
bander = fz_new_ps_band_writer(ctx, out);
+ else if (output_format == OUT_TGA)
+ bander = fz_new_tga_band_writer(ctx, out, colorspace == fz_device_bgr(ctx));
else if (output_format == OUT_PCL)
{
if (out_cs == CS_MONO)
@@ -781,8 +789,6 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in
fz_write_band(ctx, bander, bit ? bit->stride : pix->stride, drawheight, bit ? bit->samples : pix->samples);
else if (output_format == OUT_PWG)
fz_write_pixmap_as_pwg(ctx, out, pix, NULL);
- else if (output_format == OUT_TGA)
- fz_write_pixmap_as_tga(ctx, out, pix);
fz_drop_bitmap(ctx, bit);
bit = NULL;
}