adding imlib2 code in.. NOT a lib yet... :) but playable code and loader

system


SVN revision: 27
This commit is contained in:
Carsten Haitzler 1999-08-01 22:14:11 +00:00
commit 520edea668
25 changed files with 6929 additions and 0 deletions

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
INSTALL = install
SRCS = rend.c ximage.c scale.c main.c rgba.c image.c color.c grab.c \
blend.c file.c
OBJS = $(SRCS:.c=.o)
BINDIR = /usr/local/bin
BIN = imlib2
LIBS = -L/usr/X11R6/lib/ -lX11 -lXext -ldl
CFLAGS = -O -g -mpentium -mcpu=pentium -march=pentium
imlib2: $(OBJS)
$(RM) $@
$(CC) -o $@ $(OBJS) $(LIBS)
$(CC) loader_png.c -o png.so -Wl,-soname -Wl,png.so -shared -lpng -lz -lm
clean::
$(RM) $(BIN) *.CKP *.ln *.BAK *.bak *.o *.so core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"*
c.o:
$(CC) $(CFLAGS) -I/usr/X11R6/include -c $< -o $@
load.o:
$(CC) $(CFLAGS) -I/usr/X11R6/include -c $< -o $@
install::
$(INSTALL) $(BIN) $(BINDIR)

63
README Normal file
View File

