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