asimagexml.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001 Sasha Vasko <sasha@aftercode.net>
00003  * Copyright (c) 2001 Eric Kowalski <eric@beancrock.net>
00004  * Copyright (c) 2001 Ethan Fisher <allanon@crystaltokyo.com>
00005  *
00006  * This module is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  *
00020  */
00021 
00022 #undef LOCAL_DEBUG
00023 #ifdef _WIN32
00024 #include "win32/config.h"
00025 #else
00026 #include "config.h"
00027 #endif
00028 
00029 #include <ctype.h>
00030 #include <math.h>
00031 #ifdef HAVE_UNISTD_H
00032 #include <unistd.h>
00033 #endif
00034 #ifdef HAVE_STDLIB_H
00035 #include <stdlib.h>
00036 #endif
00037 #ifdef HAVE_STDARG_H
00038 #include <stdarg.h>
00039 #endif
00040 #include <string.h>
00041 #if TIME_WITH_SYS_TIME
00042 # include <sys/time.h>
00043 # include <time.h>
00044 #else
00045 # if HAVE_SYS_TIME_H
00046 #  include <sys/time.h>
00047 # else
00048 #  include <time.h>
00049 # endif
00050 #endif
00051 #ifndef _WIN32
00052 #include <sys/times.h>
00053 #endif
00054 
00055 #ifdef _WIN32
00056 # include "win32/afterbase.h"
00057 #else
00058 # include "afterbase.h"
00059 #endif
00060 #include "afterimage.h"
00061 #include "imencdec.h"
00062 
00063 static char* cdata_str = XML_CDATA_STR;
00064 
00065 /****h* libAfterImage/asimagexml
00066  * NAME
00067  * ascompose is a tool to compose image(s) and display/save it based on
00068  * supplied XML input file.
00069  *
00070  * DESCRIPTION
00071  * ascompose reads supplied XML data, and manipulates image accordingly.
00072  * It could transform images from files of any supported file format,
00073  * draw gradients, render antialiased texturized text, perform
00074  * superimposition of arbitrary number of images, and save images into
00075  * files of any of supported output file formats.
00076  *
00077  * At any point, the result of any operation could be assigned a name,
00078  * and later on referenced under this name.
00079  *
00080  * At any point during the script processing, result of any operation
00081  * could be saved into a file of any supported file types.
00082  *
00083  * Internal image format is 32bit ARGB with 8bit per channel.
00084  *
00085  * Last image referenced, will be displayed in X window, unless -n option
00086  * is specified. If -r option is specified, then this image will be
00087  * displayed in root window of X display, effectively setting a background
00088  * for a desktop. If -o option is specified, this image will also be
00089  * saved into the file or requested type.
00090  *
00091  * TAGS
00092  * 
00093  * Here is the list and description of possible XML tags to use in the
00094  * script :
00095  *      img       - load image from the file.
00096  *      recall    - recall previously loaded/generated image by its name.
00097  *      text      - render text string into new image.
00098  *      save      - save an image into the file.
00099  *      bevel     - draw solid bevel frame around the image.
00100  *      gradient  - render multipoint gradient.
00101  *      mirror    - create mirror copy of an image.
00102  *      blur      - perform gaussian blur on an image.
00103  *      rotate    - rotate/flip image in 90 degree increments.
00104  *      scale     - scale an image to arbitrary size.
00105  *      slice     - enlarge image to arbitrary size leaving corners unchanged.
00106  *      crop      - crop an image to arbitrary size.
00107  *      tile      - tile an image to arbitrary size.
00108  *      hsv       - adjust Hue, Saturation and Value of an image.
00109  *      pad       - pad image with solid color from either or all sides.
00110  *      solid     - generate new image of requested size, filled with solid
00111  *              color.
00112  *      composite - superimpose arbitrary number of images using one of 15
00113  *              available methods.
00114  *  if        - conditional processing based on value of the variables
00115  *  set       - sets value of the variable
00116  *  printf    - formated printing of the value of the variable
00117  *
00118  * Each tag generates new image as the result of the transformation -
00119  * existing images are never modified and could be reused as many times
00120  * as needed. See below for description of each tag.
00121  *
00122  * Whenever numerical values are involved, the basic math ops (add,
00123  * subtract, multiply, divide), unary minus, and parentheses are
00124  * supported.
00125  *
00126  * Operator precedence is NOT supported.  Percentages are allowed, and
00127  * apply to either width or height of the appropriate image (usually
00128  * the refid image).
00129  *
00130  * Also, variables of the form $image.width and $image.height are
00131  * supported.  $image.width is the width of the image with refid "image",
00132  * and $image.height is the height of the same image.  The special
00133  * $xroot.width and $xroot.height values are defined by the the X root
00134  * window, if there is one.  This allows images to be scaled to the
00135  * desktop size: <scale width="$xroot.width" height="$xroot.height">.
00136  *
00137  * Each tag is only allowed to return ONE image.
00138  *
00139 * 
00140  *****/
00141 
00142 static ASImageManager *_as_xml_image_manager = NULL ;
00143 static ASFontManager *_as_xml_font_manager = NULL ;
00144 
00145 void set_xml_image_manager( ASImageManager *imman )
00146 {
00147         _as_xml_image_manager = imman ;
00148 }
00149 void set_xml_font_manager( ASFontManager *fontman )
00150 {
00151         _as_xml_font_manager = fontman ;
00152 }
00153 
00154 
00155 
00156 
00157 ASImageManager *create_generic_imageman(const char *path)               
00158 {
00159         ASImageManager *my_imman = NULL ;
00160         char *path2 = copy_replace_envvar( getenv( ASIMAGE_PATH_ENVVAR ) );
00161         show_progress("image path is \"%s\".", path2?path2:"(null)" );
00162         if( path != NULL )
00163                 my_imman = create_image_manager( NULL, SCREEN_GAMMA, path, path2, NULL );
00164         else
00165                 my_imman = create_image_manager( NULL, SCREEN_GAMMA, path2, NULL );
00166         LOCAL_DEBUG_OUT( "created image manager %p with search path \"%s\"", my_imman, my_imman->search_path[0] );
00167         if( path2 )
00168                 free( path2 );
00169         return my_imman;
00170 }
00171 
00172 ASFontManager *create_generic_fontman(Display *dpy, const char *path)              
00173 {
00174         ASFontManager  *my_fontman ;
00175         char *path2 = copy_replace_envvar( getenv( ASFONT_PATH_ENVVAR ) );
00176         if( path != NULL )
00177         {
00178                 if( path2 != NULL )
00179                 {
00180                         int path_len = strlen(path);
00181                         char *full_path = safemalloc( path_len+1+strlen(path2)+1);
00182                         strcpy( full_path, path );
00183                         full_path[path_len] = ':';
00184                         strcpy( &(full_path[path_len+1]), path2 );
00185                         free( path2 );
00186                         path2 = full_path ;
00187                 }else
00188                         path2 = (char*)path ;
00189         }
00190         my_fontman = create_font_manager( dpy, path2, NULL );
00191         if( path2 && path2 != path )
00192                 free( path2 );
00193 
00194         return my_fontman;
00195 }
00196 
00197 ASImage *
00198 compose_asimage_xml_from_doc(ASVisual *asv, ASImageManager *imman, ASFontManager *fontman, xml_elem_t* doc, ASFlagType flags, int verbose, Window display_win, const char *path, int target_width, int target_height)
00199 {
00200         /* Build the image(s) from the xml document structure. */
00201         ASImage* im = NULL;
00202         ASImageManager *my_imman = imman, *old_as_xml_imman = _as_xml_image_manager ;
00203         ASFontManager  *my_fontman = fontman, *old_as_xml_fontman = _as_xml_font_manager ;
00204         int my_imman_curr_dir_path_idx = MAX_SEARCH_PATHS ;
00205 
00206         if (doc)
00207         {
00208                 int old_target_width = -1;
00209                 int old_target_height = -1;
00210                 xml_elem_t* ptr;
00211                 Bool local_dir_included = False ;
00212 
00213             asxml_var_init();
00214 #if (HAVE_AFTERBASE_FLAG==1)
00215                 if (verbose > 1) 
00216                 {
00217                         xml_print(doc);
00218                         fprintf(stderr, "\n");
00219                 }
00220 #endif
00221 
00222                 if( my_imman == NULL )
00223                 {       
00224                         if( _as_xml_image_manager == NULL )
00225                         {
00226                                 local_dir_included        = True ;
00227                                 _as_xml_image_manager = create_generic_imageman( path );/* we'll want to reuse it in case of recursion */
00228                         }
00229                         my_imman = _as_xml_image_manager ;
00230                 }
00231 
00232                 if( !local_dir_included )
00233                 {
00234                         register int i = 0;
00235                         char **paths = my_imman->search_path ;
00236                         while( i < MAX_SEARCH_PATHS && paths[i] != NULL ) ++i;
00237                         if( i < MAX_SEARCH_PATHS ) 
00238                         {       
00239                                 paths[i] = mystrdup(path) ;                     
00240                                 paths[i+1] = NULL ;
00241                                 my_imman_curr_dir_path_idx = i ;
00242                         }
00243                 }        
00244 
00245                 if( my_fontman == NULL )
00246                 {
00247                         if( _as_xml_font_manager == NULL )
00248                                 _as_xml_font_manager = create_generic_fontman( asv->dpy, path );
00249                         my_fontman = _as_xml_font_manager ;
00250                 }
00251 
00252                 /* save old target size to be restored at the end */            
00253                 old_target_width = asxml_var_get(ASXMLVAR_TargetWidth);
00254                 old_target_height = asxml_var_get(ASXMLVAR_TargetHeight);
00255                 /* set current target size */           
00256                 asxml_var_insert(ASXMLVAR_TargetWidth, target_width);
00257                 asxml_var_insert(ASXMLVAR_TargetHeight, target_height);
00258 
00259                 for (ptr = doc->child ; ptr ; ptr = ptr->next) {
00260                         ASImage* tmpim = build_image_from_xml(asv, my_imman, my_fontman, ptr, NULL, flags, verbose, display_win);
00261                         if (tmpim && im) safe_asimage_destroy(im);
00262                         if (tmpim) im = tmpim;
00263                 }
00264                 if (im && (target_width > 0 || target_height > 0) )
00265                   {
00266                         int scale_width = (target_width>0)?target_width:im->width;
00267                         int scale_height = (target_height>0)?target_height:im->height;
00268                         if (im->width != scale_width || im->height != scale_height)
00269                           {
00270                                 ASImage *tmp = scale_asimage( asv, im, scale_width, scale_height, ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT );
00271                                 if (tmp != NULL)
00272                                   {
00273                                         safe_asimage_destroy(im);
00274                                         im = tmp;
00275                                   }                                             
00276                           }
00277                   }
00278                 /* restore old target size to be restored at the end */         
00279                 asxml_var_insert(ASXMLVAR_TargetWidth, old_target_width);
00280                 asxml_var_insert(ASXMLVAR_TargetHeight, old_target_height);
00281 
00282 LOCAL_DEBUG_OUT( "result im = %p, im->imman     = %p, my_imman = %p, im->magic = %8.8lX", im, im?im->imageman:NULL, my_imman, im?im->magic:0 );
00283                 
00284                 if( my_imman_curr_dir_path_idx < MAX_SEARCH_PATHS && my_imman->search_path[my_imman_curr_dir_path_idx]) 
00285                 {
00286                         free(my_imman->search_path[my_imman_curr_dir_path_idx]);
00287                         my_imman->search_path[my_imman_curr_dir_path_idx] = NULL ;                      
00288                 }
00289 
00290                 if( my_imman != imman && my_imman != old_as_xml_imman )
00291                 {/* detach created image from imman to be destroyed : */
00292                         if( im && im->imageman == my_imman )
00293                                 forget_asimage( im );
00294                         destroy_image_manager(my_imman, False);
00295                 }
00296 
00297                 if( my_fontman != fontman && my_fontman != old_as_xml_fontman  )
00298                         destroy_font_manager(my_fontman, False);
00299                 /* must restore managers to its original state */
00300                 _as_xml_image_manager = old_as_xml_imman   ;
00301                 _as_xml_font_manager =  old_as_xml_fontman ;
00302                 
00303         }
00304         LOCAL_DEBUG_OUT( "returning im = %p, im->imman  = %p, im->magic = %8.8lX", im, im?im->imageman:NULL, im?im->magic:0 );
00305         return im;
00306 }
00307 
00308 ASImage *
00309 compose_asimage_xml_at_size(ASVisual *asv, ASImageManager *imman, ASFontManager *fontman, char *doc_str, ASFlagType flags, int verbose, Window display_win, const char *path, int target_width, int target_height)
00310 {
00311         xml_elem_t* doc = xml_parse_doc(doc_str, NULL);
00312         ASImage *im = compose_asimage_xml_from_doc(asv, imman, fontman, doc, flags, verbose, display_win, path, target_width, target_height);
00313         if (doc)
00314                 xml_elem_delete(NULL, doc);
00315         return im;
00316 }
00317 
00318 inline ASImage *
00319 compose_asimage_xml(ASVisual *asv, ASImageManager *imman, ASFontManager *fontman, char *doc_str, ASFlagType flags, int verbose, Window display_win, const char *path)
00320 {
00321         xml_elem_t* doc = xml_parse_doc(doc_str, NULL);
00322         ASImage *im = compose_asimage_xml_from_doc(asv, imman, fontman, doc, flags, verbose, display_win, path, -1, -1);
00323         if (doc)
00324                 xml_elem_delete(NULL, doc);
00325         return im;
00326 }
00327 
00328 
00329 Bool save_asimage_to_file(const char *file2bsaved, ASImage *im,
00330                    const char *strtype,
00331                            const char *compress,
00332                            const char *opacity,
00333                            int delay, int replace)
00334 {
00335         ASImageExportParams params ;
00336 
00337         memset( &params, 0x00, sizeof(params) );
00338         params.gif.flags = EXPORT_ALPHA ;
00339         if (strtype == NULL || !mystrcasecmp(strtype, "jpeg") || !mystrcasecmp(strtype, "jpg"))  {
00340                 params.type = ASIT_Jpeg;
00341                 params.jpeg.quality = (compress==NULL)?-1:100-atoi(compress);
00342                 if( params.jpeg.quality > 100 )
00343                         params.jpeg.quality = 100;
00344         } else if (!mystrcasecmp(strtype, "bitmap") || !mystrcasecmp(strtype, "bmp")) {
00345                 params.type = ASIT_Bmp;
00346         } else if (!mystrcasecmp(strtype, "png")) {
00347                 params.type = ASIT_Png;
00348                 params.png.compression = (compress==NULL)?-1:atoi(compress);
00349                 if( params.png.compression > 99 )
00350                         params.png.compression = 99;
00351         } else if (!mystrcasecmp(strtype, "xcf")) {
00352                 params.type = ASIT_Xcf;
00353         } else if (!mystrcasecmp(strtype, "ppm")) {
00354                 params.type = ASIT_Ppm;
00355         } else if (!mystrcasecmp(strtype, "pnm")) {
00356                 params.type = ASIT_Pnm;
00357         } else if (!mystrcasecmp(strtype, "ico")) {
00358                 params.type = ASIT_Ico;
00359         } else if (!mystrcasecmp(strtype, "cur")) {
00360                 params.type = ASIT_Cur;
00361         } else if (!mystrcasecmp(strtype, "gif")) {
00362                 params.type = ASIT_Gif;
00363                 params.gif.flags |= EXPORT_APPEND ;
00364                 params.gif.opaque_threshold = (opacity==NULL)?127:atoi(opacity) ;
00365                 params.gif.dither = (compress==NULL)?3:atoi(compress)/17;
00366                 if( params.gif.dither > 6 )
00367                         params.gif.dither = 6;
00368                 params.gif.animate_delay = delay ;
00369         } else if (!mystrcasecmp(strtype, "xpm")) {
00370                 params.type = ASIT_Xpm;
00371                 params.xpm.opaque_threshold = (opacity==NULL)?127:atoi(opacity) ;
00372                 params.xpm.dither = (compress==NULL)?3:atoi(compress)/17;
00373                 if( params.xpm.dither > 6 )
00374                         params.xpm.dither = 6;
00375         } else if (!mystrcasecmp(strtype, "xbm")) {
00376                 params.type = ASIT_Xbm;
00377         } else if (!mystrcasecmp(strtype, "tiff")) {
00378                 params.type = ASIT_Tiff;
00379                 params.tiff.compression_type = TIFF_COMPRESSION_NONE ;
00380                 if( compress )
00381                 {
00382                         if( mystrcasecmp( compress, "deflate" ) == 0 )
00383                                 params.tiff.compression_type = TIFF_COMPRESSION_DEFLATE ;
00384                         else if( mystrcasecmp( compress, "jpeg" ) == 0 )
00385                                 params.tiff.compression_type = TIFF_COMPRESSION_JPEG ;
00386                         else if( mystrcasecmp( compress, "ojpeg" ) == 0 )
00387                                 params.tiff.compression_type = TIFF_COMPRESSION_OJPEG ;
00388                         else if( mystrcasecmp( compress, "packbits" ) == 0 )
00389                                 params.tiff.compression_type = TIFF_COMPRESSION_PACKBITS ;
00390                 }
00391         } else {
00392                 show_error("File type not found.");
00393                 return(0);
00394         }
00395 
00396         if( replace && file2bsaved )
00397                 unlink( file2bsaved );
00398 
00399         return ASImage2file(im, NULL, file2bsaved, params.type, &params);
00400 
00401 }
00402 
00403 void show_asimage(ASVisual *asv, ASImage* im, Window w, long delay)
00404 {
00405 #ifndef X_DISPLAY_MISSING
00406         if ( im && w && asv)
00407         {
00408                 Pixmap p = asimage2pixmap(asv, w, im, NULL, False);
00409                 struct timeval value;
00410 
00411                 XSetWindowBackgroundPixmap( asv->dpy, w, p );
00412                 XClearWindow( asv->dpy, w );
00413                 XFlush( asv->dpy );
00414                 XFreePixmap( asv->dpy, p );
00415                 p = None ;
00416                 value.tv_usec = delay % 10000;
00417                 value.tv_sec = delay / 10000;
00418                 PORTABLE_SELECT (1, 0, 0, 0, &value);
00419         }
00420 #endif /* X_DISPLAY_MISSING */
00421 }
00422 
00423 typedef struct ASImageXMLState
00424 {
00425         ASFlagType              flags ;
00426         ASVisual                *asv;
00427         ASImageManager  *imman ;
00428         ASFontManager   *fontman ;
00429 
00430         int verbose ;
00431         Window display_win ;
00432         
00433 }ASImageXMLState;
00434 
00435 
00436 ASImage *commit_xml_image_built( ASImageXMLState *state, char *id, ASImage *result )
00437 {       
00438         if (state && id && result) 
00439         {
00440         char* buf = NEW_ARRAY(char, strlen(id) + 1 + 6 + 1);
00441                 if( state->verbose > 1 ) 
00442                         show_progress("Storing image id [%s] with image manager %p .", id, state->imman);
00443         sprintf(buf, "%s.width", id);
00444         asxml_var_insert(buf, result->width);
00445         sprintf(buf, "%s.height", id);
00446         asxml_var_insert(buf, result->height);
00447         free(buf);
00448                 if( result->imageman != NULL )
00449                 {
00450                         ASImage *tmp = clone_asimage(result, SCL_DO_ALL );
00451                         safe_asimage_destroy(result );
00452                         result = tmp ;
00453                 }
00454                 if( result )
00455                 {
00456                         if( !store_asimage( state->imman, result, id ) )
00457                         {
00458                                 show_warning("Failed to store image id [%s].", id);
00459                                 //safe_asimage_destroy(result );
00460                                 //result = fetch_asimage( state->imman, id );
00461                                 /*show_warning("Old image with the name fetched as %p.", result);*/
00462                         }else
00463                         {
00464                                 /* normally generated image will be destroyed right away, so we need to
00465                                 * increase ref count, in order to preserve it for future uses : */
00466                                 dup_asimage( result );
00467                         }
00468                 }
00469         }
00470         return result;
00471 }
00472 
00473 static void
00474 translate_tag_size(     const char *width_str, const char *height_str, ASImage *imtmp, ASImage *refimg, int *width_ret, int *height_ret )
00475 {
00476         int width_ref = 0;
00477         int height_ref = 0;
00478         int width = 0, height = 0 ; 
00479         LOCAL_DEBUG_OUT("width_str = \"%s\", height_str = \"%s\", imtmp = %p, refimg = %p", width_str?width_str:"(null)", height_str?height_str:"(null)", imtmp, refimg ); 
00480         
00481         if( imtmp ) 
00482         {       
00483                 width_ref = width = imtmp->width ;
00484                 height_ref = height = imtmp->height ;
00485         }
00486         if (refimg) 
00487         {
00488                 width_ref = refimg->width;
00489                 height_ref = refimg->height;
00490         }
00491         if( width_str ) 
00492         {       
00493                 if( width_str[0] == '$' || isdigit( (int)width_str[0] ) )
00494                         width = (int)parse_math(width_str, NULL, width);
00495         }
00496         if( height_str ) 
00497         {       
00498                 if( height_str[0] == '$' || isdigit( (int)height_str[0] ) )
00499                         height = (int)parse_math(height_str, NULL, height);
00500         }
00501         if( width_str && height_ref > 0 && mystrcasecmp(width_str,"proportional") == 0 )
00502                 width = (width_ref * height) / height_ref ;
00503         else if( height_str && width_ref > 0 && mystrcasecmp(height_str,"proportional") == 0 )
00504                 height = (height_ref * width) / width_ref ;
00505         if( width_ret ) 
00506                 *width_ret = (width==0)?(imtmp?imtmp->width:(refimg?refimg->width:0)):width;
00507         if( height_ret ) 
00508                 *height_ret = (height==0)?(imtmp?imtmp->height:(refimg?refimg->height:0)):height;
00509 
00510         LOCAL_DEBUG_OUT("width = %d, height = %d", *width_ret, *height_ret ); 
00511 
00512 }
00513 
00514 /****** libAfterImage/asimagexml/text
00515  * NAME
00516  * text - render text string into new image, using specific font, size
00517  *        and texture.
00518  * SYNOPSIS
00519  * <text id="new_id" font="font" point="size" fgcolor="color"
00520  *       bgcolor="color" fgimage="image_id" bgimage="image_id"
00521  *       spacing="points" type="3dtype">My Text Here</text>
00522  * ATTRIBUTES
00523  * id       Optional.  Image will be given this name for future reference.
00524  * font     Optional.  Default is "fixed".  Font to use for text.
00525  * point    Optional.  Default is 12.  Size of text in points.
00526  * fgcolor  Optional.  No default.  The text will be drawn in this color.
00527  * bgcolor  Optional.  No default.  The area behind the text will be drawn
00528  *          in this color.
00529  * fgimage  Optional.  No default.  The text will be textured by this image.
00530  * bgimage  Optional.  No default.  The area behind the text will be filled
00531  *          with this image.
00532  * spacing  Optional.  Default 0.  Extra pixels to place between each glyph.
00533  * type     Optional.  Default 0.  Valid values are from 0 to 7 and each 
00534  *                      represeend different 3d type.
00535  * NOTES
00536  * <text> without bgcolor, fgcolor, fgimage, or bgimage will NOT
00537  * produce visible output by itself.  See EXAMPLES below.
00538  ******/
00539 static ASImage *
00540 handle_asxml_tag_text( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm )
00541 {
00542         ASImage *result = NULL ;
00543         xml_elem_t* ptr ;
00544         const char* text = NULL;
00545         const char* font_name = "fixed";
00546         const char* fgimage_str = NULL;
00547         const char* bgimage_str = NULL;
00548         const char* fgcolor_str = NULL;
00549         const char* bgcolor_str = NULL;
00550         ARGB32 fgcolor = ARGB32_White, bgcolor = ARGB32_Black;
00551         int point = 12, spacing = 0, type = AST_Plain;
00552         unsigned int width = 0;
00553         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
00554         for (ptr = parm ; ptr ; ptr = ptr->next) {
00555                 if (!strcmp(ptr->tag, "font")) font_name = ptr->parm;
00556                 else if (!strcmp(ptr->tag, "point")) point = strtol(ptr->parm, NULL, 0);
00557                 else if (!strcmp(ptr->tag, "spacing")) spacing = strtol(ptr->parm, NULL, 0);
00558                 else if (!strcmp(ptr->tag, "fgimage")) fgimage_str = ptr->parm;
00559                 else if (!strcmp(ptr->tag, "bgimage")) bgimage_str = ptr->parm;
00560                 else if (!strcmp(ptr->tag, "fgcolor")) fgcolor_str = ptr->parm;
00561                 else if (!strcmp(ptr->tag, "bgcolor")) bgcolor_str = ptr->parm;
00562                 else if (!strcmp(ptr->tag, "type")) type = strtol(ptr->parm, NULL, 0);
00563                 else if (!strcmp(ptr->tag, "width")) width = strtol(ptr->parm, NULL, 0);
00564         }
00565         for (ptr = doc->child ; ptr && text == NULL ; ptr = ptr->next)
00566                 if (!strcmp(ptr->tag, cdata_str)) text = ptr->parm;
00567         
00568         if (text && point > 0) 
00569         {
00570                 struct ASFont *font = NULL;
00571                 if( state->verbose > 1 ) 
00572                         show_progress("Rendering text [%s] with font [%s] size [%d].", text, font_name, point);
00573                 if (state->fontman) font = get_asfont(state->fontman, font_name, 0, point, ASF_GuessWho);
00574                 if (font != NULL) 
00575                 {
00576                   ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0, ARGB32_White, width};
00577                         attr.type = type ;
00578                         if( IsUTF8Locale() ) 
00579                                 attr.char_type = ASCT_UTF8 ;
00580                         set_asfont_glyph_spacing(font, spacing, 0);
00581                         if( fgcolor_str ) 
00582                                 parse_argb_color(fgcolor_str, &(attr.fore_color) );
00583                         
00584                         result = draw_fancy_text( text, font, &attr, 0, 0/*autodetect length*/ );
00585                         if (result && fgcolor_str) {
00586 #if 0                      
00587                                 result->back_color = attr.fore_color ;
00588 #else
00589                                 ASImage* fgimage = create_asimage(result->width, result->height, ASIMAGE_QUALITY_TOP);
00590                                 parse_argb_color(fgcolor_str, &fgcolor);
00591                                 fill_asimage(state->asv, fgimage, 0, 0, result->width, result->height, fgcolor);
00592                                 move_asimage_channel(fgimage, IC_ALPHA, result, IC_ALPHA);
00593                                 safe_asimage_destroy(result);
00594                                 result = fgimage ;
00595 #endif
00596                         }
00597                         if (result && fgimage_str) {
00598                                 ASImage* fgimage = NULL;
00599                                 fgimage = get_asimage(state->imman, fgimage_str, 0xFFFFFFFF, 100 );
00600                                 if( state->verbose > 1 ) 
00601                                         show_progress("Using image [%s](%p) as foreground. Text size is %dx%d", fgimage_str, fgimage, result->width, result->height);
00602                                 if (fgimage) {
00603                                         ASImage *tmp = tile_asimage(state->asv, fgimage, 0, 0, result->width, result->height, 0, ASA_ASImage, 100, ASIMAGE_QUALITY_TOP);
00604                                         if( tmp )
00605                                         {
00606                                                 release_asimage( fgimage );
00607                                                 fgimage = tmp ;
00608                                         }
00609                                         move_asimage_channel(fgimage, IC_ALPHA, result, IC_ALPHA);
00610                                         safe_asimage_destroy(result);
00611                                         result = fgimage;
00612                                 }
00613                         }
00614                         if (result && (bgcolor_str || bgimage_str)) {
00615                                 ASImageLayer layers[2];
00616                                 init_image_layers(&(layers[0]), 2);
00617                                 if (bgimage_str) layers[0].im = fetch_asimage(state->imman, bgimage_str);
00618                                 if (bgcolor_str)
00619                                         if( parse_argb_color(bgcolor_str, &bgcolor) != bgcolor_str )
00620                                         {
00621                                                 if( layers[0].im != NULL )
00622                                                         layers[0].im->back_color = bgcolor ;
00623                                                 else
00624                                                         layers[0].solid_color = bgcolor ;
00625                                         }
00626                                 result->back_color = fgcolor ;
00627                                 layers[0].dst_x = 0;
00628                                 layers[0].dst_y = 0;
00629                                 layers[0].clip_width = result->width;
00630                                 layers[0].clip_height = result->height;
00631                                 layers[0].bevel = NULL;
00632                                 layers[1].im = result;
00633                                 layers[1].dst_x = 0;
00634                                 layers[1].dst_y = 0;
00635                                 layers[1].clip_width = result->width;
00636                                 layers[1].clip_height = result->height;
00637                                 result = merge_layers(state->asv, layers, 2, result->width, result->height, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
00638                                 safe_asimage_destroy( layers[0].im );
00639                         }
00640                 }
00641         }
00642 
00643         return result;
00644 }       
00645 /****** libAfterImage/asimagexml/composite
00646  * NAME
00647  * composite - superimpose arbitrary number of images on top of each
00648  * other.
00649  * SYNOPSIS
00650  * <composite id="new_id" op="op_desc"
00651  *            keep-transparency="0|1" merge="0|1">
00652  * ATTRIBUTES
00653  * id       Optional. Image will be given this name for future reference.
00654  * op       Optional. Default is "alphablend". The compositing operation.
00655  *          Valid values are the standard AS blending ops: add, alphablend,
00656  *          allanon, colorize, darken, diff, dissipate, hue, lighten,
00657  *          overlay, saturate, screen, sub, tint, value.
00658  * merge    Optional. Default is "expand". Valid values are "clip" and
00659  *          "expand". Determines whether final image will be expanded to
00660  *          the maximum size of the layers, or clipped to the bottom
00661  *          layer.
00662  * keep-transparency
00663  *          Optional. Default is "0". Valid values are "0" and "1". If
00664  *          set to "1", the transparency of the bottom layer will be
00665  *          kept for the final image.
00666  * NOTES
00667  * All images surrounded by this tag will be composited with the given op.
00668  *
00669  * ATTRIBUTES
00670  *  All tags surrounded by this tag may have some of the common attributes
00671  *  in addition to their normal ones.  Under no circumstances is there a 
00672  *  conflict with the normal child attributes:
00673  * 
00674  * crefid   Optional. An image ID defined with the "id" parameter for
00675  *          any previously created image. If set, percentages in "x"
00676  *          and "y" will be derived from the width and height of the
00677  *          crefid image.
00678  * x        Optional. Default is 0. Pixel coordinate of left edge.
00679  * y        Optional. Default is 0. Pixel coordinate of top edge.
00680  * align    Optional. Alternative to x - allowed values are right, center
00681  *          and left.
00682  * valign   Optional. Alternative to y - allowed values are top, middle
00683  *          and bottom.
00684  * clip_x   Optional. Default is 0. X Offset on infinite surface tiled
00685  *          with this image, from which to cut portion of an image to be
00686  *          used in composition.
00687  * clip_y   Optional. Default is 0. Y Offset on infinite surface tiled
00688  *          with this image, from which to cut portion of an image to be
00689  *          used in composition.
00690  * clip_width
00691  *          Optional. Default is image width. Tile image to this width
00692  *          prior to superimposition.
00693  * clip_height
00694  *          Optional. Default is image height. Tile image to this height
00695  *          prior to superimposition.
00696  * tile     Optional. Default is 0. If set will cause image to be tiled
00697  *          across entire composition, unless overridden by clip_width or
00698  *          clip_height.
00699  * tint     Optional. Additionally tint an image to specified color.
00700  *          Tinting can both lighten and darken an image. Tinting color
00701  *          0 or #7f7f7f7f yields no tinting. Tinting can be performed
00702  *          on any channel, including alpha channel.
00703  * SEE ALSO
00704  * libAfterImage
00705  ******/
00706 static ASImage *
00707 handle_asxml_tag_composite( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm )
00708 {
00709         ASImage *result = NULL ;
00710         xml_elem_t* ptr ;
00711         const char* pop = "alphablend";
00712         int keep_trans = 0;
00713         int merge = 0;
00714         int num = 0;
00715         int width = 0, height = 0;
00716         ASImageLayer *layers;
00717 #define  ASXML_ALIGN_LEFT       (0x01<<0)
00718 #define  ASXML_ALIGN_RIGHT      (0x01<<1)
00719 #define  ASXML_ALIGN_TOP    (0x01<<2)
00720 #define  ASXML_ALIGN_BOTTOM (0x01<<3)
00721         int *align ;
00722         int i ;
00723         merge_scanlines_func op_func = NULL ;
00724 
00725         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
00726         for (ptr = parm ; ptr ; ptr = ptr->next) {
00727                 if (!strcmp(ptr->tag, "op")) { pop = ptr->parm; op_func = blend_scanlines_name2func(pop); }
00728                 else if (!strcmp(ptr->tag, "keep-transparency")) keep_trans = strtol(ptr->parm, NULL, 0);
00729                 else if (!strcmp(ptr->tag, "merge") && !mystrcasecmp(ptr->parm, "clip")) merge = 1;
00730         }
00731         /* Find out how many subimages we have. */
00732         for (ptr = doc->child ; ptr ; ptr = ptr->next) 
00733                 if (strcmp(ptr->tag, cdata_str)) num++;
00734 
00735         if( num == 0 ) 
00736         {
00737                 show_warning( "composite tag with no subimages to compose from specified!");      
00738                 return NULL;
00739         }
00740 
00741         
00742         if( op_func == NULL ) 
00743         {       
00744                 LOCAL_DEBUG_OUT( "defaulting to alpha-blending%s","");
00745                 op_func = alphablend_scanlines ;
00746         }
00747         /* Build the layers first. */
00748         layers = create_image_layers( num );
00749         align = safecalloc( num, sizeof(int));
00750 
00751         for (num = 0, ptr = doc->child ; ptr ; ptr = ptr->next) 
00752         {
00753                 int x = 0, y = 0;
00754                 int clip_x = 0, clip_y = 0;
00755                 int clip_width = 0, clip_height = 0;
00756                 ARGB32 tint = 0;
00757                 Bool tile = False ;
00758                 xml_elem_t* sparm = NULL;
00759                 if (!strcmp(ptr->tag, cdata_str)) continue;
00760                 if( (layers[num].im = build_image_from_xml(state->asv, state->imman, state->fontman, ptr, &sparm, state->flags, state->verbose, state->display_win)) != NULL )
00761                 {
00762                         clip_width = layers[num].im->width;
00763                         clip_height = layers[num].im->height;
00764                 }
00765                 if (sparm) 
00766                 {
00767                         xml_elem_t* tmp;
00768                         const char* x_str = NULL;
00769                         const char* y_str = NULL;
00770                         const char* clip_x_str = NULL;
00771                         const char* clip_y_str = NULL;
00772                         const char* clip_width_str = NULL;
00773                         const char* clip_height_str = NULL;
00774                         const char* refid = NULL;
00775                         for (tmp = sparm ; tmp ; tmp = tmp->next) {
00776                                 if (!strcmp(tmp->tag, "crefid")) refid = tmp->parm;
00777                                 else if (!strcmp(tmp->tag, "x")) x_str = tmp->parm;
00778                                 else if (!strcmp(tmp->tag, "y")) y_str = tmp->parm;
00779                                 else if (!strcmp(tmp->tag, "clip_x")) clip_x_str = tmp->parm;
00780                                 else if (!strcmp(tmp->tag, "clip_y")) clip_y_str = tmp->parm;
00781                                 else if (!strcmp(tmp->tag, "clip_width")) clip_width_str = tmp->parm;
00782                                 else if (!strcmp(tmp->tag, "clip_height")) clip_height_str = tmp->parm;
00783                                 else if (!strcmp(tmp->tag, "tint")) parse_argb_color(tmp->parm, &tint);
00784                                 else if (!strcmp(tmp->tag, "tile")) tile = True;
00785                                 else if (!strcmp(tmp->tag, "align"))
00786                                 {
00787                                         if (!strcmp(tmp->parm, "left"))set_flags( align[num], ASXML_ALIGN_LEFT);
00788                                         else if (!strcmp(tmp->parm, "right"))set_flags( align[num], ASXML_ALIGN_RIGHT);
00789                                         else if (!strcmp(tmp->parm, "center"))set_flags( align[num], ASXML_ALIGN_LEFT|ASXML_ALIGN_RIGHT);
00790                                 }else if (!strcmp(tmp->tag, "valign"))
00791                                 {
00792                                         if (!strcmp(tmp->parm, "top"))set_flags( align[num], ASXML_ALIGN_TOP) ;
00793                                         else if (!strcmp(tmp->parm, "bottom"))set_flags( align[num], ASXML_ALIGN_BOTTOM);
00794                                         else if (!strcmp(tmp->parm, "middle"))set_flags( align[num], ASXML_ALIGN_TOP|ASXML_ALIGN_BOTTOM);
00795                                 }
00796                         }
00797                         if (refid) {
00798                                 ASImage* refimg = fetch_asimage(state->imman, refid);
00799                                 if (refimg) {
00800                                         x = refimg->width;
00801                                         y = refimg->height;
00802                                 }
00803                                 safe_asimage_destroy(refimg );
00804                         }
00805                         x = x_str ? (int)parse_math(x_str, NULL, x) : 0;
00806                         y = y_str ? (int)parse_math(y_str, NULL, y) : 0;
00807                         clip_x = clip_x_str ? (int)parse_math(clip_x_str, NULL, x) : 0;
00808                         clip_y = clip_y_str ? (int)parse_math(clip_y_str, NULL, y) : 0;
00809                         if( clip_width_str )
00810                                 clip_width = (int)parse_math(clip_width_str, NULL, clip_width);
00811                         else if( tile )
00812                                 clip_width = 0 ;
00813                         if( clip_height_str )
00814                                 clip_height = (int)parse_math(clip_height_str, NULL, clip_height);
00815                         else if( tile )
00816                                 clip_height = 0 ;
00817                 }
00818                 if (layers[num].im) {
00819                         layers[num].dst_x = x;
00820                         layers[num].dst_y = y;
00821                         layers[num].clip_x = clip_x;
00822                         layers[num].clip_y = clip_y;
00823                         layers[num].clip_width = clip_width ;
00824                         layers[num].clip_height = clip_height ;
00825                         layers[num].tint = tint;
00826                         layers[num].bevel = 0;
00827                         layers[num].merge_scanlines = op_func;
00828                         if( clip_width + x > 0 )
00829                         {
00830                                 if( width < clip_width + x )
00831                                         width = clip_width + x;
00832                         }else
00833                                 if (width < (int)(layers[num].im->width)) width = layers[num].im->width;
00834                         if( clip_height + y > 0 )
00835                         {
00836                                 if( height < clip_height + y )
00837                                         height = clip_height + y ;
00838                         }else
00839                                 if (height < (int)(layers[num].im->height)) height = layers[num].im->height;
00840                         num++;
00841                 }
00842                 if (sparm) xml_elem_delete(NULL, sparm);
00843         }
00844 
00845         if (num && merge && layers[0].im ) {
00846                 width = layers[0].im->width;
00847                 height = layers[0].im->height;
00848         }
00849 
00850 
00851         for (i = 0 ; i < num ; i++)
00852         {
00853                 if( get_flags(align[i], ASXML_ALIGN_LEFT|ASXML_ALIGN_RIGHT ) )
00854                 {
00855                         int im_width = ( layers[i].clip_width == 0 )? layers[i].im->width : layers[i].clip_width ;
00856                         int x = 0 ;
00857                         if( get_flags( align[i], ASXML_ALIGN_RIGHT ) )
00858                                 x = width - im_width ;
00859                         if( get_flags( align[i], ASXML_ALIGN_LEFT ) )
00860                                 x /= 2;
00861                         layers[i].dst_x = x;
00862                 }
00863                 if( get_flags(align[i], ASXML_ALIGN_TOP|ASXML_ALIGN_BOTTOM ) )
00864                 {
00865                         int im_height = ( layers[i].clip_height == 0 )? layers[i].im->height : layers[i].clip_height;
00866                         int y = 0 ;
00867                         if( get_flags( align[i], ASXML_ALIGN_BOTTOM ) )
00868                                 y = height - im_height ;
00869                         if( get_flags( align[i], ASXML_ALIGN_TOP ) )
00870                                 y /= 2;
00871                         layers[i].dst_y = y;
00872                 }
00873                 if( layers[i].clip_width == 0 )
00874                         layers[i].clip_width = width - layers[i].dst_x;
00875                 if( layers[i].clip_height == 0 )
00876                         layers[i].clip_height = height - layers[i].dst_y;
00877         }
00878 
00879         if (state->verbose > 1) {
00880                 show_progress("Compositing [%d] image(s) with op [%s].  Final geometry [%dx%d].", num, pop, width, height);
00881                 if (keep_trans) show_progress("  Keeping transparency.");
00882         
00883                 for (i = 0 ; i < num ; i++) {
00884                         show_progress("  Image [%d] geometry [%dx%d+%d+%d]", i, layers[i].clip_width, layers[i].clip_height, layers[i].dst_x, layers[i].dst_y);
00885                         if (layers[i].tint) show_progress(" tint (#%08x)", (unsigned int)layers[i].tint);
00886                 }
00887         }
00888 
00889         result = merge_layers( state->asv, layers, num, width, height, 
00890                                                         ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
00891         if (keep_trans && result && layers[0].im)
00892                 copy_asimage_channel(result, IC_ALPHA, layers[0].im, IC_ALPHA);
00893         
00894         while (--num >= 0 )
00895                 safe_asimage_destroy( layers[num].im );
00896         
00897         free(align);
00898         free(layers);
00899 
00900         return result;
00901 }
00902 
00903 /****** libAfterImage/asimagexml/img
00904  * NAME
00905  * img - load image from the file.
00906  * SYNOPSIS
00907  * <img id="new_img_id" src="filename"/>
00908  * ATTRIBUTES
00909  * id     Optional.  Image will be given this name for future reference.
00910  * src    Required.  The filename (NOT URL) of the image file to load.
00911  * NOTES
00912  * The special image src "xroot:" will import the background image
00913  * of the root X window, if any.  No attempt will be made to offset this
00914  * image to fit the location of the resulting window, if one is displayed.
00915  ******/
00916 static ASImage *
00917 handle_asxml_tag_img( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, int dst_width, int dst_height)
00918 {
00919         ASImage *result = NULL ;
00920         const char* src = NULL;
00921         xml_elem_t* ptr ;
00922         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
00923         for (ptr = parm ; ptr ; ptr = ptr->next) {
00924                 if (!strcmp(ptr->tag, "src")) src = ptr->parm;
00925         }
00926         if (src && !strcmp(src, "xroot:")) {
00927                 unsigned int width, height;
00928                 Pixmap rp = GetRootPixmap(None);
00929                 if( state->verbose > 1 ) 
00930                         show_progress("Getting root pixmap.");
00931                 if (rp) {
00932                         get_dpy_drawable_size( state->asv->dpy, rp, &width, &height);
00933                         result = pixmap2asimage(state->asv, rp, 0, 0, width, height, 0xFFFFFFFF, False, 100);
00934                         if( dst_width == 0 ) dst_width = width ; 
00935                         if( dst_height == 0 ) dst_height = height ; 
00936                         if( dst_width != (int)width || dst_height != (int)height ) 
00937                         {
00938                                 ASImage *tmp = scale_asimage( NULL, result, dst_width, dst_height, ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT );
00939                                 if( tmp ) 
00940                                 {
00941                                         safe_asimage_destroy( result );
00942                                         result = tmp ;
00943                                 }       
00944                         }       
00945                 }
00946         } else if (src) {
00947                 if( state->verbose > 1 ) 
00948                         show_progress("Loading image [%s] using imman (%p) with search path \"%s\" (dst_size = %dx%d).", src, state->imman, state->imman?state->imman->search_path[0]:"", dst_width, dst_height);
00949                 if( dst_width != 0 || dst_height != 0 ) 
00950                         result = get_thumbnail_asimage( state->imman, src, dst_width, dst_height, (dst_width==0||dst_height==0)?AS_THUMBNAIL_PROPORTIONAL:0 );
00951                 else
00952                         result = get_asimage( state->imman, src, 0xFFFFFFFF, 100 );
00953         }
00954         return result;
00955 }       
00956 
00957 /****** libAfterImage/asimagexml/recall
00958  * NAME
00959  * recall - recall previously generated and named image by its id.
00960  * SYNOPSIS
00961  * <recall id="new_id" srcid="image_id" default_src="filename"/>
00962  * ATTRIBUTES
00963  * id       Optional.  Image will be given this name for future reference.
00964  * srcid    Required.  An image ID defined with the "id" parameter for
00965  *          any previously created image.
00966  ******/
00967 static ASImage *
00968 handle_asxml_tag_recall( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
00969 {
00970         ASImage *result = NULL ;
00971         xml_elem_t* ptr = parm ; 
00972         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
00973         while ( ptr && !result ) 
00974         {       
00975                 if (!strcmp(ptr->tag, "srcid"))
00976                 { 
00977                         if( state->verbose > 1 ) 
00978                                 show_progress("Recalling image id [%s] from imman %p.", ptr->parm, state->imman);
00979                         result = fetch_asimage(state->imman, ptr->parm );
00980                         if (!result)
00981                                 show_warning("Image recall failed for id [%s].", ptr->parm);
00982                 }       
00983                 ptr = ptr->next ;
00984         }
00985         if( result == NULL ) 
00986         {
00987                 for( ptr = parm ; ptr && !result ; ptr = ptr->next )
00988                         if (!strcmp(ptr->tag, "default_src"))
00989                         { 
00990                                 if( state->verbose > 1 ) 
00991                                         show_progress("loading default image [%s] from imman %p.", ptr->parm, state->imman);
00992                                 result = get_asimage( state->imman, ptr->parm, 0xFFFFFFFF, 100 );
00993                         }
00994         }
00995         return result;
00996 }       
00997 
00998 /****** libAfterImage/asimagexml/release
00999  * NAME
01000  * release - release (destroy if possible) previously generated and named image by its id.
01001  * SYNOPSIS
01002  * <release srcid="image_id"/>
01003  * ATTRIBUTES
01004  * srcid    Required.  An image ID defined with the "id" parameter for
01005  *          any previously created image.
01006  ******/
01007 static ASImage *
01008 handle_asxml_tag_release( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
01009 {
01010         xml_elem_t* ptr ;
01011         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
01012         for (ptr = parm ; ptr ; ptr = ptr->next) 
01013                 if (!strcmp(ptr->tag, "srcid"))
01014                 {
01015                         if( state->verbose > 1 ) 
01016                                 show_progress("Releasing image id [%s] from imman %p.", ptr->parm, state->imman);
01017                         release_asimage_by_name(state->imman, (char*)ptr->parm );
01018                         break;
01019                 }
01020         return NULL;
01021 }       
01022 
01023 /****** libAfterImage/asimagexml/color
01024  * NAME
01025  * color - defines symbolic name for a color and set of variables.
01026  * SYNOPSIS
01027  * <color name="sym_name" domain="var_domain" argb="colorvalue"/>
01028  * ATTRIBUTES
01029  * name   Symbolic name for the color value, to be used to refer to that color.
01030  * argb   8 characters hex definition of the color or other symbolic color name.
01031  * domain string to be used to prepend names of defined variables.
01032  * NOTES
01033  * In addition to defining symbolic name for the color this tag will define
01034  * 7 other variables :  domain.sym_name.red, domain.sym_name.green, 
01035  *                                              domain.sym_name.blue, domain.sym_name.alpha, 
01036  *                                              domain.sym_name.hue, domain.sym_name.saturation,
01037  *                      domain.sym_name.value
01038  ******/
01039 static ASImage *
01040 handle_asxml_tag_color( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
01041 {
01042         xml_elem_t* ptr ;
01043         char* name = NULL;
01044         const char* argb_text = NULL;
01045         const char* var_domain = NULL;
01046         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
01047         for (ptr = parm ; ptr ; ptr = ptr->next) {
01048                 if (!strcmp(ptr->tag, "name")) name = ptr->parm;
01049                 else if (!strcmp(ptr->tag, "argb")) argb_text = ptr->parm;
01050                 else if (!strcmp(ptr->tag, "domain")) var_domain = ptr->parm;
01051         }
01052         if (name && argb_text) 
01053         {
01054                 ARGB32 argb = ARGB32_Black;
01055                 if( parse_argb_color( argb_text, &argb ) != argb_text )
01056                 {
01057                         char *tmp;
01058                         CARD32 hue16, sat16, val16 ;
01059                         int vd_len = var_domain?strlen(var_domain):0 ;
01060 
01061                         tmp = safemalloc( vd_len + 1+ strlen(name )+32+1 ) ;
01062 
01063                         if( var_domain && var_domain[0] != '\0' )
01064                         {
01065                                 if( var_domain[vd_len-1] != '.' )
01066                                 {
01067                                         sprintf( tmp, "%s.", var_domain );
01068                                         ++vd_len ;
01069                                 }else
01070                                         strcpy( tmp, var_domain );
01071                         }
01072 
01073 
01074 #ifdef HAVE_AFTERBASE
01075                         if( state->verbose > 1 ) 
01076                                 show_progress("defining synonim [%s] for color value #%8.8X.", name, argb);
01077                         register_custom_color( name, argb );
01078 #endif
01079                         sprintf( tmp+vd_len, "%s.alpha", name );
01080                         asxml_var_insert( tmp, ARGB32_ALPHA8(argb) );
01081                         sprintf( tmp+vd_len, "%s.red", name );
01082                         asxml_var_insert( tmp, ARGB32_RED8(argb) );
01083                         sprintf( tmp+vd_len, "%s.green", name );
01084                         asxml_var_insert( tmp, ARGB32_GREEN8(argb) );
01085                         sprintf( tmp+vd_len, "%s.blue", name );
01086                         asxml_var_insert( tmp, ARGB32_BLUE8(argb) );
01087 
01088                         hue16 = rgb2hsv( ARGB32_RED16(argb), ARGB32_GREEN16(argb), ARGB32_BLUE16(argb), &sat16, &val16 );
01089 
01090                         sprintf( tmp+vd_len, "%s.hue", name );
01091                         asxml_var_insert( tmp, hue162degrees( hue16 ) );
01092                         sprintf( tmp+vd_len, "%s.saturation", name );
01093                         asxml_var_insert( tmp, val162percent( sat16 ) );
01094                         sprintf( tmp+vd_len, "%s.value", name );
01095                         asxml_var_insert( tmp, val162percent( val16 ) );
01096                         free( tmp );
01097                 }
01098         }
01099         return NULL;
01100 }
01101 /****** libAfterImage/asimagexml/printf
01102  * NAME
01103  * printf - prints variable value to standard output.
01104  * SYNOPSIS
01105  * <printf format="format_string" var="variable_name" val="expression"/>
01106  * ATTRIBUTES
01107  * format_string  Standard C format string with exactly 1 placeholder.
01108  * var            Name of the variable, which value will be printed.
01109  * val            math expression to be printed.
01110  * NOTES
01111  ******/
01112 static ASImage *
01113 handle_asxml_tag_printf( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
01114 {
01115         xml_elem_t* ptr ;
01116         const char* format = NULL;
01117         const char* var = NULL;
01118         int val = 0 ;
01119         Bool use_val = False ;
01120         int arg_count = 0, i;
01121         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
01122         for (ptr = parm ; ptr ; ptr = ptr->next) 
01123         {
01124                 if (!strcmp(ptr->tag, "format")) format = ptr->parm;
01125                 else if (!strcmp(ptr->tag, "var")) { var = ptr->parm; use_val = False; }
01126                 else if (!strcmp(ptr->tag, "val")) { val = (int)parse_math(ptr->parm, NULL, 0); use_val = True; }
01127         }
01128                 
01129         if( format != NULL ) 
01130         {       
01131                 char *interpreted_format = interpret_ctrl_codes( mystrdup(format) );
01132                 
01133                 for( i = 0 ; format[i] != '\0' ; ++i )
01134                         if( format[i] == '%' )
01135                         {
01136                                 if( format[i+1] != '%' ) 
01137                                         ++arg_count ; 
01138                                 else 
01139                                         ++i ;
01140                         }
01141                 
01142                 if( use_val && arg_count == 1) 
01143                         printf( interpreted_format, val );
01144                 else if( var != NULL && arg_count == 1 ) 
01145                         printf( interpreted_format, asxml_var_get(var) );                               
01146                 else if( arg_count == 0 )
01147                         fputs( interpreted_format, stdout );                               
01148                 free( interpreted_format );
01149         }
01150                 
01151         return NULL;
01152 }
01153 /****** libAfterImage/asimagexml/set
01154  * NAME
01155  * set - declares variable, assigning it a numeric value of expression.
01156  * SYNOPSIS
01157  * <set var="variable_name" domain="var_domain" val="expression"/>
01158  * ATTRIBUTES
01159  * var            Name of the variable, which value will be set.
01160  * val            math expression to be evaluated.
01161  * domain         (optional) variable's domain to be prepended to its name
01162  *                using format var_domain.variable_name
01163  ******/
01164 static ASImage *
01165 handle_asxml_tag_set( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
01166 {
01167         xml_elem_t* ptr ;
01168         const char* var_domain = NULL ;
01169         const char* var = NULL;
01170         int val = 0 ;
01171         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
01172         for (ptr = parm ; ptr ; ptr = ptr->next) 
01173         {
01174                 if (!strcmp(ptr->tag, "var"))                   var = ptr->parm;
01175                 else if (!strcmp(ptr->tag, "domain"))   var_domain = ptr->parm;
01176                 else if (!strcmp(ptr->tag, "val"))      val = (int)parse_math(ptr->parm, NULL, 0);
01177         }
01178                 
01179         if( var != NULL ) 
01180         {       
01181                 char *tmp = (char*)var ; 
01182                 if( var_domain && var_domain[0] != '\0' )
01183                 {
01184                         int vd_len = strlen(var_domain);
01185                         tmp = safemalloc( vd_len + 1 + strlen(var) + 1 );
01186                         sprintf( tmp, ( var_domain[vd_len-1] != '.' )?"%s.%s":"%s%s", var_domain, var );
01187                 }
01188                 asxml_var_insert( tmp, val );
01189                 if( tmp != var ) 
01190                         free( tmp );
01191         }
01192                 
01193         return NULL;
01194 }
01195 /****** libAfterImage/asimagexml/if
01196  * NAME
01197  * if - evaluates logical expression and if result evaluates to not true(or false 
01198  * if <unless> tag is used ), handles tags within.
01199  * SYNOPSIS
01200  * <if val1="expression" [op="gt|lt|ge|le|eq|ne" val2="expression"]/>
01201  *      [<then>...</then><else>...</else>]
01202  * </if>
01203  * <unless val1="expression" [op="gt|lt|ge|le|eq|ne" val2="expression"]/>
01204  * ATTRIBUTES
01205  * val1            math expression to be evaluated.
01206  * val2            math expression to be evaluated.
01207  * op            (optional) comparison op to be applied to values
01208  * EXAMPLE
01209  * <if val1="$ascs.Base.value" val2="50" op="gt"><then>...</then><else>...</else></if>
01210  ******/
01211 static ASImage *
01212 handle_asxml_tag_if( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm)
01213 {
01214         xml_elem_t* ptr ;
01215         int val1 = 0, val2 = 0 ;
01216         const char *op = NULL ;
01217         int res = 0 ; 
01218         ASImage *im = NULL, *imtmp = NULL  ; 
01219         LOCAL_DEBUG_OUT("doc = %p, parm = %p", doc, parm ); 
01220         
01221         for (ptr = parm ; ptr ; ptr = ptr->next) 
01222         {
01223                 if (!strcmp(ptr->tag, "op"))                    op = ptr->parm;
01224                 else if (!strcmp(ptr->tag, "val1"))     val1 = (int)parse_math(ptr->parm, NULL, 0);
01225                 else if (!strcmp(ptr->tag, "val2"))     val2 = (int)parse_math(ptr->parm, NULL, 0);
01226         }
01227                 
01228         if( op != NULL ) 
01229         {       
01230                 if     ( strcmp(op, "gt") == 0 ) res = (val1 > val2);
01231                 else if( strcmp(op, "lt") == 0 ) res = (val1 < val2);
01232                 else if( strcmp(op, "ge") == 0 ) res = (val1 >= val2);
01233                 else if( strcmp(op, "le") == 0 ) res = (val1 <= val2);
01234                 else if( strcmp(op, "eq") == 0 ) res = (val1 == val2);
01235                 else if( strcmp(op, "ne") == 0 ) res = (val1 != val2);
01236         }
01237 
01238         if( doc->tag[0] == 'u' ) /* <unless> */
01239                 res = !res ;
01240 
01241         ptr = NULL ;
01242         for (ptr = doc->child ; ptr ; ptr = ptr->next) 
01243         {
01244                 if( strcmp(ptr->tag, res?"then":"else" ) )
01245                 {
01246                         ptr = ptr->child ;
01247                         break;
01248                 }
01249                 if( res && ptr->next == NULL ) 
01250                         ptr = doc->child ;
01251         }
01252         
01253         while( ptr ) 
01254         {
01255                 imtmp = build_image_from_xml(state->asv, state->imman, state->fontman, ptr, NULL, state->flags, state->verbose, state->display_win);
01256                 if( im && imtmp ) safe_asimage_destroy( im ); 
01257                 if( imtmp ) im = imtmp ;
01258                  ptr = ptr->next ;
01259         }
01260         return im ;
01261 }
01262 
01263 /****** libAfterImage/asimagexml/gradient
01264  * NAME
01265  * gradient - render multipoint gradient.
01266  * SYNOPSIS
01267  * <gradient id="new_id" angle="degrees" 
01268  *           refid="refid" width="pixels" height="pixels"
01269  *           colors ="color1 color2 color3 [...]"
01270  *           offsets="fraction1 fraction2 fraction3 [...]"/>
01271  * ATTRIBUTES
01272  * id       Optional.  Image will be given this name for future reference.
01273  * refid    Optional.  An image ID defined with the "id" parameter for
01274  *          any previously created image.  If set, percentages in "width"
01275  *          and "height" will be derived from the width and height of the
01276  *          refid image.
01277  * width    Optional.  The result will have this width.
01278  * height   Optional.  The result will have this height.
01279  * colors   Required.  Whitespace-separated list of colors.  At least two
01280  *          colors are required.  Each color in this list will be visited
01281  *          in turn, at the intervals given by the offsets attribute.
01282  * offsets  Optional.  Whitespace-separated list of floating point values
01283  *          ranging from 0.0 to 1.0.  The colors from the colors attribute
01284  *          are given these offsets, and the final gradient is rendered
01285  *          from the combination of the two.  If both colors and offsets
01286  *          are given but the number of colors and offsets do not match,
01287  *          the minimum of the two will be used, and the other will be
01288  *          truncated to match.  If offsets are not given, a smooth
01289  *          stepping from 0.0 to 1.0 will be used.
01290  * angle    Optional.  Given in degrees.  Default is 0.  This is the
01291  *          direction of the gradient.  Currently the only supported
01292  *          values are 0, 45, 90, 135, 180, 225, 270, 315.  0 means left
01293  *          to right, 90 means top to bottom, etc.
01294  *****/
01295 static ASImage *
01296 handle_asxml_tag_gradient( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, int width, int height)
01297 {
01298         ASImage *result = NULL ;
01299         xml_elem_t* ptr ;
01300         double angle = 0;
01301         char* color_str = NULL;
01302         char* offset_str = NULL;
01303         LOCAL_DEBUG_OUT("doc = %p, parm = %p, width = %d, height = %d", doc, parm, width, height ); 
01304         for (ptr = parm ; ptr ; ptr = ptr->next) {
01305                 if (!strcmp(ptr->tag, "angle")) angle = strtod(ptr->parm, NULL);
01306                 else if (!strcmp(ptr->tag, "colors")) color_str = ptr->parm;
01307                 else if (!strcmp(ptr->tag, "offsets")) offset_str = ptr->parm;
01308         }
01309         if ( color_str) 
01310         {
01311                 ASGradient gradient;
01312                 int reverse = 0, npoints1 = 0, npoints2 = 0;
01313                 char* p;
01314                 angle = fmod(angle, 2 * PI);
01315                 if (angle > 2 * PI * 15 / 16 || angle < 2 * PI * 1 / 16) {
01316                         gradient.type = GRADIENT_Left2Right;
01317                 } else if (angle < 2 * PI * 3 / 16) {
01318                         gradient.type = GRADIENT_TopLeft2BottomRight;
01319                 } else if (angle < 2 * PI * 5 / 16) {
01320                         gradient.type = GRADIENT_Top2Bottom;
01321                 } else if (angle < 2 * PI * 7 / 16) {
01322                         gradient.type = GRADIENT_BottomLeft2TopRight; reverse = 1;
01323                 } else if (angle < 2 * PI * 9 / 16) {
01324                         gradient.type = GRADIENT_Left2Right; reverse = 1;
01325                 } else if (angle < 2 * PI * 11 / 16) {
01326                         gradient.type = GRADIENT_TopLeft2BottomRight; reverse = 1;
01327                 } else if (angle < 2 * PI * 13 / 16) {
01328                         gradient.type = GRADIENT_Top2Bottom; reverse = 1;
01329                 } else {
01330                         gradient.type = GRADIENT_BottomLeft2TopRight;
01331                 }
01332                 for (p = color_str ; isspace((int)*p) ; p++);
01333                 for (npoints1 = 0 ; *p ; npoints1++) {
01334                         if (*p) for ( ; *p && !isspace((int)*p) ; p++);
01335                         for ( ; isspace((int)*p) ; p++);
01336                 }
01337                 if (offset_str) {
01338                         for (p = offset_str ; isspace((int)*p) ; p++);
01339                         for (npoints2 = 0 ; *p ; npoints2++) {
01340                                 if (*p) for ( ; *p && !isspace((int)*p) ; p++);
01341                                 for ( ; isspace((int)*p) ; p++);
01342                         }
01343                 }
01344                 gradient.npoints = max( npoints1, npoints2 );
01345                 if (npoints1 > 1) {
01346                         int i;
01347                         gradient.color = safecalloc(gradient.npoints, sizeof(ARGB32));
01348                         gradient.offset = NEW_ARRAY(double, gradient.npoints);
01349                         for (p = color_str ; isspace((int)*p) ; p++);
01350                         for (npoints1 = 0 ; *p ; ) {
01351                                 char* pb = p, ch;
01352                                 if (*p) for ( ; *p && !isspace((int)*p) ; p++);
01353                                 for ( ; isspace((int)*p) ; p++);
01354                                 ch = *p; *p = '\0';
01355                                 if (parse_argb_color(pb, gradient.color + npoints1) != pb)
01356                                 {
01357                                         npoints1++;
01358                                 }else
01359                                         show_warning( "failed to parse color [%s] - defaulting to black", pb );
01360                                 *p = ch;
01361                         }
01362                         if (offset_str) {
01363                                 for (p = offset_str ; isspace((int)*p) ; p++);
01364                                 for (npoints2 = 0 ; *p ; ) {
01365                                         char* pb = p, ch;
01366                                         if (*p) for ( ; *p && !isspace((int)*p) ; p++);
01367                                         ch = *p; *p = '\0';
01368                                         gradient.offset[npoints2] = strtod(pb, &pb);
01369                                         if (pb == p) npoints2++;
01370                                         *p = ch;
01371                                         for ( ; isspace((int)*p) ; p++);
01372                                 }
01373                         } else {
01374                                 for (npoints2 = 0 ; npoints2 < gradient.npoints ; npoints2++)
01375                                         gradient.offset[npoints2] = (double)npoints2 / (gradient.npoints - 1);
01376                         }
01377                         if (reverse) {
01378                                 for (i = 0 ; i < gradient.npoints / 2 ; i++) {
01379                                         int i2 = gradient.npoints - 1 - i;
01380                                         ARGB32 c = gradient.color[i];
01381                                         double o = gradient.offset[i];
01382                                         gradient.color[i] = gradient.color[i2];
01383                                         gradient.color[i2] = c;
01384                                         gradient.offset[i] = gradient.offset[i2];
01385                                         gradient.offset[i2] = o;
01386                                 }
01387                                 for (i = 0 ; i < gradient.npoints ; i++) {
01388                                         gradient.offset[i] = 1.0 - gradient.offset[i];
01389                                 }
01390                         }
01391                         if (state->verbose > 1) {
01392                                 show_progress("Generating [%dx%d] gradient with angle [%f] and npoints [%d/%d].", width, height, angle, npoints1, npoints2);
01393                                 for (i = 0 ; i < gradient.npoints ; i++) {
01394                                         show_progress("  Point [%d] has color [#%08x] and offset [%f].", i, (unsigned int)gradient.color[i], gradient.offset[i]);
01395                                 }
01396                         }
01397                         result = make_gradient(state->asv, &gradient, width, height, SCL_DO_ALL, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
01398                         if( gradient.color ) 
01399                                 free( gradient.color );
01400                         if( gradient.offset )
01401                                 free( gradient.offset );
01402                 }
01403         }
01404         return result;
01405 }
01406 
01407 /****** libAfterImage/asimagexml/solid
01408  * NAME
01409  * solid - generate image of specified size and fill it with solid color.
01410  * SYNOPSIS
01411  * <solid id="new_id" color="color" opacity="opacity" 
01412  *      width="pixels" height="pixels"
01413  *      refid="refid" width="pixels" height="pixels"/>
01414  * 
01415  * ATTRIBUTES
01416  * id       Optional. Image will be given this name for future reference.
01417  * width    Optional.  The result will have this width.
01418  * height   Optional.  The result will have this height.
01419  * refid    Optional.  An image ID defined with the "id" parameter for
01420  *          any previously created image.  If set, percentages in "width"
01421  *          and "height" will be derived from the width and height of the
01422  *          refid image.
01423  * color    Optional.  Default is "#ffffffff".  An image will be created
01424  *          and filled with this color.
01425  * width    Required.  The image will have this width.
01426  * height   Required.  The image will have this height.
01427  * opacity  Optional. Default is 100. Values from 0 to 100 represent the
01428  *          opacity of resulting image with 100 being completely opaque.
01429  *                  Effectively overrides alpha component of the color setting.
01430  ******/
01431 static ASImage *
01432 handle_asxml_tag_solid( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, int width, int height)
01433 {
01434         ASImage *result = NULL ;
01435         xml_elem_t* ptr;
01436         Bool opacity_set = False ;
01437         int opacity = 100 ;
01438         ARGB32 color = ARGB32_White;
01439         CARD32 a, r, g, b ;
01440         LOCAL_DEBUG_OUT("doc = %p, parm = %p, width = %d, height = %d", doc, parm, width, height ); 
01441         for (ptr = parm ; ptr ; ptr = ptr->next) {
01442                 if (!strcmp(ptr->tag, "color")) parse_argb_color(ptr->parm, &color);
01443                 else if (!strcmp(ptr->tag, "opacity")) { opacity = atol(ptr->parm); opacity_set = True ; }
01444         }
01445         if( state->verbose > 1 )
01446                 show_progress("Creating solid color [#%08x] image [%dx%d].", (unsigned int)color, width, height);
01447         result = create_asimage(width, height, ASIMAGE_QUALITY_TOP);
01448         if( opacity < 0 ) opacity = 0 ;
01449         else if( opacity > 100 )  opacity = 100 ;
01450         a = opacity_set? (0x000000FF * (CARD32)opacity)/100: ARGB32_ALPHA8(color);
01451         r = ARGB32_RED8(color);
01452         g = ARGB32_GREEN8(color);
01453         b = ARGB32_BLUE8(color);
01454         color = MAKE_ARGB32(a,r,g,b);
01455         if (result) 
01456                 fill_asimage(state->asv, result, 0, 0, width, height, color);
01457 
01458         return result;
01459 }
01460 
01461 
01462 
01463 /****** libAfterImage/asimagexml/save
01464  * NAME
01465  * save - write generated/loaded image into the file of one of the
01466  *        supported types
01467  * SYNOPSIS
01468  * <save id="new_id" dst="filename" format="format" compress="value"
01469  *       opacity="value" replace="0|1" delay="mlsecs">
01470  * ATTRIBUTES
01471  * id       Optional.  Image will be given this name for future reference.
01472  * dst      Optional.  Name of file image will be saved to. If omitted
01473  *          image will be dumped into stdout - usefull for CGI apps.
01474  * format   Optional.  Ouput format of saved image.  Defaults to the
01475  *          extension of the "dst" parameter.  Valid values are the
01476  *          standard AS image file formats: xpm, jpg, png, gif, tiff.
01477  * compress Optional.  Compression level if supported by output file
01478  *          format. Valid values are in range of 0 - 100 and any of
01479  *          "deflate", "jpeg", "ojpeg", "packbits" for TIFF files.
01480  *          Note that JPEG and GIF will produce images with deteriorated
01481  *          quality when compress is greater then 0. For JPEG default is
01482  *          25, for PNG default is 6 and for GIF it is 0.
01483  * opacity  Optional. Level below which pixel is considered to be
01484  *          transparent, while saving image as XPM or GIF. Valid values
01485  *          are in range 0-255. Default is 127.
01486  * replace  Optional. Causes ascompose to delete file if the file with the
01487  *          same name already exists. Valid values are 0 and 1. Default
01488  *          is 1 - files are deleted before being saved. Disable this to
01489  *          get multimage animated gifs.
01490  * delay    Optional. Delay to be stored in GIF image. This could be used
01491  *          to create animated gifs. Note that you have to set replace="0"
01492  *          and then write several images into the GIF file with the same
01493  *          name.
01494  * NOTES
01495  * This tag applies to the first image contained within the tag.  Any
01496  * further images will be discarded.
01497  *******/
01498 static ASImage *
01499 handle_asxml_tag_save( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp)
01500 {
01501         ASImage *result = NULL ;
01502         xml_elem_t* ptr ;
01503         const char* dst = NULL;
01504         const char* ext = NULL;
01505         const char* compress = NULL ;
01506         const char* opacity = NULL ;
01507         int delay = 0 ;
01508         int replace = 1;
01509         /*<save id="" dst="" format="" compression="" delay="" replace="" opacity=""> */
01510         int autoext = 0;
01511         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p", doc, parm, imtmp ); 
01512         for (ptr = parm ; ptr ; ptr = ptr->next) {
01513                 if (!strcmp(ptr->tag, "dst")) dst = ptr->parm;
01514                 else if (!strcmp(ptr->tag, "format")) ext = ptr->parm;
01515                 else if (!strncmp(ptr->tag, "compress", 8)) compress = ptr->parm;
01516                 else if (!strcmp(ptr->tag, "opacity")) opacity = ptr->parm;
01517                 else if (!strcmp(ptr->tag, "delay"))   delay = atoi(ptr->parm);
01518                 else if (!strcmp(ptr->tag, "replace")) replace = atoi(ptr->parm);
01519         }
01520         if (dst && !ext) {
01521                 ext = strrchr(dst, '.');
01522                 if (ext) ext++;
01523                 autoext = 1;
01524         }
01525         
01526         result = imtmp;
01527         
01528         if ( autoext && ext )
01529                 show_warning("No format given.  File extension [%s] used as format.", ext);
01530         if( state->verbose > 1 )
01531                 show_progress("reSaving image to file [%s].", dst?dst:"stdout");
01532         if (result && get_flags( state->flags, ASIM_XML_ENABLE_SAVE) )
01533         {
01534                 if( state->verbose > 1 )
01535                         show_progress("Saving image to file [%s].", dst?dst:"stdout");
01536                 if( !save_asimage_to_file(dst, result, ext, compress, opacity, delay, replace))
01537                         show_error("Unable to save image into file [%s].", dst?dst:"stdout");
01538         }
01539 
01540         return result;
01541 }
01542 
01543 /****** libAfterImage/asimagexml/background
01544  * NAME
01545  * background - set image's background color.
01546  * SYNOPSIS
01547  *  <background id="new_id" color="color">
01548  * ATTRIBUTES
01549  * id       Optional. Image will be given this name for future reference.
01550  * color    Required. Color to be used for background - fills all the
01551  *          spaces in image with missing pixels.
01552  * NOTES
01553  * This tag applies to the first image contained within the tag.  Any
01554  * further images will be discarded.
01555  ******/
01556 static ASImage *
01557 handle_asxml_tag_background( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp)
01558 {
01559         ASImage *result = NULL ;
01560         xml_elem_t* ptr ;
01561         ARGB32 argb = ARGB32_Black;
01562         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p", doc, parm, imtmp ); 
01563         for (ptr = parm ; ptr ; ptr = ptr->next) {
01564                 if (!strcmp(ptr->tag, "color")) parse_argb_color( ptr->parm, &argb );
01565         }
01566         if (imtmp) {
01567                 result = clone_asimage( imtmp, SCL_DO_ALL );
01568                 result->back_color = argb ;
01569         }
01570         if( state->verbose > 1 )
01571                 show_progress( "Setting back_color for image %p to 0x%8.8X", result, argb );
01572         return result;
01573 }
01574 
01575 /****** libAfterImage/asimagexml/blur
01576  * NAME
01577  * blur - perform a gaussian blurr on an image.
01578  * SYNOPSIS
01579  * <blur id="new_id" horz="radius" vert="radius" channels="argb">
01580  * ATTRIBUTES
01581  * id       Optional. Image will be given this name for future reference.
01582  * horz     Optional. Horizontal radius of the blur in pixels.
01583  * vert     Optional. Vertical radius of the blur in pixels.
01584  * channels Optional. Applys blur only on listed color channels:
01585  *                       a - alpha,
01586  *                       r - red,
01587  *                       g - green,
01588  *                       b - blue
01589  * NOTES
01590  * This tag applies to the first image contained within the tag.  Any
01591  * further images will be discarded.
01592  ******/
01593 static ASImage *
01594 handle_asxml_tag_blur( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp)
01595 {
01596         ASImage *result = NULL ;
01597         xml_elem_t* ptr ;
01598         int horz = 0, vert = 0;
01599     int filter = SCL_DO_ALL;
01600         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p", doc, parm, imtmp ); 
01601         for (ptr = parm ; ptr ; ptr = ptr->next) 
01602         {
01603                 if (!strcmp(ptr->tag, "horz")) horz = atoi(ptr->parm);
01604         else if (!strcmp(ptr->tag, "vert")) vert = atoi(ptr->parm);
01605         else if (!strcmp(ptr->tag, "channels"))
01606         {
01607             int i = 0 ;
01608             char *str = &(ptr->parm[0]) ;
01609             filter = 0 ;
01610             while( str[i] != '\0' )
01611             {
01612                 if( str[i] == 'a' )
01613                     filter |= SCL_DO_ALPHA ;
01614                 else if( str[i] == 'r' )
01615                     filter |= SCL_DO_RED ;
01616                 else if( str[i] == 'g' )
01617                     filter |= SCL_DO_GREEN ;
01618                 else if( str[i] == 'b' )
01619                     filter |= SCL_DO_BLUE ;
01620                 ++i ;
01621             }
01622         }
01623         }
01624     result = blur_asimage_gauss(state->asv, imtmp, horz, vert, filter, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
01625         if( state->verbose > 1 )        
01626                 show_progress("Blurrer image with radii %d, %d.", horz, vert);
01627         return result;
01628 }
01629 
01630 
01631 
01632 /****** libAfterImage/asimagexml/bevel
01633  * NAME
01634  * bevel - draws solid bevel frame around the image.
01635  * SYNOPSIS
01636  * <bevel id="new_id" colors="color1 color2" 
01637  *                width="pixels" height="pixels" refid="refid"
01638  *        border="left top right bottom" solid=0|1 outline=0|1>
01639  * ATTRIBUTES
01640  * id       Optional.  Image will be given this name for future reference.
01641  * colors   Optional.  Whitespace-separated list of colors.  Exactly two
01642  *          colors are required.  Default is "#ffdddddd #ff555555".  The
01643  *          first color is the color of the upper and left edges, and the
01644  *          second is the color of the lower and right edges.
01645  * borders  Optional.  Whitespace-separated list of integer values.
01646  *          Default is "10 10 10 10".  The values represent the offsets
01647  *          toward the center of the image of each border: left, top,
01648  *          right, bottom.
01649  * solid    Optional - default is 1. If set to 0 will draw bevel gradually
01650  *          fading into the image.
01651  * outline  Optional - default is 0. If set to 1 will draw bevel around the 
01652  *                      image vs. inside the image.
01653  * width    Optional. The result will have this width.
01654  * height   Optional. The result will have this height.
01655  * refid    Optional.  An image ID defined with the "id" parameter for
01656  *          any previously created image.  If set, percentages in "width"
01657  *          and "height" will be derived from the width and height of the
01658  *          refid image.
01659  * NOTES
01660  * This tag applies to the first image contained within the tag.  Any
01661  * further images will be discarded.
01662  ******/
01663 static ASImage *
01664 handle_asxml_tag_bevel( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01665 {
01666         ASImage *result = NULL ;
01667         xml_elem_t* ptr ;
01668         char* color_str = NULL;
01669         char* border_str = NULL;
01670         int solid = 1, outline = 0 ;
01671         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01672         for (ptr = parm ; ptr ; ptr = ptr->next) {
01673                 if (!strcmp(ptr->tag, "colors")) color_str = ptr->parm;
01674                 else if (!strcmp(ptr->tag, "border")) border_str = ptr->parm;
01675                 else if (!strcmp(ptr->tag, "solid")) solid = atoi(ptr->parm);
01676                 else if (!strcmp(ptr->tag, "outline")) outline = atoi(ptr->parm);
01677         }
01678         if (imtmp) 
01679         {
01680                 ASImageBevel bevel;
01681                 ASImageLayer layer;
01682                 memset( &bevel, 0x00, sizeof(ASImageBevel) );
01683                 if( solid )
01684                         bevel.type = BEVEL_SOLID_INLINE;
01685                 bevel.hi_color = 0xffdddddd;
01686                 bevel.lo_color = 0xff555555;
01687                 if( outline ) 
01688                         bevel.top_outline = bevel.left_outline = bevel.right_outline = bevel.bottom_outline = 10;
01689                 else
01690                         bevel.top_inline = bevel.left_inline = bevel.right_inline = bevel.bottom_inline = 10;
01691                 if (color_str) {
01692                         char* p = color_str;
01693                         while (isspace((int)*p)) p++;
01694                         p = (char*)parse_argb_color(p, &bevel.hi_color);
01695                         while (isspace((int)*p)) p++;
01696                         parse_argb_color(p, &bevel.lo_color);
01697                 }
01698                 if (border_str) {
01699                         char* p = (char*)border_str;
01700                         if( outline )
01701                         {
01702                                 bevel.left_outline = (unsigned short)parse_math(p, &p, width);
01703                                 bevel.top_outline = (unsigned short)parse_math(p, &p, height);
01704                                 bevel.right_outline = (unsigned short)parse_math(p, &p, width);
01705                                 bevel.bottom_outline = (unsigned short)parse_math(p, &p, height);
01706                         }else
01707                         {                         
01708                                 bevel.left_inline = (unsigned short)parse_math(p, &p, width);
01709                                 bevel.top_inline = (unsigned short)parse_math(p, &p, height);
01710                                 bevel.right_inline = (unsigned short)parse_math(p, &p, width);
01711                                 bevel.bottom_inline = (unsigned short)parse_math(p, &p, height);
01712                         }
01713                 }
01714                 bevel.hihi_color = bevel.hi_color;
01715                 bevel.hilo_color = bevel.hi_color;
01716                 bevel.lolo_color = bevel.lo_color;
01717                 if( state->verbose > 1 )
01718                         show_progress("Generating bevel with offsets [%d %d %d %d] and colors [#%08x #%08x].", bevel.left_inline, bevel.top_inline, bevel.right_inline, bevel.bottom_inline, (unsigned int)bevel.hi_color, (unsigned int)bevel.lo_color);
01719                 init_image_layers( &layer, 1 );
01720                 layer.im = imtmp;
01721                 if( width <= bevel.left_outline+bevel.right_outline )
01722                         layer.clip_width = 1;
01723                 else
01724                         layer.clip_width = width-(bevel.left_outline+bevel.right_outline);
01725                 if( height <= bevel.top_outline+bevel.bottom_outline )
01726                         layer.clip_height = 1;
01727                 else
01728                         layer.clip_height = height-(bevel.top_outline+bevel.bottom_outline);
01729                 layer.bevel = &bevel;
01730                 result = merge_layers(state->asv, &layer, 1, 
01731                                                           width, height, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
01732         }
01733         return result;
01734 }
01735 
01736 /****** libAfterImage/asimagexml/mirror
01737  * NAME
01738  * mirror - create new image as mirror copy of an old one.
01739  * SYNOPSIS
01740  *  <mirror id="new_id" dir="direction" 
01741  *                      width="pixels" height="pixels" refid="refid">
01742  * ATTRIBUTES
01743  * id       Optional. Image will be given this name for future reference.
01744  * dir      Required. Possible values are "vertical" and "horizontal".
01745  *          The image will be flipped over the x-axis if dir is vertical,
01746  *          and flipped over the y-axis if dir is horizontal.
01747  * width    Optional.  The result will have this width.
01748  * height   Optional.  The result will have this height.
01749  * refid    Optional.  An image ID defined with the "id" parameter for
01750  *          any previously created image.  If set, percentages in "width"
01751  *          and "height" will be derived from the width and height of the
01752  *          refid image.
01753  * NOTES
01754  * This tag applies to the first image contained within the tag.  Any
01755  * further images will be discarded.
01756  ******/
01757 static ASImage *
01758 handle_asxml_tag_mirror( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01759 {
01760         ASImage *result = NULL ;
01761         xml_elem_t* ptr ;
01762         int dir = 0;
01763         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01764         for (ptr = parm ; ptr ; ptr = ptr->next) {
01765                 if (!strcmp(ptr->tag, "dir")) dir = !mystrcasecmp(ptr->parm, "vertical");
01766         }
01767         result = mirror_asimage(state->asv, imtmp, 0, 0, width, height, dir,
01768                                                         ASA_ASImage, 
01769                                                         0, ASIMAGE_QUALITY_DEFAULT);
01770         if( state->verbose > 1 )
01771                 show_progress("Mirroring image [%sally].", dir ? "horizont" : "vertic");
01772         return result;
01773 }
01774 
01775 /****** libAfterImage/asimagexml/rotate
01776  * NAME
01777  * rotate - rotate an image in 90 degree increments (flip).
01778  * SYNOPSIS
01779  *  <rotate id="new_id" angle="degrees"
01780  *                      width="pixels" height="pixels" refid="refid">
01781   * ATTRIBUTES
01782  * id       Optional. Image will be given this name for future reference.
01783  * angle    Required.  Given in degrees.  Possible values are currently
01784  *          "90", "180", and "270".  Rotates the image through the given
01785  *          angle.
01786  * width    Optional.  The result will have this width.
01787  * height   Optional.  The result will have this height.
01788  * refid    Optional.  An image ID defined with the "id" parameter for
01789  *          any previously created image.  If set, percentages in "width"
01790  *          and "height" will be derived from the width and height of the
01791  *          refid image.
01792  * NOTES
01793  * This tag applies to the first image contained within the tag.  Any
01794  * further images will be discarded.
01795  ******/
01796 static ASImage *
01797 handle_asxml_tag_rotate( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01798 {
01799         ASImage *result = NULL ;
01800         xml_elem_t* ptr ;
01801         double angle = 0;
01802         int dir = 0;
01803         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01804         for (ptr = parm ; ptr ; ptr = ptr->next) 
01805                 if (!strcmp(ptr->tag, "angle")) angle = strtod(ptr->parm, NULL);
01806         
01807         angle = fmod(angle, 2 * PI);
01808         if (angle > 2 * PI * 7 / 8 || angle < 2 * PI * 1 / 8)
01809                 dir = 0;
01810         else if (angle < 2 * PI * 3 / 8)
01811                 dir = FLIP_VERTICAL;
01812         else if (angle < 2 * PI * 5 / 8)
01813                 dir = FLIP_UPSIDEDOWN;
01814         else 
01815                 dir = FLIP_VERTICAL | FLIP_UPSIDEDOWN;
01816         if (dir) 
01817         {
01818                 if( get_flags(dir, FLIP_VERTICAL))
01819                 {
01820                         int tmp = width ;
01821                         width = height ;
01822                         height = tmp ;  
01823                 }        
01824                 result = flip_asimage(state->asv, imtmp, 0, 0, width, height, dir, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
01825                 if( state->verbose > 1 )
01826                         show_progress("Rotating image [%f degrees].", angle);
01827         } else 
01828                 result = imtmp;
01829 
01830         return result;
01831 }
01832 
01833 /****** libAfterImage/asimagexml/scale
01834  * NAME
01835  * scale - scale image to arbitrary size
01836  * SYNOPSIS
01837  * <scale id="new_id" refid="other_imag" src_x="pixels"  src_y="pixels" 
01838  *        src_width="pixels" src_height="pixels" 
01839  *        width="pixels" height="pixels">
01840  * ATTRIBUTES
01841  * id       Optional. Image will be given this name for future reference.
01842  * refid    Optional.  An image ID defined with the "id" parameter for
01843  *          any previously created image.  If set, percentages in "width"
01844  *          and "height" will be derived from the width and height of the
01845  *          refid image.
01846  * width    Required.  The image will be scaled to this width.
01847  * height   Required.  The image will be scaled to this height.
01848  * src_x   Optional. Default is 0. X Offset on infinite surface tiled
01849  *          with this image, from which to cut portion of an image to be
01850  *          used in scaling.
01851  * src_y   Optional. Default is 0. Y Offset on infinite surface tiled
01852  *          with this image, from which to cut portion of an image to be
01853  *          used in scaling.
01854  * src_width
01855  *          Optional. Default is image width. Tile image to this width
01856  *          prior to scaling.
01857  * src_height
01858  *          Optional. Default is image height. Tile image to this height
01859  *          prior to scaling.
01860   * NOTES
01861  * This tag applies to the first image contained within the tag.  Any
01862  * further images will be discarded.
01863  * If you want to keep image proportions while scaling - use "proportional"
01864  * instead of specific size for particular dimention.
01865  ******/
01866 static ASImage *
01867 handle_asxml_tag_scale( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01868 {
01869         ASImage *result = NULL ;
01870         xml_elem_t* ptr;
01871         int src_x = 0, src_y = 0 ;
01872         int src_width = 0, src_height = 0 ;
01873         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01874         for (ptr = parm ; ptr ; ptr = ptr->next) 
01875         {
01876                 if (!strcmp(ptr->tag, "src_x"))                 src_x = (int)parse_math(ptr->parm, NULL, width);
01877                 else if (!strcmp(ptr->tag, "src_y"))    src_y = (int)parse_math(ptr->parm, NULL, width);
01878                 else if (!strcmp(ptr->tag, "src_width"))        src_width = (int)parse_math(ptr->parm, NULL, width);
01879                 else if (!strcmp(ptr->tag, "src_height"))       src_height = (int)parse_math(ptr->parm, NULL, width);
01880         }       
01881         if( state->verbose > 1 )
01882                 show_progress("Scaling image to [%dx%d].", width, height);
01883         result = scale_asimage2( state->asv, imtmp, 
01884                                                         src_x, src_y, src_width, src_height,
01885                                                         width, height, 
01886                                                         ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
01887         return result;
01888 }
01889 /****** libAfterImage/asimagexml/slice
01890  * NAME
01891  * slice - slice image to arbitrary size leaving corners unchanged
01892  * SYNOPSIS
01893  * <slice id="new_id" ref_id="other_imag" width="pixels" height="pixels"
01894  *        x_start="slice_x_start" x_end="slice_x_end"
01895  *                y_start="slice_y_start" y_end="slice_y_end"
01896  *                scale="0|1">
01897  * ATTRIBUTES
01898  * id       Optional. Image will be given this name for future reference.
01899  * refid    Optional.  An image ID defined with the "id" parameter for
01900  *          any previously created image.  If set, percentages in "width"
01901  *          and "height" will be derived from the width and height of the
01902  *          refid image.
01903  * width    Required.  The image will be scaled to this width.
01904  * height   Required.  The image will be scaled to this height.
01905  * x_start  Optional. Position at which vertical image slicing begins. 
01906  *                      Corresponds to the right side of the left corners.
01907  * x_end    Optional. Position at which vertical image slicing end.
01908  *                      Corresponds to the left side of the right corners.
01909  * y_start  Optional. Position at which horisontal image slicing begins. 
01910  *          Corresponds to the bottom side of the top corners.
01911  * y_end    Optional. Position at which horisontal image slicing end.
01912  *                      Corresponds to the top side of the bottom corners.
01913  * scale    Optional. If set to 1 will cause middle portion of the 
01914  *                      image to be scaled instead of tiled.
01915  * NOTES
01916  * This tag applies to the first image contained within the tag.  Any
01917  * further images will be discarded.
01918  * Contents of the image between x_start and x_end will be tiled 
01919  * horizontally. Contents of the image between y_start and y_end will be 
01920  * tiled vertically. This is usefull to get background images to fit the 
01921  * size of the text or a widget, while preserving its borders undistorted, 
01922  * which is the usuall result of simple scaling.
01923  * If you want to keep image proportions while resizing-use "proportional"
01924  * instead of specific size for particular dimention.
01925  ******/
01926 static ASImage *
01927 handle_asxml_tag_slice( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01928 {
01929         ASImage *result = NULL ;
01930         xml_elem_t* ptr;
01931         int x_start = 0, x_end = 0 ;
01932         int y_start = 0, y_end = 0 ;
01933         Bool scale = False ;
01934         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01935         for (ptr = parm ; ptr ; ptr = ptr->next) 
01936         {
01937                 if (!strcmp(ptr->tag, "x_start"))               x_start = (int)parse_math(ptr->parm, NULL, width);
01938                 else if (!strcmp(ptr->tag, "x_end"))    x_end = (int)parse_math(ptr->parm, NULL, width);
01939                 else if (!strcmp(ptr->tag, "y_start"))  y_start = (int)parse_math(ptr->parm, NULL, height);
01940                 else if (!strcmp(ptr->tag, "y_end"))    y_end = (int)parse_math(ptr->parm, NULL, height);
01941                 else if (!strcmp(ptr->tag, "scale"))    scale = (ptr->parm[0] == '1');
01942         }
01943 
01944         if( state->verbose > 1 )
01945                 show_progress("Slicing image to [%dx%d].", width, height);
01946         result = slice_asimage2( state->asv, imtmp, x_start, x_end, y_start, y_end, width, height, 
01947                                                          scale, ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
01948         return result;
01949 }
01950 
01951 /****** libAfterImage/asimagexml/pixelize
01952  * NAME
01953  * pixelize - pixelize image using arbitrary pixel size
01954  * SYNOPSIS
01955  * <pixelize id="new_id" ref_id="other_imag" width="pixels" height="pixels"
01956  *        clip_x="clip_x" clip_y="clip_y"
01957  *        pixel_width="pixel_width" pixel_height="pixel_height">
01958  * ATTRIBUTES
01959  * id       Optional. Image will be given this name for future reference.
01960  * refid    Optional.  An image ID defined with the "id" parameter for
01961  *          any previously created image.  If set, percentages in "width"
01962  *          and "height" will be derived from the width and height of the
01963  *          refid image.
01964  * width    Required.  The image will be scaled to this width.
01965  * height   Required.  The image will be scaled to this height.
01966  * clip_x   Optional. Offset into original image.
01967  * clip_y   Optional. Offset into original image.
01968  * pixel_width Required. Horizontal pixelization step;
01969  * pixel_height Required. Vertical pixelization step;
01970  * NOTES
01971  * This tag applies to the first image contained within the tag.  Any
01972  * further images will be discarded.
01973  * If you want to keep image proportions while resizing-use "proportional"
01974  * instead of specific size for particular dimention.
01975  ******/
01976 static ASImage *
01977 handle_asxml_tag_pixelize( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
01978 {
01979         ASImage *result = NULL ;
01980         xml_elem_t* ptr;
01981         int clip_x = 0, clip_y = 0 ;
01982         int pixel_width = 1, pixel_height = 1 ;
01983         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
01984         for (ptr = parm ; ptr ; ptr = ptr->next) 
01985         {
01986                 if (!strcmp(ptr->tag, "clip_x"))                clip_x = (int)parse_math(ptr->parm, NULL, width);
01987                 else if (!strcmp(ptr->tag, "clip_y"))   clip_y = (int)parse_math(ptr->parm, NULL, height);
01988                 else if (!strcmp(ptr->tag, "pixel_width"))              pixel_width = (int)parse_math(ptr->parm, NULL, width);
01989                 else if (!strcmp(ptr->tag, "pixel_height"))     pixel_height = (int)parse_math(ptr->parm, NULL, height);
01990         }
01991 
01992         if( state->verbose > 1 )
01993                 show_progress("Pixelizing image to [%dx%d] using pixel size %dx%d.", 
01994                                                 width, height, pixel_width, pixel_height);
01995         result = pixelize_asimage (state->asv, imtmp, clip_x, clip_y, width, height,
01996                                                            pixel_width, pixel_height,
01997                                                            ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
01998         return result;
01999 }
02000 
02001 /****** libAfterImage/asimagexml/color2alpha
02002  * NAME
02003  * color2alpha - set alpha channel based on color closeness to specified color
02004  * SYNOPSIS
02005  * <color2alpha id="new_id" ref_id="other_imag" width="pixels" height="pixels"
02006  *        clip_x="clip_x" clip_y="clip_y"
02007  *        color="color">
02008  * ATTRIBUTES
02009  * id       Optional. Image will be given this name for future reference.
02010  * refid    Optional.  An image ID defined with the "id" parameter for
02011  *          any previously created image.  If set, percentages in "width"
02012  *          and "height" will be derived from the width and height of the
02013  *          refid image.
02014  * width    Required.  The image will be scaled to this width.
02015  * height   Required.  The image will be scaled to this height.
02016  * clip_x   Optional. Offset into original image.
02017  * clip_y   Optional. Offset into original image.
02018  * color    Required. Color to match against.
02019  * NOTES
02020  * This tag applies to the first image contained within the tag.  Any
02021  * further images will be discarded.
02022  * If you want to keep image proportions while resizing-use "proportional"
02023  * instead of specific size for particular dimention.
02024  ******/
02025 static ASImage *
02026 handle_asxml_tag_color2alpha( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
02027 {
02028         ASImage *result = NULL ;
02029         xml_elem_t* ptr;
02030         int clip_x = 0, clip_y = 0 ;
02031         ARGB32 color;
02032         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
02033         for (ptr = parm ; ptr ; ptr = ptr->next) 
02034         {
02035                 if (!strcmp(ptr->tag, "clip_x"))                clip_x = (int)parse_math(ptr->parm, NULL, width);
02036                 else if (!strcmp(ptr->tag, "clip_y"))   clip_y = (int)parse_math(ptr->parm, NULL, height);
02037                 else if (!strcmp(ptr->tag, "color"))    parse_argb_color(ptr->parm, &color);
02038         }
02039 
02040         if( state->verbose > 1 )
02041                 show_progress("color2alpha image to [%dx%d] using color #%8.8X.", width, height, color);
02042         result = color2alpha_asimage (state->asv, imtmp, clip_x, clip_y, width, height,
02043                                                                         color,
02044                                                                         ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
02045         return result;
02046 }
02047 
02048 /****** libAfterImage/asimagexml/crop
02049  * NAME
02050  * crop - crop image to arbitrary area within it.
02051  * SYNOPSIS
02052  *  <crop id="new_id" refid="other_image" srcx="pixels" srcy="pixels"
02053  *        width="pixels" height="pixels" tint="color">
02054  * ATTRIBUTES
02055  * id       Optional. Image will be given this name for future reference.
02056  * refid    Optional. An image ID defined with the "id" parameter for
02057  *          any previously created image.  If set, percentages in "width"
02058  *          and "height" will be derived from the width and height of the
02059  *          refid image.
02060  * srcx     Optional. Default is "0". Skip this many pixels from the left.
02061  * srcy     Optional. Default is "0". Skip this many pixels from the top.
02062  * width    Optional. Default is "100%".  Keep this many pixels wide.
02063  * height   Optional. Default is "100%".  Keep this many pixels tall.
02064  * tint     Optional. Additionally tint an image to specified color.
02065  *          Tinting can both lighten and darken an image. Tinting color
02066  *          0 or #7f7f7f7f yeilds no tinting. Tinting can be performed on
02067  *          any channel, including alpha channel.
02068  * NOTES
02069  * This tag applies to the first image contained within the tag.  Any
02070  * further images will be discarded.
02071  ******/
02072 static ASImage *
02073 handle_asxml_tag_crop( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
02074 {
02075         ASImage *result = NULL ;
02076         xml_elem_t* ptr;
02077         ARGB32 tint = 0 ;
02078         int srcx = 0, srcy = 0;
02079         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
02080         for (ptr = parm ; ptr ; ptr = ptr->next) {
02081                 if (!strcmp(ptr->tag, "srcx")) srcx = (int)parse_math(ptr->parm, NULL, width);
02082                 else if (!strcmp(ptr->tag, "srcy")) srcy = (int)parse_math(ptr->parm, NULL, height);
02083                 else if (!strcmp(ptr->tag, "tint")) parse_argb_color(ptr->parm, &tint);
02084         }
02085         if( state->verbose > 1 )
02086                 show_progress("Cropping image to [%dx%d].", width, height);
02087         result = tile_asimage(state->asv, imtmp, srcx, srcy, width, height, tint, ASA_ASImage, 100, ASIMAGE_QUALITY_TOP);
02088         return result;
02089 }
02090 
02091 /****** libAfterImage/asimagexml/tile
02092  * NAME
02093  * tile - tile an image to specified area.
02094  * SYNOPSIS
02095  *  <tile id="new_id" refid="other_image" width="pixels" height="pixels"
02096  *        x_origin="pixels" y_origin="pixels" tint="color" complement=0|1>
02097  * ATTRIBUTES
02098  * id       Optional. Image will be given this name for future reference.
02099  * refid    Optional. An image ID defined with the "id" parameter for
02100  *          any previously created image.  If set, percentages in "width"
02101  *          and "height" will be derived from the width and height of the
02102  *          refid image.
02103  * width    Optional. Default is "100%". The image will be tiled to this
02104  *          width.
02105  * height   Optional. Default is "100%". The image will be tiled to this
02106  *          height.
02107  * x_origin Optional. Horizontal position on infinite surface, covered
02108  *          with tiles of the image, from which to cut out resulting
02109  *          image.
02110  * y_origin Optional. Vertical position on infinite surface, covered
02111  *          with tiles of the image, from which to cut out resulting
02112  *          image.
02113  * tint     Optional. Additionally tint an image to specified color.
02114  *          Tinting can both lighten and darken an image. Tinting color
02115  *          0 or #7f7f7f7f yields no tinting. Tinting can be performed
02116  *          on any channel, including alpha channel.
02117  * complement Optional. Will use color that is the complement to tint color
02118  *          for the tinting, if set to 1. Default is 0.
02119  *
02120  * NOTES
02121  * This tag applies to the first image contained within the tag.  Any
02122  * further images will be discarded.
02123  ******/
02124 static ASImage *
02125 handle_asxml_tag_tile( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
02126 {
02127         ASImage *result = NULL ;
02128         xml_elem_t* ptr;
02129         int xorig = 0, yorig = 0;
02130         ARGB32 tint = 0 ;
02131         char *complement_str = NULL ;
02132         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
02133         for (ptr = parm ; ptr ; ptr = ptr->next) {
02134                 if (!strcmp(ptr->tag, "x_origin")) xorig = (int)parse_math(ptr->parm, NULL, width);
02135                 else if (!strcmp(ptr->tag, "y_origin")) yorig = (int)parse_math(ptr->parm, NULL, height);
02136                 else if (!strcmp(ptr->tag, "tint")) parse_argb_color(ptr->parm, &tint);
02137                 else if (!strcmp(ptr->tag, "complement")) complement_str = ptr->parm;
02138         }
02139         if( complement_str )
02140         {
02141                 register char *ptr = complement_str ;
02142                 CARD32 a = ARGB32_ALPHA8(tint),
02143                                 r = ARGB32_RED8(tint),
02144                                 g = ARGB32_GREEN8(tint),
02145                                 b = ARGB32_BLUE8(tint) ;
02146                 while( *ptr )
02147                 {
02148                         if( *ptr == 'a' )               a = ~a ;
02149                         else if( *ptr == 'r' )  r = ~r ;
02150                         else if( *ptr == 'g' )  g = ~g ;
02151                         else if( *ptr == 'b' )  b = ~b ;
02152                         ++ptr ;
02153                 }
02154 
02155                 tint = MAKE_ARGB32(a, r, g, b );
02156         }
02157         if( state->verbose > 1 )
02158                 show_progress("Tiling image to [%dx%d].", width, height);
02159         result = tile_asimage(state->asv, imtmp, xorig, yorig, width, height, tint, ASA_ASImage, 100, ASIMAGE_QUALITY_TOP);
02160         return result;
02161 }
02162 
02163 /****** libAfterImage/asimagexml/hsv
02164  * NAME
02165  * hsv - adjust Hue, Saturation and/or Value of an image and optionally
02166  * tile an image to arbitrary area.
02167  * SYNOPSIS
02168  * <hsv id="new_id" refid="other_image"
02169  *      x_origin="pixels" y_origin="pixels" width="pixels" height="pixels"
02170  *      affected_hue="degrees|color" affected_radius="degrees"
02171  *      hue_offset="degrees" saturation_offset="value"
02172  *      value_offset="value">
02173  * ATTRIBUTES
02174  * id       Optional. Image will be given this name for future reference.
02175  * refid    Optional. An image ID defined with the "id" parameter for
02176  *          any previously created image.  If set, percentages in "width"
02177  *          and "height" will be derived from the width and height of the
02178  *          refid image.
02179  * width    Optional. Default is "100%". The image will be tiled to this
02180  *          width.
02181  * height   Optional. Default is "100%". The image will be tiled to this
02182  *          height.
02183  * x_origin Optional. Horizontal position on infinite surface, covered
02184  *          with tiles of the image, from which to cut out resulting
02185  *          image.
02186  * y_origin Optional. Vertical position on infinite surface, covered
02187  *          with tiles of the image, from which to cut out resulting
02188  *          image.
02189  * affected_hue    Optional. Limits effects to the renage of hues around
02190  *          this hue. If numeric value is specified - it is treated as
02191  *          degrees on 360 degree circle, with :
02192  *              red = 0,
02193  *              yellow = 60,
02194  *              green = 120,
02195  *              cyan = 180,
02196  *              blue = 240,
02197  *              magenta = 300.
02198  *          If colorname or value preceded with # is specified here - it
02199  *          will be treated as RGB color and converted into hue
02200  *          automagically.
02201  * affected_radius
02202  *          Optional. Value in degrees to be used in order to
02203  *          calculate the range of affected hues. Range is determined by
02204  *          substracting and adding this value from/to affected_hue.
02205  * hue_offset
02206  *          Optional. Value by which to adjust the hue.
02207  * saturation_offset
02208  *          Optional. Value by which to adjust the saturation.
02209  * value_offset
02210  *          Optional. Value by which to adjust the value.
02211  * NOTES
02212  * One of the Offsets must be not 0, in order for operation to be
02213  * performed.
02214  *
02215  * This tag applies to the first image contained within the tag.  Any
02216  * further images will be discarded.
02217  ******/
02218 static ASImage *
02219 handle_asxml_tag_hsv( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
02220 {
02221         ASImage *result = NULL ;
02222         xml_elem_t* ptr;
02223         int affected_hue = 0, affected_radius = 360 ;
02224         int hue_offset = 0, saturation_offset = 0, value_offset = 0 ;
02225         int xorig = 0, yorig = 0;
02226         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
02227         for (ptr = parm ; ptr ; ptr = ptr->next) 
02228         {
02229                 if (!strcmp(ptr->tag, "x_origin")) xorig = (int)parse_math(ptr->parm, NULL, width);
02230                 else if (!strcmp(ptr->tag, "y_origin")) yorig = (int)parse_math(ptr->parm, NULL, height);
02231                 else if (!strcmp(ptr->tag, "affected_hue"))
02232                 {
02233                         if( isdigit( (int)ptr->parm[0] ) )
02234                                 affected_hue = (int)parse_math(ptr->parm, NULL, 360);
02235                         else
02236                         {
02237                                 ARGB32 color = 0;
02238                                 if( parse_argb_color( ptr->parm, &color ) != ptr->parm )
02239                                 {
02240                                         affected_hue = rgb2hue( ARGB32_RED16(color),
02241                                                                                         ARGB32_GREEN16(color),
02242                                                                                         ARGB32_BLUE16(color));
02243                                         affected_hue = hue162degrees( affected_hue );
02244                                 }
02245                         }
02246                 }
02247                 else if (!strcmp(ptr->tag, "affected_radius"))  affected_radius = (int)parse_math(ptr->parm, NULL, 360);
02248                 else if (!strcmp(ptr->tag, "hue_offset"))               hue_offset = (int)parse_math(ptr->parm, NULL, 360);
02249                 else if (!strcmp(ptr->tag, "saturation_offset"))saturation_offset = (int)parse_math(ptr->parm, NULL, 100);
02250                 else if (!strcmp(ptr->tag, "value_offset"))     value_offset = (int)parse_math(ptr->parm, NULL, 100);
02251         }
02252         if( hue_offset == -1 && saturation_offset == -1 ) 
02253         {
02254                 hue_offset = 0 ; 
02255                 saturation_offset = -99 ;
02256         }
02257         if (hue_offset!=0 || saturation_offset != 0 || value_offset != 0 ) 
02258         {
02259                 result = adjust_asimage_hsv(state->asv, imtmp, xorig, yorig, width, height,
02260                                                     affected_hue, affected_radius,
02261                                                                         hue_offset, saturation_offset, value_offset,
02262                                                     ASA_ASImage, 100, ASIMAGE_QUALITY_TOP);
02263         }
02264         if( state->verbose > 1 )
02265                 show_progress("adjusted HSV of the image by [%d,%d,%d] affected hues are %+d-%+d.result = %p", hue_offset, saturation_offset, value_offset, affected_hue-affected_radius, affected_hue+affected_radius, result);
02266         return result;
02267 }
02268 
02269 /****** libAfterImage/asimagexml/pad
02270  * NAME
02271  * pad - pad an image with solid color rectangles.
02272  * SYNOPSIS
02273  * <pad id="new_id" left="pixels" top="pixels"
02274  *      right="pixels" bottom="pixels" color="color"
02275  *              refid="refid" width="pixels" height="pixels">
02276  * ATTRIBUTES
02277  * id       Optional. Image will be given this name for future reference.
02278  * width    Optional.  The result will have this width.
02279  * height   Optional.  The result will have this height.
02280  * refid    Optional.  An image ID defined with the "id" parameter for
02281  *          any previously created image.  If set, percentages in "width"
02282  *          and "height" will be derived from the width and height of the
02283  *          refid image.
02284  * left     Optional. Size to add to the left of the image.
02285  * top      Optional. Size to add to the top of the image.
02286  * right    Optional. Size to add to the right of the image.
02287  * bottom   Optional. Size to add to the bottom of the image.
02288  * color    Optional. Color value to fill added areas with. It could be
02289  *          transparent of course. Default is #FF000000 - totally black.
02290  * NOTES
02291  * This tag applies to the first image contained within the tag.  Any
02292  * further images will be discarded.
02293  ******/
02294 static ASImage *
02295 handle_asxml_tag_pad( ASImageXMLState *state, xml_elem_t* doc, xml_elem_t* parm, ASImage *imtmp, int width, int height)
02296 {
02297         ASImage *result = NULL ;
02298         xml_elem_t* ptr;
02299         ARGB32 color  = ARGB32_Black;
02300         int left = 0, top = 0, right = 0, bottom = 0;
02301         LOCAL_DEBUG_OUT("doc = %p, parm = %p, imtmp = %p, width = %d, height = %d", doc, parm, imtmp, width, height ); 
02302         for (ptr = parm ; ptr ; ptr = ptr->next) {
02303                 if (!strcmp(ptr->tag, "left"))   left = (int)parse_math(ptr->parm, NULL, width);
02304                 else if (!strcmp(ptr->tag, "top"))    top = (int)parse_math(ptr->parm, NULL, height);
02305                 else if (!strcmp(ptr->tag, "right"))  right = (int)parse_math(ptr->parm, NULL, width);
02306                 else if (!strcmp(ptr->tag, "bottom")) bottom = (int)parse_math(ptr->parm, NULL, height);
02307                 else if (!strcmp(ptr->tag, "color"))  parse_argb_color(ptr->parm, &color);
02308         }
02309         if( state->verbose > 1 )
02310                 show_progress("Padding image to [%dx%d%+d%+d].", width+left+right, height+top+bottom, left, top);
02311         if (left > 0 || top > 0 || right > 0 || bottom > 0 )
02312                 result = pad_asimage(state->asv, imtmp, left, top, width+left+right, height+top+bottom,
02313                                                     color, ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
02314         return result;
02315 }
02316 
02317 #define REPLACE_STRING(str,val) do {if(str)free(str);(str) = (val);}while(0)
02318 
02319 /* Each tag is only allowed to return ONE image. */
02320 ASImage*
02321 build_image_from_xml( ASVisual *asv, ASImageManager *imman, ASFontManager *fontman, xml_elem_t* doc, xml_elem_t** rparm, ASFlagType flags, int verbose, Window display_win)
02322 {
02323         xml_elem_t* ptr;
02324         char* id = NULL;
02325         ASImage* result = NULL;
02326         ASImageXMLState state ; 
02327 
02328         if( IsCDATA(doc) )  return NULL ;
02329 
02330         memset( &state, 0x00, sizeof(state));
02331         state.flags = flags ;
02332         state.asv = asv ; 
02333         state.imman = imman ; 
02334         state.fontman = fontman ; 
02335         state.verbose = verbose ;
02336         state.display_win = display_win ;
02337 
02338         if( doc ) 
02339         {                
02340                 xml_elem_t* parm = xml_parse_parm(doc->parm, NULL);
02341                 xml_elem_t* ptr ;
02342                 char* refid = NULL;
02343                 char* width_str = NULL;
02344                 char* height_str = NULL;
02345                 ASImage *refimg = NULL ; 
02346                 int width = 0, height = 0 ;
02347                 LOCAL_DEBUG_OUT("parm = %p", parm);
02348 
02349                 for (ptr = parm ; ptr ; ptr = ptr->next)
02350                 {       
02351                         if (ptr->tag[0] == 'i' && ptr->tag[1] == 'd' && ptr->tag[2] == '\0')
02352                                 REPLACE_STRING(id,mystrdup(ptr->parm));
02353                         else if (strcmp(ptr->tag, "refid") == 0 )       refid = ptr->parm ;
02354                         else if (strcmp(ptr->tag, "width") == 0 )       width_str = ptr->parm ;
02355                         else if (strcmp(ptr->tag, "height") == 0 )      height_str = ptr->parm ;
02356                 }               
02357 
02358                 if( id ) 
02359                         if( (result = fetch_asimage( imman, id)) != NULL ) 
02360                         {
02361                                 free( id );
02362                                 xml_elem_delete(NULL, parm);
02363                                 return result ; 
02364                         }
02365 
02366                 if( refid ) 
02367                         refimg = fetch_asimage( imman, refid);
02368 
02369                 if (!strcmp(doc->tag, "composite")) 
02370                         result = handle_asxml_tag_composite( &state, doc, parm );       
02371                 else if (!strcmp(doc->tag, "text")) 
02372                         result = handle_asxml_tag_text( &state, doc, parm );    
02373                 else if (!strcmp(doc->tag, "img")) 
02374                 {
02375                         translate_tag_size(     width_str, height_str, NULL, refimg, &width, &height );  
02376                         result = handle_asxml_tag_img( &state, doc, parm, width, height );
02377                 }else if (!strcmp(doc->tag, "recall")) 
02378                         result = handle_asxml_tag_recall( &state, doc, parm );
02379                 else if (!strcmp(doc->tag, "release"))
02380                         result = handle_asxml_tag_release( &state, doc, parm );
02381                 else if (!strcmp(doc->tag, "color"))
02382                         result = handle_asxml_tag_color( &state, doc, parm ); 
02383                 else if (!strcmp(doc->tag, "printf"))
02384                         result = handle_asxml_tag_printf( &state, doc, parm ); 
02385                 else if (!strcmp(doc->tag, "set"))
02386                         result = handle_asxml_tag_set( &state, doc, parm ); 
02387                 else if (!strcmp(doc->tag, "if") || !strcmp(doc->tag, "unless") )
02388                         result = handle_asxml_tag_if( &state, doc, parm ); 
02389                 else if ( !strcmp(doc->tag, "gradient") )
02390                 {       
02391                         translate_tag_size(     width_str, height_str, NULL, refimg, &width, &height );  
02392                         if( width > 0 && height > 0 )
02393                                 result = handle_asxml_tag_gradient( &state, doc, parm, width, height );            
02394                 }else if (!strcmp(doc->tag, "solid"))
02395                 {       
02396                         translate_tag_size(     width_str, height_str, NULL, refimg, &width, &height );  
02397                         if( width > 0 && height > 0 )
02398                                 result = handle_asxml_tag_solid( &state, doc, parm, width, height);
02399                 }else
02400                 {       
02401                         ASImage *imtmp = NULL ; 
02402 
02403                         for (ptr = doc->child ; ptr && !imtmp ; ptr = ptr->next) 
02404                                 imtmp = build_image_from_xml(asv, imman, fontman, ptr, NULL, flags, verbose, display_win);
02405 
02406                         if( imtmp ) 
02407                         {       
02408                                 if (imtmp && !strcmp(doc->tag, "save")) 
02409                                         result = handle_asxml_tag_save( &state, doc, parm, imtmp );     
02410                                 else if (imtmp && !strcmp(doc->tag, "background")) 
02411                                         result = handle_asxml_tag_background( &state, doc, parm, imtmp );       
02412                                 else if (imtmp && !strcmp(doc->tag, "blur")) 
02413                                         result = handle_asxml_tag_blur( &state, doc, parm, imtmp );     
02414                                 else 
02415                                 {       
02416                                         translate_tag_size(     width_str, height_str, imtmp, refimg, &width, &height );   
02417                 
02418                                         if ( width > 0 && height > 0 )
02419                                         { 
02420 #define HANDLE_SIZED_TAG(ttag) \
02421                 else if( !strcmp(doc->tag, #ttag) )     result = handle_asxml_tag_##ttag( &state, doc, parm, imtmp, width, height )
02422                                                 if (0){}
02423                                                 HANDLE_SIZED_TAG(bevel);
02424                                                 HANDLE_SIZED_TAG(mirror);
02425                                                 HANDLE_SIZED_TAG(rotate);
02426                                                 HANDLE_SIZED_TAG(scale);
02427                                                 HANDLE_SIZED_TAG(slice);
02428                                                 HANDLE_SIZED_TAG(crop);
02429                                                 HANDLE_SIZED_TAG(tile);
02430                                                 HANDLE_SIZED_TAG(hsv);
02431                                                 HANDLE_SIZED_TAG(pad);
02432                                                 HANDLE_SIZED_TAG(pixelize);
02433                                                 HANDLE_SIZED_TAG(color2alpha);
02434 #undef HANDLE_SIZED_TAG                                         
02435                                         }               
02436                                 }
02437                                 
02438                                 if( result != imtmp ) 
02439                                         safe_asimage_destroy(imtmp);
02440                         }
02441                 }
02442                 
02443                 if( refimg ) 
02444                         release_asimage( refimg );
02445                 
02446                 if (rparm) *rparm = parm; 
02447                 else xml_elem_delete(NULL, parm);
02448         }
02449         LOCAL_DEBUG_OUT("result = %p, id = \"%s\"", result, id?id:"(null)" );
02450 
02451 
02452 
02453         /* No match so far... see if one of our children can do any better.*/
02454         if (!result  && doc ) 
02455         {
02456                 xml_elem_t* tparm = NULL;
02457                 for (ptr = doc->child ; ptr && !result ; ptr = ptr->next) 
02458                 {
02459                         xml_elem_t* sparm = NULL;
02460                         result = build_image_from_xml(asv, imman, fontman, ptr, &sparm, flags, verbose, display_win);
02461                         if (result) 
02462                         {
02463                                 if (tparm) xml_elem_delete(NULL, tparm);
02464                                 tparm = sparm; 
02465                         }else 
02466                                 if (sparm) xml_elem_delete(NULL, sparm);
02467 
02468                 }
02469                 if (rparm) 
02470                 { 
02471                         if( *rparm ) xml_elem_delete(NULL, *rparm); *rparm = tparm; 
02472                 }else 
02473                         xml_elem_delete(NULL, tparm);
02474         }
02475 
02476         LOCAL_DEBUG_OUT("result = %p", result );
02477         result = commit_xml_image_built( &state, id, result );
02478         if( id ) 
02479                 free( id );
02480         LOCAL_DEBUG_OUT("result = %p", result );
02481         if( result )
02482         {
02483                 LOCAL_DEBUG_OUT("result's size = %dx%d", result->width, result->height );       
02484         }        
02485         return result;
02486 }
02487 
02488 
02489 
02490 

Generated on Tue Jul 5 14:13:26 2011 for ROOT_528-00b_version by  doxygen 1.5.1