@ -0,0 +1,63 @@
Imlib 2.0 pre pre pre pre alpha toy code...
WARNING!
this isn't even a library yet - it's a single program thats modularised to
become a librayr once it's all debugged.
what you DO have here is:
color allocation & adjustment code - if in 8bbp or less it will cose the
larges colorcube it can that fits in your available colormap space - right
now the code uses the default colormap, but if you look at color.c carefully
you'll see the code will not be hard to change (have prefercnes as to size
of colorcube etc.)
does alpha blending onto any X drawable with any colormap.
does ``high quality'' rendering with dithering available for all modes up to
16bpp (1bpp, 8bpp, 15bpp, 16bpp).
probably has nasty endianess problems.
has VERY VERY VERY fast rendering code.
has anti-aliased scaling up and down code.
has a modularised loader system (works right now - but still possible
changes might have to be made)
simple to get this going:
mkdir ~/.loaders
mkdir ~/.loaders/image
cp png.so ~/.loaders/image
you just installed the png loader - it's theonly one i've written and it
isnt very good (comments in code - load.c) but it works.
the laoder system automagically updates yhe loaders were you to dump new
files there or overwrite the old ones to any program RUNTIME will pick up
the new code.. :) you dont even have to restart the program.. OOH what joy :)
the image caching is all there and the pixmap caching backend is there too.
there is nothign to generate pixmaps yet - that has yet to come (it will use
the rendering code in rend.c).
things that still need to be worked on:
* colormodifiers (to do gamma etc. correction - need to develop a new system
wherby i can uniquely tag pixmaps with a colormodifier ID for caching
properly).
* border scaling - you know - like E does now for buttons etc.
* saving functions
* image manipulation funcitons (flip, rotate, scale etc of original data)
* nice api for the actual library with context-like system (the api you see
here is actually going to be the internal api for imlib - a level down from
what api the user actually gets to see & use - all access to image data will
be goverend by going thru the api too rather than just snarfing structure
memebrs)
* a new name for imlib2.0 - 2.0 just sounds boring :)
* more loader / saver modules for jpeg, ppm, pgm, pgm, xpm, tiff etc...
* RGBA drawing area - basically a RGBA buffer with RGBA buffer ops written
(copyarea, poasteimage, fillrect, drawline, drawtext etc. so you can have a
little virtual RGBA framebuffer - also will include rectangle os ineterst
updating mechanism (so anly the parts of the RGBA buffer that were drawn to
are drawn and updated to the scren).
* more flim!

54
blend.c Normal file
View File

@ -0,0 +1,54 @@
#include "common.h"
#include "blend.h"
void
BlendRGBAToRGBA(DATA32 *src, int src_jump, DATA32 *dst, int dst_jump,
int w, int h)
{
int x, y;
DATA32 *p1, *p2;
for (y = 0; y < h; y++)
{
DATA8 a, nr, ng, nb, r, g, b, rr, gg, bb;
int tmp;
p1 = src + (y * (w + src_jump));
p2 = dst + (y * (w + dst_jump));
for (x = 0; x < w; x++)
{
a = (*p1 >> 24) & 0xff;
if (a < 255)
{
#if 1
r = 255 - a;
*p2 =
((((*p1 & 0x00ff00ff) * a) >> 8) & 0x00ff00ff) +
((((*p1 >> 8) & 0x00ff00ff) * a) & 0xff00ff00) +
((((*p2 & 0x00ff00ff) * r) >> 8) & 0x00ff00ff) +
((((*p2 >> 8) & 0x00ff00ff) * r) & 0xff00ff00);
#else
r = (*p1 ) & 0xff;
g = (*p1 >> 8 ) & 0xff;
b = (*p1 >> 16) & 0xff;
rr = (*p2 ) & 0xff;
gg = (*p2 >> 8 ) & 0xff;
bb = (*p2 >> 16) & 0xff;
tmp = (r - rr) * a;
nr = rr + ((tmp + (tmp >> 8) + 0x80) >> 8);
tmp = (g - gg) * a;
ng = gg + ((tmp + (tmp >> 8) + 0x80) >> 8);
tmp = (b - bb) * a;
nb = bb + ((tmp + (tmp >> 8) + 0x80) >> 8);
*p2 = ((nb & 0xff) << 16) | ((ng & 0xff) << 8) | (nr & 0xff);
#endif
}
else
*p2 = *p1;
p1++;
p2++;
}
}
}

6
blend.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __BLEND
#define __BLEND 1
void
BlendRGBAToRGBA(DATA32 *src, int src_jump, DATA32 *dst, int dst_jump,
int w, int h);
#endif

298
color.c Normal file
View File

@ -0,0 +1,298 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "common.h"
#include "color.h"
/* FIXME: DATA32 must become DATA8 */
DATA8 _dither_color_lut[256];
DATA8 _pal_type = 0;
void
AllocColorTable(Display *d, Colormap cmap)
{
if (AllocColors332(d, cmap))
return;
if (AllocColors232(d, cmap))
return;
if (AllocColors222(d, cmap))
return;
if (AllocColors221(d, cmap))
return;
if (AllocColors121(d, cmap))
return;
if (AllocColors111(d, cmap))
return;
if (AllocColors1(d, cmap))
return;
}
char
AllocColors332(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 8; r++)
{
for (g = 0; g < 8; g++)
{
for (b = 0; b < 4; b++)
{
XColor xcl;
int val;
val = (r << 5) | (r << 2) | (r >> 1);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 5) | (g << 2) | (g >> 1);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 6) | (b << 4) | (b << 2) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 0;
return 1;
}
char
AllocColors232(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 4; r++)
{
for (g = 0; g < 8; g++)
{
for (b = 0; b < 4; b++)
{
XColor xcl;
int val;
val = (r << 6) | (r << 4) | (r << 2) | (r);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 5) | (g << 2) | (g >> 1);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 6) | (b << 4) | (b << 2) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 1;
return 1;
}
char
AllocColors222(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 4; r++)
{
for (g = 0; g < 4; g++)
{
for (b = 0; b < 4; b++)
{
XColor xcl;
int val;
val = (r << 6) | (r << 4) | (r << 2) | (r);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 6) | (g << 4) | (g << 2) | (g);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 6) | (b << 4) | (b << 2) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 2;
return 1;
}
char
AllocColors221(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 4; r++)
{
for (g = 0; g < 4; g++)
{
for (b = 0; b < 2; b++)
{
XColor xcl;
int val;
val = (r << 6) | (r << 4) | (r << 2) | (r);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 6) | (g << 4) | (g << 2) | (g);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 3;
return 1;
}
char
AllocColors121(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 2; r++)
{
for (g = 0; g < 4; g++)
{
for (b = 0; b < 2; b++)
{
XColor xcl;
int val;
val = (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r << 2) | (r << 1) | (r);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 6) | (g << 4) | (g << 2) | (g);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 4;
return 1;
}
char
AllocColors111(Display *d, Colormap cmap)
{
int r, g, b, i = 0;
for (r = 0; r < 2; r++)
{
for (g = 0; g < 2; g++)
{
for (b = 0; b < 2; b++)
{
XColor xcl;
int val;
val = (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r << 2) | (r << 1) | (r);
xcl.red = (unsigned short)((val << 8) | (val));
val = (g << 7) | (g << 6) | (g << 5) | (g << 4) | (g << 3) | (g << 2) | (g << 1) | (g);
xcl.green = (unsigned short)((val << 8) | (val));
val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b);
xcl.blue = (unsigned short)((val << 8) | (val));
if (!XAllocColor(d, cmap, &xcl))
{
unsigned long pixels[256];
int j;
if (i > 0)
{
for(j = 0; j < i; j++)
pixels[j] = (unsigned long) _dither_color_lut[j];
XFreeColors(d, cmap, pixels, i, 0);
}
return 0;
}
_dither_color_lut[i] = xcl.pixel;
i++;
}
}
}
_pal_type = 5;
return 1;
}
char
AllocColors1(Display *d, Colormap cmap)
{
XColor xcl;
xcl.red = (unsigned short)(0x0000);
xcl.green = (unsigned short)(0x0000);
xcl.blue = (unsigned short)(0x0000);
XAllocColor(d, cmap, &xcl);
_dither_color_lut[0] = xcl.pixel;
xcl.red = (unsigned short)(0xffff);
xcl.green = (unsigned short)(0xffff);
xcl.blue = (unsigned short)(0xffff);
XAllocColor(d, cmap, &xcl);
_dither_color_lut[1] = xcl.pixel;
_pal_type = 6;
return 1;
}

23
color.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __COLOR
#define __COLOR 1
/* FIXME: DATA32 must become DATA8 */
extern DATA8 _dither_color_lut[256];
extern DATA8 _pal_type;
void
AllocColorTable(Display *d, Colormap cmap);
char
AllocColors332(Display *d, Colormap cmap);
char
AllocColors232(Display *d, Colormap cmap);
char
AllocColors222(Display *d, Colormap cmap);
char
AllocColors221(Display *d, Colormap cmap);
char
AllocColors121(Display *d, Colormap cmap);
char
AllocColors111(Display *d, Colormap cmap);
char
AllocColors1(Display *d, Colormap cmap);
#endif

13
common.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __COMMON
#define __COMMON 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DATA64 unsigned long long
#define DATA32 unsigned int
#define DATA16 unsigned short
#define DATA8 unsigned char
#endif

311
file.c Normal file
View File

@ -0,0 +1,311 @@
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include "file.h"
static void FileFieldWord(char *s, int num, char *wd);
char *
FileExtension(char *file)
{
char *p;
p = strrchr(file, '.');
if (p != NULL)
return(p + 1);
return("");
}
int
FileExists(char *s)
{
struct stat st;
if ((!s) || (!*s))
return(0);
if (stat(s, &st) < 0)
return(0);
return(1);
}
int
FileIsFile(char *s)
{
struct stat st;
if ((!s) || (!*s))
return(0);
if (stat(s, &st) < 0)
return(0);
if (S_ISREG(st.st_mode))
return(1);
return(0);
}
int
FileIsDir(char *s)
{
struct stat st;
if ((!s) || (!*s))
return(0);
if (stat(s, &st) < 0)
return(0);
if (S_ISDIR(st.st_mode))
return(1);
return(0);
}
char **
FileDir(char *dir, int *num)
{
int i, dirlen;
int done = 0;
DIR *dirp;
char **names;
struct dirent *dp;
if ((!dir) || (!*dir))
return(0);
dirp = opendir(dir);
if (!dirp)
{
*num = 0;
return(NULL);
}
/* count # of entries in dir (worst case) */
for (dirlen = 0; (dp = readdir(dirp)) != NULL; dirlen++);
if (!dirlen)
{
closedir(dirp);
*num = dirlen;
return(NULL);
}
names = (char **)malloc(dirlen * sizeof(char *));
if (!names)
return(NULL);
rewinddir(dirp);
for (i = 0; i < dirlen;)
{
dp = readdir(dirp);
if (!dp)
break;
if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
{
names[i] = strdup(dp->d_name);
i++;
}
}
if (i < dirlen)
dirlen = i; /* dir got shorter... */
closedir(dirp);
*num = dirlen;
/* do a simple bubble sort here to alphanumberic it */
while (!done)
{
done = 1;
for (i = 0; i < dirlen - 1; i++)
{
if (strcmp(names[i], names[i + 1]) > 0)
{
char *tmp;
tmp = names[i];
names[i] = names[i + 1];
names[i + 1] = tmp;
done = 0;
}
}
}
return(names);
}
void
FileFreeDirList(char **l, int num)
{
if (!l)
return;
while (num--)
if (l[num])
free(l[num]);
free(l);
return;
}
void
FileDel(char *s)
{
if ((!s) || (!*s))
return;
unlink(s);
return;
}
time_t
FileModDate(char *s)
{
struct stat st;
if ((!s) || (!*s))
return(0);
if (!stat(s, &st) < 0)
return(0);
if (st.st_mtime > st.st_ctime)
{
return(st.st_mtime);
}
else
return(st.st_ctime);
return(0);
}
char *
FileHomeDir(int uid)
{
static int usr_uid = -1;
static char *usr_s = NULL;
char *s;
struct passwd *pwd;
s = getenv("HOME");
if (s)
return strdup(s);
if (usr_uid < 0)
usr_uid = getuid();
if ((uid == usr_uid) && (usr_s))
{
return(strdup(usr_s));
}
pwd = getpwuid(uid);
if (pwd)
{
s = strdup(pwd->pw_dir);
if (uid == usr_uid)
usr_s = strdup(s);
return(s);
}
return NULL;
}
/* gets word number [num] in the string [s] and copies it into [wd] */
/* wd is NULL terminated. If word [num] does not exist wd = "" */
/* NB: this function now handles quotes so for a line: */
/* Hello to "Welcome sir - may I Help" Shub Foo */
/* Word 1 = Hello */
/* Word 2 = to */
/* Word 3 = Welcome sir - may I Help */
/* Word 4 = Shub */
/* word 5 = Foo */
char *
FileField(char *s, int field)
{
char buf[4096];
buf[0] = 0;
FileFieldWord(s, field + 1, buf);
if (buf[0])
{
if ((!strcmp(buf, "NULL")) ||
(!strcmp(buf, "(null)")))
return(NULL);
return(strdup(buf));
}
return(NULL);
}
static void
FileFieldWord(char *s, int num, char *wd)
{
char *cur, *start, *end;
int count, inword, inquote, len;
if (!s)
return;
if (!wd)
return;
*wd = 0;
if (num <= 0)
return;
cur = s;
count = 0;
inword = 0;
inquote = 0;
start = NULL;
end = NULL;
while ((*cur) && (count < num))
{
if (inword)
{
if (inquote)
{
if (*cur == '"')
{
inquote = 0;
inword = 0;
end = cur;
count++;
}
}
else
{
if (isspace(*cur))
{
end = cur;
inword = 0;
count++;
}
}
}
else
{
if (!isspace(*cur))
{
if (*cur == '"')
{
inquote = 1;
start = cur + 1;
}
else
start = cur;
inword = 1;
}
}
if (count == num)
break;
cur++;
}
if (!start)
return;
if (!end)
end = cur;
if (end <= start)
return;
len = (int)(end - start);
if (len > 4000)
len = 4000;
if (len > 0)
{
strncpy(wd, start, len);
wd[len] = 0;
}
return;
}

13
file.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __FILE
#define __FILE 1
char *FileExtension(char *file);
int FileExists(char *s);
int FileIsFile(char *s);
int FileIsDir(char *s);
char **FileDir(char *dir, int *num);
void FileFreeDirList(char **l, int num);
void FileDel(char *s);
time_t FileModDate(char *s);
char *FileHomeDir(int uid);
char *FileField(char *s, int field);
#endif

537
grab.c Normal file
View File

@ -0,0 +1,537 @@
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "common.h"
#include "grab.h"
static char _x_err = 0;
static void
Tmp_HandleXError(Display * d, XErrorEvent * ev)
{
d = NULL;
ev = NULL;
_x_err = 1;
}
DATA32 *
GrabDrawableToRGBA(Display *d, Drawable p, Pixmap m, Visual *v, Colormap cm,
int depth, int x, int y, int w, int h, char domask)
{
XErrorHandler prev_erh = NULL;
XWindowAttributes xatt, ratt;
char is_pixmap = 0, created_mask = 0, is_shm = 0, is_mshm = 0;
int i, pixel, mpixel;
int src_x, src_y, src_w, src_h, ow, oh, ox, oy;
int width, height, clipx, clipy, inx, iny;
XShmSegmentInfo shminfo, mshminfo;
XImage *xim = NULL, *mxim = NULL;
static char x_does_shm = -1;
DATA32 *data, *ptr;
DATA8 rtab[256], gtab[256], btab[256];
XColor cols[256];
ox = x;
oy = y;
ow = w;
oh = h;
/* FIXME: hmm - need to co-ordinate this with the app */
XGrabServer(d);
prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError);
_x_err = 0;
/* lets see if its a pixmap or not */
XGetWindowAttributes(d, p, &xatt);
XSync(d, False);
if (_x_err)
is_pixmap = 1;
/* reset our error handler */
XSetErrorHandler((XErrorHandler) prev_erh);
if (is_pixmap)
{
Window dw;
XGetGeometry(d, p, &dw, &src_x, &src_y,
(unsigned int *)&src_w, (unsigned int *)&src_h,
(unsigned int *)&src_x, (unsigned int *)&xatt.depth);
src_x = 0;
src_y = 0;
}
else
{
Window dw;
XGetWindowAttributes(d, xatt.root, &ratt);
XTranslateCoordinates(d, p, xatt.root, 0, 0, &src_x, &src_y, &dw);
if ((xatt.map_state != IsViewable) &&
(xatt.backing_store == NotUseful))
{
XUngrabServer(d);
return NULL;
}
}
/* clip to the drawable tree and screen */
clipx = 0;
clipy = 0;
width = xatt.width - x;
height = xatt.height - y;
if (width > w)
width = w;
if (height > h)
height = h;
if (!is_pixmap)
{
if ((src_x + x + width) > ratt.width)
width = ratt.width - (src_x + x);
if ((src_y + y + height) > ratt.height)
height = ratt.height - (src_y + y);
}
if (x < 0)
{
clipx = -x;
width += x;
x = 0;
}
if (y < 0)
{
clipy = -y;
height += y;
y = 0;
}
if (!is_pixmap)
{
if ((src_x + x) < 0)
{
clipx -= (src_x + x);
width += (src_x + x);
x = -src_x;
}
if ((src_y + y) < 0)
{
clipy -= (src_y + y);
height += (src_y + y);
y = -src_y;
}
}
if ((width <= 0) || (height <= 0))
{
XUngrabServer(d);
return NULL;
}
w = width;
h = height;
if ((!is_pixmap) && (domask) && (!m))
{
int ord, rect_no = 0;
XRectangle *r = NULL;
r = XShapeGetRectangles(d, p, ShapeBounding, &rect_no, &ord);
if (r)
{
if (!((rect_no == 1) &&
(r[0].x == 0) && (r[0].y == 0) &&
(r[0].width == xatt.width) && (r[0].height == xatt.height)))
{
XGCValues gcv;
GC gc;
created_mask = 1;
m = XCreatePixmap(d, p, w, h, 1);
gcv.foreground = 0;
gc = XCreateGC(d, m, GCForeground, &gcv);
XFillRectangle(d, m, gc, 0, 0, w, h);
XSetForeground(d, gc, 1);
for (i = 0; i < rect_no; i++)
XFillRectangle(d, m, gc,
r[i].x - x, r[i].y - y,
r[i].width, r[i].height);
XFreeGC(d, gc);
}
XFree(r);
}
}
/* Create an Ximage (shared or not) */
if (x_does_shm < 0)
{
if (XShmQueryExtension(d))
x_does_shm = 1;
else
x_does_shm = 0;
}
prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError);
_x_err = 0;
if (x_does_shm)
{
xim = XShmCreateImage(d, v, xatt.depth, ZPixmap, NULL,
&shminfo, w, h);
if (!xim)
xim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
else
{
XSync(d, False);
if (_x_err)
{
XDestroyImage(xim);
xim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
_x_err = 0;
}
else
{
shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line *
xim->height, IPC_CREAT | 0666);
if (shminfo.shmid < 0)
{
XDestroyImage(xim);
xim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
}
else
{
shminfo.shmaddr = xim->data = shmat(shminfo.shmid, 0, 0);
if (xim->data != (char *)-1)
{
shminfo.readOnly = False;
XShmAttach(d, &shminfo);
is_shm = 1;
}
else
{
shmctl(shminfo.shmid, IPC_RMID, 0);
XDestroyImage(xim);
xim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
}
}
}
}
}
else
xim = XGetImage(d, p, x, y, w, h, 0xffffffff, ZPixmap);
if (is_shm)
{
XShmGetImage(d, p, xim, x, y, 0xffffffff);
XSync(d, False);
if (_x_err)
{
shmdt(shminfo.shmaddr);
shmctl(shminfo.shmid, IPC_RMID, 0);
XDestroyImage(xim);
xim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
is_shm = 0;
}
}
XSetErrorHandler((XErrorHandler) prev_erh);
if ((m) && (domask))
{
prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError);
_x_err = 0;
if (x_does_shm)
{
mxim = XShmCreateImage(d, v, 1, ZPixmap, NULL,
&mshminfo, w, h);
if (!mxim)
mxim = XGetImage(d, p, 0, 0, w, h,
0xffffffff, ZPixmap);
else
{
XSync(d, False);
if (_x_err)
{
XDestroyImage(mxim);
xim = XGetImage(d, p, 0, 0, w, h,
0xffffffff, ZPixmap);
_x_err = 0;
}
else
{
mshminfo.shmid = shmget(IPC_PRIVATE,
mxim->bytes_per_line *
mxim->height, IPC_CREAT | 0666);
if (mshminfo.shmid < 0)
{
XDestroyImage(mxim);
mxim = XGetImage(d, p, 0, 0, w, h,
0xffffffff, ZPixmap);
}
else
{
mshminfo.shmaddr = xim->data =
shmat(mshminfo.shmid, 0, 0);
if (mxim->data != (char *)-1)
{
mshminfo.readOnly = False;
XShmAttach(d, &mshminfo);
is_mshm = 1;
}
else
{
shmctl(mshminfo.shmid, IPC_RMID, 0);
XDestroyImage(mxim);
mxim = XGetImage(d, p, x, y, w, h,
0xffffffff, ZPixmap);
}
}
}
}
}
else
mxim = XGetImage(d, m, 0, 0, w, h, 0xffffffff, ZPixmap);
if (is_mshm)
{
XShmGetImage(d, p, mxim, 0, 0, 0xffffffff);
XSync(d, False);
if (_x_err)
{
shmdt(mshminfo.shmaddr);
shmctl(mshminfo.shmid, IPC_RMID, 0);
XDestroyImage(mxim);
mxim = XGetImage(d, p, 0, 0, w, h,
0xffffffff, ZPixmap);
is_mshm = 0;
}
XSetErrorHandler((XErrorHandler) prev_erh);
}
}
if ((is_shm) || (is_mshm))
{
XSync(d, False);
XUngrabServer(d);
XSync(d, False);
}
else
XUngrabServer(d);
if ((xatt.depth == 1) && (!cm) && (is_pixmap))
{
rtab[0] = 0;
gtab[0] = 0;
btab[0] = 0;
rtab[1] = 255;
gtab[1] = 255;
btab[1] = 255;
}
else if (xatt.depth <= 8)
{
if ((!is_pixmap) && (!cm))
{
cm = xatt.colormap;
if (cm == None)
cm = ratt.colormap;
}
else
cm = ratt.colormap;
for (i = 0; i < (1 << xatt.depth); i++)
{
cols[i].pixel = i;
cols[i].flags = DoRed | DoGreen | DoBlue;
}
XQueryColors(d, cm, cols, 1 << xatt.depth);
for (i = 0; i < (1 << xatt.depth); i++)
{
rtab[i] = cols[i].red >> 8;
gtab[i] = cols[i].green >> 8;
btab[i] = cols[i].blue >> 8;
}
}
data = malloc(ow * oh * sizeof(DATA32));
if (data)
{
inx = x - ox;
iny = y - oy;
/* go thru the XImage and convert */
switch (depth)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
if (mxim)
{
for (y = 0; y < h; y++)
{
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
mpixel = XGetPixel(mxim, x, y);
*ptr++ = (0xff000000 >> (mpixel << 31)) |
(btab[pixel & 0xff] << 16) |
(gtab[pixel & 0xff] << 8) |
(rtab[pixel & 0xff]);
}
}
}
else
{
for (y = 0; y < h; y++)
{
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
*ptr++ = 0xff000000 |
(btab[pixel & 0xff] << 16) |
(gtab[pixel & 0xff] << 8) |
(rtab[pixel & 0xff]);
}
}
}
break;
case 16:
if (mxim)
{
for (y = 0; y < h; y++)
{
DATA8 r, g, b;
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
r = (pixel >> 8) & 0xf8;
g = (pixel >> 3) & 0xfc;
b = (pixel << 3) & 0xf8;
mpixel = XGetPixel(mxim, x, y);
*ptr++ = (0xff000000 >> (mpixel << 31)) |
(b << 16) |
(g << 8) |
(r);
}
}
}
else
{
for (y = 0; y < h; y++)
{
DATA8 r, g, b;
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
r = (pixel >> 8) & 0xf8;
g = (pixel >> 3) & 0xfc;
b = (pixel << 3) & 0xf8;
*ptr++ = 0xff000000 |
(b << 16) |
(g << 8) |
(r);
}
}
}
break;
case 15:
if (mxim)
{
for (y = 0; y < h; y++)
{
DATA8 r, g, b;
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
r = (pixel >> 7) & 0xf8;
g = (pixel >> 2) & 0xf8;
b = (pixel << 3) & 0xf8;
mpixel = XGetPixel(mxim, x, y);
*ptr++ = (0xff000000 >> (mpixel << 31)) |
(b << 16) |
(g << 8) |
(r);
}
}
}
else
{
for (y = 0; y < h; y++)
{
DATA8 r, g, b;
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
r = (pixel >> 7) & 0xf8;
g = (pixel >> 2) & 0xf8;
b = (pixel << 3) & 0xf8;
*ptr++ = 0xff000000 |
(b << 16) |
(g << 8) |
(r);
}
}
}
break;
case 24:
case 32:
if (mxim)
{
for (y = 0; y < h; y++)
{
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
mpixel = XGetPixel(mxim, x, y);
*ptr++ = (0xff000000 >> (mpixel << 31)) |
((pixel & 0x000000ff) << 16) |
((pixel & 0x0000ff00)) |
((pixel & 0x00ff0000) >> 16);
}
}
}
else
{
for (y = 0; y < h; y++)
{
ptr = data + ((y + iny) * ow) + inx;
for (x = 0; x < w; x++)
{
pixel = XGetPixel(xim, x, y);
*ptr++ = 0xff000000 |
((pixel & 0x000000ff) << 16) |
((pixel & 0x0000ff00)) |
((pixel & 0x00ff0000) >> 16);
}
}
}
break;
default:
break;
}
}
/* destroy the Ximage */
if (is_shm)
{
XSync(d, False);
XShmDetach(d, &shminfo);
shmdt(shminfo.shmaddr);
shmctl(shminfo.shmid, IPC_RMID, 0);
}
if ((is_mshm) && (mxim))
{
XShmDetach(d, &mshminfo);
shmdt(mshminfo.shmaddr);
shmctl(mshminfo.shmid, IPC_RMID, 0);
}
XDestroyImage(xim);
if (created_mask)
XFreePixmap(d, m);
if (mxim)
XDestroyImage(mxim);
return data;
}

