summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-11-07 17:32:15 +0000
committerRobin Watts <robin.watts@artifex.com>2017-11-08 12:57:18 +0000
commit3119f69dd9536cdaab0719fba2898be894e8fc01 (patch)
tree7e034de6e3d83ca163ce656b328e29c1b55a03e4
parent520cc26d18c9ee245b56e9e91f9d4fcae02be5f0 (diff)
downloadmupdf-3119f69dd9536cdaab0719fba2898be894e8fc01.tar.xz
Pixmap writers for formats with alpha should handle premultiplied data.
Any pixmap writers that can handle data with an alpha plane should accept that data in premultiplied form, and write it out appropriately for the file format. This avoids the need to unpremultiply data in mudraw, and solves the issue we were seeing where we want the png writer to be able to cope with premultiplied data (such as for the debug blending routines) and unpremultiplied data (such as that given after mudraw has unpremultiplied the data).
-rw-r--r--source/fitz/output-pnm.c154
-rw-r--r--source/fitz/output-psd.c73
-rw-r--r--source/fitz/output-tga.c28
-rw-r--r--source/tools/mudraw.c3
4 files changed, 195 insertions, 63 deletions
diff --git a/source/fitz/output-pnm.c b/source/fitz/output-pnm.c
index 9bc5e6aa..598d66f6 100644
--- a/source/fitz/output-pnm.c
+++ b/source/fitz/output-pnm.c
@@ -15,6 +15,9 @@ pnm_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *c
if (writer->s != 0)
fz_throw(ctx, FZ_ERROR_GENERIC, "PNM writer cannot cope with spot colors");
+ if (alpha)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "PNM writer cannot cope with alpha");
+
n -= alpha;
if (n != 1 && n != 3)
fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pnm");
@@ -34,12 +37,10 @@ pnm_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_sta
int w = writer->w;
int h = writer->h;
int n = writer->n;
- int alpha = writer->alpha;
- char buffer[2*3*4*5*6]; /* Buffer must be a multiple of 2 and 3 at least. */
int len;
int end = band_start + band_height;
- if (n-alpha != 1 && n-alpha != 3)
+ if (n != 1 && n != 3)
fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pnm");
if (!out)
@@ -67,44 +68,10 @@ pnm_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_sta
fz_write_data(ctx, out, p, num_written);
p += num_written;
break;
- case 2:
- {
- char *o = buffer;
- int count;
-
- if (num_written > sizeof(buffer))
- num_written = sizeof(buffer);
-
- for (count = num_written; count; count--)
- {
- *o++ = *p;
- p += 2;
- }
- fz_write_data(ctx, out, buffer, num_written);
- break;
- }
case 3:
fz_write_data(ctx, out, p, num_written*3);
p += num_written*3;
break;
- case 4:
- {
- char *o = buffer;
- int count;
-
- if (num_written > sizeof(buffer)/3)
- num_written = sizeof(buffer)/3;
-
- for (count = num_written; count; count--)
- {
- *o++ = p[0];
- *o++ = p[1];
- *o++ = p[2];
- p += n;
- }
- fz_write_data(ctx, out, buffer, num_written * 3);
- break;
- }
}
len -= num_written;
}
@@ -191,7 +158,7 @@ pam_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *c
else if (n == 3 && !alpha) fz_write_printf(ctx, out, "TUPLTYPE RGB\n");
else if (n == 3 && alpha) fz_write_printf(ctx, out, "TUPLTYPE RGB_ALPHA\n");
else if (n == 4 && !alpha) fz_write_printf(ctx, out, "TUPLTYPE CMYK\n");
- else if (n == 5) fz_write_printf(ctx, out, "TUPLTYPE CMYK_ALPHA\n");
+ else if (n == 4 && alpha) fz_write_printf(ctx, out, "TUPLTYPE CMYK_ALPHA\n");
fz_write_printf(ctx, out, "ENDHDR\n");
}
@@ -202,7 +169,8 @@ pam_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_sta
int w = writer->w;
int h = writer->h;
int n = writer->n;
- int y;
+ int alpha = writer->alpha;
+ int x, y;
int end = band_start + band_height;
if (!out)
@@ -212,11 +180,113 @@ pam_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_sta
end = h;
end -= band_start;
- for (y = 0; y < end; y++)
+ if (alpha)
{
- fz_write_data(ctx, out, sp, w * n);
- sp += stride;
+ /* Buffer must be a multiple of 2, 3 and 5 at least. */
+ /* Also, for the generic case, it must be bigger than FZ_MAX_COLORS */
+ char buffer[2*3*4*5*6];
+ char *b = buffer;
+ stride -= n * w;
+ switch (n)
+ {
+ case 2:
+ for (y = 0; y < end; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int a = sp[1];
+ *b++ = a ? (sp[0] * 255 + (a>>1))/a : 0;
+ *b++ = a;
+ sp += 2;
+ if (b == &buffer[sizeof(buffer)])
+ {
+ fz_write_data(ctx, out, buffer, sizeof(buffer));
+ b = buffer;
+ }
+ }
+ sp += stride;
+ }
+ if (b != buffer)
+ fz_write_data(ctx, out, buffer, b - buffer);
+ break;
+ case 4:
+ for (y = 0; y < end; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int a = sp[3];
+ int inva = a ? 256 * 255 / a : 0;
+ *b++ = (sp[0] * inva + 128)>>8;
+ *b++ = (sp[1] * inva + 128)>>8;
+ *b++ = (sp[2] * inva + 128)>>8;
+ *b++ = a;
+ sp += 4;
+ if (b == &buffer[sizeof(buffer)])
+ {
+ fz_write_data(ctx, out, buffer, sizeof(buffer));
+ b = buffer;
+ }
+ }
+ sp += stride;
+ }
+ if (b != buffer)
+ fz_write_data(ctx, out, buffer, b - buffer);
+ break;
+ case 5:
+ for (y = 0; y < end; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int a = sp[4];
+ int inva = a ? 256 * 255 / a : 0;
+ *b++ = (sp[0] * inva + 128)>>8;
+ *b++ = (sp[1] * inva + 128)>>8;
+ *b++ = (sp[2] * inva + 128)>>8;
+ *b++ = (sp[3] * inva + 128)>>8;
+ *b++ = a;
+ sp += 5;
+ if (b == &buffer[sizeof(buffer)])
+ {
+ fz_write_data(ctx, out, buffer, sizeof(buffer));
+ b = buffer;
+ }
+ }
+ sp += stride;
+ }
+ if (b != buffer)
+ fz_write_data(ctx, out, buffer, b - buffer);
+ break;
+ default:
+ for (y = 0; y < end; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int a = sp[n-1];
+ int inva = a ? 256 * 255 / a : 0;
+ int k;
+ for (k = 0; k < n-1; k++)
+ *b++ = (*sp++ * inva + 128)>>8;
+ *b++ = a;
+ sp++;
+ if (b >= &buffer[sizeof(buffer)] - n)
+ {
+ fz_write_data(ctx, out, buffer, b - buffer);
+ b = buffer;
+ }
+ }
+ sp += stride;
+ }
+ if (b != buffer)
+ fz_write_data(ctx, out, buffer, b - buffer);
+ break;
+ }
}
+ else
+ for (y = 0; y < end; y++)
+ {
+ fz_write_data(ctx, out, sp, w * n);
+ sp += stride;
+ }
}
fz_band_writer *fz_new_pam_band_writer(fz_context *ctx, fz_output *out)
diff --git a/source/fitz/output-psd.c b/source/fitz/output-psd.c
index 223a591e..e097e9a6 100644
--- a/source/fitz/output-psd.c
+++ b/source/fitz/output-psd.c
@@ -254,8 +254,41 @@ psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_st
plane_inc = w * (h - band_height);
line_skip = stride - w*n;
b = buffer;
- for (k = 0; k < n; k++)
+ if (writer->super.alpha)
{
+ const unsigned char *ap = &sp[n-1];
+ for (k = 0; k < n-1; k++)
+ {
+ for (y = 0; y < band_height; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int a = *ap;
+ ap += n;
+ *b++ = a != 0 ? (*sp * 255 + 128)/a : 0;
+ sp += n;
+ if (b == buffer_end)
+ {
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
+ fz_write_data(ctx, out, buffer, sizeof(buffer));
+ b = buffer;
+ }
+ }
+ sp += line_skip;
+ ap += line_skip;
+ }
+ sp -= stride * band_height - 1;
+ ap -= stride * band_height;
+ if (b != buffer)
+ {
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
+ fz_write_data(ctx, out, buffer, b - buffer);
+ b = buffer;
+ }
+ fz_seek_output(ctx, out, plane_inc, SEEK_CUR);
+ }
for (y = 0; y < band_height; y++)
{
for (x = 0; x < w; x++)
@@ -264,25 +297,51 @@ psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_st
sp += n;
if (b == buffer_end)
{
- if (k >= num_additive)
- psd_invert_buffer(buffer, sizeof(buffer));
fz_write_data(ctx, out, buffer, sizeof(buffer));
b = buffer;
}
}
sp += line_skip;
}
- sp -= stride * band_height - 1;
if (b != buffer)
{
- if (k >= num_additive)
- psd_invert_buffer(buffer, sizeof(buffer));
fz_write_data(ctx, out, buffer, b - buffer);
b = buffer;
}
fz_seek_output(ctx, out, plane_inc, SEEK_CUR);
}
- fz_seek_output(ctx, out, w * h * (1-n), SEEK_CUR);
+ else
+ {
+ for (k = 0; k < n; k++)
+ {
+ for (y = 0; y < band_height; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *b++ = *sp;
+ sp += n;
+ if (b == buffer_end)
+ {
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
+ fz_write_data(ctx, out, buffer, sizeof(buffer));
+ b = buffer;
+ }
+ }
+ sp += line_skip;
+ }
+ sp -= stride * band_height - 1;
+ if (b != buffer)
+ {
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
+ fz_write_data(ctx, out, buffer, b - buffer);
+ b = buffer;
+ }
+ fz_seek_output(ctx, out, plane_inc, SEEK_CUR);
+ }
+ }
+ fz_seek_output(ctx, out, w * (band_height - h * n), SEEK_CUR);
}
static void
diff --git a/source/fitz/output-tga.c b/source/fitz/output-tga.c
index 3bee3640..0e7a213c 100644
--- a/source/fitz/output-tga.c
+++ b/source/fitz/output-tga.c
@@ -13,19 +13,22 @@ typedef struct {
static inline void tga_put_pixel(fz_context *ctx, fz_output *out, const unsigned char *data, int n, int is_bgr)
{
+ int a, inva;
switch(n)
{
case 4: /* RGBA or BGRA */
+ a = data[3];
+ inva = a ? 256 * 255 / a : 0;
if (!is_bgr) {
- fz_write_byte(ctx, out, data[2]);
- fz_write_byte(ctx, out, data[1]);
- fz_write_byte(ctx, out, data[0]);
+ fz_write_byte(ctx, out, (data[2] * inva + 128)>>8);
+ fz_write_byte(ctx, out, (data[1] * inva + 128)>>8);
+ fz_write_byte(ctx, out, (data[0] * inva + 128)>>8);
} else {
- fz_write_byte(ctx, out, data[0]);
- fz_write_byte(ctx, out, data[1]);
- fz_write_byte(ctx, out, data[2]);
+ fz_write_byte(ctx, out, (data[0] * inva + 128)>>8);
+ fz_write_byte(ctx, out, (data[1] * inva + 128)>>8);
+ fz_write_byte(ctx, out, (data[2] * inva + 128)>>8);
}
- fz_write_byte(ctx, out, data[3]);
+ fz_write_byte(ctx, out, a);
break;
case 3: /* RGB or BGR */
if (!is_bgr) {
@@ -39,10 +42,13 @@ static inline void tga_put_pixel(fz_context *ctx, fz_output *out, const unsigned
}
break;
case 2: /* GA */
- fz_write_byte(ctx, out, data[0]);
- fz_write_byte(ctx, out, data[0]);
- fz_write_byte(ctx, out, data[0]);
- fz_write_byte(ctx, out, data[1]);
+ a = data[1];
+ inva = a ? 256 * 255 / a : 0;
+ inva = (data[0] * inva + 128)>>8;
+ fz_write_byte(ctx, out, inva);
+ fz_write_byte(ctx, out, inva);
+ fz_write_byte(ctx, out, inva);
+ fz_write_byte(ctx, out, a);
break;
case 1: /* G */
fz_write_byte(ctx, out, data[0]);
diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c
index e2322266..9477919e 100644
--- a/source/tools/mudraw.c
+++ b/source/tools/mudraw.c
@@ -490,9 +490,6 @@ static void drawband(fz_context *ctx, fz_page *page, fz_display_list *list, cons
if (gamma_value != 1)
fz_gamma_pixmap(ctx, pix, gamma_value);
- if (pix->alpha)
- fz_unmultiply_pixmap(ctx, pix);
-
if (((output_format == OUT_PCL || output_format == OUT_PWG) && out_cs == CS_MONO) || (output_format == OUT_PBM) || (output_format == OUT_PKM))
*bit = fz_new_bitmap_from_pixmap_band(ctx, pix, NULL, band_start);
}