summaryrefslogtreecommitdiff
path: root/fitz/res_pixmap.c
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2010-07-15 14:35:34 +0000
committerTor Andersson <tor@ghostscript.com>2010-07-15 14:35:34 +0000
commit53237faa9e4a81794180a9a5d9c922d0af808d24 (patch)
treea6ae802355aaf211e7d5362ba829ab88fa36cb21 /fitz/res_pixmap.c
parent4520fd49b5cfd3b2796b374a2251f031b21f7008 (diff)
downloadmupdf-53237faa9e4a81794180a9a5d9c922d0af808d24.tar.xz
Add pixmap writing functions for PNM, PAM and PNG (without libpng) formats.
Diffstat (limited to 'fitz/res_pixmap.c')
-rw-r--r--fitz/res_pixmap.c269
1 files changed, 183 insertions, 86 deletions
diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c
index c6a299f9..ed596d7b 100644
--- a/fitz/res_pixmap.c
+++ b/fitz/res_pixmap.c
@@ -72,116 +72,213 @@ fz_gammapixmap(fz_pixmap *pix, float gamma)
}
}
-void
-fz_debugpixmap(fz_pixmap *pix, char *prefix)
+/*
+ * Write pixmap to PNM file (without alpha channel)
+ */
+
+fz_error
+fz_writepnm(fz_pixmap *pixmap, char *filename)
{
- static int counter = 0;
- char colorname[40];
- char alphaname[40];
- FILE *color = NULL;
- FILE *alpha = NULL;
- int x, y;
+ FILE *fp;
+ unsigned char *p;
+ int len;
- sprintf(alphaname, "%s-%04d-alpha.pgm", prefix, counter);
- alpha = fopen(alphaname, "wb");
- if (!alpha)
- goto cleanup;
+ if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
+ return fz_throw("pixmap must be grayscale or rgb to write as pnm");
- fprintf(stderr, "saving debug pixmap %s-%04d (%s)\n", prefix, counter, pix->colorspace->name);
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
- if (pix->n > 1)
- {
- if (pix->n > 2)
- sprintf(colorname, "%s-%04d-color.ppm", prefix, counter);
- else
- sprintf(colorname, "%s-%04d-color.pgm", prefix, counter);
-
- color = fopen(colorname, "wb");
- if (!color)
- goto cleanup;
- }
+ if (pixmap->n == 1 || pixmap->n == 2)
+ fprintf(fp, "P5\n");
+ if (pixmap->n == 4)
+ fprintf(fp, "P6\n");
+ fprintf(fp, "%d %d\n", pixmap->w, pixmap->h);
+ fprintf(fp, "255\n");
- counter ++;
+ len = pixmap->w * pixmap->h;
+ p = pixmap->samples;
- if (pix->n == 5)
+ switch (pixmap->n)
{
- fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h);
- fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h);
-
- for (y = 0; y < pix->h; y++)
+ case 1:
+ fwrite(p, 1, len, fp);
+ break;
+ case 2:
+ while (len--)
{
- for (x = 0; x < pix->w; x++)
- {
- int cc = pix->samples[x * pix->n + y * pix->w * pix->n + 0];
- int mm = pix->samples[x * pix->n + y * pix->w * pix->n + 1];
- int yy = pix->samples[x * pix->n + y * pix->w * pix->n + 2];
- int kk = pix->samples[x * pix->n + y * pix->w * pix->n + 3];
- int a = pix->samples[x * pix->n + y * pix->w * pix->n + 4];
- int r = 255 - MIN(cc + kk, 255);
- int g = 255 - MIN(mm + kk, 255);
- int b = 255 - MIN(yy + kk, 255);
- fputc(a, alpha);
- fputc(r, color);
- fputc(g, color);
- fputc(b, color);
- }
+ putc(p[0], fp);
+ p += 2;
+ }
+ break;
+ case 4:
+ while (len--)
+ {
+ putc(p[0], fp);
+ putc(p[1], fp);
+ putc(p[2], fp);
+ p += 4;
}
}
- else if (pix->n == 4)
- {
- fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h);
- fprintf(color, "P6\n%d %d\n255\n", pix->w, pix->h);
+ fclose(fp);
+ return fz_okay;
+}
- for (y = 0; y < pix->h; y++)
- {
- for (x = 0; x < pix->w; x++)
- {
- int r = pix->samples[x * pix->n + y * pix->w * pix->n + 0];
- int g = pix->samples[x * pix->n + y * pix->w * pix->n + 1];
- int b = pix->samples[x * pix->n + y * pix->w * pix->n + 2];
- int a = pix->samples[x * pix->n + y * pix->w * pix->n + 3];
- fputc(a, alpha);
- fputc(r, color);
- fputc(g, color);
- fputc(b, color);
- }
- }
+/*
+ * Write pixmap to PAM file (with alpha channel)
+ */
+
+fz_error
+fz_writepam(fz_pixmap *pixmap, char *filename)
+{
+ FILE *fp;
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
+
+ fprintf(fp, "P7\n");
+ fprintf(fp, "WIDTH %d\n", pixmap->w);
+ fprintf(fp, "HEGIHT %d\n", pixmap->h);
+ fprintf(fp, "DEPTH %d\n", pixmap->n);
+ fprintf(fp, "MAXVAL 255\n");
+ switch (pixmap->n)
+ {
+ case 1: fprintf(fp, "TUPLTYPE GRAYSCALE\n"); break;
+ case 2: fprintf(fp, "TUPLTYPE GRAYSCALE_ALPHA\n"); break;
+ case 4: fprintf(fp, "TUPLTYPE RGB_ALPHA\n"); break;
+ case 5: fprintf(fp, "TUPLTYPE CMYK_ALPHA\n"); break;
}
+ fprintf(fp, "ENDHDR\n");
+
+ fwrite(pixmap->samples, pixmap->w * pixmap->n, pixmap->h, fp);
+
+ fclose(fp);
+
+ return fz_okay;
+}
+
+/*
+ * Write pixmap to PNG file (with or without alpha channel)
+ */
+
+#include <zlib.h>
- else if (pix->n == 2)
+static inline void big32(unsigned char *buf, unsigned int v)
+{
+ buf[0] = (v >> 24) & 0xff;
+ buf[1] = (v >> 16) & 0xff;
+ buf[2] = (v >> 8) & 0xff;
+ buf[3] = (v) & 0xff;
+}
+
+static inline void put32(unsigned int v, FILE *fp)
+{
+ putc(v >> 24, fp);
+ putc(v >> 16, fp);
+ putc(v >> 8, fp);
+ putc(v, fp);
+}
+
+static void putchunk(char *tag, unsigned char *data, int size, FILE *fp)
+{
+ unsigned int sum;
+ put32(size, fp);
+ fwrite(tag, 1, 4, fp);
+ fwrite(data, 1, size, fp);
+ sum = crc32(0, NULL, 0);
+ sum = crc32(sum, (unsigned char*)tag, 4);
+ sum = crc32(sum, data, size);
+ put32(sum, fp);
+}
+
+fz_error
+fz_writepng(fz_pixmap *pixmap, char *filename, int alpha)
+{
+ static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
+ FILE *fp;
+ unsigned char head[13];
+ unsigned char *udata, *cdata, *sp, *dp;
+ uLong usize, csize;
+ int y, x, k, sn, dn;
+ int color;
+ int err;
+
+ if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
+ return fz_throw("pixmap must be grayscale or rgb to write as png");
+
+ sn = pixmap->n;
+ dn = pixmap->n;
+ if (!alpha && dn > 1)
+ dn--;
+
+ switch (dn)
{
- fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h);
- fprintf(color, "P5\n%d %d\n255\n", pix->w, pix->h);
+ default:
+ case 1: color = 0; break;
+ case 2: color = 4; break;
+ case 3: color = 2; break;
+ case 4: color = 6; break;
+ }
+
+ usize = (pixmap->w * dn + 1) * pixmap->h;
+ csize = compressBound(usize);
+ udata = fz_malloc(usize);
+ cdata = fz_malloc(csize);
- for (y = 0; y < pix->h; y++)
+ sp = pixmap->samples;
+ dp = udata;
+ for (y = 0; y < pixmap->h; y++)
+ {
+ *dp++ = 1; /* sub prediction filter */
+ for (x = 0; x < pixmap->w; x++)
{
- for (x = 0; x < pix->w; x++)
+ for (k = 0; k < dn; k++)
{
- int g = pix->samples[x * pix->n + y * pix->w * pix->n + 0];
- int a = pix->samples[x * pix->n + y * pix->w * pix->n + 1];
- fputc(a, alpha);
- fputc(g, color);
+ if (x == 0)
+ dp[k] = sp[k];
+ else
+ dp[k] = sp[k] - sp[k-sn];
}
+ sp += sn;
+ dp += dn;
}
}
- else if (pix->n == 1)
+ err = compress(cdata, &csize, udata, usize);
+ if (err != Z_OK)
{
- fprintf(alpha, "P5\n%d %d\n255\n", pix->w, pix->h);
+ fz_free(udata);
+ fz_free(cdata);
+ return fz_throw("cannot compress image data");
+ }
- for (y = 0; y < pix->h; y++)
- {
- for (x = 0; x < pix->w; x++)
- {
- int g = pix->samples[x * pix->n + y * pix->w * pix->n + 0];
- fputc(g, alpha);
- }
- }
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ {
+ fz_free(udata);
+ fz_free(cdata);
+ return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
}
-cleanup:
- if (alpha) fclose(alpha);
- if (color) fclose(color);
-}
+ big32(head+0, pixmap->w);
+ big32(head+4, pixmap->h);
+ head[8] = 8; /* depth */
+ head[9] = color;
+ head[10] = 0; /* compression */
+ head[11] = 0; /* filter */
+ head[12] = 0; /* interlace */
+
+ fwrite(pngsig, 1, 8, fp);
+ putchunk("IHDR", head, 13, fp);
+ putchunk("IDAT", cdata, csize, fp);
+ putchunk("IEND", head, 0, fp);
+ fclose(fp);
+ fz_free(udata);
+ fz_free(cdata);
+ return fz_okay;
+}