6
grab.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __GRAB
#define __GRAB 1
DATA32 *
GrabDrawableToRGBA(Display *d, Drawable p, Pixmap m, Visual *v, Colormap cm,
int depth, int x, int y, int w, int h, char domask);
#endif

679
image.c Normal file
View File

@ -0,0 +1,679 @@
#include "common.h"
#include <time.h>
#include <string.h>
#include <dlfcn.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include "image.h"
#include "file.h"
static ImlibImage *images = NULL;
static ImlibImagePixmap *pixmaps = NULL;
static ImlibLoader *loaders = NULL;
static int cache_size = 4096 * 1024;
void
SetCacheSize(int size)
{
cache_size = size;
CleanupImageCache();
CleanupImagePixmapCache();
}
int
GetCacheSize(void)
{
return cache_size;
}
ImlibImage *
ProduceImage(void)
{
ImlibImage *im;
im = malloc(sizeof(ImlibImage));
im->data = NULL;
im->file = NULL;
im->moddate = 0;
im->flags = F_NONE;
im->border.left = 0;
im->border.right = 0;
im->border.top = 0;
im->border.bottom = 0;
im->references = 0;
im->w = 0;
im->h = 0;
im->loader = NULL;
im->next = NULL;
return im;
}
void
ConsumeImage(ImlibImage *im)
{
if (im->file)
free(im->file);
if (im->data)
free(im->data);
if (im->format)
free(im->format);
free(im);
}
ImlibImage *
FindCachedImage(char *file)
{
ImlibImage *im, *previous_im;
im = images;
previous_im = NULL;
/* go through the images list */
while (im)
{
/* if the filenames match */
if (!strcmp(file, im->file))
{
/* move the image to the head of the pixmap list */
if (previous_im)
{
previous_im->next = im->next;
im->next = images;
images = im;
}
/* return it */
return im;
}
previous_im = im;
im = im->next;
}
return NULL;
}
void
AddImageToCache(ImlibImage *im)
{
im->next = images;
images = im;
}
void
RemoveImageFromCache(ImlibImage *im)
{
ImlibImage *current_im, *previous_im;
current_im = images;
previous_im = NULL;
while (current_im)
{
if (im == current_im)
{
if (previous_im)
previous_im->next = im->next;
else
images = im->next;
return;
}
current_im = current_im->next;
}
}
int
CurrentCacheSize(void)
{
ImlibImage *im;
ImlibImagePixmap *ip;
int current_cache = 0;
im = images;
while(im)
{
if (im->references == 0)
{
if (!(IMAGE_IS_VALID(im)))
{
RemoveImageFromCache(im);
ConsumeImage(im);
}
else
current_cache += im->w * im->h * sizeof(DATA32);
}
im = im->next;
}
ip = pixmaps;
while(ip)
{
if (ip->references == 0)
{
if (!(IMAGE_IS_VALID(ip->image)))
{
RemoveImagePixmapFromCache(ip);
ConsumeImagePixmap(ip);
}
else
{
if (ip->pixmap)
{
if (ip->depth < 8)
current_cache += ip->w * ip->h * (ip->depth / 8);
else if (ip->depth == 8)
current_cache += ip->w * ip->h;
else if (ip->depth <= 16)
current_cache += ip->w * ip->h * 2;
else if (ip->depth <= 32)
current_cache += ip->w * ip->h * 4;
}
if (ip->mask)
current_cache += ip->w * ip->h / 8;
}
}
ip = ip->next;
}
}
void
CleanupImageCache(void)
{
ImlibImage *im, *im_last;
int current_cache;
char operation = 1;
current_cache = CurrentCacheSize();
while ((current_cache > cache_size) || (operation));
{
im_last = NULL;
operation = 0;
im = images;
while(im)
{
if (im->references <= 0)
im_last = im;
im = im->next;
}
if (im_last)
{
RemoveImageFromCache(im_last);
ConsumeImage(im_last);
operation = 1;
}
current_cache = CurrentCacheSize();
}
}
ImlibImagePixmap *
ProduceImagePixmap(void)
{
ImlibImagePixmap *ip;
ip = malloc(sizeof(ImlibImagePixmap));
ip->w = 0;
ip->h = 0;
ip->pixmap = 0;
ip->mask = 0;
ip->display = NULL;
ip->visual = NULL;
ip->depth = 0;
ip->mode_count = 0;
ip->image = NULL;
ip->references = 0;
ip->next = NULL;
return ip;
}
void
ConsumeImagePixmap(ImlibImagePixmap *ip)
{
if (ip->pixmap)
XFreePixmap(ip->display, ip->pixmap);
if (ip->mask)
XFreePixmap(ip->display, ip->mask);
free(ip);
}
ImlibImagePixmap *
FindCachedImagePixmap(ImlibImage *im, int w, int h, Display *d, Visual *v,
int depth, int mode_count)
{
ImlibImagePixmap *ip, *previous_ip;
ip = pixmaps;
previous_ip = NULL;
/* go through the pixmap list */
while (ip)
{
/* if all the pixmap attributes match */
if ((ip->w == w) && (ip->h == h) && (ip->depth == depth) &&
(ip->visual == v) && (ip->display == d) &&
(ip->mode_count == mode_count))
{
/* move the pixmap to the head of the pixmap list */
if (previous_ip)
{
previous_ip->next = ip->next;
ip->next = pixmaps;
pixmaps = ip;
}
/* return it */
return ip;
}
previous_ip = ip;
ip = ip->next;
}
return NULL;
}
void
AddImagePixmapToCache(ImlibImagePixmap *ip)
{
ip->next = pixmaps;
pixmaps = ip;
}
void
RemoveImagePixmapFromCache(ImlibImagePixmap *ip)
{
ImlibImagePixmap *current_ip, *previous_ip;
current_ip = pixmaps;
previous_ip = NULL;
while (current_ip)
{
if (ip == current_ip)
{
if (previous_ip)
previous_ip->next = ip->next;
else
pixmaps = ip->next;
return;
}
current_ip = current_ip->next;
}
}
void
CleanupImagePixmapCache()
{
ImlibImagePixmap *ip, *ip_last;
int current_cache;
char operation = 1;
current_cache = CurrentCacheSize();
while ((current_cache > cache_size) || (operation));
{
ip_last = NULL;
operation = 0;
ip = pixmaps;
while(ip)
{
if (ip->references <= 0)
ip_last = ip;
ip = ip->next;
}
if (ip_last)
{
RemoveImagePixmapFromCache(ip_last);
ConsumeImagePixmap(ip_last);
operation = 1;
}
current_cache = CurrentCacheSize();
}
}
ImlibLoader *
ProduceLoader(char *file)
{
ImlibLoader *l;
void (*l_formats)(ImlibLoader *l) ;
l = malloc(sizeof(ImlibLoader));
l->num_formats = 0;
l->formats = NULL;
l->handle = dlopen(file, RTLD_NOW);
if (!l->handle)
{
free(l);
return NULL;
}
l->load = dlsym(l->handle, "load");
l->save = dlsym(l->handle, "save");
l_formats = dlsym(l->handle, "formats");
if ((!(l->load)) || (!(l->save)) || (!(l_formats)))
{
dlclose(l->handle);
free(l);
return NULL;
}
l_formats(l);
l->file = strdup(file);
l->next = NULL;
return l;
}
char **
ListLoaders(int *num_ret)
{
char **list = NULL, **l, s[4096], *home;
int num, i, pi = 0;
*num_ret = 0;
home = FileHomeDir(getuid());
sprintf(s, "%s/.loaders/image/", home);
l = FileDir(s, &num);
if (num > 0)
{
*num_ret += num;
list = malloc(sizeof(char *) * *num_ret);
for (i = 0; i < num; i++)
{
sprintf(s, "%s/.loaders/image/%s", home, l[i]);
list[i] = strdup(s);
}
pi = i;
FileFreeDirList(l, num);
}
sprintf(s, "/usr/lib/loaders/image/");
l = FileDir(s, &num);
if (num > 0)
{
*num_ret += num;
list = realloc(list, sizeof(char *) * *num_ret);
for (i = 0; i < num; i++)
{
sprintf(s, "/usr/lib/loaders/image/%s", l[i]);
list[pi + i] = strdup(s);
}
FileFreeDirList(l, num);
free(home);
}
return list;
}
void
ConsumeLoader(ImlibLoader *l)
{
if (l->file)
free(l->file);
if (l->handle)
dlclose(l->handle);
if (l->formats)
{
int i;
for (i = 0; i < l->num_formats; i++)
free(l->formats[i]);
free(l->formats);
}
free(l);
}
void
RescanLoaders(void)
{
static time_t last_scan_time = 0;
static time_t last_modified_home_time = 0;
static time_t last_modified_system_time = 0;
time_t current_time;
char s[4096], *home;
char do_reload = 0;
/* dont stat the dir and rescan if we checked in the last 5 seconds */
current_time = time(NULL);
if ((current_time - last_scan_time) < 5)
return;
/* ok - was the system loaders dir contents modified ? */
last_scan_time = current_time;
if (FileIsDir("/usr/lib/loaders/image/"))
{
current_time = FileModDate("/usr/lib/loaders/image/");
if (current_time > last_modified_system_time)
{
/* yup - set the "do_reload" flag */
do_reload = 1;
last_modified_system_time = current_time;
}
}
/* ok - was the users own loaders dir contents modified ? */
home = FileHomeDir(getuid());
sprintf(s, "%s/.loaders/image/", home);
free(home);
if (FileIsDir(s))
{
current_time = FileModDate(s);
if (current_time > last_modified_home_time)
{
/* yup - set the "do_reload" flag */
do_reload = 1;
last_modified_home_time = current_time;
}
}
/* if we dont ned to reload the loaders - get out now */
if (!do_reload)
return;
RemoveAllLoaders();
LoadAllLoaders();
}
void
RemoveAllLoaders(void)
{
ImlibLoader *l, *il;
l = loaders;
while(l)
{
il = l;
l = l->next;
ConsumeLoader(il);
}
loaders = NULL;
}
void
LoadAllLoaders(void)
{
int i, num;
char **list;
list = ListLoaders(&num);
if (!list)
return;
for (i = num - 1; i >= 0; i--)
{
ImlibLoader *l;
l = ProduceLoader(list[i]);
if (l)
{
l->next = loaders;
loaders = l;
}
if (list[i])
free(list[i]);
}
free(list);
}
ImlibLoader *
FindBestLoaderForFile(char *file)
{
char *extension, *lower;
ImlibLoader *l = NULL;
/* use the file extension for a "best guess" as to what loader to try */
/* first at any rate */
extension = strdup(FileExtension(file));
/* change the extensiont o all lwoer case as all "types" are listed as */
/* lower case strings fromt he loader that represent all the possible */
/* extensions that file format could have */
lower = extension;
while (*lower)
{
*lower = tolower(*lower);
lower++;
}
/* go through the loaders - first loader that claims to handle that */
/* image type (extension wise) wins as a first guess to use - NOTE */
/* this is an OPTIMISATION - it is possible the file has no extension */
/* or has an unrecognised one but still is loadable by a loader. */
/* if thkis initial loader failes to load the load mechanism will */
/* systematically go from most recently used to least recently used */
/* loader until one succeeds - or none are left and all have failed */
/* and only if all fail does the laod fail. the lao9der that does */
/* succeed gets it way tot he head of the list so it's going */
/* to be used first next time in this search mechanims - this */
/* assumes you tend to laod a few image types and ones generally */
/* of the same format */
l = loaders;
while (l)
{
int i;
for (i = 0; i < l->num_formats; i++)
{
if (!strcmp(l->formats[i], extension))
{
free(extension);
return l;
}
}
l = l->next;
}
free(extension);
return l;
}
ImlibImage *
LoadImage(char *file)
{
ImlibImage *im;
ImlibLoader *best_loader;
/* see if we alreayd have the image cached */
im = FindCachedImage(file);
/* if we found a cached image and we shoudl always check that it is */
/* accurate to the disk conents if they changed since we last loaded */
/* and that it is still a valid image */
if ((im) && (IMAGE_IS_VALID(im)) && (IMAGE_ALWAYS_CHECK_DISK(im)))
{
time_t current_modified_time;
current_modified_time = FileModDate(file);
/* if the file on disk is newer than the cached one */
if (current_modified_time > im->moddate)
{
/* invalidate image */
im->flags &= F_INVALID;
}
else
{
/* image is ok to re-use - program is just being stupid loading */
/* the same data twice */
im->references++;
return im;
}
}
/* either image in cache is invalid or we dont even have it in cache */
/* so produce a new one and load an image into that */
im = ProduceImage();
im->file = strdup(file);
im->moddate = FileModDate(file);
/* ok - just check all our loaders are up to date */
RescanLoaders();
/* take a guess by extension on the best loader to use */
best_loader = FindBestLoaderForFile(file);
if (best_loader)
best_loader->load(im);
/* width is still 0 - the laoder didnt manage to do anything */
if (im->w == 0)
{
ImlibLoader *l, *previous_l = NULL;
l = loaders;
/* run through all loaders and try load until one succeeds */
while ((l) && (im->w == 0))
{
/* if its not the best loader that alreayd failed - try load */
if (l != best_loader)
l->load(im);
/* if it failed - advance */
if (im->w == 0)
{
previous_l = l;
l = l->next;
}
}
/* if we have a loader then its the loader that succeeded */
/* move the successful loader to the head of the list */
/* as long as it's not alreayd at the head of the list */
if ((l) && (previous_l))
{
im->loader = l;
previous_l->next = l->next;
l->next = loaders;
loaders = l;
}
}
else
im->loader = best_loader;
/* all loaders have been tried and they all failed. free the skeleton */
/* image struct we had and return NULL */
if (im->w == 0)
{
ConsumeImage(im);
return NULL;
}
#if 0
/* FIXME: need to turn this png loading function into a loader andf then */
/* remove the below stuff */
im->data = RGBA_Load(file, &(im->w), &(im->h));
im->flags = F_HAS_ALPHA;
#endif
/* the laod succeeded - make sure the image is refernenced then add */
/* it to our cache */
im->references = 1;
AddImageToCache(im);
return im;
}
ImlibImagePixmap *
FindImlibImagePixmapByID(Display *d, Pixmap p)
{
ImlibImagePixmap *ip;
ip = pixmaps;
/* go through the pixmap list */
while (ip)
{
/* if all the pixmap ID & Display match */
if ((ip->pixmap == p) && (ip->display == d))
return ip;
ip = ip->next;
}
return NULL;
}
void
FreeImage(ImlibImage *im)
{
if (im->references > 0)
{
im->references--;
CleanupImageCache();
}
}
void
FreePixmap(Display *d, Pixmap p)
{
ImlibImagePixmap *ip;
ip = FindImlibImagePixmapByID(d, p);
if (ip->references > 0)
{
ip->references--;
CleanupImagePixmapCache();
}
}

97
image.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef __IMAGE
# define __IMAGE 1
typedef enum _iflags Iflags;
typedef struct _imlibimage ImlibImage;
typedef struct _imlibimagepixmap ImlibImagePixmap;
typedef struct _imlibborder ImlibBorder;
typedef struct _imlibloader ImlibLoader;
enum _iflags
{
F_NONE = 0,
F_HAS_ALPHA = (1 << 0),
F_UNLOADED = (1 << 1),
F_UNCACHEABLE = (1 << 2),
F_ALWAYS_CHECK_DISK = (1 << 3),
F_INVALID = (1 << 4)
};
struct _imlibborder
{
int left, right, top, bottom;
};
struct _imlibimage
{
char *file;
int w, h;
DATA32 *data;
Iflags flags;
time_t moddate;
ImlibBorder border;
int references;
ImlibLoader *loader;
ImlibImage *next;
char *format;
};
struct _imlibimagepixmap
{
int w, h;
Pixmap pixmap, mask;
Display *display;
Visual *visual;
int depth;
int mode_count;
ImlibImage *image;
int references;
ImlibImagePixmap *next;
};
struct _imlibloader
{
char *file;
int num_formats;
char **formats;
void *handle;
char (*load)(ImlibImage *im);
char (*save)(ImlibImage *im);
ImlibLoader *next;
};
void SetCacheSize(int size);
int GetCacheSize(void);
ImlibImage *ProduceImage(void);
void ConsumeImage(ImlibImage *im);
ImlibImage *FindCachedImage(char *file);
void AddImageToCache(ImlibImage *im);
void RemoveImageFromCache(ImlibImage *im);
void CleanupImageCache(void);
ImlibImagePixmap *ProduceImagePixmap(void);
void ConsumeImagePixmap(ImlibImagePixmap *ip);
ImlibImagePixmap *FindCachedImagePixmap(ImlibImage *im, int w, int h,
Display *d, Visual *v,
int depth, int mode_count);
void AddImagePixmapToCache(ImlibImagePixmap *ip);
void RemoveImagePixmapFromCache(ImlibImagePixmap *ip);
void CleanupImagePixmapCache();
ImlibLoader *ProduceLoader(char *file);
char **ListLoaders(int *num_ret);
void ConsumeLoader(ImlibLoader *l);
void RescanLoaders(void);
void RemoveAllLoaders(void);
void LoadAllLoaders(void);
ImlibLoader *FindBestLoaderForFile(char *file);
ImlibImage *LoadImage(char *file);
ImlibImagePixmap *FindImlibImagePixmapByID(Display *d, Pixmap p);
void FreeImage(ImlibImage *im);
void FreePixmap(Display *d, Pixmap p);
# define IMAGE_HAS_ALPHA(im) (im->flags & F_HAS_ALPHA)
# define IMAGE_IS_UNLOADED(im) (im->flags & F_UNLOADED)
# define IMAGE_IS_UNCACHEABLE(im) (im->flags & F_UNCACHEABLE)
# define IMAGE_ALWAYS_CHECK_DISK(im) (im->flags & F_ALWAYS_CHECK_DISK)
# define IMAGE_IS_VALID(im) (!(im->flags & F_INVALID))
#endif

162
loader_png.c Normal file
View File

@ -0,0 +1,162 @@
#include "common.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include "image.h"
#include <png.h>
/* this is a quick sample png loader module... nioce and small isnt it? */
/* PNG stuff */
#define PNG_BYTES_TO_CHECK 4
static void *
_load_PNG (int *ww, int *hh, FILE *f)
{
png_structp png_ptr;
png_infop info_ptr;
unsigned char *data, **lines;
int i, bit_depth, color_type, interlace_type;
unsigned char buf[PNG_BYTES_TO_CHECK];
int w, h;
fread(buf, 1, PNG_BYTES_TO_CHECK, f);
if (!png_check_sig(buf, PNG_BYTES_TO_CHECK))
{
rewind(f);
return NULL;
}
rewind(f);
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
rewind(f);
return NULL;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
rewind(f);
return NULL;
}
if (setjmp(png_ptr->jmpbuf))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
rewind(f);
return NULL;
}
png_init_io(png_ptr, f);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)(&w), (png_uint_32 *)(&h),
&bit_depth, &color_type, &interlace_type,
NULL, NULL);
/* Palette -> RGB */
if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
png_set_expand(png_ptr);
/* 16bit color -> 8bit color */
png_set_strip_16(png_ptr);
/* pack all pixels to byte boundaires */
png_set_packing(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
*ww = w;
*hh = h;
data = malloc(w * h * 4);
lines = (unsigned char **)malloc(h * sizeof(unsigned char *));
for (i = 0; i < h; i++)
lines[i] = data + (i * w * 4);
png_read_image(png_ptr, lines);
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
free(lines);
return data;
}
DATA32 *
RGBA_Load(char *file, int *w, int *h)
{
FILE *f;
DATA32 *data;
f = fopen(file, "r");
data = (DATA32 *)_load_PNG(w, h, f);
fclose(f);
return data;
}
char
load (ImlibImage *im)
{
int w, h;
DATA32 *data;
/* alreayd data in this image - dont load it again */
if (im->data)
return 0;
/* ok - this is not 100% right. */
/* what I SHOULD be doing is checking the im->loader value - if it's */
/* set and im->data is NULL - then I do the SECOND loading phase. */
/* this Is optional - but an OPTIMISED loader (like all loaders should */
/* if the format allows it) has 2 loading phases. the first time the */
/* loader is called If it can withotu performance penalty, read the */
/* image header - glean ingormation like width, height, if the image */
/* has an alpha channel or not - etc. If this information can be gathered */
/* now without haveing to also decode the image data, and if it is */
/* possible for the image data to later in a second load / phase, to be */
/* loaded separately withotu significant penalty, then the loader */
/* shoudl delay imge data decoding until it is actually needed in the */
/* second load phase. if it is unable to do this, or the author does */
/* not have time to do it properly, then ALL data, including image data */
/* should be decoded on the first phase. The loader, if it does this */
/* shoudl ignore the image laod if the data memebr is not NULL */
/* the below code for now just does a one phase load */
data = RGBA_Load(im->file, &w, &h);
if (data)
{
im->data = data;
im->flags = F_HAS_ALPHA;
/* setting the width to somthign > 0 means you managed to load */
/* the image */
im->w = w;
im->h = h;
/* set the format string member to the lower-case full extension */
/* name for the format - so example names would be: */
/* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */
im->format = strdup("png");
/* success - retrun 1 */
return 1;
}
/* failure to load... return 0 */
return 0;
}
char
save (ImlibImage *im)
{
/* if we cant do this - just return 0 */
return 0;
}
/* fills the ImlibLoader struct with a strign array of format file */
/* extensions this loader can load. eg: */
/* loader->formats = { "jpeg", "jpg"}; */
/* giving permutations is a good idea. case sensitivity is irrelevant */
/* your laoder CAN load more than one format if it likes - like: */
/* loader->formats = { "gif", "png", "jpeg", "jpg"} */
/* if it can load those formats. */
void
formats (ImlibLoader *l)
{
char *list_formats[] =
{ "png" };
int num_formats = 1;
int i;
l->formats = malloc(sizeof(char *) * num_formats);
for (i = 0; i < num_formats; i++)
l->formats[i] = strdup(list_formats[i]);
}

153
main.c Normal file
View File

@ -0,0 +1,153 @@
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <sys/time.h>
#include "common.h"
#include "image.h"
#include "rend.h"
#include "rgba.h"
Display *disp;
int main (int argc, char **argv)
{
Window win;
int i, j;
ImlibImage *im;
Visual *vis;
int depth;
int sec1, usec1, sec2, usec2;
int pixels = 0;
struct timeval timev;
double sec;
char *file;
int root = 0;
int scale = 0;
int w = -1;
int h = -1;
int aa = 0;
int dith = 0;
int loop = 1;
int blend = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-root"))
root = 1;
else if (!strcmp(argv[i], "-smooth"))
aa = 1;
else if (!strcmp(argv[i], "-blend"))
blend = 1;
else if (!strcmp(argv[i], "-dither"))
dith = 1;
else if (!strcmp(argv[i], "-scale"))
scale = 1;
else if (!strcmp(argv[i], "-noloop"))
loop = 0;
else if (!strcmp(argv[i], "-size"))
{
i++;
w = atoi(argv[i++]);
h = atoi(argv[i]);
}
else
file = argv[i];
}
printf("init\n");
RGBA_init();
disp = XOpenDisplay(NULL);
printf("load\n");
im = LoadImage(file);
if (!im)
printf("load fialed\n");
if (w < 0)
{
w = im->w;
h = im->h;
}
if (root)
win = DefaultRootWindow(disp);
else
{
win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, w, h, 0, 0, 0);
XMapWindow(disp, win);
}
if (scale)
{
Window d;
int dd;
XGetGeometry(disp, win, &d, &dd, &dd, &w, &h, &dd, &dd);
}
vis = DefaultVisual(disp, DefaultScreen(disp));
depth = DefaultDepth(disp, DefaultScreen(disp));
if (depth == 8)
AllocColorTable(disp, DefaultColormap(disp, DefaultScreen(disp)));
XSync(disp, False);
printf("rend\n");
gettimeofday(&timev,NULL);
sec1=(int)timev.tv_sec; /* and stores it so we can time outselves */
usec1=(int)timev.tv_usec; /* we will use this to vary speed of rot */
SetMaxXImageCount(disp, 5);
if (loop)
{
for (i = 0; i < w; i++)
{
static Pixmap m = 0;
if (m)
XFreePixmap(disp, m);
m = 0;
/*
if (((w - i) > 0) && ((((w - i) * h) / w) > 0))
m = XCreatePixmap(disp, win, (w - i), ((w - i) * h) / w, 1);
*/ RenderImage(disp, im,
win, m,
vis,
DefaultColormap(disp, DefaultScreen(disp)),
depth,
0, 0, im->w, im->h,
0, 0, w - i, ((w - i) * h) / w,
(char)aa, (char)dith, (char)blend, 0
);
if (m)
{
XShapeCombineMask(disp, win, ShapeBounding, 0, 0, m, ShapeSet);
}
pixels += (w - i) * (((w - i) * h) / w);
}
}
else
{
RenderImage(disp, im,
win, 0,
vis,
DefaultColormap(disp, DefaultScreen(disp)),
depth,
0, 0, im->w, im->h,
0, 0, w, h,
(char)aa, (char)dith, (char)blend, 0
);
pixels += (w) * (h);
}
gettimeofday(&timev,NULL);
sec2=(int)timev.tv_sec; /* and stores it so we can time outselves */
usec2=(int)timev.tv_usec; /* we will use this to vary speed of rot */
printf("done\n");
i = sec2 - sec1;
j = usec2 - usec1;
while (j < 0)
{
i++;
j += 1000000;
}
sec = (double)i + ((double)j / 1000000);
printf("%3.3f sec\n", sec);
printf("%3.3f Mpixels / sec\n", (double)(pixels) / (sec * 1000000));
return 0;
}

424
rend.c Normal file
View File

@ -0,0 +1,424 @@
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include "common.h"
#include "scale.h"
#include "image.h"
#include "ximage.h"
#include "rend.h"
#include "rgba.h"
#include "image.h"
#include "color.h"
#include "grab.h"
#include "blend.h"
/* size of the lines per segment we scale / render at a time */
#define LINESIZE 16
/* useful macro */
#define CLIP(x, y, w, h, xx, yy, ww, hh) \
if (x < xx) {w += x; x = xx;} \
if (y < yy) {h += y; y = xx;} \
if ((x + w) > ww) {w = ww - x;} \
if ((y + h) > hh) {h = hh - y;}
void
RenderImage(Display *d, ImlibImage *im,
Drawable w, Drawable m,
Visual *v, Colormap cm, int depth,
int sx, int sy, int sw, int sh,
int dx, int dy, int dw, int dh,
char anitalias, char hiq, char blend, char dither_mask)
{
XImage *xim, *mxim;
DATA32 *buf = NULL, *pointer, *back = NULL;
int y, h, hh, jump;
static GC gc = 0;
static GC gcm = 0;
XGCValues gcv;
DATA32 **ypoints = NULL;
int *xpoints = NULL;
int *yapoints = NULL;
int *xapoints = NULL;
int scw, sch;
int psx, psy, psw, psh;
char xup = 0, yup = 0;
char shm = 0;
/* dont do anything if we have a 0 widht or height image to render */
if ((dw <= 0) || (dh <= 0))
return;
/* if the input rect size < 0 dont render either */
if ((sw <= 0) || (sh <= 0))
return;
/* if the output is too big (8k arbitary limit here) dont bother */
if ((dw > 8192) || (dh > 8192))
return;
/* clip the source rect to be within the actual image */
psx = sx;
psy = sy;
psw = sw;
psh = sh;
CLIP(sx, sy, sw, sh, 0, 0, im->w, im->h);
/* clip output coords to clipped input coords */
if (psx != sx)
dx = (dx * sx) / psx;
if (psy != sy)
dy = (dy * sy) / psy;
if (psw != sw)
dw = (dw * sw) / psw;
if (psh != sh)
dh = (dh * sh) / psh;
/* do a second check to see if we now have invalid coords */
/* dont do anything if we have a 0 widht or height image to render */
if ((dw <= 0) || (dh <= 0))
return;
/* if the input rect size < 0 dont render either */
if ((sw <= 0) || (sh <= 0))
return;
/* if the output is too big (8k arbitary limit here) dont bother */
if ((dw > 8192) || (dh > 8192))
return;
/* calculate the scaling factors of width and height for a whole image */
scw = dw * im->w / sw;
sch = dh * im->h / sh;
/* if we are scaling the image at all make a scaling buffer */
if (!((sw == dw) && (sh == dh)))
{
/* need to calculate ypoitns and xpoints array */
ypoints = CalcYPoints(im->data, im->w, im->h, sch, im->border.top, im->border.bottom);
if (!ypoints)
return;
xpoints = CalcXPoints(im->w, scw, im->border.left, im->border.right);
if (!xpoints)
{
free(ypoints);
return;
}
/* calculate aliasing counts */
if (anitalias)
{
yapoints = CalcApoints(im->h, sch, im->border.top, im->border.bottom);
if (!yapoints)
{
free(ypoints);
free(xpoints);
return;
}
xapoints = CalcApoints(im->w, scw, im->border.left, im->border.right);
if (!xapoints)
{
free(yapoints);
free(ypoints);
free(xpoints);
return;
}
}
}
if ((blend) && (IMAGE_HAS_ALPHA(im)))
back = GrabDrawableToRGBA(d, w, 0, v, cm, depth, dx, dy, dw, dh, 0);
/* get a new XImage - or get one from the cached list */
xim = ProduceXImage(d, v, depth, dw, dh, &shm);
if (!xim)
{
if (anitalias)
{
free(xapoints);
free(yapoints);
}
free(ypoints);
free(xpoints);
if (back)
free(back);
return;
}
/* do a double check in 24/32bpp */
if ((xim->bits_per_pixel == 32) && (depth == 24))
depth = 32;
if (m)
{
mxim = ProduceXImage(d, v, 1, dw, dh, &shm);
if (!mxim)
{
ConsumeXImage(d, xim);
if (anitalias)
{
free(xapoints);
free(yapoints);
}
free(ypoints);
free(xpoints);
if (back)
free(back);
return;
}
}
/* if we are scaling the image at all make a scaling buffer */
if (!((sw == dw) && (sh == dh)))
{
/* allocate a buffer to render scaled RGBA data into */
buf = malloc(dw * LINESIZE * sizeof(int));
if (!buf)
{
ConsumeXImage(d, xim);
if (m)
ConsumeXImage(d, mxim);
if (anitalias)
{
free(xapoints);
free(yapoints);
}
free(ypoints);
free(xpoints);
if (back)
free(back);
return;
}
}
/* setup h */
h = dh;
/* set our scaling up in x / y dir flags */
if (dw > sw)
xup = 1;
if (dh > sh)
yup = 1;
/* scale in LINESIZE Y chunks and convert to depth*/
for (y = 0; y < dh; y += LINESIZE)
{
hh = LINESIZE;
if (h < LINESIZE)
hh = h;
/* if we're scaling it */
if (buf)
{
/* scale the imagedata for this LINESIZE lines chunk of image data */
if (anitalias)
{
if (IMAGE_HAS_ALPHA(im))
ScaleAARGBA(ypoints, xpoints, buf, xapoints, yapoints, xup, yup, dx, dy + y, 0, 0, dw, hh, dw, im->w);
else
ScaleAARGB(ypoints, xpoints, buf, xapoints, yapoints, xup, yup, dx, dy + y, 0, 0, dw, hh, dw, im->w);
}
else
ScaleSampleRGBA(ypoints, xpoints, buf, dx, dy + y, 0, 0, dw, hh, dw);
jump = 0;
pointer = buf;
}
else
{
jump = im->w - sw;
pointer = im->data + ((y + sy) * im->w) + sx;
}
/* if we have a back buffer - we're blending to the bg */
if (back)
{
BlendRGBAToRGBA(pointer, jump, back + (y * dw), 0, dw, hh);
pointer = back + (y * dw);
jump = 0;
}
/* once scaled... convert chunk to bit depth into XImage bufer */
/* NB - the order here may be random - but I chose it to select most */
/* common depths first */
if (depth == 16)
{
if (hiq)
RGBA_to_RGB565_dither(pointer, jump,
((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))),
(xim->bytes_per_line / sizeof(DATA16)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB565_fast(pointer, jump,
((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))),
(xim->bytes_per_line / sizeof(DATA16)) - dw,
dw, hh, dx, dy + y);
}
/* FIXME: need to handle different RGB ordering */
else if (depth == 24)
{
RGBA_to_RGB888_fast(pointer, jump,
((DATA8 *)xim->data) + (y * xim->bytes_per_line),
xim->bytes_per_line - (dw * 3),
dw, hh, dx, dy + y);
}
else if (depth == 32)
{
RGBA_to_RGB8888_fast(pointer, jump,
((DATA32 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA32))),
(xim->bytes_per_line / sizeof(DATA32)) - dw,
dw, hh, dx, dy + y);
}
else if (depth == 8)
{
if (_pal_type == 0)
{
if (hiq)
RGBA_to_RGB332_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB332_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 1)
{
if (hiq)
RGBA_to_RGB232_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB232_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 2)
{
if (hiq)
RGBA_to_RGB222_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB222_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 3)
{
if (hiq)
RGBA_to_RGB221_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB221_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 4)
{
if (hiq)
RGBA_to_RGB121_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB121_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 5)
{
if (hiq)
RGBA_to_RGB111_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB111_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
else if (_pal_type == 6)
{
if (hiq)
RGBA_to_RGB1_dither(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB1_fast(pointer, jump,
((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))),
(xim->bytes_per_line / sizeof(DATA8)) - dw,
dw, hh, dx, dy + y);
}
}
else if (depth == 15)
{
if (hiq)
RGBA_to_RGB555_dither(pointer, jump,
((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))),
(xim->bytes_per_line / sizeof(DATA16)) - dw,
dw, hh, dx, dy + y);
else
RGBA_to_RGB555_fast(pointer, jump,
((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))),
(xim->bytes_per_line / sizeof(DATA16)) - dw,
dw, hh, dx, dy + y);
}
if (m)
{
memset(((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)),
0x0, mxim->bytes_per_line * hh);
if (dither_mask)
RGBA_to_A1_dither(pointer, jump,
((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)),
(mxim->bytes_per_line) - (dw >> 3),
dw, hh, dx, dy + y);
else
RGBA_to_A1_fast(pointer, jump,
((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)),
(mxim->bytes_per_line) - (dw >> 3),
dw, hh, dx, dy + y);
}
/* FIXME: have to add code to generate mask if asked for */
h -= LINESIZE;
}
/* free up our buffers and poit tables */
if (buf)
{
free(buf);
free(ypoints);
free(xpoints);
}
if (anitalias)
{
free(yapoints);
free(xapoints);
}
if (back)
free(back);
/* if we didnt have a gc... create it */
if (!gc)
{
gcv.graphics_exposures = False;
gc = XCreateGC(d, w, GCGraphicsExposures, &gcv);
}
if (m)
{
if (!gcm)
{
gcv.graphics_exposures = False;
gcm = XCreateGC(d, m, GCGraphicsExposures, &gcv);
}
/* write the mask */
if (shm)
/* write shm XImage */
XShmPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh, False);
/* write regular XImage */
else
XPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh);
}
/* write the image */
if (shm)
/* write shm XImage */
XShmPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh, False);
/* write regular XImage */
else
XPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh);
/* free the XImage and put onto our free list */
/* wait for the write to be done */
if (shm)
XSync(d, False);
ConsumeXImage(d, xim);
if (m)
ConsumeXImage(d, mxim);
}

