asimage.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 Valeriy Onuchin <Valeri dot Onoutchine at cern dot ch>
00003  * Copyright (c) 2000-2004 Sasha Vasko <sasha at aftercode.net>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #define LOCAL_DEBUG
00021 #undef DO_CLOCKING
00022 #ifndef NO_DEBUG_OUTPUT
00023 #undef DEBUG_RECTS
00024 #undef DEBUG_RECTS2
00025 #endif
00026 
00027 #ifdef _WIN32
00028 #include "win32/config.h"
00029 #else
00030 #include "config.h"
00031 #endif
00032 
00033 
00034 #define USE_64BIT_FPU
00035 
00036 #include <string.h>
00037 #ifdef DO_CLOCKING
00038 #if TIME_WITH_SYS_TIME
00039 # include <sys/time.h>
00040 # include <time.h>
00041 #else
00042 # if HAVE_SYS_TIME_H
00043 #  include <sys/time.h>
00044 # else
00045 #  include <time.h>
00046 # endif
00047 #endif
00048 #endif
00049 #ifdef HAVE_UNISTD_H
00050 #include <unistd.h>
00051 #endif
00052 #ifdef HAVE_STDLIB_H
00053 #include <stdlib.h>
00054 #endif
00055 #ifdef HAVE_STDARG_H
00056 #include <stdarg.h>
00057 #endif
00058 
00059 #ifdef _WIN32
00060 # include "win32/afterbase.h"
00061 #else
00062 # include "afterbase.h"
00063 #endif
00064 #include "asvisual.h"
00065 #include "scanline.h"
00066 #include "blender.h"
00067 #include "asimage.h"
00068 #include "ascmap.h"
00069 
00070 static ASVisual __as_dummy_asvisual = {0};
00071 static ASVisual *__as_default_asvisual = &__as_dummy_asvisual ;
00072 
00073 /* these are internal library things - user should not mess with it ! */
00074 ASVisual *_set_default_asvisual( ASVisual *new_v )
00075 {
00076         ASVisual *old_v = __as_default_asvisual ;
00077         __as_default_asvisual = new_v?new_v:&__as_dummy_asvisual ;
00078 /* This should be done in application - we should not meddle with other lib's stuff! 
00079 #if HAVE_AFTERBASE_FLAG 
00080         if (new_v && new_v->dpy && !get_current_X_display (new_v->dpy))
00081                 set_current_X_display (new_v->dpy);
00082 #endif
00083 */
00084         return old_v;
00085 }
00086 
00087 ASVisual *get_default_asvisual()
00088 {
00089         return __as_default_asvisual?__as_default_asvisual:&__as_dummy_asvisual;
00090 }
00091 
00092 /* internal buffer used for compression/decompression */
00093 
00094 static CARD8 *__as_compression_buffer = NULL ;
00095 static size_t __as_compression_buffer_len = 0;   /* allocated size */
00096 
00097 static inline CARD8* get_compression_buffer( size_t size )
00098 {
00099         if( size > __as_compression_buffer_len )
00100                 __as_compression_buffer_len = (size+1023)&(~0x03FF) ;
00101         return (__as_compression_buffer = realloc( __as_compression_buffer, __as_compression_buffer_len ));
00102 }
00103 
00104 static inline void release_compression_buffer( CARD8 *ptr )
00105 {
00106         /* do nothing so far */
00107 }
00108 
00109 
00110 
00111 #ifdef TRACK_ASIMAGES
00112 static ASHashTable *__as_image_registry = NULL ;
00113 #endif
00114 
00115 #ifdef HAVE_MMX
00116 Bool asimage_use_mmx = True;
00117 #else
00118 Bool asimage_use_mmx = False;
00119 #endif
00120 
00121 /* *********************   ASImage  ************************************/
00122 void
00123 asimage_init (ASImage * im, Bool free_resources)
00124 {
00125         if (im != NULL)
00126         {
00127                 if (free_resources)
00128                 {
00129                         register int i ;
00130                         for( i = im->height*4-1 ; i>= 0 ; --i )
00131                                 if( im->red[i] != 0 )
00132                                         forget_data( NULL, im->red[i] );
00133                         if( im->red )
00134                                 free(im->red);
00135 #ifndef X_DISPLAY_MISSING
00136                         if( im->alt.ximage )
00137                                 XDestroyImage( im->alt.ximage );
00138                         if( im->alt.mask_ximage )
00139                                 XDestroyImage( im->alt.mask_ximage );
00140 #endif
00141                         if( im->alt.argb32 )
00142                                 free( im->alt.argb32 );
00143                         if( im->alt.vector )
00144                                 free( im->alt.vector );
00145                         if( im->name ) 
00146                                 free( im->name );
00147                 }
00148                 memset (im, 0x00, sizeof (ASImage));
00149                 im->magic = MAGIC_ASIMAGE ;
00150                 im->back_color = ARGB32_DEFAULT_BACK_COLOR ;
00151         }
00152 }
00153 
00154 void
00155 flush_asimage_cache( ASImage *im )
00156 {
00157 #ifndef X_DISPLAY_MISSING
00158         if( im->alt.ximage )
00159     {
00160                 XDestroyImage( im->alt.ximage );
00161         im->alt.ximage = NULL ;
00162     }
00163         if( im->alt.mask_ximage )
00164     {
00165                 XDestroyImage( im->alt.mask_ximage );
00166         im->alt.mask_ximage = NULL ;
00167     }
00168 #endif
00169 }
00170 
00171 static void
00172 alloc_asimage_channels ( ASImage *im )
00173 {
00174         /* we want result to be 32bit aligned and padded */
00175         im->red = safecalloc (1, sizeof (ASStorageID) * im->height * 4);
00176         LOCAL_DEBUG_OUT( "allocated %p for channels of the image %p", im->red, im );
00177         if( im->red == NULL )
00178         {
00179                 show_error( "Insufficient memory to create image %dx%d!", im->width, im->height );
00180                 return ;
00181         }
00182 
00183         im->green = im->red+im->height;
00184         im->blue =      im->red+(im->height*2);
00185         im->alpha = im->red+(im->height*3);
00186         im->channels[IC_RED] = im->red ;
00187         im->channels[IC_GREEN] = im->green ;
00188         im->channels[IC_BLUE] = im->blue ;
00189         im->channels[IC_ALPHA] = im->alpha ;
00190 }
00191 
00192 void
00193 asimage_start (ASImage * im, unsigned int width, unsigned int height, unsigned int compression)
00194 {
00195         if (im)
00196         {
00197                 asimage_init (im, True);
00198                 im->height = height;
00199                 im->width = width;
00200                 
00201                 alloc_asimage_channels( im );
00202 
00203                 if( compression == 0 ) 
00204                         set_flags( im->flags, ASIM_NO_COMPRESSION );
00205         }
00206 }
00207 
00208 Bool
00209 asimage_replace (ASImage *im, ASImage *from)
00210 {
00211         if ( im && from && im != from )
00212                 if( im->magic == MAGIC_ASIMAGE && from->magic == MAGIC_ASIMAGE && from->imageman == NULL )
00213                 {
00214                         int ref_count = im->ref_count ;
00215                         ASImageManager *imageman = im->imageman ;
00216                         char *name = im->name ;
00217                         ASFlagType  saved_flags = im->flags & (ASIM_NAME_IS_FILENAME|ASIM_NO_COMPRESSION) ;
00218 
00219                         im->name = NULL ; 
00220                         asimage_init (im, True);
00221 
00222                         memcpy( im, from, sizeof(ASImage) );
00223                         /* Assume : from->name == NULL as from->imageman == NULL (see above ) */
00224                         memset( from, 0x00, sizeof(ASImage) );          
00225 
00226                         im->ref_count = ref_count ; 
00227                         im->imageman = imageman ;
00228                         im->name = name ;
00229                         set_flags( im->flags, saved_flags );
00230 
00231                         return True ;
00232                 }
00233         return False;
00234 }
00235 
00236 
00237 static ASImage* 
00238 check_created_asimage( ASImage *im, unsigned int width, unsigned int height )
00239 {
00240         if( im->width == 0 || im->height == 0 )
00241         {
00242                 free( im );
00243                 im = NULL ;
00244 #ifdef TRACK_ASIMAGES
00245         show_error( "failed to create ASImage of size %dx%d", width, height );
00246 #endif
00247     }else
00248     {
00249 #ifdef TRACK_ASIMAGES
00250         show_progress( "created ASImage %p of size %dx%d (%s compressed )", im,  
00251                                                 width, height, (get_flags(im->flags, ASIM_NO_COMPRESSION)?" no":"") );
00252         if( __as_image_registry == NULL )
00253             __as_image_registry = create_ashash( 0, pointer_hash_value, NULL, NULL );
00254         add_hash_item( __as_image_registry, AS_HASHABLE(im), im );
00255 #endif
00256     }
00257         return im ;
00258 }
00259 
00260 ASImage *
00261 create_asimage( unsigned int width, unsigned int height, unsigned int compression)
00262 {
00263         ASImage *im = safecalloc( 1, sizeof(ASImage) );
00264         asimage_start( im, width, height, compression );
00265         return check_created_asimage( im, width, height );
00266 }
00267 
00268 void
00269 destroy_asimage( ASImage **im )
00270 {
00271         if( im )
00272         {
00273 
00274                 if( *im && !AS_ASSERT_NOTVAL((*im)->imageman,NULL))
00275                 {
00276 #ifdef TRACK_ASIMAGES
00277             show_progress( "destroying ASImage %p of size %dx%d", *im, (*im)->width, (*im)->height );
00278             remove_hash_item( __as_image_registry, AS_HASHABLE(*im), NULL, False );
00279 #endif
00280                         asimage_init( *im, True );
00281                         (*im)->magic = 0;
00282                         free( *im );
00283                         *im = NULL ;
00284                 }else if( *im )
00285                 {
00286                 show_error( "Failed to destroy ASImage %p:", *im );
00287                         print_asimage_func (AS_HASHABLE(*im));
00288                 }
00289 
00290         }
00291 }
00292 
00293 void print_asimage_func (ASHashableValue value)
00294 {
00295     ASImage *im = (ASImage*)value ;
00296     if( im && im->magic == MAGIC_ASIMAGE )
00297     {
00298         unsigned int k;
00299         unsigned int red_mem = 0, green_mem = 0, blue_mem = 0, alpha_mem = 0;
00300         unsigned int red_count = 0, green_count = 0, blue_count = 0, alpha_count = 0;
00301                 ASStorageSlot slot ;
00302 
00303         fprintf( stderr,"\n\tASImage[%p].size = %dx%d;\n",  im, im->width, im->height );
00304         fprintf( stderr,"\tASImage[%p].back_color = 0x%lX;\n", im, (long)im->back_color );
00305         fprintf( stderr,"\t\tASImage[%p].alt.ximage = %p;\n", im, im->alt.ximage );
00306         if( im->alt.ximage )
00307         {
00308             fprintf( stderr,"\t\t\tASImage[%p].alt.ximage.bytes_per_line = %d;\n", im, im->alt.ximage->bytes_per_line);
00309             fprintf( stderr,"\t\t\tASImage[%p].alt.ximage.size = %dx%d;\n", im, im->alt.ximage->width, im->alt.ximage->height);
00310         }
00311         fprintf( stderr,"\t\tASImage[%p].alt.mask_ximage = %p;\n", im, im->alt.mask_ximage);
00312         if( im->alt.mask_ximage )
00313         {
00314             fprintf( stderr,"\t\t\tASImage[%p].alt.mask_ximage.bytes_per_line = %d;\n", im, im->alt.mask_ximage->bytes_per_line);
00315             fprintf( stderr,"\t\t\tASImage[%p].alt.mask_ximage.size = %dx%d;\n", im, im->alt.mask_ximage->width, im->alt.mask_ximage->height);
00316         }
00317         fprintf( stderr,"\t\tASImage[%p].alt.argb32 = %p;\n", im, im->alt.argb32 );
00318         fprintf( stderr,"\t\tASImage[%p].alt.vector = %p;\n", im, im->alt.vector );
00319         fprintf( stderr,"\tASImage[%p].imageman = %p;\n", im, im->imageman );
00320         fprintf( stderr,"\tASImage[%p].ref_count = %d;\n", im, im->ref_count );
00321         fprintf( stderr,"\tASImage[%p].name = \"%s\";\n", im, im->name );
00322         fprintf( stderr,"\tASImage[%p].flags = 0x%lX;\n", im, im->flags );
00323 
00324         for( k = 0 ; k < im->height ; k++ )
00325         {
00326                         if( im->red[k] ) 
00327                                 if( query_storage_slot(NULL, im->red[k], &slot ) )
00328                                 {       
00329                                         ++red_count;    
00330                                         red_mem += slot.size ;
00331                                 }
00332                         if( im->green[k] ) 
00333                                 if( query_storage_slot(NULL, im->green[k], &slot ) )
00334                                 {       
00335                                         ++green_count;  
00336                                         green_mem += slot.size ;
00337                                 }
00338                         if( im->blue[k] ) 
00339                                 if( query_storage_slot(NULL, im->blue[k], &slot ) )
00340                                 {       
00341                                         ++blue_count;   
00342                                         blue_mem += slot.size ;
00343                                 }
00344                         if( im->alpha[k] ) 
00345                                 if( query_storage_slot(NULL, im->alpha[k], &slot ) )
00346                                 {       
00347                                         ++alpha_count;  
00348                                         alpha_mem += slot.size ;
00349                                 }
00350         }
00351 
00352         fprintf( stderr,"\tASImage[%p].uncompressed_size = %d;\n", im, im->width*red_count +
00353                                                                     im->width*green_count +
00354                                                                     im->width*blue_count +
00355                                                                     im->width*alpha_count );
00356         fprintf( stderr,"\tASImage[%p].compressed_size = %d;\n",   im, red_mem + green_mem +blue_mem + alpha_mem );
00357         fprintf( stderr,"\t\tASImage[%p].channel[red].lines_count = %d;\n", im, red_count );
00358         fprintf( stderr,"\t\tASImage[%p].channel[red].memory_used = %d;\n", im, red_mem );
00359         fprintf( stderr,"\t\tASImage[%p].channel[green].lines_count = %d;\n", im, green_count );
00360         fprintf( stderr,"\t\tASImage[%p].channel[green].memory_used = %d;\n", im, green_mem );
00361         fprintf( stderr,"\t\tASImage[%p].channel[blue].lines_count = %d;\n", im, blue_count );
00362         fprintf( stderr,"\t\tASImage[%p].channel[blue].memory_used = %d;\n", im, blue_mem );
00363         fprintf( stderr,"\t\tASImage[%p].channel[alpha].lines_count = %d;\n", im, alpha_count );
00364         fprintf( stderr,"\t\tASImage[%p].channel[alpha].memory_used = %d;\n", im, alpha_mem );
00365     }
00366 }
00367 
00368 void
00369 print_asimage_registry()
00370 {
00371 #ifdef TRACK_ASIMAGES
00372     print_ashash( __as_image_registry, print_asimage_func );
00373 #endif
00374 }
00375 
00376 void
00377 purge_asimage_registry()
00378 {
00379 #ifdef TRACK_ASIMAGES
00380     if( __as_image_registry )
00381         destroy_ashash( &__as_image_registry );
00382 #endif
00383 }
00384 
00385 /* ******************** ASImageManager ****************************/
00386 static void
00387 asimage_destroy (ASHashableValue value, void *data)
00388 {
00389         if( data )
00390         {
00391                 ASImage *im = (ASImage*)data ;
00392                 if( im != NULL )
00393                 {
00394                         if( AS_ASSERT_NOTVAL(im->magic, MAGIC_ASIMAGE) )
00395                                 im = NULL ;
00396                         else
00397                                 im->imageman = NULL ;
00398                 }
00399                 if( im == NULL || (char*)value != im->name ) 
00400                         free( (char*)value );/* name */
00401                 destroy_asimage( &im );
00402         }
00403 }
00404 
00405 ASImageManager *create_image_manager( struct ASImageManager *reusable_memory, double gamma, ... )
00406 {
00407         ASImageManager *imman = reusable_memory ;
00408         int i ;
00409         va_list ap;
00410 
00411         if( imman == NULL )
00412                 imman = safecalloc( 1, sizeof(ASImageManager));
00413         else
00414                 memset( imman, 0x00, sizeof(ASImageManager));
00415 
00416         va_start (ap, gamma);
00417         for( i = 0 ; i < MAX_SEARCH_PATHS ; i++ )
00418         {
00419                 char *path = va_arg(ap,char*);
00420                 if( path == NULL )
00421                         break;
00422                 imman->search_path[i] = mystrdup( path );
00423         }
00424         va_end (ap);
00425 
00426         imman->search_path[MAX_SEARCH_PATHS] = NULL ;
00427         imman->gamma = gamma ;
00428 
00429         imman->image_hash = create_ashash( 7, string_hash_value, string_compare, asimage_destroy );
00430 
00431         return imman;
00432 }
00433 
00434 void
00435 destroy_image_manager( struct ASImageManager *imman, Bool reusable )
00436 {
00437         if( imman )
00438         {
00439                 int i = MAX_SEARCH_PATHS;
00440                 destroy_ashash( &(imman->image_hash) );
00441                 while( --i >= 0 )
00442                         if(imman->search_path[i])
00443                                 free( imman->search_path[i] );
00444 
00445                 if( !reusable )
00446                         free( imman );
00447                 else
00448                         memset( imman, 0x00, sizeof(ASImageManager));
00449         }
00450 }
00451 
00452 Bool
00453 store_asimage( ASImageManager* imageman, ASImage *im, const char *name )
00454 {
00455         Bool res = False ;
00456         if( !AS_ASSERT(im) )
00457                 if( AS_ASSERT_NOTVAL(im->magic, MAGIC_ASIMAGE) )
00458                         im = NULL ;
00459         if( !AS_ASSERT(imageman) && !AS_ASSERT(im) && !AS_ASSERT((char*)name) )
00460         {
00461                 if( im->imageman == NULL )
00462                 {
00463                         int hash_res ;
00464                         char *stored_name = mystrdup( name );
00465                         if( im->name ) 
00466                                 free( im->name );
00467                         im->name = stored_name ;
00468                         hash_res = add_hash_item( imageman->image_hash, AS_HASHABLE(im->name), im);
00469                         res = ( hash_res == ASH_Success);
00470                         if( !res )
00471                         {
00472                                 free( im->name );
00473                                 im->name = NULL ;
00474                         }else
00475                         {
00476                                 im->imageman = imageman ;
00477                                 im->ref_count = 1 ;
00478                         }
00479                 }
00480         }
00481         return res ;
00482 }
00483 
00484 inline ASImage *
00485 query_asimage( ASImageManager* imageman, const char *name )
00486 {
00487         ASImage *im = NULL ;
00488         if( !AS_ASSERT(imageman) && !AS_ASSERT(name) )
00489         {
00490                 ASHashData hdata = {0} ;
00491                 if( get_hash_item( imageman->image_hash, AS_HASHABLE((char*)name), &hdata.vptr) == ASH_Success )
00492                 {
00493                         im = hdata.vptr ;
00494                         if( im->magic != MAGIC_ASIMAGE )
00495                                 im = NULL ;
00496         }
00497         }
00498         return im;
00499 }
00500 
00501 ASImage *
00502 fetch_asimage( ASImageManager* imageman, const char *name )
00503 {
00504     ASImage *im = query_asimage( imageman, name );
00505     if( im )
00506         {
00507         im->ref_count++ ;
00508         }
00509         return im;
00510 }
00511 
00512 
00513 ASImage *
00514 dup_asimage( ASImage* im )
00515 {
00516         if( !AS_ASSERT(im) )
00517                 if( AS_ASSERT_NOTVAL(im->magic,MAGIC_ASIMAGE) )
00518                 {
00519                         im = NULL ;
00520                         show_error( "ASImage %p has invalid magic number - discarding!", im );
00521                 }
00522 
00523         if( !AS_ASSERT(im) && !AS_ASSERT(im->imageman) )
00524         {
00525 /*              fprintf( stderr, __FUNCTION__" on image %p ref_count = %d\n", im, im->ref_count ); */
00526                 im->ref_count++ ;
00527                 return im;
00528         }else if( im ) 
00529         {
00530                 show_debug( __FILE__, "dup_asimage", __LINE__, "Attempt to duplicate ASImage %p that is not tracked by any image manager!", im );
00531         }
00532         return NULL ;
00533 }
00534 
00535 inline int
00536 release_asimage( ASImage *im )
00537 {
00538         int res = -1 ;
00539         if( !AS_ASSERT(im) )
00540         {
00541                 if( im->magic == MAGIC_ASIMAGE )
00542                 {
00543                         if( --(im->ref_count) <= 0 )
00544                         {
00545                                 ASImageManager *imman = im->imageman ;
00546                                 if( !AS_ASSERT(imman) )
00547                     if( remove_hash_item(imman->image_hash, (ASHashableValue)(char*)im->name, NULL, True) != ASH_Success )
00548                         destroy_asimage( &im );
00549                         }else
00550                                 res = im->ref_count ;
00551                 }
00552         }
00553         return res ;
00554 }
00555 
00556 void
00557 forget_asimage( ASImage *im )
00558 {
00559         if( !AS_ASSERT(im) )
00560         {
00561                 if( im->magic == MAGIC_ASIMAGE )
00562                 {
00563                         ASImageManager *imman = im->imageman ;
00564                         if( !AS_ASSERT(imman) )
00565                                 remove_hash_item(imman->image_hash, (ASHashableValue)(char*)im->name, NULL, False);
00566             im->ref_count = 0;
00567             im->imageman = NULL;
00568                 }
00569         }
00570 }
00571 
00572 void
00573 relocate_asimage( ASImageManager* to_imageman, ASImage *im )
00574 {
00575         if( !AS_ASSERT(im) )
00576         {
00577                 if( im->magic == MAGIC_ASIMAGE )
00578                 {
00579                         ASImageManager *imman = im->imageman ;
00580                         int ref_count = im->ref_count ; 
00581                         if( imman != NULL )
00582                         {
00583                                 remove_hash_item(imman->image_hash, (ASHashableValue)(char*)im->name, NULL, False);
00584                     im->ref_count = 0;
00585                 im->imageman = NULL;
00586                         }
00587                         if( to_imageman != NULL ) 
00588                         {
00589                                 if( add_hash_item( to_imageman->image_hash, AS_HASHABLE(im->name), im) == ASH_Success ) 
00590                                 {
00591                             im->ref_count = ref_count < 1 ? 1: ref_count;
00592                         im->imageman = to_imageman ; 
00593                                 }
00594                         }
00595                 }
00596         }
00597 }
00598 
00599 void
00600 forget_asimage_name( ASImageManager *imman, const char *name )
00601 {
00602     if( !AS_ASSERT(imman) && name != NULL )
00603         {
00604         remove_hash_item(imman->image_hash, AS_HASHABLE((char*)name), NULL, False);
00605     }
00606 }
00607 
00608 inline int
00609 safe_asimage_destroy( ASImage *im )
00610 {
00611         int res = -1 ;
00612         if( !AS_ASSERT(im) )
00613         {
00614                 if( im->magic == MAGIC_ASIMAGE )
00615                 {
00616                         ASImageManager *imman = im->imageman ;
00617                         if( imman != NULL )
00618                         {
00619                 res = --(im->ref_count) ;
00620                 if( im->ref_count <= 0 )
00621                                         remove_hash_item(imman->image_hash, (ASHashableValue)(char*)im->name, NULL, True);
00622             }else
00623                         {
00624                                 destroy_asimage( &im );
00625                                 res = -1 ;
00626                         }
00627                 }
00628         }
00629         return res ;
00630 }
00631 
00632 int
00633 release_asimage_by_name( ASImageManager *imageman, char *name )
00634 {
00635         int res = -1 ;
00636         ASImage *im = NULL ;
00637         if( !AS_ASSERT(imageman) && !AS_ASSERT(name) )
00638         {
00639                 ASHashData hdata ;
00640                 if( get_hash_item( imageman->image_hash, AS_HASHABLE((char*)name), &hdata.vptr) == ASH_Success )
00641                 {
00642                         im = hdata.vptr ;
00643                         res = release_asimage( im );
00644                 }
00645         }
00646         return res ;
00647 }
00648 
00649 void
00650 print_asimage_manager(ASImageManager *imageman)
00651 {
00652 #ifdef TRACK_ASIMAGES
00653     print_ashash( imageman->image_hash, string_print );
00654 #endif    
00655 }
00656 
00657 /* ******************** ASGradient ****************************/
00658 
00659 void
00660 destroy_asgradient( ASGradient **pgrad )
00661 {
00662         if( pgrad && *pgrad )
00663         {
00664                 if( (*pgrad)->color )
00665                 {
00666                         free( (*pgrad)->color );
00667                         (*pgrad)->color = NULL ;
00668                 }
00669                 if( (*pgrad)->offset )
00670                 {
00671                         free( (*pgrad)->offset );
00672                         (*pgrad)->offset = NULL ;
00673                 }
00674                 (*pgrad)->npoints = 0 ;
00675                 free( *pgrad );
00676                 *pgrad = NULL ;
00677         }
00678 
00679 }
00680 
00681 ASGradient *
00682 flip_gradient( ASGradient *orig, int flip )
00683 {
00684         ASGradient *grad ;
00685         int npoints ;
00686         int type ;
00687         Bool inverse_points = False ;
00688 
00689         flip &= FLIP_MASK ;
00690         if( orig == NULL || flip == 0 )
00691                 return orig;
00692 
00693         grad = safecalloc( 1, sizeof(ASGradient));
00694 
00695         grad->npoints = npoints = orig->npoints ;
00696         type = orig->type ;
00697     grad->color = safemalloc( npoints*sizeof(ARGB32) );
00698     grad->offset = safemalloc( npoints*sizeof(double) );
00699 
00700         if( get_flags(flip, FLIP_VERTICAL) )
00701         {
00702                 Bool upsidedown = get_flags(flip, FLIP_UPSIDEDOWN) ;
00703                 switch(type)
00704                 {
00705                         case GRADIENT_Left2Right  :
00706                                 type = GRADIENT_Top2Bottom ; inverse_points = !upsidedown ;
00707                                 break;
00708                         case GRADIENT_TopLeft2BottomRight :
00709                                 type = GRADIENT_BottomLeft2TopRight ; inverse_points = upsidedown ;
00710                                 break;
00711                         case GRADIENT_Top2Bottom  :
00712                                 type = GRADIENT_Left2Right ; inverse_points = upsidedown ;
00713                                 break;
00714                         case GRADIENT_BottomLeft2TopRight :
00715                                 type = GRADIENT_TopLeft2BottomRight ; inverse_points = !upsidedown ;
00716                                 break;
00717                 }
00718         }else if( flip == FLIP_UPSIDEDOWN )
00719         {
00720                 inverse_points = True ;
00721         }
00722 
00723         grad->type = type ;
00724         if( inverse_points )
00725     {
00726         register int i = 0, k = npoints;
00727         while( --k >= 0 )
00728         {
00729             grad->color[i] = orig->color[k] ;
00730             grad->offset[i] = 1.0 - orig->offset[k] ;
00731                         ++i ;
00732         }
00733     }else
00734         {
00735         register int i = npoints ;
00736         while( --i >= 0 )
00737         {
00738             grad->color[i] = orig->color[i] ;
00739             grad->offset[i] = orig->offset[i] ;
00740         }
00741     }
00742         return grad;
00743 }
00744 
00745 /* ******************** ASImageLayer ****************************/
00746 
00747 void
00748 init_image_layers( register ASImageLayer *l, int count )
00749 {
00750         memset( l, 0x00, sizeof(ASImageLayer)*count );
00751         while( --count >= 0 )
00752         {
00753                 l[count].merge_scanlines = alphablend_scanlines ;
00754 /*              l[count].solid_color = ARGB32_DEFAULT_BACK_COLOR ; */
00755         }
00756 }
00757 
00758 ASImageLayer *
00759 create_image_layers( int count )
00760 {
00761         ASImageLayer *l = NULL;
00762 
00763         if( count > 0 )
00764         {
00765                 l = safecalloc( count, sizeof(ASImageLayer) );
00766                 init_image_layers( l, count );
00767         }
00768         return l;
00769 }
00770 
00771 void
00772 destroy_image_layers( register ASImageLayer *l, int count, Bool reusable )
00773 {
00774         if( l )
00775         {
00776                 register int i = count;
00777                 while( --i >= 0 )
00778                 {
00779                         if( l[i].im )
00780                         {
00781                                 if( l[i].im->imageman )
00782                                         release_asimage( l[i].im );
00783                                 else
00784                                         destroy_asimage( &(l[i].im) );
00785                         }
00786                         if( l[i].bevel )
00787                                 free( l[i].bevel );
00788                 }
00789                 if( !reusable )
00790                         free( l );
00791                 else
00792                         memset( l, 0x00, sizeof(ASImageLayer)*count );
00793         }
00794 }
00795 
00796 
00797 
00798 /* **********************************************************************/
00799 /*  Compression/decompression                                                                              */
00800 /* **********************************************************************/
00801 size_t
00802 asimage_add_line_mono (ASImage * im, ColorPart color, CARD8 value, unsigned int y)
00803 {
00804         if (AS_ASSERT(im) || color <0 || color >= IC_NUM_CHANNELS )
00805                 return 0;
00806         if (y >= im->height)
00807                 return 0;
00808         
00809         if( im->channels[color][y] ) 
00810                 forget_data( NULL, im->channels[color][y] ); 
00811         im->channels[color][y] = store_data( NULL, &value, 1, 0, 0);
00812         return im->width;
00813 }
00814 
00815 size_t
00816 asimage_add_line (ASImage * im, ColorPart color, register CARD32 * data, unsigned int y)
00817 {
00818         if (AS_ASSERT(im) || color <0 || color >= IC_NUM_CHANNELS )
00819                 return 0;
00820         if (y >= im->height)
00821                 return 0;
00822         if( im->channels[color][y] ) 
00823                 forget_data( NULL, im->channels[color][y] ); 
00824         im->channels[color][y] = store_data( NULL, (CARD8*)data, im->width*4, ASStorage_RLEDiffCompress|ASStorage_32Bit, 0);
00825         return im->width;
00826 }
00827 
00828 size_t
00829 asimage_add_line_bgra (ASImage * im, register CARD32 * data, unsigned int y)
00830 {
00831         if (AS_ASSERT(im) )
00832                 return 0;
00833         if (y >= im->height)
00834                 return 0;
00835         if( im->channels[IC_ALPHA][y] ) 
00836                 forget_data( NULL, im->channels[IC_ALPHA][y] ); 
00837         im->channels[IC_ALPHA][y] = store_data( NULL, (CARD8*)data, im->width*4, 
00838                                                 ASStorage_24BitShift|ASStorage_Masked|
00839                                                                                         ASStorage_RLEDiffCompress|ASStorage_32Bit, 0);
00840         if( im->channels[IC_RED][y] ) 
00841                 forget_data( NULL, im->channels[IC_RED][y] ); 
00842         im->channels[IC_RED][y] = store_data( NULL, (CARD8*)data, im->width*4, 
00843                                                 ASStorage_16BitShift|ASStorage_Masked|
00844                                                                                         ASStorage_RLEDiffCompress|ASStorage_32Bit, 0);
00845         if( im->channels[IC_GREEN][y] ) 
00846                 forget_data( NULL, im->channels[IC_GREEN][y] ); 
00847         im->channels[IC_GREEN][y] = store_data( NULL, (CARD8*)data, im->width*4, 
00848                                                 ASStorage_8BitShift|ASStorage_Masked|
00849                                                                                         ASStorage_RLEDiffCompress|ASStorage_32Bit, 0);
00850         if( im->channels[IC_BLUE][y] ) 
00851                 forget_data( NULL, im->channels[IC_BLUE][y] ); 
00852         im->channels[IC_BLUE][y] = store_data( NULL, (CARD8*)data, im->width*4, 
00853                                                 ASStorage_Masked|
00854                                                                                         ASStorage_RLEDiffCompress|ASStorage_32Bit, 0);
00855         return im->width;
00856 }
00857 
00858 unsigned int
00859 asimage_print_line (ASImage * im, ColorPart color, unsigned int y, unsigned long verbosity)
00860 {
00861         if (AS_ASSERT(im) || color < 0 || color >= IC_NUM_CHANNELS )
00862                 return 0;
00863         if (y >= im->height)
00864                 return 0;
00865         
00866         return print_storage_slot(NULL, im->channels[color][y]);
00867 }
00868 
00869 void print_asimage( ASImage *im, int flags, char * func, int line )
00870 {
00871         if( im )
00872         {
00873                 register unsigned int k ;
00874                 int total_mem = 0 ;
00875                 fprintf( stderr, "%s:%d> printing ASImage %p.\n", func, line, im);
00876                 for( k = 0 ; k < im->height ; k++ )
00877         {
00878                         fprintf( stderr, "%s:%d> ******* %d *******\n", func, line, k );
00879                         total_mem+=asimage_print_line( im, IC_RED  , k, flags );
00880                         total_mem+=asimage_print_line( im, IC_GREEN, k, flags );
00881                         total_mem+=asimage_print_line( im, IC_BLUE , k, flags );
00882             total_mem+=asimage_print_line( im, IC_ALPHA , k, flags );
00883         }
00884         fprintf( stderr, "%s:%d> Total memory : %u - image size %dx%d ratio %d%%\n", func, line, total_mem, im->width, im->height, (total_mem*100)/(im->width*im->height*3) );
00885         }else
00886                 fprintf( stderr, "%s:%d> Attempted to print NULL ASImage.\n", func, line);
00887 }
00888 
00889 void print_component( register CARD32 *data, int nonsense, int len );
00890 
00891 int
00892 asimage_decode_line (ASImage * im, ColorPart color, CARD32 * to_buf, unsigned int y, unsigned int skip, unsigned int out_width)
00893 {
00894         ASStorageID id = im->channels[color][y];
00895         register int i = 0;
00896         /* that thing below is supposedly highly optimized : */
00897 LOCAL_DEBUG_CALLER_OUT( "im->width = %d, color = %d, y = %d, skip = %d, out_width = %d", im->width, color, y, skip, out_width );
00898 
00899         if( id )
00900         {
00901                 i = fetch_data32( NULL, id, to_buf, skip, out_width, 0, NULL);
00902         LOCAL_DEBUG_OUT( "decoded %d pixels", i );
00903 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
00904         {
00905             int z = -1 ;
00906             while( ++z < i )
00907                 fprintf( stderr, "%lX ", (unsigned long)to_buf[z] );
00908             fprintf( stderr, "\n");
00909 
00910         }
00911 #endif
00912                 return i;
00913         }
00914         return 0;
00915 }
00916 
00917 void
00918 move_asimage_channel( ASImage *dst, int channel_dst, ASImage *src, int channel_src )
00919 {
00920         if( !AS_ASSERT(dst) && !AS_ASSERT(src) && channel_src >= 0 && channel_src < IC_NUM_CHANNELS &&
00921                 channel_dst >= 0 && channel_dst < IC_NUM_CHANNELS )
00922         {
00923                 register int i = MIN(dst->height, src->height);
00924                 register ASStorageID *dst_rows = dst->channels[channel_dst] ;
00925                 register ASStorageID *src_rows = src->channels[channel_src] ;
00926                 while( --i >= 0 )
00927                 {
00928                         if( dst_rows[i] )
00929                                 forget_data( NULL, dst_rows[i] );
00930                         dst_rows[i] = src_rows[i] ;
00931                         src_rows[i] = 0 ;
00932                 }
00933         }
00934 }
00935 
00936 
00937 void
00938 copy_asimage_channel( ASImage *dst, int channel_dst, ASImage *src, int channel_src )
00939 {
00940         if( !AS_ASSERT(dst) && !AS_ASSERT(src) && channel_src >= 0 && channel_src < IC_NUM_CHANNELS &&
00941                 channel_dst >= 0 && channel_dst < IC_NUM_CHANNELS )
00942         {
00943                 register int i = MIN(dst->height, src->height);
00944                 register ASStorageID *dst_rows = dst->channels[channel_dst] ;
00945                 register ASStorageID *src_rows = src->channels[channel_src] ;
00946                 LOCAL_DEBUG_OUT( "src = %p, dst = %p, dst->width = %d, src->width = %d", src, dst, dst->width, src->width );
00947                 while( --i >= 0 )
00948                 {
00949                         if( dst_rows[i] )
00950                                 forget_data( NULL, dst_rows[i] );
00951                         dst_rows[i] = dup_data( NULL, src_rows[i] );
00952                 }
00953         }
00954 }
00955 
00956 void
00957 copy_asimage_lines( ASImage *dst, unsigned int offset_dst,
00958                     ASImage *src, unsigned int offset_src,
00959                                         unsigned int nlines, ASFlagType filter )
00960 {
00961         if( !AS_ASSERT(dst) && !AS_ASSERT(src) &&
00962                 offset_src < src->height && offset_dst < dst->height )
00963         {
00964                 int chan;
00965 
00966                 if( offset_src+nlines > src->height )
00967                         nlines = src->height - offset_src ;
00968                 if( offset_dst+nlines > dst->height )
00969                         nlines = dst->height - offset_dst ;
00970 
00971                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
00972                         if( get_flags( filter, 0x01<<chan ) )
00973                         {
00974                                 register int i = -1;
00975                                 register ASStorageID *dst_rows = &(dst->channels[chan][offset_dst]) ;
00976                                 register ASStorageID *src_rows = &(src->channels[chan][offset_src]) ;
00977 LOCAL_DEBUG_OUT( "copying %d lines of channel %d...", nlines, chan );
00978                                 while( ++i < (int)nlines )
00979                                 {
00980                                         if( dst_rows[i] )
00981                                                 forget_data( NULL, dst_rows[i] );
00982                                         dst_rows[i] = dup_data( NULL, src_rows[i] );
00983                                 }
00984                         }
00985 #if 0
00986                 for( i = 0 ; i < nlines ; ++i )
00987                 {
00988                         asimage_print_line( src, IC_ALPHA, i, (i==4)?VRB_EVERYTHING:VRB_LINE_SUMMARY );
00989                         asimage_print_line( dst, IC_ALPHA, i, (i==4)?VRB_EVERYTHING:VRB_LINE_SUMMARY );
00990                 }
00991 #endif
00992         }
00993 }
00994 
00995 Bool
00996 asimage_compare_line (ASImage *im, ColorPart color, CARD32 *to_buf, CARD32 *tmp, unsigned int y, Bool verbose)
00997 {
00998         register unsigned int i;
00999         asimage_decode_line( im, color, tmp, y, 0, im->width );
01000         for( i = 0 ; i < im->width ; i++ )
01001                 if( tmp[i] != to_buf[i] )
01002                 {
01003                         if( verbose )
01004                                 show_error( "line %d, component %d differ at offset %d ( 0x%lX(compresed) != 0x%lX(orig) )\n", y, color, i, (unsigned long)tmp[i], (unsigned long)to_buf[i] );
01005                         return False ;
01006                 }
01007         return True;
01008 }
01009 
01010 ASFlagType
01011 get_asimage_chanmask( ASImage *im)
01012 {
01013     ASFlagType mask = 0 ;
01014         int color ;
01015 
01016         if( !AS_ASSERT(im) )
01017                 for( color = 0; color < IC_NUM_CHANNELS ; color++ )
01018                 {
01019                         register ASStorageID *chan = im->channels[color];
01020                         register int y, height = im->height ;
01021                         for( y = 0 ; y < height ; y++ )
01022                                 if( chan[y] )
01023                                 {
01024                                         set_flags( mask, 0x01<<color );
01025                                         break;
01026                                 }
01027                 }
01028     return mask ;
01029 }
01030 
01031 int
01032 check_asimage_alpha (ASVisual *asv, ASImage *im )
01033 {
01034         int recomended_depth = 0 ;
01035         unsigned int            i;
01036         ASScanline     buf;
01037 
01038         if( asv == NULL )
01039                 asv = get_default_asvisual();
01040 
01041         if (im == NULL)
01042                 return 0;
01043 
01044         prepare_scanline( im->width, 0, &buf, asv->BGR_mode );
01045         buf.flags = SCL_DO_ALPHA ;
01046         for (i = 0; i < im->height; i++)
01047         {
01048                 int count = asimage_decode_line (im, IC_ALPHA, buf.alpha, i, 0, buf.width);
01049                 if( count < (int)buf.width )
01050                 {
01051                         if( ARGB32_ALPHA8(im->back_color) == 0 )
01052                         {
01053                                 if( recomended_depth == 0 )
01054                                         recomended_depth = 1 ;
01055                         }else if( ARGB32_ALPHA8(im->back_color) != 0xFF )
01056                         {
01057                                 recomended_depth = 8 ;
01058                                 break ;
01059                         }
01060                 }
01061                 while( --count >= 0 )
01062                         if( buf.alpha[count] == 0  )
01063                         {
01064                                 if( recomended_depth == 0 )
01065                                         recomended_depth = 1 ;
01066                         }else if( (buf.alpha[count]&0xFF) != 0xFF  )
01067                         {
01068                                 recomended_depth = 8 ;
01069                                 break ;
01070                         }
01071                 if( recomended_depth == 8 )
01072                         break;
01073         }
01074         free_scanline(&buf, True);
01075 
01076         return recomended_depth;
01077 }
01078 
01079 
01080 
01081 /* ********************************************************************************/
01082 /* Vector -> ASImage functions :                                                  */
01083 /* ********************************************************************************/
01084 Bool
01085 set_asimage_vector( ASImage *im, register double *vector )
01086 {
01087         if( vector == NULL || im == NULL )
01088                 return False;
01089 
01090         if( im->alt.vector == NULL )
01091                 im->alt.vector = safemalloc( im->width*im->height*sizeof(double));
01092 
01093         {
01094                 register double *dst = im->alt.vector ;
01095                 register int i = im->width*im->height;
01096                 while( --i >= 0 )
01097                         dst[i] = vector[i] ;
01098         }
01099 
01100         return True;
01101 }
01102 
01103 ASVectorPalette*
01104 vectorize_asimage( ASImage *im, unsigned int max_colors, unsigned int dither,
01105                                    int opaque_threshold )
01106 {
01107         ASVectorPalette* pal ;
01108         double *vec ;
01109         ASColormap cmap;
01110     unsigned int r, g, b, v;
01111         unsigned int x, y, j ;
01112 
01113         if( im->alt.vector == NULL )
01114                 im->alt.vector = safemalloc( im->width*im->height*sizeof(double));
01115         vec = im->alt.vector ;
01116 
01117         /* contributed by Valeriy Onuchin from Root project at cern.ch */   
01118 
01119         dither = dither > 7 ? 7 : dither;
01120         {
01121                 int *res = colormap_asimage(im, &cmap, max_colors, dither, opaque_threshold);
01122  
01123         for ( y = 0; y < im->height; y++) 
01124                 {
01125                 for ( x = 0; x < im->width; x++) 
01126                         {
01127                         int i = y*im->width + x;
01128                         g = INDEX_SHIFT_GREEN(cmap.entries[res[i]].green);
01129                         b = INDEX_SHIFT_BLUE(cmap.entries[res[i]].blue);
01130                         r = INDEX_SHIFT_RED(cmap.entries[res[i]].red);
01131                         v = MAKE_INDEXED_COLOR24(r,g,b);
01132                         v = (v>>12)&0x0FFF;
01133                         vec[(im->height - y - 1)*im->width + x] = ((double)v)/0x0FFF;
01134                 }
01135         }
01136         
01137                 free (res);
01138         }
01139     pal = safecalloc( 1, sizeof(ASVectorPalette));
01140 
01141         pal->npoints = cmap.count ;     
01142         pal->points = safemalloc( sizeof(double)*cmap.count);
01143         pal->channels[IC_RED] = safemalloc( sizeof(CARD16)*cmap.count);
01144         pal->channels[IC_GREEN] = safemalloc( sizeof(CARD16)*cmap.count);
01145         pal->channels[IC_BLUE] = safemalloc( sizeof(CARD16)*cmap.count);
01146         pal->channels[IC_ALPHA] = safemalloc( sizeof(CARD16)*cmap.count);
01147  
01148     for ( j = 0; j < cmap.count; j++) {
01149        g = INDEX_SHIFT_GREEN(cmap.entries[j].green);
01150        b = INDEX_SHIFT_BLUE(cmap.entries[j].blue);
01151        r = INDEX_SHIFT_RED(cmap.entries[j].red);
01152        v = MAKE_INDEXED_COLOR24(r,g,b);
01153  
01154        v = (v>>12)&0x0FFF;
01155        pal->points[j] = ((double)v)/0x0FFF;
01156                 /* palette uses 16 bit color values for greater precision */
01157        pal->channels[IC_RED][j] = cmap.entries[j].red<<QUANT_ERR_BITS;
01158        pal->channels[IC_GREEN][j] = cmap.entries[j].green<<QUANT_ERR_BITS;
01159        pal->channels[IC_BLUE][j] = cmap.entries[j].blue<<QUANT_ERR_BITS;
01160        pal->channels[IC_ALPHA][j] = 0xFFFF;
01161     }
01162  
01163     destroy_colormap(&cmap, True);
01164 
01165         return pal;
01166 }
01167 
01168 /* ********************************************************************************/
01169 /* Convinience function - very fast image cloning :                               */
01170 /* ********************************************************************************/
01171 ASImage*
01172 clone_asimage( ASImage *src, ASFlagType filter )
01173 {
01174         ASImage *dst = NULL ;
01175         START_TIME(started);
01176 
01177         if( !AS_ASSERT(src) )
01178         {
01179                 int chan ;
01180                 dst = create_asimage(src->width, src->height, 100);
01181                 if( get_flags( src->flags, ASIM_DATA_NOT_USEFUL ) )
01182                         set_flags( dst->flags, ASIM_DATA_NOT_USEFUL );
01183                 dst->back_color = src->back_color ;
01184                 for( chan = 0 ; chan < IC_NUM_CHANNELS;  chan++ )
01185                         if( get_flags( filter, 0x01<<chan) )
01186                         {
01187                                 register int i = dst->height;
01188                                 register ASStorageID *dst_rows = dst->channels[chan] ;
01189                                 register ASStorageID *src_rows = src->channels[chan] ;
01190                                 while( --i >= 0 )
01191                                         dst_rows[i] = dup_data( NULL, src_rows[i] );
01192                         }
01193         }
01194         SHOW_TIME("", started);
01195         return dst;
01196 }
01197 
01198 /* ********************************************************************************/
01199 /* Convinience function
01200  *              - generate rectangles list for channel values exceeding threshold:        */
01201 /* ********************************************************************************/
01202 XRectangle*
01203 get_asimage_channel_rects( ASImage *src, int channel, unsigned int threshold, unsigned int *rects_count_ret )
01204 {
01205         XRectangle *rects = NULL ;
01206         int rects_count = 0, rects_allocated = 0 ;
01207 
01208         START_TIME(started);
01209 
01210         if( !AS_ASSERT(src) && channel < IC_NUM_CHANNELS )
01211         {
01212                 int i = src->height;
01213                 ASStorageID  *src_rows = src->channels[channel] ;
01214                 unsigned int *height = safemalloc( (src->width+1)*2 * sizeof(unsigned int) );
01215                 unsigned int *prev_runs = NULL ;
01216                 int prev_runs_count = 0 ;
01217                 unsigned int *runs = safemalloc( (src->width+1)*2 * sizeof(unsigned int) );
01218                 unsigned int *tmp_runs = safemalloc( (src->width+1)*2 * sizeof(unsigned int) );
01219                 unsigned int *tmp_height = safemalloc( (src->width+1)*2 * sizeof(unsigned int) );
01220                 Bool count_empty = (ARGB32_CHAN8(src->back_color,channel)>= threshold);
01221 
01222 #ifdef DEBUG_RECTS
01223                 fprintf( stderr, "%d:back_color = #%8.8lX,  count_empty = %d, thershold = %d\n", __LINE__, src->back_color, count_empty, threshold );
01224 #endif
01225                 while( --i >= -1 )
01226                 {
01227                         int runs_count = 0 ;
01228 #ifdef DEBUG_RECTS
01229                         fprintf( stderr, "%d: LINE %d **********************\n", __LINE__, i );
01230 #ifdef DEBUG_RECTS2
01231                         asimage_print_line (src, channel, i, 0xFFFFFFFF);
01232 #else
01233                         asimage_print_line (src, channel, i, VRB_LINE_CONTENT);
01234 #endif
01235 #endif
01236                         if( i >= 0 )
01237                         {
01238                                 if( src_rows[i] )
01239                                 {
01240                                         runs_count = threshold_stored_data(NULL, src_rows[i], runs, src->width, threshold);
01241                                 }else if( count_empty )
01242                                 {
01243                                         runs_count = 2 ;
01244                                         runs[0] = 0 ;
01245                                         runs[1] = src->width ;
01246                                 }
01247                         }
01248 #ifdef DEBUG_RECTS
01249                         fprintf( stderr, "runs_count = %d\n", runs_count );
01250 #endif
01251                         if( runs_count > 0 && (runs_count &0x0001) != 0 )
01252                         {                                  /* allways wants to have even number of runs */
01253                                 runs[runs_count] = 0 ;
01254                                 ++runs_count ;
01255                         }
01256 
01257                         if( prev_runs_count > 0 )
01258                         { /* here we need to merge runs and add all the detached rectangles to the rects list */
01259                                 int k = 0, l = 0, last_k = 0 ;
01260                                 int tmp_count = 0 ;
01261                                 unsigned int *tmp ;
01262                                 if( runs_count == 0 )
01263                                 {
01264                                         runs[0] = src->width ;
01265                                         runs[1] = src->width ;
01266                                         runs_count = 2 ;
01267                                 }
01268                                 tmp_runs[0] = 0 ;
01269                                 tmp_runs[1] = src->width ;
01270                                 /* two passes : in first pass we go through old runs and try and see if they are continued
01271                                  * in this line. If not - we add them to the list of rectangles. At
01272                                  * the same time we subtract them from new line's runs : */
01273                                 for( l = 0 ; l < prev_runs_count ; ++l, ++l )
01274                                 {
01275                                         int start = prev_runs[l], end = prev_runs[l+1] ;
01276                                         int matching_runs = 0 ;
01277 #ifdef DEBUG_RECTS
01278                                         fprintf( stderr, "%d: prev run %d : start = %d, end = %d, last_k = %d, height = %d\n", __LINE__, l, start, end, last_k, height[l] );
01279 #endif
01280                                         for( k = last_k ; k < runs_count ; ++k, ++k )
01281                                         {
01282 #ifdef DEBUG_RECTS
01283                                                 fprintf( stderr, "*%d: new run %d : start = %d, end = %d\n", __LINE__, k, runs[k], runs[k+1] );
01284 #endif
01285                                                 if( (int)runs[k] > end )
01286                                                 {       /* add entire run to rectangles list */
01287                                                         if( rects_count >= rects_allocated )
01288                                                         {
01289                                                                 rects_allocated = rects_count + 8 + (rects_count>>3);
01290                                                                 rects = realloc( rects, rects_allocated*sizeof(XRectangle));
01291                                                         }
01292                                                         rects[rects_count].x = start ;
01293                                                         rects[rects_count].y = i+1 ;
01294                                                         rects[rects_count].width = (end-start)+1 ;
01295                                                         rects[rects_count].height = height[l] ;
01296 #ifdef DEBUG_RECTS
01297                                                         fprintf( stderr, "*%d: added rectangle at y = %d\n", __LINE__, rects[rects_count].y );
01298 #endif
01299                                                         ++rects_count ;
01300                                                         ++matching_runs;
01301                                                         break;
01302                                                 }else if( (int)runs[k+1] >= start  )
01303                                                 {
01304                                                         if( start < (int)runs[k] )
01305                                                         {       /* add rectangle start, , runs[k]-start, height[l] */
01306                                                                 if( rects_count >= rects_allocated )
01307                                                                 {
01308                                                                         rects_allocated = rects_count + 8 + (rects_count>>3);
01309                                                                         rects = realloc( rects, rects_allocated*sizeof(XRectangle));
01310                                                                 }
01311                                                                 rects[rects_count].x = start ;
01312                                                                 rects[rects_count].y = i+1 ;
01313                                                                 rects[rects_count].width = runs[k]-start ;
01314                                                                 rects[rects_count].height = height[l] ;
01315 #ifdef DEBUG_RECTS
01316                                                                 fprintf( stderr, "*%d: added rectangle at y = %d\n", __LINE__, rects[rects_count].y );
01317 #endif
01318                                                                 ++rects_count ;
01319                                                                 start = runs[k] ;
01320                                                         }else if( start > (int)runs[k] )
01321                                                         {
01322                                                                 tmp_runs[tmp_count] = runs[k] ;
01323                                                                 tmp_runs[tmp_count+1] = start-1 ;
01324                                                                 tmp_height[tmp_count] = 1 ;
01325 #ifdef DEBUG_RECTS
01326                                                                 fprintf( stderr, "*%d: tmp_run %d added : %d ... %d, height = %d\n", __LINE__, tmp_count, runs[k], start-1, 1 );
01327 #endif
01328                                                                 ++tmp_count ; ++tmp_count ;
01329                                                                 runs[k] = start ;
01330                                                         }
01331                                                         /* at that point both runs start at the same point */
01332                                                         if( end < (int)runs[k+1] )
01333                                                         {
01334                                                                 runs[k] = end+1 ;
01335                                                         }else 
01336                                                         {   
01337                                                                 if( end > (int)runs[k+1] )
01338                                                                 {       
01339                                                                         /* add rectangle runs[k+1]+1, , end - runs[k+1], height[l] */
01340                                                                         if( rects_count >= rects_allocated )
01341                                                                         {
01342                                                                                 rects_allocated = rects_count + 8 + (rects_count>>3);
01343                                                                                 rects = realloc( rects, rects_allocated*sizeof(XRectangle));
01344                                                                         }
01345                                                                         rects[rects_count].x = runs[k+1]+1 ;
01346                                                                         rects[rects_count].y = i+1 ;
01347                                                                         rects[rects_count].width = end - runs[k+1] ;
01348                                                                         rects[rects_count].height = height[l] ;
01349 #ifdef DEBUG_RECTS
01350                                                                         fprintf( stderr, "*%d: added rectangle at y = %d\n", __LINE__, rects[rects_count].y );
01351 #endif
01352                                                                         ++rects_count ;
01353                                                                         end = runs[k+1] ;
01354                                                                 
01355                                                                 } 
01356                                                                 /* eliminating new run - it was all used up :) */
01357                                                                 runs[k] = src->width ;
01358                                                                 runs[k+1] = src->width ;
01359 #ifdef DEBUG_RECTS
01360                                                                 fprintf( stderr, "*%d: eliminating new run %d\n", __LINE__, k );
01361 #endif
01362                                                                 ++k ; ++k ;
01363                                                         }
01364                                                         tmp_runs[tmp_count] = start ;
01365                                                         tmp_runs[tmp_count+1] = end ;
01366                                                         tmp_height[tmp_count] = height[l]+1 ;
01367 #ifdef DEBUG_RECTS
01368                                                         fprintf( stderr, "*%d: tmp_run %d added : %d ... %d, height = %d\n", __LINE__, tmp_count, start, end, height[l]+1 );
01369 #endif
01370                                                         ++tmp_count ; ++tmp_count ;
01371                                                         last_k = k ;
01372                                                         ++matching_runs;
01373                                                         break;
01374                                                 }
01375                                         }
01376                                         if( matching_runs == 0 ) 
01377                                         {  /* no new runs for this prev run - add rectangle */
01378 #ifdef DEBUG_RECTS
01379                                                 fprintf( stderr, "%d: NO MATCHING NEW RUNS : start = %d, end = %d, height = %d\n", __LINE__, start, end, height[l] );
01380 #endif
01381                                                 if( rects_count >= rects_allocated )
01382                                                 {
01383                                                         rects_allocated = rects_count + 8 + (rects_count>>3);
01384                                                         rects = realloc( rects, rects_allocated*sizeof(XRectangle));
01385                                                 }
01386                                                 rects[rects_count].x = start ;
01387                                                 rects[rects_count].y = i+1 ;
01388                                                 rects[rects_count].width = (end-start)+1 ;
01389                                                 rects[rects_count].height = height[l] ;
01390 #ifdef DEBUG_RECTS
01391                                                 fprintf( stderr, "*%d: added rectangle at y = %d\n", __LINE__, rects[rects_count].y );
01392 #endif
01393                                                 ++rects_count ;
01394                                         }        
01395                                 }
01396                                 /* second pass: we need to pick up remaining new runs */
01397                                 /* I think these should be inserted in oredrly manner so that we have runs list arranged in ascending order */
01398                                 for( k = 0 ; k < runs_count ; ++k, ++k )
01399                                         if( runs[k] < src->width )
01400                                         {
01401                                                 int ii = tmp_count ; 
01402                                                 while( ii > 0 && tmp_runs[ii-1] > runs[k] )
01403                                                 {
01404                                                         tmp_runs[ii] = tmp_runs[ii-2] ;
01405                                                         tmp_runs[ii+1] = tmp_runs[ii-1] ;
01406                                                         tmp_height[ii] = tmp_height[ii-2] ;
01407                                                         --ii ; --ii ;
01408                                                 }
01409                                                 tmp_runs[ii] = runs[k] ;
01410                                                 tmp_runs[ii+1] = runs[k+1] ;
01411                                                 tmp_height[ii] = 1 ;
01412 #ifdef DEBUG_RECTS
01413                                                 fprintf( stderr, "*%d: tmp_run %d added : %d ... %d, height = %d\n", __LINE__, ii, runs[k], runs[k+1], 1 );
01414 #endif
01415                                                 ++tmp_count, ++tmp_count;
01416                                         }
01417                                 tmp = prev_runs ;
01418                                 prev_runs = tmp_runs ;
01419                                 tmp_runs = tmp ;
01420                                 tmp = height ;
01421                                 height = tmp_height ;
01422                                 tmp_height = tmp ;
01423                                 prev_runs_count = tmp_count ;
01424                         }else if( runs_count > 0 )
01425                         {
01426                                 int k = runs_count;
01427                                 prev_runs_count = runs_count ;
01428                                 prev_runs = runs ;
01429                                 runs = safemalloc( (src->width+1)*2 * sizeof(unsigned int) );
01430                                 while( --k >= 0 )
01431                                         height[k] = 1 ;
01432                         }
01433                 }
01434                 free( runs );
01435                 if( prev_runs )
01436                         free( prev_runs );
01437                 free( tmp_runs );
01438                 free( tmp_height );
01439                 free( height );
01440         }
01441         SHOW_TIME("", started);
01442 
01443         if( rects_count_ret )
01444                 *rects_count_ret = rects_count ;
01445 
01446         return rects;
01447 }
01448 
01449 /***********************************************************************************/
01450 void
01451 raw2scanline( register CARD8 *row, ASScanline *buf, CARD8 *gamma_table, unsigned int width, Bool grayscale, Bool do_alpha )
01452 {
01453         register int x = width;
01454 
01455         if( grayscale )
01456                 row += do_alpha? width<<1 : width ;
01457         else
01458                 row += width*(do_alpha?4:3) ;
01459 
01460         if( gamma_table )
01461         {
01462                 if( !grayscale )
01463                 {
01464                         while ( --x >= 0 )
01465                         {
01466                                 row -= 3 ;
01467                                 if( do_alpha )
01468                                 {
01469                                         --row;
01470                                         buf->alpha[x] = row[3];
01471                                 }
01472                                 buf->xc1[x]  = gamma_table[row[0]];
01473                                 buf->xc2[x]= gamma_table[row[1]];
01474                                 buf->xc3[x] = gamma_table[row[2]];
01475                         }
01476                 }else /* greyscale */
01477                         while ( --x >= 0 )
01478                         {
01479                                 if( do_alpha )
01480                                         buf->alpha[x] = *(--row);
01481                                 buf->red [x] = gamma_table[*(--row)];
01482                         }
01483         }else
01484         {
01485                 if( !grayscale )
01486                 {
01487                         while ( --x >= 0 )
01488                         {
01489                                 row -= 3 ;
01490                                 if( do_alpha )
01491                                 {
01492                                         --row;
01493                                         buf->alpha[x] = row[3];
01494                                 }
01495                                 buf->xc1[x]  = row[0];
01496                                 buf->xc2[x]= row[1];
01497                                 buf->xc3[x] = row[2];
01498                         }
01499                 }else /* greyscale */
01500                         while ( --x >= 0 )
01501                         {
01502                                 if( do_alpha )
01503                                         buf->alpha[x] = *(--row);
01504                                 buf->red [x] = *(--row);
01505                         }
01506         }
01507 }
01508 
01509 /* ********************************************************************************/
01510 /* The end !!!!                                                                                                                                  */
01511 /* ********************************************************************************/
01512 

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