transform.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2000,2001 Sasha Vasko <sasha at aftercode.net>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 /*#undef NO_DEBUG_OUTPUT */
00019 #undef USE_STUPID_GIMP_WAY_DESTROYING_COLORS
00020 #undef LOCAL_DEBUG
00021 #undef DO_CLOCKING
00022 #undef DEBUG_HSV_ADJUSTMENT
00023 #define USE_64BIT_FPU
00024 #undef NEED_RBITSHIFT_FUNCS
00025 
00026 #ifdef _WIN32
00027 #include "win32/config.h"
00028 #else
00029 #include "config.h"
00030 #endif
00031 //#undef HAVE_MMX
00032 
00033 #ifdef DO_CLOCKING
00034 #if TIME_WITH_SYS_TIME
00035 # include <sys/time.h>
00036 # include <time.h>
00037 #else
00038 # if HAVE_SYS_TIME_H
00039 #  include <sys/time.h>
00040 # else
00041 #  include <time.h>
00042 # endif
00043 #endif
00044 #endif
00045 #ifdef HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 #ifdef HAVE_STDLIB_H
00049 #include <stdlib.h>
00050 #endif
00051 #ifdef HAVE_STDARG_H
00052 #include <stdarg.h>
00053 #endif
00054 #include <math.h>
00055 #include <string.h>
00056 
00057 #ifdef HAVE_MMX
00058 #include <mmintrin.h>
00059 #endif
00060 
00061 #ifdef _WIN32
00062 # include "win32/afterbase.h"
00063 #else
00064 # include "afterbase.h"
00065 #endif
00066 #include "asvisual.h"
00067 #include "blender.h"
00068 #include "asimage.h"
00069 #include "imencdec.h"
00070 #include "transform.h"
00071 
00072 ASVisual __transform_fake_asv = {0};
00073 
00074 
00075 /* ******************************************************************************/
00076 /* below goes all kinds of funky stuff we can do with scanlines :                          */
00077 /* ******************************************************************************/
00078 /* this will enlarge array based on count of items in dst per PAIR of src item with smoothing/scatter/dither */
00079 /* the following formulas use linear approximation to calculate   */
00080 /* color values for new pixels :                                                                  */
00081 /* for scale factor of 2 we use this formula :    */
00082 /* C = (-C1+3*C2+3*C3-C4)/4                                       */
00083 /* or better :                                                                    */
00084 /* C = (-C1+5*C2+5*C3-C4)/8                                       */
00085 #define INTERPOLATE_COLOR1(c)                           ((c)<<QUANT_ERR_BITS)  /* nothing really to interpolate here */
00086 #define INTERPOLATE_COLOR2(c1,c2,c3,c4)         ((((c2)<<2)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))<<(QUANT_ERR_BITS-3))
00087 #define INTERPOLATE_COLOR2_V(c1,c2,c3,c4)       ((((c2)<<2)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))>>3)
00088 /* for scale factor of 3 we use these formulas :  */
00089 /* Ca = (-2C1+8*C2+5*C3-2C4)/9                                    */
00090 /* Cb = (-2C1+5*C2+8*C3-2C4)/9                                    */
00091 /* or better :                                                                    */
00092 /* Ca = (-C1+5*C2+3*C3-C4)/6                                      */
00093 /* Cb = (-C1+3*C2+5*C3-C4)/6                                      */
00094 #define INTERPOLATE_A_COLOR3(c1,c2,c3,c4)       (((((c2)<<2)+(c2)+((c3)<<1)+(c3)-(c1)-(c4))<<QUANT_ERR_BITS)/6)
00095 #define INTERPOLATE_B_COLOR3(c1,c2,c3,c4)       (((((c2)<<1)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))<<QUANT_ERR_BITS)/6)
00096 #define INTERPOLATE_A_COLOR3_V(c1,c2,c3,c4)     ((((c2)<<2)+(c2)+((c3)<<1)+(c3)-(c1)-(c4))/6)
00097 #define INTERPOLATE_B_COLOR3_V(c1,c2,c3,c4)     ((((c2)<<1)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))/6)
00098 /* just a hypotesus, but it looks good for scale factors S > 3: */
00099 /* Cn = (-C1+(2*(S-n)+1)*C2+(2*n+1)*C3-C4)/2S                              */
00100 /* or :
00101  * Cn = (-C1+(2*S+1)*C2+C3-C4+n*(2*C3-2*C2)/2S                             */
00102 /*       [ T                   [C2s]  [C3s]]                           */
00103 #define INTERPOLATION_Cs(c)                                 ((c)<<1)
00104 /*#define INTERPOLATION_TOTAL_START(c1,c2,c3,c4,S)      (((S)<<1)*(c2)+((c3)<<1)+(c3)-c2-c1-c4)*/
00105 #define INTERPOLATION_TOTAL_START(c1,c2,c3,c4,S)        ((((S)<<1)+1)*(c2)+(c3)-(c1)-(c4))
00106 #define INTERPOLATION_TOTAL_STEP(c2,c3)         ((c3<<1)-(c2<<1))
00107 #define INTERPOLATE_N_COLOR(T,S)                        (((T)<<(QUANT_ERR_BITS-1))/(S))
00108 
00109 #define AVERAGE_COLOR1(c)                                       ((c)<<QUANT_ERR_BITS)
00110 #define AVERAGE_COLOR2(c1,c2)                           (((c1)+(c2))<<(QUANT_ERR_BITS-1))
00111 #define AVERAGE_COLORN(T,N)                                     (((T)<<QUANT_ERR_BITS)/N)
00112 
00113 static inline void
00114 enlarge_component12( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00115 {/* expected len >= 2  */
00116         register int i = 0, k = 0;
00117         register int c1 = src[0], c4;
00118         --len; --len ;
00119         while( i < len )
00120         {
00121                 c4 = src[i+2];
00122                 /* that's right we can do that PRIOR as we calculate nothing */
00123                 dst[k] = INTERPOLATE_COLOR1(src[i]) ;
00124                 if( scales[i] == 2 )
00125                 {
00126                         register int c2 = src[i], c3 = src[i+1] ;
00127                         c3 = INTERPOLATE_COLOR2(c1,c2,c3,c4);
00128                         dst[++k] = (c3&0xFF000000 )?0:c3;
00129                 }
00130                 c1 = src[i];
00131                 ++k;
00132                 ++i;
00133         }
00134 
00135         /* to avoid one more if() in loop we moved tail part out of the loop : */
00136         if( scales[i] == 1 )
00137                 dst[k] = INTERPOLATE_COLOR1(src[i]);
00138         else
00139         {
00140                 register int c2 = src[i], c3 = src[i+1] ;
00141                 c2 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
00142                 dst[k] = (c2&0xFF000000 )?0:c2;
00143         }
00144         dst[k+1] = INTERPOLATE_COLOR1(src[i+1]);
00145 }
00146 
00147 static inline void
00148 enlarge_component23( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00149 {/* expected len >= 2  */
00150         register int i = 0, k = 0;
00151         register int c1 = src[0], c4 = src[1];
00152         if( scales[0] == 1 )
00153         {/* special processing for first element - it can be 1 - others can only be 2 or 3 */
00154                 dst[k] = INTERPOLATE_COLOR1(src[0]) ;
00155                 ++k;
00156                 ++i;
00157         }
00158         --len; --len ;
00159         while( i < len )
00160         {
00161                 register int c2 = src[i], c3 = src[i+1] ;
00162                 c4 = src[i+2];
00163                 dst[k] = INTERPOLATE_COLOR1(c2) ;
00164                 if( scales[i] == 2 )
00165                 {
00166                         c3 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
00167                         dst[++k] = (c3&0x7F000000 )?0:c3;
00168                 }else
00169                 {
00170                         dst[++k] = INTERPOLATE_A_COLOR3(c1,c2,c3,c4);
00171                         if( dst[k]&0x7F000000 )
00172                                 dst[k] = 0 ;
00173                         c3 = INTERPOLATE_B_COLOR3(c1,c2,c3,c3);
00174                         dst[++k] = (c3&0x7F000000 )?0:c3;
00175                 }
00176                 c1 = c2 ;
00177                 ++k;
00178                 ++i;
00179         }
00180         /* to avoid one more if() in loop we moved tail part out of the loop : */
00181         {
00182                 register int c2 = src[i], c3 = src[i+1] ;
00183                 dst[k] = INTERPOLATE_COLOR1(c2) ;
00184                 if( scales[i] == 2 )
00185                 {
00186                         c2 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
00187                         dst[k+1] = (c2&0x7F000000 )?0:c2;
00188                 }else
00189                 {
00190                         if( scales[i] == 1 )
00191                                 --k;
00192                         else
00193                         {
00194                                 dst[++k] = INTERPOLATE_A_COLOR3(c1,c2,c3,c3);
00195                                 if( dst[k]&0x7F000000 )
00196                                         dst[k] = 0 ;
00197                                 c2 = INTERPOLATE_B_COLOR3(c1,c2,c3,c3);
00198                                 dst[k+1] = (c2&0x7F000000 )?0:c2;
00199                         }
00200                 }
00201         }
00202         dst[k+2] = INTERPOLATE_COLOR1(src[i+1]) ;
00203 }
00204 
00205 /* this case is more complex since we cannot really hardcode coefficients
00206  * visible artifacts on smooth gradient-like images
00207  */
00208 static inline void
00209 enlarge_component( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00210 {/* we skip all checks as it is static function and we want to optimize it
00211   * as much as possible */
00212         int i = 0;
00213         int c1 = src[0];
00214         register int T ;
00215         --len ;
00216         if( len < 1 )
00217         {
00218                 CARD32 c = INTERPOLATE_COLOR1(c1) ;
00219                 for( i = 0 ; i < scales[0] ; ++i )
00220                         dst[i] = c;
00221                 return;
00222         }
00223         do
00224         {
00225                 register short S = scales[i];
00226                 register int step = INTERPOLATION_TOTAL_STEP(src[i],src[i+1]);
00227 
00228                 if( i+1 == len )
00229                         T = INTERPOLATION_TOTAL_START(c1,src[i],src[i+1],src[i+1],S);
00230                 else
00231                         T = INTERPOLATION_TOTAL_START(c1,src[i],src[i+1],src[i+2],S);
00232 
00233 /*              LOCAL_DEBUG_OUT( "pixel %d, S = %d, step = %d", i, S, step );*/
00234                 if( step )
00235                 {
00236                         register int n = 0 ;
00237                         do
00238                         {
00239                                 dst[n] = (T&0x7F000000)?0:INTERPOLATE_N_COLOR(T,S);
00240                                 if( ++n >= S ) break;
00241                                 T = (int)T + (int)step;
00242                         }while(1);
00243                         dst += n ;
00244                 }else
00245                 {
00246                         register CARD32 c = (T&0x7F000000)?0:INTERPOLATE_N_COLOR(T,S);
00247                         while(--S >= 0){        dst[S] = c;     }
00248                         dst += scales[i] ;
00249                 }
00250                 c1 = src[i];
00251         }while(++i < len );
00252         *dst = INTERPOLATE_COLOR1(src[i]) ;
00253 /*LOCAL_DEBUG_OUT( "%d pixels written", k );*/
00254 }
00255 
00256 static inline void
00257 enlarge_component_dumb( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00258 {/* we skip all checks as it is static function and we want to optimize it
00259   * as much as possible */
00260         int i = 0, k = 0;
00261         do
00262         {
00263                 register CARD32 c = INTERPOLATE_COLOR1(src[i]);
00264                 int max_k = k+scales[i];
00265                 do
00266                 {
00267                         dst[k] = c ;
00268                 }while( ++k < max_k );
00269         }while( ++i < len );
00270 }
00271 
00272 /* this will shrink array based on count of items in src per one dst item with averaging */
00273 static inline void
00274 shrink_component( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00275 {/* we skip all checks as it is static function and we want to optimize it
00276   * as much as possible */
00277         register int i = -1, k = -1;
00278         while( ++k < len )
00279         {
00280                 register int reps = scales[k] ;
00281                 register int c1 = src[++i];
00282 /*LOCAL_DEBUG_OUT( "pixel = %d, scale[k] = %d", k, reps );*/
00283                 if( reps == 1 )
00284                         dst[k] = AVERAGE_COLOR1(c1);
00285                 else if( reps == 2 )
00286                 {
00287                         ++i;
00288                         dst[k] = AVERAGE_COLOR2(c1,src[i]);
00289                 }else
00290                 {
00291                         reps += i-1;
00292                         while( reps > i )
00293                         {
00294                                 ++i ;
00295                                 c1 += src[i];
00296                         }
00297                         {
00298                                 register short S = scales[k];
00299                                 dst[k] = AVERAGE_COLORN(c1,S);
00300                         }
00301                 }
00302         }
00303 }
00304 static inline void
00305 shrink_component11( register CARD32 *src, register CARD32 *dst, int *scales, int len )
00306 {
00307         register int i ;
00308         for( i = 0 ; i < len ; ++i )
00309                 dst[i] = AVERAGE_COLOR1(src[i]);
00310 }
00311 
00312 
00313 static inline void
00314 reverse_component( register CARD32 *src, register CARD32 *dst, int *unused, int len )
00315 {
00316         register int i = 0;
00317         src += len-1 ;
00318         do
00319         {
00320                 dst[i] = src[-i];
00321         }while(++i < len );
00322 }
00323 
00324 static inline void
00325 add_component( CARD32 *src, CARD32 *incr, int *scales, int len )
00326 {
00327         len += len&0x01;
00328 #ifdef HAVE_MMX   
00329 #if 1
00330         if( asimage_use_mmx )
00331         {
00332                 int i = 0;
00333                 __m64  *vdst = (__m64*)&(src[0]);
00334                 __m64  *vinc = (__m64*)&(incr[0]);
00335                 len = len>>1;
00336                 do{
00337                         vdst[i] = _mm_add_pi32(vdst[i],vinc[i]);  /* paddd */
00338                 }while( ++i  < len );
00339                 _mm_empty();
00340         }else
00341 #else
00342         if( asimage_use_mmx )
00343         {
00344                 double *ddst = (double*)&(src[0]);
00345                 double *dinc = (double*)&(incr[0]);
00346                 len = len>>1;
00347                 do{
00348                         asm volatile
00349                 (
00350                 "movq %0, %%mm0  \n\t" /* load 8 bytes from src[i] into MM0 */
00351                 "paddd %1, %%mm0 \n\t" /* MM0=src[i]>>1              */
00352                 "movq %%mm0, %0  \n\t" /* store the result in dest */
00353                                 : "=m" (ddst[i])       /* %0 */
00354                                 :  "m"  (dinc[i])       /* %2 */
00355                 );
00356                 }while( ++i < len );
00357         }else
00358 #endif
00359 #endif
00360         {
00361                 register int c1, c2;
00362                 int i = 0;
00363                 do{
00364                         c1 = (int)src[i] + (int)incr[i] ;
00365                         c2 = (int)src[i+1] + (int)incr[i+1] ;
00366                         src[i] = c1;
00367                         src[i+1] = c2;
00368                         i += 2 ;
00369                 }while( i < len );
00370         }
00371 }
00372 
00373 #ifdef NEED_RBITSHIFT_FUNCS
00374 static inline void
00375 rbitshift_component( register CARD32 *src, register CARD32 *dst, int shift, int len )
00376 {
00377         register int i ;
00378         for( i = 0 ; i < len ; ++i )
00379                 dst[i] = src[i]>>shift;
00380 }
00381 #endif
00382 
00383 static inline void
00384 start_component_interpolation( CARD32 *c1, CARD32 *c2, CARD32 *c3, CARD32 *c4, register CARD32 *T, register CARD32 *step, int S, int len)
00385 {
00386         register int i;
00387         for( i = 0 ; i < len ; i++ )
00388         {
00389                 register int rc2 = c2[i], rc3 = c3[i] ;
00390                 T[i] = INTERPOLATION_TOTAL_START(c1[i],rc2,rc3,c4[i],S)/(S<<1);
00391                 step[i] = INTERPOLATION_TOTAL_STEP(rc2,rc3)/(S<<1);
00392         }
00393 }
00394 
00395 static inline void
00396 component_interpolation_hardcoded( CARD32 *c1, CARD32 *c2, CARD32 *c3, CARD32 *c4, register CARD32 *T, CARD32 *unused, CARD16 kind, int len)
00397 {
00398         register int i;
00399         if( kind == 1 )
00400         {
00401                 for( i = 0 ; i < len ; i++ )
00402                 {
00403 #if 1
00404                         /* its seems that this simple formula is completely sufficient
00405                            and even better then more complicated one : */
00406                         T[i] = (c2[i]+c3[i])>>1 ;
00407 #else
00408                 register int minus = c1[i]+c4[i] ;
00409                         register int plus  = (c2[i]<<1)+c2[i]+(c3[i]<<1)+c3[i];
00410 
00411                         T[i] = ( (plus>>1) < minus )?(c2[i]+c3[i])>>1 :
00412                                                                                  (plus-minus)>>2;
00413 #endif
00414                 }
00415         }else if( kind == 2 )
00416         {
00417                 for( i = 0 ; i < len ; i++ )
00418                 {
00419                 register int rc1 = c1[i], rc2 = c2[i], rc3 = c3[i] ;
00420                         T[i] = INTERPOLATE_A_COLOR3_V(rc1,rc2,rc3,c4[i]);
00421                 }
00422         }else
00423                 for( i = 0 ; i < len ; i++ )
00424                 {
00425                 register int rc1 = c1[i], rc2 = c2[i], rc3 = c3[i] ;
00426                         T[i] = INTERPOLATE_B_COLOR3_V(rc1,rc2,rc3,c4[i]);
00427                 }
00428 }
00429 
00430 #ifdef NEED_RBITSHIFT_FUNCS
00431 static inline void
00432 divide_component_mod( register CARD32 *data, CARD16 ratio, int len )
00433 {
00434         register int i ;
00435         for( i = 0 ; i < len ; ++i )
00436                 data[i] /= ratio;
00437 }
00438 
00439 static inline void
00440 rbitshift_component_mod( register CARD32 *data, int bits, int len )
00441 {
00442         register int i ;
00443         for( i = 0 ; i < len ; ++i )
00444                 data[i] = data[i]>>bits;
00445 }
00446 #endif
00447 void
00448 print_component( register CARD32 *data, int nonsense, int len )
00449 {
00450         register int i ;
00451         for( i = 0 ; i < len ; ++i )
00452                 fprintf( stderr, " %8.8lX", (long)data[i] );
00453         fprintf( stderr, "\n");
00454 }
00455 
00456 static inline void
00457 tint_component_mod( register CARD32 *data, CARD16 ratio, int len )
00458 {
00459         register int i ;
00460         if( ratio == 255 )
00461                 for( i = 0 ; i < len ; ++i )
00462                         data[i] = data[i]<<8;
00463         else if( ratio == 128 )
00464                 for( i = 0 ; i < len ; ++i )
00465                         data[i] = data[i]<<7;
00466         else if( ratio == 0 )
00467                 for( i = 0 ; i < len ; ++i )
00468                         data[i] = 0;
00469         else
00470                 for( i = 0 ; i < len ; ++i )
00471                         data[i] = data[i]*ratio;
00472 }
00473 
00474 static inline void
00475 make_component_gradient16( register CARD32 *data, CARD16 from, CARD16 to, CARD8 seed, int len )
00476 {
00477         register int i ;
00478         long incr = (((long)to<<8)-((long)from<<8))/len ;
00479 
00480         if( incr == 0 )
00481                 for( i = 0 ; i < len ; ++i )
00482                         data[i] = from;
00483         else
00484         {
00485                 long curr = from<<8;
00486                 curr += ((long)(((CARD32)seed)<<8) > incr)?incr:((CARD32)seed)<<8 ;
00487                 for( i = 0 ; i < len ; ++i )
00488                 {/* we make calculations in 24bit per chan, then convert it back to 16 and
00489                   * carry over half of the quantization error onto the next pixel */
00490                         data[i] = curr>>8;
00491                         curr += ((curr&0x00FF)>>1)+incr ;
00492                 }
00493         }
00494 }
00495 
00496 
00497 static inline void
00498 copytintpad_scanline( ASScanline *src, ASScanline *dst, int offset, ARGB32 tint )
00499 {
00500         register int i ;
00501         CARD32 chan_tint[4], chan_fill[4] ;
00502         int color ;
00503         int copy_width = src->width, dst_offset = 0, src_offset = 0;
00504 
00505         if( offset+(int)src->width < 0 || offset > (int)dst->width )
00506                 return;
00507         chan_tint[IC_RED]   = ARGB32_RED8  (tint)<<1;
00508         chan_tint[IC_GREEN] = ARGB32_GREEN8(tint)<<1;
00509         chan_tint[IC_BLUE]  = ARGB32_BLUE8 (tint)<<1;
00510         chan_tint[IC_ALPHA] = ARGB32_ALPHA8(tint)<<1;
00511         chan_fill[IC_RED]   = ARGB32_RED8  (dst->back_color)<<dst->shift;
00512         chan_fill[IC_GREEN] = ARGB32_GREEN8(dst->back_color)<<dst->shift;
00513         chan_fill[IC_BLUE]  = ARGB32_BLUE8 (dst->back_color)<<dst->shift;
00514         chan_fill[IC_ALPHA] = ARGB32_ALPHA8(dst->back_color)<<dst->shift;
00515         if( offset < 0 )
00516                 src_offset = -offset ;
00517         else
00518                 dst_offset = offset ;
00519         copy_width = MIN( src->width-src_offset, dst->width-dst_offset );
00520 
00521         dst->flags = src->flags ;
00522         for( color = 0 ; color < IC_NUM_CHANNELS ; ++color )
00523         {
00524                 register CARD32 *psrc = src->channels[color]+src_offset;
00525                 register CARD32 *pdst = dst->channels[color];
00526                 int ratio = chan_tint[color];
00527 /*      fprintf( stderr, "channel %d, tint is %d(%X), src_width = %d, src_offset = %d, dst_width = %d, dst_offset = %d psrc = %p, pdst = %p\n", color, ratio, ratio, src->width, src_offset, dst->width, dst_offset, psrc, pdst );
00528 */
00529                 {
00530 /*                      register CARD32 fill = chan_fill[color]; */
00531                         for( i = 0 ; i < dst_offset ; ++i )
00532                                 pdst[i] = 0;
00533                         pdst += dst_offset ;
00534                 }
00535 
00536                 if( get_flags(src->flags, 0x01<<color) )
00537                 {
00538                         if( ratio >= 254 )
00539                                 for( i = 0 ; i < copy_width ; ++i )
00540                                         pdst[i] = psrc[i]<<8;
00541                         else if( ratio == 128 )
00542                                 for( i = 0 ; i < copy_width ; ++i )
00543                                         pdst[i] = psrc[i]<<7;
00544                         else if( ratio == 0 )
00545                                 for( i = 0 ; i < copy_width ; ++i )
00546                                         pdst[i] = 0;
00547                         else
00548                                 for( i = 0 ; i < copy_width ; ++i )
00549                                         pdst[i] = psrc[i]*ratio;
00550                 }else
00551                 {
00552                     ratio = ratio*chan_fill[color];
00553                         for( i = 0 ; i < copy_width ; ++i )
00554                                 pdst[i] = ratio;
00555                         set_flags( dst->flags, (0x01<<color));
00556                 }
00557                 {
00558 /*                      register CARD32 fill = chan_fill[color]; */
00559                         for( ; i < (int)dst->width-dst_offset ; ++i )
00560                                 pdst[i] = 0;
00561 /*                              print_component(pdst, 0, dst->width ); */
00562                 }
00563         }
00564 }
00565 
00566 /* **********************************************************************************************/
00567 /* drawing gradient on scanline :                                                                                                                          */
00568 /* **********************************************************************************************/
00569 void
00570 make_gradient_scanline( ASScanline *scl, ASGradient *grad, ASFlagType filter, ARGB32 seed )
00571 {
00572         if( scl && grad && filter != 0 )
00573         {
00574                 int offset = 0, step, i, max_i = grad->npoints - 1 ;
00575                 ARGB32 last_color = ARGB32_Black ;
00576                 int last_idx = 0;
00577                 double last_offset = 0., *offsets = grad->offset ;
00578                 int *used = safecalloc(max_i+1, sizeof(int));
00579                 /* lets find the color of the very first point : */
00580                 for( i = 0 ; i <= max_i ; ++i )
00581                         if( offsets[i] <= 0. )
00582                         {
00583                                 last_color = grad->color[i] ;
00584                                 last_idx = i ;
00585                                 used[i] = 1 ;
00586                                 break;
00587                         }
00588 
00589                 for( i = 0  ; i <= max_i ; i++ )
00590                 {
00591                         register int k ;
00592                         int new_idx = -1 ;
00593                         /* now lets find the next point  : */
00594                         for( k = 0 ; k <= max_i ; ++k )
00595                         {
00596                                 if( used[k]==0 && offsets[k] >= last_offset )
00597                                 {
00598                                         if( new_idx < 0 )
00599                                                 new_idx = k ;
00600                                         else if( offsets[new_idx] > offsets[k] )
00601                                                 new_idx = k ;
00602                                         else
00603                                         {
00604                                                 register int d1 = new_idx-last_idx ;
00605                                                 register int d2 = k - last_idx ;
00606                                                 if( d1*d1 > d2*d2 )
00607                                                         new_idx = k ;
00608                                         }
00609                                 }
00610                         }
00611                         if( new_idx < 0 )
00612                                 break;
00613                         used[new_idx] = 1 ;
00614                         step = (int)((grad->offset[new_idx] * (double)scl->width) - (double)offset) ;
00615 /*                      fprintf( stderr, __FUNCTION__":%d>last_offset = %f, last_color = %8.8X, new_idx = %d, max_i = %d, new_offset = %f, new_color = %8.8X, step = %d, offset = %d\n", __LINE__, last_offset, last_color, new_idx, max_i, offsets[new_idx], grad->color[new_idx], step, offset ); */
00616                         if( step > (int)scl->width-offset )
00617                                 step = (int)scl->width-offset ;
00618                         if( step > 0 )
00619                         {
00620                                 int color ;
00621                                 for( color = 0 ; color < IC_NUM_CHANNELS ; ++color )
00622                                         if( get_flags( filter, 0x01<<color ) )
00623                                         {
00624                                                 LOCAL_DEBUG_OUT("channel %d from #%4.4lX to #%4.4lX, ofset = %d, step = %d",
00625                                                                                         color, ARGB32_CHAN8(last_color,color)<<8, ARGB32_CHAN8(grad->color[new_idx],color)<<8, offset, step );
00626                                                 make_component_gradient16( scl->channels[color]+offset,
00627                                                                                                    (CARD16)(ARGB32_CHAN8(last_color,color)<<8),
00628                                                                                                    (CARD16)(ARGB32_CHAN8(grad->color[new_idx],color)<<8),
00629                                                                                                    (CARD8)ARGB32_CHAN8(seed,color),
00630                                                                                                    step);
00631                                         }
00632                                 offset += step ;
00633                         }
00634                         last_offset = offsets[new_idx];
00635                         last_color = grad->color[new_idx];
00636                         last_idx = new_idx ;
00637                 }
00638                 scl->flags = filter ;
00639                 free( used );
00640         }
00641 }
00642 
00643 /* **********************************************************************************************/
00644 /* Scaling code ;                                                                                                                                                          */
00645 /* **********************************************************************************************/
00646 Bool
00647 check_scale_parameters( ASImage *src, int src_width, int src_height, int *to_width, int *to_height )
00648 {
00649         if( src == NULL )
00650                 return False;
00651 
00652         if( *to_width == 0 )
00653                 *to_width = src_width ;
00654         else if( *to_width < 2 )
00655                 *to_width = 2 ;
00656         if( *to_height == 0 )
00657                 *to_height = src_height ;
00658         else if( *to_height < 2 )
00659                 *to_height = 2 ;
00660         return True;
00661 }
00662 
00663 int *
00664 make_scales( int from_size, int to_size, int tail )
00665 {
00666         int *scales ;
00667     int smaller = MIN(from_size,to_size);
00668     int bigger  = MAX(from_size,to_size);
00669         register int i = 0, k = 0;
00670         int eps;
00671     LOCAL_DEBUG_OUT( "from %d to %d tail %d", from_size, to_size, tail );
00672         scales = safecalloc( smaller+tail, sizeof(int));
00673         if( smaller <= 1 ) 
00674         {
00675                 scales[0] = bigger ; 
00676                 return scales;
00677         }
00678 #if 1
00679         else if( smaller == bigger )
00680         {
00681                 for ( i = 0 ; i < smaller ; i++ )
00682                         scales[i] = 1 ; 
00683                 return scales;  
00684         }
00685 #endif
00686         if( from_size >= to_size )
00687                 tail = 0 ;
00688         if( tail != 0 )
00689     {
00690         bigger-=tail ;
00691         if( (smaller-=tail) == 1 ) 
00692                 {
00693                         scales[0] = bigger ; 
00694                         return scales;
00695                 }       
00696     }else if( smaller == 2 ) 
00697         {
00698                 scales[1] = bigger/2 ; 
00699                 scales[0] = bigger - scales[1] ; 
00700                 return scales ;
00701         }
00702 
00703     eps = -bigger/2;
00704     LOCAL_DEBUG_OUT( "smaller %d, bigger %d, eps %d", smaller, bigger, eps );
00705     /* now using Bresengham algoritm to fiill the scales :
00706          * since scaling is merely transformation
00707          * from 0:bigger space (x) to 0:smaller space(y)*/
00708         for ( i = 0 ; i < bigger ; i++ )
00709         {
00710                 ++scales[k];
00711                 eps += smaller;
00712         LOCAL_DEBUG_OUT( "scales[%d] = %d, i = %d, k = %d, eps %d", k, scales[k], i, k, eps );
00713         if( eps+eps >= bigger )
00714                 {
00715                         ++k ;
00716                         eps -= bigger ;
00717                 }
00718         }
00719 
00720         return scales;
00721 }
00722 
00723 /* *******************************************************************/
00724 void
00725 scale_image_down( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
00726 {
00727         ASScanline dst_line, total ;
00728         int k = -1;
00729         int max_k        = imout->im->height,
00730                 line_len = MIN(imout->im->width, imdec->out_width);
00731 
00732         prepare_scanline( imout->im->width, QUANT_ERR_BITS, &dst_line, imout->asv->BGR_mode );
00733         prepare_scanline( imout->im->width, QUANT_ERR_BITS, &total, imout->asv->BGR_mode );
00734         while( ++k < max_k )
00735         {
00736                 int reps = scales_v[k] ;
00737                 imdec->decode_image_scanline( imdec );
00738                 total.flags = imdec->buffer.flags ;
00739                 CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,total,scales_h,line_len);
00740 
00741                 while( --reps > 0 )
00742                 {
00743                         imdec->decode_image_scanline( imdec );
00744                         total.flags = imdec->buffer.flags ;
00745                         CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,dst_line,scales_h,line_len);
00746                         SCANLINE_FUNC(add_component,total,dst_line,NULL,total.width);
00747                 }
00748 
00749                 imout->output_image_scanline( imout, &total, scales_v[k] );
00750         }
00751         free_scanline(&dst_line, True);
00752         free_scanline(&total, True);
00753 }
00754 
00755 void
00756 scale_image_up( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
00757 {
00758         ASScanline src_lines[4], *c1, *c2, *c3, *c4 = NULL;
00759         int i = 0, max_i,
00760                 line_len = MIN(imout->im->width, imdec->out_width),
00761                 out_width = imout->im->width;
00762         ASScanline step ;
00763 
00764         prepare_scanline( out_width, 0, &(src_lines[0]), imout->asv->BGR_mode);
00765         prepare_scanline( out_width, 0, &(src_lines[1]), imout->asv->BGR_mode);
00766         prepare_scanline( out_width, 0, &(src_lines[2]), imout->asv->BGR_mode);
00767         prepare_scanline( out_width, 0, &(src_lines[3]), imout->asv->BGR_mode);
00768         prepare_scanline( out_width, QUANT_ERR_BITS, &step, imout->asv->BGR_mode );
00769 
00770 /*      set_component(src_lines[0].red,0x00000000,0,out_width*3); */
00771         imdec->decode_image_scanline( imdec );
00772         src_lines[1].flags = imdec->buffer.flags ;
00773         CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_lines[1],scales_h,line_len);
00774 
00775         step.flags = src_lines[0].flags = src_lines[1].flags ;
00776 
00777         SCANLINE_FUNC(copy_component,src_lines[1],src_lines[0],0,out_width);
00778 
00779         imdec->decode_image_scanline( imdec );
00780         src_lines[2].flags = imdec->buffer.flags ;
00781         CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_lines[2],scales_h,line_len);
00782 
00783         i = 0 ;
00784         max_i = imdec->out_height-1 ;
00785         LOCAL_DEBUG_OUT( "i = %d, max_i = %d", i, max_i );
00786         do
00787         {
00788                 int S = scales_v[i] ;
00789                 c1 = &(src_lines[i&0x03]);
00790                 c2 = &(src_lines[(i+1)&0x03]);
00791                 c3 = &(src_lines[(i+2)&0x03]);
00792                 c4 = &(src_lines[(i+3)&0x03]);
00793 
00794                 if( i+1 < max_i )
00795                 {
00796                         imdec->decode_image_scanline( imdec );
00797                         c4->flags = imdec->buffer.flags ;
00798                         CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,*c4,scales_h,line_len);
00799                 }
00800                 /* now we'll prepare total and step : */
00801         if( S > 0 )
00802         {
00803             imout->output_image_scanline( imout, c2, 1);
00804             if( S > 1 )
00805             {
00806                 if( S == 2 )
00807                 {
00808                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,1,out_width);
00809                     imout->output_image_scanline( imout, c1, 1);
00810                 }else if( S == 3 )
00811                 {
00812                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,2,out_width);
00813                     imout->output_image_scanline( imout, c1, 1);
00814                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,3,out_width);
00815                     imout->output_image_scanline( imout, c1, 1);
00816                 }else
00817                 {
00818                     SCANLINE_COMBINE(start_component_interpolation,*c1,*c2,*c3,*c4,*c1,step,S,out_width);
00819                     do
00820                     {
00821                         imout->output_image_scanline( imout, c1, 1);
00822                         if((--S)<=1)
00823                             break;
00824                         SCANLINE_FUNC(add_component,*c1,step,NULL,out_width );
00825                     }while(1);
00826                 }
00827             }
00828         }
00829         }while( ++i < max_i );
00830     imout->output_image_scanline( imout, c3, 1);
00831         free_scanline(&step, True);
00832         free_scanline(&(src_lines[3]), True);
00833         free_scanline(&(src_lines[2]), True);
00834         free_scanline(&(src_lines[1]), True);
00835         free_scanline(&(src_lines[0]), True);
00836 }
00837 
00838 void
00839 scale_image_up_dumb( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
00840 {
00841         ASScanline src_line;
00842         int     line_len = MIN(imout->im->width, imdec->out_width);
00843         int     out_width = imout->im->width;
00844         int y = 0 ;
00845 
00846         prepare_scanline( out_width, QUANT_ERR_BITS, &src_line, imout->asv->BGR_mode );
00847 
00848         imout->tiling_step = 1 ;
00849         LOCAL_DEBUG_OUT( "imdec->next_line = %d, imdec->out_height = %d", imdec->next_line, imdec->out_height );
00850         while( y < (int)imdec->out_height )
00851         {
00852                 imdec->decode_image_scanline( imdec );
00853                 src_line.flags = imdec->buffer.flags ;
00854                 CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_line,scales_h,line_len);
00855                 imout->tiling_range = scales_v[y];
00856                 LOCAL_DEBUG_OUT( "y = %d, tiling_range = %d", y, imout->tiling_range );
00857                 imout->output_image_scanline( imout, &src_line, 1);
00858                 imout->next_line += scales_v[y]-1;
00859                 ++y;
00860         }
00861         free_scanline(&src_line, True);
00862 }
00863 
00864 
00865 static inline ASImage *
00866 create_destination_image( unsigned int width, unsigned int height, ASAltImFormats format, 
00867                                                   unsigned int compression, ARGB32 back_color )
00868 {
00869         ASImage *dst = create_asimage(width, height, compression);
00870         if( dst )
00871         {
00872                 if( format != ASA_ASImage )
00873                         set_flags( dst->flags, ASIM_DATA_NOT_USEFUL );
00874         
00875                 dst->back_color = back_color ;
00876         }
00877         return dst ;
00878 }
00879                                                   
00880 
00881 /* *****************************************************************************/
00882 /* ASImage transformations :                                                                                              */
00883 /* *****************************************************************************/
00884 ASImage *
00885 scale_asimage( ASVisual *asv, ASImage *src, int to_width, int to_height,
00886                            ASAltImFormats out_format, unsigned int compression_out, int quality )
00887 {
00888         ASImage *dst = NULL ;
00889         ASImageOutput  *imout ;
00890         ASImageDecoder *imdec;
00891         int h_ratio ;
00892         int *scales_h = NULL, *scales_v = NULL;
00893         START_TIME(started);
00894         
00895         if( asv == NULL )       asv = &__transform_fake_asv ;
00896         
00897         if( !check_scale_parameters(src,src->width, src->height,&to_width,&to_height) )
00898                 return NULL;
00899         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, 0, 0, NULL)) == NULL )
00900                 return NULL;
00901 
00902         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
00903 
00904         if( to_width == src->width )
00905                 h_ratio = 0;
00906         else if( to_width < src->width )
00907                 h_ratio = 1;
00908         else
00909         {
00910                 if ( quality == ASIMAGE_QUALITY_POOR )
00911                         h_ratio = 1 ;
00912                 else if( src->width > 1 )
00913                 {
00914                         h_ratio = (to_width/(src->width-1))+1;
00915                         if( h_ratio*(src->width-1) < to_width )
00916                                 ++h_ratio ;
00917                 }else
00918                         h_ratio = to_width ;
00919                 ++h_ratio ;
00920         }
00921         scales_h = make_scales( src->width, to_width, ( quality == ASIMAGE_QUALITY_POOR )?0:1 );
00922         scales_v = make_scales( src->height, to_height, ( quality == ASIMAGE_QUALITY_POOR  || src->height <= 3)?0:1 );
00923 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
00924         {
00925           register int i ;
00926           for( i = 0 ; i < MIN(src->width, to_width) ; i++ )
00927                 fprintf( stderr, " %d", scales_h[i] );
00928           fprintf( stderr, "\n" );
00929           for( i = 0 ; i < MIN(src->height, to_height) ; i++ )
00930                 fprintf( stderr, " %d", scales_v[i] );
00931           fprintf( stderr, "\n" );
00932         }
00933 #endif
00934         if((imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality )) == NULL )
00935         {
00936         destroy_asimage( &dst );
00937         }else
00938         {
00939                 if( to_height <= src->height )                                     /* scaling down */
00940                         scale_image_down( imdec, imout, h_ratio, scales_h, scales_v );
00941                 else if( quality == ASIMAGE_QUALITY_POOR || src->height <= 3 ) 
00942                         scale_image_up_dumb( imdec, imout, h_ratio, scales_h, scales_v );
00943                 else
00944                         scale_image_up( imdec, imout, h_ratio, scales_h, scales_v );
00945                 stop_image_output( &imout );
00946         }
00947         free( scales_h );
00948         free( scales_v );
00949         stop_image_decoding( &imdec );
00950         SHOW_TIME("", started);
00951         return dst;
00952 }
00953 
00954 ASImage *
00955 scale_asimage2( ASVisual *asv, ASImage *src, 
00956                                         int clip_x, int clip_y, 
00957                                         int clip_width, int clip_height, 
00958                                         int to_width, int to_height,
00959                                         ASAltImFormats out_format, unsigned int compression_out, int quality )
00960 {
00961         ASImage *dst = NULL ;
00962         ASImageOutput  *imout ;
00963         ASImageDecoder *imdec;
00964         int h_ratio ;
00965         int *scales_h = NULL, *scales_v = NULL;
00966         START_TIME(started);
00967 
00968         if( src == NULL ) 
00969                 return NULL;
00970 
00971         if( asv == NULL )       asv = &__transform_fake_asv ;
00972 
00973         if( clip_width == 0 )
00974                 clip_width = src->width ;
00975         if( clip_height == 0 )
00976                 clip_height = src->height ;
00977         if( !check_scale_parameters(src, clip_width, clip_height, &to_width, &to_height) )
00978                 return NULL;
00979         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, clip_height, NULL)) == NULL )
00980                 return NULL;
00981 
00982         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
00983 
00984         if( to_width == clip_width )
00985                 h_ratio = 0;
00986         else if( to_width < clip_width )
00987                 h_ratio = 1;
00988         else
00989         {
00990                 if ( quality == ASIMAGE_QUALITY_POOR )
00991                         h_ratio = 1 ;
00992                 else if( clip_width > 1 )
00993                 {
00994                         h_ratio = (to_width/(clip_width-1))+1;
00995                         if( h_ratio*(clip_width-1) < to_width )
00996                                 ++h_ratio ;
00997                 }else
00998                         h_ratio = to_width ;
00999                 ++h_ratio ;
01000         }
01001         scales_h = make_scales( clip_width, to_width, ( quality == ASIMAGE_QUALITY_POOR )?0:1 );
01002         scales_v = make_scales( clip_height, to_height, ( quality == ASIMAGE_QUALITY_POOR  || clip_height <= 3)?0:1 );
01003 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
01004         {
01005           register int i ;
01006           for( i = 0 ; i < MIN(clip_width, to_width) ; i++ )
01007                 fprintf( stderr, " %d", scales_h[i] );
01008           fprintf( stderr, "\n" );
01009           for( i = 0 ; i < MIN(clip_height, to_height) ; i++ )
01010                 fprintf( stderr, " %d", scales_v[i] );
01011           fprintf( stderr, "\n" );
01012         }
01013 #endif
01014         if((imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality )) == NULL )
01015         {
01016         destroy_asimage( &dst );
01017         }else
01018         {
01019                 if( to_height <= clip_height )                                     /* scaling down */
01020                         scale_image_down( imdec, imout, h_ratio, scales_h, scales_v );
01021                 else if( quality == ASIMAGE_QUALITY_POOR || clip_height <= 3 ) 
01022                         scale_image_up_dumb( imdec, imout, h_ratio, scales_h, scales_v );
01023                 else
01024                         scale_image_up( imdec, imout, h_ratio, scales_h, scales_v );
01025                 stop_image_output( &imout );
01026         }
01027         free( scales_h );
01028         free( scales_v );
01029         stop_image_decoding( &imdec );
01030         SHOW_TIME("", started);
01031         return dst;
01032 }
01033 
01034 ASImage *
01035 tile_asimage( ASVisual *asv, ASImage *src,
01036                       int offset_x, int offset_y,
01037                           int to_width,
01038                           int to_height,
01039                           ARGB32 tint,
01040                           ASAltImFormats out_format, unsigned int compression_out, int quality )
01041 {
01042         ASImage *dst = NULL ;
01043         ASImageDecoder *imdec ;
01044         ASImageOutput  *imout ;
01045         START_TIME(started);
01046 
01047         if( asv == NULL )       asv = &__transform_fake_asv ;
01048 
01049 LOCAL_DEBUG_CALLER_OUT( "src = %p, offset_x = %d, offset_y = %d, to_width = %d, to_height = %d, tint = #%8.8lX", src, offset_x, offset_y, to_width, to_height, tint );
01050         if( src== NULL || (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y, to_width, 0, NULL)) == NULL )
01051         {
01052                 LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
01053                 return NULL;
01054         }
01055 
01056         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
01057 
01058         if((imout = start_image_output( asv, dst, out_format, (tint!=0)?8:0, quality)) == NULL )
01059         {
01060                 LOCAL_DEBUG_OUT( "failed to start image output%s", "");
01061         destroy_asimage( &dst );
01062     }else
01063         {
01064                 int y, max_y = to_height;
01065 LOCAL_DEBUG_OUT("tiling actually...%s", "");
01066                 if( to_height > src->height )
01067                 {
01068                         imout->tiling_step = src->height ;
01069                         max_y = src->height ;
01070                 }
01071                 if( tint != 0 )
01072                 {
01073                         for( y = 0 ; y < max_y ; y++  )
01074                         {
01075                                 imdec->decode_image_scanline( imdec );
01076                                 tint_component_mod( imdec->buffer.red, (CARD16)(ARGB32_RED8(tint)<<1), to_width );
01077                                 tint_component_mod( imdec->buffer.green, (CARD16)(ARGB32_GREEN8(tint)<<1), to_width );
01078                                 tint_component_mod( imdec->buffer.blue, (CARD16)(ARGB32_BLUE8(tint)<<1), to_width );
01079                                 tint_component_mod( imdec->buffer.alpha, (CARD16)(ARGB32_ALPHA8(tint)<<1), to_width );
01080                                 imout->output_image_scanline( imout, &(imdec->buffer), 1);
01081                         }
01082                 }else
01083                         for( y = 0 ; y < max_y ; y++  )
01084                         {
01085                                 imdec->decode_image_scanline( imdec );
01086                                 imout->output_image_scanline( imout, &(imdec->buffer), 1);
01087                         }
01088                 stop_image_output( &imout );
01089         }
01090         stop_image_decoding( &imdec );
01091 
01092         SHOW_TIME("", started);
01093         return dst;
01094 }
01095 
01096 ASImage *
01097 merge_layers( ASVisual *asv,
01098                                 ASImageLayer *layers, int count,
01099                                 int dst_width,
01100                                 int dst_height,
01101                                 ASAltImFormats out_format, unsigned int compression_out, int quality )
01102 {
01103         ASImage *dst = NULL ;
01104         ASImageDecoder **imdecs ;
01105         ASImageOutput  *imout ;
01106         ASImageLayer *pcurr = layers;
01107         int i ;
01108         ASScanline dst_line ;
01109         START_TIME(started);
01110 
01111 LOCAL_DEBUG_CALLER_OUT( "dst_width = %d, dst_height = %d", dst_width, dst_height );
01112         
01113         dst = create_destination_image( dst_width, dst_height, out_format, compression_out, ARGB32_DEFAULT_BACK_COLOR );
01114         if( dst == NULL )
01115                 return NULL;
01116 
01117         if( asv == NULL )       asv = &__transform_fake_asv ;
01118 
01119         prepare_scanline( dst_width, QUANT_ERR_BITS, &dst_line, asv->BGR_mode );
01120         dst_line.flags = SCL_DO_ALL ;
01121 
01122         imdecs = safecalloc( count+20, sizeof(ASImageDecoder*));
01123 
01124         for( i = 0 ; i < count ; i++ )
01125         {
01126                 /* all laayers but first must have valid image or solid_color ! */
01127                 if( (pcurr->im != NULL || pcurr->solid_color != 0 || i == 0) &&
01128                         pcurr->dst_x < (int)dst_width && pcurr->dst_x+(int)pcurr->clip_width > 0 )
01129                 {
01130                         imdecs[i] = start_image_decoding(asv, pcurr->im, SCL_DO_ALL,
01131                                                              pcurr->clip_x, pcurr->clip_y,
01132                                                                                          pcurr->clip_width, pcurr->clip_height,
01133                                                                                          pcurr->bevel);
01134                         if( pcurr->bevel_width != 0 && pcurr->bevel_height != 0 )
01135                                 set_decoder_bevel_geom( imdecs[i],
01136                                                         pcurr->bevel_x, pcurr->bevel_y,
01137                                                                                 pcurr->bevel_width, pcurr->bevel_height );
01138                         if( pcurr->tint == 0 && i != 0 )
01139                                 set_decoder_shift( imdecs[i], 8 );
01140                         if( pcurr->im == NULL )
01141                                 set_decoder_back_color( imdecs[i], pcurr->solid_color );
01142                 }
01143                 if( pcurr->next == pcurr )
01144                         break;
01145                 else
01146                         pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
01147         }
01148         if( i < count )
01149                 count = i+1 ;
01150 
01151         if(imdecs[0] == NULL || (imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality)) == NULL )
01152         {
01153                 for( i = 0 ; i < count ; i++ )
01154                         if( imdecs[i] )
01155                                 stop_image_decoding( &(imdecs[i]) );
01156 
01157         destroy_asimage( &dst );
01158                 free_scanline( &dst_line, True );
01159     }else
01160         {
01161                 int y, max_y = 0;
01162                 int min_y = dst_height;
01163                 int bg_tint = (layers[0].tint==0)?0x7F7F7F7F:layers[0].tint ;
01164                 int bg_bottom = layers[0].dst_y+layers[0].clip_height+imdecs[0]->bevel_v_addon ;
01165 LOCAL_DEBUG_OUT("blending actually...%s", "");
01166                 pcurr = layers ;
01167                 for( i = 0 ; i < count ; i++ )
01168                 {
01169                         if( imdecs[i] )
01170                         {
01171                                 int layer_bottom = pcurr->dst_y+pcurr->clip_height ;
01172                                 if( pcurr->dst_y < min_y )
01173                                         min_y = pcurr->dst_y;
01174                                 layer_bottom += imdecs[i]->bevel_v_addon ;
01175                                 if( (int)layer_bottom > max_y )
01176                                         max_y = layer_bottom;
01177                         }
01178                         pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
01179                 }
01180                 if( min_y < 0 )
01181                         min_y = 0 ;
01182                 else if( min_y >= (int)dst_height )
01183                         min_y = dst_height ;
01184                         
01185                 if( max_y >= (int)dst_height )
01186                         max_y = dst_height ;
01187                 else
01188                         imout->tiling_step = max_y ;
01189 
01190 LOCAL_DEBUG_OUT( "min_y = %d, max_y = %d", min_y, max_y );
01191                 dst_line.back_color = imdecs[0]->back_color ;
01192                 dst_line.flags = 0 ;
01193                 for( y = 0 ; y < min_y ; ++y  )
01194                         imout->output_image_scanline( imout, &dst_line, 1);
01195                 dst_line.flags = SCL_DO_ALL ;
01196                 pcurr = layers ;
01197                 for( i = 0 ; i < count ; ++i )
01198                 {
01199                         if( imdecs[i] && pcurr->dst_y < min_y  )
01200                                 imdecs[i]->next_line = min_y - pcurr->dst_y ;
01201                         pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
01202                 }
01203                 for( ; y < max_y ; ++y  )
01204                 {
01205                         if( layers[0].dst_y <= y && bg_bottom > y )
01206                                 imdecs[0]->decode_image_scanline( imdecs[0] );
01207                         else
01208                         {
01209                                 imdecs[0]->buffer.back_color = imdecs[0]->back_color ;
01210                                 imdecs[0]->buffer.flags = 0 ;
01211                         }
01212                         copytintpad_scanline( &(imdecs[0]->buffer), &dst_line, layers[0].dst_x, bg_tint );
01213                         pcurr = layers[0].next?layers[0].next:&(layers[1]) ;
01214                         for( i = 1 ; i < count ; i++ )
01215                         {
01216                                 if( imdecs[i] && pcurr->dst_y <= y &&
01217                                         pcurr->dst_y+(int)pcurr->clip_height+(int)imdecs[i]->bevel_v_addon > y )
01218                                 {
01219                                         register ASScanline *b = &(imdecs[i]->buffer);
01220                                         CARD32 tint = pcurr->tint ;
01221                                         imdecs[i]->decode_image_scanline( imdecs[i] );
01222                                         if( tint != 0 )
01223                                         {
01224                                                 tint_component_mod( b->red,   (CARD16)(ARGB32_RED8(tint)<<1),   b->width );
01225                                                 tint_component_mod( b->green, (CARD16)(ARGB32_GREEN8(tint)<<1), b->width );
01226                                                 tint_component_mod( b->blue,  (CARD16)(ARGB32_BLUE8(tint)<<1),  b->width );
01227                                                 tint_component_mod( b->alpha, (CARD16)(ARGB32_ALPHA8(tint)<<1), b->width );
01228                                         }
01229                                         pcurr->merge_scanlines( &dst_line, b, pcurr->dst_x );
01230                                 }
01231                                 pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
01232                         }
01233                         imout->output_image_scanline( imout, &dst_line, 1);
01234                 }
01235                 dst_line.back_color = imdecs[0]->back_color ;
01236                 dst_line.flags = 0 ;
01237                 for( ; y < (int)dst_height ; y++  )
01238                         imout->output_image_scanline( imout, &dst_line, 1);
01239                 stop_image_output( &imout );
01240         }
01241         for( i = 0 ; i < count ; i++ )
01242                 if( imdecs[i] != NULL )
01243                 {
01244                         stop_image_decoding( &(imdecs[i]) );
01245                 }
01246         free( imdecs );
01247         free_scanline( &dst_line, True );
01248         SHOW_TIME("", started);
01249         return dst;
01250 }
01251 
01252 /* **************************************************************************************/
01253 /* GRADIENT drawing :                                                                                                                              */
01254 /* **************************************************************************************/
01255 static void
01256 make_gradient_left2right( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter )
01257 {
01258         int line ;
01259 
01260         imout->tiling_step = dither_lines_num;
01261         for( line = 0 ; line < dither_lines_num ; line++ )
01262                 imout->output_image_scanline( imout, &(dither_lines[line]), 1);
01263 }
01264 
01265 static void
01266 make_gradient_top2bottom( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter )
01267 {
01268         int y, height = imout->im->height, width = imout->im->width ;
01269         int line ;
01270         ASScanline result;
01271         CARD32 chan_data[MAX_GRADIENT_DITHER_LINES] = {0,0,0,0};
01272 LOCAL_DEBUG_CALLER_OUT( "width = %d, height = %d, filetr = 0x%lX, dither_count = %d\n", width, height, filter, dither_lines_num );
01273         prepare_scanline( width, QUANT_ERR_BITS, &result, imout->asv->BGR_mode );
01274         for( y = 0 ; y < height ; y++ )
01275         {
01276                 int color ;
01277 
01278                 result.flags = 0 ;
01279                 result.back_color = ARGB32_DEFAULT_BACK_COLOR ;
01280                 LOCAL_DEBUG_OUT( "line: %d", y );
01281                 for( color = 0 ; color < IC_NUM_CHANNELS ; color++ )
01282                         if( get_flags( filter, 0x01<<color ) )
01283                         {
01284                                 Bool dithered = False ;
01285                                 for( line = 0 ; line < dither_lines_num ; line++ )
01286                                 {
01287                                         /* we want to do error diffusion here since in other places it only works
01288                                                 * in horisontal direction : */
01289                                         CARD32 c = dither_lines[line].channels[color][y] ; 
01290                                         if( y+1 < height )
01291                                         {
01292                                                 c += ((dither_lines[line].channels[color][y+1]&0xFF)>>1);
01293                                                 if( (c&0xFFFF0000) != 0 )
01294                                                         c = ( c&0x7F000000 )?0:0x0000FF00;
01295                                         }
01296                                         chan_data[line] = c ;
01297 
01298                                         if( chan_data[line] != chan_data[0] )
01299                                                 dithered = True;
01300                                 }
01301                                 LOCAL_DEBUG_OUT( "channel: %d. Dithered ? %d", color, dithered );
01302 
01303                                 if( !dithered )
01304                                 {
01305                                         result.back_color = (result.back_color&(~MAKE_ARGB32_CHAN8(0xFF,color)))|
01306                                                                                 MAKE_ARGB32_CHAN16(chan_data[0],color);
01307                                         LOCAL_DEBUG_OUT( "back_color = %8.8lX", result.back_color);
01308                                 }else
01309                                 {
01310                                         register CARD32  *dst = result.channels[color] ;
01311                                         for( line = 0 ; line  < dither_lines_num ; line++ )
01312                                         {
01313                                                 register int x ;
01314                                                 register CARD32 d = chan_data[line] ;
01315                                                 for( x = line ; x < width ; x+=dither_lines_num )
01316                                                 {
01317                                                         dst[x] = d ;
01318                                                 }
01319                                         }
01320                                         set_flags(result.flags, 0x01<<color);
01321                                 }
01322                         }
01323                 imout->output_image_scanline( imout, &result, 1);
01324         }
01325         free_scanline( &result, True );
01326 }
01327 
01328 static void
01329 make_gradient_diag_width( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter, Bool from_bottom )
01330 {
01331         int line = 0;
01332         /* using bresengham algorithm again to trigger horizontal shift : */
01333         short smaller = imout->im->height;
01334         short bigger  = imout->im->width;
01335         register int i = 0;
01336         int eps;
01337 LOCAL_DEBUG_CALLER_OUT( "width = %d, height = %d, filetr = 0x%lX, dither_count = %d, dither width = %d\n", bigger, smaller, filter, dither_lines_num, dither_lines[0].width );
01338 
01339         if( from_bottom )
01340                 toggle_image_output_direction( imout );
01341         eps = -(bigger>>1);
01342         for ( i = 0 ; i < bigger ; i++ )
01343         {
01344                 eps += smaller;
01345                 if( (eps << 1) >= bigger )
01346                 {
01347                         /* put scanline with the same x offset */
01348                         dither_lines[line].offset_x = i ;
01349                         imout->output_image_scanline( imout, &(dither_lines[line]), 1);
01350                         if( ++line >= dither_lines_num )
01351                                 line = 0;
01352                         eps -= bigger ;
01353                 }
01354         }
01355 }
01356 
01357 static void
01358 make_gradient_diag_height( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter, Bool from_bottom )
01359 {
01360         int line = 0;
01361         unsigned short width = imout->im->width, height = imout->im->height ;
01362         /* using bresengham algorithm again to trigger horizontal shift : */
01363         unsigned short smaller = width;
01364         unsigned short bigger  = height;
01365         register int i = 0, k =0;
01366         int eps;
01367         ASScanline result;
01368         int *offsets ;
01369 
01370         prepare_scanline( width, QUANT_ERR_BITS, &result, imout->asv->BGR_mode );
01371         offsets = safemalloc( sizeof(int)*width );
01372         offsets[0] = 0 ;
01373 
01374         eps = -(bigger>>1);
01375         for ( i = 0 ; i < bigger ; i++ )
01376         {
01377                 ++offsets[k];
01378                 eps += smaller;
01379                 if( (eps << 1) >= bigger )
01380                 {
01381                         if( ++k >= width )
01382                                 break;
01383                         offsets[k] = offsets[k-1] ; /* seeding the offset */
01384                         eps -= bigger ;
01385                 }
01386         }
01387 
01388         if( from_bottom )
01389                 toggle_image_output_direction( imout );
01390 
01391         result.flags = (filter&SCL_DO_ALL);
01392         if( (filter&SCL_DO_ALL) == SCL_DO_ALL )
01393         {
01394                 for( i = 0 ; i < height ; i++ )
01395                 {
01396                         for( k = 0 ; k < width ; k++ )
01397                         {
01398                                 int offset = i+offsets[k] ;
01399                                 CARD32 **src_chan = &(dither_lines[line].channels[0]) ;
01400                                 result.alpha[k] = src_chan[IC_ALPHA][offset] ;
01401                                 result.red  [k] = src_chan[IC_RED]  [offset] ;
01402                                 result.green[k] = src_chan[IC_GREEN][offset] ;
01403                                 result.blue [k] = src_chan[IC_BLUE] [offset] ;
01404                                 if( ++line >= dither_lines_num )
01405                                         line = 0 ;
01406                         }
01407                         imout->output_image_scanline( imout, &result, 1);
01408                 }
01409         }else
01410         {
01411                 for( i = 0 ; i < height ; i++ )
01412                 {
01413                         for( k = 0 ; k < width ; k++ )
01414                         {
01415                                 int offset = i+offsets[k] ;
01416                                 CARD32 **src_chan = &(dither_lines[line].channels[0]) ;
01417                                 if( get_flags(filter, SCL_DO_ALPHA) )
01418                                         result.alpha[k] = src_chan[IC_ALPHA][offset] ;
01419                                 if( get_flags(filter, SCL_DO_RED) )
01420                                         result.red[k]   = src_chan[IC_RED]  [offset] ;
01421                                 if( get_flags(filter, SCL_DO_GREEN) )
01422                                         result.green[k] = src_chan[IC_GREEN][offset] ;
01423                                 if( get_flags(filter, SCL_DO_BLUE) )
01424                                         result.blue[k]  = src_chan[IC_BLUE] [offset] ;
01425                                 if( ++line >= dither_lines_num )
01426                                         line = 0 ;
01427                         }
01428                         imout->output_image_scanline( imout, &result, 1);
01429                 }
01430         }
01431 
01432         free( offsets );
01433         free_scanline( &result, True );
01434 }
01435 
01436 static ARGB32
01437 get_best_grad_back_color( ASGradient *grad )
01438 {
01439         ARGB32 back_color = 0 ;
01440         int chan ;
01441         for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
01442         {
01443                 CARD8 best = 0;
01444                 unsigned int best_size = 0;
01445                 register int i = grad->npoints;
01446                 while( --i > 0 )
01447                 { /* very crude algorithm, detecting biggest spans of the same color :*/
01448                         CARD8 c = ARGB32_CHAN8(grad->color[i], chan );
01449                         unsigned int span = grad->color[i]*20000;
01450                         if( c == ARGB32_CHAN8(grad->color[i-1], chan ) )
01451                         {
01452                                 span -= grad->color[i-1]*2000;
01453                                 if( c == best )
01454                                         best_size += span ;
01455                                 else if( span > best_size )
01456                                 {
01457                                         best_size = span ;
01458                                         best = c ;
01459                                 }
01460                         }
01461                 }
01462                 back_color |= MAKE_ARGB32_CHAN8(best,chan);
01463         }
01464         return back_color;
01465 }
01466 
01467 ASImage*
01468 make_gradient( ASVisual *asv, ASGradient *grad,
01469                int width, int height, ASFlagType filter,
01470                            ASAltImFormats out_format, unsigned int compression_out, int quality  )
01471 {
01472         ASImage *im = NULL ;
01473         ASImageOutput *imout;
01474         int line_len = width;
01475         START_TIME(started);
01476 LOCAL_DEBUG_CALLER_OUT( "type = 0x%X, width=%d, height = %d, filter = 0x%lX", grad->type, width, height, filter );
01477         if( grad == NULL )
01478                 return NULL;
01479 
01480         if( asv == NULL )       asv = &__transform_fake_asv ;
01481 
01482         if( width == 0 )
01483                 width = 2;
01484         if( height == 0 )
01485                 height = 2;
01486 
01487         im = create_destination_image( width, height, out_format, compression_out, get_best_grad_back_color( grad ) );
01488 
01489         if( get_flags(grad->type,GRADIENT_TYPE_ORIENTATION) )
01490                 line_len = height ;
01491         if( get_flags(grad->type,GRADIENT_TYPE_DIAG) )
01492                 line_len = MAX(width,height)<<1 ;
01493         if((imout = start_image_output( asv, im, out_format, QUANT_ERR_BITS, quality)) == NULL )
01494         {
01495         destroy_asimage( &im );
01496     }else
01497         {
01498                 int dither_lines = MIN(imout->quality+1, MAX_GRADIENT_DITHER_LINES) ;
01499                 ASScanline *lines;
01500                 int line;
01501                 static ARGB32 dither_seeds[MAX_GRADIENT_DITHER_LINES] = { 0, 0xFFFFFFFF, 0x7F0F7F0F, 0x0F7F0F7F };
01502 
01503                 if( dither_lines > (int)im->height || dither_lines > (int)im->width )
01504                         dither_lines = MIN(im->height, im->width) ;
01505 
01506                 lines = safecalloc( dither_lines, sizeof(ASScanline));
01507                 for( line = 0 ; line < dither_lines ; line++ )
01508                 {
01509                         prepare_scanline( line_len, QUANT_ERR_BITS, &(lines[line]), asv->BGR_mode );
01510                         make_gradient_scanline( &(lines[line]), grad, filter, dither_seeds[line] );
01511                 }
01512                 switch( get_flags(grad->type,GRADIENT_TYPE_MASK) )
01513                 {
01514                         case GRADIENT_Left2Right :
01515                                 make_gradient_left2right( imout, lines, dither_lines, filter );
01516                         break ;
01517                         case GRADIENT_Top2Bottom :
01518                                 make_gradient_top2bottom( imout, lines, dither_lines, filter );
01519                                 break ;
01520                         case GRADIENT_TopLeft2BottomRight :
01521                         case GRADIENT_BottomLeft2TopRight :
01522                                 if( width >= height )
01523                                         make_gradient_diag_width( imout, lines, dither_lines, filter,
01524                                                                                          (grad->type==GRADIENT_BottomLeft2TopRight));
01525                                 else
01526                                         make_gradient_diag_height( imout, lines, dither_lines, filter,
01527                                                                                           (grad->type==GRADIENT_BottomLeft2TopRight));
01528                                 break ;
01529                         default:
01530                                 break;
01531                 }
01532                 stop_image_output( &imout );
01533                 for( line = 0 ; line < dither_lines ; line++ )
01534                         free_scanline( &(lines[line]), True );
01535                 free( lines );
01536         }
01537         SHOW_TIME("", started);
01538         return im;
01539 }
01540 
01541 /* ***************************************************************************/
01542 /* Image flipping(rotation)                                                                                                     */
01543 /* ***************************************************************************/
01544 ASImage *
01545 flip_asimage( ASVisual *asv, ASImage *src,
01546                       int offset_x, int offset_y,
01547                           int to_width,
01548                           int to_height,
01549                           int flip,
01550                           ASAltImFormats out_format, unsigned int compression_out, int quality )
01551 {
01552         ASImage *dst = NULL ;
01553         ASImageOutput  *imout ;
01554         ASFlagType filter = SCL_DO_ALL;
01555         START_TIME(started);
01556 
01557 LOCAL_DEBUG_CALLER_OUT( "offset_x = %d, offset_y = %d, to_width = %d, to_height = %d", offset_x, offset_y, to_width, to_height );
01558         if( src == NULL )
01559                 return NULL ;
01560         
01561         filter = get_asimage_chanmask(src);
01562         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
01563 
01564         if( asv == NULL )       asv = &__transform_fake_asv ;
01565 
01566         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
01567         {
01568         destroy_asimage( &dst );
01569     }else
01570         {
01571                 ASImageDecoder *imdec ;
01572                 ASScanline result ;
01573                 int y;
01574 LOCAL_DEBUG_OUT("flip-flopping actually...%s", "");
01575                 prepare_scanline( to_width, 0, &result, asv->BGR_mode );
01576                 if( (imdec = start_image_decoding(asv, src, filter, offset_x, offset_y,
01577                                                   get_flags( flip, FLIP_VERTICAL )?to_height:to_width,
01578                                                                                   get_flags( flip, FLIP_VERTICAL )?to_width:to_height, NULL)) != NULL )
01579                 {
01580             if( get_flags( flip, FLIP_VERTICAL ) )
01581                         {
01582                                 CARD32 *chan_data ;
01583                                 size_t  pos = 0;
01584                                 int x ;
01585                                 CARD32 *a = imdec->buffer.alpha ;
01586                                 CARD32 *r = imdec->buffer.red ;
01587                                 CARD32 *g = imdec->buffer.green ;
01588                                 CARD32 *b = imdec->buffer.blue;
01589 
01590                                 chan_data = safemalloc( to_width*to_height*sizeof(CARD32));
01591                 result.back_color = src->back_color;
01592                                 result.flags = filter ;
01593 /*                              memset( a, 0x00, to_height*sizeof(CARD32));
01594                                 memset( r, 0x00, to_height*sizeof(CARD32));
01595                                 memset( g, 0x00, to_height*sizeof(CARD32));
01596                                 memset( b, 0x00, to_height*sizeof(CARD32));
01597   */                    for( y = 0 ; y < (int)to_width ; y++ )
01598                                 {
01599                                         imdec->decode_image_scanline( imdec );
01600                                         for( x = 0; x < (int)to_height ; x++ )
01601                                         {
01602                                                 chan_data[pos++] = MAKE_ARGB32( a[x],r[x],g[x],b[x] );
01603                                         }
01604                                 }
01605 
01606                                 if( get_flags( flip, FLIP_UPSIDEDOWN ) )
01607                                 {
01608                                         for( y = 0 ; y < (int)to_height ; ++y )
01609                                         {
01610                                                 pos = y + (int)(to_width-1)*(to_height) ;
01611                                                 for( x = 0 ; x < (int)to_width ; ++x )
01612                                                 {
01613                                                         result.alpha[x] = ARGB32_ALPHA8(chan_data[pos]);
01614                                                         result.red  [x] = ARGB32_RED8(chan_data[pos]);
01615                                                         result.green[x] = ARGB32_GREEN8(chan_data[pos]);
01616                                                         result.blue [x] = ARGB32_BLUE8(chan_data[pos]);
01617                                                         pos -= to_height ;
01618                                                 }
01619                                                 imout->output_image_scanline( imout, &result, 1);
01620                                         }
01621                                 }else
01622                                 {
01623                                         for( y = to_height-1 ; y >= 0 ; --y )
01624                                         {
01625                                                 pos = y ;
01626                                                 for( x = 0 ; x < (int)to_width ; ++x )
01627                                                 {
01628                                                         result.alpha[x] = ARGB32_ALPHA8(chan_data[pos]);
01629                                                         result.red  [x] = ARGB32_RED8(chan_data[pos]);
01630                                                         result.green[x] = ARGB32_GREEN8(chan_data[pos]);
01631                                                         result.blue [x] = ARGB32_BLUE8(chan_data[pos]);
01632                                                         pos += to_height ;
01633                                                 }
01634                                                 imout->output_image_scanline( imout, &result, 1);
01635                                         }
01636                                 }
01637                                 free( chan_data );
01638                         }else
01639                         {
01640                                 toggle_image_output_direction( imout );
01641 /*                fprintf( stderr, __FUNCTION__":chanmask = 0x%lX", filter ); */
01642                                 for( y = 0 ; y < (int)to_height ; y++  )
01643                                 {
01644                                         imdec->decode_image_scanline( imdec );
01645                     result.flags = imdec->buffer.flags = imdec->buffer.flags & filter ;
01646                     result.back_color = imdec->buffer.back_color ;
01647                     SCANLINE_FUNC_FILTERED(reverse_component,imdec->buffer,result,0,to_width);
01648                                         imout->output_image_scanline( imout, &result, 1);
01649                                 }
01650                         }
01651                         stop_image_decoding( &imdec );
01652                 }
01653                 free_scanline( &result, True );
01654                 stop_image_output( &imout );
01655         }
01656         SHOW_TIME("", started);
01657         return dst;
01658 }
01659 
01660 ASImage *
01661 mirror_asimage( ASVisual *asv, ASImage *src,
01662                       int offset_x, int offset_y,
01663                           int to_width,
01664                           int to_height,
01665                           Bool vertical, ASAltImFormats out_format,
01666                           unsigned int compression_out, int quality )
01667 {
01668         ASImage *dst = NULL ;
01669         ASImageOutput  *imout ;
01670         START_TIME(started);
01671 
01672         LOCAL_DEBUG_CALLER_OUT( "offset_x = %d, offset_y = %d, to_width = %d, to_height = %d", offset_x, offset_y, to_width, to_height );
01673         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
01674 
01675         if( asv == NULL )       asv = &__transform_fake_asv ;
01676 
01677         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
01678         {
01679         destroy_asimage( &dst );
01680     }else
01681         {
01682                 ASImageDecoder *imdec ;
01683                 ASScanline result ;
01684                 int y;
01685                 if( !vertical )
01686                         prepare_scanline( to_width, 0, &result, asv->BGR_mode );
01687 LOCAL_DEBUG_OUT("miroring actually...%s", "");
01688                 if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y,
01689                                                   to_width, to_height, NULL)) != NULL )
01690                 {
01691                         if( vertical )
01692                         {
01693                                 toggle_image_output_direction( imout );
01694                                 for( y = 0 ; y < (int)to_height ; y++  )
01695                                 {
01696                                         imdec->decode_image_scanline( imdec );
01697                                         imout->output_image_scanline( imout, &(imdec->buffer), 1);
01698                                 }
01699                         }else
01700                         {
01701                                 for( y = 0 ; y < (int)to_height ; y++  )
01702                                 {
01703                                         imdec->decode_image_scanline( imdec );
01704                                         result.flags = imdec->buffer.flags ;
01705                                         result.back_color = imdec->buffer.back_color ;
01706                                         SCANLINE_FUNC(reverse_component,imdec->buffer,result,0,to_width);
01707                                         imout->output_image_scanline( imout, &result, 1);
01708                                 }
01709                         }
01710                         stop_image_decoding( &imdec );
01711                 }
01712                 if( !vertical )
01713                         free_scanline( &result, True );
01714                 stop_image_output( &imout );
01715         }
01716         SHOW_TIME("", started);
01717         return dst;
01718 }
01719 
01720 ASImage *
01721 pad_asimage(  ASVisual *asv, ASImage *src,
01722                       int dst_x, int dst_y,
01723                           int to_width,
01724                           int to_height,
01725                           ARGB32 color,
01726                           ASAltImFormats out_format,
01727                           unsigned int compression_out, int quality )
01728 {
01729         ASImage *dst = NULL ;
01730         ASImageOutput  *imout ;
01731         int clip_width, clip_height ;
01732         START_TIME(started);
01733 
01734 LOCAL_DEBUG_CALLER_OUT( "dst_x = %d, dst_y = %d, to_width = %d, to_height = %d", dst_x, dst_y, to_width, to_height );
01735         if( src == NULL )
01736                 return NULL ;
01737 
01738         if( to_width == src->width && to_height == src->height && dst_x == 0 && dst_y == 0 )
01739                 return clone_asimage( src, SCL_DO_ALL );
01740 
01741         if( asv == NULL )       asv = &__transform_fake_asv ;
01742 
01743         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
01744 
01745         clip_width = src->width ;
01746         clip_height = src->height ;
01747         if( dst_x < 0 )
01748                 clip_width = MIN( (int)to_width, dst_x+clip_width );
01749         else
01750                 clip_width = MIN( (int)to_width-dst_x, clip_width );
01751     if( dst_y < 0 )
01752                 clip_height = MIN( (int)to_height, dst_y+clip_height);
01753         else
01754                 clip_height = MIN( (int)to_height-dst_y, clip_height);
01755         if( (clip_width <= 0 || clip_height <= 0) )
01756         {                              /* we are completely outside !!! */
01757                 dst->back_color = color ;
01758                 return dst ;
01759         }
01760 
01761         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
01762         {
01763         destroy_asimage( &dst );
01764     }else
01765         {
01766                 ASImageDecoder *imdec = NULL;
01767                 ASScanline result ;
01768                 int y;
01769                 int start_x = (dst_x < 0)? 0: dst_x;
01770                 int start_y = (dst_y < 0)? 0: dst_y;
01771 
01772                 if( (int)to_width != clip_width || clip_width != (int)src->width )
01773                 {
01774                         prepare_scanline( to_width, 0, &result, asv->BGR_mode );
01775                         imdec = start_image_decoding(  asv, src, SCL_DO_ALL,
01776                                                        (dst_x<0)? -dst_x:0,
01777                                                                                    (dst_y<0)? -dst_y:0,
01778                                                     clip_width, clip_height, NULL);
01779                 }
01780 
01781                 result.back_color = color ;
01782                 result.flags = 0 ;
01783 LOCAL_DEBUG_OUT( "filling %d lines with %8.8lX", start_y, color );
01784                 for( y = 0 ; y < start_y ; y++  )
01785                         imout->output_image_scanline( imout, &result, 1);
01786 
01787                 if( imdec )
01788                         result.back_color = imdec->buffer.back_color ;
01789                 if( (int)to_width == clip_width )
01790                 {
01791                         if( imdec == NULL )
01792                         {
01793 LOCAL_DEBUG_OUT( "copiing %d lines", clip_height );
01794                                 copy_asimage_lines( dst, start_y, src, (dst_y < 0 )? -dst_y: 0, clip_height, SCL_DO_ALL );
01795                                 imout->next_line += clip_height ;
01796                         }else
01797                                 for( y = 0 ; y < clip_height ; y++  )
01798                                 {
01799                                         imdec->decode_image_scanline( imdec );
01800                                         imout->output_image_scanline( imout, &(imdec->buffer), 1);
01801                                 }
01802                 }else if( imdec )
01803                 {
01804                         for( y = 0 ; y < clip_height ; y++  )
01805                         {
01806                                 int chan ;
01807 
01808                                 imdec->decode_image_scanline( imdec );
01809                                 result.flags = imdec->buffer.flags ;
01810                                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
01811                                 {
01812                                         register CARD32 *chan_data = result.channels[chan] ;
01813                                         register CARD32 *src_chan_data = imdec->buffer.channels[chan]+((dst_x<0)? -dst_x : 0) ;
01814                                         CARD32 chan_val = ARGB32_CHAN8(color, chan);
01815                                         register int k = -1;
01816                                         for( k = 0 ; k < start_x ; ++k )
01817                                                 chan_data[k] = chan_val ;
01818                                         chan_data += k ;
01819                                         for( k = 0 ; k < clip_width ; ++k )
01820                                                 chan_data[k] = src_chan_data[k];
01821                                         chan_data += k ;
01822                                         k = to_width-(start_x+clip_width) ;
01823                                         while( --k >= 0 )
01824                                                 chan_data[k] = chan_val ;
01825                                 }
01826                                 imout->output_image_scanline( imout, &result, 1);
01827                         }
01828                 }
01829                 result.back_color = color ;
01830                 result.flags = 0 ;
01831 LOCAL_DEBUG_OUT( "filling %d lines with %8.8lX at the end", to_height-(start_y+clip_height), color );
01832                 for( y = start_y+clip_height ; y < (int)to_height ; y++  )
01833                         imout->output_image_scanline( imout, &result, 1);
01834 
01835                 if( imdec )
01836                 {
01837                         stop_image_decoding( &imdec );
01838                         free_scanline( &result, True );
01839                 }
01840                 stop_image_output( &imout );
01841         }
01842         SHOW_TIME("", started);
01843         return dst;
01844 }
01845 
01846 
01847 /**********************************************************************/
01848 
01849 Bool fill_asimage( ASVisual *asv, ASImage *im,
01850                    int x, int y, int width, int height,
01851                                    ARGB32 color )
01852 {
01853         ASImageOutput *imout;
01854         ASImageDecoder *imdec;
01855         START_TIME(started);
01856 
01857         if( asv == NULL )       asv = &__transform_fake_asv ;
01858 
01859         if( im == NULL )
01860                 return False;
01861         if( x < 0 )
01862         {       width += x ; x = 0 ; }
01863         if( y < 0 )
01864         {       height += y ; y = 0 ; }
01865 
01866         if( width <= 0 || height <= 0 || x >= (int)im->width || y >= (int)im->height )
01867                 return False;
01868         if( x+width > (int)im->width )
01869                 width = (int)im->width-x ;
01870         if( y+height > (int)im->height )
01871                 height = (int)im->height-y ;
01872 
01873         if((imout = start_image_output( asv, im, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT)) == NULL )
01874                 return False ;
01875         else
01876         {
01877                 int i ;
01878                 imout->next_line = y ;
01879                 if( x == 0 && width == (int)im->width )
01880                 {
01881                         ASScanline result ;
01882                         result.flags = 0 ;
01883                         result.back_color = color ;
01884                         for( i = 0 ; i < height ; i++ )
01885                                 imout->output_image_scanline( imout, &result, 1);
01886                 }else if ((imdec = start_image_decoding(asv, im, SCL_DO_ALL, 0, y, im->width, height, NULL)) != NULL )
01887                 {
01888                         CARD32 alpha = ARGB32_ALPHA8(color), red = ARGB32_RED8(color),
01889                                    green = ARGB32_GREEN8(color), blue = ARGB32_BLUE8(color);
01890                         CARD32  *a = imdec->buffer.alpha + x ; 
01891                         CARD32  *r = imdec->buffer.red + x ;
01892                         CARD32  *g = imdec->buffer.green + x ;
01893                         CARD32  *b = imdec->buffer.blue + x  ;
01894                         for( i = 0 ; i < height ; i++ )
01895                         {
01896                                 register int k ;
01897                                 imdec->decode_image_scanline( imdec );
01898                                 for( k = 0 ; k < width ; ++k )
01899                                 {
01900                                         a[k] = alpha ;
01901                                         r[k] = red ;
01902                                         g[k] = green ;
01903                                         b[k] = blue ;
01904                                 }
01905                                 imout->output_image_scanline( imout, &(imdec->buffer), 1);
01906                         }
01907                         stop_image_decoding( &imdec );
01908                 }
01909         }
01910         stop_image_output( &imout );
01911         SHOW_TIME("", started);
01912         return True;
01913 }
01914 
01915 /* ********************************************************************************/
01916 /* Vector -> ASImage functions :                                                  */
01917 /* ********************************************************************************/
01918 Bool
01919 colorize_asimage_vector( ASVisual *asv, ASImage *im,
01920                                                  ASVectorPalette *palette,
01921                                                  ASAltImFormats out_format,
01922                                                  int quality )
01923 {
01924         ASImageOutput  *imout = NULL ;
01925         ASScanline buf ;
01926         int x, y, curr_point, last_point ;
01927     register double *vector ;
01928         double *points ;
01929         double *multipliers[IC_NUM_CHANNELS] ;
01930         START_TIME(started);
01931 
01932         if( im == NULL || palette == NULL || out_format == ASA_Vector )
01933                 return False;
01934 
01935         if( im->alt.vector == NULL )
01936                 return False;
01937         vector = im->alt.vector ;
01938 
01939         if( asv == NULL )       asv = &__transform_fake_asv ;
01940 
01941         if((imout = start_image_output( asv, im, out_format, QUANT_ERR_BITS, quality)) == NULL )
01942                 return False;
01943         /* as per ROOT ppl request double data goes from bottom to top,
01944          * instead of from top to bottom : */
01945         if( !get_flags( im->flags, ASIM_VECTOR_TOP2BOTTOM) )
01946                 toggle_image_output_direction(imout);
01947 
01948         prepare_scanline( im->width, QUANT_ERR_BITS, &buf, asv->BGR_mode );
01949         curr_point = palette->npoints/2 ;
01950         points = palette->points ;
01951         last_point = palette->npoints-1 ;
01952         buf.flags = 0 ;
01953         for( y = 0 ; y < IC_NUM_CHANNELS ; ++y )
01954         {
01955                 if( palette->channels[y] )
01956                 {
01957                         multipliers[y] = safemalloc( last_point*sizeof(double));
01958                         for( x = 0 ; x < last_point ; ++x )
01959                         {
01960                                 if (points[x+1] == points[x])
01961                                 multipliers[y][x] = 1;
01962                                 else
01963                                         multipliers[y][x] = (double)(palette->channels[y][x+1] - palette->channels[y][x])/
01964                                                                 (points[x+1]-points[x]);
01965 /*                              fprintf( stderr, "%e-%e/%e-%e=%e ", (double)palette->channels[y][x+1], (double)palette->channels[y][x],
01966                                                                 points[x+1], points[x], multipliers[y][x] );
01967  */
01968                         }
01969 /*                      fputc( '\n', stderr ); */
01970                         set_flags(buf.flags, (0x01<<y));
01971                 }else
01972                         multipliers[y] = NULL ;
01973         }
01974         for( y = 0 ; y < (int)im->height ; ++y )
01975         {
01976                 for( x = 0 ; x < (int)im->width ;)
01977                 {
01978                         register int i = IC_NUM_CHANNELS ;
01979                         double d ;
01980 
01981                         if( points[curr_point] > vector[x] )
01982                         {
01983                                 while( --curr_point >= 0 )
01984                                         if( points[curr_point] < vector[x] )
01985                                                 break;
01986                                 if( curr_point < 0 )
01987                                         ++curr_point ;
01988                         }else
01989                         {
01990                                 while( points[curr_point+1] < vector[x] )
01991                                         if( ++curr_point >= last_point )
01992                                         {
01993                                                 curr_point = last_point-1 ;
01994                                                 break;
01995                                         }
01996                         }
01997                         d = vector[x]-points[curr_point];
01998 /*                      fprintf( stderr, "%f|%d|%f*%f=%d(%f)+%d=", vector[x], curr_point, d, multipliers[0][curr_point], (int)(d*multipliers[0][curr_point]),(d*multipliers[0][curr_point]) , palette->channels[0][curr_point] ); */
01999                         while( --i >= 0 )
02000                                 if( multipliers[i] )
02001                                 {/* the following calculation is the most expensive part of the algorithm : */
02002                                         buf.channels[i][x] = (int)(d*multipliers[i][curr_point])+palette->channels[i][curr_point] ;
02003 /*                                      fprintf( stderr, "%2.2X.", buf.channels[i][x] ); */
02004                                 }
02005 /*                      fputc( ' ', stderr ); */
02006 #if 1
02007                         while( ++x < (int)im->width )
02008                                 if( vector[x] == vector[x-1] )
02009                                 {
02010                                         buf.red[x] = buf.red[x-1] ;
02011                                         buf.green[x] = buf.green[x-1] ;
02012                                         buf.blue[x] = buf.blue[x-1] ;
02013                                         buf.alpha[x] = buf.alpha[x-1] ;
02014                                 }else
02015                                         break;
02016 #else
02017                         ++x ;
02018 #endif
02019                 }
02020 /*              fputc( '\n', stderr ); */
02021                 imout->output_image_scanline( imout, &buf, 1);
02022                 vector += im->width ;
02023         }
02024         for( y = 0 ; y < IC_NUM_CHANNELS ; ++y )
02025                 if( multipliers[y] )
02026                         free(multipliers[y]);
02027 
02028         stop_image_output( &imout );
02029         free_scanline( &buf, True );
02030         SHOW_TIME("", started);
02031         return True;
02032 }
02033 
02034 ASImage *
02035 create_asimage_from_vector( ASVisual *asv, double *vector,
02036                                                         int width, int height,
02037                                                         ASVectorPalette *palette,
02038                                                         ASAltImFormats out_format,
02039                                                         unsigned int compression, int quality )
02040 {
02041         ASImage *im = NULL;
02042 
02043         if( asv == NULL )       asv = &__transform_fake_asv ;
02044 
02045         if( vector != NULL )
02046         {
02047                 im = create_destination_image( width, height, out_format, compression, ARGB32_DEFAULT_BACK_COLOR);
02048 
02049                 if( im != NULL )
02050                 {
02051                         if( set_asimage_vector( im, vector ) )
02052                                 if( palette )
02053                                         colorize_asimage_vector( asv, im, palette, out_format, quality );
02054                 }
02055         }
02056         return im ;
02057 }
02058 
02059 
02060 /***********************************************************************
02061  * Gaussian blur code.
02062  **********************************************************************/
02063 
02064 #undef PI
02065 #define PI 3.141592526
02066 
02067 #if 0
02068 static inline void
02069 gauss_component(CARD32 *src, CARD32 *dst, int radius, double* gauss, int len)
02070 {
02071         int x, j, r = radius - 1;
02072         for (x = 0 ; x < len ; x++) {
02073                 register double v = 0.0;
02074                 for (j = x - r ; j <= 0 ; j++) v += src[0] * gauss[x - j];
02075                 for ( ; j < x ; j++) v += src[j] * gauss[x - j];
02076                 v += src[x] * gauss[0];
02077                 for (j = x + r ; j >= len ; j--) v += src[len - 1] * gauss[j - x];
02078                 for ( ; j > x ; j--) v += src[j] * gauss[j - x];
02079                 dst[x] = (CARD32)v;
02080         }
02081 }
02082 #endif
02083 
02084 #define GAUSS_COEFF_TYPE int
02085 /* static void calc_gauss_double(double radius, double* gauss); */
02086 static void calc_gauss_int(int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums);
02087 
02088 #define gauss_data_t CARD32
02089 #define gauss_var_t int
02090 
02091 static inline void
02092 gauss_component_int(gauss_data_t *s1, gauss_data_t *d1, int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums, int len)
02093 {
02094 #define DEFINE_GAUS_TMP_VAR             CARD32 *xs1 = &s1[x]; CARD32 v1 = xs1[0]*gauss[0]
02095         if( len < radius + radius )
02096         {
02097                 int x = 0, j;
02098                 while( x < len )
02099                 {
02100                         int tail = len - 1 - x;
02101                         int gauss_sum = gauss[0];
02102                         DEFINE_GAUS_TMP_VAR;
02103                         for (j = 1 ; j <= x ; ++j)
02104                         {
02105                                 v1 += xs1[-j]*gauss[j];
02106                                 gauss_sum += gauss[j];
02107                         }
02108                         for (j = 1 ; j <= tail ; ++j)
02109                         {
02110                                 v1 += xs1[j]*gauss[j];
02111                                 gauss_sum += gauss[j];
02112                         }
02113                         d1[x] = (v1<<10)/gauss_sum;
02114                         ++x;
02115                 }
02116                 return;
02117         }
02118 
02119 #define MIDDLE_STRETCH_GAUSS(j_check)   \
02120         do{ for( j = 1 ; j j_check ; ++j ) v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]); }while(0)
02121 
02122         /* left stretch [0, r-2] */
02123         {
02124                 int x = 0 ;
02125                 for( ; x < radius-1 ; ++x )
02126                 {
02127                         int j ;
02128                         gauss_data_t *xs1 = &s1[x]; 
02129                         gauss_var_t v1 = xs1[0]*gauss[0];
02130                         for( j = 1 ; j <= x ; ++j )
02131                                 v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);
02132 
02133                         for( ; j < radius ; ++j ) 
02134                                 v1 += xs1[j]*gauss[j];
02135                         d1[x] = (v1<<10)/gauss_sums[x];
02136                 }       
02137         }
02138 
02139         /* middle stretch : [r-1, l-r] */
02140         if (radius-1 == len - radius)
02141         {
02142                 gauss_data_t *xs1 = &s1[radius-1]; 
02143                 gauss_var_t v1 = xs1[0]*gauss[0];
02144                 int j = 1;
02145                 for( ; j < radius ; ++j ) 
02146                         v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);
02147                 d1[radius] = v1 ;
02148         }else
02149         {
02150                 int x = radius;
02151                 for(; x <= len - radius + 1; x+=3)
02152                 {
02153                         gauss_data_t *xs1 = &s1[x]; 
02154                         gauss_var_t v1 = xs1[-1]*gauss[0];
02155                         gauss_var_t v2 = xs1[0]*gauss[0];
02156                         gauss_var_t v3 = xs1[1]*gauss[0];
02157                         int j = 1;
02158                         for( ; j < radius ; ++j ) 
02159                         {
02160                                 int g = gauss[j];
02161                                 v1 += xs1[-j-1]*g+xs1[j-1]*g;
02162                                 v2 += xs1[-j]*g+xs1[j]*g;
02163                                 v3 += xs1[-j+1]*g+xs1[j+1]*g;
02164                         }
02165                         d1[x-1] = v1 ; 
02166                         d1[x] = v2 ;
02167                         d1[x+1] = v3 ;
02168                 }
02169         }
02170         {
02171                 int x = 0;
02172                 gauss_data_t *td1 = &d1[len-1];
02173                 for( ; x < radius-1; ++x )
02174                 {
02175                         int j;
02176                         gauss_data_t *xs1 = &s1[len-1-x]; 
02177                         gauss_var_t v1 = xs1[0]*gauss[0];
02178                         for( j = 1 ; j <= x ; ++j ) 
02179                                 v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);                       
02180                                 
02181                         for( ; j <radius ; ++j )
02182                                 v1 += xs1[-j]*gauss[j];
02183                         td1[-x] = (v1<<10)/gauss_sums[x];
02184                 }
02185         }
02186 #undef  MIDDLE_STRETCH_GAUSS
02187 #undef DEFINE_GAUS_TMP_VAR
02188 }
02189 
02190 /*#define       USE_PARALLEL_OPTIMIZATION */
02191 
02192 #ifdef USE_PARALLEL_OPTIMIZATION
02193 /* this ain't worth a crap it seems. The code below seems to perform 20% slower then 
02194    plain and simple one component at a time 
02195  */
02196 static inline void
02197 gauss_component_int2(CARD32 *s1, CARD32 *d1, CARD32 *s2, CARD32 *d2, int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums, int len)
02198 {
02199 #define MIDDLE_STRETCH_GAUSS do{GAUSS_COEFF_TYPE g = gauss[j]; \
02200                                                                 v1 += (xs1[-j]+xs1[j])*g; \
02201                                                                 v2 += (xs2[-j]+xs2[j])*g; }while(0)
02202 
02203         int x, j;
02204         int tail = radius;
02205         GAUSS_COEFF_TYPE g0 = gauss[0];
02206         for( x = 0 ; x < radius ; ++x )
02207         {
02208                 register CARD32 *xs1 = &s1[x];
02209                 register CARD32 *xs2 = &s2[x];
02210                 register CARD32 v1 = s1[x]*g0;
02211                 register CARD32 v2 = s2[x]*g0;
02212                 for( j = 1 ; j <= x ; ++j )
02213                         MIDDLE_STRETCH_GAUSS;
02214                 for( ; j < radius ; ++j ) 
02215                 {
02216                         GAUSS_COEFF_TYPE g = gauss[j];
02217                         CARD32 m1 = xs1[j]*g;
02218                         CARD32 m2 = xs2[j]*g;
02219                         v1 += m1;
02220                         v2 += m2;
02221                 }
02222                 v1 = v1<<10;
02223                 v2 = v2<<10;
02224                 {
02225                         GAUSS_COEFF_TYPE gs = gauss_sums[x];
02226                         d1[x] = v1/gs;
02227                         d2[x] = v2/gs;
02228                 }
02229         }       
02230         while( x <= len-radius )
02231         {
02232                 register CARD32 *xs1 = &s1[x];
02233                 register CARD32 *xs2 = &s2[x];
02234                 register CARD32 v1 = s1[x]*g0;
02235                 register CARD32 v2 = s2[x]*g0;
02236                 for( j = 1 ; j < radius ; ++j ) 
02237                         MIDDLE_STRETCH_GAUSS;
02238                 d1[x] = v1 ;
02239                 d2[x] = v2 ;
02240                 ++x;
02241         }
02242         while( --tail > 0 )/*x < len*/
02243         {
02244                 register CARD32 *xs1 = &s1[x];
02245                 register CARD32 *xs2 = &s2[x];
02246                 register CARD32 v1 = xs1[0]*g0;
02247                 register CARD32 v2 = xs2[0]*g0;
02248                 for( j = 1 ; j < tail ; ++j ) 
02249                         MIDDLE_STRETCH_GAUSS;
02250                 for( ; j <radius ; ++j )
02251                 {
02252                         GAUSS_COEFF_TYPE g = gauss[j];
02253                         CARD32 m1 = xs1[-j]*g;
02254                         CARD32 m2 = xs2[-j]*g;
02255                         v1 += m1;
02256                         v2 += m2;
02257                 }
02258                 v1 = v1<<10;
02259                 v2 = v2<<10;
02260                 {
02261                         GAUSS_COEFF_TYPE gs = gauss_sums[tail];
02262                         d1[x] = v1/gs;
02263                         d2[x] = v2/gs;
02264                 }
02265                 ++x;
02266         }
02267 #undef  MIDDLE_STRETCH_GAUSS
02268 }
02269 #endif
02270 
02271 static inline void
02272 load_gauss_scanline(ASScanline *result, ASImageDecoder *imdec, int horz, GAUSS_COEFF_TYPE *sgauss, GAUSS_COEFF_TYPE *sgauss_sums, ASFlagType filter )
02273 {
02274     ASFlagType lf; 
02275         int x, chan;
02276 #ifdef USE_PARALLEL_OPTIMIZATION
02277         int todo_count = 0;
02278         int todo[IC_NUM_CHANNELS] = {-1,-1,-1,-1};
02279 #endif
02280         imdec->decode_image_scanline(imdec);
02281         lf = imdec->buffer.flags&filter ;
02282         result->flags = imdec->buffer.flags;
02283         result->back_color = imdec->buffer.back_color;
02284 
02285         for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
02286         {
02287                 CARD32 *res_chan = result->channels[chan];
02288                 CARD32 *src_chan = imdec->buffer.channels[chan];
02289                 if( get_flags(lf, 0x01<<chan) )
02290                 {
02291                         if( horz == 1 ) 
02292                         {
02293                                 for( x =  0 ; x < result->width ; ++x ) 
02294                                         res_chan[x] = src_chan[x]<<10 ;
02295                         }else
02296                         {
02297 #ifdef USE_PARALLEL_OPTIMIZATION
02298                                 todo[todo_count++] = chan;
02299 #else                   
02300                                 gauss_component_int(src_chan, res_chan, horz, sgauss, sgauss_sums, result->width);
02301 #endif
02302                         }
02303             }else if( get_flags( result->flags, 0x01<<chan ) )
02304                 copy_component( src_chan, res_chan, 0, result->width);
02305                 else if( get_flags( filter, 0x01<<chan ) )
02306                 {
02307                         CARD32 fill = (CARD32)ARGB32_RED8(imdec->buffer.back_color)<<10;
02308                         for( x =  0 ; x < result->width ; ++x ) res_chan[x] = fill ;
02309                 }
02310         }
02311 
02312 #ifdef USE_PARALLEL_OPTIMIZATION
02313         switch( 4 - todo_count )
02314         {
02315                 case 0 : /* todo_count == 4 */
02316                         gauss_component_int2(imdec->buffer.channels[todo[2]], result->channels[todo[2]],
02317                                                                  imdec->buffer.channels[todo[3]], result->channels[todo[3]],
02318                                                                  horz, sgauss, sgauss_sums, result->width);
02319                 case 2 : /* todo_count == 2 */
02320                         gauss_component_int2(imdec->buffer.channels[todo[0]], result->channels[todo[0]], 
02321                                                                  imdec->buffer.channels[todo[1]], result->channels[todo[1]],
02322                                                                  horz, sgauss, sgauss_sums, result->width); break ;
02323                 case 1 : /* todo_count == 3 */
02324                         gauss_component_int2(imdec->buffer.channels[todo[1]], result->channels[todo[1]],
02325                                                                  imdec->buffer.channels[todo[2]], result->channels[todo[2]],
02326                                                                  horz, sgauss, sgauss_sums, result->width);
02327                 case 3 : /* todo_count == 1 */
02328                         gauss_component_int( imdec->buffer.channels[todo[0]], 
02329                                                                  result->channels[todo[0]], 
02330                                                                  horz, sgauss, sgauss_sums, result->width); break ;
02331         }
02332 #endif
02333 }
02334 
02335 
02336 ASImage* blur_asimage_gauss(ASVisual* asv, ASImage* src, double dhorz, double dvert,
02337                             ASFlagType filter,
02338                                                         ASAltImFormats out_format, unsigned int compression_out, int quality)
02339 {
02340         ASImage *dst = NULL;
02341         ASImageOutput *imout;
02342         ASImageDecoder *imdec;
02343         int y, x, chan;
02344         int horz = (int)dhorz;
02345         int vert = (int)dvert;
02346         int width, height ; 
02347 #if 0
02348         struct timeval stv;
02349         gettimeofday (&stv,NULL);
02350 #define PRINT_BACKGROUND_OP_TIME do{ struct timeval tv;gettimeofday (&tv,NULL); tv.tv_sec-= stv.tv_sec;\
02351                                      fprintf (stderr,__FILE__ "%d: elapsed  %ld usec\n",__LINE__,\
02352                                               tv.tv_sec*1000000+tv.tv_usec-stv.tv_usec );}while(0)
02353 #else                                           
02354 #define PRINT_BACKGROUND_OP_TIME do{}while(0)                                          
02355 #endif
02356 
02357         if (!src) return NULL;
02358 
02359         if( asv == NULL )       asv = &__transform_fake_asv ;
02360 
02361         width = src->width ;
02362         height = src->height ;
02363         dst = create_destination_image( width, height, out_format, compression_out, src->back_color);
02364 
02365         imout = start_image_output(asv, dst, out_format, 0, quality);
02366     if (!imout)
02367     {
02368         destroy_asimage( &dst );
02369                 return NULL;
02370         }
02371 
02372         imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, src->width, src->height, NULL);
02373         if (!imdec) 
02374         {
02375                 stop_image_output(&imout);
02376         destroy_asimage( &dst );
02377                 return NULL;
02378         }
02379         
02380         if( horz > (width-1)/2  ) horz = (width==1 )?1:(width-1)/2 ;
02381         if( vert > (height-1)/2 ) vert = (height==1)?1:(height-1)/2 ;
02382         if (horz > 128) 
02383                 horz = 128;
02384         else if (horz < 1) 
02385                 horz = 1;
02386         if( vert > 128 )
02387                 vert = 128 ;
02388         else if( vert < 1 ) 
02389                 vert = 1 ;
02390 
02391         if( vert == 1 && horz == 1 ) 
02392         {
02393             for (y = 0 ; y < dst->height ; y++)
02394                 {
02395                         imdec->decode_image_scanline(imdec);
02396                 imout->output_image_scanline(imout, &(imdec->buffer), 1);
02397                 }
02398         }else
02399         {
02400                 ASScanline result;
02401                 GAUSS_COEFF_TYPE *horz_gauss = NULL;
02402                 GAUSS_COEFF_TYPE *horz_gauss_sums = NULL;
02403 
02404                 if( horz > 1 )
02405                 {
02406                         PRINT_BACKGROUND_OP_TIME;
02407                         horz_gauss = safecalloc(horz+1, sizeof(GAUSS_COEFF_TYPE));
02408                         horz_gauss_sums = safecalloc(horz+1, sizeof(GAUSS_COEFF_TYPE));
02409                         calc_gauss_int(horz, horz_gauss, horz_gauss_sums);
02410                         PRINT_BACKGROUND_OP_TIME;
02411                 }
02412                 prepare_scanline(width, 0, &result, asv->BGR_mode);
02413                 if( vert == 1 ) 
02414                 {
02415                     for (y = 0 ; y < height ; y++)
02416                     {
02417                                 load_gauss_scanline(&result, imdec, horz, horz_gauss, horz_gauss_sums, filter );
02418                                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
02419                                         if( get_flags( filter, 0x01<<chan ) )
02420                                         {
02421                                                 CARD32 *res_chan = result.channels[chan];
02422                                                 for( x = 0 ; x < width ; ++x ) 
02423                                                         res_chan[x] = (res_chan[x]&0x03Fc0000)?255:res_chan[x]>>10;
02424                                         }
02425                         imout->output_image_scanline(imout, &result, 1);
02426                         }
02427                 }else
02428                 { /* new code : */
02429                         GAUSS_COEFF_TYPE *vert_gauss = safecalloc(vert+1, sizeof(GAUSS_COEFF_TYPE));
02430                         GAUSS_COEFF_TYPE *vert_gauss_sums = safecalloc(vert+1, sizeof(GAUSS_COEFF_TYPE));
02431                         int lines_count = vert*2-1;
02432                         int first_line = 0, last_line = lines_count-1;
02433                         ASScanline *lines_mem = safecalloc( lines_count, sizeof(ASScanline));
02434                         ASScanline **lines = safecalloc( dst->height+1, sizeof(ASScanline*));
02435 
02436                         /* init */
02437                         calc_gauss_int(vert, vert_gauss, vert_gauss_sums);
02438                         PRINT_BACKGROUND_OP_TIME;
02439 
02440                         for( y = 0 ; y < lines_count ; ++y ) 
02441                         {
02442                                 lines[y] = &lines_mem[y] ;
02443                                 prepare_scanline(width, 0, lines[y], asv->BGR_mode);
02444                                 load_gauss_scanline(lines[y], imdec, horz, horz_gauss, horz_gauss_sums, filter );
02445                         }
02446 
02447                         PRINT_BACKGROUND_OP_TIME;
02448                         result.flags = 0xFFFFFFFF;
02449                         /* top band  [0, vert-2] */
02450                 for (y = 0 ; y < vert-1 ; y++)
02451                 {
02452                                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
02453                                 {
02454                                         CARD32 *res_chan = result.channels[chan];
02455                                         if( !get_flags(filter, 0x01<<chan) )
02456                                         copy_component( lines[y]->channels[chan], res_chan, 0, width);
02457                                         else
02458                                         {       
02459                                                 register ASScanline **ysrc = &lines[y];
02460                                                 int j = 0;
02461                                                 GAUSS_COEFF_TYPE g = vert_gauss[0];
02462                                                 CARD32 *src_chan1 = ysrc[0]->channels[chan];
02463                                                 for( x = 0 ; x < width ; ++x ) 
02464                                                         res_chan[x] = src_chan1[x]*g;
02465                                                 while( ++j <= y )
02466                                                 {
02467                                                         CARD32 *src_chan2 = ysrc[j]->channels[chan];
02468                                                         g = vert_gauss[j];
02469                                                         src_chan1 = ysrc[-j]->channels[chan];
02470                                                         for( x = 0 ; x < width ; ++x ) 
02471                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
02472                                                 }       
02473                                                 for( ; j < vert ; ++j ) 
02474                                                 {
02475                                                         g = vert_gauss[j];
02476                                                         src_chan1 = ysrc[j]->channels[chan];
02477                                                         for( x = 0 ; x < width ; ++x ) 
02478                                                                 res_chan[x] += src_chan1[x]*g;
02479                                                 }
02480                                                 g = vert_gauss_sums[y];
02481                                                 for( x = 0 ; x < width ; ++x ) 
02482                                                 {
02483                                                         gauss_var_t v = res_chan[x]/g;
02484                                                         res_chan[x] = (v&0x03Fc0000)?255:v>>10;
02485                                                 }
02486                                         }
02487                                 }
02488                         imout->output_image_scanline(imout, &result, 1);
02489                         }
02490                         PRINT_BACKGROUND_OP_TIME;
02491                         /* middle band [vert-1, height-vert] */
02492                         for( ; y <= height - vert; ++y)
02493                         {
02494                                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
02495                                 {
02496                                         CARD32 *res_chan = result.channels[chan];
02497                                         if( !get_flags(filter, 0x01<<chan) )
02498                                         copy_component( lines[y]->channels[chan], res_chan, 0, result.width);
02499                                         else
02500                                         {       
02501                                                 register ASScanline **ysrc = &lines[y];
02502 /* surprisingly, having x loops inside y loop yields 30% to 80% better performance */
02503                                                 int j = 0;
02504                                                 CARD32 *src_chan1 = ysrc[0]->channels[chan];
02505                                                 memset( res_chan, 0x00, width*4 );
02506 /*                                              for( x = 0 ; x < width ; ++x ) 
02507                                                         res_chan[x] = src_chan1[x]*vert_gauss[0];
02508  */                                                     
02509                                                 while( ++j < vert ) 
02510                                                 {
02511                                                         CARD32 *src_chan2 = ysrc[j]->channels[chan];
02512                                                         GAUSS_COEFF_TYPE g = vert_gauss[j];
02513                                                         src_chan1 = ysrc[-j]->channels[chan];
02514                                                         switch( g ) 
02515                                                         {
02516                                                                 case 1 :
02517                                                                         for( x = 0 ; x < width ; ++x ) 
02518                                                                                 res_chan[x] += src_chan1[x]+src_chan2[x];
02519                                                                         break;
02520                                                                 case 2 :
02521                                                                         for( x = 0 ; x < width ; ++x ) 
02522                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])<<1;
02523                                                                         break;
02524 #if 1
02525                                                                 case 4 :
02526                                                                         for( x = 0 ; x < width ; ++x ) 
02527                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])<<2;
02528                                                                         break;
02529                                                                 case 8 :
02530                                                                         for( x = 0 ; x < width ; ++x ) 
02531                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])<<3;
02532                                                                         break;
02533                                                                 case 16 :
02534                                                                         for( x = 0 ; x < width ; ++x ) 
02535                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])<<4;
02536                                                                         break;
02537                                                                 case 32 :
02538                                                                         for( x = 0 ; x < width ; ++x ) 
02539                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])<<5;
02540                                                                         break;
02541 #endif          
02542                                                                 default :                                                                       
02543                                                                         for( x = 0 ; x < width ; ++x ) 
02544                                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
02545                                                         }
02546                                                 }
02547                                                 src_chan1 = ysrc[0]->channels[chan];
02548                                                 for( x = 0 ; x < width ; ++x ) 
02549                                                 {
02550                                                         gauss_var_t v = src_chan1[x]*vert_gauss[0] + res_chan[x];
02551                                                         res_chan[x] = (v&0xF0000000)?255:v>>20;
02552                                                 } 
02553                                         }
02554                                 }
02555 
02556                         imout->output_image_scanline(imout, &result, 1);
02557                                 ++last_line;
02558                                 /* fprintf( stderr, "last_line = %d, first_line = %d, height = %d, vert = %d, y = %d\n", last_line, first_line, dst->height, vert, y ); */
02559                                 lines[last_line] = lines[first_line] ; 
02560                                 ++first_line;
02561                                 load_gauss_scanline(lines[last_line], imdec, horz, horz_gauss, horz_gauss_sums, filter );
02562                         }
02563                         PRINT_BACKGROUND_OP_TIME;
02564                         /* bottom band */
02565                         for( ; y < height; ++y)
02566                         {
02567                                 int tail = height - y ; 
02568                                 for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
02569                                 {
02570                                         CARD32 *res_chan = result.channels[chan];
02571                                         if( !get_flags(filter, 0x01<<chan) )
02572                                         copy_component( lines[y]->channels[chan], res_chan, 0, result.width);
02573                                         else
02574                                         {       
02575                                                 register ASScanline **ysrc = &lines[y];
02576                                                 int j = 0;
02577                                                 GAUSS_COEFF_TYPE g ;
02578                                                 CARD32 *src_chan1 = ysrc[0]->channels[chan];
02579                                                 for( x = 0 ; x < width ; ++x ) 
02580                                                         res_chan[x] = src_chan1[x]*vert_gauss[0];
02581                                                 for( j = 1 ; j < tail ; ++j ) 
02582                                                 {
02583                                                         CARD32 *src_chan2 = ysrc[j]->channels[chan];
02584                                                         g = vert_gauss[j];
02585                                                         src_chan1 = ysrc[-j]->channels[chan];
02586                                                         for( x = 0 ; x < width ; ++x ) 
02587                                                                 res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
02588                                                 }
02589                                                 for( ; j < vert ; ++j )
02590                                                 {
02591                                                         g = vert_gauss[j];
02592                                                         src_chan1 = ysrc[-j]->channels[chan];
02593                                                         for( x = 0 ; x < width ; ++x ) 
02594                                                                 res_chan[x] += src_chan1[x]*g;
02595                                                 }
02596                                                 g = vert_gauss_sums[tail];
02597                                                 for( x = 0 ; x < width ; ++x ) 
02598                                                 {
02599                                                         gauss_var_t v = res_chan[x]/g;
02600                                                         res_chan[x] = (v&0x03Fc0000)?255:v>>10;
02601                                                 }
02602                                         }
02603                                 }
02604 
02605                         imout->output_image_scanline(imout, &result, 1);
02606                         }
02607                         /* cleanup */
02608                         for( y = 0 ; y < lines_count ; ++y ) 
02609                                 free_scanline(&lines_mem[y], True);
02610                         free( lines_mem );
02611                         free( lines );
02612                         free(vert_gauss_sums);
02613                         free(vert_gauss);
02614 
02615                 }
02616                 free_scanline(&result, True);
02617                 if( horz_gauss_sums )
02618                         free(horz_gauss_sums);
02619                 if( horz_gauss )
02620                         free(horz_gauss);
02621         }
02622 PRINT_BACKGROUND_OP_TIME;
02623 
02624         stop_image_decoding(&imdec);
02625         stop_image_output(&imout);
02626 
02627         return dst;
02628 }
02629 
02630 #if 0 /* unused for the time being */
02631 static void calc_gauss_double(double radius, double* gauss) 
02632 {
02633         int i, mult;
02634         double std_dev, sum = 0.0;
02635         double g0, g_last;
02636         double n, nn, nPI, nnPI;
02637         if (radius <= 1.0) 
02638         {
02639                 gauss[0] = 1.0;
02640                 return;
02641         }
02642         /* after radius of 128 - gaussian degrades into something wierd, 
02643            since our colors are only 8 bit */
02644         if (radius > 128.0) radius = 128.0; 
02645         std_dev = (radius - 1) * 0.3003866304;
02646         do
02647         {
02648                 sum = 0 ;
02649                 n = std_dev * std_dev;
02650                 nn = 2*n ;
02651                 nPI = n*PI;
02652                 nnPI = nn*PI;
02653                 sum = g0 = 1.0 / nnPI ;
02654                 for (i = 1 ; i < radius-1 ; i++) 
02655                         sum += exp((double)-i * (double)i / nn)/nPI; 
02656                 g_last = exp((double)-i * (double)i / nn)/nnPI; 
02657                 sum += g_last*2.0 ; 
02658         
02659                 mult = (int)((1024.0+radius*0.94)/sum);
02660                 std_dev += 0.1 ;
02661         }while( g_last*mult  < 1. );
02662 
02663         gauss[0] = g0/sum ; 
02664         gauss[(int)radius-1] = g_last/sum;
02665         
02666         sum *= nnPI;
02667         for (i = 1 ; i < radius-1 ; i++)
02668                 gauss[i] = exp((double)-i * (double)i / nn)/sum;
02669 }
02670 #endif
02671 
02672 /* even though lookup tables take space - using those speeds kernel calculations tenfold */
02673 static const double standard_deviations[128] = 
02674 {
02675                  0.0,       0.300387,  0.600773,  0.901160,  1.201547,  1.501933,  1.852320,  2.202706,  2.553093,  2.903480,  3.253866,  3.604253,  3.954640,  4.355026,  4.705413,  5.105799, 
02676                  5.456186,  5.856573,  6.256959,  6.657346,  7.057733,  7.458119,  7.858506,  8.258892,  8.659279,  9.059666,  9.510052,  9.910439, 10.360826, 10.761212, 11.211599, 11.611986, 
02677                 12.062372, 12.512759, 12.963145, 13.413532, 13.863919, 14.314305, 14.764692, 15.215079, 15.665465, 16.115852, 16.566238, 17.066625, 17.517012, 18.017398, 18.467785, 18.968172, 
02678                 19.418558, 19.918945, 20.419332, 20.869718, 21.370105, 21.870491, 22.370878, 22.871265, 23.371651, 23.872038, 24.372425, 24.872811, 25.373198, 25.923584, 26.423971, 26.924358, 
02679                 27.474744, 27.975131, 28.525518, 29.025904, 29.576291, 30.126677, 30.627064, 31.177451, 31.727837, 32.278224, 32.828611, 33.378997, 33.929384, 34.479771, 35.030157, 35.580544, 
02680                 36.130930, 36.731317, 37.281704, 37.832090, 38.432477, 38.982864, 39.583250, 40.133637, 40.734023, 41.334410, 41.884797, 42.485183, 43.085570, 43.685957, 44.286343, 44.886730, 
02681                 45.487117, 46.087503, 46.687890, 47.288276, 47.938663, 48.539050, 49.139436, 49.789823, 50.390210, 50.990596, 51.640983, 52.291369, 52.891756, 53.542143, 54.192529, 54.842916, 
02682                 55.443303, 56.093689, 56.744076, 57.394462, 58.044849, 58.745236, 59.395622, 60.046009, 60.696396, 61.396782, 62.047169, 62.747556, 63.397942, 64.098329, 64.748715, 65.449102
02683         
02684 };
02685 
02686 static const double descr_approxim_mult[128] = 
02687 {
02688                  0.0,             576.033927, 1539.585724, 2313.193545, 3084.478025, 3855.885078, 4756.332754, 5657.242476, 6558.536133, 7460.139309, 8361.990613, 9264.041672, 10166.254856, 11199.615571, 12102.233350, 13136.515398, 
02689                  14039.393687,  15074.393173, 16109.866931, 17145.763345, 18182.036948, 19218.647831, 20255.561010, 21292.745815, 22330.175327, 23367.825876, 24540.507339, 25578.741286, 26752.587529, 27791.291872, 28966.144174, 30005.229117, 
02690                  31180.955186,  32357.252344, 33534.082488, 34711.410459, 35889.203827, 37067.432679, 38246.069415, 39425.088562, 40604.466591, 41784.181759, 42964.213952, 44284.538859, 45465.382595, 46787.130142, 47968.686878, 49291.724522, 
02691                  50473.909042,  51798.119528, 53123.060725, 54306.137507, 55632.091099, 56958.688068, 58285.899344, 59613.697438, 60942.056354, 62270.951500, 63600.359608, 64930.258655, 66260.627789, 67737.102560, 69068.620203, 70400.544942, 
02692                  71879.460632,  73212.395873, 74692.932606, 76026.792904, 77508.839552, 78991.791376, 80327.002820, 81811.308203, 83296.434414, 84782.353155, 86269.037314, 87756.460905, 89244.599028, 90733.427810, 92222.924365, 93713.066749, 
02693                  95203.833910,  96847.414084, 98339.659244, 99832.465294, 101479.012792, 102973.158567, 104621.682880, 106117.081106, 107767.473327, 109418.953577, 110916.202212, 112569.394820, 114223.592283, 115878.766626, 117534.890826, 119191.938777, 
02694                 120849.885258, 122508.705901, 124168.377156, 125828.876263, 127648.916790, 129311.319925, 130974.481906, 132798.169283, 134463.087846, 136128.703019, 137955.784611, 139784.215161, 141452.370894, 143283.009733, 145114.908442, 146948.037106, 
02695                 148619.357599, 150454.489089, 152290.771330, 154128.177628, 155966.682058, 157971.069246, 159812.039780, 161654.030102, 163497.017214, 165507.250512, 167352.489586, 169365.683736, 171213.071546, 173229.105499, 175078.544507, 177097.303447
02696         
02697 };
02698 
02699 static void calc_gauss_int(int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums) 
02700 {
02701         int i = radius;
02702         double dmult;
02703         double std_dev;
02704         if (i <= 1) 
02705         {
02706                 gauss[0] = 1024;
02707                 gauss_sums[0] = 1024;
02708                 return;
02709         }
02710         /* after radius of 128 - gaussian degrades into something wierd, 
02711            since our colors are only 8 bit */
02712         if (i > 128) i = 128; 
02713 #if 1
02714         {
02715                 double nn;
02716                 GAUSS_COEFF_TYPE sum = 1024 ;
02717                 std_dev = standard_deviations[i-1];
02718                 dmult = descr_approxim_mult[i-1];
02719                 nn = 2*std_dev * std_dev ;
02720                 dmult /=nn*PI;
02721                 gauss[0] = (GAUSS_COEFF_TYPE)(dmult + 0.5);
02722                 while( i >= 1 )
02723                 {
02724                         gauss[i] = (GAUSS_COEFF_TYPE)(exp((double)-i * (double)i / nn)*dmult + 0.5);
02725                         gauss_sums[i] = sum;
02726                         sum -= gauss[i];
02727                         --i;
02728                 }
02729                 gauss_sums[0] = sum;
02730         }
02731 #else 
02732         double g0, g_last, sum = 0.;
02733         double n, nn, nPI, nnPI;
02734         std_dev = (radius - 1) * 0.3003866304;
02735         do
02736         {
02737                 sum = 0 ;
02738                 n = std_dev * std_dev;
02739                 nn = 2*n ;
02740                 nPI = n*PI;
02741                 nnPI = nn*PI;
02742                 sum = g0 = 1.0 / nnPI ;
02743                 for (i = 1 ; i < radius-1 ; i++) 
02744                         sum += exp((double)-i * (double)i / nn)/nPI; 
02745                 g_last = exp((double)-i * (double)i / nn)/nnPI; 
02746                 sum += g_last*2.0 ; 
02747         
02748                 dmult = 1024.0/sum;
02749                 std_dev += 0.05 ;
02750         }while( g_last*dmult  < 1. );
02751         gauss[0] = g0 * dmult + 0.5; 
02752         gauss[(int)radius-1] = g_last * dmult + 0.5;
02753         dmult /=nnPI;
02754         for (i = 1 ; i < radius-1 ; i++)
02755                 gauss[i] = exp((double)-i * (double)i / nn)*dmult + 0.5;
02756 
02757 #endif  
02758 
02759 #if 0
02760         {
02761                 static int count = 0 ; 
02762                 if( ++count == 16 ) 
02763                 {
02764                         fprintf( stderr, "\n            " );
02765                         count = 0 ;
02766                 }
02767                         
02768                 fprintf(stderr, "%lf, ", dmult*nnPI );                  
02769         }
02770 #endif
02771 #if 0
02772         {
02773                 int sum_da = 0 ;
02774                 fprintf(stderr, "sum = %f, dmult = %f\n", sum, dmult );
02775                 for (i = 0 ; i < radius ; i++)
02776                 {
02777 //                      gauss[i] /= sum;
02778                         sum_da += gauss[i]*2 ;
02779                         fprintf(stderr, "discr_approx(%d) = %d\n", i, gauss[i]);
02780                 }
02781                 sum_da -= gauss[0];
02782         
02783                 fprintf(stderr, "sum_da = %d\n", sum_da );                      
02784         }
02785 #endif  
02786 }
02787 
02788 
02789 /***********************************************************************
02790  * Hue,saturation and lightness adjustments.
02791  **********************************************************************/
02792 ASImage*
02793 adjust_asimage_hsv( ASVisual *asv, ASImage *src,
02794                                     int offset_x, int offset_y,
02795                                     int to_width, int to_height,
02796                                         int affected_hue, int affected_radius,
02797                                         int hue_offset, int saturation_offset, int value_offset,
02798                                         ASAltImFormats out_format,
02799                                         unsigned int compression_out, int quality )
02800 {
02801         ASImage *dst = NULL ;
02802         ASImageDecoder *imdec ;
02803         ASImageOutput  *imout ;
02804         START_TIME(started);
02805 
02806         if( asv == NULL )       asv = &__transform_fake_asv ;
02807 
02808 LOCAL_DEBUG_CALLER_OUT( "offset_x = %d, offset_y = %d, to_width = %d, to_height = %d, hue = %u", offset_x, offset_y, to_width, to_height, affected_hue );
02809         if( src == NULL ) 
02810                 return NULL;
02811         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y, to_width, 0, NULL)) == NULL )
02812                 return NULL;
02813 
02814         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
02815         set_decoder_shift(imdec,8);
02816         if((imout = start_image_output( asv, dst, out_format, 8, quality)) == NULL )
02817         {
02818         destroy_asimage( &dst );
02819     }else
02820         {
02821             CARD32 from_hue1 = 0, from_hue2 = 0, to_hue1 = 0, to_hue2 = 0 ;
02822                 int y, max_y = to_height;
02823                 Bool do_greyscale = False ; 
02824 
02825                 affected_hue = normalize_degrees_val( affected_hue );
02826                 affected_radius = normalize_degrees_val( affected_radius );
02827                 if( value_offset != 0 )
02828                         do_greyscale = (affected_hue+affected_radius >= 360 || affected_hue-affected_radius <= 0 );
02829                 if( affected_hue > affected_radius )
02830                 {
02831                         from_hue1 = degrees2hue16(affected_hue-affected_radius);
02832                         if( affected_hue+affected_radius >= 360 )
02833                         {
02834                                 to_hue1 = MAX_HUE16 ;
02835                                 from_hue2 = MIN_HUE16 ;
02836                                 to_hue2 = degrees2hue16(affected_hue+affected_radius-360);
02837                         }else
02838                                 to_hue1 = degrees2hue16(affected_hue+affected_radius);
02839                 }else
02840                 {
02841                         from_hue1 = degrees2hue16(affected_hue+360-affected_radius);
02842                         to_hue1 = MAX_HUE16 ;
02843                         from_hue2 = MIN_HUE16 ;
02844                         to_hue2 = degrees2hue16(affected_hue+affected_radius);
02845                 }
02846                 hue_offset = degrees2hue16(hue_offset);
02847                 saturation_offset = (saturation_offset<<16) / 100;
02848                 value_offset = (value_offset<<16)/100 ;
02849 LOCAL_DEBUG_OUT("adjusting actually...%s", "");
02850                 if( to_height > src->height )
02851                 {
02852                         imout->tiling_step = src->height ;
02853                         max_y = src->height ;
02854                 }
02855                 for( y = 0 ; y < max_y ; y++  )
02856                 {
02857                         register int x = imdec->buffer.width;
02858                         CARD32 *r = imdec->buffer.red;
02859                         CARD32 *g = imdec->buffer.green;
02860                         CARD32 *b = imdec->buffer.blue ;
02861                         long h, s, v ;
02862                         imdec->decode_image_scanline( imdec );
02863                         while( --x >= 0 )
02864                         {
02865                                 if( (h = rgb2hue( r[x], g[x], b[x] )) != 0 )
02866                                 {
02867 #ifdef DEBUG_HSV_ADJUSTMENT
02868                                         fprintf( stderr, "IN  %d: rgb = #%4.4lX.%4.4lX.%4.4lX hue = %ld(%d)        range is (%ld - %ld, %ld - %ld), dh = %d\n", __LINE__, r[x], g[x], b[x], h, ((h>>8)*360)>>8, from_hue1, to_hue1, from_hue2, to_hue2, hue_offset );
02869 #endif
02870 
02871                                         if( affected_radius >= 180 ||
02872                                                 (h >= (int)from_hue1 && h <= (int)to_hue1 ) ||
02873                                                 (h >= (int)from_hue2 && h <= (int)to_hue2 ) )
02874 
02875                                         {
02876                                                 s = rgb2saturation( r[x], g[x], b[x] ) + saturation_offset;
02877                                                 v = rgb2value( r[x], g[x], b[x] )+value_offset;
02878                                                 h += hue_offset ;
02879                                                 if( h > MAX_HUE16 )
02880                                                         h -= MAX_HUE16 ;
02881                                                 else if( h == 0 )
02882                                                         h =  MIN_HUE16 ;
02883                                                 else if( h < 0 )
02884                                                         h += MAX_HUE16 ;
02885                                                 if( v < 0 ) v = 0 ;
02886                                                 else if( v > 0x00FFFF ) v = 0x00FFFF ;
02887 
02888                                                 if( s < 0 ) s = 0 ;
02889                                                 else if( s > 0x00FFFF ) s = 0x00FFFF ;
02890 
02891                                                 hsv2rgb ( (CARD32)h, (CARD32)s, (CARD32)v, &r[x], &g[x], &b[x]);
02892 
02893 #ifdef DEBUG_HSV_ADJUSTMENT
02894                                                 fprintf( stderr, "OUT %d: rgb = #%4.4lX.%4.4lX.%4.4lX hue = %ld(%ld)     sat = %ld val = %ld\n", __LINE__, r[x], g[x], b[x], h, ((h>>8)*360)>>8, s, v );
02895 #endif
02896                                         }
02897                                 }else if( do_greyscale ) 
02898                                 {
02899                                         int tmp = (int)r[x] + value_offset ; 
02900                                         g[x] = b[x] = r[x] = (tmp < 0)?0:((tmp>0x00FFFF)?0x00FFff:tmp);
02901                                 }
02902                         }
02903                         imdec->buffer.flags = 0xFFFFFFFF ;
02904                         imout->output_image_scanline( imout, &(imdec->buffer), 1);
02905                 }
02906                 stop_image_output( &imout );
02907         }
02908         stop_image_decoding( &imdec );
02909 
02910         SHOW_TIME("", started);
02911         return dst;
02912 }
02913 
02914 static void 
02915 slice_scanline( ASScanline *dst, ASScanline *src, int start_x, int end_x, ASScanline *middle )
02916 {
02917         CARD32 *sa = src->alpha, *da = dst->alpha ;
02918         CARD32 *sr = src->red, *dr = dst->red ;
02919         CARD32 *sg = src->green, *dg = dst->green ;
02920         CARD32 *sb = src->blue, *db = dst->blue ;
02921         int max_x = min( start_x, (int)dst->width);
02922         int tail = (int)src->width - end_x ; 
02923         int tiling_step = end_x - start_x ;
02924         int x1, x2, max_x2 ;
02925 
02926         LOCAL_DEBUG_OUT( "start_x = %d, end_x = %d, tail = %d, tiling_step = %d, max_x = %d", start_x, end_x, tail, tiling_step, max_x );
02927         for( x1 = 0 ; x1 < max_x ; ++x1 ) 
02928         {
02929                 da[x1] = sa[x1] ; 
02930                 dr[x1] = sr[x1] ; 
02931                 dg[x1] = sg[x1] ; 
02932                 db[x1] = sb[x1] ;         
02933         }
02934         if( x1 >= dst->width )
02935                 return;
02936         /* middle portion */
02937         max_x2 = (int) dst->width - tail ; 
02938         max_x = min(end_x, max_x2);             
02939         if( middle ) 
02940         {         
02941                 CARD32 *ma = middle->alpha-x1 ;
02942                 CARD32 *mr = middle->red-x1 ;
02943                 CARD32 *mg = middle->green-x1 ;
02944                 CARD32 *mb = middle->blue-x1 ;
02945                 LOCAL_DEBUG_OUT( "middle->width = %d", middle->width );
02946 
02947                 for( ; x1 < max_x2 ; ++x1 )
02948                 {
02949                         da[x1] = ma[x1] ; 
02950                         dr[x1] = mr[x1] ; 
02951                         dg[x1] = mg[x1] ; 
02952                         db[x1] = mb[x1] ;         
02953                 }        
02954                 LOCAL_DEBUG_OUT( "%d: %8.8lX %8.8lX %8.8lX %8.8lX", x1-1, ma[x1-1], mr[x1-1], mg[x1-1], mb[x1-1] );
02955         }else
02956         {       
02957                 for( ; x1 < max_x ; ++x1 )
02958                 {
02959                         x2 = x1 ;
02960                         for( x2 = x1 ; x2 < max_x2 ; x2 += tiling_step )
02961                         {
02962                                 da[x2] = sa[x1] ; 
02963                                 dr[x2] = sr[x1] ; 
02964                                 dg[x2] = sg[x1] ; 
02965                                 db[x2] = sb[x1] ;         
02966                         }                                 
02967                 }        
02968         }
02969         /* tail portion */
02970         x1 = src->width - tail ;
02971         x2 = max(max_x2,start_x) ; 
02972         max_x = src->width ;
02973         max_x2 = dst->width ;
02974         for( ; x1 < max_x && x2 < max_x2; ++x1, ++x2 )
02975         {
02976                 da[x2] = sa[x1] ; 
02977                 dr[x2] = sr[x1] ; 
02978                 dg[x2] = sg[x1] ; 
02979                 db[x2] = sb[x1] ;         
02980         }
02981 }        
02982 
02983 
02984 ASImage*
02985 slice_asimage2( ASVisual *asv, ASImage *src,
02986                            int slice_x_start, int slice_x_end,
02987                            int slice_y_start, int slice_y_end,
02988                            int to_width,
02989                            int to_height,
02990                            Bool scale,
02991                            ASAltImFormats out_format,
02992                            unsigned int compression_out, int quality )
02993 {
02994         ASImage *dst = NULL ;
02995         ASImageDecoder *imdec = NULL ;
02996         ASImageOutput  *imout = NULL ;
02997         START_TIME(started);
02998 
02999         if( asv == NULL )       asv = &__transform_fake_asv ;
03000 
03001 LOCAL_DEBUG_CALLER_OUT( "scale = %d, sx1 = %d, sx2 = %d, sy1 = %d, sy2 = %d, to_width = %d, to_height = %d", scale, slice_x_start, slice_x_end, slice_y_start, slice_y_end, to_width, to_height );
03002         if( src == NULL )
03003                 return NULL;
03004         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, src->width, 0, NULL)) == NULL )
03005                 return NULL;
03006         if( slice_x_end == 0 && slice_x_start > 0 ) 
03007                 slice_x_end = slice_x_start + 1 ;
03008         if( slice_y_end == 0 && slice_y_start > 0 ) 
03009                 slice_y_end = slice_y_start + 1 ;
03010         if( slice_x_end > src->width ) 
03011                 slice_x_end = src->width ;
03012         if( slice_y_end > src->height ) 
03013                 slice_y_end = src->height ;
03014         if( slice_x_start > slice_x_end ) 
03015                 slice_x_start = (slice_x_end > 0 ) ? slice_x_end-1 : 0 ;
03016         if( slice_y_start > slice_y_end ) 
03017                 slice_y_start = (slice_y_end > 0 ) ? slice_y_end-1 : 0 ;
03018 
03019 LOCAL_DEBUG_OUT( "sx1 = %d, sx2 = %d, sy1 = %d, sy2 = %d, to_width = %d, to_height = %d", slice_x_start, slice_x_end, slice_y_start, slice_y_end, to_width, to_height );
03020         dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
03021         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
03022         {
03023         destroy_asimage( &dst );
03024     }else 
03025         {       
03026                 int y1, y2 ;
03027                 int max_y = min( slice_y_start, (int)dst->height);
03028                 int tail = (int)src->height - slice_y_end ; 
03029                 int max_y2 = (int) dst->height - tail ;                 
03030                 ASScanline *out_buf = prepare_scanline( to_width, 0, NULL, asv->BGR_mode );
03031 
03032                 out_buf->flags = 0xFFFFFFFF ;
03033 
03034                 if( scale ) 
03035                 {
03036                         ASImageDecoder *imdec_scaled ;
03037                         ASImage *tmp ;
03038                         int x_middle = to_width - slice_x_start ; 
03039                         int x_right = src->width - (slice_x_end+1) ;
03040                         int y_middle = to_height - slice_y_start ;
03041                         int y_bottom = src->height - (slice_y_end+1) ;
03042                         x_middle = ( x_middle <= x_right  )? 0 : x_middle-x_right ;
03043                         y_middle = ( y_middle <= y_bottom )? 0 : y_middle-y_bottom ;
03044                         
03045                         if( x_middle > 0 )
03046                         {       
03047                                 tmp = scale_asimage2( asv, src, slice_x_start, 0, 
03048                                                                            slice_x_end-slice_x_start, max_y, 
03049                                                                            x_middle, max_y, ASA_ASImage, 0, quality );
03050                                 imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
03051                                 for( y1 = 0 ; y1 < max_y ; ++y1 ) 
03052                                 {
03053                                         imdec->decode_image_scanline( imdec );
03054                                         imdec_scaled->decode_image_scanline( imdec_scaled );
03055                                         slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
03056                                         imout->output_image_scanline( imout, out_buf, 1);
03057                                 }        
03058                                 stop_image_decoding( &imdec_scaled );
03059                                 destroy_asimage( &tmp );
03060                         }else
03061                         {       
03062                                 for( y1 = 0 ; y1 < max_y ; ++y1 ) 
03063                                 {
03064                                         imdec->decode_image_scanline( imdec );
03065                                         imout->output_image_scanline( imout, &(imdec->buffer), 1);
03066                                 }        
03067                         }
03068                         /*************************************************************/
03069                         /* middle portion */
03070                         if( y_middle > 0 ) 
03071                         {       
03072                                 ASImage *sides ;
03073                                 ASImageDecoder *imdec_sides ;
03074                                 sides = scale_asimage2( asv, src, 0, slice_y_start, 
03075                                                                                 src->width, slice_y_end-slice_y_start,
03076                                                                                 src->width, y_middle, ASA_ASImage, 0, quality );
03077                                 imdec_sides = start_image_decoding(asv, sides, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
03078 /*                              print_asimage( sides, 0, __FUNCTION__, __LINE__ ); */
03079                                 if( x_middle > 0 ) 
03080                                 {
03081                                         tmp = scale_asimage2( asv, sides, slice_x_start, 0, 
03082                                                                                 slice_x_end-slice_x_start, y_middle, 
03083                                                                                 x_middle, y_middle, ASA_ASImage, 0, quality );
03084 /*                                      print_asimage( tmp, 0, __FUNCTION__, __LINE__ ); */
03085 
03086                                         imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
03087                                         for( y1 = 0 ; y1 < y_middle ; ++y1 ) 
03088                                         {
03089                                                 imdec_sides->decode_image_scanline( imdec_sides );
03090                                                 imdec_scaled->decode_image_scanline( imdec_scaled );
03091                                                 slice_scanline( out_buf, &(imdec_sides->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
03092                                                 imout->output_image_scanline( imout, out_buf, 1);
03093                                         }        
03094                                         stop_image_decoding( &imdec_scaled );
03095                                         destroy_asimage( &tmp );
03096                                 
03097                                 }else
03098                                 {
03099                                         for( y1 = 0 ; y1 < y_middle ; ++y1 ) 
03100                                         {
03101                                                 imdec_sides->decode_image_scanline( imdec_sides );
03102                                                 imout->output_image_scanline( imout, &(imdec->buffer), 1);
03103                                         }        
03104                                 }                
03105                                 stop_image_decoding( &imdec_sides );
03106                                 destroy_asimage( &sides );
03107                         }                       
03108                         /*************************************************************/
03109                         /* bottom portion */
03110 
03111                         y2 =  max(max_y2,(int)slice_y_start) ; 
03112                         y1 = src->height - tail ;
03113                         imout->next_line = y2 ; 
03114                         imdec->next_line = y1 ;
03115                         max_y = src->height ;
03116                         if( y2 + max_y - y1 > dst->height ) 
03117                                 max_y = dst->height + y1 - y2 ;
03118                         LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d", y1, max_y );               
03119                         if( x_middle > 0 )
03120                         {       
03121                                 tmp = scale_asimage2( asv, src, slice_x_start, y1, 
03122                                                                            slice_x_end-slice_x_start, src->height-y1, 
03123                                                                            x_middle, src->height-y1, ASA_ASImage, 0, quality );
03124                                 imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
03125                                 for( ; y1 < max_y ; ++y1 )
03126                                 {
03127                                         imdec->decode_image_scanline( imdec );
03128                                         imdec_scaled->decode_image_scanline( imdec_scaled );
03129                                         slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
03130                                         imout->output_image_scanline( imout, out_buf, 1);
03131                                 }        
03132                                 stop_image_decoding( &imdec_scaled );
03133                                 destroy_asimage( &tmp );
03134                         }else
03135                         {       
03136                                 for( ; y1 < max_y ; ++y1 )
03137                                 {
03138                                         imdec->decode_image_scanline( imdec );
03139                                         imout->output_image_scanline( imout, &(imdec->buffer), 1);
03140                                 }        
03141                         }
03142                         
03143                 }else    /* tile middle portion */
03144                 {                      
03145                         imout->tiling_step = 0;
03146                         LOCAL_DEBUG_OUT( "max_y = %d", max_y );
03147                         for( y1 = 0 ; y1 < max_y ; ++y1 ) 
03148                         {
03149                                 imdec->decode_image_scanline( imdec );
03150                                 slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
03151                                 imout->output_image_scanline( imout, out_buf, 1);
03152                         }        
03153                         /* middle portion */
03154                         imout->tiling_step = (int)slice_y_end - (int)slice_y_start;
03155                         max_y = min(slice_y_end, max_y2);
03156                         LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d, tiling_step = %d", y1, max_y, imout->tiling_step );
03157                         for( ; y1 < max_y ; ++y1 )
03158                         {
03159                                 imdec->decode_image_scanline( imdec );
03160                                 slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
03161                                 imout->output_image_scanline( imout, out_buf, 1);
03162                         }
03163 
03164                         /* bottom portion */
03165                         imout->tiling_step = 0;
03166                         imout->next_line = y2 =  max(max_y2,(int)slice_y_start) ; 
03167                         imdec->next_line = y1 = src->height - tail ;
03168                         max_y = src->height ;
03169                         if( y2 + max_y - y1 > dst->height ) 
03170                                 max_y = dst->height + y1 - y2 ;
03171                         LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d", y1, max_y );               
03172                         for( ; y1 < max_y ; ++y1 )
03173                         {
03174                                 imdec->decode_image_scanline( imdec );
03175                                 slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
03176                                 imout->output_image_scanline( imout, out_buf, 1);
03177                         }
03178                 }
03179                 free_scanline( out_buf, False );
03180                 stop_image_output( &imout );
03181         }
03182         stop_image_decoding( &imdec );
03183 
03184         SHOW_TIME("", started);
03185         return dst;
03186 }
03187 
03188 ASImage*
03189 slice_asimage( ASVisual *asv, ASImage *src,
03190                            int slice_x_start, int slice_x_end,
03191                            int slice_y_start, int slice_y_end,
03192                            int to_width, int to_height,
03193                            ASAltImFormats out_format,
03194                            unsigned int compression_out, int quality )
03195 {
03196         
03197         return slice_asimage2( asv, src, slice_x_start, slice_x_end,
03198                                                    slice_y_start, slice_y_end, to_width,  to_height,
03199                                                         False, out_format, compression_out, quality );
03200 }
03201 
03202 
03203 ASImage *
03204 pixelize_asimage( ASVisual *asv, ASImage *src,
03205                               int clip_x, int clip_y, int clip_width, int clip_height,
03206                                   int pixel_width, int pixel_height,
03207                                   ASAltImFormats out_format, unsigned int compression_out, int quality )
03208 {
03209         ASImage *dst = NULL ;
03210         ASImageDecoder *imdec ;
03211         ASImageOutput  *imout ;
03212         START_TIME(started);
03213 
03214         if( asv == NULL )       asv = &__transform_fake_asv ;
03215 
03216         if (src== NULL)
03217                 return NULL;
03218                 
03219         if (clip_width <= 0)
03220                 clip_width = src->width;
03221         if (clip_height <= 0)
03222                 clip_height = src->height;
03223 
03224         if (pixel_width <= 0)
03225                 pixel_width = 1;
03226         else if (pixel_width > clip_width)
03227                 pixel_width = clip_width;
03228                 
03229         if (pixel_height <= 0)
03230                 pixel_height = 1;
03231         else if (pixel_height > clip_height)
03232                 pixel_height = clip_height;
03233                 
03234 LOCAL_DEBUG_CALLER_OUT( "src = %p, offset_x = %d, offset_y = %d, to_width = %d, to_height = %d, pixel_width = %d, pixel_height = %d", src, clip_x, clip_y, clip_width, clip_height, pixel_width, pixel_height );
03235         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, 0, NULL)) == NULL )
03236         {
03237                 LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
03238                 return NULL;
03239         }
03240 
03241         dst = create_destination_image( clip_width, clip_height, out_format, compression_out, src->back_color );
03242 
03243         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
03244         {
03245                 LOCAL_DEBUG_OUT( "failed to start image output%s", "");
03246         destroy_asimage( &dst );
03247     }else
03248         {
03249                 int y, max_y = clip_height;
03250 LOCAL_DEBUG_OUT("pixelizing actually...%s", "");
03251 
03252                 if( pixel_width > 1 || pixel_height > 1 )
03253                 {
03254                         int pixel_h_count = (clip_width+pixel_width-1)/pixel_width;
03255                         ASScanline *pixels = prepare_scanline( pixel_h_count, 0, NULL, asv->BGR_mode );
03256                         ASScanline *out_buf = prepare_scanline( clip_width, 0, NULL, asv->BGR_mode );
03257                         int lines_count = 0;
03258 
03259                         out_buf->flags = SCL_DO_ALL;
03260                         
03261                         for( y = 0 ; y < max_y ; y++  )
03262                         {
03263                                 int pixel_x = 0, x ;
03264                                 imdec->decode_image_scanline( imdec );
03265                                 for (x = 0; x < clip_width; x += pixel_width)
03266                                 {
03267                                         int xx = x+pixel_width;
03268                                         ASScanline *srcsl = &(imdec->buffer);
03269                                         
03270                                         if (xx > clip_width)
03271                                                 xx = clip_width;
03272                                         
03273                                         while ( --xx >= x)
03274                                         {
03275                                                 pixels->red[pixel_x] += srcsl->red[xx];
03276                                                 pixels->green[pixel_x] += srcsl->green[xx];
03277                                                 pixels->blue[pixel_x] += srcsl->blue[xx];
03278                                                 pixels->alpha[pixel_x] += srcsl->alpha[xx];
03279                                         }
03280                                         ++pixel_x;
03281                                 }
03282                                 if (++lines_count >= pixel_height || y == max_y-1)
03283                                 {
03284                                         pixel_x = 0;
03285                                         
03286                                         for (x = 0; x < clip_width; x += pixel_width)
03287                                         {
03288                                                 int xx = (x + pixel_width> clip_width) ? clip_width : x + pixel_width;
03289                                                 int count = (xx - x) * lines_count;
03290                                                 CARD32 r = pixels->red [pixel_x] / count;
03291                                                 CARD32 g = pixels->green [pixel_x] / count;
03292                                                 CARD32 b = pixels->blue [pixel_x] / count;
03293                                                 CARD32 a = pixels->alpha [pixel_x] / count;
03294                                                 
03295                                                 pixels->red [pixel_x] = 0;
03296                                                 pixels->green [pixel_x] = 0;
03297                                                 pixels->blue [pixel_x] = 0;
03298                                                 pixels->alpha [pixel_x] = 0;
03299 
03300                                                 if (xx > clip_width)
03301                                                         xx = clip_width;
03302 
03303                                                 while ( --xx >= x)
03304                                                 {
03305                                                         out_buf->red[xx]        = r;
03306                                                         out_buf->green[xx]  = g;
03307                                                         out_buf->blue[xx]       = b;
03308                                                         out_buf->alpha[xx]  = a;
03309                                                 }
03310 
03311                                                 ++pixel_x;
03312                                         }
03313                                         while (lines_count--)
03314                                                 imout->output_image_scanline( imout, out_buf, 1);
03315                                         lines_count = 0;
03316                                 }
03317                         }
03318                         free_scanline( out_buf, False );
03319                         free_scanline( pixels, False );
03320                 }else
03321                         for( y = 0 ; y < max_y ; y++  )
03322                         {
03323                                 imdec->decode_image_scanline( imdec );
03324                                 imout->output_image_scanline( imout, &(imdec->buffer), 1);
03325                         }
03326                 stop_image_output( &imout );
03327         }
03328         stop_image_decoding( &imdec );
03329 
03330         SHOW_TIME("", started);
03331         return dst;
03332 }
03333 
03334 ASImage *
03335 color2alpha_asimage( ASVisual *asv, ASImage *src,
03336                                  int clip_x, int clip_y, int clip_width, int clip_height,
03337                                      ARGB32 color,
03338                                      ASAltImFormats out_format, unsigned int compression_out, int quality )
03339 {
03340         ASImage *dst = NULL ;
03341         ASImageDecoder *imdec ;
03342         ASImageOutput  *imout ;
03343         START_TIME(started);
03344 
03345         if( asv == NULL )       asv = &__transform_fake_asv ;
03346 
03347         if (src== NULL)
03348                 return NULL;
03349                 
03350         if (clip_width <= 0)
03351                 clip_width = src->width;
03352         if (clip_height <= 0)
03353                 clip_height = src->height;
03354 
03355                 
03356 LOCAL_DEBUG_CALLER_OUT( "src = %p, offset_x = %d, offset_y = %d, to_width = %d, to_height = %d, color = #%8.8x", src, clip_x, clip_y, clip_width, clip_height, color );
03357         if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, 0, NULL)) == NULL )
03358         {
03359                 LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
03360                 return NULL;
03361         }
03362 
03363         dst = create_destination_image( clip_width, clip_height, out_format, compression_out, src->back_color );
03364 
03365         if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
03366         {
03367                 LOCAL_DEBUG_OUT( "failed to start image output%s", "");
03368         destroy_asimage( &dst );
03369     }else
03370         {
03371                 int y, max_y = min(clip_height,(int)src->height);
03372                 CARD32 cr = ARGB32_RED8(color);
03373                 CARD32 cg = ARGB32_GREEN8(color);
03374                 CARD32 cb = ARGB32_BLUE8(color);
03375 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)                                   
03376 fprintf (stderr, "color2alpha():%d: color: red = 0x%8.8X green = 0x%8.8X blue = 0x%8.8X\n", __LINE__, cr, cg, cb);
03377 #endif
03378 
03379                 for( y = 0 ; y < max_y ; y++  )
03380                 {
03381                         int x ;
03382                         ASScanline *srcsl = &(imdec->buffer);
03383                         imdec->decode_image_scanline( imdec );
03384                         for (x = 0; x < imdec->buffer.width; ++x)
03385                         {
03386                                 CARD32 r = srcsl->red[x];
03387                                 CARD32 g = srcsl->green[x];
03388                                 CARD32 b = srcsl->blue[x];
03389                                 CARD32 a = srcsl->alpha[x];
03390                                 /* the following logic is stolen from gimp and altered for our color format and beauty*/
03391                                 {
03392                                         CARD32 aa = a, ar, ag, ab;
03393                                         
03394 #define AS_MIN_CHAN_VAL         2                       /* GIMP uses 0.0001 */
03395 #define AS_MAX_CHAN_VAL         255                     /* GIMP uses 1.0 */
03396 #define MAKE_CHAN_ALPHA_FROM_COL(chan) \
03397                                         ((c##chan < AS_MIN_CHAN_VAL)? (chan)<<4 : \
03398                                                 ((chan > c##chan)? ((chan - c##chan)<<12) / (AS_MAX_CHAN_VAL - c##chan) : \
03399                                                         ((c##chan - chan)<<12) / c##chan))
03400 
03401                                         ar = MAKE_CHAN_ALPHA_FROM_COL(r);
03402                                         ag = MAKE_CHAN_ALPHA_FROM_COL(g);
03403                                         ab = MAKE_CHAN_ALPHA_FROM_COL(b);
03404 #undef  MAKE_CHAN_ALPHA_FROM_COL
03405                         
03406 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)                                   
03407 fprintf (stderr, "color2alpha():%d: src(argb): %8.8X %8.8X %8.8X %8.8X; ", __LINE__, a, r, g, b);
03408 #endif
03409                                         a = (ar > ag) ? max(ar, ab) : max(ag,ab);
03410 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)                                   
03411 fprintf (stderr, "alpha: (%8.8X %8.8X %8.8X)->%8.8X; ", ar, ag, ab, a);
03412 #endif
03413 
03414                                         if (a == 0) a = 1;
03415 #if defined(USE_STUPID_GIMP_WAY_DESTROYING_COLORS)
03416 #define APPLY_ALPHA_TO_CHAN(chan)  ({int __s = chan; int __c = c##chan; __c += (( __s - __c)*4096)/(int)a;(__c<=0)?0:((__c>=255)?255:__c);})
03417 #else
03418 #define APPLY_ALPHA_TO_CHAN(chan)       chan    
03419 #endif
03420                                         srcsl->red[x]   = APPLY_ALPHA_TO_CHAN(r);
03421                                         srcsl->green[x]         = APPLY_ALPHA_TO_CHAN(g);
03422                                         srcsl->blue[x]  = APPLY_ALPHA_TO_CHAN(b);
03423 #undef APPLY_ALPHA_TO_CHAN
03424                                         a = a*aa>>12;
03425                                         srcsl->alpha[x] = (a>255)?255:a;
03426 
03427 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)                                   
03428 fprintf (stderr, "result: %8.8X %8.8X %8.8X %8.8X.\n", src->alpha[x], src->red[x], src->green[x], src->blue[x]);
03429 #endif
03430 
03431                                 }
03432                                 /* end of gimp code */
03433                         }
03434                         imout->output_image_scanline( imout, srcsl, 1);
03435                 }
03436                 stop_image_output( &imout );
03437         }
03438         stop_image_decoding( &imdec );
03439 
03440         SHOW_TIME("", started);
03441         return dst;
03442 }
03443 
03444 
03445 /* ********************************************************************************/
03446 /* The end !!!!                                                                                                                                  */
03447 /* ********************************************************************************/
03448 

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