/* +-------------------------------------------------------------------+ */
/* | This file is derived from | */
/* | Xpaint's read/write routines, copyrighted | */
/* | by David Koblas (koblas@netcom.com), | */
/* | Torsten Martinsen ( | */
/* | Greg Roelofs (newt@pobox.com) | */
/* | | */
/* | Permission to use, copy, modify, and to distribute this software | */
/* | and its documentation for any purpose is hereby granted without | */
/* | fee, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. There is no | */
/* | representations about the suitability of this software for | */
/* | any purpose. this software is provided "as is" without express | */
/* | or implied warranty. | */
/* | | */
/* +-------------------------------------------------------------------+ */
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <jpeglib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/xpm.h>
#include "xrmap.h"
#include "numdefs.h"
extern Display * dpy;
extern Visual * visual;
extern Colormap cmap;
extern GC gc;
extern int scr;
extern int bigendian;
extern int color_depth;
extern int color_pad;
extern int runlevel;
extern int num_flag_types;
extern int brief_menu;
extern char *color_table;
extern int cmdwin_on;
extern Window mainwin, datawin, cmdwin;
extern char *error_msg;
extern char **msg;
extern char *flag_formats[];
extern char *flag_ordering;
extern char **flag_type;
extern char **flag_dir;
extern int flag_size;
extern int num_flag_dirs;
extern int num_flag_types;
int bytes_per_pixel;
/* Make a temporary file */
char * mk_tmp(char *suff)
{
static char template[256];
int fd;
sprintf(template, "%s/xrmapXXXXXX", P_tmpdir);
fd = mkstemp(template);
if (fd == -1) return NULL;
close(fd);
unlink(template);
strcat(template, suff);
return template;
}
XImage *
ximage_rescale(XImage * image, int height)
{
XImage * ximage;
int i, ip, j, jp, k, b, bp, width;
width = (int)
(((double)image->width * (double) height / (double) image->height)+0.5);
ximage = XCreateImage(dpy, visual,
DefaultDepth(dpy, scr), ZPixmap,0, NULL,
width, height, color_pad,0);
XFlush(dpy);
if (!ximage) return NULL;
ximage->data = (char *) malloc(ximage->bytes_per_line
* ximage->height);
if (!ximage->data) return NULL;
for (j=0; j<height; j++) {
jp = (j * image->height)/height;
for (i=0; i<width; i++) {
ip = (i * image->width)/width;
b = i*bytes_per_pixel + j * ximage->bytes_per_line;
bp = ip*bytes_per_pixel + jp*image->bytes_per_line;
for (k=0; k<bytes_per_pixel; k++)
ximage->data[b+k] = image->data[bp+k];
}
}
XDestroyImage(image);
return ximage;
}
/* PNG routines */
typedef struct _jmpbuf_wrapper {
jmp_buf jmpbuf;
} jmpbuf_wrapper;
/* this can be shared between reading/writing code since they never overlap: */
static jmpbuf_wrapper jmpbuf_struct;
static void
png_error_handler (png_structp png_ptr, png_const_charp msg)
{
jmpbuf_wrapper *jmpbuf_ptr;
/* this function, aside from the extra step of retrieving the "error
* pointer" (below) and the fact that it exists within the application
* rather than within libpng, is essentially identical to libpng's
* default error handler. The second point is critical: since both
* setjmp() and longjmp() are called from the same code, they are
* guaranteed to have compatible notions of how big a jmp_buf is,
* regardless of whether _BSD_SOURCE or anything else has (or has not)
* been defined. */
fprintf(stderr, "Fatal libpng error !!\n");
fflush(stderr);
jmpbuf_ptr = png_get_error_ptr(png_ptr);
if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
exit(99);
}
longjmp(jmpbuf_ptr->jmpbuf, 1);
}
void
fill_line(char *scan, char* c, int w, int wp)
{
unsigned char r, g, b;
int i, j, k;
k = 0;
if (color_depth>16) {
if (bigendian)
k = bytes_per_pixel - 3;
for (i = 0; i < wp; i++) {
if (i==0) j = 0 ; else j = 3 * ((i* (w-1))/(wp-1));
if (bigendian) {
c[k] = scan[j];
c[k+1] = scan[j+1];
c[k+2] = scan[j+2];
} else {
c[k] = scan[j+2];
c[k+1] = scan[j+1];
c[k+2] = scan[j];
}
k += bytes_per_pixel;
}
} else
if (color_depth==16)
for (i = 0; i < wp; i++) {
if (i==0) j = 0 ; else j = 3 * ((i* (w-1))/(wp-1));
r = scan[j];
g = scan[j+1];
b = scan[j+2];
/* blue c[k] = 31; c[k+1] = 0;
green c[k] = 224 (low weight) c[k+1] = 7 (high weight)
red c[k] = 0; c[k+1] = 248; */
if (bigendian) {
c[k+1] = (((b&248)>>3) | ((g&28)<<3));
c[k] = (((g&224)>>5) | (r&248));
} else {
c[k] = (((b&248)>>3) | ((g&28)<<3));
c[k+1] = (((g&224)>>5) | (r&248));
}
k += 2;
}
else
if (color_depth==15)
for (i = 0; i < wp; i++) {
if (i==0) j = 0 ; else j = 3 * ((i* (w-1))/(wp-1));
r = scan[j];
g = scan[j+1];
b = scan[j+2];
/* blue c[k] = 31; c[k+1] = 0;
green c[k] = 224 (low weight) c[k+1] = 7 (high weight)
red c[k] = 0; c[k+1] = 248; */
if (bigendian) {
c[k+1] = (b&248)>>3 | (g&56)<<2;
c[k] = (g&192)>>6 | (r&248)>>1;
} else {
c[k] = (b&248)>>3 | (g&56)<<2;
c[k+1] = (g&192)>>6 | (r&248)>>1;
}
k += 2;
}
else {
for (i = 0; i < wp; i++) {
if (i==0) j = 0 ; else j = 3 * ((i* (w-1))/(wp-1));
r = scan[j];
g = scan[j+1];
b = scan[j+2];
c[k] = color_table[(((6*g)>>8)*36)+(((6*r)>>8)*6)+((6*b)>>8)];
k++;
}
}
}
XImage *
readPNG(char *file, int height, Colordata *color)
{
XImage *ximage;
FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width0, height0;
png_colorp palette;
png_bytep *row_pointers, png_data, png;
int bit_depth, color_type, interlace_type, num_palette, rowbytes;
int i, i1, i2, x, y, yp, size, width = 0;
int * ys;
unsigned char * scan, *scanp, *out;
unsigned char c;
unsigned char bg[4];
if ((fp = fopen(file, "rb")) == (FILE *)NULL) {
return NULL;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
&jmpbuf_struct, png_error_handler, NULL);
if (!png_ptr) {
fclose(fp);
return NULL;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(fp);
return NULL;
}
if (setjmp(jmpbuf_struct.jmpbuf)) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return NULL;
}
png_init_io(png_ptr, fp);
png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
png_get_IHDR(png_ptr, info_ptr, &width0, &height0, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
switch (color_type) {
case PNG_COLOR_TYPE_PALETTE:
if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return NULL;
}
break;
case PNG_COLOR_TYPE_RGB:
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
break;
case PNG_COLOR_TYPE_GRAY: /* treat grayscale as special colormap */
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
bit_depth = 8;
}
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
break;
default:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return NULL;
}
if (height == 0) height = height0;
if (height == height0)
width = width0;
else
width = (int)
(((double)width0 * (double) height / (double) height0)+0.5);
ximage = XCreateImage(dpy, visual,
DefaultDepth(dpy, scr), ZPixmap, 0, NULL,
width, height, color_pad, 0);
XFlush(dpy);
if (!ximage) return NULL;
bytes_per_pixel = ximage->bits_per_pixel/8;
size = ximage->bytes_per_line * height;
ximage->data = (char *) malloc(size);
if (!ximage->data) {
XDestroyImage(ximage);
return NULL;
}
if (bit_depth < 8)
png_set_packing(png_ptr);
if (interlace_type)
/* npasses = */ png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
png_data = (png_bytep) malloc(height0*rowbytes);
row_pointers = (png_bytep *)malloc(height0 * sizeof(png_bytep));
scan = (char *)malloc(3*width0);
ys = (int *)malloc((height0+1)*sizeof(int));
if (!png_data || !row_pointers || !scan || !ys) {
if (png_data) free(png_data);
png_data = NULL;
if (row_pointers) free(row_pointers);
row_pointers = NULL;
if (scan) free(scan);
if (ys) free(ys);
XDestroyImage(ximage);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return NULL;
}
for (y=0; y<height0; ++y)
row_pointers[y] = (png_bytep)png_data + y*rowbytes;
png_read_image(png_ptr, row_pointers);
bg[1] = color->b>>8;
bg[2] = color->g>>8;
bg[3] = color->r>>8;
for (y=0; y<height0; ++y) {
if (y==0) yp=0; else yp = (y*(height-1))/(height0-1);
ys[y] = yp;
out = ximage->data + yp * ximage->bytes_per_line;
png = png_data + y*rowbytes;
scanp = scan;
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
for (x=0; x<width0; x++) {
*scanp++ = *png++;
*scanp++ = *png++;
*scanp++ = *png++;
if ((c=*png++)<255) /* alpha channel */
for (i=1; i<=3; i++)
*(scanp-i) = (*(scanp-i) * c + bg[i] * ( 255-c))>>8;
}
} else
if (color_type == PNG_COLOR_TYPE_RGB) {
for (x=0; x<width0; x++) {
*scanp++ = *png++;
*scanp++ = *png++;
*scanp++ = *png++;
}
} else
if (color_type == PNG_COLOR_TYPE_PALETTE) {
for(x=0; x<width0; x++) {
c = *png++;
*scanp++ = palette[c].red;
*scanp++ = palette[c].green;
*scanp++ = palette[c].blue;
}
} else
if (color_type == PNG_COLOR_TYPE_GRAY) {
for(x=0; x<width0; x++) {
*scanp++ = c = *png++;
*scanp++ = c;
*scanp++ = c;
}
} else
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
for(x=0; x<width0; x++) {
*scanp++ = c = *png++;
*scanp++ = c;
*scanp++ = c;
if ((c=*png++)<255) /* alpha channel */
for (i=1; i<=3; i++)
*(scanp-i) = (*(scanp-i) * c + bg[i] * ( 255-c))>>8;
}
}
fill_line(scan, out, width0, width);
}
/* fill intermediate lines in output, if necessary*/
if (height>height0) {
ys[height0] = height;
for(y=0; y<height0; ++y) {
if (ys[y]>=0 || ys[y+1]<height) {
if (ys[y]<0) {
out = ximage->data +
ys[y+1] * ximage->bytes_per_line;
i1 = 0;
i2 = ys[y+1];
} else {
out = ximage->data +
ys[y]*ximage->bytes_per_line;
i1 = ys[y]+1;
i2 = ys[y+1];
if (i2>height) i2=height;
}
for (i=i1; i<i2; i++)
memcpy(ximage->data+i*ximage->bytes_per_line, out,
ximage->bytes_per_line);
}
}
}
/* Close everything */
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(png_data);
free(row_pointers);
free(scan);
free(ys);
fclose(fp);
return ximage;
} /* end function ReadPNG() */
/* GIF routines */
#define MAXCOLORMAPSIZE 256
#define TRUE 1
#define FALSE 0
#define CM_RED 0
#define CM_GREEN 1
#define CM_BLUE 2
#define MAX_LWZ_BITS 12
#define INTERLACE 0x40
#define LOCALCOLORMAP 0x80
#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
#define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
#define LM_to_uint(a,b) (((b)<<8)|(a))
struct {
unsigned int Width;
unsigned int Height;
unsigned char ColorMap[3][MAXCOLORMAPSIZE];
unsigned int BitPixel;
unsigned int ColorResolution;
unsigned int Background;
unsigned int AspectRatio;
int Grayscale;
} GifScreen;
static struct {
int transparent;
int delayTime;
int inputFlag;
int disposal;
} Gif89 = {
-1, -1, -1, 0
};
static int ReadColorMap(FILE * fd, int number,
unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
static int DoExtension(FILE * fd, int label);
static int GetDataBlock(FILE * fd, unsigned char *buf);
static int GetCode(FILE * fd, int code_size, int flag);
static int LWZReadByte(FILE * fd, int flag, int input_code_size);
static int ReadImage(FILE * fd, XImage *ximage,
int width, int height, int bitPixel,
unsigned char cmap[3][MAXCOLORMAPSIZE],
int gray, int interlace);
XImage *
readGIF(char *file, int height, Colordata *color)
{
XImage *image;
unsigned char buf[16];
unsigned char c;
unsigned char localColorMap[3][MAXCOLORMAPSIZE];
int output = 0, size;
int grayScale;
int useGlobalColormap;
int bitPixel;
char version[4];
FILE *fd;
fd = fopen(file, "r");
if (fd == NULL)
return NULL;
if (!ReadOK(fd, buf, 6)) {
fclose(fd);
return NULL;
}
if (strncmp((char *) buf, "GIF", 3) != 0) {
fclose(fd);
return NULL;
}
strncpy(version, (char *) buf + 3, 3);
version[3] = '\0';
if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
fclose(fd);
return NULL;
}
if (!ReadOK(fd, buf, 7)) {
fclose(fd);
return NULL;
}
GifScreen.Width = LM_to_uint(buf[0], buf[1]);
GifScreen.Height = LM_to_uint(buf[2], buf[3]);
GifScreen.BitPixel = 2 << (buf[4] & 0x07);
GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
GifScreen.Background = buf[5];
GifScreen.AspectRatio = buf[6];
if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
if (ReadColorMap(fd, GifScreen.BitPixel, GifScreen.ColorMap,
&GifScreen.Grayscale)) {
fclose(fd);
return NULL;
}
}
repeat:
if (!ReadOK(fd, &c, 1)) {
fclose(fd);
return NULL;
}
if (c == '!') { /* Extension */
if (!ReadOK(fd, &c, 1)) {
fclose(fd);
return NULL;
}
DoExtension(fd, c);
goto repeat;
}
if (c != ',') { /* Not a valid start character */
goto repeat;
}
if (!ReadOK(fd, buf, 9)) {
fclose(fd);
return NULL;
}
useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
bitPixel = 1 << ((buf[8] & 0x07) + 1);
image = XCreateImage(dpy, visual,
DefaultDepth(dpy, scr), ZPixmap, 0, NULL,
GifScreen.Width, GifScreen.Height, color_pad, 0);
XFlush(dpy);
if (!image) return NULL;
bytes_per_pixel = (image->bits_per_pixel/8);
size = image->bytes_per_line * GifScreen.Height;
image->data = (char *) malloc(size);
if (!image->data) {
XDestroyImage(image);
return NULL;
}
if (!useGlobalColormap) {
if (ReadColorMap(fd, bitPixel, localColorMap, &grayScale)) {
XDestroyImage(image);
return NULL;
}
output = ReadImage(fd, image,
LM_to_uint(buf[4], buf[5]),
LM_to_uint(buf[6], buf[7]),
bitPixel, localColorMap, grayScale,
BitSet(buf[8], INTERLACE));
} else {
output = ReadImage(fd, image,
LM_to_uint(buf[4], buf[5]),
LM_to_uint(buf[6], buf[7]),
GifScreen.BitPixel, GifScreen.ColorMap,
GifScreen.Grayscale, BitSet(buf[8], INTERLACE));
}
if (output) {
XDestroyImage(image);
return NULL;
}
if (height == 0 || height == image->height) {
return image;
}
return ximage_rescale(image, height);
}
static int
ReadColorMap(FILE *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE],
int *gray)
{
int i;
unsigned char rgb[3];
int flag;
flag = TRUE;
for (i = 0; i < number; ++i) {
if (!ReadOK(fd, rgb, sizeof(rgb))) {
return 1;
}
buffer[CM_RED][i] = rgb[0];
buffer[CM_GREEN][i] = rgb[1];
buffer[CM_BLUE][i] = rgb[2];
flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
}
#if 0
if (flag)
*gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
else
*gray = PPM_TYPE;
#else
*gray = 0;
#endif
return FALSE;
}
static int
DoExtension(FILE *fd, int label)
{
static char buf[256];
char *str;
switch (label) {
case 0x01: /* Plain Text Extension */
str = "Plain Text Extension";
break;
case 0xff: /* Application Extension */
str = "Application Extension";
break;
case 0xfe: /* Comment Extension */
str = "Comment Extension";
while (GetDataBlock(fd, (unsigned char *) buf) != 0);
return FALSE;
case 0xf9: /* Graphic Control Extension */
str = "Graphic Control Extension";
(void) GetDataBlock(fd, (unsigned char *) buf);
Gif89.disposal = (buf[0] >> 2) & 0x7;
Gif89.inputFlag = (buf[0] >> 1) & 0x1;
Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
if ((buf[0] & 0x1) != 0)
Gif89.transparent = buf[3];
while (GetDataBlock(fd, (unsigned char *) buf) != 0);
return FALSE;
default:
str = buf;
sprintf(buf, "UNKNOWN (0x%02x)", label);
break;
}
while (GetDataBlock(fd, (unsigned char *) buf) != 0);
return FALSE;
}
static int ZeroDataBlock = FALSE;
static int
GetDataBlock(FILE *fd, unsigned char *buf)
{
unsigned char count;
if (!ReadOK(fd, &count, 1)) {
/* pm_message("error in getting DataBlock size" ); */
return -1;
}
ZeroDataBlock = count == 0;
if ((count != 0) && (!ReadOK(fd, buf, count))) {
/* pm_message("error in reading DataBlock" ); */
return -1;
}
return count;
}
static int
GetCode(FILE *fd, int code_size, int flag)
{
static unsigned char buf[280];
static int curbit, lastbit, done, last_byte;
int i, j, ret;
unsigned char count;
if (flag) {
curbit = 0;
lastbit = 0;
done = FALSE;
return 0;
}
if ((curbit + code_size) >= lastbit) {
if (done) {
if (curbit >= lastbit)
fprintf(stderr, "ran off the end of my bits...\n");
return -1;
}
buf[0] = buf[last_byte - 2];
buf[1] = buf[last_byte - 1];
if ((count = GetDataBlock(fd, &buf[2])) == 0)
done = TRUE;
last_byte = 2 + count;
curbit = (curbit - lastbit) + 16;
lastbit = (2 + count) * 8;
}
ret = 0;
for (i = curbit, j = 0; j < code_size; ++i, ++j)
ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
curbit += code_size;
return ret;
}
static int
LWZReadByte(FILE *fd, int flag, int input_code_size)
{
static int fresh = FALSE;
int code, incode;
static int code_size, set_code_size;
static int max_code, max_code_size;
static int firstcode, oldcode;
static int clear_code, end_code;
static int table[2][(1 << MAX_LWZ_BITS)];
static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
register int i;
if (flag) {
set_code_size = input_code_size;
code_size = set_code_size + 1;
clear_code = 1 << set_code_size;
end_code = clear_code + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
GetCode(fd, 0, TRUE);
fresh = TRUE;
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1 << MAX_LWZ_BITS); ++i)
table[0][i] = table[1][0] = 0;
sp = stack;
return 0;
} else if (fresh) {
fresh = FALSE;
do {
firstcode = oldcode = GetCode(fd, code_size, FALSE);
} while (firstcode == clear_code);
return firstcode;
}
if (sp > stack)
return *--sp;
while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
if (code == clear_code) {
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1 << MAX_LWZ_BITS); ++i)
table[0][i] = table[1][i] = 0;
code_size = set_code_size + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
sp = stack;
firstcode = oldcode = GetCode(fd, code_size, FALSE);
return firstcode;
} else if (code == end_code) {
int count;
unsigned char buf[260];
if (ZeroDataBlock)
return -2;
while ((count = GetDataBlock(fd, buf)) > 0);
if (count != 0) {
/*
* pm_message("missing EOD in data stream (common occurence)");
*/
}
return -2;
}
incode = code;
if (code >= max_code) {
*sp++ = firstcode;
code = oldcode;
}
while (code >= clear_code) {
*sp++ = table[1][code];
if (code == table[0][code])
fprintf(stderr, "circular table entry BIG ERROR...\n");
code = table[0][code];
}
*sp++ = firstcode = table[1][code];
if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
table[0][code] = oldcode;
table[1][code] = firstcode;
++max_code;
if ((max_code >= max_code_size) &&
(max_code_size < (1 << MAX_LWZ_BITS))) {
max_code_size *= 2;
++code_size;
}
}
oldcode = incode;
if (sp > stack)
return *--sp;
}
return code;
}
static int
ReadImage(FILE * fd, XImage *ximage, int width, int height, int cmapSize,
unsigned char cmap[3][MAXCOLORMAPSIZE],
int gray, int interlace)
{
unsigned char c;
char *out;
int v, ind;
int xpos = 0, ypos = 0, pass = 0;
unsigned char *scan;
/*
** Initialize the compression routines
*/
scan = (unsigned char *)malloc(3*width);
if (!scan) return 4;
if (!ReadOK(fd, &c, 1)) {
return 2;
}
if (LWZReadByte(fd, TRUE, c) < 0) {
return 2;
}
while ((v = LWZReadByte(fd, FALSE, c)) >= 0) {
ind = 3*xpos;
scan[ind] = cmap[CM_RED][v];
scan[ind+1] = cmap[CM_GREEN][v];
scan[ind+2] = cmap[CM_BLUE][v];
out = ximage->data + ypos * ximage->bytes_per_line;
++xpos;
if (xpos == width) {
xpos = 0;
if (interlace) {
switch (pass) {
case 0:
case 1:
ypos += 8;
break;
case 2:
ypos += 4;
break;
case 3:
ypos += 2;
break;
}
if (ypos >= height) {
++pass;
switch (pass) {
case 1:
ypos = 4;
break;
case 2:
ypos = 2;
break;
case 3:
ypos = 1;
break;
default:
goto fini;
}
}
} else {
++ypos;
}
fill_line(scan, out, width, width);
}
if (ypos >= height)
break;
}
fini:
free(scan);
return 0;
}
/* JPEG routines */
struct error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct error_mgr * error_ptr;
void
error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
error_ptr err = (error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(err->setjmp_buffer, 1);
}
XImage *
readJPG(char * file, int height, Colordata *color)
{
FILE *input_file;
XImage *ximage;
struct jpeg_decompress_struct cinfo;
struct error_mgr jerr;
double ratio;
int l, prev, next=0, size, width;
JSAMPROW scanline[1];
char *scan, *c;
if ((input_file = fopen(file, "r")) == NULL) return NULL;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = error_exit;
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file,
* and return.
*/
jpeg_destroy_decompress(&cinfo);
fclose(input_file);
return NULL;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, input_file);
jpeg_read_header(&cinfo, TRUE);
if (cinfo.jpeg_color_space == JCS_GRAYSCALE) return NULL;
if (height == 0) {
width = cinfo.image_width;
height = cinfo.image_height;
ratio = 1.0;
cinfo.scale_denom = 1;
} else {
width = (int)((double) cinfo.image_width * (double) height /
(double) cinfo.image_height + 0.5);
ratio = ((double) cinfo.image_width/(double) width +
(double) cinfo.image_height/(double) height )/1.8;
if (ratio>=8.0)
cinfo.scale_denom = 8;
else
if (ratio>=4.0)
cinfo.scale_denom = 4;
else
if (ratio>=2.0)
cinfo.scale_denom = 2;
else
cinfo.scale_denom = 1;
}
jpeg_start_decompress(&cinfo);
ximage = XCreateImage(dpy, visual,
DefaultDepth(dpy, scr), ZPixmap, 0, NULL,
width, height, color_pad, 0);
XFlush(dpy);
if (!ximage) return NULL;
bytes_per_pixel = (ximage->bits_per_pixel/8);
size = ximage->bytes_per_line * height;
ximage->data = (char *) malloc(size);
scan = (char *) malloc(3 * cinfo.output_width * sizeof(char));
#if 0 /* verbose */
fprintf(stderr, "Loading %s\n"
"Rescaling JPEG data by 1/%d, "
"%d %d --> %d %d, %d bytes per pixel\n",
file, cinfo.scale_denom,
cinfo.image_width, cinfo.image_height,
width, height,
bytes_per_pixel);
#endif
prev = -1;
scanline[0] = (JSAMPROW) scan;
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, scanline, (JDIMENSION) 1);
next = ((2*cinfo.output_scanline - 1) * height)/
(2*(int)cinfo.output_height);
if (next>=0) {
if (next>=height) {
next = height - 1;
/* get loop to stop at next iteration ! */
cinfo.output_scanline = cinfo.output_height;
}
for (l = prev+1; l<= next; l++) {
c = ximage->data + l * ximage->bytes_per_line;
fill_line(scan, c, cinfo.output_width, width);
}
prev = next;
}
}
free(scan);
jpeg_destroy_decompress(&cinfo);
fclose(input_file);
if (jerr.pub.num_warnings > 0) {
longjmp(jerr.setjmp_buffer, 1);
}
return ximage;
}
/* XPM routines */
XImage *
readXPM(char *file, int height, Colordata *color)
{
XImage *image;
XpmAttributes attrib;
XpmColorSymbol flagbg;
XColor xc;
#ifdef XPMBUG
char *buffer;
gzFile fd;
#endif
int j, k;
if (color_depth<=8) {
attrib.valuemask = XpmColormap;
attrib.valuemask = XpmColormap | XpmReturnPixels | XpmColorSymbols;
attrib.colormap = XCreateColormap(dpy, mainwin, visual, AllocNone);
attrib.numsymbols = 1;
attrib.colorsymbols = &flagbg;
flagbg.name = NULL;
flagbg.value = "None";
flagbg.pixel = 255;
} else {
attrib.valuemask = XpmColormap | XpmReturnPixels | XpmColorSymbols;
attrib.colormap = cmap;
attrib.numsymbols = 1;
attrib.colorsymbols = &flagbg;
flagbg.pixel = color->pix;
flagbg.name = NULL;
flagbg.value = "None";
}
if (!file || !*file) return NULL;
image = NULL;
#ifdef XPMBUG
fd = gzopen(file, "r");
buffer = NULL;
j = 0;
k = -1;
while (!gzeof(fd)) {
++k;
if (k>=j) {
j += 4096;
buffer = realloc(buffer, j);
}
buffer[k] = gzgetc(fd);
}
gzclose(fd);
if (XpmCreateImageFromBuffer(dpy, buffer, &image, NULL, &attrib)
!= XpmSuccess) {
free(buffer);
return NULL;
}
free(buffer);
#else
if (XpmReadFileToImage(dpy, file, &image, NULL, &attrib) != XpmSuccess)
return NULL;
#endif
if (image)
bytes_per_pixel = image->bits_per_pixel/8;
else
return NULL;
if (color_depth<=8) {
unsigned char * cvs_table;
unsigned char r, g, b, *c;
cvs_table = (unsigned char*) malloc(256);
for (j=0; j<256; j++) {
xc.pixel = j;
XQueryColor(dpy, attrib.colormap, &xc);
r = xc.red>>8;
g = xc.green>>8;
b = xc.blue>>8;
cvs_table[j]=color_table[(((6*g)>>8)*36)+(((6*r)>>8)*6)+((6*b)>>8)];
}
cvs_table[255] = color->pix;
c = image->data;
k = image->bytes_per_line * image->height;
for (j=0; j<k; j++) {
*c = cvs_table[*c];
c++;
}
free(cvs_table);
XFreeColormap(dpy, attrib.colormap);
}
if (height == 0 || height == image->height) {
return image;
}
return ximage_rescale(image, height);
}
XImage *
readEPS(char *file, int height, Colordata *color)
{
XImage *ximage;
char scan[80], buf[512];
double x1, x2, y1, y2, res;
int l, width, zip;
char *tmp;
#ifdef ZLIB
gzFile fd;
#else
FILE * fd;
#endif
zip = 0;
tmp = mk_tmp(".png");
if (!tmp) return NULL;
#ifdef ZLIB
strcpy(buf, file);
l = strlen(file);
if (l>=3 && !strcmp(file+l-3, ".gz"))
zip = -1;
fd = gzopen(buf, "r");
if (!fd && zip==0) {
strcat(buf, ".gz");
fd = gzopen(buf, "r");
if (!fd) return NULL;
zip = 1;
}
width = 0;
while (!gzeof(fd)) {
gzgets(fd, buf, 256);
if (!strncasecmp(buf, "%%HiResBoundingBox:", 19)) {
sscanf(buf, "%s %lf %lf %lf %lf", scan, &x1, &y1, &x2, &y2);
width = -1;
break;
}
}
gzclose(fd);
#else
fd = fopen(file, "r");
width = 0;
while (!feof(fd)) {
fgets(buf, 256, fd);
if (!strncasecmp(buf, "%%HiResBoundingBox:", 19)) {
sscanf(buf, "%s %lf %lf %lf %lf", scan, &x1, &y1, &x2, &y2);
width = 1;
break;
}
}
fclose(fd);
#endif
if (!width) {
return NULL;
}
res = (72.0 * height) / y2;
width = (int) (0.999 + height * x2 / y2);
if (zip)
sprintf(buf, "zcat %s%s | gs -r%f -sDEVICE=pngalpha -dNOPAUSE -dQUIET "
"-g%dx%d -sOutputFile=%s - -c quit",
file, (zip==1)?".gz":"", res, width, height, tmp);
else
sprintf(buf, "gs -r%f -sDEVICE=pngalpha -dNOPAUSE -dQUIET -g%dx%d "
"-sOutputFile=%s %s -c quit",
res, width, height, tmp, file);
system(buf);
ximage = readPNG(tmp, 0, color);
unlink(tmp);
return ximage;
}
XImage *
readSVG(char *file, int height, Colordata *color)
{
XImage * ximage;
char buf[512];
char *tmp;
int l, zip;
#ifdef ZLIB
gzFile fd;
#else
FILE * fd;
#endif
zip = 0;
tmp = mk_tmp(".png");
if (!tmp) return NULL;
#ifdef ZLIB
strcpy(buf, file);
fd = gzopen(buf, "r");
l = strlen(file);
if (l>=3 && !strcmp(file+l-3, ".gz"))
zip = -1;
if (!fd && zip==0) {
strcat(buf, ".gz");
fd = gzopen(buf, "r");
if (!fd) return NULL;
zip = 1;
}
gzclose(fd);
#endif
sprintf(buf, "inkscape %s%s --export-height=%d --export-png=%s",
file, (zip==1)?".gz":"", height, tmp);
system(buf);
ximage = readPNG(tmp, 0, color);
unlink(tmp);
return ximage;
}
int image_type(char *name)
{
int k, l, ret;
char *ptr;
ret = -1;
if ((k=strlen(name))>=4 && name[k-4] == '.') {
ptr = name + k-3;
for (l=0; l<num_flag_types; l++)
if (!strcasecmp(ptr, flag_formats[l])) { ret = l; break; }
}
if ((k=strlen(name))>=7 && name[k-7] == '.' && !strcmp(name+k-3, ".gz")) {
ptr = name + k-6;
for (l=0; l<num_flag_types; l++)
if (!strncasecmp(ptr, flag_formats[l], 3)) { ret = l; break; }
}
return ret;
}
XImage *
readIMG(ImageLayout *scene,
char *default_dir, char *file, int height, Colordata *color)
{
struct stat buf;
int k, l, s;
char *ptr;
char name[512];
char errstr[768];
XImage *image;
if (!file || !*file) {
return NULL;
}
*name = '\0';
if (*file == '/') /* absolute path */
strcpy(name, file);
else
if (!strncmp(file, "./", 2)) /* CWD relative */
strcpy(name, file+2);
else
if (!strncmp(file , "~/", 2)) { /* HOME relative */
ptr = getenv("HOME");
sprintf(name, "%s/%s", (ptr)? ptr:".", file+2);
} else
if (!strncmp(file , "$HOME/", 6)) { /* HOME relative */
ptr = getenv("HOME");
sprintf(name, "%s/%s", (ptr)? ptr:".", file+6);
} else
if (!strncmp(file , "$SHAREDIR/", 10)) { /* SHAREDIR relative */
sprintf(name, "%s/%s", SHAREDIR, file+10);
} else { /* just a rough specification */
if (image_type(file)>=0) { /* image extension specified */
if (default_dir && *default_dir)
sprintf(name, "%s/%s", default_dir, file);
else
strcpy(name, file);
} else { /* image extension not specified - try to find ... */
s = flag_size * (num_flag_dirs+1);
*name = '\0';
for (l=0; l<num_flag_dirs; l++) {
k = flag_ordering[l+s] - '1';
if (k>9)
k = flag_ordering[l+s] - 'a' + 9;
if (k<0 || k>=num_flag_dirs) continue;
sprintf(name, "%s/%s/%s.%s",
FLAGPATH, flag_dir[k], file, flag_type[k]);
if (!stat(name, &buf) && S_ISREG(buf.st_mode)) break;
strcat(name, ".gz");
if (!stat(name, &buf) && S_ISREG(buf.st_mode)) break;
}
}
}
if (!*name) {
strcpy(name, file);
image = NULL;
goto error;
}
l = strlen(name);
if (l<=2 || strcmp(name+l-3, ".gz")) {
if (stat(name, &buf) || !S_ISREG(buf.st_mode)) strcat(name, ".gz");
}
if (stat(name, &buf) || !S_ISREG(buf.st_mode)) {
image = NULL;
goto error;
}
k = image_type(name);
switch(k) {
case 0: image = readXPM(name, height, color); break;
case 1: image = readGIF(name, height, color); break;
case 2: image = readPNG(name, height, color); break;
case 3: image = readJPG(name, height, color); break;
case 4: image = readEPS(name, height, color); break;
case 5: image = readSVG(name, height, color); break;
default: image = NULL; break;
}
error:
if (!image) {
sprintf(errstr, msg[COULDNT_READ_IMAGE_FILE], name);
if (runlevel) {
if (error_msg) free(error_msg);
error_msg = strdup(errstr);
brief_menu = 4;
show_brief_menu(scene);
} else
fprintf(stderr, "%s\n", errstr);
}
return image;
}
Pixmap xim2pix(XImage *ximage)
{
GC gc;
XGCValues values;
Pixmap pixmap;
if (!ximage) return None;
pixmap = XCreatePixmap(dpy, datawin, ximage->width,
ximage->height, ximage->depth);
if (!pixmap) return pixmap;
/* set fg and bg in case we have an XYBitmap */
values.foreground = 1;
values.background = 0;
gc = XCreateGC(dpy, pixmap,
GCForeground | GCBackground, &values);
if (!gc) {
XFreePixmap(dpy, pixmap);
return None;
}
XPutImage(dpy, pixmap, gc, ximage, 0, 0, 0, 0,
ximage->width, ximage->height);
XFreeGC(dpy, gc);
return pixmap;
}
syntax highlighted by Code2HTML, v. 0.9.1