You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
9.0 KiB
431 lines
9.0 KiB
/*
|
|
* tcxpm2rgb.c
|
|
*
|
|
* Copyright (C) Tilmann Bitterberg - September 2003
|
|
*
|
|
* This file is part of transcode, a video stream processing tool
|
|
*
|
|
* transcode is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* transcode is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
#include "transcode.h"
|
|
#include "ioaux.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
/* ParseColor and QueryColorDatabase are from ImageMagick */
|
|
|
|
static char *ParseColor(char *data)
|
|
{
|
|
#define NumberTargets 6
|
|
|
|
static const char
|
|
*targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
|
|
|
|
register char
|
|
*p,
|
|
*r;
|
|
|
|
register const char
|
|
*q;
|
|
|
|
register int
|
|
i;
|
|
|
|
for (i=0; i < NumberTargets; i++)
|
|
{
|
|
r=data;
|
|
for (q=targets[i]; *r != '\0'; r++)
|
|
{
|
|
if (*r != *q)
|
|
continue;
|
|
if (!isspace((int) (*(r-1))))
|
|
continue;
|
|
p=r;
|
|
for ( ; ; )
|
|
{
|
|
if (*q == '\0')
|
|
return(r);
|
|
if (*p++ != *q++)
|
|
break;
|
|
}
|
|
q=targets[i];
|
|
}
|
|
}
|
|
return((char *) NULL);
|
|
}
|
|
|
|
typedef struct color_t {
|
|
int red, green, blue, opacity;
|
|
} color_t;
|
|
|
|
|
|
#define TransparentOpacity 255
|
|
#define OpaqueOpacity 0
|
|
#define BackgroundColor "#ff"
|
|
|
|
static unsigned int QueryColorDatabase(const char *name,
|
|
color_t *color)
|
|
{
|
|
int
|
|
blue,
|
|
green,
|
|
opacity,
|
|
red;
|
|
|
|
register long
|
|
i;
|
|
|
|
/*
|
|
Initialize color return value.
|
|
*/
|
|
memset(color,0,sizeof(color_t));
|
|
color->opacity=TransparentOpacity;
|
|
if ((name == (char *) NULL) || (*name == '\0'))
|
|
name=BackgroundColor;
|
|
while (isspace((int) (*name)))
|
|
name++;
|
|
if (*name == '#')
|
|
{
|
|
char
|
|
c;
|
|
|
|
long
|
|
n;
|
|
|
|
green=0;
|
|
blue=0;
|
|
opacity=(-1);
|
|
name++;
|
|
for (n=0; isxdigit((int) name[n]); n++);
|
|
if ((n == 3) || (n == 6) || (n == 9) || (n == 12))
|
|
{
|
|
/*
|
|
Parse RGB specification.
|
|
*/
|
|
n/=3;
|
|
do
|
|
{
|
|
red=green;
|
|
green=blue;
|
|
blue=0;
|
|
for (i=n-1; i >= 0; i--)
|
|
{
|
|
c=(*name++);
|
|
blue<<=4;
|
|
if ((c >= '0') && (c <= '9'))
|
|
blue|=c-'0';
|
|
else
|
|
if ((c >= 'A') && (c <= 'F'))
|
|
blue|=c-('A'-10);
|
|
else
|
|
if ((c >= 'a') && (c <= 'f'))
|
|
blue|=c-('a'-10);
|
|
else
|
|
return(0);
|
|
}
|
|
} while (isxdigit((int) *name));
|
|
}
|
|
else
|
|
if ((n != 4) && (n != 8) && (n != 16))
|
|
return(0);
|
|
else
|
|
{
|
|
/*
|
|
Parse RGBA specification.
|
|
*/
|
|
n/=4;
|
|
do
|
|
{
|
|
red=green;
|
|
green=blue;
|
|
blue=opacity;
|
|
opacity=0;
|
|
for (i=n-1; i >= 0; i--)
|
|
{
|
|
c=(*name++);
|
|
opacity<<=4;
|
|
if ((c >= '0') && (c <= '9'))
|
|
opacity|=c-'0';
|
|
else
|
|
if ((c >= 'A') && (c <= 'F'))
|
|
opacity|=c-('A'-10);
|
|
else
|
|
if ((c >= 'a') && (c <= 'f'))
|
|
opacity|=c-('a'-10);
|
|
else
|
|
return(0);
|
|
}
|
|
} while (isxdigit((int) *name));
|
|
}
|
|
n<<=1;
|
|
color->red=red/(1<<n);
|
|
color->green=green/(1<<n);
|
|
color->blue=blue/(1<<n);
|
|
color->opacity=OpaqueOpacity;
|
|
if (opacity >= 0) color->opacity=opacity>>((1 << n));
|
|
return(1);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
#define EXE "tcxpm2rgb"
|
|
#define MAX_BUF 1024
|
|
|
|
void version(void)
|
|
{
|
|
// print id string to stderr
|
|
fprintf(stderr, "%s (%s v%s) (C) 2003 Tilmann Bitterberg\n",
|
|
EXE, PACKAGE, VERSION);
|
|
}
|
|
|
|
|
|
static void usage(int status)
|
|
{
|
|
version();
|
|
|
|
fprintf(stderr,"\n%s converts a XPM file to rgb24 format\n", EXE);
|
|
fprintf(stderr,"Usage: %s [options]\n", EXE);
|
|
|
|
fprintf(stderr," -i name input file name [stdin]\n");
|
|
fprintf(stderr," -o name output file name [stdout]\n");
|
|
fprintf(stderr," -v print version\n");
|
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
char linebuf[MAX_BUF], target[MAX_BUF], key[16];
|
|
FILE *f, *o;
|
|
int width, height, colors, bwidth, n, j, linelen, x, y, ch;
|
|
char **clist, **keys;
|
|
char *p, *q, *line;
|
|
char *out = NULL, *d;
|
|
char *outfile = NULL, *infile=NULL;
|
|
color_t *colormap;
|
|
long sret;
|
|
|
|
while ((ch = getopt(argc, argv, "i:o:vh?")) != -1) {
|
|
|
|
switch (ch) {
|
|
|
|
case 'i':
|
|
|
|
if(optarg[0]=='-') usage(EXIT_FAILURE);
|
|
infile = optarg;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
if(optarg[0]=='-') usage(EXIT_FAILURE);
|
|
outfile = optarg;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
version();
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
case '?':
|
|
case 'h':
|
|
default:
|
|
usage(EXIT_SUCCESS);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (infile) {
|
|
f = fopen(infile, "r");
|
|
if (!f) {
|
|
tc_log_perror(EXE, "fopen infile");
|
|
return 1;
|
|
}
|
|
} else
|
|
f = stdin;
|
|
|
|
if (outfile) {
|
|
o = fopen(outfile, "w");
|
|
if (!o) {
|
|
tc_log_perror(EXE, "fopen outfile");
|
|
return 1;
|
|
}
|
|
} else
|
|
o = stdout;
|
|
|
|
|
|
if (!fgets(linebuf, MAX_BUF, f)) {
|
|
tc_log_error(EXE, "No more lines");
|
|
return 1;
|
|
}
|
|
|
|
if (strncmp ("/* XPM */", linebuf, 9) != 0) {
|
|
tc_log_error(EXE, "Not an xpm file 1 (%s)", linebuf);
|
|
return 1;
|
|
}
|
|
|
|
if (!fgets(linebuf, MAX_BUF, f)) {
|
|
tc_log_error(EXE, "No more lines");
|
|
return 1;
|
|
}
|
|
if (strncmp ("static char", linebuf, 11) != 0) {
|
|
tc_log_error(EXE, "Not an xpm file 2");
|
|
return 1;
|
|
}
|
|
|
|
fgets(linebuf, MAX_BUF, f);
|
|
n = sscanf(linebuf+1, "%d %d %d %d", &width, &height, &colors, &bwidth);
|
|
if (n != 4 || (bwidth > 2) || (width == 0) || (height == 0) || (colors == 0)) {
|
|
tc_log_error(EXE, "Error reading header");
|
|
return 1;
|
|
}
|
|
//tc_log_info(EXE, "XPM Image: %dx%d; %d colors, %d byte wide", width, height, colors, bwidth);
|
|
|
|
clist = tc_malloc(colors*sizeof(char *));
|
|
|
|
if (clist == (char **)NULL) {
|
|
tc_log_error(EXE, "Error malloc clist");
|
|
return 1;
|
|
}
|
|
|
|
// color lookup table
|
|
colormap = tc_malloc(colors*sizeof(color_t));
|
|
|
|
for (n=0; n<colors; n++) {
|
|
int len;
|
|
|
|
if (!fgets(linebuf, MAX_BUF, f)) {
|
|
tc_log_error(EXE, "Error reading color table");
|
|
return 1;
|
|
}
|
|
len=strlen(linebuf);
|
|
|
|
clist[n] = tc_malloc(len);
|
|
memcpy(clist[n], linebuf+1, len-3);
|
|
clist[n][len-4] = '\0';
|
|
//tc_log_msg(EXE, "[%d] : %s|", n, clist[n]);
|
|
}
|
|
|
|
keys = tc_malloc(colors*sizeof(char *));
|
|
|
|
for (j=0; j<colors; j++) {
|
|
p = clist[j];
|
|
|
|
keys[j] = tc_malloc(bwidth+1); // a bit stupid since bwidth is usually just 1 or 2
|
|
keys[j][bwidth]='\0';
|
|
|
|
sret = strlcpy(keys[j], p, bwidth+1);
|
|
tc_test_string(__FILE__, __LINE__, bwidth+1, sret, errno);
|
|
|
|
sret = strlcpy(target, "gray", sizeof(target));
|
|
tc_test_string(__FILE__, __LINE__, sizeof(target), sret, errno);
|
|
|
|
q = ParseColor (p+bwidth);
|
|
if (q != (char *) NULL)
|
|
{
|
|
while (!isspace((int) (*q)) && (*q != '\0'))
|
|
q++;
|
|
(void) strncpy(target,q,sizeof(target)-1);
|
|
q=ParseColor(target);
|
|
if (q != (char *) NULL)
|
|
*q='\0';
|
|
}
|
|
QueryColorDatabase(target, &colormap[j]);
|
|
}
|
|
|
|
if (j < colors) {
|
|
tc_log_error(EXE, "Corrupt XPM image file");
|
|
return 1;
|
|
}
|
|
memset (key, '\0', 16);
|
|
|
|
linelen = width * bwidth + 16;
|
|
line = tc_malloc(linelen);
|
|
|
|
out = tc_malloc (width*height*3);
|
|
if (!out || !line) {
|
|
tc_log_error(EXE, "Error malloc line");
|
|
return 1;
|
|
}
|
|
|
|
d = out;
|
|
j=0;
|
|
for (y = 0; y<height; y++) {
|
|
int len;
|
|
|
|
if (!fgets(line, linelen, f)) {
|
|
tc_log_error(EXE, "Error reading line %d", y);
|
|
return 1;
|
|
}
|
|
len = strlen(line);
|
|
p = line+1;
|
|
p[len-4]='\0';
|
|
|
|
for (x = 0; x<width; x++) {
|
|
|
|
strncpy(key,p,bwidth);
|
|
|
|
// can anything be slower?
|
|
if (strcmp(key,keys[j]) != 0)
|
|
for (j=0; j < colors; j++)
|
|
if (strcmp(key,keys[j]) == 0)
|
|
break;
|
|
|
|
*d++ = colormap[j].red&0xff;
|
|
*d++ = colormap[j].green&0xff;
|
|
*d++ = colormap[j].blue&0xff;
|
|
p+=bwidth;
|
|
|
|
}
|
|
}
|
|
|
|
if ( (n = fwrite (out, width*height*3, 1, o))<0) {
|
|
tc_log_error(EXE, "fwrite failed (should = %d, have = %d)", width*height*3, n);
|
|
return 1;
|
|
}
|
|
|
|
fclose(o);
|
|
|
|
//tc_log_msg(EXE, "Wrote %s", outfile);
|
|
|
|
free(out);
|
|
free(line);
|
|
for (n=0; n<colors; n++) {
|
|
free(clist[n]);
|
|
free(keys[n]);
|
|
}
|
|
free(clist);
|
|
free(keys);
|
|
free(colormap);
|
|
|
|
// read };
|
|
if (!fgets(linebuf, MAX_BUF, f)) {
|
|
tc_log_perror(EXE, "fgets header");
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
fclose (f);
|
|
|
|
return 0;
|
|
}
|