summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}