1 /*
2  * Copyright (c) 2000,2001 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 /*#undef NO_DEBUG_OUTPUT */
19 #undef USE_STUPID_GIMP_WAY_DESTROYING_COLORS
20 #undef LOCAL_DEBUG
21 #undef DO_CLOCKING
22 #undef DEBUG_HSV_ADJUSTMENT
23 #define USE_64BIT_FPU
24 #undef NEED_RBITSHIFT_FUNCS
25 
26 #ifdef _WIN32
27 #include "win32/config.h"
28 #else
29 #include "config.h"
30 #endif
31 //#undef HAVE_MMX
32 
33 #ifdef DO_CLOCKING
34 #if TIME_WITH_SYS_TIME
35 # include <sys/time.h>
36 # include <time.h>
37 #else
38 # if HAVE_SYS_TIME_H
39 #  include <sys/time.h>
40 # else
41 #  include <time.h>
42 # endif
43 #endif
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_STDLIB_H
49 #include <stdlib.h>
50 #endif
51 #ifdef HAVE_STDARG_H
52 #include <stdarg.h>
53 #endif
54 #include <math.h>
55 #include <string.h>
56 
57 #ifdef HAVE_MMX
58 #include <mmintrin.h>
59 #endif
60 
61 #ifdef _WIN32
62 # include "win32/afterbase.h"
63 #else
64 # include "afterbase.h"
65 #endif
66 #include "asvisual.h"
67 #include "blender.h"
68 #include "asimage.h"
69 #include "imencdec.h"
70 #include "transform.h"
71 
72 ASVisual __transform_fake_asv = {0};
73 
74 
75 /* ******************************************************************************/
76 /* below goes all kinds of funky stuff we can do with scanlines : 			   */
77 /* ******************************************************************************/
78 /* this will enlarge array based on count of items in dst per PAIR of src item with smoothing/scatter/dither */
79 /* the following formulas use linear approximation to calculate   */
80 /* color values for new pixels : 				  				  */
81 /* for scale factor of 2 we use this formula :    */
82 /* C = (-C1+3*C2+3*C3-C4)/4 					  */
83 /* or better :				 					  */
84 /* C = (-C1+5*C2+5*C3-C4)/8 					  */
85 #define INTERPOLATE_COLOR1(c) 			   	((c)<<QUANT_ERR_BITS)  /* nothing really to interpolate here */
86 #define INTERPOLATE_COLOR2(c1,c2,c3,c4)    	((((c2)<<2)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))<<(QUANT_ERR_BITS-3))
87 #define INTERPOLATE_COLOR2_V(c1,c2,c3,c4)    	((((c2)<<2)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))>>3)
88 /* for scale factor of 3 we use these formulas :  */
89 /* Ca = (-2C1+8*C2+5*C3-2C4)/9 		  			  */
90 /* Cb = (-2C1+5*C2+8*C3-2C4)/9 		  			  */
91 /* or better : 									  */
92 /* Ca = (-C1+5*C2+3*C3-C4)/6 		  			  */
93 /* Cb = (-C1+3*C2+5*C3-C4)/6 		  			  */
94 #define INTERPOLATE_A_COLOR3(c1,c2,c3,c4)  	(((((c2)<<2)+(c2)+((c3)<<1)+(c3)-(c1)-(c4))<<QUANT_ERR_BITS)/6)
95 #define INTERPOLATE_B_COLOR3(c1,c2,c3,c4)  	(((((c2)<<1)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))<<QUANT_ERR_BITS)/6)
96 #define INTERPOLATE_A_COLOR3_V(c1,c2,c3,c4)  	((((c2)<<2)+(c2)+((c3)<<1)+(c3)-(c1)-(c4))/6)
97 #define INTERPOLATE_B_COLOR3_V(c1,c2,c3,c4)  	((((c2)<<1)+(c2)+((c3)<<2)+(c3)-(c1)-(c4))/6)
98 /* just a hypotesus, but it looks good for scale factors S > 3: */
99 /* Cn = (-C1+(2*(S-n)+1)*C2+(2*n+1)*C3-C4)/2S  	  			   */
100 /* or :
101  * Cn = (-C1+(2*S+1)*C2+C3-C4+n*(2*C3-2*C2)/2S  			   */
102 /*       [ T                   [C2s]  [C3s]]   			       */
103 #define INTERPOLATION_Cs(c)	 		 	    ((c)<<1)
104 /*#define INTERPOLATION_TOTAL_START(c1,c2,c3,c4,S) 	(((S)<<1)*(c2)+((c3)<<1)+(c3)-c2-c1-c4)*/
105 #define INTERPOLATION_TOTAL_START(c1,c2,c3,c4,S) 	((((S)<<1)+1)*(c2)+(c3)-(c1)-(c4))
106 #define INTERPOLATION_TOTAL_STEP(c2,c3)  	((c3<<1)-(c2<<1))
107 #define INTERPOLATE_N_COLOR(T,S)		  	(((T)<<(QUANT_ERR_BITS-1))/(S))
108 
109 #define AVERAGE_COLOR1(c) 					((c)<<QUANT_ERR_BITS)
110 #define AVERAGE_COLOR2(c1,c2)				(((c1)+(c2))<<(QUANT_ERR_BITS-1))
111 #define AVERAGE_COLORN(T,N)					(((T)<<QUANT_ERR_BITS)/N)
112 
113 static inline void
enlarge_component12(register CARD32 * src,register CARD32 * dst,int * scales,int len)114 enlarge_component12( register CARD32 *src, register CARD32 *dst, int *scales, int len )
115 {/* expected len >= 2  */
116 	register int i = 0, k = 0;
117 	register int c1 = src[0], c4;
118 	--len; --len ;
119 	while( i < len )
120 	{
121 		c4 = src[i+2];
122 		/* that's right we can do that PRIOR as we calculate nothing */
123 		dst[k] = INTERPOLATE_COLOR1(src[i]) ;
124 		if( scales[i] == 2 )
125 		{
126 			register int c2 = src[i], c3 = src[i+1] ;
127 			c3 = INTERPOLATE_COLOR2(c1,c2,c3,c4);
128 			dst[++k] = (c3&0xFF000000 )?0:c3;
129 		}
130 		c1 = src[i];
131 		++k;
132 		++i;
133 	}
134 
135 	/* to avoid one more if() in loop we moved tail part out of the loop : */
136 	if( scales[i] == 1 )
137 		dst[k] = INTERPOLATE_COLOR1(src[i]);
138 	else
139 	{
140 		register int c2 = src[i], c3 = src[i+1] ;
141 		c2 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
142 		dst[k] = (c2&0xFF000000 )?0:c2;
143 	}
144 	dst[k+1] = INTERPOLATE_COLOR1(src[i+1]);
145 }
146 
147 static inline void
enlarge_component23(register CARD32 * src,register CARD32 * dst,int * scales,int len)148 enlarge_component23( register CARD32 *src, register CARD32 *dst, int *scales, int len )
149 {/* expected len >= 2  */
150 	register int i = 0, k = 0;
151 	register int c1 = src[0], c4 = src[1];
152 	if( scales[0] == 1 )
153 	{/* special processing for first element - it can be 1 - others can only be 2 or 3 */
154 		dst[k] = INTERPOLATE_COLOR1(src[0]) ;
155 		++k;
156 		++i;
157 	}
158 	--len; --len ;
159 	while( i < len )
160 	{
161 		register int c2 = src[i], c3 = src[i+1] ;
162 		c4 = src[i+2];
163 		dst[k] = INTERPOLATE_COLOR1(c2) ;
164 		if( scales[i] == 2 )
165 		{
166 			c3 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
167 			dst[++k] = (c3&0x7F000000 )?0:c3;
168 		}else
169 		{
170 			dst[++k] = INTERPOLATE_A_COLOR3(c1,c2,c3,c4);
171 			if( dst[k]&0x7F000000 )
172 				dst[k] = 0 ;
173 			c3 = INTERPOLATE_B_COLOR3(c1,c2,c3,c3);
174 			dst[++k] = (c3&0x7F000000 )?0:c3;
175 		}
176 		c1 = c2 ;
177 		++k;
178 		++i;
179 	}
180 	/* to avoid one more if() in loop we moved tail part out of the loop : */
181 	{
182 		register int c2 = src[i], c3 = src[i+1] ;
183 		dst[k] = INTERPOLATE_COLOR1(c2) ;
184 		if( scales[i] == 2 )
185 		{
186 			c2 = INTERPOLATE_COLOR2(c1,c2,c3,c3);
187 			dst[k+1] = (c2&0x7F000000 )?0:c2;
188 		}else
189 		{
190 			if( scales[i] == 1 )
191 				--k;
192 			else
193 			{
194 				dst[++k] = INTERPOLATE_A_COLOR3(c1,c2,c3,c3);
195 				if( dst[k]&0x7F000000 )
196 					dst[k] = 0 ;
197 				c2 = INTERPOLATE_B_COLOR3(c1,c2,c3,c3);
198   				dst[k+1] = (c2&0x7F000000 )?0:c2;
199 			}
200 		}
201 	}
202  	dst[k+2] = INTERPOLATE_COLOR1(src[i+1]) ;
203 }
204 
205 /* this case is more complex since we cannot really hardcode coefficients
206  * visible artifacts on smooth gradient-like images
207  */
208 static inline void
enlarge_component(register CARD32 * src,register CARD32 * dst,int * scales,int len)209 enlarge_component( register CARD32 *src, register CARD32 *dst, int *scales, int len )
210 {/* we skip all checks as it is static function and we want to optimize it
211   * as much as possible */
212 	int i = 0;
213 	int c1 = src[0];
214 	register int T ;
215 	--len ;
216 	if( len < 1 )
217 	{
218 		CARD32 c = INTERPOLATE_COLOR1(c1) ;
219 		for( i = 0 ; i < scales[0] ; ++i )
220 			dst[i] = c;
221 		return;
222 	}
223 	do
224 	{
225 		register short S = scales[i];
226 		register int step = INTERPOLATION_TOTAL_STEP(src[i],src[i+1]);
227 
228 		if( i+1 == len )
229 			T = INTERPOLATION_TOTAL_START(c1,src[i],src[i+1],src[i+1],S);
230 		else
231 			T = INTERPOLATION_TOTAL_START(c1,src[i],src[i+1],src[i+2],S);
232 
233 /*		LOCAL_DEBUG_OUT( "pixel %d, S = %d, step = %d", i, S, step );*/
234 		if( step )
235 		{
236 			register int n = 0 ;
237 			do
238 			{
239 				dst[n] = (T&0x7F000000)?0:INTERPOLATE_N_COLOR(T,S);
240 				if( ++n >= S ) break;
241 				T = (int)T + (int)step;
242 			}while(1);
243 			dst += n ;
244 		}else
245 		{
246 			register CARD32 c = (T&0x7F000000)?0:INTERPOLATE_N_COLOR(T,S);
247 			while(--S >= 0){	dst[S] = c;	}
248 			dst += scales[i] ;
249 		}
250 		c1 = src[i];
251 	}while(++i < len );
252 	*dst = INTERPOLATE_COLOR1(src[i]) ;
253 /*LOCAL_DEBUG_OUT( "%d pixels written", k );*/
254 }
255 
256 static inline void
enlarge_component_dumb(register CARD32 * src,register CARD32 * dst,int * scales,int len)257 enlarge_component_dumb( register CARD32 *src, register CARD32 *dst, int *scales, int len )
258 {/* we skip all checks as it is static function and we want to optimize it
259   * as much as possible */
260 	int i = 0, k = 0;
261 	do
262 	{
263 		register CARD32 c = INTERPOLATE_COLOR1(src[i]);
264 		int max_k = k+scales[i];
265 		do
266 		{
267 			dst[k] = c ;
268 		}while( ++k < max_k );
269 	}while( ++i < len );
270 }
271 
272 /* this will shrink array based on count of items in src per one dst item with averaging */
273 static inline void
shrink_component(register CARD32 * src,register CARD32 * dst,int * scales,int len)274 shrink_component( register CARD32 *src, register CARD32 *dst, int *scales, int len )
275 {/* we skip all checks as it is static function and we want to optimize it
276   * as much as possible */
277 	register int i = -1, k = -1;
278 	while( ++k < len )
279 	{
280 		register int reps = scales[k] ;
281 		register int c1 = src[++i];
282 /*LOCAL_DEBUG_OUT( "pixel = %d, scale[k] = %d", k, reps );*/
283 		if( reps == 1 )
284 			dst[k] = AVERAGE_COLOR1(c1);
285 		else if( reps == 2 )
286 		{
287 			++i;
288 			dst[k] = AVERAGE_COLOR2(c1,src[i]);
289 		}else
290 		{
291 			reps += i-1;
292 			while( reps > i )
293 			{
294 				++i ;
295 				c1 += src[i];
296 			}
297 			{
298 				register short S = scales[k];
299 				dst[k] = AVERAGE_COLORN(c1,S);
300 			}
301 		}
302 	}
303 }
304 static inline void
shrink_component11(register CARD32 * src,register CARD32 * dst,int * scales,int len)305 shrink_component11( register CARD32 *src, register CARD32 *dst, int *scales, int len )
306 {
307 	register int i ;
308 	for( i = 0 ; i < len ; ++i )
309 		dst[i] = AVERAGE_COLOR1(src[i]);
310 }
311 
312 
313 static inline void
reverse_component(register CARD32 * src,register CARD32 * dst,int * unused,int len)314 reverse_component( register CARD32 *src, register CARD32 *dst, int *unused, int len )
315 {
316 	register int i = 0;
317 	src += len-1 ;
318 	do
319 	{
320 		dst[i] = src[-i];
321 	}while(++i < len );
322 }
323 
324 static inline void
add_component(CARD32 * src,CARD32 * incr,int * scales,int len)325 add_component( CARD32 *src, CARD32 *incr, int *scales, int len )
326 {
327 	len += len&0x01;
328 #ifdef HAVE_MMX
329 #if 1
330 	if( asimage_use_mmx )
331 	{
332 		int i = 0;
333 		__m64  *vdst = (__m64*)&(src[0]);
334 		__m64  *vinc = (__m64*)&(incr[0]);
335 		len = len>>1;
336 		do{
337 			vdst[i] = _mm_add_pi32(vdst[i],vinc[i]);  /* paddd */
338 		}while( ++i  < len );
339 		_mm_empty();
340 	}else
341 #else
342 	if( asimage_use_mmx )
343 	{
344 		double *ddst = (double*)&(src[0]);
345 		double *dinc = (double*)&(incr[0]);
346 		len = len>>1;
347 		do{
348 			asm volatile
349        		(
350             	"movq %0, %%mm0  \n\t" /* load 8 bytes from src[i] into MM0 */
351             	"paddd %1, %%mm0 \n\t" /* MM0=src[i]>>1              */
352             	"movq %%mm0, %0  \n\t" /* store the result in dest */
353 				: "=m" (ddst[i])       /* %0 */
354 				:  "m"  (dinc[i])       /* %2 */
355 	        );
356 		}while( ++i < len );
357 	}else
358 #endif
359 #endif
360 	{
361 		register int c1, c2;
362 		int i = 0;
363 		do{
364 			c1 = (int)src[i] + (int)incr[i] ;
365 			c2 = (int)src[i+1] + (int)incr[i+1] ;
366 			src[i] = c1;
367 			src[i+1] = c2;
368 			i += 2 ;
369 		}while( i < len );
370 	}
371 }
372 
373 #ifdef NEED_RBITSHIFT_FUNCS
374 static inline void
rbitshift_component(register CARD32 * src,register CARD32 * dst,int shift,int len)375 rbitshift_component( register CARD32 *src, register CARD32 *dst, int shift, int len )
376 {
377 	register int i ;
378 	for( i = 0 ; i < len ; ++i )
379 		dst[i] = src[i]>>shift;
380 }
381 #endif
382 
383 static inline void
start_component_interpolation(CARD32 * c1,CARD32 * c2,CARD32 * c3,CARD32 * c4,register CARD32 * T,register CARD32 * step,int S,int len)384 start_component_interpolation( CARD32 *c1, CARD32 *c2, CARD32 *c3, CARD32 *c4, register CARD32 *T, register CARD32 *step, int S, int len)
385 {
386 	register int i;
387 	for( i = 0 ; i < len ; i++ )
388 	{
389 		register int rc2 = c2[i], rc3 = c3[i] ;
390 		T[i] = INTERPOLATION_TOTAL_START(c1[i],rc2,rc3,c4[i],S)/(S<<1);
391 		step[i] = INTERPOLATION_TOTAL_STEP(rc2,rc3)/(S<<1);
392 	}
393 }
394 
395 static inline void
component_interpolation_hardcoded(CARD32 * c1,CARD32 * c2,CARD32 * c3,CARD32 * c4,register CARD32 * T,CARD32 * unused,CARD16 kind,int len)396 component_interpolation_hardcoded( CARD32 *c1, CARD32 *c2, CARD32 *c3, CARD32 *c4, register CARD32 *T, CARD32 *unused, CARD16 kind, int len)
397 {
398 	register int i;
399 	if( kind == 1 )
400 	{
401 		for( i = 0 ; i < len ; i++ )
402 		{
403 #if 1
404 			/* its seems that this simple formula is completely sufficient
405 			   and even better then more complicated one : */
406 			T[i] = (c2[i]+c3[i])>>1 ;
407 #else
408     		register int minus = c1[i]+c4[i] ;
409 			register int plus  = (c2[i]<<1)+c2[i]+(c3[i]<<1)+c3[i];
410 
411 			T[i] = ( (plus>>1) < minus )?(c2[i]+c3[i])>>1 :
412 								   		 (plus-minus)>>2;
413 #endif
414 		}
415 	}else if( kind == 2 )
416 	{
417 		for( i = 0 ; i < len ; i++ )
418 		{
419     		register int rc1 = c1[i], rc2 = c2[i], rc3 = c3[i] ;
420 			T[i] = INTERPOLATE_A_COLOR3_V(rc1,rc2,rc3,c4[i]);
421 		}
422 	}else
423 		for( i = 0 ; i < len ; i++ )
424 		{
425     		register int rc1 = c1[i], rc2 = c2[i], rc3 = c3[i] ;
426 			T[i] = INTERPOLATE_B_COLOR3_V(rc1,rc2,rc3,c4[i]);
427 		}
428 }
429 
430 #ifdef NEED_RBITSHIFT_FUNCS
431 static inline void
divide_component_mod(register CARD32 * data,CARD16 ratio,int len)432 divide_component_mod( register CARD32 *data, CARD16 ratio, int len )
433 {
434 	register int i ;
435 	for( i = 0 ; i < len ; ++i )
436 		data[i] /= ratio;
437 }
438 
439 static inline void
rbitshift_component_mod(register CARD32 * data,int bits,int len)440 rbitshift_component_mod( register CARD32 *data, int bits, int len )
441 {
442 	register int i ;
443 	for( i = 0 ; i < len ; ++i )
444 		data[i] = data[i]>>bits;
445 }
446 #endif
447 void
print_component(register CARD32 * data,int nonsense,int len)448 print_component( register CARD32 *data, int nonsense, int len )
449 {
450 	register int i ;
451 	for( i = 0 ; i < len ; ++i )
452 		fprintf( stderr, " %8.8lX", (long)data[i] );
453 	fprintf( stderr, "\n");
454 }
455 
456 static inline void
tint_component_mod(register CARD32 * data,CARD16 ratio,int len)457 tint_component_mod( register CARD32 *data, CARD16 ratio, int len )
458 {
459 	register int i ;
460 	if( ratio == 255 )
461 		for( i = 0 ; i < len ; ++i )
462 			data[i] = data[i]<<8;
463 	else if( ratio == 128 )
464 		for( i = 0 ; i < len ; ++i )
465 			data[i] = data[i]<<7;
466 	else if( ratio == 0 )
467 		for( i = 0 ; i < len ; ++i )
468 			data[i] = 0;
469 	else
470 		for( i = 0 ; i < len ; ++i )
471 			data[i] = data[i]*ratio;
472 }
473 
474 static inline void
make_component_gradient16(register CARD32 * data,CARD16 from,CARD16 to,CARD8 seed,int len)475 make_component_gradient16( register CARD32 *data, CARD16 from, CARD16 to, CARD8 seed, int len )
476 {
477 	register int i ;
478 	long incr = (((long)to<<8)-((long)from<<8))/len ;
479 
480 	if( incr == 0 )
481 		for( i = 0 ; i < len ; ++i )
482 			data[i] = from;
483 	else
484 	{
485 		long curr = from<<8;
486 		curr += ((long)(((CARD32)seed)<<8) > incr)?incr:((CARD32)seed)<<8 ;
487 		for( i = 0 ; i < len ; ++i )
488 		{/* we make calculations in 24bit per chan, then convert it back to 16 and
489 		  * carry over half of the quantization error onto the next pixel */
490 			data[i] = curr>>8;
491 			curr += ((curr&0x00FF)>>1)+incr ;
492 		}
493 	}
494 }
495 
496 
497 static inline void
copytintpad_scanline(ASScanline * src,ASScanline * dst,int offset,ARGB32 tint)498 copytintpad_scanline( ASScanline *src, ASScanline *dst, int offset, ARGB32 tint )
499 {
500 	register int i ;
501 	CARD32 chan_tint[4], chan_fill[4] ;
502 	int color ;
503 	int copy_width = src->width, dst_offset = 0, src_offset = 0;
504 
505 	if( offset+(int)src->width < 0 || offset > (int)dst->width )
506 		return;
507 	chan_tint[IC_RED]   = ARGB32_RED8  (tint)<<1;
508 	chan_tint[IC_GREEN] = ARGB32_GREEN8(tint)<<1;
509 	chan_tint[IC_BLUE]  = ARGB32_BLUE8 (tint)<<1;
510 	chan_tint[IC_ALPHA] = ARGB32_ALPHA8(tint)<<1;
511 	chan_fill[IC_RED]   = ARGB32_RED8  (dst->back_color)<<dst->shift;
512 	chan_fill[IC_GREEN] = ARGB32_GREEN8(dst->back_color)<<dst->shift;
513 	chan_fill[IC_BLUE]  = ARGB32_BLUE8 (dst->back_color)<<dst->shift;
514 	chan_fill[IC_ALPHA] = ARGB32_ALPHA8(dst->back_color)<<dst->shift;
515 	if( offset < 0 )
516 		src_offset = -offset ;
517 	else
518 		dst_offset = offset ;
519 	copy_width = MIN( src->width-src_offset, dst->width-dst_offset );
520 
521 	dst->flags = src->flags ;
522 	for( color = 0 ; color < IC_NUM_CHANNELS ; ++color )
523 	{
524 		register CARD32 *psrc = src->channels[color]+src_offset;
525 		register CARD32 *pdst = dst->channels[color];
526 		int ratio = chan_tint[color];
527 /*	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 );
528 */
529 		{
530 /*			register CARD32 fill = chan_fill[color]; */
531 			for( i = 0 ; i < dst_offset ; ++i )
532 				pdst[i] = 0;
533 			pdst += dst_offset ;
534 		}
535 
536 		if( get_flags(src->flags, 0x01<<color) )
537 		{
538 			if( ratio >= 254 )
539 				for( i = 0 ; i < copy_width ; ++i )
540 					pdst[i] = psrc[i]<<8;
541 			else if( ratio == 128 )
542 				for( i = 0 ; i < copy_width ; ++i )
543 					pdst[i] = psrc[i]<<7;
544 			else if( ratio == 0 )
545 				for( i = 0 ; i < copy_width ; ++i )
546 					pdst[i] = 0;
547 			else
548 				for( i = 0 ; i < copy_width ; ++i )
549 					pdst[i] = psrc[i]*ratio;
550 		}else
551 		{
552 		    ratio = ratio*chan_fill[color];
553 			for( i = 0 ; i < copy_width ; ++i )
554 				pdst[i] = ratio;
555 			set_flags( dst->flags, (0x01<<color));
556 		}
557 		{
558 /*			register CARD32 fill = chan_fill[color]; */
559 			for( ; i < (int)dst->width-dst_offset ; ++i )
560 				pdst[i] = 0;
561 /*				print_component(pdst, 0, dst->width ); */
562 		}
563 	}
564 }
565 
566 /* **********************************************************************************************/
567 /* drawing gradient on scanline :  															   */
568 /* **********************************************************************************************/
569 void
make_gradient_scanline(ASScanline * scl,ASGradient * grad,ASFlagType filter,ARGB32 seed)570 make_gradient_scanline( ASScanline *scl, ASGradient *grad, ASFlagType filter, ARGB32 seed )
571 {
572 	if( scl && grad && filter != 0 )
573 	{
574 		int offset = 0, step, i, max_i = grad->npoints - 1 ;
575 		ARGB32 last_color = ARGB32_Black ;
576 		int last_idx = 0;
577 		double last_offset = 0., *offsets = grad->offset ;
578 		int *used = safecalloc(max_i+1, sizeof(int));
579 		/* lets find the color of the very first point : */
580 		for( i = 0 ; i <= max_i ; ++i )
581 			if( offsets[i] <= 0. )
582 			{
583 				last_color = grad->color[i] ;
584 				last_idx = i ;
585 				used[i] = 1 ;
586 				break;
587 			}
588 
589 		for( i = 0  ; i <= max_i ; i++ )
590 		{
591 			register int k ;
592 			int new_idx = -1 ;
593 			/* now lets find the next point  : */
594 			for( k = 0 ; k <= max_i ; ++k )
595 			{
596 				if( used[k]==0 && offsets[k] >= last_offset )
597 				{
598 					if( new_idx < 0 )
599 						new_idx = k ;
600 					else if( offsets[new_idx] > offsets[k] )
601 						new_idx = k ;
602 					else
603 					{
604 						register int d1 = new_idx-last_idx ;
605 						register int d2 = k - last_idx ;
606 						if( d1*d1 > d2*d2 )
607 							new_idx = k ;
608 					}
609 				}
610 			}
611 			if( new_idx < 0 )
612 				break;
613 			used[new_idx] = 1 ;
614 			step = (int)((grad->offset[new_idx] * (double)scl->width) - (double)offset) ;
615 /*			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 ); */
616 			if( step > (int)scl->width-offset )
617 				step = (int)scl->width-offset ;
618 			if( step > 0 )
619 			{
620 				int color ;
621 				for( color = 0 ; color < IC_NUM_CHANNELS ; ++color )
622 					if( get_flags( filter, 0x01<<color ) )
623 					{
624 						LOCAL_DEBUG_OUT("channel %d from #%4.4lX to #%4.4lX, ofset = %d, step = %d",
625 	 	 									color, ARGB32_CHAN8(last_color,color)<<8, ARGB32_CHAN8(grad->color[new_idx],color)<<8, offset, step );
626 						make_component_gradient16( scl->channels[color]+offset,
627 												   (CARD16)(ARGB32_CHAN8(last_color,color)<<8),
628 												   (CARD16)(ARGB32_CHAN8(grad->color[new_idx],color)<<8),
629 												   (CARD8)ARGB32_CHAN8(seed,color),
630 												   step);
631 					}
632 				offset += step ;
633 			}
634 			last_offset = offsets[new_idx];
635 			last_color = grad->color[new_idx];
636 			last_idx = new_idx ;
637 		}
638 		scl->flags = filter ;
639 		free( used );
640 	}
641 }
642 
643 /* **********************************************************************************************/
644 /* Scaling code ; 																			   */
645 /* **********************************************************************************************/
646 Bool
check_scale_parameters(ASImage * src,int src_width,int src_height,int * to_width,int * to_height)647 check_scale_parameters( ASImage *src, int src_width, int src_height, int *to_width, int *to_height )
648 {
649 	if( src == NULL )
650 		return False;
651 
652 	if( *to_width == 0 )
653 		*to_width = src_width ;
654 	else if( *to_width < 2 )
655 		*to_width = 2 ;
656 	if( *to_height == 0 )
657 		*to_height = src_height ;
658 	else if( *to_height < 2 )
659 		*to_height = 2 ;
660 	return True;
661 }
662 
663 int *
make_scales(int from_size,int to_size,int tail)664 make_scales( int from_size, int to_size, int tail )
665 {
666 	int *scales ;
667     int smaller = MIN(from_size,to_size);
668     int bigger  = MAX(from_size,to_size);
669 	register int i = 0, k = 0;
670 	int eps;
671     LOCAL_DEBUG_OUT( "from %d to %d tail %d", from_size, to_size, tail );
672 	scales = safecalloc( smaller+tail, sizeof(int));
673 	if( smaller <= 1 )
674 	{
675 		scales[0] = bigger ;
676 		return scales;
677 	}
678 #if 1
679 	else if( smaller == bigger )
680 	{
681 		for ( i = 0 ; i < smaller ; i++ )
682 			scales[i] = 1 ;
683 		return scales;
684 	}
685 #endif
686 	if( from_size >= to_size )
687 		tail = 0 ;
688 	if( tail != 0 )
689     {
690         bigger-=tail ;
691         if( (smaller-=tail) == 1 )
692 		{
693 			scales[0] = bigger ;
694 			return scales;
695 		}
696     }else if( smaller == 2 )
697 	{
698 		scales[1] = bigger/2 ;
699 		scales[0] = bigger - scales[1] ;
700 		return scales ;
701 	}
702 
703     eps = -bigger/2;
704     LOCAL_DEBUG_OUT( "smaller %d, bigger %d, eps %d", smaller, bigger, eps );
705     /* now using Bresengham algoritm to fiill the scales :
706 	 * since scaling is merely transformation
707 	 * from 0:bigger space (x) to 0:smaller space(y)*/
708 	for ( i = 0 ; i < bigger ; i++ )
709 	{
710 		++scales[k];
711 		eps += smaller;
712         LOCAL_DEBUG_OUT( "scales[%d] = %d, i = %d, k = %d, eps %d", k, scales[k], i, k, eps );
713         if( eps+eps >= bigger )
714 		{
715 			++k ;
716 			eps -= bigger ;
717 		}
718 	}
719 
720 	return scales;
721 }
722 
723 /* *******************************************************************/
724 void
scale_image_down(ASImageDecoder * imdec,ASImageOutput * imout,int h_ratio,int * scales_h,int * scales_v)725 scale_image_down( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
726 {
727 	ASScanline dst_line, total ;
728 	int k = -1;
729 	int max_k 	 = imout->im->height,
730 		line_len = MIN(imout->im->width, imdec->out_width);
731 
732 	prepare_scanline( imout->im->width, QUANT_ERR_BITS, &dst_line, imout->asv->BGR_mode );
733 	prepare_scanline( imout->im->width, QUANT_ERR_BITS, &total, imout->asv->BGR_mode );
734 	while( ++k < max_k )
735 	{
736 		int reps = scales_v[k] ;
737 		imdec->decode_image_scanline( imdec );
738 		total.flags = imdec->buffer.flags ;
739 		CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,total,scales_h,line_len);
740 
741 		while( --reps > 0 )
742 		{
743 			imdec->decode_image_scanline( imdec );
744 			total.flags = imdec->buffer.flags ;
745 			CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,dst_line,scales_h,line_len);
746 			SCANLINE_FUNC(add_component,total,dst_line,NULL,total.width);
747 		}
748 
749 		imout->output_image_scanline( imout, &total, scales_v[k] );
750 	}
751 	free_scanline(&dst_line, True);
752 	free_scanline(&total, True);
753 }
754 
755 void
scale_image_up(ASImageDecoder * imdec,ASImageOutput * imout,int h_ratio,int * scales_h,int * scales_v)756 scale_image_up( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
757 {
758 	ASScanline src_lines[4], *c1, *c2, *c3, *c4 = NULL;
759 	int i = 0, max_i,
760 		line_len = MIN(imout->im->width, imdec->out_width),
761 		out_width = imout->im->width;
762 	ASScanline step ;
763 
764 	prepare_scanline( out_width, 0, &(src_lines[0]), imout->asv->BGR_mode);
765 	prepare_scanline( out_width, 0, &(src_lines[1]), imout->asv->BGR_mode);
766 	prepare_scanline( out_width, 0, &(src_lines[2]), imout->asv->BGR_mode);
767 	prepare_scanline( out_width, 0, &(src_lines[3]), imout->asv->BGR_mode);
768 	prepare_scanline( out_width, QUANT_ERR_BITS, &step, imout->asv->BGR_mode );
769 
770 /*	set_component(src_lines[0].red,0x00000000,0,out_width*3); */
771 	imdec->decode_image_scanline( imdec );
772 	src_lines[1].flags = imdec->buffer.flags ;
773 	CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_lines[1],scales_h,line_len);
774 
775 	step.flags = src_lines[0].flags = src_lines[1].flags ;
776 
777 	SCANLINE_FUNC(copy_component,src_lines[1],src_lines[0],0,out_width);
778 
779 	imdec->decode_image_scanline( imdec );
780 	src_lines[2].flags = imdec->buffer.flags ;
781 	CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_lines[2],scales_h,line_len);
782 
783 	i = 0 ;
784 	max_i = imdec->out_height-1 ;
785 	LOCAL_DEBUG_OUT( "i = %d, max_i = %d", i, max_i );
786 	do
787 	{
788 		int S = scales_v[i] ;
789 		c1 = &(src_lines[i&0x03]);
790 		c2 = &(src_lines[(i+1)&0x03]);
791 		c3 = &(src_lines[(i+2)&0x03]);
792 		c4 = &(src_lines[(i+3)&0x03]);
793 
794 		if( i+1 < max_i )
795 		{
796 			imdec->decode_image_scanline( imdec );
797 			c4->flags = imdec->buffer.flags ;
798 			CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,*c4,scales_h,line_len);
799 		}
800 		/* now we'll prepare total and step : */
801         if( S > 0 )
802         {
803             imout->output_image_scanline( imout, c2, 1);
804             if( S > 1 )
805             {
806                 if( S == 2 )
807                 {
808                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,1,out_width);
809                     imout->output_image_scanline( imout, c1, 1);
810                 }else if( S == 3 )
811                 {
812                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,2,out_width);
813                     imout->output_image_scanline( imout, c1, 1);
814                     SCANLINE_COMBINE(component_interpolation_hardcoded,*c1,*c2,*c3,*c4,*c1,*c1,3,out_width);
815                     imout->output_image_scanline( imout, c1, 1);
816                 }else
817                 {
818                     SCANLINE_COMBINE(start_component_interpolation,*c1,*c2,*c3,*c4,*c1,step,S,out_width);
819                     do
820                     {
821                         imout->output_image_scanline( imout, c1, 1);
822                         if((--S)<=1)
823                             break;
824                         SCANLINE_FUNC(add_component,*c1,step,NULL,out_width );
825                     }while(1);
826                 }
827             }
828         }
829 	}while( ++i < max_i );
830     imout->output_image_scanline( imout, c3, 1);
831 	free_scanline(&step, True);
832 	free_scanline(&(src_lines[3]), True);
833 	free_scanline(&(src_lines[2]), True);
834 	free_scanline(&(src_lines[1]), True);
835 	free_scanline(&(src_lines[0]), True);
836 }
837 
838 void
scale_image_up_dumb(ASImageDecoder * imdec,ASImageOutput * imout,int h_ratio,int * scales_h,int * scales_v)839 scale_image_up_dumb( ASImageDecoder *imdec, ASImageOutput *imout, int h_ratio, int *scales_h, int* scales_v)
840 {
841 	ASScanline src_line;
842 	int	line_len = MIN(imout->im->width, imdec->out_width);
843 	int	out_width = imout->im->width;
844 	int y = 0 ;
845 
846 	prepare_scanline( out_width, QUANT_ERR_BITS, &src_line, imout->asv->BGR_mode );
847 
848 	imout->tiling_step = 1 ;
849 	LOCAL_DEBUG_OUT( "imdec->next_line = %d, imdec->out_height = %d", imdec->next_line, imdec->out_height );
850 	while( y < (int)imdec->out_height )
851 	{
852 		imdec->decode_image_scanline( imdec );
853 		src_line.flags = imdec->buffer.flags ;
854 		CHOOSE_SCANLINE_FUNC(h_ratio,imdec->buffer,src_line,scales_h,line_len);
855 		imout->tiling_range = scales_v[y];
856 		LOCAL_DEBUG_OUT( "y = %d, tiling_range = %d", y, imout->tiling_range );
857 		imout->output_image_scanline( imout, &src_line, 1);
858 		imout->next_line += scales_v[y]-1;
859 		++y;
860 	}
861 	free_scanline(&src_line, True);
862 }
863 
864 
865 static inline ASImage *
create_destination_image(unsigned int width,unsigned int height,ASAltImFormats format,unsigned int compression,ARGB32 back_color)866 create_destination_image( unsigned int width, unsigned int height, ASAltImFormats format,
867 						  unsigned int compression, ARGB32 back_color )
868 {
869 	ASImage *dst = create_asimage(width, height, compression);
870 	if( dst )
871 	{
872 		if( format != ASA_ASImage )
873 			set_flags( dst->flags, ASIM_DATA_NOT_USEFUL );
874 
875 		dst->back_color = back_color ;
876 	}
877 	return dst ;
878 }
879 
880 
881 /* *****************************************************************************/
882 /* ASImage transformations : 												  */
883 /* *****************************************************************************/
884 ASImage *
scale_asimage(ASVisual * asv,ASImage * src,int to_width,int to_height,ASAltImFormats out_format,unsigned int compression_out,int quality)885 scale_asimage( ASVisual *asv, ASImage *src, int to_width, int to_height,
886 			   ASAltImFormats out_format, unsigned int compression_out, int quality )
887 {
888 	ASImage *dst = NULL ;
889 	ASImageOutput  *imout ;
890 	ASImageDecoder *imdec;
891 	int h_ratio ;
892 	int *scales_h = NULL, *scales_v = NULL;
893 	START_TIME(started);
894 
895 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
896 
897 	if( !check_scale_parameters(src,src->width, src->height,&to_width,&to_height) )
898 		return NULL;
899 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, 0, 0, NULL)) == NULL )
900 		return NULL;
901 
902 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
903 
904 	if( to_width == src->width )
905 		h_ratio = 0;
906 	else if( to_width < src->width )
907 		h_ratio = 1;
908 	else
909 	{
910 		if ( quality == ASIMAGE_QUALITY_POOR )
911 			h_ratio = 1 ;
912 		else if( src->width > 1 )
913 		{
914 			h_ratio = (to_width/(src->width-1))+1;
915 			if( h_ratio*(src->width-1) < to_width )
916 				++h_ratio ;
917 		}else
918 			h_ratio = to_width ;
919 		++h_ratio ;
920 	}
921 	scales_h = make_scales( src->width, to_width, ( quality == ASIMAGE_QUALITY_POOR )?0:1 );
922 	scales_v = make_scales( src->height, to_height, ( quality == ASIMAGE_QUALITY_POOR  || src->height <= 3)?0:1 );
923 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
924 	{
925 	  register int i ;
926 	  for( i = 0 ; i < MIN(src->width, to_width) ; i++ )
927 		fprintf( stderr, " %d", scales_h[i] );
928 	  fprintf( stderr, "\n" );
929 	  for( i = 0 ; i < MIN(src->height, to_height) ; i++ )
930 		fprintf( stderr, " %d", scales_v[i] );
931 	  fprintf( stderr, "\n" );
932 	}
933 #endif
934 	if((imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality )) == NULL )
935 	{
936         destroy_asimage( &dst );
937 	}else
938 	{
939 		if( to_height <= src->height ) 					   /* scaling down */
940 			scale_image_down( imdec, imout, h_ratio, scales_h, scales_v );
941 		else if( quality == ASIMAGE_QUALITY_POOR || src->height <= 3 )
942 			scale_image_up_dumb( imdec, imout, h_ratio, scales_h, scales_v );
943 		else
944 			scale_image_up( imdec, imout, h_ratio, scales_h, scales_v );
945 		stop_image_output( &imout );
946 	}
947 	free( scales_h );
948 	free( scales_v );
949 	stop_image_decoding( &imdec );
950 	SHOW_TIME("", started);
951 	return dst;
952 }
953 
954 ASImage *
scale_asimage2(ASVisual * asv,ASImage * src,int clip_x,int clip_y,int clip_width,int clip_height,int to_width,int to_height,ASAltImFormats out_format,unsigned int compression_out,int quality)955 scale_asimage2( ASVisual *asv, ASImage *src,
956 					int clip_x, int clip_y,
957 					int clip_width, int clip_height,
958 					int to_width, int to_height,
959 			   		ASAltImFormats out_format, unsigned int compression_out, int quality )
960 {
961 	ASImage *dst = NULL ;
962 	ASImageOutput  *imout ;
963 	ASImageDecoder *imdec;
964 	int h_ratio ;
965 	int *scales_h = NULL, *scales_v = NULL;
966 	START_TIME(started);
967 
968 	if( src == NULL )
969 		return NULL;
970 
971 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
972 
973 	if( clip_width == 0 )
974 		clip_width = src->width ;
975 	if( clip_height == 0 )
976 		clip_height = src->height ;
977 	if( !check_scale_parameters(src, clip_width, clip_height, &to_width, &to_height) )
978 		return NULL;
979 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, clip_height, NULL)) == NULL )
980 		return NULL;
981 
982 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
983 
984 	if( to_width == clip_width )
985 		h_ratio = 0;
986 	else if( to_width < clip_width )
987 		h_ratio = 1;
988 	else
989 	{
990 		if ( quality == ASIMAGE_QUALITY_POOR )
991 			h_ratio = 1 ;
992 		else if( clip_width > 1 )
993 		{
994 			h_ratio = (to_width/(clip_width-1))+1;
995 			if( h_ratio*(clip_width-1) < to_width )
996 				++h_ratio ;
997 		}else
998 			h_ratio = to_width ;
999 		++h_ratio ;
1000 	}
1001 	scales_h = make_scales( clip_width, to_width, ( quality == ASIMAGE_QUALITY_POOR )?0:1 );
1002 	scales_v = make_scales( clip_height, to_height, ( quality == ASIMAGE_QUALITY_POOR  || clip_height <= 3)?0:1 );
1003 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
1004 	{
1005 	  register int i ;
1006 	  for( i = 0 ; i < MIN(clip_width, to_width) ; i++ )
1007 		fprintf( stderr, " %d", scales_h[i] );
1008 	  fprintf( stderr, "\n" );
1009 	  for( i = 0 ; i < MIN(clip_height, to_height) ; i++ )
1010 		fprintf( stderr, " %d", scales_v[i] );
1011 	  fprintf( stderr, "\n" );
1012 	}
1013 #endif
1014 	if((imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality )) == NULL )
1015 	{
1016         destroy_asimage( &dst );
1017 	}else
1018 	{
1019 		if( to_height <= clip_height ) 					   /* scaling down */
1020 			scale_image_down( imdec, imout, h_ratio, scales_h, scales_v );
1021 		else if( quality == ASIMAGE_QUALITY_POOR || clip_height <= 3 )
1022 			scale_image_up_dumb( imdec, imout, h_ratio, scales_h, scales_v );
1023 		else
1024 			scale_image_up( imdec, imout, h_ratio, scales_h, scales_v );
1025 		stop_image_output( &imout );
1026 	}
1027 	free( scales_h );
1028 	free( scales_v );
1029 	stop_image_decoding( &imdec );
1030 	SHOW_TIME("", started);
1031 	return dst;
1032 }
1033 
1034 ASImage *
tile_asimage(ASVisual * asv,ASImage * src,int offset_x,int offset_y,int to_width,int to_height,ARGB32 tint,ASAltImFormats out_format,unsigned int compression_out,int quality)1035 tile_asimage( ASVisual *asv, ASImage *src,
1036 		      int offset_x, int offset_y,
1037 			  int to_width,
1038 			  int to_height,
1039 			  ARGB32 tint,
1040 			  ASAltImFormats out_format, unsigned int compression_out, int quality )
1041 {
1042 	ASImage *dst = NULL ;
1043 	ASImageDecoder *imdec ;
1044 	ASImageOutput  *imout ;
1045 	START_TIME(started);
1046 
1047 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1048 
1049 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 );
1050 	if( src== NULL || (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y, to_width, 0, NULL)) == NULL )
1051 	{
1052 		LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
1053 		return NULL;
1054 	}
1055 
1056 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color );
1057 
1058 	if((imout = start_image_output( asv, dst, out_format, (tint!=0)?8:0, quality)) == NULL )
1059 	{
1060 		LOCAL_DEBUG_OUT( "failed to start image output%s", "");
1061         destroy_asimage( &dst );
1062     }else
1063 	{
1064 		int y, max_y = to_height;
1065 LOCAL_DEBUG_OUT("tiling actually...%s", "");
1066 		if( to_height > src->height )
1067 		{
1068 			imout->tiling_step = src->height ;
1069 			max_y = src->height ;
1070 		}
1071 		if( tint != 0 )
1072 		{
1073 			for( y = 0 ; y < max_y ; y++  )
1074 			{
1075 				imdec->decode_image_scanline( imdec );
1076 				tint_component_mod( imdec->buffer.red, (CARD16)(ARGB32_RED8(tint)<<1), to_width );
1077 				tint_component_mod( imdec->buffer.green, (CARD16)(ARGB32_GREEN8(tint)<<1), to_width );
1078   				tint_component_mod( imdec->buffer.blue, (CARD16)(ARGB32_BLUE8(tint)<<1), to_width );
1079 				tint_component_mod( imdec->buffer.alpha, (CARD16)(ARGB32_ALPHA8(tint)<<1), to_width );
1080 				imout->output_image_scanline( imout, &(imdec->buffer), 1);
1081 			}
1082 		}else
1083 			for( y = 0 ; y < max_y ; y++  )
1084 			{
1085 				imdec->decode_image_scanline( imdec );
1086 				imout->output_image_scanline( imout, &(imdec->buffer), 1);
1087 			}
1088 		stop_image_output( &imout );
1089 	}
1090 	stop_image_decoding( &imdec );
1091 
1092 	SHOW_TIME("", started);
1093 	return dst;
1094 }
1095 
1096 ASImage *
merge_layers(ASVisual * asv,ASImageLayer * layers,int count,int dst_width,int dst_height,ASAltImFormats out_format,unsigned int compression_out,int quality)1097 merge_layers( ASVisual *asv,
1098 				ASImageLayer *layers, int count,
1099 			  	int dst_width,
1100 			  	int dst_height,
1101 			  	ASAltImFormats out_format, unsigned int compression_out, int quality )
1102 {
1103 	ASImage *dst = NULL ;
1104 	ASImageDecoder **imdecs ;
1105 	ASImageOutput  *imout ;
1106 	ASImageLayer *pcurr = layers;
1107 	int i ;
1108 	ASScanline dst_line ;
1109 	START_TIME(started);
1110 
1111 LOCAL_DEBUG_CALLER_OUT( "dst_width = %d, dst_height = %d", dst_width, dst_height );
1112 
1113 	dst = create_destination_image( dst_width, dst_height, out_format, compression_out, ARGB32_DEFAULT_BACK_COLOR );
1114 	if( dst == NULL )
1115 		return NULL;
1116 
1117 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1118 
1119 	prepare_scanline( dst_width, QUANT_ERR_BITS, &dst_line, asv->BGR_mode );
1120 	dst_line.flags = SCL_DO_ALL ;
1121 
1122 	imdecs = safecalloc( count+20, sizeof(ASImageDecoder*));
1123 
1124 	for( i = 0 ; i < count ; i++ )
1125 	{
1126 		/* all laayers but first must have valid image or solid_color ! */
1127 		if( (pcurr->im != NULL || pcurr->solid_color != 0 || i == 0) &&
1128 			pcurr->dst_x < (int)dst_width && pcurr->dst_x+(int)pcurr->clip_width > 0 )
1129 		{
1130 			imdecs[i] = start_image_decoding(asv, pcurr->im, SCL_DO_ALL,
1131 				                             pcurr->clip_x, pcurr->clip_y,
1132 											 pcurr->clip_width, pcurr->clip_height,
1133 											 pcurr->bevel);
1134 			if( pcurr->bevel_width != 0 && pcurr->bevel_height != 0 )
1135 				set_decoder_bevel_geom( imdecs[i],
1136 				                        pcurr->bevel_x, pcurr->bevel_y,
1137 										pcurr->bevel_width, pcurr->bevel_height );
1138   			if( pcurr->tint == 0 && i != 0 )
1139 				set_decoder_shift( imdecs[i], 8 );
1140 			if( pcurr->im == NULL )
1141 				set_decoder_back_color( imdecs[i], pcurr->solid_color );
1142 		}
1143 		if( pcurr->next == pcurr )
1144 			break;
1145 		else
1146 			pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
1147 	}
1148 	if( i < count )
1149 		count = i+1 ;
1150 
1151 	if(imdecs[0] == NULL || (imout = start_image_output( asv, dst, out_format, QUANT_ERR_BITS, quality)) == NULL )
1152 	{
1153 		for( i = 0 ; i < count ; i++ )
1154 			if( imdecs[i] )
1155 				stop_image_decoding( &(imdecs[i]) );
1156 
1157         destroy_asimage( &dst );
1158 		free_scanline( &dst_line, True );
1159     }else
1160 	{
1161 		int y, max_y = 0;
1162 		int min_y = dst_height;
1163 		int bg_tint = (layers[0].tint==0)?0x7F7F7F7F:layers[0].tint ;
1164 		int bg_bottom = layers[0].dst_y+layers[0].clip_height+imdecs[0]->bevel_v_addon ;
1165 LOCAL_DEBUG_OUT("blending actually...%s", "");
1166 		pcurr = layers ;
1167 		for( i = 0 ; i < count ; i++ )
1168 		{
1169 			if( imdecs[i] )
1170 			{
1171 				int layer_bottom = pcurr->dst_y+pcurr->clip_height ;
1172 				if( pcurr->dst_y < min_y )
1173 					min_y = pcurr->dst_y;
1174 				layer_bottom += imdecs[i]->bevel_v_addon ;
1175 				if( (int)layer_bottom > max_y )
1176 					max_y = layer_bottom;
1177 			}
1178 			pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
1179 		}
1180 		if( min_y < 0 )
1181 			min_y = 0 ;
1182 		else if( min_y >= (int)dst_height )
1183 			min_y = dst_height ;
1184 
1185 		if( max_y >= (int)dst_height )
1186 			max_y = dst_height ;
1187 		else
1188 			imout->tiling_step = max_y ;
1189 
1190 LOCAL_DEBUG_OUT( "min_y = %d, max_y = %d", min_y, max_y );
1191 		dst_line.back_color = imdecs[0]->back_color ;
1192 		dst_line.flags = 0 ;
1193 		for( y = 0 ; y < min_y ; ++y  )
1194 			imout->output_image_scanline( imout, &dst_line, 1);
1195 		dst_line.flags = SCL_DO_ALL ;
1196 		pcurr = layers ;
1197 		for( i = 0 ; i < count ; ++i )
1198 		{
1199 			if( imdecs[i] && pcurr->dst_y < min_y  )
1200 				imdecs[i]->next_line = min_y - pcurr->dst_y ;
1201 			pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
1202 		}
1203 		for( ; y < max_y ; ++y  )
1204 		{
1205 			if( layers[0].dst_y <= y && bg_bottom > y )
1206 				imdecs[0]->decode_image_scanline( imdecs[0] );
1207 			else
1208 			{
1209 				imdecs[0]->buffer.back_color = imdecs[0]->back_color ;
1210 				imdecs[0]->buffer.flags = 0 ;
1211 			}
1212 			copytintpad_scanline( &(imdecs[0]->buffer), &dst_line, layers[0].dst_x, bg_tint );
1213 			pcurr = layers[0].next?layers[0].next:&(layers[1]) ;
1214 			for( i = 1 ; i < count ; i++ )
1215 			{
1216 				if( imdecs[i] && pcurr->dst_y <= y &&
1217 					pcurr->dst_y+(int)pcurr->clip_height+(int)imdecs[i]->bevel_v_addon > y )
1218 				{
1219 					register ASScanline *b = &(imdecs[i]->buffer);
1220 					CARD32 tint = pcurr->tint ;
1221 					imdecs[i]->decode_image_scanline( imdecs[i] );
1222 					if( tint != 0 )
1223 					{
1224 						tint_component_mod( b->red,   (CARD16)(ARGB32_RED8(tint)<<1),   b->width );
1225 						tint_component_mod( b->green, (CARD16)(ARGB32_GREEN8(tint)<<1), b->width );
1226   					   	tint_component_mod( b->blue,  (CARD16)(ARGB32_BLUE8(tint)<<1),  b->width );
1227 					  	tint_component_mod( b->alpha, (CARD16)(ARGB32_ALPHA8(tint)<<1), b->width );
1228 					}
1229 					pcurr->merge_scanlines( &dst_line, b, pcurr->dst_x );
1230 				}
1231 				pcurr = (pcurr->next!=NULL)?pcurr->next:pcurr+1 ;
1232 			}
1233 			imout->output_image_scanline( imout, &dst_line, 1);
1234 		}
1235 		dst_line.back_color = imdecs[0]->back_color ;
1236 		dst_line.flags = 0 ;
1237 		for( ; y < (int)dst_height ; y++  )
1238 			imout->output_image_scanline( imout, &dst_line, 1);
1239 		stop_image_output( &imout );
1240 	}
1241 	for( i = 0 ; i < count ; i++ )
1242 		if( imdecs[i] != NULL )
1243 		{
1244 			stop_image_decoding( &(imdecs[i]) );
1245 		}
1246 	free( imdecs );
1247 	free_scanline( &dst_line, True );
1248 	SHOW_TIME("", started);
1249 	return dst;
1250 }
1251 
1252 /* **************************************************************************************/
1253 /* GRADIENT drawing : 																   */
1254 /* **************************************************************************************/
1255 static void
make_gradient_left2right(ASImageOutput * imout,ASScanline * dither_lines,int dither_lines_num,ASFlagType filter)1256 make_gradient_left2right( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter )
1257 {
1258 	int line ;
1259 
1260 	imout->tiling_step = dither_lines_num;
1261 	for( line = 0 ; line < dither_lines_num ; line++ )
1262 		imout->output_image_scanline( imout, &(dither_lines[line]), 1);
1263 }
1264 
1265 static void
make_gradient_top2bottom(ASImageOutput * imout,ASScanline * dither_lines,int dither_lines_num,ASFlagType filter)1266 make_gradient_top2bottom( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter )
1267 {
1268 	int y, height = imout->im->height, width = imout->im->width ;
1269 	int line ;
1270 	ASScanline result;
1271 	CARD32 chan_data[MAX_GRADIENT_DITHER_LINES] = {0,0,0,0};
1272 LOCAL_DEBUG_CALLER_OUT( "width = %d, height = %d, filetr = 0x%lX, dither_count = %d\n", width, height, filter, dither_lines_num );
1273 	prepare_scanline( width, QUANT_ERR_BITS, &result, imout->asv->BGR_mode );
1274 	for( y = 0 ; y < height ; y++ )
1275 	{
1276 		int color ;
1277 
1278 		result.flags = 0 ;
1279 		result.back_color = ARGB32_DEFAULT_BACK_COLOR ;
1280 		LOCAL_DEBUG_OUT( "line: %d", y );
1281 		for( color = 0 ; color < IC_NUM_CHANNELS ; color++ )
1282 			if( get_flags( filter, 0x01<<color ) )
1283 			{
1284 				Bool dithered = False ;
1285 				for( line = 0 ; line < dither_lines_num ; line++ )
1286 				{
1287 					/* we want to do error diffusion here since in other places it only works
1288 						* in horisontal direction : */
1289 					CARD32 c = dither_lines[line].channels[color][y] ;
1290 					if( y+1 < height )
1291 					{
1292 						c += ((dither_lines[line].channels[color][y+1]&0xFF)>>1);
1293 						if( (c&0xFFFF0000) != 0 )
1294 							c = ( c&0x7F000000 )?0:0x0000FF00;
1295 					}
1296 					chan_data[line] = c ;
1297 
1298 					if( chan_data[line] != chan_data[0] )
1299 						dithered = True;
1300 				}
1301 				LOCAL_DEBUG_OUT( "channel: %d. Dithered ? %d", color, dithered );
1302 
1303 				if( !dithered )
1304 				{
1305 					result.back_color = (result.back_color&(~MAKE_ARGB32_CHAN8(0xFF,color)))|
1306 										MAKE_ARGB32_CHAN16(chan_data[0],color);
1307 					LOCAL_DEBUG_OUT( "back_color = %8.8lX", result.back_color);
1308 				}else
1309 				{
1310 					register CARD32  *dst = result.channels[color] ;
1311 					for( line = 0 ; line  < dither_lines_num ; line++ )
1312 					{
1313 						register int x ;
1314 						register CARD32 d = chan_data[line] ;
1315 						for( x = line ; x < width ; x+=dither_lines_num )
1316 						{
1317 							dst[x] = d ;
1318 						}
1319 					}
1320 					set_flags(result.flags, 0x01<<color);
1321 				}
1322 			}
1323 		imout->output_image_scanline( imout, &result, 1);
1324 	}
1325 	free_scanline( &result, True );
1326 }
1327 
1328 static void
make_gradient_diag_width(ASImageOutput * imout,ASScanline * dither_lines,int dither_lines_num,ASFlagType filter,Bool from_bottom)1329 make_gradient_diag_width( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter, Bool from_bottom )
1330 {
1331 	int line = 0;
1332 	/* using bresengham algorithm again to trigger horizontal shift : */
1333 	short smaller = imout->im->height;
1334 	short bigger  = imout->im->width;
1335 	register int i = 0;
1336 	int eps;
1337 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 );
1338 
1339 	if( from_bottom )
1340 		toggle_image_output_direction( imout );
1341 	eps = -(bigger>>1);
1342 	for ( i = 0 ; i < bigger ; i++ )
1343 	{
1344 		eps += smaller;
1345 		if( (eps << 1) >= bigger )
1346 		{
1347 			/* put scanline with the same x offset */
1348 			dither_lines[line].offset_x = i ;
1349 			imout->output_image_scanline( imout, &(dither_lines[line]), 1);
1350 			if( ++line >= dither_lines_num )
1351 				line = 0;
1352 			eps -= bigger ;
1353 		}
1354 	}
1355 }
1356 
1357 static void
make_gradient_diag_height(ASImageOutput * imout,ASScanline * dither_lines,int dither_lines_num,ASFlagType filter,Bool from_bottom)1358 make_gradient_diag_height( ASImageOutput *imout, ASScanline *dither_lines, int dither_lines_num, ASFlagType filter, Bool from_bottom )
1359 {
1360 	int line = 0;
1361 	unsigned short width = imout->im->width, height = imout->im->height ;
1362 	/* using bresengham algorithm again to trigger horizontal shift : */
1363 	unsigned short smaller = width;
1364 	unsigned short bigger  = height;
1365 	register int i = 0, k =0;
1366 	int eps;
1367 	ASScanline result;
1368 	int *offsets ;
1369 
1370 	prepare_scanline( width, QUANT_ERR_BITS, &result, imout->asv->BGR_mode );
1371 	offsets = safemalloc( sizeof(int)*width );
1372 	offsets[0] = 0 ;
1373 
1374 	eps = -(bigger>>1);
1375 	for ( i = 0 ; i < bigger ; i++ )
1376 	{
1377 		++offsets[k];
1378 		eps += smaller;
1379 		if( (eps << 1) >= bigger )
1380 		{
1381 			if( ++k >= width )
1382 				break;
1383 			offsets[k] = offsets[k-1] ; /* seeding the offset */
1384 			eps -= bigger ;
1385 		}
1386 	}
1387 
1388 	if( from_bottom )
1389 		toggle_image_output_direction( imout );
1390 
1391 	result.flags = (filter&SCL_DO_ALL);
1392 	if( (filter&SCL_DO_ALL) == SCL_DO_ALL )
1393 	{
1394 		for( i = 0 ; i < height ; i++ )
1395 		{
1396 			for( k = 0 ; k < width ; k++ )
1397 			{
1398 				int offset = i+offsets[k] ;
1399 				CARD32 **src_chan = &(dither_lines[line].channels[0]) ;
1400 				result.alpha[k] = src_chan[IC_ALPHA][offset] ;
1401 				result.red  [k] = src_chan[IC_RED]  [offset] ;
1402 				result.green[k] = src_chan[IC_GREEN][offset] ;
1403 				result.blue [k] = src_chan[IC_BLUE] [offset] ;
1404 				if( ++line >= dither_lines_num )
1405 					line = 0 ;
1406 			}
1407 			imout->output_image_scanline( imout, &result, 1);
1408 		}
1409 	}else
1410 	{
1411 		for( i = 0 ; i < height ; i++ )
1412 		{
1413 			for( k = 0 ; k < width ; k++ )
1414 			{
1415 				int offset = i+offsets[k] ;
1416 				CARD32 **src_chan = &(dither_lines[line].channels[0]) ;
1417 				if( get_flags(filter, SCL_DO_ALPHA) )
1418 					result.alpha[k] = src_chan[IC_ALPHA][offset] ;
1419 				if( get_flags(filter, SCL_DO_RED) )
1420 					result.red[k]   = src_chan[IC_RED]  [offset] ;
1421 				if( get_flags(filter, SCL_DO_GREEN) )
1422 					result.green[k] = src_chan[IC_GREEN][offset] ;
1423 				if( get_flags(filter, SCL_DO_BLUE) )
1424 					result.blue[k]  = src_chan[IC_BLUE] [offset] ;
1425 				if( ++line >= dither_lines_num )
1426 					line = 0 ;
1427 			}
1428 			imout->output_image_scanline( imout, &result, 1);
1429 		}
1430 	}
1431 
1432 	free( offsets );
1433 	free_scanline( &result, True );
1434 }
1435 
1436 static ARGB32
get_best_grad_back_color(ASGradient * grad)1437 get_best_grad_back_color( ASGradient *grad )
1438 {
1439 	ARGB32 back_color = 0 ;
1440 	int chan ;
1441 	for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
1442 	{
1443 		CARD8 best = 0;
1444 		unsigned int best_size = 0;
1445 		register int i = grad->npoints;
1446 		while( --i > 0 )
1447 		{ /* very crude algorithm, detecting biggest spans of the same color :*/
1448 			CARD8 c = ARGB32_CHAN8(grad->color[i], chan );
1449 			unsigned int span = grad->color[i]*20000;
1450 			if( c == ARGB32_CHAN8(grad->color[i-1], chan ) )
1451 			{
1452 				span -= grad->color[i-1]*2000;
1453 				if( c == best )
1454 					best_size += span ;
1455 				else if( span > best_size )
1456 				{
1457 					best_size = span ;
1458 					best = c ;
1459 				}
1460 			}
1461 		}
1462 		back_color |= MAKE_ARGB32_CHAN8(best,chan);
1463 	}
1464 	return back_color;
1465 }
1466 
1467 ASImage*
make_gradient(ASVisual * asv,ASGradient * grad,int width,int height,ASFlagType filter,ASAltImFormats out_format,unsigned int compression_out,int quality)1468 make_gradient( ASVisual *asv, ASGradient *grad,
1469                int width, int height, ASFlagType filter,
1470   			   ASAltImFormats out_format, unsigned int compression_out, int quality  )
1471 {
1472 	ASImage *im = NULL ;
1473 	ASImageOutput *imout;
1474 	int line_len = width;
1475 	START_TIME(started);
1476 LOCAL_DEBUG_CALLER_OUT( "type = 0x%X, width=%d, height = %d, filter = 0x%lX", grad->type, width, height, filter );
1477 	if( grad == NULL )
1478 		return NULL;
1479 
1480 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1481 
1482 	if( width == 0 )
1483 		width = 2;
1484  	if( height == 0 )
1485 		height = 2;
1486 
1487 	im = create_destination_image( width, height, out_format, compression_out, get_best_grad_back_color( grad ) );
1488 
1489 	if( get_flags(grad->type,GRADIENT_TYPE_ORIENTATION) )
1490 		line_len = height ;
1491 	if( get_flags(grad->type,GRADIENT_TYPE_DIAG) )
1492 		line_len = MAX(width,height)<<1 ;
1493 	if((imout = start_image_output( asv, im, out_format, QUANT_ERR_BITS, quality)) == NULL )
1494 	{
1495         destroy_asimage( &im );
1496     }else
1497 	{
1498 		int dither_lines = MIN(imout->quality+1, MAX_GRADIENT_DITHER_LINES) ;
1499 		ASScanline *lines;
1500 		int line;
1501 		static ARGB32 dither_seeds[MAX_GRADIENT_DITHER_LINES] = { 0, 0xFFFFFFFF, 0x7F0F7F0F, 0x0F7F0F7F };
1502 
1503 		if( dither_lines > (int)im->height || dither_lines > (int)im->width )
1504 			dither_lines = MIN(im->height, im->width) ;
1505 
1506 		lines = safecalloc( dither_lines, sizeof(ASScanline));
1507 		for( line = 0 ; line < dither_lines ; line++ )
1508 		{
1509 			prepare_scanline( line_len, QUANT_ERR_BITS, &(lines[line]), asv->BGR_mode );
1510 			make_gradient_scanline( &(lines[line]), grad, filter, dither_seeds[line] );
1511 		}
1512 		switch( get_flags(grad->type,GRADIENT_TYPE_MASK) )
1513 		{
1514 			case GRADIENT_Left2Right :
1515 				make_gradient_left2right( imout, lines, dither_lines, filter );
1516   	    		break ;
1517 			case GRADIENT_Top2Bottom :
1518 				make_gradient_top2bottom( imout, lines, dither_lines, filter );
1519 				break ;
1520 			case GRADIENT_TopLeft2BottomRight :
1521 			case GRADIENT_BottomLeft2TopRight :
1522 				if( width >= height )
1523 					make_gradient_diag_width( imout, lines, dither_lines, filter,
1524 											 (grad->type==GRADIENT_BottomLeft2TopRight));
1525 				else
1526 					make_gradient_diag_height( imout, lines, dither_lines, filter,
1527 											  (grad->type==GRADIENT_BottomLeft2TopRight));
1528 				break ;
1529 			default:
1530 				break;
1531 		}
1532 		stop_image_output( &imout );
1533 		for( line = 0 ; line < dither_lines ; line++ )
1534 			free_scanline( &(lines[line]), True );
1535 		free( lines );
1536 	}
1537 	SHOW_TIME("", started);
1538 	return im;
1539 }
1540 
1541 /* ***************************************************************************/
1542 /* Image flipping(rotation)													*/
1543 /* ***************************************************************************/
1544 ASImage *
flip_asimage(ASVisual * asv,ASImage * src,int offset_x,int offset_y,int to_width,int to_height,int flip,ASAltImFormats out_format,unsigned int compression_out,int quality)1545 flip_asimage( ASVisual *asv, ASImage *src,
1546 		      int offset_x, int offset_y,
1547 			  int to_width,
1548 			  int to_height,
1549 			  int flip,
1550 			  ASAltImFormats out_format, unsigned int compression_out, int quality )
1551 {
1552 	ASImage *dst = NULL ;
1553 	ASImageOutput  *imout ;
1554 	ASFlagType filter = SCL_DO_ALL;
1555 	START_TIME(started);
1556 
1557 LOCAL_DEBUG_CALLER_OUT( "offset_x = %d, offset_y = %d, to_width = %d, to_height = %d", offset_x, offset_y, to_width, to_height );
1558 	if( src == NULL )
1559 		return NULL ;
1560 
1561 	filter = get_asimage_chanmask(src);
1562 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
1563 
1564 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1565 
1566 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
1567 	{
1568         destroy_asimage( &dst );
1569     }else
1570 	{
1571 		ASImageDecoder *imdec ;
1572 		ASScanline result ;
1573 		int y;
1574 LOCAL_DEBUG_OUT("flip-flopping actually...%s", "");
1575 		prepare_scanline( to_width, 0, &result, asv->BGR_mode );
1576 		if( (imdec = start_image_decoding(asv, src, filter, offset_x, offset_y,
1577 		                                  get_flags( flip, FLIP_VERTICAL )?to_height:to_width,
1578 										  get_flags( flip, FLIP_VERTICAL )?to_width:to_height, NULL)) != NULL )
1579 		{
1580             if( get_flags( flip, FLIP_VERTICAL ) )
1581 			{
1582 				CARD32 *chan_data ;
1583 				size_t  pos = 0;
1584 				int x ;
1585 				CARD32 *a = imdec->buffer.alpha ;
1586 				CARD32 *r = imdec->buffer.red ;
1587 				CARD32 *g = imdec->buffer.green ;
1588 				CARD32 *b = imdec->buffer.blue;
1589 
1590 				chan_data = safemalloc( to_width*to_height*sizeof(CARD32));
1591                 result.back_color = src->back_color;
1592 				result.flags = filter ;
1593 /*				memset( a, 0x00, to_height*sizeof(CARD32));
1594 				memset( r, 0x00, to_height*sizeof(CARD32));
1595 				memset( g, 0x00, to_height*sizeof(CARD32));
1596 				memset( b, 0x00, to_height*sizeof(CARD32));
1597   */			for( y = 0 ; y < (int)to_width ; y++ )
1598 				{
1599 					imdec->decode_image_scanline( imdec );
1600 					for( x = 0; x < (int)to_height ; x++ )
1601 					{
1602 						chan_data[pos++] = MAKE_ARGB32( a[x],r[x],g[x],b[x] );
1603 					}
1604 				}
1605 
1606 				if( get_flags( flip, FLIP_UPSIDEDOWN ) )
1607 				{
1608 					for( y = 0 ; y < (int)to_height ; ++y )
1609 					{
1610 						pos = y + (int)(to_width-1)*(to_height) ;
1611 						for( x = 0 ; x < (int)to_width ; ++x )
1612 						{
1613 							result.alpha[x] = ARGB32_ALPHA8(chan_data[pos]);
1614 							result.red  [x] = ARGB32_RED8(chan_data[pos]);
1615 							result.green[x] = ARGB32_GREEN8(chan_data[pos]);
1616 							result.blue [x] = ARGB32_BLUE8(chan_data[pos]);
1617 							pos -= to_height ;
1618 						}
1619 						imout->output_image_scanline( imout, &result, 1);
1620 					}
1621 				}else
1622 				{
1623 					for( y = to_height-1 ; y >= 0 ; --y )
1624 					{
1625 						pos = y ;
1626 						for( x = 0 ; x < (int)to_width ; ++x )
1627 						{
1628 							result.alpha[x] = ARGB32_ALPHA8(chan_data[pos]);
1629 							result.red  [x] = ARGB32_RED8(chan_data[pos]);
1630 							result.green[x] = ARGB32_GREEN8(chan_data[pos]);
1631 							result.blue [x] = ARGB32_BLUE8(chan_data[pos]);
1632 							pos += to_height ;
1633 						}
1634 						imout->output_image_scanline( imout, &result, 1);
1635 					}
1636 				}
1637 				free( chan_data );
1638 			}else
1639 			{
1640 				toggle_image_output_direction( imout );
1641 /*                fprintf( stderr, __FUNCTION__":chanmask = 0x%lX", filter ); */
1642 				for( y = 0 ; y < (int)to_height ; y++  )
1643 				{
1644 					imdec->decode_image_scanline( imdec );
1645                     result.flags = imdec->buffer.flags = imdec->buffer.flags & filter ;
1646                     result.back_color = imdec->buffer.back_color ;
1647                     SCANLINE_FUNC_FILTERED(reverse_component,imdec->buffer,result,0,to_width);
1648 					imout->output_image_scanline( imout, &result, 1);
1649 				}
1650 			}
1651 			stop_image_decoding( &imdec );
1652 		}
1653 		free_scanline( &result, True );
1654 		stop_image_output( &imout );
1655 	}
1656 	SHOW_TIME("", started);
1657 	return dst;
1658 }
1659 
1660 ASImage *
mirror_asimage(ASVisual * asv,ASImage * src,int offset_x,int offset_y,int to_width,int to_height,Bool vertical,ASAltImFormats out_format,unsigned int compression_out,int quality)1661 mirror_asimage( ASVisual *asv, ASImage *src,
1662 		      int offset_x, int offset_y,
1663 			  int to_width,
1664 			  int to_height,
1665 			  Bool vertical, ASAltImFormats out_format,
1666 			  unsigned int compression_out, int quality )
1667 {
1668 	ASImage *dst = NULL ;
1669 	ASImageOutput  *imout ;
1670 	START_TIME(started);
1671 
1672 	LOCAL_DEBUG_CALLER_OUT( "offset_x = %d, offset_y = %d, to_width = %d, to_height = %d", offset_x, offset_y, to_width, to_height );
1673 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
1674 
1675 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1676 
1677 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
1678 	{
1679         destroy_asimage( &dst );
1680     }else
1681 	{
1682 		ASImageDecoder *imdec ;
1683 		ASScanline result ;
1684 		int y;
1685 		if( !vertical )
1686 			prepare_scanline( to_width, 0, &result, asv->BGR_mode );
1687 LOCAL_DEBUG_OUT("miroring actually...%s", "");
1688 		if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y,
1689 		                                  to_width, to_height, NULL)) != NULL )
1690 		{
1691 			if( vertical )
1692 			{
1693 				toggle_image_output_direction( imout );
1694 				for( y = 0 ; y < (int)to_height ; y++  )
1695 				{
1696 					imdec->decode_image_scanline( imdec );
1697 					imout->output_image_scanline( imout, &(imdec->buffer), 1);
1698 				}
1699 			}else
1700 			{
1701 				for( y = 0 ; y < (int)to_height ; y++  )
1702 				{
1703 					imdec->decode_image_scanline( imdec );
1704 					result.flags = imdec->buffer.flags ;
1705 					result.back_color = imdec->buffer.back_color ;
1706 					SCANLINE_FUNC(reverse_component,imdec->buffer,result,0,to_width);
1707 					imout->output_image_scanline( imout, &result, 1);
1708 				}
1709 			}
1710 			stop_image_decoding( &imdec );
1711 		}
1712 		if( !vertical )
1713 			free_scanline( &result, True );
1714 		stop_image_output( &imout );
1715 	}
1716 	SHOW_TIME("", started);
1717 	return dst;
1718 }
1719 
1720 ASImage *
pad_asimage(ASVisual * asv,ASImage * src,int dst_x,int dst_y,int to_width,int to_height,ARGB32 color,ASAltImFormats out_format,unsigned int compression_out,int quality)1721 pad_asimage(  ASVisual *asv, ASImage *src,
1722 		      int dst_x, int dst_y,
1723 			  int to_width,
1724 			  int to_height,
1725 			  ARGB32 color,
1726 			  ASAltImFormats out_format,
1727 			  unsigned int compression_out, int quality )
1728 {
1729 	ASImage *dst = NULL ;
1730 	ASImageOutput  *imout ;
1731 	int clip_width, clip_height ;
1732 	START_TIME(started);
1733 
1734 LOCAL_DEBUG_CALLER_OUT( "dst_x = %d, dst_y = %d, to_width = %d, to_height = %d", dst_x, dst_y, to_width, to_height );
1735 	if( src == NULL )
1736 		return NULL ;
1737 
1738 	if( to_width == src->width && to_height == src->height && dst_x == 0 && dst_y == 0 )
1739 		return clone_asimage( src, SCL_DO_ALL );
1740 
1741 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1742 
1743 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
1744 
1745 	clip_width = src->width ;
1746 	clip_height = src->height ;
1747 	if( dst_x < 0 )
1748 		clip_width = MIN( (int)to_width, dst_x+clip_width );
1749 	else
1750 		clip_width = MIN( (int)to_width-dst_x, clip_width );
1751     if( dst_y < 0 )
1752 		clip_height = MIN( (int)to_height, dst_y+clip_height);
1753 	else
1754 		clip_height = MIN( (int)to_height-dst_y, clip_height);
1755 	if( (clip_width <= 0 || clip_height <= 0) )
1756 	{                              /* we are completely outside !!! */
1757 		dst->back_color = color ;
1758 		return dst ;
1759 	}
1760 
1761 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
1762 	{
1763         destroy_asimage( &dst );
1764     }else
1765 	{
1766 		ASImageDecoder *imdec = NULL;
1767 		ASScanline result ;
1768 		int y;
1769 		int start_x = (dst_x < 0)? 0: dst_x;
1770 		int start_y = (dst_y < 0)? 0: dst_y;
1771 
1772 		if( (int)to_width != clip_width || clip_width != (int)src->width )
1773 		{
1774 			prepare_scanline( to_width, 0, &result, asv->BGR_mode );
1775 			imdec = start_image_decoding(  asv, src, SCL_DO_ALL,
1776 			                               (dst_x<0)? -dst_x:0,
1777 										   (dst_y<0)? -dst_y:0,
1778 		                                    clip_width, clip_height, NULL);
1779 		}
1780 
1781 		result.back_color = color ;
1782 		result.flags = 0 ;
1783 LOCAL_DEBUG_OUT( "filling %d lines with %8.8lX", start_y, color );
1784 		for( y = 0 ; y < start_y ; y++  )
1785 			imout->output_image_scanline( imout, &result, 1);
1786 
1787 		if( imdec )
1788 			result.back_color = imdec->buffer.back_color ;
1789 		if( (int)to_width == clip_width )
1790 		{
1791 			if( imdec == NULL )
1792 			{
1793 LOCAL_DEBUG_OUT( "copiing %d lines", clip_height );
1794 				copy_asimage_lines( dst, start_y, src, (dst_y < 0 )? -dst_y: 0, clip_height, SCL_DO_ALL );
1795 				imout->next_line += clip_height ;
1796 			}else
1797 				for( y = 0 ; y < clip_height ; y++  )
1798 				{
1799 					imdec->decode_image_scanline( imdec );
1800 					imout->output_image_scanline( imout, &(imdec->buffer), 1);
1801 				}
1802 		}else if( imdec )
1803 		{
1804 			for( y = 0 ; y < clip_height ; y++  )
1805 			{
1806 				int chan ;
1807 
1808 				imdec->decode_image_scanline( imdec );
1809 				result.flags = imdec->buffer.flags ;
1810 				for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
1811 				{
1812 	   				register CARD32 *chan_data = result.channels[chan] ;
1813 	   				register CARD32 *src_chan_data = imdec->buffer.channels[chan]+((dst_x<0)? -dst_x : 0) ;
1814 					CARD32 chan_val = ARGB32_CHAN8(color, chan);
1815 					register int k = -1;
1816 					for( k = 0 ; k < start_x ; ++k )
1817 						chan_data[k] = chan_val ;
1818 					chan_data += k ;
1819 					for( k = 0 ; k < clip_width ; ++k )
1820 						chan_data[k] = src_chan_data[k];
1821 					chan_data += k ;
1822 					k = to_width-(start_x+clip_width) ;
1823 					while( --k >= 0 )
1824 						chan_data[k] = chan_val ;
1825 				}
1826 				imout->output_image_scanline( imout, &result, 1);
1827 			}
1828 		}
1829 		result.back_color = color ;
1830 		result.flags = 0 ;
1831 LOCAL_DEBUG_OUT( "filling %d lines with %8.8lX at the end", to_height-(start_y+clip_height), color );
1832 		for( y = start_y+clip_height ; y < (int)to_height ; y++  )
1833 			imout->output_image_scanline( imout, &result, 1);
1834 
1835 		if( imdec )
1836 		{
1837 			stop_image_decoding( &imdec );
1838 			free_scanline( &result, True );
1839 		}
1840 		stop_image_output( &imout );
1841 	}
1842 	SHOW_TIME("", started);
1843 	return dst;
1844 }
1845 
1846 
1847 /**********************************************************************/
1848 
fill_asimage(ASVisual * asv,ASImage * im,int x,int y,int width,int height,ARGB32 color)1849 Bool fill_asimage( ASVisual *asv, ASImage *im,
1850                	   int x, int y, int width, int height,
1851 				   ARGB32 color )
1852 {
1853 	ASImageOutput *imout;
1854 	ASImageDecoder *imdec;
1855 	START_TIME(started);
1856 
1857 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1858 
1859 	if( im == NULL )
1860 		return False;
1861 	if( x < 0 )
1862 	{	width += x ; x = 0 ; }
1863 	if( y < 0 )
1864 	{	height += y ; y = 0 ; }
1865 
1866 	if( width <= 0 || height <= 0 || x >= (int)im->width || y >= (int)im->height )
1867 		return False;
1868 	if( x+width > (int)im->width )
1869 		width = (int)im->width-x ;
1870 	if( y+height > (int)im->height )
1871 		height = (int)im->height-y ;
1872 
1873 	if((imout = start_image_output( asv, im, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT)) == NULL )
1874 		return False ;
1875 	else
1876 	{
1877 		int i ;
1878 		imout->next_line = y ;
1879 		if( x == 0 && width == (int)im->width )
1880 		{
1881 			ASScanline result ;
1882 			result.flags = 0 ;
1883 			result.back_color = color ;
1884 			for( i = 0 ; i < height ; i++ )
1885 				imout->output_image_scanline( imout, &result, 1);
1886 		}else if ((imdec = start_image_decoding(asv, im, SCL_DO_ALL, 0, y, im->width, height, NULL)) != NULL )
1887 		{
1888 			CARD32 alpha = ARGB32_ALPHA8(color), red = ARGB32_RED8(color),
1889 				   green = ARGB32_GREEN8(color), blue = ARGB32_BLUE8(color);
1890 			CARD32 	*a = imdec->buffer.alpha + x ;
1891 			CARD32 	*r = imdec->buffer.red + x ;
1892 			CARD32 	*g = imdec->buffer.green + x ;
1893 			CARD32 	*b = imdec->buffer.blue + x  ;
1894 			for( i = 0 ; i < height ; i++ )
1895 			{
1896 				register int k ;
1897 				imdec->decode_image_scanline( imdec );
1898 				for( k = 0 ; k < width ; ++k )
1899 				{
1900 					a[k] = alpha ;
1901 					r[k] = red ;
1902 					g[k] = green ;
1903 					b[k] = blue ;
1904 				}
1905 				imout->output_image_scanline( imout, &(imdec->buffer), 1);
1906 			}
1907 			stop_image_decoding( &imdec );
1908 		}
1909 	}
1910 	stop_image_output( &imout );
1911 	SHOW_TIME("", started);
1912 	return True;
1913 }
1914 
1915 /* ********************************************************************************/
1916 /* Vector -> ASImage functions :                                                  */
1917 /* ********************************************************************************/
1918 Bool
colorize_asimage_vector(ASVisual * asv,ASImage * im,ASVectorPalette * palette,ASAltImFormats out_format,int quality)1919 colorize_asimage_vector( ASVisual *asv, ASImage *im,
1920 						 ASVectorPalette *palette,
1921 						 ASAltImFormats out_format,
1922 						 int quality )
1923 {
1924 	ASImageOutput  *imout = NULL ;
1925 	ASScanline buf ;
1926 	int x, y, curr_point, last_point ;
1927     register double *vector ;
1928 	double *points ;
1929 	double *multipliers[IC_NUM_CHANNELS] ;
1930 	START_TIME(started);
1931 
1932 	if( im == NULL || palette == NULL || out_format == ASA_Vector )
1933 		return False;
1934 
1935 	if( im->alt.vector == NULL )
1936 		return False;
1937 	vector = im->alt.vector ;
1938 
1939 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
1940 
1941 	if((imout = start_image_output( asv, im, out_format, QUANT_ERR_BITS, quality)) == NULL )
1942 		return False;
1943 	/* as per ROOT ppl request double data goes from bottom to top,
1944 	 * instead of from top to bottom : */
1945 	if( !get_flags( im->flags, ASIM_VECTOR_TOP2BOTTOM) )
1946 		toggle_image_output_direction(imout);
1947 
1948 	prepare_scanline( im->width, QUANT_ERR_BITS, &buf, asv->BGR_mode );
1949 	curr_point = palette->npoints/2 ;
1950 	points = palette->points ;
1951 	last_point = palette->npoints-1 ;
1952 	buf.flags = 0 ;
1953 	for( y = 0 ; y < IC_NUM_CHANNELS ; ++y )
1954 	{
1955 		if( palette->channels[y] )
1956 		{
1957 			multipliers[y] = safemalloc( last_point*sizeof(double));
1958 			for( x = 0 ; x < last_point ; ++x )
1959 			{
1960 				if (points[x+1] == points[x])
1961       				multipliers[y][x] = 1;
1962 				else
1963 					multipliers[y][x] = (double)(palette->channels[y][x+1] - palette->channels[y][x])/
1964 				                 	        (points[x+1]-points[x]);
1965 /*				fprintf( stderr, "%e-%e/%e-%e=%e ", (double)palette->channels[y][x+1], (double)palette->channels[y][x],
1966 				                 	        points[x+1], points[x], multipliers[y][x] );
1967  */
1968 			}
1969 /*			fputc( '\n', stderr ); */
1970 			set_flags(buf.flags, (0x01<<y));
1971 		}else
1972 			multipliers[y] = NULL ;
1973 	}
1974 	for( y = 0 ; y < (int)im->height ; ++y )
1975 	{
1976 		for( x = 0 ; x < (int)im->width ;)
1977 		{
1978 			register int i = IC_NUM_CHANNELS ;
1979 			double d ;
1980 
1981 			if( points[curr_point] > vector[x] )
1982 			{
1983 				while( --curr_point >= 0 )
1984 					if( points[curr_point] < vector[x] )
1985 						break;
1986 				if( curr_point < 0 )
1987 					++curr_point ;
1988 			}else
1989 			{
1990 				while( points[curr_point+1] < vector[x] )
1991 					if( ++curr_point >= last_point )
1992 					{
1993 						curr_point = last_point-1 ;
1994 						break;
1995 					}
1996 			}
1997 			d = vector[x]-points[curr_point];
1998 /*			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] ); */
1999 			while( --i >= 0 )
2000 				if( multipliers[i] )
2001 				{/* the following calculation is the most expensive part of the algorithm : */
2002 					buf.channels[i][x] = (int)(d*multipliers[i][curr_point])+palette->channels[i][curr_point] ;
2003 /*					fprintf( stderr, "%2.2X.", buf.channels[i][x] ); */
2004 				}
2005 /*			fputc( ' ', stderr ); */
2006 #if 1
2007 			while( ++x < (int)im->width )
2008 				if( vector[x] == vector[x-1] )
2009 				{
2010 					buf.red[x] = buf.red[x-1] ;
2011 					buf.green[x] = buf.green[x-1] ;
2012 					buf.blue[x] = buf.blue[x-1] ;
2013 					buf.alpha[x] = buf.alpha[x-1] ;
2014 				}else
2015 					break;
2016 #else
2017 			++x ;
2018 #endif
2019 		}
2020 /*		fputc( '\n', stderr ); */
2021 		imout->output_image_scanline( imout, &buf, 1);
2022 		vector += im->width ;
2023 	}
2024 	for( y = 0 ; y < IC_NUM_CHANNELS ; ++y )
2025 		if( multipliers[y] )
2026 			free(multipliers[y]);
2027 
2028 	stop_image_output( &imout );
2029 	free_scanline( &buf, True );
2030 	SHOW_TIME("", started);
2031 	return True;
2032 }
2033 
2034 ASImage *
create_asimage_from_vector(ASVisual * asv,double * vector,int width,int height,ASVectorPalette * palette,ASAltImFormats out_format,unsigned int compression,int quality)2035 create_asimage_from_vector( ASVisual *asv, double *vector,
2036 							int width, int height,
2037 							ASVectorPalette *palette,
2038 							ASAltImFormats out_format,
2039 							unsigned int compression, int quality )
2040 {
2041 	ASImage *im = NULL;
2042 
2043 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
2044 
2045 	if( vector != NULL )
2046 	{
2047 		im = create_destination_image( width, height, out_format, compression, ARGB32_DEFAULT_BACK_COLOR);
2048 
2049 		if( im != NULL )
2050 		{
2051 			if( set_asimage_vector( im, vector ) )
2052 				if( palette )
2053 					colorize_asimage_vector( asv, im, palette, out_format, quality );
2054 		}
2055 	}
2056 	return im ;
2057 }
2058 
2059 
2060 /***********************************************************************
2061  * Gaussian blur code.
2062  **********************************************************************/
2063 
2064 #undef PI
2065 #define PI 3.141592526
2066 
2067 #if 0
2068 static inline void
2069 gauss_component(CARD32 *src, CARD32 *dst, int radius, double* gauss, int len)
2070 {
2071 	int x, j, r = radius - 1;
2072 	for (x = 0 ; x < len ; x++) {
2073 		register double v = 0.0;
2074 		for (j = x - r ; j <= 0 ; j++) v += src[0] * gauss[x - j];
2075 		for ( ; j < x ; j++) v += src[j] * gauss[x - j];
2076 		v += src[x] * gauss[0];
2077 		for (j = x + r ; j >= len ; j--) v += src[len - 1] * gauss[j - x];
2078 		for ( ; j > x ; j--) v += src[j] * gauss[j - x];
2079 		dst[x] = (CARD32)v;
2080 	}
2081 }
2082 #endif
2083 
2084 #define GAUSS_COEFF_TYPE int
2085 /* static void calc_gauss_double(double radius, double* gauss); */
2086 static void calc_gauss_int(int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums);
2087 
2088 #define gauss_data_t CARD32
2089 #define gauss_var_t int
2090 
2091 static inline void
gauss_component_int(gauss_data_t * s1,gauss_data_t * d1,int radius,GAUSS_COEFF_TYPE * gauss,GAUSS_COEFF_TYPE * gauss_sums,int len)2092 gauss_component_int(gauss_data_t *s1, gauss_data_t *d1, int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums, int len)
2093 {
2094 #define DEFINE_GAUS_TMP_VAR		CARD32 *xs1 = &s1[x]; CARD32 v1 = xs1[0]*gauss[0]
2095 	if( len < radius + radius )
2096 	{
2097 		int x = 0, j;
2098 		while( x < len )
2099 		{
2100 			int tail = len - 1 - x;
2101 			int gauss_sum = gauss[0];
2102 			DEFINE_GAUS_TMP_VAR;
2103 			for (j = 1 ; j <= x ; ++j)
2104 			{
2105 				v1 += xs1[-j]*gauss[j];
2106 				gauss_sum += gauss[j];
2107 			}
2108 			for (j = 1 ; j <= tail ; ++j)
2109 			{
2110 				v1 += xs1[j]*gauss[j];
2111 				gauss_sum += gauss[j];
2112 			}
2113 			d1[x] = (v1<<10)/gauss_sum;
2114 			++x;
2115 		}
2116 		return;
2117 	}
2118 
2119 #define MIDDLE_STRETCH_GAUSS(j_check)	\
2120 	do{ for( j = 1 ; j j_check ; ++j ) v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]); }while(0)
2121 
2122 	/* left stretch [0, r-2] */
2123 	{
2124 		int x = 0 ;
2125 		for( ; x < radius-1 ; ++x )
2126 		{
2127 			int j ;
2128 			gauss_data_t *xs1 = &s1[x];
2129 			gauss_var_t v1 = xs1[0]*gauss[0];
2130 			for( j = 1 ; j <= x ; ++j )
2131 				v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);
2132 
2133 			for( ; j < radius ; ++j )
2134 				v1 += xs1[j]*gauss[j];
2135 			d1[x] = (v1<<10)/gauss_sums[x];
2136 		}
2137 	}
2138 
2139 	/* middle stretch : [r-1, l-r] */
2140 	if (radius-1 == len - radius)
2141 	{
2142 		gauss_data_t *xs1 = &s1[radius-1];
2143 		gauss_var_t v1 = xs1[0]*gauss[0];
2144 		int j = 1;
2145 		for( ; j < radius ; ++j )
2146 			v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);
2147 		d1[radius] = v1 ;
2148 	}else
2149 	{
2150 		int x = radius;
2151 		for(; x <= len - radius + 1; x+=3)
2152 		{
2153 			gauss_data_t *xs1 = &s1[x];
2154 			gauss_var_t v1 = xs1[-1]*gauss[0];
2155 			gauss_var_t v2 = xs1[0]*gauss[0];
2156 			gauss_var_t v3 = xs1[1]*gauss[0];
2157 			int j = 1;
2158 			for( ; j < radius ; ++j )
2159 			{
2160 				int g = gauss[j];
2161 				v1 += xs1[-j-1]*g+xs1[j-1]*g;
2162 				v2 += xs1[-j]*g+xs1[j]*g;
2163 				v3 += xs1[-j+1]*g+xs1[j+1]*g;
2164 			}
2165 			d1[x-1] = v1 ;
2166 			d1[x] = v2 ;
2167 			d1[x+1] = v3 ;
2168 		}
2169 	}
2170 	{
2171 		int x = 0;
2172 		gauss_data_t *td1 = &d1[len-1];
2173 		for( ; x < radius-1; ++x )
2174 		{
2175 			int j;
2176 			gauss_data_t *xs1 = &s1[len-1-x];
2177 			gauss_var_t v1 = xs1[0]*gauss[0];
2178 			for( j = 1 ; j <= x ; ++j )
2179 				v1 += (xs1[-j]*gauss[j]+xs1[j]*gauss[j]);
2180 
2181 			for( ; j <radius ; ++j )
2182 				v1 += xs1[-j]*gauss[j];
2183 			td1[-x] = (v1<<10)/gauss_sums[x];
2184 		}
2185 	}
2186 #undef 	MIDDLE_STRETCH_GAUSS
2187 #undef DEFINE_GAUS_TMP_VAR
2188 }
2189 
2190 /*#define 	USE_PARALLEL_OPTIMIZATION */
2191 
2192 #ifdef USE_PARALLEL_OPTIMIZATION
2193 /* this ain't worth a crap it seems. The code below seems to perform 20% slower then
2194    plain and simple one component at a time
2195  */
2196 static inline void
gauss_component_int2(CARD32 * s1,CARD32 * d1,CARD32 * s2,CARD32 * d2,int radius,GAUSS_COEFF_TYPE * gauss,GAUSS_COEFF_TYPE * gauss_sums,int len)2197 gauss_component_int2(CARD32 *s1, CARD32 *d1, CARD32 *s2, CARD32 *d2, int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums, int len)
2198 {
2199 #define MIDDLE_STRETCH_GAUSS do{GAUSS_COEFF_TYPE g = gauss[j]; \
2200 								v1 += (xs1[-j]+xs1[j])*g; \
2201 								v2 += (xs2[-j]+xs2[j])*g; }while(0)
2202 
2203 	int x, j;
2204 	int tail = radius;
2205 	GAUSS_COEFF_TYPE g0 = gauss[0];
2206 	for( x = 0 ; x < radius ; ++x )
2207 	{
2208 		register CARD32 *xs1 = &s1[x];
2209 		register CARD32 *xs2 = &s2[x];
2210 		register CARD32 v1 = s1[x]*g0;
2211 		register CARD32 v2 = s2[x]*g0;
2212 		for( j = 1 ; j <= x ; ++j )
2213 			MIDDLE_STRETCH_GAUSS;
2214 		for( ; j < radius ; ++j )
2215 		{
2216 			GAUSS_COEFF_TYPE g = gauss[j];
2217 			CARD32 m1 = xs1[j]*g;
2218 			CARD32 m2 = xs2[j]*g;
2219 			v1 += m1;
2220 			v2 += m2;
2221 		}
2222 		v1 = v1<<10;
2223 		v2 = v2<<10;
2224 		{
2225 			GAUSS_COEFF_TYPE gs = gauss_sums[x];
2226 			d1[x] = v1/gs;
2227 			d2[x] = v2/gs;
2228 		}
2229 	}
2230 	while( x <= len-radius )
2231 	{
2232 		register CARD32 *xs1 = &s1[x];
2233 		register CARD32 *xs2 = &s2[x];
2234 		register CARD32 v1 = s1[x]*g0;
2235 		register CARD32 v2 = s2[x]*g0;
2236 		for( j = 1 ; j < radius ; ++j )
2237 			MIDDLE_STRETCH_GAUSS;
2238 		d1[x] = v1 ;
2239 		d2[x] = v2 ;
2240 		++x;
2241 	}
2242 	while( --tail > 0 )/*x < len*/
2243 	{
2244 		register CARD32 *xs1 = &s1[x];
2245 		register CARD32 *xs2 = &s2[x];
2246 		register CARD32 v1 = xs1[0]*g0;
2247 		register CARD32 v2 = xs2[0]*g0;
2248 		for( j = 1 ; j < tail ; ++j )
2249 			MIDDLE_STRETCH_GAUSS;
2250 		for( ; j <radius ; ++j )
2251 		{
2252 			GAUSS_COEFF_TYPE g = gauss[j];
2253 			CARD32 m1 = xs1[-j]*g;
2254 			CARD32 m2 = xs2[-j]*g;
2255 			v1 += m1;
2256 			v2 += m2;
2257 		}
2258 		v1 = v1<<10;
2259 		v2 = v2<<10;
2260 		{
2261 			GAUSS_COEFF_TYPE gs = gauss_sums[tail];
2262 			d1[x] = v1/gs;
2263 			d2[x] = v2/gs;
2264 		}
2265 		++x;
2266 	}
2267 #undef 	MIDDLE_STRETCH_GAUSS
2268 }
2269 #endif
2270 
2271 static inline void
load_gauss_scanline(ASScanline * result,ASImageDecoder * imdec,int horz,GAUSS_COEFF_TYPE * sgauss,GAUSS_COEFF_TYPE * sgauss_sums,ASFlagType filter)2272 load_gauss_scanline(ASScanline *result, ASImageDecoder *imdec, int horz, GAUSS_COEFF_TYPE *sgauss, GAUSS_COEFF_TYPE *sgauss_sums, ASFlagType filter )
2273 {
2274     ASFlagType lf;
2275 	int x, chan;
2276 #ifdef USE_PARALLEL_OPTIMIZATION
2277 	int todo_count = 0;
2278 	int todo[IC_NUM_CHANNELS] = {-1,-1,-1,-1};
2279 #endif
2280 	imdec->decode_image_scanline(imdec);
2281 	lf = imdec->buffer.flags&filter ;
2282 	result->flags = imdec->buffer.flags;
2283 	result->back_color = imdec->buffer.back_color;
2284 
2285 	for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
2286 	{
2287 		CARD32 *res_chan = result->channels[chan];
2288 		CARD32 *src_chan = imdec->buffer.channels[chan];
2289 		if( get_flags(lf, 0x01<<chan) )
2290 		{
2291 			if( horz == 1 )
2292 			{
2293 				for( x =  0 ; x < result->width ; ++x )
2294 					res_chan[x] = src_chan[x]<<10 ;
2295 			}else
2296 			{
2297 #ifdef USE_PARALLEL_OPTIMIZATION
2298 				todo[todo_count++] = chan;
2299 #else
2300 				gauss_component_int(src_chan, res_chan, horz, sgauss, sgauss_sums, result->width);
2301 #endif
2302 			}
2303 	    }else if( get_flags( result->flags, 0x01<<chan ) )
2304 	        copy_component( src_chan, res_chan, 0, result->width);
2305 		else if( get_flags( filter, 0x01<<chan ) )
2306 		{
2307 			CARD32 fill = (CARD32)ARGB32_RED8(imdec->buffer.back_color)<<10;
2308 			for( x =  0 ; x < result->width ; ++x ) res_chan[x] = fill ;
2309 		}
2310 	}
2311 
2312 #ifdef USE_PARALLEL_OPTIMIZATION
2313 	switch( 4 - todo_count )
2314 	{
2315 		case 0 : /* todo_count == 4 */
2316 			gauss_component_int2(imdec->buffer.channels[todo[2]], result->channels[todo[2]],
2317 								 imdec->buffer.channels[todo[3]], result->channels[todo[3]],
2318 								 horz, sgauss, sgauss_sums, result->width);
2319 		case 2 : /* todo_count == 2 */
2320 			gauss_component_int2(imdec->buffer.channels[todo[0]], result->channels[todo[0]],
2321 								 imdec->buffer.channels[todo[1]], result->channels[todo[1]],
2322 								 horz, sgauss, sgauss_sums, result->width); break ;
2323 		case 1 : /* todo_count == 3 */
2324 			gauss_component_int2(imdec->buffer.channels[todo[1]], result->channels[todo[1]],
2325 								 imdec->buffer.channels[todo[2]], result->channels[todo[2]],
2326 								 horz, sgauss, sgauss_sums, result->width);
2327 		case 3 : /* todo_count == 1 */
2328 			gauss_component_int( imdec->buffer.channels[todo[0]],
2329 								 result->channels[todo[0]],
2330 								 horz, sgauss, sgauss_sums, result->width); break ;
2331 	}
2332 #endif
2333 }
2334 
2335 
blur_asimage_gauss(ASVisual * asv,ASImage * src,double dhorz,double dvert,ASFlagType filter,ASAltImFormats out_format,unsigned int compression_out,int quality)2336 ASImage* blur_asimage_gauss(ASVisual* asv, ASImage* src, double dhorz, double dvert,
2337                             ASFlagType filter,
2338 							ASAltImFormats out_format, unsigned int compression_out, int quality)
2339 {
2340 	ASImage *dst = NULL;
2341 	ASImageOutput *imout;
2342 	ASImageDecoder *imdec;
2343 	int y, x, chan;
2344 	int horz = (int)dhorz;
2345 	int vert = (int)dvert;
2346 	int width, height ;
2347 #if 0
2348 	struct timeval stv;
2349 	gettimeofday (&stv,NULL);
2350 #define PRINT_BACKGROUND_OP_TIME do{ struct timeval tv;gettimeofday (&tv,NULL); tv.tv_sec-= stv.tv_sec;\
2351                                      fprintf (stderr,__FILE__ "%d: elapsed  %ld usec\n",__LINE__,\
2352                                               tv.tv_sec*1000000+tv.tv_usec-stv.tv_usec );}while(0)
2353 #else
2354 #define PRINT_BACKGROUND_OP_TIME do{}while(0)
2355 #endif
2356 
2357 	if (!src) return NULL;
2358 
2359 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
2360 
2361 	width = src->width ;
2362 	height = src->height ;
2363 	dst = create_destination_image( width, height, out_format, compression_out, src->back_color);
2364 
2365 	imout = start_image_output(asv, dst, out_format, 0, quality);
2366     if (!imout)
2367     {
2368         destroy_asimage( &dst );
2369 		return NULL;
2370 	}
2371 
2372 	imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, src->width, src->height, NULL);
2373 	if (!imdec)
2374 	{
2375 		stop_image_output(&imout);
2376         destroy_asimage( &dst );
2377 		return NULL;
2378 	}
2379 
2380 	if( horz > (width-1)/2  ) horz = (width==1 )?1:(width-1)/2 ;
2381 	if( vert > (height-1)/2 ) vert = (height==1)?1:(height-1)/2 ;
2382 	if (horz > 128)
2383 		horz = 128;
2384 	else if (horz < 1)
2385 		horz = 1;
2386 	if( vert > 128 )
2387 		vert = 128 ;
2388 	else if( vert < 1 )
2389 		vert = 1 ;
2390 
2391 	if( vert == 1 && horz == 1 )
2392 	{
2393 	    for (y = 0 ; y < dst->height ; y++)
2394 		{
2395 			imdec->decode_image_scanline(imdec);
2396 	        imout->output_image_scanline(imout, &(imdec->buffer), 1);
2397 		}
2398 	}else
2399 	{
2400 		ASScanline result;
2401 		GAUSS_COEFF_TYPE *horz_gauss = NULL;
2402 		GAUSS_COEFF_TYPE *horz_gauss_sums = NULL;
2403 
2404 		if( horz > 1 )
2405 		{
2406 			PRINT_BACKGROUND_OP_TIME;
2407 			horz_gauss = safecalloc(horz+1, sizeof(GAUSS_COEFF_TYPE));
2408 			horz_gauss_sums = safecalloc(horz+1, sizeof(GAUSS_COEFF_TYPE));
2409 			calc_gauss_int(horz, horz_gauss, horz_gauss_sums);
2410 			PRINT_BACKGROUND_OP_TIME;
2411 		}
2412 		prepare_scanline(width, 0, &result, asv->BGR_mode);
2413 		if( vert == 1 )
2414 		{
2415 		    for (y = 0 ; y < height ; y++)
2416 		    {
2417 				load_gauss_scanline(&result, imdec, horz, horz_gauss, horz_gauss_sums, filter );
2418 				for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
2419 					if( get_flags( filter, 0x01<<chan ) )
2420 					{
2421 						CARD32 *res_chan = result.channels[chan];
2422 						for( x = 0 ; x < width ; ++x )
2423 							res_chan[x] = (res_chan[x]&0x03Fc0000)?255:res_chan[x]>>10;
2424 					}
2425 		        imout->output_image_scanline(imout, &result, 1);
2426 			}
2427 		}else
2428 		{ /* new code : */
2429 			GAUSS_COEFF_TYPE *vert_gauss = safecalloc(vert+1, sizeof(GAUSS_COEFF_TYPE));
2430 			GAUSS_COEFF_TYPE *vert_gauss_sums = safecalloc(vert+1, sizeof(GAUSS_COEFF_TYPE));
2431 			int lines_count = vert*2-1;
2432 			int first_line = 0, last_line = lines_count-1;
2433 			ASScanline *lines_mem = safecalloc( lines_count, sizeof(ASScanline));
2434 			ASScanline **lines = safecalloc( dst->height+1, sizeof(ASScanline*));
2435 
2436 			/* init */
2437 			calc_gauss_int(vert, vert_gauss, vert_gauss_sums);
2438 			PRINT_BACKGROUND_OP_TIME;
2439 
2440 			for( y = 0 ; y < lines_count ; ++y )
2441 			{
2442 				lines[y] = &lines_mem[y] ;
2443 				prepare_scanline(width, 0, lines[y], asv->BGR_mode);
2444 				load_gauss_scanline(lines[y], imdec, horz, horz_gauss, horz_gauss_sums, filter );
2445 			}
2446 
2447 			PRINT_BACKGROUND_OP_TIME;
2448 			result.flags = 0xFFFFFFFF;
2449 			/* top band  [0, vert-2] */
2450     		for (y = 0 ; y < vert-1 ; y++)
2451     		{
2452 				for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
2453 				{
2454 					CARD32 *res_chan = result.channels[chan];
2455 					if( !get_flags(filter, 0x01<<chan) )
2456 		        		copy_component( lines[y]->channels[chan], res_chan, 0, width);
2457 					else
2458 					{
2459 						register ASScanline **ysrc = &lines[y];
2460 						int j = 0;
2461 						GAUSS_COEFF_TYPE g = vert_gauss[0];
2462 						CARD32 *src_chan1 = ysrc[0]->channels[chan];
2463 						for( x = 0 ; x < width ; ++x )
2464 							res_chan[x] = src_chan1[x]*g;
2465 						while( ++j <= y )
2466 						{
2467 							CARD32 *src_chan2 = ysrc[j]->channels[chan];
2468 							g = vert_gauss[j];
2469 							src_chan1 = ysrc[-j]->channels[chan];
2470 							for( x = 0 ; x < width ; ++x )
2471 								res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
2472 						}
2473 						for( ; j < vert ; ++j )
2474 						{
2475 							g = vert_gauss[j];
2476 							src_chan1 = ysrc[j]->channels[chan];
2477 							for( x = 0 ; x < width ; ++x )
2478 								res_chan[x] += src_chan1[x]*g;
2479 						}
2480 						g = vert_gauss_sums[y];
2481 						for( x = 0 ; x < width ; ++x )
2482 						{
2483 							gauss_var_t v = res_chan[x]/g;
2484 							res_chan[x] = (v&0x03Fc0000)?255:v>>10;
2485 						}
2486 					}
2487 				}
2488         		imout->output_image_scanline(imout, &result, 1);
2489 			}
2490 			PRINT_BACKGROUND_OP_TIME;
2491 			/* middle band [vert-1, height-vert] */
2492 			for( ; y <= height - vert; ++y)
2493 			{
2494 				for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
2495 				{
2496 					CARD32 *res_chan = result.channels[chan];
2497 					if( !get_flags(filter, 0x01<<chan) )
2498 		        		copy_component( lines[y]->channels[chan], res_chan, 0, result.width);
2499 					else
2500 					{
2501 						register ASScanline **ysrc = &lines[y];
2502 /* surprisingly, having x loops inside y loop yields 30% to 80% better performance */
2503 						int j = 0;
2504 						CARD32 *src_chan1 = ysrc[0]->channels[chan];
2505 						memset( res_chan, 0x00, width*4 );
2506 /*						for( x = 0 ; x < width ; ++x )
2507 							res_chan[x] = src_chan1[x]*vert_gauss[0];
2508  */
2509 						while( ++j < vert )
2510 						{
2511 							CARD32 *src_chan2 = ysrc[j]->channels[chan];
2512 							GAUSS_COEFF_TYPE g = vert_gauss[j];
2513 							src_chan1 = ysrc[-j]->channels[chan];
2514 							switch( g )
2515 							{
2516 								case 1 :
2517 									for( x = 0 ; x < width ; ++x )
2518 										res_chan[x] += src_chan1[x]+src_chan2[x];
2519 									break;
2520 								case 2 :
2521 									for( x = 0 ; x < width ; ++x )
2522 										res_chan[x] += (src_chan1[x]+src_chan2[x])<<1;
2523 									break;
2524 #if 1
2525 								case 4 :
2526 									for( x = 0 ; x < width ; ++x )
2527 										res_chan[x] += (src_chan1[x]+src_chan2[x])<<2;
2528 									break;
2529 								case 8 :
2530 									for( x = 0 ; x < width ; ++x )
2531 										res_chan[x] += (src_chan1[x]+src_chan2[x])<<3;
2532 									break;
2533 								case 16 :
2534 									for( x = 0 ; x < width ; ++x )
2535 										res_chan[x] += (src_chan1[x]+src_chan2[x])<<4;
2536 									break;
2537 								case 32 :
2538 									for( x = 0 ; x < width ; ++x )
2539 										res_chan[x] += (src_chan1[x]+src_chan2[x])<<5;
2540 									break;
2541 #endif
2542 								default :
2543 									for( x = 0 ; x < width ; ++x )
2544 										res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
2545 							}
2546 						}
2547  						src_chan1 = ysrc[0]->channels[chan];
2548 						for( x = 0 ; x < width ; ++x )
2549 						{
2550 							gauss_var_t v = src_chan1[x]*vert_gauss[0] + res_chan[x];
2551 							res_chan[x] = (v&0xF0000000)?255:v>>20;
2552 						}
2553 					}
2554 				}
2555 
2556         		imout->output_image_scanline(imout, &result, 1);
2557 				++last_line;
2558 				/* fprintf( stderr, "last_line = %d, first_line = %d, height = %d, vert = %d, y = %d\n", last_line, first_line, dst->height, vert, y ); */
2559 				lines[last_line] = lines[first_line] ;
2560 				++first_line;
2561 				load_gauss_scanline(lines[last_line], imdec, horz, horz_gauss, horz_gauss_sums, filter );
2562 			}
2563 			PRINT_BACKGROUND_OP_TIME;
2564 			/* bottom band */
2565 			for( ; y < height; ++y)
2566 			{
2567 				int tail = height - y ;
2568 				for( chan = 0 ; chan < IC_NUM_CHANNELS ; ++chan )
2569 				{
2570 					CARD32 *res_chan = result.channels[chan];
2571 					if( !get_flags(filter, 0x01<<chan) )
2572 		        		copy_component( lines[y]->channels[chan], res_chan, 0, result.width);
2573 					else
2574 					{
2575 						register ASScanline **ysrc = &lines[y];
2576 						int j = 0;
2577 						GAUSS_COEFF_TYPE g ;
2578 						CARD32 *src_chan1 = ysrc[0]->channels[chan];
2579 						for( x = 0 ; x < width ; ++x )
2580 							res_chan[x] = src_chan1[x]*vert_gauss[0];
2581 						for( j = 1 ; j < tail ; ++j )
2582 						{
2583 							CARD32 *src_chan2 = ysrc[j]->channels[chan];
2584 							g = vert_gauss[j];
2585 							src_chan1 = ysrc[-j]->channels[chan];
2586 							for( x = 0 ; x < width ; ++x )
2587 								res_chan[x] += (src_chan1[x]+src_chan2[x])*g;
2588 						}
2589 						for( ; j < vert ; ++j )
2590 						{
2591 							g = vert_gauss[j];
2592 							src_chan1 = ysrc[-j]->channels[chan];
2593 							for( x = 0 ; x < width ; ++x )
2594 								res_chan[x] += src_chan1[x]*g;
2595 						}
2596 						g = vert_gauss_sums[tail];
2597 						for( x = 0 ; x < width ; ++x )
2598 						{
2599 							gauss_var_t v = res_chan[x]/g;
2600 							res_chan[x] = (v&0x03Fc0000)?255:v>>10;
2601 						}
2602 					}
2603 				}
2604 
2605         		imout->output_image_scanline(imout, &result, 1);
2606 			}
2607 			/* cleanup */
2608 			for( y = 0 ; y < lines_count ; ++y )
2609 				free_scanline(&lines_mem[y], True);
2610 			free( lines_mem );
2611 			free( lines );
2612 			free(vert_gauss_sums);
2613 			free(vert_gauss);
2614 
2615 		}
2616 		free_scanline(&result, True);
2617 		if( horz_gauss_sums )
2618 			free(horz_gauss_sums);
2619 		if( horz_gauss )
2620 			free(horz_gauss);
2621 	}
2622 PRINT_BACKGROUND_OP_TIME;
2623 
2624 	stop_image_decoding(&imdec);
2625 	stop_image_output(&imout);
2626 
2627 	return dst;
2628 }
2629 
2630 #if 0 /* unused for the time being */
2631 static void calc_gauss_double(double radius, double* gauss)
2632 {
2633 	int i, mult;
2634 	double std_dev, sum = 0.0;
2635 	double g0, g_last;
2636 	double n, nn, nPI, nnPI;
2637 	if (radius <= 1.0)
2638 	{
2639 		gauss[0] = 1.0;
2640 		return;
2641 	}
2642 	/* after radius of 128 - gaussian degrades into something weird,
2643 	   since our colors are only 8 bit */
2644 	if (radius > 128.0) radius = 128.0;
2645 	std_dev = (radius - 1) * 0.3003866304;
2646 	do
2647 	{
2648 		sum = 0 ;
2649 		n = std_dev * std_dev;
2650 		nn = 2*n ;
2651 		nPI = n*PI;
2652 		nnPI = nn*PI;
2653 		sum = g0 = 1.0 / nnPI ;
2654 		for (i = 1 ; i < radius-1 ; i++)
2655 			sum += exp((double)-i * (double)i / nn)/nPI;
2656 		g_last = exp((double)-i * (double)i / nn)/nnPI;
2657 		sum += g_last*2.0 ;
2658 
2659 		mult = (int)((1024.0+radius*0.94)/sum);
2660 		std_dev += 0.1 ;
2661 	}while( g_last*mult  < 1. );
2662 
2663 	gauss[0] = g0/sum ;
2664 	gauss[(int)radius-1] = g_last/sum;
2665 
2666 	sum *= nnPI;
2667 	for (i = 1 ; i < radius-1 ; i++)
2668 		gauss[i] = exp((double)-i * (double)i / nn)/sum;
2669 }
2670 #endif
2671 
2672 /* even though lookup tables take space - using those speeds kernel calculations tenfold */
2673 static const double standard_deviations[128] =
2674 {
2675 		 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,
2676 		 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,
2677 		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,
2678 		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,
2679 		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,
2680 		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,
2681 		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,
2682 		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
2683 
2684 };
2685 
2686 static const double descr_approxim_mult[128] =
2687 {
2688 		 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,
2689 		 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,
2690 		 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,
2691 		 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,
2692 		 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,
2693 		 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,
2694 		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,
2695 		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
2696 
2697 };
2698 
calc_gauss_int(int radius,GAUSS_COEFF_TYPE * gauss,GAUSS_COEFF_TYPE * gauss_sums)2699 static void calc_gauss_int(int radius, GAUSS_COEFF_TYPE* gauss, GAUSS_COEFF_TYPE* gauss_sums)
2700 {
2701 	int i = radius;
2702 	double dmult;
2703 	double std_dev;
2704 	if (i <= 1)
2705 	{
2706 		gauss[0] = 1024;
2707 		gauss_sums[0] = 1024;
2708 		return;
2709 	}
2710 	/* after radius of 128 - gaussian degrades into something weird,
2711 	   since our colors are only 8 bit */
2712 	if (i > 128) i = 128;
2713 #if 1
2714 	{
2715 		double nn;
2716 		GAUSS_COEFF_TYPE sum = 1024 ;
2717 		std_dev = standard_deviations[i-1];
2718 		dmult = descr_approxim_mult[i-1];
2719 		nn = 2*std_dev * std_dev ;
2720 		dmult /=nn*PI;
2721 		gauss[0] = (GAUSS_COEFF_TYPE)(dmult + 0.5);
2722 		while( i >= 1 )
2723 		{
2724 			gauss[i] = (GAUSS_COEFF_TYPE)(exp((double)-i * (double)i / nn)*dmult + 0.5);
2725 			gauss_sums[i] = sum;
2726 			sum -= gauss[i];
2727 			--i;
2728 		}
2729 		gauss_sums[0] = sum;
2730 	}
2731 #else
2732 	double g0, g_last, sum = 0.;
2733 	double n, nn, nPI, nnPI;
2734 	std_dev = (radius - 1) * 0.3003866304;
2735 	do
2736 	{
2737 		sum = 0 ;
2738 		n = std_dev * std_dev;
2739 		nn = 2*n ;
2740 		nPI = n*PI;
2741 		nnPI = nn*PI;
2742 		sum = g0 = 1.0 / nnPI ;
2743 		for (i = 1 ; i < radius-1 ; i++)
2744 			sum += exp((double)-i * (double)i / nn)/nPI;
2745 		g_last = exp((double)-i * (double)i / nn)/nnPI;
2746 		sum += g_last*2.0 ;
2747 
2748 		dmult = 1024.0/sum;
2749 		std_dev += 0.05 ;
2750 	}while( g_last*dmult  < 1. );
2751 	gauss[0] = g0 * dmult + 0.5;
2752 	gauss[(int)radius-1] = g_last * dmult + 0.5;
2753 	dmult /=nnPI;
2754 	for (i = 1 ; i < radius-1 ; i++)
2755 		gauss[i] = exp((double)-i * (double)i / nn)*dmult + 0.5;
2756 
2757 #endif
2758 
2759 #if 0
2760 	{
2761 		static int count = 0 ;
2762 		if( ++count == 16 )
2763 		{
2764 			fprintf( stderr, "\n		" );
2765 			count = 0 ;
2766 		}
2767 
2768 		fprintf(stderr, "%lf, ", dmult*nnPI );
2769 	}
2770 #endif
2771 #if 0
2772 	{
2773 		int sum_da = 0 ;
2774 		fprintf(stderr, "sum = %f, dmult = %f\n", sum, dmult );
2775 		for (i = 0 ; i < radius ; i++)
2776 		{
2777 //			gauss[i] /= sum;
2778 			sum_da += gauss[i]*2 ;
2779 			fprintf(stderr, "discr_approx(%d) = %d\n", i, gauss[i]);
2780 		}
2781 		sum_da -= gauss[0];
2782 
2783 		fprintf(stderr, "sum_da = %d\n", sum_da );
2784 	}
2785 #endif
2786 }
2787 
2788 
2789 /***********************************************************************
2790  * Hue,saturation and lightness adjustments.
2791  **********************************************************************/
2792 ASImage*
adjust_asimage_hsv(ASVisual * asv,ASImage * src,int offset_x,int offset_y,int to_width,int to_height,int affected_hue,int affected_radius,int hue_offset,int saturation_offset,int value_offset,ASAltImFormats out_format,unsigned int compression_out,int quality)2793 adjust_asimage_hsv( ASVisual *asv, ASImage *src,
2794 				    int offset_x, int offset_y,
2795 	  			    int to_width, int to_height,
2796 					int affected_hue, int affected_radius,
2797 					int hue_offset, int saturation_offset, int value_offset,
2798 					ASAltImFormats out_format,
2799 					unsigned int compression_out, int quality )
2800 {
2801 	ASImage *dst = NULL ;
2802 	ASImageDecoder *imdec ;
2803 	ASImageOutput  *imout ;
2804 	START_TIME(started);
2805 
2806 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
2807 
2808 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 );
2809 	if( src == NULL )
2810 		return NULL;
2811 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, offset_x, offset_y, to_width, 0, NULL)) == NULL )
2812 		return NULL;
2813 
2814 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
2815 	set_decoder_shift(imdec,8);
2816 	if((imout = start_image_output( asv, dst, out_format, 8, quality)) == NULL )
2817 	{
2818         destroy_asimage( &dst );
2819     }else
2820 	{
2821 	    CARD32 from_hue1 = 0, from_hue2 = 0, to_hue1 = 0, to_hue2 = 0 ;
2822 		int y, max_y = to_height;
2823 		Bool do_greyscale = False ;
2824 
2825 		affected_hue = normalize_degrees_val( affected_hue );
2826 		affected_radius = normalize_degrees_val( affected_radius );
2827 		if( value_offset != 0 )
2828 			do_greyscale = (affected_hue+affected_radius >= 360 || affected_hue-affected_radius <= 0 );
2829 		if( affected_hue > affected_radius )
2830 		{
2831 			from_hue1 = degrees2hue16(affected_hue-affected_radius);
2832 			if( affected_hue+affected_radius >= 360 )
2833 			{
2834 				to_hue1 = MAX_HUE16 ;
2835 				from_hue2 = MIN_HUE16 ;
2836 				to_hue2 = degrees2hue16(affected_hue+affected_radius-360);
2837 			}else
2838 				to_hue1 = degrees2hue16(affected_hue+affected_radius);
2839 		}else
2840 		{
2841 			from_hue1 = degrees2hue16(affected_hue+360-affected_radius);
2842 			to_hue1 = MAX_HUE16 ;
2843 			from_hue2 = MIN_HUE16 ;
2844 			to_hue2 = degrees2hue16(affected_hue+affected_radius);
2845 		}
2846 		hue_offset = degrees2hue16(hue_offset);
2847 		saturation_offset = (saturation_offset<<16) / 100;
2848 		value_offset = (value_offset<<16)/100 ;
2849 LOCAL_DEBUG_OUT("adjusting actually...%s", "");
2850 		if( to_height > src->height )
2851 		{
2852 			imout->tiling_step = src->height ;
2853 			max_y = src->height ;
2854 		}
2855 		for( y = 0 ; y < max_y ; y++  )
2856 		{
2857 			register int x = imdec->buffer.width;
2858 			CARD32 *r = imdec->buffer.red;
2859 			CARD32 *g = imdec->buffer.green;
2860 			CARD32 *b = imdec->buffer.blue ;
2861 			long h, s, v ;
2862 			imdec->decode_image_scanline( imdec );
2863 			while( --x >= 0 )
2864 			{
2865 				if( (h = rgb2hue( r[x], g[x], b[x] )) != 0 )
2866 				{
2867 #ifdef DEBUG_HSV_ADJUSTMENT
2868 					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 );
2869 #endif
2870 
2871 					if( affected_radius >= 180 ||
2872 						(h >= (int)from_hue1 && h <= (int)to_hue1 ) ||
2873 						(h >= (int)from_hue2 && h <= (int)to_hue2 ) )
2874 
2875 					{
2876 						s = rgb2saturation( r[x], g[x], b[x] ) + saturation_offset;
2877 						v = rgb2value( r[x], g[x], b[x] )+value_offset;
2878 						h += hue_offset ;
2879 						if( h > MAX_HUE16 )
2880 							h -= MAX_HUE16 ;
2881 						else if( h == 0 )
2882 							h =  MIN_HUE16 ;
2883 						else if( h < 0 )
2884 							h += MAX_HUE16 ;
2885 						if( v < 0 ) v = 0 ;
2886 						else if( v > 0x00FFFF ) v = 0x00FFFF ;
2887 
2888 						if( s < 0 ) s = 0 ;
2889 						else if( s > 0x00FFFF ) s = 0x00FFFF ;
2890 
2891 						hsv2rgb ( (CARD32)h, (CARD32)s, (CARD32)v, &r[x], &g[x], &b[x]);
2892 
2893 #ifdef DEBUG_HSV_ADJUSTMENT
2894 						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 );
2895 #endif
2896 					}
2897 				}else if( do_greyscale )
2898 				{
2899 					int tmp = (int)r[x] + value_offset ;
2900 					g[x] = b[x] = r[x] = (tmp < 0)?0:((tmp>0x00FFFF)?0x00FFff:tmp);
2901 				}
2902 			}
2903 			imdec->buffer.flags = 0xFFFFFFFF ;
2904 			imout->output_image_scanline( imout, &(imdec->buffer), 1);
2905 		}
2906 		stop_image_output( &imout );
2907 	}
2908 	stop_image_decoding( &imdec );
2909 
2910 	SHOW_TIME("", started);
2911 	return dst;
2912 }
2913 
2914 static void
slice_scanline(ASScanline * dst,ASScanline * src,int start_x,int end_x,ASScanline * middle)2915 slice_scanline( ASScanline *dst, ASScanline *src, int start_x, int end_x, ASScanline *middle )
2916 {
2917 	CARD32 *sa = src->alpha, *da = dst->alpha ;
2918 	CARD32 *sr = src->red, *dr = dst->red ;
2919 	CARD32 *sg = src->green, *dg = dst->green ;
2920 	CARD32 *sb = src->blue, *db = dst->blue ;
2921 	int max_x = min( start_x, (int)dst->width);
2922 	int tail = (int)src->width - end_x ;
2923 	int tiling_step = end_x - start_x ;
2924 	int x1, x2, max_x2 ;
2925 
2926 	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 );
2927 	for( x1 = 0 ; x1 < max_x ; ++x1 )
2928 	{
2929 		da[x1] = sa[x1] ;
2930 		dr[x1] = sr[x1] ;
2931 		dg[x1] = sg[x1] ;
2932 		db[x1] = sb[x1] ;
2933 	}
2934 	if( x1 >= dst->width )
2935 		return;
2936 	/* middle portion */
2937 	max_x2 = (int) dst->width - tail ;
2938 	max_x = min(end_x, max_x2);
2939 	if( middle )
2940 	{
2941 		CARD32 *ma = middle->alpha-x1 ;
2942 		CARD32 *mr = middle->red-x1 ;
2943 		CARD32 *mg = middle->green-x1 ;
2944 		CARD32 *mb = middle->blue-x1 ;
2945 		LOCAL_DEBUG_OUT( "middle->width = %d", middle->width );
2946 
2947 		for( ; x1 < max_x2 ; ++x1 )
2948 		{
2949 			da[x1] = ma[x1] ;
2950 			dr[x1] = mr[x1] ;
2951 			dg[x1] = mg[x1] ;
2952 			db[x1] = mb[x1] ;
2953 		}
2954 		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] );
2955 	}else
2956 	{
2957 		for( ; x1 < max_x ; ++x1 )
2958 		{
2959   			x2 = x1 ;
2960 			for( x2 = x1 ; x2 < max_x2 ; x2 += tiling_step )
2961 			{
2962 				da[x2] = sa[x1] ;
2963 				dr[x2] = sr[x1] ;
2964 				dg[x2] = sg[x1] ;
2965 				db[x2] = sb[x1] ;
2966 			}
2967 		}
2968 	}
2969 	/* tail portion */
2970 	x1 = src->width - tail ;
2971 	x2 = max(max_x2,start_x) ;
2972 	max_x = src->width ;
2973 	max_x2 = dst->width ;
2974 	for( ; x1 < max_x && x2 < max_x2; ++x1, ++x2 )
2975 	{
2976 		da[x2] = sa[x1] ;
2977 		dr[x2] = sr[x1] ;
2978 		dg[x2] = sg[x1] ;
2979 		db[x2] = sb[x1] ;
2980 	}
2981 }
2982 
2983 
2984 ASImage*
slice_asimage2(ASVisual * asv,ASImage * src,int slice_x_start,int slice_x_end,int slice_y_start,int slice_y_end,int to_width,int to_height,Bool scale,ASAltImFormats out_format,unsigned int compression_out,int quality)2985 slice_asimage2( ASVisual *asv, ASImage *src,
2986 			   int slice_x_start, int slice_x_end,
2987 			   int slice_y_start, int slice_y_end,
2988 			   int to_width,
2989 			   int to_height,
2990 			   Bool scale,
2991 			   ASAltImFormats out_format,
2992 			   unsigned int compression_out, int quality )
2993 {
2994 	ASImage *dst = NULL ;
2995 	ASImageDecoder *imdec = NULL ;
2996 	ASImageOutput  *imout = NULL ;
2997 	START_TIME(started);
2998 
2999 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
3000 
3001 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 );
3002 	if( src == NULL )
3003 		return NULL;
3004 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, 0, 0, src->width, 0, NULL)) == NULL )
3005 		return NULL;
3006 	if( slice_x_end == 0 && slice_x_start > 0 )
3007 		slice_x_end = slice_x_start + 1 ;
3008 	if( slice_y_end == 0 && slice_y_start > 0 )
3009 		slice_y_end = slice_y_start + 1 ;
3010 	if( slice_x_end > src->width )
3011 		slice_x_end = src->width ;
3012 	if( slice_y_end > src->height )
3013 		slice_y_end = src->height ;
3014 	if( slice_x_start > slice_x_end )
3015 		slice_x_start = (slice_x_end > 0 ) ? slice_x_end-1 : 0 ;
3016 	if( slice_y_start > slice_y_end )
3017 		slice_y_start = (slice_y_end > 0 ) ? slice_y_end-1 : 0 ;
3018 
3019 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 );
3020 	dst = create_destination_image( to_width, to_height, out_format, compression_out, src->back_color);
3021 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
3022 	{
3023         destroy_asimage( &dst );
3024     }else
3025 	{
3026 		int y1, y2 ;
3027 		int max_y = min( slice_y_start, (int)dst->height);
3028 		int tail = (int)src->height - slice_y_end ;
3029 		int max_y2 = (int) dst->height - tail ;
3030 		ASScanline *out_buf = prepare_scanline( to_width, 0, NULL, asv->BGR_mode );
3031 
3032 		out_buf->flags = 0xFFFFFFFF ;
3033 
3034 		if( scale )
3035 		{
3036 			ASImageDecoder *imdec_scaled ;
3037 			ASImage *tmp ;
3038 			int x_middle = to_width - slice_x_start ;
3039 			int x_right = src->width - (slice_x_end+1) ;
3040 			int y_middle = to_height - slice_y_start ;
3041 			int y_bottom = src->height - (slice_y_end+1) ;
3042 			x_middle = ( x_middle <= x_right  )? 0 : x_middle-x_right ;
3043 			y_middle = ( y_middle <= y_bottom )? 0 : y_middle-y_bottom ;
3044 
3045 			if( x_middle > 0 )
3046 			{
3047 				tmp = scale_asimage2( asv, src, slice_x_start, 0,
3048 									   slice_x_end-slice_x_start, max_y,
3049 									   x_middle, max_y, ASA_ASImage, 0, quality );
3050 				imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
3051 				for( y1 = 0 ; y1 < max_y ; ++y1 )
3052 				{
3053 					imdec->decode_image_scanline( imdec );
3054 					imdec_scaled->decode_image_scanline( imdec_scaled );
3055 					slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
3056 					imout->output_image_scanline( imout, out_buf, 1);
3057 				}
3058 				stop_image_decoding( &imdec_scaled );
3059 				destroy_asimage( &tmp );
3060 			}else
3061 			{
3062 				for( y1 = 0 ; y1 < max_y ; ++y1 )
3063 				{
3064 					imdec->decode_image_scanline( imdec );
3065 					imout->output_image_scanline( imout, &(imdec->buffer), 1);
3066 				}
3067 			}
3068 			/*************************************************************/
3069 			/* middle portion */
3070 			if( y_middle > 0 )
3071 			{
3072 				ASImage *sides ;
3073 				ASImageDecoder *imdec_sides ;
3074 				sides = scale_asimage2( asv, src, 0, slice_y_start,
3075 								   		src->width, slice_y_end-slice_y_start,
3076 								   		src->width, y_middle, ASA_ASImage, 0, quality );
3077 				imdec_sides = start_image_decoding(asv, sides, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
3078 /*				print_asimage( sides, 0, __FUNCTION__, __LINE__ ); */
3079 				if( x_middle > 0 )
3080 				{
3081 					tmp = scale_asimage2( asv, sides, slice_x_start, 0,
3082 									   	slice_x_end-slice_x_start, y_middle,
3083 									   	x_middle, y_middle, ASA_ASImage, 0, quality );
3084 /*					print_asimage( tmp, 0, __FUNCTION__, __LINE__ ); */
3085 
3086 					imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
3087 					for( y1 = 0 ; y1 < y_middle ; ++y1 )
3088 					{
3089 						imdec_sides->decode_image_scanline( imdec_sides );
3090 						imdec_scaled->decode_image_scanline( imdec_scaled );
3091 						slice_scanline( out_buf, &(imdec_sides->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
3092 						imout->output_image_scanline( imout, out_buf, 1);
3093 					}
3094 					stop_image_decoding( &imdec_scaled );
3095 					destroy_asimage( &tmp );
3096 
3097 				}else
3098 				{
3099 					for( y1 = 0 ; y1 < y_middle ; ++y1 )
3100 					{
3101 						imdec_sides->decode_image_scanline( imdec_sides );
3102 						imout->output_image_scanline( imout, &(imdec->buffer), 1);
3103 					}
3104 				}
3105 				stop_image_decoding( &imdec_sides );
3106 				destroy_asimage( &sides );
3107 			}
3108 			/*************************************************************/
3109 			/* bottom portion */
3110 
3111 			y2 =  max(max_y2,(int)slice_y_start) ;
3112 			y1 = src->height - tail ;
3113 			imout->next_line = y2 ;
3114 			imdec->next_line = y1 ;
3115 			max_y = src->height ;
3116 			if( y2 + max_y - y1 > dst->height )
3117 				max_y = dst->height + y1 - y2 ;
3118 			LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d", y1, max_y );
3119 			if( x_middle > 0 )
3120 			{
3121 				tmp = scale_asimage2( asv, src, slice_x_start, y1,
3122 									   slice_x_end-slice_x_start, src->height-y1,
3123 									   x_middle, src->height-y1, ASA_ASImage, 0, quality );
3124 				imdec_scaled = start_image_decoding(asv, tmp, SCL_DO_ALL, 0, 0, 0, 0, NULL) ;
3125 				for( ; y1 < max_y ; ++y1 )
3126 				{
3127 					imdec->decode_image_scanline( imdec );
3128 					imdec_scaled->decode_image_scanline( imdec_scaled );
3129 					slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, &(imdec_scaled->buffer) );
3130 					imout->output_image_scanline( imout, out_buf, 1);
3131 				}
3132 				stop_image_decoding( &imdec_scaled );
3133 				destroy_asimage( &tmp );
3134 			}else
3135 			{
3136 				for( ; y1 < max_y ; ++y1 )
3137 				{
3138 					imdec->decode_image_scanline( imdec );
3139 					imout->output_image_scanline( imout, &(imdec->buffer), 1);
3140 				}
3141 			}
3142 
3143 		}else	 /* tile middle portion */
3144 		{
3145 			imout->tiling_step = 0;
3146 			LOCAL_DEBUG_OUT( "max_y = %d", max_y );
3147 			for( y1 = 0 ; y1 < max_y ; ++y1 )
3148 			{
3149 				imdec->decode_image_scanline( imdec );
3150 				slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
3151 				imout->output_image_scanline( imout, out_buf, 1);
3152 			}
3153 			/* middle portion */
3154 			imout->tiling_step = (int)slice_y_end - (int)slice_y_start;
3155 			max_y = min(slice_y_end, max_y2);
3156 			LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d, tiling_step = %d", y1, max_y, imout->tiling_step );
3157 			for( ; y1 < max_y ; ++y1 )
3158 			{
3159 				imdec->decode_image_scanline( imdec );
3160 				slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
3161 				imout->output_image_scanline( imout, out_buf, 1);
3162 			}
3163 
3164 			/* bottom portion */
3165 			imout->tiling_step = 0;
3166 			imout->next_line = y2 =  max(max_y2,(int)slice_y_start) ;
3167 			imdec->next_line = y1 = src->height - tail ;
3168 			max_y = src->height ;
3169 			if( y2 + max_y - y1 > dst->height )
3170 				max_y = dst->height + y1 - y2 ;
3171 			LOCAL_DEBUG_OUT( "y1 = %d, max_y = %d", y1, max_y );
3172 			for( ; y1 < max_y ; ++y1 )
3173 			{
3174 				imdec->decode_image_scanline( imdec );
3175 				slice_scanline( out_buf, &(imdec->buffer), slice_x_start, slice_x_end, NULL );
3176 				imout->output_image_scanline( imout, out_buf, 1);
3177 			}
3178 		}
3179 		free_scanline( out_buf, False );
3180 		stop_image_output( &imout );
3181 	}
3182 	stop_image_decoding( &imdec );
3183 
3184 	SHOW_TIME("", started);
3185 	return dst;
3186 }
3187 
3188 ASImage*
slice_asimage(ASVisual * asv,ASImage * src,int slice_x_start,int slice_x_end,int slice_y_start,int slice_y_end,int to_width,int to_height,ASAltImFormats out_format,unsigned int compression_out,int quality)3189 slice_asimage( ASVisual *asv, ASImage *src,
3190 			   int slice_x_start, int slice_x_end,
3191 			   int slice_y_start, int slice_y_end,
3192 			   int to_width, int to_height,
3193 			   ASAltImFormats out_format,
3194 			   unsigned int compression_out, int quality )
3195 {
3196 
3197 	return slice_asimage2( asv, src, slice_x_start, slice_x_end,
3198 			   			   slice_y_start, slice_y_end, to_width,  to_height,
3199 			   				False, out_format, compression_out, quality );
3200 }
3201 
3202 
3203 ASImage *
pixelize_asimage(ASVisual * asv,ASImage * src,int clip_x,int clip_y,int clip_width,int clip_height,int pixel_width,int pixel_height,ASAltImFormats out_format,unsigned int compression_out,int quality)3204 pixelize_asimage( ASVisual *asv, ASImage *src,
3205 			      int clip_x, int clip_y, int clip_width, int clip_height,
3206 				  int pixel_width, int pixel_height,
3207 				  ASAltImFormats out_format, unsigned int compression_out, int quality )
3208 {
3209 	ASImage *dst = NULL ;
3210 	ASImageDecoder *imdec ;
3211 	ASImageOutput  *imout ;
3212 	START_TIME(started);
3213 
3214 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
3215 
3216 	if (src== NULL)
3217 		return NULL;
3218 
3219 	if (clip_width <= 0)
3220 		clip_width = src->width;
3221 	if (clip_height <= 0)
3222 		clip_height = src->height;
3223 
3224 	if (pixel_width <= 0)
3225 		pixel_width = 1;
3226 	else if (pixel_width > clip_width)
3227 		pixel_width = clip_width;
3228 
3229 	if (pixel_height <= 0)
3230 		pixel_height = 1;
3231 	else if (pixel_height > clip_height)
3232 		pixel_height = clip_height;
3233 
3234 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 );
3235 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, 0, NULL)) == NULL )
3236 	{
3237 		LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
3238 		return NULL;
3239 	}
3240 
3241 	dst = create_destination_image( clip_width, clip_height, out_format, compression_out, src->back_color );
3242 
3243 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
3244 	{
3245 		LOCAL_DEBUG_OUT( "failed to start image output%s", "");
3246         destroy_asimage( &dst );
3247     }else
3248 	{
3249 		int y, max_y = clip_height;
3250 LOCAL_DEBUG_OUT("pixelizing actually...%s", "");
3251 
3252 		if( pixel_width > 1 || pixel_height > 1 )
3253 		{
3254 			int pixel_h_count = (clip_width+pixel_width-1)/pixel_width;
3255 			ASScanline *pixels = prepare_scanline( pixel_h_count, 0, NULL, asv->BGR_mode );
3256 			ASScanline *out_buf = prepare_scanline( clip_width, 0, NULL, asv->BGR_mode );
3257 			int lines_count = 0;
3258 
3259 			out_buf->flags = SCL_DO_ALL;
3260 
3261 			for( y = 0 ; y < max_y ; y++  )
3262 			{
3263 				int pixel_x = 0, x ;
3264 				imdec->decode_image_scanline( imdec );
3265 				for (x = 0; x < clip_width; x += pixel_width)
3266 				{
3267 					int xx = x+pixel_width;
3268 					ASScanline *srcsl = &(imdec->buffer);
3269 
3270 					if (xx > clip_width)
3271 						xx = clip_width;
3272 
3273 					while ( --xx >= x)
3274 					{
3275 						pixels->red[pixel_x] += srcsl->red[xx];
3276 						pixels->green[pixel_x] += srcsl->green[xx];
3277 						pixels->blue[pixel_x] += srcsl->blue[xx];
3278 						pixels->alpha[pixel_x] += srcsl->alpha[xx];
3279 					}
3280 					++pixel_x;
3281 				}
3282 				if (++lines_count >= pixel_height || y == max_y-1)
3283 				{
3284 					pixel_x = 0;
3285 
3286 					for (x = 0; x < clip_width; x += pixel_width)
3287 					{
3288 						int xx = (x + pixel_width> clip_width) ? clip_width : x + pixel_width;
3289 						int count = (xx - x) * lines_count;
3290 						CARD32 r = pixels->red [pixel_x] / count;
3291 						CARD32 g = pixels->green [pixel_x] / count;
3292 						CARD32 b = pixels->blue [pixel_x] / count;
3293 						CARD32 a = pixels->alpha [pixel_x] / count;
3294 
3295 						pixels->red [pixel_x] = 0;
3296 						pixels->green [pixel_x] = 0;
3297 						pixels->blue [pixel_x] = 0;
3298 						pixels->alpha [pixel_x] = 0;
3299 
3300 						if (xx > clip_width)
3301 							xx = clip_width;
3302 
3303 						while ( --xx >= x)
3304 						{
3305 							out_buf->red[xx] 	= r;
3306 							out_buf->green[xx]  = g;
3307 							out_buf->blue[xx] 	= b;
3308 							out_buf->alpha[xx]  = a;
3309 						}
3310 
3311 						++pixel_x;
3312 					}
3313 					while (lines_count--)
3314 						imout->output_image_scanline( imout, out_buf, 1);
3315 					lines_count = 0;
3316 				}
3317 			}
3318 			free_scanline( out_buf, False );
3319 			free_scanline( pixels, False );
3320 		}else
3321 			for( y = 0 ; y < max_y ; y++  )
3322 			{
3323 				imdec->decode_image_scanline( imdec );
3324 				imout->output_image_scanline( imout, &(imdec->buffer), 1);
3325 			}
3326 		stop_image_output( &imout );
3327 	}
3328 	stop_image_decoding( &imdec );
3329 
3330 	SHOW_TIME("", started);
3331 	return dst;
3332 }
3333 
3334 ASImage *
color2alpha_asimage(ASVisual * asv,ASImage * src,int clip_x,int clip_y,int clip_width,int clip_height,ARGB32 color,ASAltImFormats out_format,unsigned int compression_out,int quality)3335 color2alpha_asimage( ASVisual *asv, ASImage *src,
3336 			         int clip_x, int clip_y, int clip_width, int clip_height,
3337 				     ARGB32 color,
3338 				     ASAltImFormats out_format, unsigned int compression_out, int quality )
3339 {
3340 	ASImage *dst = NULL ;
3341 	ASImageDecoder *imdec ;
3342 	ASImageOutput  *imout ;
3343 	START_TIME(started);
3344 
3345 	if( asv == NULL ) 	asv = &__transform_fake_asv ;
3346 
3347 	if (src== NULL)
3348 		return NULL;
3349 
3350 	if (clip_width <= 0)
3351 		clip_width = src->width;
3352 	if (clip_height <= 0)
3353 		clip_height = src->height;
3354 
3355 
3356 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 );
3357 	if( (imdec = start_image_decoding(asv, src, SCL_DO_ALL, clip_x, clip_y, clip_width, 0, NULL)) == NULL )
3358 	{
3359 		LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
3360 		return NULL;
3361 	}
3362 
3363 	dst = create_destination_image( clip_width, clip_height, out_format, compression_out, src->back_color );
3364 
3365 	if((imout = start_image_output( asv, dst, out_format, 0, quality)) == NULL )
3366 	{
3367 		LOCAL_DEBUG_OUT( "failed to start image output%s", "");
3368         destroy_asimage( &dst );
3369     }else
3370 	{
3371 		int y, max_y = min(clip_height,(int)src->height);
3372 		CARD32 cr = ARGB32_RED8(color);
3373 		CARD32 cg = ARGB32_GREEN8(color);
3374 		CARD32 cb = ARGB32_BLUE8(color);
3375 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
3376 fprintf (stderr, "color2alpha():%d: color: red = 0x%8.8X green = 0x%8.8X blue = 0x%8.8X\n", __LINE__, cr, cg, cb);
3377 #endif
3378 
3379 		for( y = 0 ; y < max_y ; y++  )
3380 		{
3381 			int x ;
3382 			ASScanline *srcsl = &(imdec->buffer);
3383 			imdec->decode_image_scanline( imdec );
3384 			for (x = 0; x < imdec->buffer.width; ++x)
3385 			{
3386 				CARD32 r = srcsl->red[x];
3387 				CARD32 g = srcsl->green[x];
3388 				CARD32 b = srcsl->blue[x];
3389 				CARD32 a = srcsl->alpha[x];
3390 				/* the following logic is stolen from gimp and altered for our color format and beauty*/
3391 				{
3392 					CARD32 aa = a, ar, ag, ab;
3393 
3394 #define AS_MIN_CHAN_VAL 	2			/* GIMP uses 0.0001 */
3395 #define AS_MAX_CHAN_VAL 	255			/* GIMP uses 1.0 */
3396 #define MAKE_CHAN_ALPHA_FROM_COL(chan) \
3397 					((c##chan < AS_MIN_CHAN_VAL)? (chan)<<4 : \
3398 						((chan > c##chan)? ((chan - c##chan)<<12) / (AS_MAX_CHAN_VAL - c##chan) : \
3399 							((c##chan - chan)<<12) / c##chan))
3400 
3401 					ar = MAKE_CHAN_ALPHA_FROM_COL(r);
3402 					ag = MAKE_CHAN_ALPHA_FROM_COL(g);
3403 					ab = MAKE_CHAN_ALPHA_FROM_COL(b);
3404 #undef 	MAKE_CHAN_ALPHA_FROM_COL
3405 
3406 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
3407 fprintf (stderr, "color2alpha():%d: src(argb): %8.8X %8.8X %8.8X %8.8X; ", __LINE__, a, r, g, b);
3408 #endif
3409   					a = (ar > ag) ? max(ar, ab) : max(ag,ab);
3410 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
3411 fprintf (stderr, "alpha: (%8.8X %8.8X %8.8X)->%8.8X; ", ar, ag, ab, a);
3412 #endif
3413 
3414 					if (a == 0) a = 1;
3415 #if defined(USE_STUPID_GIMP_WAY_DESTROYING_COLORS)
3416 #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);})
3417 #else
3418 #define APPLY_ALPHA_TO_CHAN(chan)	chan
3419 #endif
3420 	  				srcsl->red[x] 	= APPLY_ALPHA_TO_CHAN(r);
3421 					srcsl->green[x] 	= APPLY_ALPHA_TO_CHAN(g);
3422 		  			srcsl->blue[x] 	= APPLY_ALPHA_TO_CHAN(b);
3423 #undef APPLY_ALPHA_TO_CHAN
3424 					a = a*aa>>12;
3425 	  				srcsl->alpha[x] = (a>255)?255:a;
3426 
3427 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
3428 fprintf (stderr, "result: %8.8X %8.8X %8.8X %8.8X.\n", src->alpha[x], src->red[x], src->green[x], src->blue[x]);
3429 #endif
3430 
3431 				}
3432 				/* end of gimp code */
3433 			}
3434 			imout->output_image_scanline( imout, srcsl, 1);
3435 		}
3436 		stop_image_output( &imout );
3437 	}
3438 	stop_image_decoding( &imdec );
3439 
3440 	SHOW_TIME("", started);
3441 	return dst;
3442 }
3443 
3444 
3445 /* ********************************************************************************/
3446 /* The end !!!! 																 */
3447 /* ********************************************************************************/
3448 
3449