Compare commits
2 Commits
035239f5db
...
33ab27e323
Author | SHA1 | Date |
---|---|---|
Kim Woelders | 33ab27e323 | |
Kim Woelders | 13d311561d |
|
@ -1,6 +1,8 @@
|
|||
#include "config.h"
|
||||
#include "Imlib2_Loader.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DBG_PFX "LDR-xpm"
|
||||
|
||||
static const char *const _formats[] = { "xpm" };
|
||||
|
@ -32,19 +34,19 @@ mm_getc(void)
|
|||
|
||||
static FILE *rgb_txt = NULL;
|
||||
|
||||
static void
|
||||
xpm_parse_color(char *color, uint32_t *pixel)
|
||||
static uint32_t
|
||||
xpm_parse_color(const char *color)
|
||||
{
|
||||
char buf[4096];
|
||||
int r, g, b;
|
||||
char buf[256];
|
||||
int a, r, g, b;
|
||||
|
||||
a = 0xff;
|
||||
r = g = b = 0;
|
||||
|
||||
/* is a #ff00ff like color */
|
||||
if (color[0] == '#')
|
||||
{
|
||||
int len;
|
||||
char val[32];
|
||||
|
||||
len = strlen(color) - 1;
|
||||
if (len < 96)
|
||||
|
@ -53,17 +55,17 @@ xpm_parse_color(char *color, uint32_t *pixel)
|
|||
|
||||
len /= 3;
|
||||
for (i = 0; i < len; i++)
|
||||
val[i] = color[1 + i + (0 * len)];
|
||||
val[i] = 0;
|
||||
sscanf(val, "%x", &r);
|
||||
buf[i] = color[1 + i + (0 * len)];
|
||||
buf[i] = '\0';
|
||||
sscanf(buf, "%x", &r);
|
||||
for (i = 0; i < len; i++)
|
||||
val[i] = color[1 + i + (1 * len)];
|
||||
val[i] = 0;
|
||||
sscanf(val, "%x", &g);
|
||||
buf[i] = color[1 + i + (1 * len)];
|
||||
buf[i] = '\0';
|
||||
sscanf(buf, "%x", &g);
|
||||
for (i = 0; i < len; i++)
|
||||
val[i] = color[1 + i + (2 * len)];
|
||||
val[i] = 0;
|
||||
sscanf(val, "%x", &b);
|
||||
buf[i] = color[1 + i + (2 * len)];
|
||||
buf[i] = '\0';
|
||||
sscanf(buf, "%x", &b);
|
||||
if (len == 1)
|
||||
{
|
||||
r = (r << 4) | r;
|
||||
|
@ -80,6 +82,12 @@ xpm_parse_color(char *color, uint32_t *pixel)
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (!strcasecmp(color, "none"))
|
||||
{
|
||||
a = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* look in rgb txt database */
|
||||
if (!rgb_txt)
|
||||
rgb_txt = fopen(PACKAGE_DATA_DIR "/rgb.txt", "r");
|
||||
|
@ -89,12 +97,12 @@ xpm_parse_color(char *color, uint32_t *pixel)
|
|||
goto done;
|
||||
|
||||
fseek(rgb_txt, 0, SEEK_SET);
|
||||
while (fgets(buf, 4000, rgb_txt))
|
||||
while (fgets(buf, sizeof(buf), rgb_txt))
|
||||
{
|
||||
if (buf[0] != '!')
|
||||
{
|
||||
int rr, gg, bb;
|
||||
char name[4096];
|
||||
char name[256];
|
||||
|
||||
sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name);
|
||||
if (!strcasecmp(name, color))
|
||||
|
@ -106,8 +114,9 @@ xpm_parse_color(char *color, uint32_t *pixel)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
*pixel = PIXEL_ARGB(0xff, r, g, b);
|
||||
return PIXEL_ARGB(a, r, g, b);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -152,23 +161,87 @@ xpm_cmap_lookup(const cmap_t *cmap, int nc, int cpp, const char *s)
|
|||
return cmap[i1].pixel;
|
||||
}
|
||||
|
||||
static int
|
||||
xpm_parse_cmap_line(const char *line, int len, int cpp, cmap_t *cme)
|
||||
{
|
||||
char s[256], tag[256], col[256];
|
||||
int i, nr;
|
||||
bool is_tag, is_col, is_eol, hascolor;
|
||||
|
||||
if (len < cpp)
|
||||
return -1;
|
||||
|
||||
is_tag = is_col = is_eol = false;
|
||||
hascolor = false;
|
||||
tag[0] = '\0';
|
||||
col[0] = '\0';
|
||||
|
||||
strncpy(cme->str, line, cpp);
|
||||
|
||||
for (i = cpp; i < len;)
|
||||
{
|
||||
s[0] = '\0';
|
||||
nr = 0;
|
||||
sscanf(&line[i], "%255s %n", s, &nr);
|
||||
i += nr;
|
||||
is_tag = !strcmp(s, "c") || !strcmp(s, "m") || !strcmp(s, "s") ||
|
||||
!strcmp(s, "g4") || !strcmp(s, "g");
|
||||
is_eol = i >= len;
|
||||
|
||||
if (!is_tag)
|
||||
{
|
||||
/* Not tag - append to value */
|
||||
if (col[0])
|
||||
{
|
||||
if (strlen(col) < (sizeof(col) - 2))
|
||||
strcat(col, " ");
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if (strlen(col) + strlen(s) < (sizeof(col) - 1))
|
||||
strcat(col, s);
|
||||
}
|
||||
|
||||
if ((is_tag || is_eol) && col[0])
|
||||
{
|
||||
/* Next tag or end of line - process color */
|
||||
is_col = !strcmp(tag, "c");
|
||||
if ((is_col || !cme->assigned) && !hascolor)
|
||||
{
|
||||
cme->pixel = xpm_parse_color(col);
|
||||
cme->assigned = 1;
|
||||
cme->transp = cme->pixel == 0x00000000;
|
||||
if (is_col)
|
||||
hascolor = true;
|
||||
DL(" Coltbl tag='%s' col='%s' hasc=%d tr=%d %08x\n",
|
||||
tag, col, hascolor, cme->transp, cme->pixel);
|
||||
}
|
||||
|
||||
/* Starting new tag */
|
||||
strcpy(tag, s);
|
||||
col[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_load(ImlibImage *im, int load_data)
|
||||
{
|
||||
int rc;
|
||||
int rc, err;
|
||||
uint32_t *ptr;
|
||||
int pc, c, i, j, k, w, h, ncolors, cpp;
|
||||
int comment, transp, quote, context, len, done, backslash;
|
||||
char *line, s[256], tok[256], col[256];
|
||||
int pc, c, i, j, w, h, ncolors, cpp;
|
||||
int context, len;
|
||||
char *line;
|
||||
int lsz = 256;
|
||||
cmap_t *cmap;
|
||||
short lookup[128 - 32][128 - 32];
|
||||
int count, pixels;
|
||||
int last_row = 0;
|
||||
bool comment, quote, backslash, transp;
|
||||
|
||||
rc = LOAD_FAIL;
|
||||
done = 0;
|
||||
transp = -1;
|
||||
line = NULL;
|
||||
cmap = NULL;
|
||||
|
||||
|
@ -183,12 +256,12 @@ _load(ImlibImage *im, int load_data)
|
|||
j = 0;
|
||||
w = 10;
|
||||
h = 10;
|
||||
transp = false;
|
||||
ncolors = 0;
|
||||
cpp = 0;
|
||||
ptr = NULL;
|
||||
c = ' ';
|
||||
comment = 0;
|
||||
quote = 0;
|
||||
comment = quote = backslash = false;
|
||||
context = 0;
|
||||
pixels = 0;
|
||||
count = 0;
|
||||
|
@ -197,9 +270,8 @@ _load(ImlibImage *im, int load_data)
|
|||
QUIT_WITH_RC(LOAD_OOM);
|
||||
len = 0;
|
||||
|
||||
backslash = 0;
|
||||
memset(lookup, 0, sizeof(lookup));
|
||||
while (!done)
|
||||
for (;;)
|
||||
{
|
||||
pc = c;
|
||||
c = mm_getc();
|
||||
|
@ -209,237 +281,174 @@ _load(ImlibImage *im, int load_data)
|
|||
if (!quote)
|
||||
{
|
||||
if ((pc == '/') && (c == '*'))
|
||||
comment = 1;
|
||||
comment = true;
|
||||
else if ((pc == '*') && (c == '/') && (comment))
|
||||
comment = 0;
|
||||
comment = false;
|
||||
}
|
||||
|
||||
if (comment)
|
||||
continue;
|
||||
|
||||
if ((!quote) && (c == '"'))
|
||||
{
|
||||
quote = 1;
|
||||
len = 0;
|
||||
}
|
||||
else if ((quote) && (c == '"'))
|
||||
{
|
||||
line[len] = 0;
|
||||
quote = 0;
|
||||
if (context == 0)
|
||||
{
|
||||
/* Header */
|
||||
sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp);
|
||||
if ((ncolors > 32766) || (ncolors < 1))
|
||||
{
|
||||
E("XPM files with colors > 32766 or < 1 not supported\n");
|
||||
goto quit;
|
||||
}
|
||||
if ((cpp > 5) || (cpp < 1))
|
||||
{
|
||||
E("XPM files with characters per pixel > 5 or < 1 not supported\n");
|
||||
goto quit;
|
||||
}
|
||||
if (!IMAGE_DIMENSIONS_OK(w, h))
|
||||
{
|
||||
E("Invalid image dimension: %dx%d\n", w, h);
|
||||
goto quit;
|
||||
}
|
||||
im->w = w;
|
||||
im->h = h;
|
||||
|
||||
cmap = calloc(ncolors, sizeof(cmap_t));
|
||||
if (!cmap)
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
|
||||
pixels = w * h;
|
||||
|
||||
j = 0;
|
||||
context++;
|
||||
}
|
||||
else if (context == 1)
|
||||
{
|
||||
/* Color Table */
|
||||
if (j < ncolors)
|
||||
{
|
||||
int slen;
|
||||
int hascolor, iscolor;
|
||||
|
||||
iscolor = 0;
|
||||
hascolor = 0;
|
||||
tok[0] = 0;
|
||||
col[0] = 0;
|
||||
s[0] = 0;
|
||||
if (len < cpp)
|
||||
goto quit;
|
||||
strncpy(cmap[j].str, line, cpp);
|
||||
for (k = cpp; k < len; k++)
|
||||
{
|
||||
if (line[k] == ' ')
|
||||
continue;
|
||||
|
||||
s[0] = 0;
|
||||
sscanf(&line[k], "%255s", s);
|
||||
slen = strlen(s);
|
||||
k += slen;
|
||||
if (!strcmp(s, "c"))
|
||||
iscolor = 1;
|
||||
if ((!strcmp(s, "m")) || (!strcmp(s, "s")) ||
|
||||
(!strcmp(s, "g4")) || (!strcmp(s, "g")) ||
|
||||
(!strcmp(s, "c")) || (k >= len))
|
||||
{
|
||||
if (k >= len)
|
||||
{
|
||||
if (col[0])
|
||||
{
|
||||
if (strlen(col) < (sizeof(col) - 2))
|
||||
strcat(col, " ");
|
||||
else
|
||||
done = 1;
|
||||
}
|
||||
if (strlen(col) + strlen(s) < (sizeof(col) - 1))
|
||||
strcat(col, s);
|
||||
}
|
||||
if (col[0])
|
||||
{
|
||||
if (!strcasecmp(col, "none"))
|
||||
{
|
||||
cmap[j].transp = 1;
|
||||
cmap[j].pixel = 0;
|
||||
}
|
||||
else if ((!cmap[j].assigned ||
|
||||
!strcmp(tok, "c")) && (!hascolor))
|
||||
{
|
||||
xpm_parse_color(col, &cmap[j].pixel);
|
||||
cmap[j].assigned = 1;
|
||||
cmap[j].transp = 0;
|
||||
if (iscolor)
|
||||
hascolor = 1;
|
||||
}
|
||||
}
|
||||
strcpy(tok, s);
|
||||
col[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col[0])
|
||||
{
|
||||
if (strlen(col) < (sizeof(col) - 2))
|
||||
strcat(col, " ");
|
||||
else
|
||||
done = 1;
|
||||
}
|
||||
if (strlen(col) + strlen(s) < (sizeof(col) - 1))
|
||||
strcat(col, s);
|
||||
}
|
||||
}
|
||||
if (cmap[j].transp)
|
||||
transp = 1;
|
||||
}
|
||||
j++;
|
||||
if (j >= ncolors)
|
||||
{
|
||||
if (cpp == 1)
|
||||
for (i = 0; i < ncolors; i++)
|
||||
lookup[(int)cmap[i].str[0] - 32][0] = i;
|
||||
else if (cpp == 2)
|
||||
for (i = 0; i < ncolors; i++)
|
||||
lookup[(int)cmap[i].str[0] -
|
||||
32][(int)cmap[i].str[1] - 32] = i;
|
||||
else
|
||||
qsort(cmap, ncolors, sizeof(cmap_t), xpm_cmap_sort);
|
||||
context++;
|
||||
|
||||
im->has_alpha = transp >= 0;
|
||||
|
||||
if (!load_data)
|
||||
QUIT_WITH_RC(LOAD_SUCCESS);
|
||||
|
||||
ptr = __imlib_AllocateData(im);
|
||||
if (!ptr)
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Image Data */
|
||||
|
||||
if (cpp == 1)
|
||||
{
|
||||
#define CM1(c0) (&cmap[lookup[c0 - ' '][0]])
|
||||
for (i = 0; count < pixels && i < len; i++)
|
||||
{
|
||||
*ptr++ = CM1(line[i])->pixel;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else if (cpp == 2)
|
||||
{
|
||||
#define CM2(c0, c1) (&cmap[lookup[c0 - ' '][c1 - ' ']])
|
||||
for (i = 0; count < pixels && i < len - 1; i += 2)
|
||||
{
|
||||
*ptr++ = CM2(line[i], line[i + 1])->pixel;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; count < pixels && i < len - (cpp - 1); i += cpp)
|
||||
{
|
||||
*ptr++ = xpm_cmap_lookup(cmap, ncolors, cpp, &line[i]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
i = count / w;
|
||||
if (im->lc && i > last_row)
|
||||
{
|
||||
if (__imlib_LoadProgressRows(im, last_row, i - last_row))
|
||||
QUIT_WITH_RC(LOAD_BREAK);
|
||||
|
||||
last_row = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan in line from XPM file */
|
||||
if ((quote) && (c != '"'))
|
||||
if (!quote)
|
||||
{
|
||||
/* Waiting for start quote */
|
||||
if (c != '"')
|
||||
continue;
|
||||
/* Got start quote */
|
||||
quote = true;
|
||||
len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != '"')
|
||||
{
|
||||
/* Waiting for end quote */
|
||||
if (c < 32)
|
||||
c = 32;
|
||||
else if (c > 127)
|
||||
c = 127;
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
if (++backslash < 2)
|
||||
if (!backslash)
|
||||
{
|
||||
line[len++] = c;
|
||||
backslash = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
backslash = 0;
|
||||
backslash = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backslash = 0;
|
||||
line[len++] = c;
|
||||
backslash = false;
|
||||
}
|
||||
|
||||
if (len >= lsz)
|
||||
{
|
||||
char *nline;
|
||||
|
||||
lsz += 256;
|
||||
nline = realloc(line, lsz);
|
||||
if (!nline)
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
line = nline;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len >= lsz)
|
||||
/* Got end quote */
|
||||
line[len] = '\0';
|
||||
quote = false;
|
||||
|
||||
if (context == 0)
|
||||
{
|
||||
char *nline;
|
||||
/* Header */
|
||||
DL("Header line: '%s'\n", line);
|
||||
sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp);
|
||||
D("Header: WxH=%dx%d ncol=%d cpp=%d\n", w, h, ncolors, cpp);
|
||||
if ((ncolors > 32766) || (ncolors < 1))
|
||||
{
|
||||
E("XPM files with colors > 32766 or < 1 not supported\n");
|
||||
goto quit;
|
||||
}
|
||||
if ((cpp > 5) || (cpp < 1))
|
||||
{
|
||||
E("XPM files with characters per pixel > 5 or < 1 not supported\n");
|
||||
goto quit;
|
||||
}
|
||||
if (!IMAGE_DIMENSIONS_OK(w, h))
|
||||
{
|
||||
E("Invalid image dimension: %dx%d\n", w, h);
|
||||
goto quit;
|
||||
}
|
||||
im->w = w;
|
||||
im->h = h;
|
||||
|
||||
lsz += 256;
|
||||
nline = realloc(line, lsz);
|
||||
if (!nline)
|
||||
cmap = calloc(ncolors, sizeof(cmap_t));
|
||||
if (!cmap)
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
line = nline;
|
||||
}
|
||||
|
||||
if ((context > 1) && (count >= pixels))
|
||||
done = 1;
|
||||
pixels = w * h;
|
||||
|
||||
j = 0;
|
||||
context = 1;
|
||||
}
|
||||
else if (context == 1)
|
||||
{
|
||||
/* Color Table */
|
||||
DL("Coltbl line: '%s'\n", line);
|
||||
|
||||
err = xpm_parse_cmap_line(line, len, cpp, &cmap[j]);
|
||||
if (err)
|
||||
goto quit;
|
||||
|
||||
if (cmap[j].transp)
|
||||
transp = true;
|
||||
|
||||
j++;
|
||||
if (j < ncolors)
|
||||
continue;
|
||||
|
||||
/* Got all colors */
|
||||
#define LU(c0, c1) lookup[(int)(c0 - ' ')][(int)(c1 - ' ')]
|
||||
|
||||
if (cpp == 1)
|
||||
for (i = 0; i < ncolors; i++)
|
||||
LU(cmap[i].str[0], ' ') = i;
|
||||
else if (cpp == 2)
|
||||
for (i = 0; i < ncolors; i++)
|
||||
LU(cmap[i].str[0], cmap[i].str[1]) = i;
|
||||
else
|
||||
qsort(cmap, ncolors, sizeof(cmap_t), xpm_cmap_sort);
|
||||
|
||||
im->has_alpha = transp;
|
||||
|
||||
if (!load_data)
|
||||
QUIT_WITH_RC(LOAD_SUCCESS);
|
||||
|
||||
ptr = __imlib_AllocateData(im);
|
||||
if (!ptr)
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
|
||||
context = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Image Data */
|
||||
DL("Data line: '%s'\n", line);
|
||||
|
||||
if (cpp == 1)
|
||||
{
|
||||
for (i = 0; count < pixels && i <= len - cpp; i += cpp, count++)
|
||||
*ptr++ = cmap[LU(line[i], ' ')].pixel;
|
||||
}
|
||||
else if (cpp == 2)
|
||||
{
|
||||
for (i = 0; count < pixels && i <= len - cpp; i += cpp, count++)
|
||||
*ptr++ = cmap[LU(line[i], line[i + 1])].pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; count < pixels && i <= len - cpp; i += cpp, count++)
|
||||
*ptr++ = xpm_cmap_lookup(cmap, ncolors, cpp, &line[i]);
|
||||
}
|
||||
|
||||
i = count / w;
|
||||
if (im->lc && i > last_row)
|
||||
{
|
||||
if (__imlib_LoadProgressRows(im, last_row, i - last_row))
|
||||
QUIT_WITH_RC(LOAD_BREAK);
|
||||
|
||||
last_row = i;
|
||||
}
|
||||
|
||||
if (count >= pixels)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!im->data || !cmap)
|
||||
|
|
Loading…
Reference in New Issue