1 /*
2  * art_rgba.c: Functions for manipulating RGBA pixel data.
3  *
4  * Libart_LGPL - library of basic graphic primitives
5  * Copyright (C) 2000 Raph Levien
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 #include "config.h"
24 #include "art_rgba.h"
25 
26 #define ART_OPTIMIZE_SPACE
27 
28 #ifndef ART_OPTIMIZE_SPACE
29 #include "art_rgba_table.c"
30 #endif
31 
32 /**
33  * art_rgba_rgba_composite: Composite RGBA image over RGBA buffer.
34  * @dst: Destination RGBA buffer.
35  * @src: Source RGBA buffer.
36  * @n: Number of RGBA pixels to composite.
37  *
38  * Composites the RGBA pixels in @dst over the @src buffer.
39  **/
40 void
art_rgba_rgba_composite(art_u8 * dst,const art_u8 * src,int n)41 art_rgba_rgba_composite (art_u8 *dst, const art_u8 *src, int n)
42 {
43   int i;
44 #ifdef WORDS_BIGENDIAN
45   art_u32 src_rgba, dst_rgba;
46 #else
47   art_u32 src_abgr, dst_abgr;
48 #endif
49   art_u8 src_alpha, dst_alpha;
50 
51   for (i = 0; i < n; i++)
52     {
53 #ifdef WORDS_BIGENDIAN
54       src_rgba = ((art_u32 *)src)[i];
55       src_alpha = src_rgba & 0xff;
56 #else
57       src_abgr = ((art_u32 *)src)[i];
58       src_alpha = (src_abgr >> 24) & 0xff;
59 #endif
60       if (src_alpha)
61 	{
62 	  if (src_alpha == 0xff ||
63 	      (
64 #ifdef WORDS_BIGENDIAN
65 	       dst_rgba = ((art_u32 *)dst)[i],
66 	       dst_alpha = dst_rgba & 0xff,
67 #else
68 	       dst_abgr = ((art_u32 *)dst)[i],
69 	       dst_alpha = (dst_abgr >> 24),
70 #endif
71 	       dst_alpha == 0))
72 #ifdef WORDS_BIGENDIAN
73 	    ((art_u32 *)dst)[i] = src_rgba;
74 #else
75 	    ((art_u32 *)dst)[i] = src_abgr;
76 #endif
77 	  else
78 	    {
79 	      int r, g, b, a;
80 	      int src_r, src_g, src_b;
81 	      int dst_r, dst_g, dst_b;
82 	      int tmp;
83 	      int c;
84 
85 #ifdef ART_OPTIMIZE_SPACE
86 	      tmp = (255 - src_alpha) * (255 - dst_alpha) + 0x80;
87 	      a = 255 - ((tmp + (tmp >> 8)) >> 8);
88 	      c = ((src_alpha << 16) + (a >> 1)) / a;
89 #else
90 	      tmp = art_rgba_composite_table[(src_alpha << 8) + dst_alpha];
91 	      c = tmp & 0x1ffff;
92 	      a = tmp >> 24;
93 #endif
94 #ifdef WORDS_BIGENDIAN
95 	      src_r = (src_rgba >> 24) & 0xff;
96 	      src_g = (src_rgba >> 16) & 0xff;
97 	      src_b = (src_rgba >> 8) & 0xff;
98 	      dst_r = (dst_rgba >> 24) & 0xff;
99 	      dst_g = (dst_rgba >> 16) & 0xff;
100 	      dst_b = (dst_rgba >> 8) & 0xff;
101 #else
102 	      src_r = src_abgr & 0xff;
103 	      src_g = (src_abgr >> 8) & 0xff;
104 	      src_b = (src_abgr >> 16) & 0xff;
105 	      dst_r = dst_abgr & 0xff;
106 	      dst_g = (dst_abgr >> 8) & 0xff;
107 	      dst_b = (dst_abgr >> 16) & 0xff;
108 #endif
109 	      r = dst_r + (((src_r - dst_r) * c + 0x8000) >> 16);
110 	      g = dst_g + (((src_g - dst_g) * c + 0x8000) >> 16);
111 	      b = dst_b + (((src_b - dst_b) * c + 0x8000) >> 16);
112 #ifdef WORDS_BIGENDIAN
113 	    ((art_u32 *)dst)[i] = (r << 24) | (g << 16) | (b << 8) | a;
114 #else
115 	    ((art_u32 *)dst)[i] = (a << 24) | (b << 16) | (g << 8) | r;
116 #endif
117 	    }
118 	}
119 #if 0
120       /* it's not clear to me this optimization really wins */
121       else
122 	{
123 	  /* skip over run of transparent pixels */
124 	  for (; i < n - 1; i++)
125 	    {
126 #ifdef WORDS_BIGENDIAN
127 	      src_rgba = ((art_u32 *)src)[i + 1];
128 	      if (src_rgba & 0xff)
129 		break;
130 #else
131 	      src_abgr = ((art_u32 *)src)[i + 1];
132 	      if (src_abgr & 0xff000000)
133 		break;
134 #endif
135 	    }
136 	}
137 #endif
138     }
139 }
140 
141 /**
142  * art_rgba_fill_run: fill an RGBA buffer a solid RGB color.
143  * @buf: Buffer to fill.
144  * @r: Red, range 0..255.
145  * @g: Green, range 0..255.
146  * @b: Blue, range 0..255.
147  * @n: Number of RGB triples to fill.
148  *
149  * Fills a buffer with @n copies of the (@r, @g, @b) triple, solid
150  * alpha. Thus, locations @buf (inclusive) through @buf + 4 * @n
151  * (exclusive) are written.
152  **/
153 void
art_rgba_fill_run(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int n)154 art_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
155 {
156   int i;
157 #ifdef WORDS_BIGENDIAN
158   art_u32 src_rgba;
159 #else
160   art_u32 src_abgr;
161 #endif
162 
163 #ifdef WORDS_BIGENDIAN
164   src_rgba = (r << 24) | (g << 16) | (b << 8) | 255;
165 #else
166   src_abgr = (255 << 24) | (b << 16) | (g << 8) | r;
167 #endif
168   for (i = 0; i < n; i++)
169     {
170 #ifdef WORDS_BIGENDIAN
171       ((art_u32 *)buf)[i] = src_rgba;
172 #else
173       ((art_u32 *)buf)[i] = src_abgr;
174 #endif
175     }
176 }
177 
178 /**
179  * art_rgba_run_alpha: Render semitransparent color over RGBA buffer.
180  * @buf: Buffer for rendering.
181  * @r: Red, range 0..255.
182  * @g: Green, range 0..255.
183  * @b: Blue, range 0..255.
184  * @alpha: Alpha, range 0..255.
185  * @n: Number of RGB triples to render.
186  *
187  * Renders a sequential run of solid (@r, @g, @b) color over @buf with
188  * opacity @alpha. Note that the range of @alpha is 0..255, in contrast
189  * to art_rgb_run_alpha, which has a range of 0..256.
190  **/
191 void
art_rgba_run_alpha(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int alpha,int n)192 art_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
193 {
194   int i;
195 #ifdef WORDS_BIGENDIAN
196   art_u32 src_rgba, dst_rgba;
197 #else
198   art_u32 src_abgr, dst_abgr;
199 #endif
200   art_u8 dst_alpha;
201   int a;
202   int dst_r, dst_g, dst_b;
203   int tmp;
204   int c;
205 
206 #ifdef WORDS_BIGENDIAN
207   src_rgba = (r << 24) | (g << 16) | (b << 8) | alpha;
208 #else
209   src_abgr = (alpha << 24) | (b << 16) | (g << 8) | r;
210 #endif
211   for (i = 0; i < n; i++)
212     {
213 #ifdef WORDS_BIGENDIAN
214       dst_rgba = ((art_u32 *)buf)[i];
215       dst_alpha = dst_rgba & 0xff;
216 #else
217       dst_abgr = ((art_u32 *)buf)[i];
218       dst_alpha = (dst_abgr >> 24) & 0xff;
219 #endif
220       if (dst_alpha)
221 	{
222 #ifdef ART_OPTIMIZE_SPACE
223 	  tmp = (255 - alpha) * (255 - dst_alpha) + 0x80;
224 	  a = 255 - ((tmp + (tmp >> 8)) >> 8);
225 	  c = ((alpha << 16) + (a >> 1)) / a;
226 #else
227 	  tmp = art_rgba_composite_table[(alpha << 8) + dst_alpha];
228 	  c = tmp & 0x1ffff;
229 	  a = tmp >> 24;
230 #endif
231 #ifdef WORDS_BIGENDIAN
232 	  dst_r = (dst_rgba >> 24) & 0xff;
233 	  dst_g = (dst_rgba >> 16) & 0xff;
234 	  dst_b = (dst_rgba >> 8) & 0xff;
235 #else
236 	  dst_r = dst_abgr & 0xff;
237 	  dst_g = (dst_abgr >> 8) & 0xff;
238 	  dst_b = (dst_abgr >> 16) & 0xff;
239 #endif
240 	  dst_r += (((r - dst_r) * c + 0x8000) >> 16);
241 	  dst_g += (((g - dst_g) * c + 0x8000) >> 16);
242 	  dst_b += (((b - dst_b) * c + 0x8000) >> 16);
243 #ifdef WORDS_BIGENDIAN
244 	  ((art_u32 *)buf)[i] = (dst_r << 24) | (dst_g << 16) | (dst_b << 8) | a;
245 #else
246 	  ((art_u32 *)buf)[i] = (a << 24) | (dst_b << 16) | (dst_g << 8) | dst_r;
247 #endif
248 	}
249       else
250 	{
251 #ifdef WORDS_BIGENDIAN
252 	  ((art_u32 *)buf)[i] = src_rgba;
253 #else
254 	  ((art_u32 *)buf)[i] = src_abgr;
255 #endif
256 	}
257     }
258 }
259