10
rend.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __REND
#define __REND 1
void
RenderImage(Display *d, ImlibImage *im,
Drawable w, Drawable m,
Visual *v, Colormap cm, int depth,
int sx, int sy, int sw, int sh,
int dx, int dy, int dw, int dh,
char anitalias, char hiq, char blend, char dither_mask);
#endif

2797
rgba.c Normal file

File diff suppressed because it is too large Load Diff

71
rgba.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef __RGBA
#define __RGBA 1
void RGBA_init(void);
void RGBA_to_RGB565_fast(DATA32 *src , int src_jump,
DATA16 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB565_dither(DATA32 *src , int src_jump,
DATA16 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB555_fast(DATA32 *src , int src_jump,
DATA16 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB555_dither(DATA32 *src , int src_jump,
DATA16 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB332_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB332_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB232_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB232_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB222_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB222_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB221_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB221_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB121_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB121_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB111_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB111_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB1_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB1_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_A1_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_A1_dither(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB8888_fast(DATA32 *src , int src_jump,
DATA32 *dest, int dest_jump,
int width, int height, int dx, int dy);
void RGBA_to_RGB888_fast(DATA32 *src , int src_jump,
DATA8 *dest, int dest_jump,
int width, int height, int dx, int dy);
#endif

872
scale.c Normal file
View File

@ -0,0 +1,872 @@
#include "common.h"
#include "scale.h"
#define R_VAL(x) (((x) & 0x000000ff))
#define G_VAL(x) (((x) & 0x0000ff00) >> 8)
#define B_VAL(x) (((x) & 0x00ff0000) >> 16)
#define A_VAL(x) (((x) & 0xff000000) >> 24)
#define RGBA_COMPOSE(r, g, b, a) ((a) << 24) | ((b) << 16) | ((g) << 8) | (r)
#define INV_XAP (255 - xapoints[x])
#define XAP (xapoints[x])
#define INV_YAP (255 - yapoints[dyy + y])
#define YAP (yapoints[dyy + y])
DATA32 **
CalcYPoints(DATA32 *src, int sw, int sh, int dh, int b1, int b2)
{
DATA32 **p;
int i, j = 0;
int val, inc;
p = malloc(dh * sizeof(DATA32 *));
if (dh < (b1 + b2))
{
if (dh < b1)
{
b1 = dh;
b2 = 0;
}
else
b2 = dh - b1;
}
val = 0;
inc = 1 << 16;
for (i = 0; i < b1; i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
if (dh > (b1 + b2))
{
val = (b1 << 16);
inc = ((sh - b1 - b2) << 16) / (dh - b1 - b2);
for (i = 0; i < (dh - b1 - b2); i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
}
val = (sh - b2) << 16;
inc = 1 << 16;
for (i = 0; i < b2; i++)
{
p[j++] = src + ((val >> 16) * sw);
val += inc;
}
return p;
}
int *
CalcXPoints(int sw, int dw, int b1, int b2)
{
int *p, i, j = 0;
int val, inc;
p = malloc(dw * sizeof(int));
if (dw < (b1 + b2))
{
if (dw < b1)
{
b1 = dw;
b2 = 0;
}
else
b2 = dw - b1;
}
val = 0;
inc = 1 << 16;
for (i = 0; i < b1; i++)
{
p[j++] = (val >> 16);
val += inc;
}
if (dw > (b1 + b2))
{
val = (b1 << 16);
inc = ((sw - b1 - b2) << 16) / (dw - b1 - b2);
for (i = 0; i < (dw - b1 - b2); i++)
{
p[j++] = (val >> 16);
val += inc;
}
}
val = (sw - b2) << 16;
inc = 1 << 16;
for (i = 0; i < b2; i++)
{
p[j++] = (val >> 16);
val += inc;
}
return p;
}
int *
CalcApoints(int s, int d, int b1, int b2)
{
int *p, i, v, j = 0;
p = malloc(d * sizeof(int));
if (d < (b1 + b2))
{
if (d < b1)
{
b1 = d;
b2 = 0;
}
else
b2 = d - b1;
}
/* scaling up */
if (d > s)
{
int val, inc;
for (i = 0; i < b1; i++)
p[j++] = 0;
if (d > (b1 + b2))
{
int ss, dd;
ss = s - b1 - b2;
dd = d - b1 - b2;
val = 0;
inc = (ss << 16) / dd;
for (i = 0; i < dd; i++)
{
p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
if (((val >> 16) + b1) >= (s - 1))
p[j - 1] = 0;
val += inc;
}
}
for (i = 0; i < b2; i++)
p[j++] = 0;
}
/* scaling down */
else
{
for (i = 0; i < b1; i++)
p[j++] = 1;
if (d > (b1 + b2))
{
int ss, dd;
ss = s - b1 - b2;
dd = d - b1 - b2;
for (i = 0; i < dd; i++)
{
v = (((i + 1) * ss) / dd) - ((i * ss) / dd);
if (v != 1)
{
if (((((i + 1) * ss) / dd) + b1) >= s)
v = s - (((i * ss) / dd) + b1) - 1;
p[j++] = v;
}
else
p[j++] = v;
if (p[j - 1] < 1)
p[j - 1] = 1;
}
}
for (i = 0; i < b2; i++)
p[j++] = 1;
}
return p;
}
/* scale by pixel sampling only */
void
ScaleSampleRGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow)
{
DATA32 *sptr, *dptr;
int x, y, end;
/* whats the last pixel ont he line so we stop there */
end = dxx + dw;
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* get the pointer to the start of the destination scanline */
dptr = dest + dx + ((y + dy) * dow);
/* calculate the source line we'll scan from */
sptr = ypoints[dyy + y];
/* go thru the scanline and copy across */
for (x = dxx; x < end; x++)
*dptr++ = sptr[xpoints[x]];
}
}
/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/
/* scale by area sampling */
void
ScaleAARGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow)
{
DATA32 *sptr, *ssptr, *dptr;
int x, y, i, j, end;
end = dxx + dw;
/* scaling up both ways */
if ((xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
rr = R_VAL(pix) * INV_XAP;
gg = G_VAL(pix) * INV_XAP;
bb = B_VAL(pix) * INV_XAP;
aa = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix) * XAP;
gg += G_VAL(pix) * XAP;
bb += B_VAL(pix) * XAP;
aa += A_VAL(pix) * XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
a = ((aa * YAP) + (a * INV_YAP)) >> 16;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
a = A_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
a += A_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if ((xup) && (!yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
int count;
DATA32 pix;
if (XAP > 0)
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = j;
r = r * INV_XAP / count;
g = g * INV_XAP / count;
b = b * INV_XAP / count;
a = a * INV_XAP / count;
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
aa += A_VAL(pix);
}
count = j;
r = (r + ((rr * XAP) / count)) >> 8;
g = (g + ((gg * XAP) / count)) >> 8;
b = (b + ((bb * XAP) / count)) >> 8;
a = (a + ((aa * XAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j *sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = j;
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally */
else if ((!xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int rr = 0, gg = 0, bb = 0, aa = 0;
int count;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = i;
r = r * INV_YAP / count;
g = g * INV_YAP / count;
b = b * INV_YAP / count;
a = a * INV_YAP / count;
ssptr = ypoints[dyy + y] + sow;
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
aa += A_VAL(pix);
}
count = i;
r = (r + ((rr * YAP) / count)) >> 8;
g = (g + ((gg * YAP) / count)) >> 8;
b = (b + ((bb * YAP) / count)) >> 8;
a = (a + ((aa * YAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
a = A_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
a += A_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
}
else
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
count = i;
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally & vertically */
else
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0, a = 0;
int count;
DATA32 pix;
if ((XAP > 1) || (YAP > 1))
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
a += A_VAL(pix);
}
}
count = (i * j);
r /= count;
g /= count;
b /= count;
a /= count;
pix = RGBA_COMPOSE(r, g, b, a);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* scale by area sampling - IGNORE the ALPHA byte*/
void
ScaleAARGB(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow)
{
DATA32 *sptr, *ssptr, *dptr;
int x, y, i, j, end;
end = dxx + dw;
/* scaling up both ways */
if ((xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
rr = R_VAL(pix) * INV_XAP;
gg = G_VAL(pix) * INV_XAP;
bb = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix) * XAP;
gg += G_VAL(pix) * XAP;
bb += B_VAL(pix) * XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (XAP > 0)
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if ((xup) && (!yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
int count;
DATA32 pix;
if (XAP > 0)
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = j;
r = r * INV_XAP / count;
g = g * INV_XAP / count;
b = b * INV_XAP / count;
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
pix = ssptr[xpoints[x] + 1];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
}
count = j;
r = (r + ((rr * XAP) / count)) >> 8;
g = (g + ((gg * XAP) / count)) >> 8;
b = (b + ((bb * XAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix = ssptr[xpoints[x] + 1];
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (YAP > 1)
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j *sow);
pix = ssptr[xpoints[x]];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = j;
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally */
else if ((!xup) && (yup))
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
int count;
DATA32 pix;
if (YAP > 0)
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = i;
r = r * INV_YAP / count;
g = g * INV_YAP / count;
b = b * INV_YAP / count;
ssptr = ypoints[dyy + y] + sow;
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
rr += R_VAL(pix);
gg += G_VAL(pix);
bb += B_VAL(pix);
}
count = i;
r = (r + ((rr * YAP) / count)) >> 8;
g = (g + ((gg * YAP) / count)) >> 8;
b = (b + ((bb * YAP) / count)) >> 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
{
ssptr = ypoints[dyy + y];
pix = ssptr[xpoints[x]];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
ssptr += sow;
pix = ssptr[xpoints[x]];
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
}
else
{
if (XAP > 1)
{
ssptr = ypoints[dyy + y];
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
count = i;
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}
/* if we're scaling down horizontally & vertically */
else
{
/* go through every scanline in the output buffer */
for (y = 0; y < dh; y++)
{
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
for (x = dxx; x < end; x++)
{
int r = 0, g = 0, b = 0;
int count;
DATA32 pix;
if ((XAP > 1) || (YAP > 1))
{
for (j = 0; j < YAP; j++)
{
ssptr = ypoints[dyy + y] + (j * sow);
for (i = 0; i < XAP; i++)
{
pix = ssptr[xpoints[x] + i];
r += R_VAL(pix);
g += G_VAL(pix);
b += B_VAL(pix);
}
}
count = (i * j);
r /= count;
g /= count;
b /= count;
pix = RGBA_COMPOSE(r, g, b, 0xff);
*dptr++ = pix;
}
else
*dptr++ = sptr[xpoints[x]];
}
}
}
}

21
scale.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __SCALE
#define __SCALE 1
DATA32 **
CalcYPoints(DATA32 *src, int sw, int sh, int dh, int b1, int b2);
int *
CalcXPoints(int sw, int dw, int b1, int b2);
int *
CalcApoints(int s, int d, int b1, int b2);
void
ScaleSampleRGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow);
void
ScaleAARGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow);
void
ScaleAARGB(DATA32 **ypoints, int *xpoints, DATA32 *dest,
int *xapoints, int *yapoints, char xup, char yup,
int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow);
#endif

BIN
test_images/im.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

BIN
test_images/im_rgb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

282
ximage.c Normal file
View File

@ -0,0 +1,282 @@
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "common.h"
#include "ximage.h"
/* static private variables */
static char x_does_shm = -1;
static int list_num = 0;
static XImage **list_xim = NULL;
static XShmSegmentInfo **list_si = NULL;
static Display **list_d = NULL;
static char *list_used = NULL;
static int list_mem_use = 0;
static int list_max_mem = 1024 * 1024 * 1024;
static int list_max_count = 1;
/* temporary X error catcher we use later */
static char _x_err = 0;
/* the fucntion we use for catching the error */
static void
TmpXError(Display * d, XErrorEvent * ev)
{
_x_err = 1;
}
void
SetMaxXImageCount(Display *d, int num)
{
list_max_count = num;
FlushXImage(d);
}
int
GetMaxXImageCount(Display *d)
{
return list_max_count;
}
void
SetMaxXImageTotalSize(Display *d, int num)
{
list_max_mem = num;
FlushXImage(d);
}
int
GetMaxXImageTotalSize(Display *d)
{
return list_max_mem;
}
void
FlushXImage(Display *d)
{
int i;
XImage *xim;
char did_free = 1;
while (((list_mem_use > list_max_mem) || (list_num > list_max_count)) &&
(did_free))
{
did_free = 0;
for (i = 0; i < list_num; i++)
{
if (list_used[i] == 0)
{
int j;
xim = list_xim[i];
list_mem_use -= xim->bytes_per_line * xim->height;
if (list_si[i])
XShmDetach(d, list_si[i]);
XDestroyImage(xim);
if (list_si[i])
{
shmdt(list_si[i]->shmaddr);
shmctl(list_si[i]->shmid, IPC_RMID, 0);
free(list_si[i]);
}
list_num--;
for (j = i; j < list_num; j++)
{
list_xim[j] = list_xim[j + 1];
list_si[j] = list_si[j + 1];
list_used[j] = list_used[j + 1];
list_d[j] = list_d[j + 1];
}
list_xim = realloc(list_xim, sizeof(XImage *) * list_num);
list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num);
list_used = realloc(list_used, sizeof(char) * list_num);
list_d = realloc(list_d, sizeof(Display *) * list_num);
did_free = 1;
}
}
}
}
/* free (consume == opposite of produce) the XImage (mark as unused) */
void
ConsumeXImage(Display *d, XImage *xim)
{
int i;
/* march through the XImage list */
for (i = 0; i < list_num; i++)
{
/* find a match */
if (list_xim[i] == xim)
{
/* we have a match = mark as unused */
list_used[i] = 0;
/* flush the XImage list to get rud of stuff we dont want */
FlushXImage(d);
/* return */
return;
}
}
}
/* create a new XImage or find it on our list of currently available ones so */
/* we dont need to create a new one */
XImage *
ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared)
{
XImage *xim;
int i;
/* if we havent check the shm extension before - see if its there */
if (x_does_shm < 0)
{
/* if its there set dose_xhm flag */
if (XShmQueryExtension(d))
x_does_shm = 1;
/* clear the flag - no shm at all */
else
x_does_shm = 0;
}
/* find a cached XImage (to avoid server to & fro) that is big enough */
/* for our needs and the right depth */
*shared = 0;
/* go thru the current image list */
for (i = 0; i < list_num; i++)
{
/* if the image has the same depth, width and height - recycle it */
/* as long as its not used */
if ((list_xim[i]->bits_per_pixel == depth) &&
(list_xim[i]->width >= w) &&
(list_xim[i]->height >= h) &&
/* (list_d[i] == d) &&*/
(!list_used[i]))
{
/* mark it as used */
list_used[i] = 1;
/* if its shared set shared flag */
if (list_si[i])
*shared = 1;
/* return it */
return list_xim[i];
}
}
/* can't find a usable XImage on the cache - create one */
/* add the new XImage to the XImage cache */
list_num++;
list_xim = realloc(list_xim, sizeof(XImage *) * list_num);
list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num);
list_used = realloc(list_used, sizeof(char) * list_num);
list_d = realloc(list_d, sizeof(Display *) * list_num);
list_si[list_num - 1] = malloc(sizeof(XShmSegmentInfo));
/* work on making a shared image */
xim = NULL;
/* if the server does shm */
if (x_does_shm)
{
/* try create an shm image */
xim = XShmCreateImage(d, v, depth, ZPixmap, NULL,
list_si[list_num - 1], w, h);
/* if it succeeds */
if (xim)
{
/* add to list */
list_xim[list_num - 1] = xim;
/* get an shm id of this image */
list_si[list_num - 1]->shmid =
shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height,
IPC_CREAT | 0777);
/* if the get succeeds */
if (list_si[list_num - 1]->shmid != -1)
{
/* set the params for the shm segment */
list_si[list_num - 1]->readOnly = False;
list_si[list_num - 1]->shmaddr = xim->data =
shmat(list_si[list_num - 1]->shmid, 0, 0);
/* get the shm addr for this data chunk */
if (xim->data != (char *)-1)
{
XErrorHandler ph;
/* setup a temporary error handler */
_x_err = 0;
ph = XSetErrorHandler((XErrorHandler) TmpXError);
/* ask X to attach to the shared mem segment */
XShmAttach(d, list_si[list_num - 1]);
/* wait for X to reply and do this */
XSync(d, False);
/* reset the error handler */
XSetErrorHandler((XErrorHandler) ph);
/* if we attached without an error we're set */
if (!_x_err)
{
/* mark the image as used */
list_used[list_num - 1] = 1;
/* incrument our memory count */
list_mem_use += xim->bytes_per_line * xim->height;
/* set shared flag */
*shared = 1;
}
/* attach by X failed... must be remote client */
else
{
/* flag shm foevere to not work - remote */
x_does_shm = 0;
/* destroy our previous image */
XDestroyImage(xim);
/* detach */
shmdt(list_si[list_num - 1]->shmaddr);
/* remove the shm id */
shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0);
/* flag out xim as NULL */
xim = NULL;
}
}
/* get failed - out of shm id's or shm segment too big ? */
else
{
/* destroy previous image */
XDestroyImage(xim);
/* remove the shm id we created */
shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0);
/* flag xim as NULL */
xim = NULL;
}
}
/* couldnt create SHM image ? */
else
{
/* destroy previous image */
XDestroyImage(xim);
/* flag xim as NULL */
xim = NULL;
}
}
}
/* ok if xim == NULL it all failed - fall back to XImages */
if (!xim)
{
/* get rid of out shm info struct */
free(list_si[list_num - 1]);
/* flag it as NULL ot indicate a normal XImage */
list_si[list_num - 1] = NULL;
/* create a normal ximage */
xim = XCreateImage(d, v, depth, ZPixmap, 0, NULL, w, h, 32, 0);
/* allocate data for it */
xim->data = malloc(xim->bytes_per_line * xim->height);
/* add xim to our list */
list_xim[list_num - 1] = xim;
/* incriment our memory count */
list_mem_use += xim->bytes_per_line * xim->height;
/* mark image as used */
list_used[list_num - 1] = 1;
/* remember what display that XImage was for */
list_d[list_num - 1] = d;
}
/* flush unused images from the image list */
FlushXImage(d);
/* return out image */
return xim;
}

10
ximage.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __XIMAGE
#define __XIMAGE 1
void SetMaxXImageCount(Display *d, int num);
int GetMaxXImageCount(Display *d);
void SetMaxXImageTotalSize(Display *d, int num);
int GetMaxXImageTotalSize(Display *d);
void FlushXImage(Display *d);
void ConsumeXImage(Display *d, XImage *xim);
XImage *ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared);
#endif