summaryrefslogtreecommitdiff
path: root/Build/source/libs/potrace/potrace-src/src/greymap.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/potrace/potrace-src/src/greymap.c')
-rw-r--r--Build/source/libs/potrace/potrace-src/src/greymap.c238
1 files changed, 187 insertions, 51 deletions
diff --git a/Build/source/libs/potrace/potrace-src/src/greymap.c b/Build/source/libs/potrace/potrace-src/src/greymap.c
index ad8e5d7e303..785774dd8da 100644
--- a/Build/source/libs/potrace/potrace-src/src/greymap.c
+++ b/Build/source/libs/potrace/potrace-src/src/greymap.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
+/* Copyright (C) 2001-2017 Peter Selinger.
This file is part of Potrace. It is free software and it is covered
by the GNU General Public License. See the file COPYING for details. */
@@ -26,39 +26,79 @@
static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
+#define TRY(x) if (x) goto try_error
+#define TRY_EOF(x) if (x) goto eof
+#define TRY_STD(x) if (x) goto std_error
+
/* ---------------------------------------------------------------------- */
/* basic greymap routines */
-/* return new un-initialized greymap. NULL with errno on error.
+/* calculate the size, in bytes, required for the data area of a
+ greymap of the given dy and h. Assume h >= 0. Return -1 if the size
+ does not fit into the ptrdiff_t type. */
+static inline ptrdiff_t getsize(int dy, int h) {
+ ptrdiff_t size;
+
+ if (dy < 0) {
+ dy = -dy;
+ }
+
+ size = (ptrdiff_t)dy * (ptrdiff_t)h * (ptrdiff_t)sizeof(gm_sample_t);
+
+ /* check for overflow error */
+ if (size < 0 || (h != 0 && dy != 0 && size / h / dy != sizeof(gm_sample_t))) {
+ return -1;
+ }
+
+ return size;
+}
+
+/* return the size, in bytes, of the data area of the greymap. Return
+ -1 if the size does not fit into the ptrdiff_t type; however, this
+ cannot happen if the bitmap is well-formed, i.e., if created with
+ gm_new or gm_dup. */
+static inline ptrdiff_t gm_size(const greymap_t *gm) {
+ return getsize(gm->dy, gm->h);
+}
+
+
+
+/* return new greymap initialized to 0. NULL with errno on error.
Assumes w, h >= 0. */
greymap_t *gm_new(int w, int h) {
greymap_t *gm;
- ptrdiff_t size = (ptrdiff_t)w * (ptrdiff_t)h * (ptrdiff_t)sizeof(signed short int);
-
- /* check for overflow error */
- if (size < 0 || size / w / h != sizeof(signed short int)) {
+ int dy = w;
+ ptrdiff_t size;
+
+ size = getsize(dy, h);
+ if (size < 0) {
errno = ENOMEM;
return NULL;
}
-
+ if (size == 0) {
+ size = 1; /* make surecmalloc() doesn't return NULL */
+ }
+
gm = (greymap_t *) malloc(sizeof(greymap_t));
if (!gm) {
return NULL;
}
gm->w = w;
gm->h = h;
- gm->map = (signed short int *) malloc(size);
- if (!gm->map) {
+ gm->dy = dy;
+ gm->base = (gm_sample_t *) calloc(1, size);
+ if (!gm->base) {
free(gm);
return NULL;
}
+ gm->map = gm->base;
return gm;
}
/* free the given greymap */
void gm_free(greymap_t *gm) {
if (gm) {
- free(gm->map);
+ free(gm->base);
}
free(gm);
}
@@ -66,26 +106,91 @@ void gm_free(greymap_t *gm) {
/* duplicate the given greymap. Return NULL on error with errno set. */
greymap_t *gm_dup(greymap_t *gm) {
greymap_t *gm1 = gm_new(gm->w, gm->h);
+ int y;
+
if (!gm1) {
return NULL;
}
- memcpy(gm1->map, gm->map, gm->w*gm->h*sizeof(signed short int));
+ for (y=0; y<gm->h; y++) {
+ memcpy(gm_scanline(gm1, y), gm_scanline(gm, y), (size_t)gm1->dy * sizeof(gm_sample_t));
+ }
return gm1;
}
/* clear the given greymap to color b. */
void gm_clear(greymap_t *gm, int b) {
- int i;
-
+ ptrdiff_t size = gm_size(gm);
+ int x, y;
+
if (b==0) {
- memset(gm->map, 0, gm->w*gm->h*sizeof(signed short int));
+ memset(gm->base, 0, size);
} else {
- for (i=0; i<gm->w*gm->h; i++) {
- gm->map[i] = b;
+ for (y=0; y<gm->h; y++) {
+ for (x=0; x<gm->w; x++) {
+ GM_UPUT(gm, x, y, b);
+ }
}
- }
+ }
+}
+
+/* turn the given greymap upside down. This does not move the pixel
+ data or change the base address. */
+static inline void gm_flip(greymap_t *gm) {
+ int dy = gm->dy;
+
+ if (gm->h == 0 || gm->h == 1) {
+ return;
+ }
+
+ gm->map = gm_scanline(gm, gm->h - 1);
+ gm->dy = -dy;
+}
+
+/* resize the greymap to the given new height. The pixel data remains
+ bottom-aligned (truncated at the top) when dy >= 0 and top-aligned
+ (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on
+ error with errno set. If the new height is <= the old one, no error
+ should occur. If the new height is larger, the additional pixel
+ data is *not* initialized. */
+static inline int gm_resize(greymap_t *gm, int h) {
+ int dy = gm->dy;
+ ptrdiff_t newsize;
+ gm_sample_t *newbase;
+
+ if (dy < 0) {
+ gm_flip(gm);
+ }
+
+ newsize = getsize(dy, h);
+ if (newsize < 0) {
+ errno = ENOMEM;
+ goto error;
+ }
+ if (newsize == 0) {
+ newsize = 1; /* make sure realloc() doesn't return NULL */
+ }
+
+ newbase = (gm_sample_t *)realloc(gm->base, newsize);
+ if (newbase == NULL) {
+ goto error;
+ }
+ gm->base = newbase;
+ gm->map = newbase;
+ gm->h = h;
+
+ if (dy < 0) {
+ gm_flip(gm);
+ }
+ return 0;
+
+ error:
+ if (dy < 0) {
+ gm_flip(gm);
+ }
+ return 1;
}
+
/* ---------------------------------------------------------------------- */
/* routines for reading pnm streams */
@@ -178,7 +283,7 @@ static int readbit(FILE *f) {
-4 if wrong magic number. If the return value is >=0, *gmp is
valid. */
-char *gm_read_error = NULL;
+const char *gm_read_error = NULL;
int gm_read(FILE *f, greymap_t **gmp) {
int magic[2];
@@ -212,7 +317,9 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
int x, y, i, j, b, b1, sum;
int bpr; /* bytes per row (as opposed to 4*gm->c) */
int w, h, max;
-
+ int realheight; /* in case of incomplete file, keeps track of how
+ many scan lines actually contain data */
+
gm = NULL;
w = readnum(f);
@@ -228,11 +335,10 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
/* allocate greymap */
gm = gm_new(w, h);
if (!gm) {
- return -1;
+ goto std_error;
}
- /* zero it out */
- gm_clear(gm, 0);
+ realheight = 0;
switch (magic) {
default:
@@ -242,7 +348,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
case '1':
/* read P1 format: PBM ascii */
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (x=0; x<w; x++) {
b = readbit(f);
if (b<0) {
@@ -261,7 +368,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
goto format_error;
}
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (x=0; x<w; x++) {
b = readnum(f);
if (b<0) {
@@ -280,7 +388,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
goto format_error;
}
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (x=0; x<w; x++) {
sum = 0;
for (i=0; i<3; i++) {
@@ -305,7 +414,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
bpr = (w+7)/8;
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (i=0; i<bpr; i++) {
b = fgetc(f);
if (b==EOF) {
@@ -331,7 +441,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
goto format_error;
}
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (x=0; x<w; x++) {
b = fgetc(f);
if (b==EOF)
@@ -361,7 +472,8 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
goto format_error;
}
- for (y=h-1; y>=0; y--) {
+ for (y=0; y<h; y++) {
+ realheight = y+1;
for (x=0; x<w; x++) {
sum = 0;
for (i=0; i<3; i++) {
@@ -384,10 +496,13 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
break;
}
+ gm_flip(gm);
*gmp = gm;
return 0;
eof:
+ TRY_STD(gm_resize(gm, realheight));
+ gm_flip(gm);
*gmp = gm;
return 1;
@@ -401,6 +516,10 @@ static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
gm_read_error = "invalid ppm file";
}
return -2;
+
+ std_error:
+ gm_free(gm);
+ return -1;
}
/* ---------------------------------------------------------------------- */
@@ -447,7 +566,7 @@ static int bmp_readint(FILE *f, int n, unsigned int *p) {
if (b==EOF) {
return 1;
}
- sum += b << (8*i);
+ sum += (unsigned)b << (8*i);
}
bmp_count += n;
bmp_pos += n;
@@ -492,11 +611,8 @@ static int bmp_forward(FILE *f, int pos) {
return 0;
}
-#define TRY(x) if (x) goto try_error
-#define TRY_EOF(x) if (x) goto eof
-
-/* correct y-coordinate for top-down format */
-#define ycorr(y) (bmpinfo.topdown ? bmpinfo.h-1-y : y)
+/* safe colortable access */
+#define COLTABLE(c) ((c) < bmpinfo.ncolors ? coltable[(c)] : 0)
/* read BMP stream after magic number. Return values as for gm_read.
We choose to be as permissive as possible, since there are many
@@ -516,6 +632,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
unsigned int bitbuf;
unsigned int n;
unsigned int redshift, greenshift, blueshift;
+ int realheight; /* in case of incomplete file, keeps track of how
+ many scan lines actually contain data */
gm_read_error = NULL;
gm = NULL;
@@ -581,6 +699,10 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
goto format_error;
}
+ if (bmpinfo.comp > 3 || bmpinfo.bits > 32) {
+ goto format_error;
+ }
+
/* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
@@ -589,7 +711,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
goto format_error; /* can't handle planes */
}
- if (bmpinfo.ncolors == 0) {
+ if (bmpinfo.ncolors == 0 && bmpinfo.bits <= 8) {
bmpinfo.ncolors = 1 << bmpinfo.bits;
}
@@ -618,10 +740,9 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if (!gm) {
goto std_error;
}
-
- /* zero it out */
- gm_clear(gm, 0);
+ realheight = 0;
+
switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
default:
@@ -632,11 +753,12 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
/* raster data */
for (y=0; y<bmpinfo.h; y++) {
+ realheight = y+1;
bmp_pad_reset();
for (i=0; 8*i<bmpinfo.w; i++) {
TRY_EOF(bmp_readint(f, 1, &b));
for (j=0; j<8; j++) {
- GM_PUT(gm, i*8+j, ycorr(y), b & (0x80 >> j) ? coltable[1] : coltable[0]);
+ GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? COLTABLE(1) : COLTABLE(0));
}
}
TRY(bmp_pad(f));
@@ -651,6 +773,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
case 0x007:
case 0x008:
for (y=0; y<bmpinfo.h; y++) {
+ realheight = y+1;
bmp_pad_reset();
bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
n = 0; /* number of bits currently in bitbuffer */
@@ -663,7 +786,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
b = bitbuf >> (INTBITS - bmpinfo.bits);
bitbuf <<= bmpinfo.bits;
n -= bmpinfo.bits;
- GM_UPUT(gm, x, ycorr(y), coltable[b]);
+ GM_UPUT(gm, x, y, COLTABLE(b));
}
TRY(bmp_pad(f));
}
@@ -679,11 +802,12 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
case 0x018: /* 24-bit encoding */
case 0x020: /* 32-bit encoding */
for (y=0; y<bmpinfo.h; y++) {
+ realheight = y+1;
bmp_pad_reset();
for (x=0; x<bmpinfo.w; x++) {
TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
- GM_UPUT(gm, x, ycorr(y), c/3);
+ GM_UPUT(gm, x, y, c/3);
}
TRY(bmp_pad(f));
}
@@ -695,11 +819,12 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
blueshift = lobit(bmpinfo.BlueMask);
for (y=0; y<bmpinfo.h; y++) {
+ realheight = y+1;
bmp_pad_reset();
for (x=0; x<bmpinfo.w; x++) {
TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
- GM_UPUT(gm, x, ycorr(y), c/3);
+ GM_UPUT(gm, x, y, c/3);
}
TRY(bmp_pad(f));
}
@@ -713,8 +838,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
if (b>0) {
/* repeat count */
- col[0] = coltable[(c>>4) & 0xf];
- col[1] = coltable[c & 0xf];
+ col[0] = COLTABLE((c>>4) & 0xf);
+ col[1] = COLTABLE(c & 0xf);
for (i=0; i<b && x<bmpinfo.w; i++) {
if (x>=bmpinfo.w) {
x=0;
@@ -723,7 +848,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if (y>=bmpinfo.h) {
break;
}
- GM_UPUT(gm, x, ycorr(y), col[i&1]);
+ realheight = y+1;
+ GM_UPUT(gm, x, y, col[i&1]);
x++;
}
} else if (c == 0) {
@@ -752,7 +878,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if (y>=bmpinfo.h) {
break;
}
- GM_PUT(gm, x, ycorr(y), coltable[(b>>(4-4*(i&1))) & 0xf]);
+ realheight = y+1;
+ GM_PUT(gm, x, y, COLTABLE((b>>(4-4*(i&1))) & 0xf));
x++;
}
if ((c+1) & 2) {
@@ -779,7 +906,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if (y>=bmpinfo.h) {
break;
}
- GM_UPUT(gm, x, ycorr(y), coltable[c]);
+ realheight = y+1;
+ GM_UPUT(gm, x, y, COLTABLE(c));
x++;
}
} else if (c == 0) {
@@ -806,7 +934,8 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if (y>=bmpinfo.h) {
break;
}
- GM_PUT(gm, x, ycorr(y), coltable[b]);
+ realheight = y+1;
+ GM_PUT(gm, x, y, COLTABLE(b));
x++;
}
if (c & 1) {
@@ -824,18 +953,25 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
bmp_forward(f, bmpinfo.FileSize);
free(coltable);
+ if (bmpinfo.topdown) {
+ gm_flip(gm);
+ }
*gmp = gm;
return 0;
eof:
+ TRY_STD(gm_resize(gm, realheight));
free(coltable);
+ if (bmpinfo.topdown) {
+ gm_flip(gm);
+ }
*gmp = gm;
return 1;
format_error:
try_error:
free(coltable);
- free(gm);
+ gm_free(gm);
if (!gm_read_error) {
gm_read_error = "invalid bmp file";
}
@@ -843,7 +979,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
std_error:
free(coltable);
- free(gm);
+ gm_free(gm);
return -1;
}
@@ -855,7 +991,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
if any (set to 2.2 if the image is to look optimal on a CRT monitor,
2.8 for LCD). Set to 1.0 for no gamma correction */
-int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) {
+int gm_writepgm(FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma) {
int x, y, v;
int gammatable[256];