PNM loader: add read support for PAM #3

Closed
goulash-lover wants to merge 1 commits from goulash-lover:PAM-support into master
1 changed files with 388 additions and 136 deletions

View File

@ -3,11 +3,17 @@
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#define DBG_PFX "LDR-pnm"
static const char *const _formats[] = { "pnm", "ppm", "pgm", "pbm", "pam" };
typedef enum
{ BW_RAW_PACKED, BW_RAW, BW_PLAIN, GRAY_RAW, GRAY_PLAIN, RGB_RAW, RGB_PLAIN,
XV332
} px_type;
static struct {
const unsigned char *data, *dptr;
unsigned int size;
@ -78,6 +84,7 @@ mm_getu(unsigned int *pui)
bool comment;
/* Strip whitespace and comments */
for (comment = false;;)
{
ch = mm_getc();
@ -114,70 +121,202 @@ mm_getu(unsigned int *pui)
return 0; /* Ok */
}
static int
mm_parse_pam_header(unsigned *w, unsigned *h, unsigned *v, px_type * pxt,
char *alpha)
{
char tuple_type[32] = { 0 };
unsigned tti = 0, d;
for (int ch;;)
{
if ((ch = mm_getc()) == -1)
return -1;
if (ch == '#')
{
do
{
if ((ch = mm_getc()) == -1)
return -1;
}
while (ch != '\n');
}
else
{
char key[9] = { 0 }; /* max key size per spec: 8 */
for (unsigned ki = 0; !isspace(ch) && ki < sizeof(key) - 1; ++ki)
{
key[ki] = (char)ch;
if ((ch = mm_getc()) == -1)
return -1;
}
if (!strcmp(key, "ENDHDR"))
break;
unsigned int *p = NULL;
if (!strcmp(key, "HEIGHT"))
p = h;
else if (!strcmp(key, "WIDTH"))
p = w;
else if (!strcmp(key, "DEPTH"))
p = &d;
else if (!strcmp(key, "MAXVAL"))
p = v;
else if (!strcmp(key, "TUPLTYPE"))
{
while (isspace(ch))
{
if ((ch = mm_getc()) == -1)
return -1;
}
if (tti != 0) /* not the first TUPLE_TYPE header */
{
if (tti < sizeof(tuple_type) - 1)
tuple_type[tti++] = ' ';
}
while (ch != '\n' && tti < sizeof(tuple_type) - 1)
{
tuple_type[tti++] = ch;
if ((ch = mm_getc()) == -1)
return -1;
}
}
else /* unknown header */
{
}
if (p)
{
if (mm_getu(p) == -1)
return -1;
}
}
}
*alpha = (tti >= 6 && !strcmp(tuple_type + tti - 6, "_ALPHA"));
if (!strncmp(tuple_type, "BLACKANDWHITE", 13))
{
*pxt = BW_RAW;
/* assert(d == *alpha + 1);
* assert(*v == 1); */
}
else if (!strncmp(tuple_type, "GRAYSCALE", 9))
{
*pxt = GRAY_RAW;
/* assert(d == *alpha + 1); */
}
else if (!strncmp(tuple_type, "RGB", 3))
{
*pxt = RGB_RAW;
/* assert(d == *alpha + 3); */
}
else /* unknown tuple type */
{
return -1;
}
return 0;
}
static int
_load(ImlibImage * im, int load_data)
{
int rc;
int c, p;
int w, h, v, numbers, count;
int p;
unsigned int w, h, v, hlen;
uint8_t *data = NULL; /* for the binary versions */
uint8_t *ptr = NULL;
int *idata = NULL; /* for the ASCII versions */
uint32_t *ptr2, rval, gval, bval;
int i, j, x, y;
unsigned i, j, x, y;
px_type pxt;
rc = LOAD_FAIL;
mm_init(im->fi->fdata, im->fi->fsize);
/* read the header info */
c = mm_getc();
if (c != 'P')
if (mm_getc() != 'P')
goto quit;
numbers = 3;
p = mm_getc();
if (p == '1' || p == '4')
numbers = 2; /* bitimages don't have max value */
if ((p < '1') || (p > '8'))
goto quit;
/* read numbers */
w = h = 0;
v = 255;
for (count = i = 0; count < numbers; i++)
hlen = 3;
switch (p)
{
if (mm_getu(&gval))
goto quit;
if (p == '7' && i == 0)
case '1':
pxt = BW_PLAIN;
hlen = 2;
break;
case '2':
pxt = GRAY_PLAIN;
break;
case '3':
pxt = RGB_PLAIN;
break;
case '4':
pxt = BW_RAW_PACKED;
hlen = 2;
break;
case '5':
pxt = GRAY_RAW;
break;
case '6':
pxt = RGB_RAW;
break;
case '7':
if (mm_getc() != '\n')
{
if (gval != 332)
if (mm_getu(&gval) || gval != 332) /* XV thumbnail format */
goto quit;
else
continue;
pxt = XV332;
}
count++;
switch (count)
else
{
case 1: /* width */
w = gval;
break;
case 2: /* height */
h = gval;
break;
case 3: /* max value, only for color and greyscale */
v = gval;
break;
if (mm_parse_pam_header(&w, &h, &v, &pxt, &im->has_alpha))
goto quit;
hlen = 0;
}
break;
case '8': /* not in netpbm, unknown format provenance (Imlib2 specific?) */
pxt = RGB_RAW;
im->has_alpha = 1;
break;
default:
goto quit;
}
/* read header for non-PAM formats */
if (hlen != 0)
{
w = h = 0;
v = 255;
for (i = 0; i < hlen; i++)
{
if (mm_getu(&gval))
goto quit;
switch (i)
{
case 0: /* width */
w = gval;
break;
case 1: /* height */
h = gval;
break;
case 2: /* max value, only for color and greyscale */
v = gval;
break;
}
}
}
if ((v < 0) || (v > 255))
if (v > 255)
goto quit;
D("P%c: WxH=%dx%d V=%d\n", p, w, h, v);
D("P%c: pxtype=%d WxH=%ux%u V=%u A=%s\n",
p, pxt, w, h, v, im->has_alpha ? "YES" : "NO");
rc = LOAD_BADIMAGE; /* Format accepted */
@ -186,8 +325,6 @@ _load(ImlibImage * im, int load_data)
if (!IMAGE_DIMENSIONS_OK(w, h))
goto quit;
im->has_alpha = p == '8';
if (!load_data)
QUIT_WITH_RC(LOAD_SUCCESS);
@ -198,25 +335,27 @@ _load(ImlibImage * im, int load_data)
QUIT_WITH_RC(LOAD_OOM);
/* start reading the data */
switch (p)
switch (pxt)
{
case '1': /* ASCII monochrome */
case BW_PLAIN: /* ASCII monochrome */
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
i = mm_get01();
if (i < 0)
int px = mm_get01();
if (px < 0)
goto quit;
*ptr2++ = i ? 0xff000000 : 0xffffffff;
*ptr2++ = px ? 0xff000000 : 0xffffffff;
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
break;
case '2': /* ASCII greyscale */
case GRAY_PLAIN: /* ASCII greyscale */
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
@ -231,7 +370,8 @@ _load(ImlibImage * im, int load_data)
else
{
*ptr2++ =
0xff000000 | (((gval * 255) / v) << 16) |
0xff000000 |
(((gval * 255) / v) << 16) |
(((gval * 255) / v) << 8) | ((gval * 255) / v);
}
}
@ -240,7 +380,8 @@ _load(ImlibImage * im, int load_data)
goto quit_progress;
}
break;
case '3': /* ASCII RGB */
case RGB_PLAIN: /* ASCII RGB */
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
@ -269,7 +410,8 @@ _load(ImlibImage * im, int load_data)
goto quit_progress;
}
break;
case '4': /* binary 1bit monochrome */
case BW_RAW_PACKED: /* binary 1bit monochrome */
data = malloc((w + 7) / 8 * sizeof(uint8_t));
if (!data)
QUIT_WITH_RC(LOAD_OOM);
@ -299,36 +441,49 @@ _load(ImlibImage * im, int load_data)
goto quit_progress;
}
break;
case '5': /* binary 8bit grayscale GGGGGGGG */
data = malloc(1 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
case BW_RAW: /* binary 1byte monochrome */
if (im->has_alpha)
{
if (mm_read(data, w * 1))
goto quit;
data = malloc(2 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr = data;
if (v == 0 || v == 255)
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 2))
goto quit;
ptr = data;
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 | (ptr[0] << 16) | (ptr[0] << 8) | ptr[0];
(ptr[1] ? 0xff000000 : 0) | (ptr[0] ? 0xffffff : 0);
ptr2++;
ptr++;
ptr += 2;
}
}
else
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
else
{
data = malloc(1 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 1))
goto quit;
ptr = data;
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 |
(((ptr[0] * 255) / v) << 16) |
(((ptr[0] * 255) / v) << 8) | ((ptr[0] * 255) / v);
*ptr2 = 0xff000000 | (ptr[0] ? 0xffffff : 0);
ptr2++;
ptr++;
}
@ -338,46 +493,180 @@ _load(ImlibImage * im, int load_data)
goto quit_progress;
}
break;
case '6': /* 24bit binary RGBRGBRGB */
data = malloc(3 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
case GRAY_RAW: /* binary 8bit grayscale GGGGGGGG */
if (im->has_alpha)
{
if (mm_read(data, w * 3))
goto quit;
data = malloc(2 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr = data;
if (v == 0 || v == 255)
ptr2 = im->data;
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 | (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
ptr2++;
ptr += 3;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 |
(((ptr[0] * 255) / v) << 16) |
(((ptr[1] * 255) / v) << 8) | ((ptr[2] * 255) / v);
ptr2++;
ptr += 3;
}
}
if (mm_read(data, w * 2))
goto quit;
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
ptr = data;
if (v == 0 || v == 255)
{
for (x = 0; x < w; x++)
{
*ptr2 =
(ptr[1] << 24) | (ptr[0] << 16) | (ptr[0] << 8) |
ptr[0];
ptr2++;
ptr += 2;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
(((ptr[1] * 255) / v) << 24) |
(((ptr[0] * 255) / v) << 16) |
(((ptr[0] * 255) / v) << 8) | ((ptr[0] * 255) /
v);
ptr2++;
ptr += 2;
}
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
}
else
{
data = malloc(1 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 1))
goto quit;
ptr = data;
if (v == 0 || v == 255)
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 | (ptr[0] << 16) | (ptr[0] << 8) |
ptr[0];
ptr2++;
ptr++;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 |
(((ptr[0] * 255) / v) << 16) |
(((ptr[0] * 255) / v) << 8) | ((ptr[0] * 255) /
v);
ptr2++;
ptr++;
}
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
}
break;
case '7': /* XV's 8bit 332 format */
case RGB_RAW: /* 24bit binary RGBRGBRGB */
if (im->has_alpha)
{
data = malloc(4 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 4))
goto quit;
ptr = data;
if (v == 0 || v == 255)
{
for (x = 0; x < w; x++)
{
*ptr2 = PIXEL_ARGB(ptr[3], ptr[0], ptr[1], ptr[2]);
ptr2++;
ptr += 4;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
PIXEL_ARGB((ptr[3] * 255) / v,
(ptr[0] * 255) / v,
(ptr[1] * 255) / v,
(ptr[2] * 255) / v);
ptr2++;
ptr += 4;
}
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
}
else
{
data = malloc(3 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 3))
goto quit;
ptr = data;
if (v == 0 || v == 255)
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 | (ptr[0] << 16) | (ptr[1] << 8) |
ptr[2];
ptr2++;
ptr += 3;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
0xff000000 |
(((ptr[0] * 255) / v) << 16) |
(((ptr[1] * 255) / v) << 8) | ((ptr[2] * 255) /
v);
ptr2++;
ptr += 3;
}
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
}
break;
case XV332: /* XV's 8bit 332 format */
data = malloc(1 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
@ -409,44 +698,7 @@ _load(ImlibImage * im, int load_data)
goto quit_progress;
}
break;
case '8': /* 24bit binary RGBARGBARGBA */
data = malloc(4 * sizeof(uint8_t) * w);
if (!data)
QUIT_WITH_RC(LOAD_OOM);
ptr2 = im->data;
for (y = 0; y < h; y++)
{
if (mm_read(data, w * 4))
goto quit;
ptr = data;
if (v == 0 || v == 255)
{
for (x = 0; x < w; x++)
{
*ptr2 = PIXEL_ARGB(ptr[3], ptr[0], ptr[1], ptr[2]);
ptr2++;
ptr += 4;
}
}
else
{
for (x = 0; x < w; x++)
{
*ptr2 =
PIXEL_ARGB((ptr[3] * 255) / v,
(ptr[0] * 255) / v,
(ptr[1] * 255) / v, (ptr[2] * 255) / v);
ptr2++;
ptr += 4;
}
}
if (im->lc && __imlib_LoadProgressRows(im, y, 1))
goto quit_progress;
}
break;
default:
goto quit;
quit_progress: