diff --git a/Makefile.am b/Makefile.am index 0ed1e1c..6b594a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ MAINTAINERCLEANFILES = INSTALL Makefile.in aclocal.m4 config.guess \ ltconfig ltmain.sh missing mkinstalldirs \ stamp-h.in -SUBDIRS = libltdl loaders src +SUBDIRS = libltdl loaders src filters EXTRA_DIST = \ imlib2.spec \ diff --git a/configure.in b/configure.in index 0a840c0..c776058 100644 --- a/configure.in +++ b/configure.in @@ -117,5 +117,5 @@ AC_MSG_ERROR([Fatal Error: no FreeType header files detected.]) fi fi -AC_OUTPUT(Makefile loaders/Makefile src/Makefile test/Makefile demo/Makefile, +AC_OUTPUT(Makefile loaders/Makefile src/Makefile test/Makefile filters/Makefile demo/Makefile, [test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h]) diff --git a/filters/Makefile.am b/filters/Makefile.am new file mode 100644 index 0000000..5ffc8c8 --- /dev/null +++ b/filters/Makefile.am @@ -0,0 +1,19 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = 1.4 foreign + +# A list of all the files in the current directory which can be regenerated +MAINTAINERCLEANFILES = Makefile.in + +LDFLAGS = -L/usr/X11R6/lib +INCLUDES = -I/usr/X11R6/include -I$(top_srcdir)/libltdl \ + $(X_CFLAGS) -I$(prefix)/include -I$(includedir) \ + -I. -I$(top_srcdir) -I$(top_srcdir)/src \ + -I$(top_srcdir)/loaders + +pkgdir = $(libdir)/loaders/filter +pkg_LTLIBRARIES = testfilter.la + +testfilter_la_SOURCES = filter_test.c +testfilter_la_LDFLAGS = -no-undefined -module -avoid-version +testfilter_la_LIBADD = diff --git a/filters/filter_test.c b/filters/filter_test.c new file mode 100644 index 0000000..43b03c6 --- /dev/null +++ b/filters/filter_test.c @@ -0,0 +1,99 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include "Imlib2.h" +#include "image.h" +#include "script.h" +#include "dynamic_filters.h" + +void init( struct imlib_filter_info *info ); +void deinit(); +void *exec( char *filter, void *im, pIFunctionParam params ); + +void init( struct imlib_filter_info *info ) +{ + char *filters[] = { "tint", "cool_text" }; + int i = 0; + + info->num_filters = 2; + info->filters = malloc(sizeof(char *)*2); + for (i = 0; i < info->num_filters; i++) + info->filters[i] = strdup(filters[i]); + +} + +void deinit() +{ + return; +} + +void *exec( char *filter, void *im, pIFunctionParam params ) +{ + Imlib_Image imge = im; + Imlib_Image anoim; + IFunctionParam *ptr; + + if( strcmp( filter, "tint" ) == 0 ) + { + Imlib_Color_Modifier cm; + DATA8 atab[256]; + int x = 0, y = 0, w = 100, h = 100; + DATA8 r = 255, b = 255, g = 255, a = 255; +/* + printf( "filter_test.c: tint called\n" ); + */ + +#define ASSIGN_DATA8_VALUE( var, v ) if( strcmp( ptr->key, var ) == 0 ) v = (DATA8)atoi( (char *)ptr->data ) +#define ASSIGN_VALUE( var, v ) if( strcmp( ptr->key, var ) == 0 ) v = atoi( (char *)ptr->data ) + + for( ptr = params; ptr != NULL; ptr = ptr->next ) + { + ASSIGN_DATA8_VALUE( "red", r ); + ASSIGN_DATA8_VALUE( "blue", b ); + ASSIGN_DATA8_VALUE( "green", g ); + ASSIGN_VALUE( "x", x ); + ASSIGN_VALUE( "y", y ); + ASSIGN_VALUE( "w", w ); + ASSIGN_VALUE( "h", h ); + ASSIGN_DATA8_VALUE( "alpha", a ); + } +/* + printf( "Using values red=%d,blue=%d,green=%d,x=%d,y=%d,height=%d,width=%d,alpha=%d\n", r,b,g,x,y,w,h,a ); + */ + anoim = imlib_create_image( w, h ); + cm = imlib_create_color_modifier(); + imlib_context_set_color_modifier(cm); + imlib_context_set_image(anoim); + + imlib_context_set_color(r, g, b, 255); + imlib_image_fill_rectangle(0, 0, w, h); + imlib_context_set_blend(1); + imlib_image_set_has_alpha(1); + + memset(atab, a, sizeof(atab)); + imlib_set_color_modifier_tables(NULL, NULL, NULL, atab); + imlib_apply_color_modifier_to_rectangle(0, 0, w, h); + + imlib_context_set_image( imge ); + imlib_blend_image_onto_image( anoim, 0, 0, 0, w, h, x, y, w, h); + + imlib_free_color_modifier(); + imlib_context_set_image(anoim); + imlib_free_image_and_decache(); + imlib_context_set_image(imge); + + + return imge; + } + + if( strcmp( filter, "cool_text" ) == 0 ) + { + return imge; + } +} diff --git a/src/Imlib2.h b/src/Imlib2.h index fcee340..1b9c254 100644 --- a/src/Imlib2.h +++ b/src/Imlib2.h @@ -268,6 +268,8 @@ void imlib_filter_set_green(int xoff, int yoff, int a, int r, int g, int b); void imlib_filter_set_blue(int xoff, int yoff, int a, int r, int g, int b); void imlib_filter_constants(int a, int r, int g, int b); void imlib_filter_divisors(int a, int r, int g, int b); + +Imlib_Image imlib_apply_filter( char *script, ... ); /* need to add polygon fill code */ diff --git a/src/Makefile.am b/src/Makefile.am index 2cc58c1..c3fd1b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,11 +16,11 @@ include_HEADERS = Imlib2.h libImlib2_la_SOURCES = rend.c ximage.c scale.c rgba.c image.c color.c grab.c \ blend.c file.c rgbadraw.c api.c draw.c context.c \ updates.c colormod.c font.c format.c grad.c rotate.c \ - filter.c \ + filter.c script.c dynamic_filters.c \ Imlib2.h image.h scale.h blend.h context.h updates.h \ color.h draw.h rend.h ximage.h colormod.h file.h \ rgba.h common.h grab.h rgbadraw.h font.h format.h \ - rotate.h grad.h filter.h \ + rotate.h grad.h filter.h script.h dynamic_filters.h \ asm_blend.S asm_rgba.S asm_scale.S asm_rotate.S \ asm_blend_cmod.S libImlib2_la_LIBADD = @DLLDFLAGS@ $(top_builddir)/libltdl/libltdlc.la \ diff --git a/src/api.c b/src/api.c index a494e0d..25c7e64 100644 --- a/src/api.c +++ b/src/api.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "common.h" #include "colormod.h" #include "image.h" @@ -28,6 +29,8 @@ #include "grad.h" #include "rotate.h" #include "filter.h" +#include "dynamic_filters.h" +#include "script.h" #include /* convenience macros */ @@ -2428,3 +2431,31 @@ imlib_filter_divisors(int a, int r, int g, int b) CHECK_PARAM_POINTER("imlib_filter_divisors", "filter", ctxt_filter); __imlib_FilterDivisors((ImlibFilter *)ctxt_filter, a, r, g, b); } + +Imlib_Image imlib_apply_filter( char *script, ... ) +{ + Imlib_Image im; + IFunction *func = NULL, *ptr; + va_list param_list; + pImlibExternalFilter filter; + + __imlib_dynamic_filters_init(); + + CAST_IMAGE(im, ctxt_image); + va_start( param_list, script ); + func = (IFunction *)__imlib_script_parse( script, param_list ); + va_end( param_list ); + + for( ptr = func->next; ptr != NULL; ptr = ptr->next ) + { + filter = __imlib_get_dynamic_filter( ptr->name ); + if( filter != NULL ) + { + im = filter->exec_filter( ptr->name, im, ptr->params ); + imlib_context_set_image( im ); + } + } + + __imlib_script_tidyup( func ); + return im; +} diff --git a/src/dynamic_filters.c b/src/dynamic_filters.c new file mode 100644 index 0000000..8700791 --- /dev/null +++ b/src/dynamic_filters.c @@ -0,0 +1,194 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "image.h" +#include "file.h" +#include "dynamic_filters.h" +#include "script.h" +#include "loaderpath.h" + + +pImlibExternalFilter filters = NULL; +int dyn_initialised = 0; + +#define MALLOCSHOW +#define FREESHOW +/* +#define FDEBUG +*/ + +pImlibExternalFilter __imlib_LoadFilter( char *file ) +{ + ImlibExternalFilter *ptr; + struct imlib_filter_info *info; + int i = 0; + + printf( "Loading filter %s\n", file ); + MALLOCSHOW; + ptr = malloc( sizeof( ImlibExternalFilter ) ); + ptr->filename = strdup(file); + ptr->handle = lt_dlopenext(file); + if( !ptr->handle ) + { + FREESHOW; + free( ptr->filename ); + FREESHOW; + free( ptr ); + return NULL; + } + ptr->init_filter = lt_dlsym( ptr->handle, "init" ); + ptr->deinit_filter = lt_dlsym( ptr->handle, "deinit" ); + ptr->exec_filter = lt_dlsym( ptr->handle, "exec" ); + if( !ptr->init_filter || !ptr->deinit_filter || !ptr->exec_filter ) + { + lt_dlclose( ptr->handle ); + FREESHOW; + free( ptr->filename ); + FREESHOW; + free( ptr ); + return NULL; + } + info = malloc( sizeof( struct imlib_filter_info ) ); + ptr->init_filter( info ); + ptr->num_filters = info->num_filters; + ptr->filters = info->filters; + + free( info ); + +#ifdef FDEBUG + printf( "Filter has %d filters in it.\n", ptr->num_filters ); + for( i = 0; i < ptr->num_filters; i++ ) + printf( " -> \"%s\"\n", ptr->filters[i] ); +#endif + + ptr->next = NULL; + return ptr; +} + +void __imlib_dynamic_filters_init() +{ + char **list; + int num_filters, i = 0; + ImlibExternalFilter *ptr, *tptr; + + if( ! dyn_initialised ) + { + MALLOCSHOW; + filters = malloc( sizeof( ImlibExternalFilter ) ); + filters->filename = ""; + filters->next = NULL; + ptr = filters; +#ifdef FDEBUG + printf( "DEBUG: Dynamic filters Initisialising\n" ); +#endif + dyn_initialised = 1; +#ifdef FDEBUG + printf( "DEBUG: Loading Filters\n" ); +#endif + list = __imlib_ListFilters( &num_filters ); + for( i = num_filters - 1; i >= 0; i -- ) + { + tptr = NULL; + if((tptr = __imlib_LoadFilter( list[i] )) != NULL ) + { + ptr->next = tptr; + ptr = ptr->next; + } + if( list[i] ){ + FREESHOW; + free( list[i] ); + } + } + FREESHOW; + if( list ) + free( list ); + } +} + +void __imlib_dynamic_filters_deinit() +{ +} + +pImlibExternalFilter __imlib_get_dynamic_filter( char *name ) +{ + pImlibExternalFilter f_ptr; + int i = 0; + + /* scan the filters */ + for( f_ptr = filters->next; f_ptr != NULL; f_ptr = f_ptr->next ) + { + /* scan the methods provided */ + for( i = 0; i < f_ptr->num_filters; i++ ) + { + if( strcmp( f_ptr->filters[i], name ) == 0 ) + { +#ifdef FDEBUG + printf( "DEBUG: Found filter \"%s\"\n", name ); +#endif + return f_ptr; + } + } + } + return NULL; +} + +/* loader dir */ +char **__imlib_ListFilters(int *num_ret) +{ + char **list = NULL, **l, s[4096], *home; + int num, i, pi = 0; + + *num_ret = 0; + /* get the user's home dir */ + home = __imlib_FileHomeDir(getuid()); + sprintf(s, "%s/" USER_LOADERS_PATH "/filter", home); + /* list the dir contents of their loader dir */ + l = __imlib_FileDir(s, &num); + /* if theres files */ + if (num > 0) + { + /* make a list of them */ + *num_ret += num; + list = malloc(sizeof(char *) * *num_ret); + for (i = 0; i < num; i++) + { + sprintf(s, "%s/" USER_LOADERS_PATH "/filter/%s", home, l[i]); + list[i] = strdup(s); + } + pi = i; + __imlib_FileFreeDirList(l, num); + } + /* same for system loader path */ + sprintf(s, SYS_LOADERS_PATH "/filter"); + l = __imlib_FileDir(s, &num); + if (num > 0) + { + *num_ret += num; + list = realloc(list, sizeof(char *) * *num_ret); + for (i = 0; i < num; i++) + { + sprintf(s, SYS_LOADERS_PATH "/filter/%s", l[i]); + list[pi + i] = strdup(s); + } + __imlib_FileFreeDirList(l, num); + } + free(home); + + /* List currently contains *everything in there* we need to weed out + * the .so, .la, .a versions of the same loader or whatever else. + * lt_dlopen can take an extension-less name and do the Right Thing + * with it, so that's what we'll give it. */ + list = __imlib_TrimLoaderList(list, num_ret); + + return list; +} diff --git a/src/dynamic_filters.h b/src/dynamic_filters.h new file mode 100644 index 0000000..e5b46f6 --- /dev/null +++ b/src/dynamic_filters.h @@ -0,0 +1,38 @@ +#ifndef _DYNAMIC_FILTERS_H_ +#define _DYNAMIC_FILTERS_H_ + +#include "script.h" + +struct imlib_filter_info +{ + char **filters; + int num_filters; +}; + +typedef struct _imlib_external_filter ImlibExternalFilter; +typedef struct _imlib_external_filter *pImlibExternalFilter; +struct _imlib_external_filter +{ + int num_filters; + char *filename; + void *handle; + char **filters; + void (*init_filter)( struct imlib_filter_info *info ); + void (*deinit_filter)(); + void *(*exec_filter)( char *filter, void *im, pIFunctionParam params ); + pImlibExternalFilter next; +}; + + +void __imlib_dynamic_filters_init(); +void __imlib_dynamic_filters_deinit(); +pImlibExternalFilter __imlib_get_dynamic_filter( char *name ); +char **__imlib_ListFilters(int *num_ret); +pImlibExternalFilter __imlib_LoadFilter( char *file ); + + + +#endif + + + diff --git a/src/script.c b/src/script.c new file mode 100644 index 0000000..3dfd34d --- /dev/null +++ b/src/script.c @@ -0,0 +1,237 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "image.h" +#include "file.h" +#include "script.h" +#include "loaderpath.h" +/* +#define FDEBUG 1 +*/ + +int find_string( char *haystack, char *needle ) +{ + if( strstr( haystack, needle ) != NULL ) + return ( strstr( haystack, needle ) - haystack ); + return 0; +} + +char *stripwhitespace( char *str ) +{ + int i, strt = 0, in_quote = 0; + char *tmpstr = calloc( strlen(str)+1, sizeof(char) ); + for( i = 0; i < strlen(str); i++ ) + { + if( str[i] == '\"' ) + in_quote = (in_quote == 0 ? 1 : 0); + if( in_quote || ! isspace(*(str+i)) ) + tmpstr[strt++] = str[i]; + } + strcpy( str, tmpstr ); + free(tmpstr); + return str; +} + +char *copystr( char *str, int start, int end ) +{ + int i = 0; + char *rstr = calloc( 1024, sizeof( char ) ); + if( start <= end && end < strlen( str ) ) + { + for( i = start; i <= end; i++ ) + rstr[i-start] = str[i]; + return rstr; + } + return NULL; +} + +pIFunctionParam parse_param( char *param ) +{ + int i; + + IFunctionParam *ptr; + if( param != NULL ) + { + ptr = malloc( sizeof( IFunctionParam ) ); + i = find_string(param,"="); + if( i > 0 ) + { + ptr->key = copystr(param, 0, i-1); + ptr->type = 1; + if( param[i+1] == '\"' ) + ptr->data = (void *)copystr(param, i+2, strlen(param)-2); + else + ptr->data = (void *)copystr(param, i+1, strlen(param)-1); +#ifdef FDEBUG + printf( "DEBUG: -> param [%s]=\"%s\"\n", ptr->key, (char *)ptr->data ); +#endif /* FDEBUG */ + ptr->next = NULL; + } + else + { + ptr->key = strdup(param); + ptr->data = strdup( "" ); + ptr->type = VAR_CHAR; + printf( "DEBUG: -> s_param [%s]=\"%s\"\n", ptr->key, (char *)ptr->data ); + ptr->next = NULL; + } + return ptr; + } + return NULL; +} + +pIFunction parse_function( char *func ) +{ + int i = 0, in_quote=0, start=0; + IFunction *ptrfunc = malloc( sizeof( IFunction ) ); + IFunctionParam *ptrparam = NULL; + char *tmpbuf; + + if( func != NULL ) + { + func = stripwhitespace( func ); + ptrfunc->name = copystr( func, 0, find_string( func, "(" ) - 1 ); +#ifdef FDEBUG + printf( "DEBUG: Function name: \"%s\"\n", ptrfunc->name ); +#endif /* FDEBUG */ + + ptrfunc->params = malloc( sizeof( IFunctionParam ) ); + ptrfunc->params->key = strdup(""); + ptrfunc->params->data = strdup(""); + ptrfunc->params->type = VAR_CHAR; + ptrfunc->params->next = NULL; + ptrparam = ptrfunc->params; + + start = find_string( func, "(" ) + 1; + for( i = start; i < strlen(func); i++ ) + { + if( func[i] == '\"' ) + in_quote = (in_quote == 0 ? 1 : 0); + if( !in_quote && (func[i] == ',' || func[i] == ')') ) + { + tmpbuf = copystr( func, start, i-1 ); + ptrparam->next = parse_param( tmpbuf ); + if( ptrparam->next != NULL ) + ptrparam = ptrparam->next; + start = i+1; + if( tmpbuf && tmpbuf != NULL ) free(tmpbuf); + } + } + free( func ); + } + else + { + ptrfunc->name = strdup( "root-function" ); + ptrfunc->params = NULL; + } + ptrfunc->next = NULL; + return ptrfunc; +} + +pIFunction __imlib_script_parse( char *script, ... ) +{ + int i = 0, in_quote = 0, start = 0, hit_null = 0; + IFunction *ptr = parse_function( NULL ), *tmp_fptr = NULL; + IFunction *rptr = ptr; + IFunctionParam *tmp_pptr; + va_list param_list; + void *tmpptr; + +#ifdef FDEBUG + printf( "DEBUG: Imlib Script Parser Start.\n" ); +#endif + + if( script != NULL ) + { + /* scan the script line */ + for( i = 0; i < strlen(script); i++ ) + { + if( script[i] == '\"' ) + in_quote = (in_quote == 0 ? 1 : 0); + if( ! in_quote && script[i] == ';' ) + { + ptr->next = parse_function( copystr( script, start, i-1 ) ); + ptr = ptr->next; + start = i+1; + } + } + /* righty now we need to traverse the whole of the function tree and see if we have hit + * any [], if we have replace it with the next var off the list update the pointer, luverly + * jubly */ + va_start( param_list, script ); + for( tmp_fptr = rptr->next; tmp_fptr != NULL; tmp_fptr = tmp_fptr->next ) + { + for( tmp_pptr = tmp_fptr->params; tmp_pptr != NULL; tmp_pptr = tmp_pptr->next ) + { + if( strcmp( (char *)(tmp_pptr->data), "[]" ) == 0 ) + { + if( !hit_null ) + tmpptr = va_arg( param_list, void *); + else + tmpptr = NULL; + + if( tmpptr == NULL ) + { +#ifdef FDEBUG + printf( "DEBUG: WARNING: We have hit a null. (dyn_filter.c)\n" ); +#endif + hit_null = 1; + } +#ifdef FDEBUG + printf( "Setting %s::%s to a pointer.\n", tmp_fptr->name, tmp_pptr->key ); +#endif + tmp_pptr->type = VAR_PTR; + tmp_pptr->data = ( tmpptr != NULL ? tmpptr : NULL ); +#ifdef FDEBUG + printf( "%p\n", tmp_pptr->data ); +#endif + } + } + } + va_end( param_list ); +#ifdef FDEBUG + printf( "DEBUG: Imlib Script Parser End.\n" ); +#endif + return rptr; + } + else + { +#ifdef FDEBUG + printf( "DEBUG: Imlib Script Parser End. (!!)\n" ); +#endif + return NULL; + } +} + +void __imlib_script_tidyup_params( IFunctionParam *param ) +{ + if( param->next ){ + __imlib_script_tidyup_params( param->next ); + } + free( param->key ); + if( param->type == VAR_CHAR ) + free( param->data ); + free( param ); +} + +void __imlib_script_tidyup( IFunction *func ) +{ + if( func->next != NULL ) + __imlib_script_tidyup( func->next ); + + if( func->params != NULL ) + __imlib_script_tidyup_params( func->params ); + + free( func->name ); + free( func ); +} diff --git a/src/script.h b/src/script.h new file mode 100644 index 0000000..8d07e04 --- /dev/null +++ b/src/script.h @@ -0,0 +1,30 @@ +#ifndef _DYN_FUNCTION_H_ +#define _DYN_FUNCTION_H_ + +#include "ltdl.h" + +#define VAR_CHAR 1 +#define VAR_PTR 2 + +typedef struct _imlib_function_param IFunctionParam; +typedef struct _imlib_function_param *pIFunctionParam; +struct _imlib_function_param +{ + char *key; + int type; + void *data; + pIFunctionParam next; +}; + +typedef struct _imlib_function IFunction; +typedef struct _imlib_function *pIFunction; +struct _imlib_function +{ + char *name; + pIFunctionParam params; + pIFunction next; +}; + +pIFunction __imlib_script_parse( char *script, ... ); +void __imlib_script_tidyup( IFunction *func ); +#endif /* _FUNCTION_H_ */ diff --git a/test/main.c b/test/main.c index be2992b..bdd8b0d 100644 --- a/test/main.c +++ b/test/main.c @@ -830,6 +830,11 @@ int main (int argc, char **argv) } } } + imlib_apply_filter( "tint(x=200,y=200,w=300,h=100,alpha=100,red=155,green=25,blue=25);"\ + "tint(green=20,red=20,blue=20,alpha=200,x=30,y=30);" \ + "tint(green=40,red=40,blue=240,alpha=60,x=50,y=150,h=200);", + NULL ); + imlib_blend_image_onto_image(im_sh1, 0, 0, 0, 50, 50, 0, 0, 50, 50); up = imlib_update_append_rect(up, 0, 0, 50, 50); imlib_blend_image_onto_image(im_sh2, 0, 0, 0, 50, 50, 50, 0, w - 50, 50);