1*b2055c35SXin Li // Copyright 2013 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // Utilities for processing transparent channel.
11*b2055c35SXin Li //
12*b2055c35SXin Li // Author: Skal ([email protected])
13*b2055c35SXin Li
14*b2055c35SXin Li #include <assert.h>
15*b2055c35SXin Li #include "src/dsp/dsp.h"
16*b2055c35SXin Li
17*b2055c35SXin Li // Tables can be faster on some platform but incur some extra binary size (~2k).
18*b2055c35SXin Li #if !defined(USE_TABLES_FOR_ALPHA_MULT)
19*b2055c35SXin Li #define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE
20*b2055c35SXin Li #endif
21*b2055c35SXin Li
22*b2055c35SXin Li
23*b2055c35SXin Li // -----------------------------------------------------------------------------
24*b2055c35SXin Li
25*b2055c35SXin Li #define MFIX 24 // 24bit fixed-point arithmetic
26*b2055c35SXin Li #define HALF ((1u << MFIX) >> 1)
27*b2055c35SXin Li #define KINV_255 ((1u << MFIX) / 255u)
28*b2055c35SXin Li
Mult(uint8_t x,uint32_t mult)29*b2055c35SXin Li static uint32_t Mult(uint8_t x, uint32_t mult) {
30*b2055c35SXin Li const uint32_t v = (x * mult + HALF) >> MFIX;
31*b2055c35SXin Li assert(v <= 255); // <- 24bit precision is enough to ensure that.
32*b2055c35SXin Li return v;
33*b2055c35SXin Li }
34*b2055c35SXin Li
35*b2055c35SXin Li #if (USE_TABLES_FOR_ALPHA_MULT == 1)
36*b2055c35SXin Li
37*b2055c35SXin Li static const uint32_t kMultTables[2][256] = {
38*b2055c35SXin Li { // (255u << MFIX) / alpha
39*b2055c35SXin Li 0x00000000, 0xff000000, 0x7f800000, 0x55000000, 0x3fc00000, 0x33000000,
40*b2055c35SXin Li 0x2a800000, 0x246db6db, 0x1fe00000, 0x1c555555, 0x19800000, 0x172e8ba2,
41*b2055c35SXin Li 0x15400000, 0x139d89d8, 0x1236db6d, 0x11000000, 0x0ff00000, 0x0f000000,
42*b2055c35SXin Li 0x0e2aaaaa, 0x0d6bca1a, 0x0cc00000, 0x0c249249, 0x0b9745d1, 0x0b1642c8,
43*b2055c35SXin Li 0x0aa00000, 0x0a333333, 0x09cec4ec, 0x0971c71c, 0x091b6db6, 0x08cb08d3,
44*b2055c35SXin Li 0x08800000, 0x0839ce73, 0x07f80000, 0x07ba2e8b, 0x07800000, 0x07492492,
45*b2055c35SXin Li 0x07155555, 0x06e45306, 0x06b5e50d, 0x0689d89d, 0x06600000, 0x063831f3,
46*b2055c35SXin Li 0x06124924, 0x05ee23b8, 0x05cba2e8, 0x05aaaaaa, 0x058b2164, 0x056cefa8,
47*b2055c35SXin Li 0x05500000, 0x05343eb1, 0x05199999, 0x05000000, 0x04e76276, 0x04cfb2b7,
48*b2055c35SXin Li 0x04b8e38e, 0x04a2e8ba, 0x048db6db, 0x0479435e, 0x04658469, 0x045270d0,
49*b2055c35SXin Li 0x04400000, 0x042e29f7, 0x041ce739, 0x040c30c3, 0x03fc0000, 0x03ec4ec4,
50*b2055c35SXin Li 0x03dd1745, 0x03ce540f, 0x03c00000, 0x03b21642, 0x03a49249, 0x03976fc6,
51*b2055c35SXin Li 0x038aaaaa, 0x037e3f1f, 0x03722983, 0x03666666, 0x035af286, 0x034fcace,
52*b2055c35SXin Li 0x0344ec4e, 0x033a5440, 0x03300000, 0x0325ed09, 0x031c18f9, 0x0312818a,
53*b2055c35SXin Li 0x03092492, 0x03000000, 0x02f711dc, 0x02ee5846, 0x02e5d174, 0x02dd7baf,
54*b2055c35SXin Li 0x02d55555, 0x02cd5cd5, 0x02c590b2, 0x02bdef7b, 0x02b677d4, 0x02af286b,
55*b2055c35SXin Li 0x02a80000, 0x02a0fd5c, 0x029a1f58, 0x029364d9, 0x028ccccc, 0x0286562d,
56*b2055c35SXin Li 0x02800000, 0x0279c952, 0x0273b13b, 0x026db6db, 0x0267d95b, 0x026217ec,
57*b2055c35SXin Li 0x025c71c7, 0x0256e62a, 0x0251745d, 0x024c1bac, 0x0246db6d, 0x0241b2f9,
58*b2055c35SXin Li 0x023ca1af, 0x0237a6f4, 0x0232c234, 0x022df2df, 0x02293868, 0x02249249,
59*b2055c35SXin Li 0x02200000, 0x021b810e, 0x021714fb, 0x0212bb51, 0x020e739c, 0x020a3d70,
60*b2055c35SXin Li 0x02061861, 0x02020408, 0x01fe0000, 0x01fa0be8, 0x01f62762, 0x01f25213,
61*b2055c35SXin Li 0x01ee8ba2, 0x01ead3ba, 0x01e72a07, 0x01e38e38, 0x01e00000, 0x01dc7f10,
62*b2055c35SXin Li 0x01d90b21, 0x01d5a3e9, 0x01d24924, 0x01cefa8d, 0x01cbb7e3, 0x01c880e5,
63*b2055c35SXin Li 0x01c55555, 0x01c234f7, 0x01bf1f8f, 0x01bc14e5, 0x01b914c1, 0x01b61eed,
64*b2055c35SXin Li 0x01b33333, 0x01b05160, 0x01ad7943, 0x01aaaaaa, 0x01a7e567, 0x01a5294a,
65*b2055c35SXin Li 0x01a27627, 0x019fcbd2, 0x019d2a20, 0x019a90e7, 0x01980000, 0x01957741,
66*b2055c35SXin Li 0x0192f684, 0x01907da4, 0x018e0c7c, 0x018ba2e8, 0x018940c5, 0x0186e5f0,
67*b2055c35SXin Li 0x01849249, 0x018245ae, 0x01800000, 0x017dc11f, 0x017b88ee, 0x0179574e,
68*b2055c35SXin Li 0x01772c23, 0x01750750, 0x0172e8ba, 0x0170d045, 0x016ebdd7, 0x016cb157,
69*b2055c35SXin Li 0x016aaaaa, 0x0168a9b9, 0x0166ae6a, 0x0164b8a7, 0x0162c859, 0x0160dd67,
70*b2055c35SXin Li 0x015ef7bd, 0x015d1745, 0x015b3bea, 0x01596596, 0x01579435, 0x0155c7b4,
71*b2055c35SXin Li 0x01540000, 0x01523d03, 0x01507eae, 0x014ec4ec, 0x014d0fac, 0x014b5edc,
72*b2055c35SXin Li 0x0149b26c, 0x01480a4a, 0x01466666, 0x0144c6af, 0x01432b16, 0x0141938b,
73*b2055c35SXin Li 0x01400000, 0x013e7063, 0x013ce4a9, 0x013b5cc0, 0x0139d89d, 0x01385830,
74*b2055c35SXin Li 0x0136db6d, 0x01356246, 0x0133ecad, 0x01327a97, 0x01310bf6, 0x012fa0be,
75*b2055c35SXin Li 0x012e38e3, 0x012cd459, 0x012b7315, 0x012a150a, 0x0128ba2e, 0x01276276,
76*b2055c35SXin Li 0x01260dd6, 0x0124bc44, 0x01236db6, 0x01222222, 0x0120d97c, 0x011f93bc,
77*b2055c35SXin Li 0x011e50d7, 0x011d10c4, 0x011bd37a, 0x011a98ef, 0x0119611a, 0x01182bf2,
78*b2055c35SXin Li 0x0116f96f, 0x0115c988, 0x01149c34, 0x0113716a, 0x01124924, 0x01112358,
79*b2055c35SXin Li 0x01100000, 0x010edf12, 0x010dc087, 0x010ca458, 0x010b8a7d, 0x010a72f0,
80*b2055c35SXin Li 0x01095da8, 0x01084a9f, 0x010739ce, 0x01062b2e, 0x01051eb8, 0x01041465,
81*b2055c35SXin Li 0x01030c30, 0x01020612, 0x01010204, 0x01000000 },
82*b2055c35SXin Li { // alpha * KINV_255
83*b2055c35SXin Li 0x00000000, 0x00010101, 0x00020202, 0x00030303, 0x00040404, 0x00050505,
84*b2055c35SXin Li 0x00060606, 0x00070707, 0x00080808, 0x00090909, 0x000a0a0a, 0x000b0b0b,
85*b2055c35SXin Li 0x000c0c0c, 0x000d0d0d, 0x000e0e0e, 0x000f0f0f, 0x00101010, 0x00111111,
86*b2055c35SXin Li 0x00121212, 0x00131313, 0x00141414, 0x00151515, 0x00161616, 0x00171717,
87*b2055c35SXin Li 0x00181818, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d,
88*b2055c35SXin Li 0x001e1e1e, 0x001f1f1f, 0x00202020, 0x00212121, 0x00222222, 0x00232323,
89*b2055c35SXin Li 0x00242424, 0x00252525, 0x00262626, 0x00272727, 0x00282828, 0x00292929,
90*b2055c35SXin Li 0x002a2a2a, 0x002b2b2b, 0x002c2c2c, 0x002d2d2d, 0x002e2e2e, 0x002f2f2f,
91*b2055c35SXin Li 0x00303030, 0x00313131, 0x00323232, 0x00333333, 0x00343434, 0x00353535,
92*b2055c35SXin Li 0x00363636, 0x00373737, 0x00383838, 0x00393939, 0x003a3a3a, 0x003b3b3b,
93*b2055c35SXin Li 0x003c3c3c, 0x003d3d3d, 0x003e3e3e, 0x003f3f3f, 0x00404040, 0x00414141,
94*b2055c35SXin Li 0x00424242, 0x00434343, 0x00444444, 0x00454545, 0x00464646, 0x00474747,
95*b2055c35SXin Li 0x00484848, 0x00494949, 0x004a4a4a, 0x004b4b4b, 0x004c4c4c, 0x004d4d4d,
96*b2055c35SXin Li 0x004e4e4e, 0x004f4f4f, 0x00505050, 0x00515151, 0x00525252, 0x00535353,
97*b2055c35SXin Li 0x00545454, 0x00555555, 0x00565656, 0x00575757, 0x00585858, 0x00595959,
98*b2055c35SXin Li 0x005a5a5a, 0x005b5b5b, 0x005c5c5c, 0x005d5d5d, 0x005e5e5e, 0x005f5f5f,
99*b2055c35SXin Li 0x00606060, 0x00616161, 0x00626262, 0x00636363, 0x00646464, 0x00656565,
100*b2055c35SXin Li 0x00666666, 0x00676767, 0x00686868, 0x00696969, 0x006a6a6a, 0x006b6b6b,
101*b2055c35SXin Li 0x006c6c6c, 0x006d6d6d, 0x006e6e6e, 0x006f6f6f, 0x00707070, 0x00717171,
102*b2055c35SXin Li 0x00727272, 0x00737373, 0x00747474, 0x00757575, 0x00767676, 0x00777777,
103*b2055c35SXin Li 0x00787878, 0x00797979, 0x007a7a7a, 0x007b7b7b, 0x007c7c7c, 0x007d7d7d,
104*b2055c35SXin Li 0x007e7e7e, 0x007f7f7f, 0x00808080, 0x00818181, 0x00828282, 0x00838383,
105*b2055c35SXin Li 0x00848484, 0x00858585, 0x00868686, 0x00878787, 0x00888888, 0x00898989,
106*b2055c35SXin Li 0x008a8a8a, 0x008b8b8b, 0x008c8c8c, 0x008d8d8d, 0x008e8e8e, 0x008f8f8f,
107*b2055c35SXin Li 0x00909090, 0x00919191, 0x00929292, 0x00939393, 0x00949494, 0x00959595,
108*b2055c35SXin Li 0x00969696, 0x00979797, 0x00989898, 0x00999999, 0x009a9a9a, 0x009b9b9b,
109*b2055c35SXin Li 0x009c9c9c, 0x009d9d9d, 0x009e9e9e, 0x009f9f9f, 0x00a0a0a0, 0x00a1a1a1,
110*b2055c35SXin Li 0x00a2a2a2, 0x00a3a3a3, 0x00a4a4a4, 0x00a5a5a5, 0x00a6a6a6, 0x00a7a7a7,
111*b2055c35SXin Li 0x00a8a8a8, 0x00a9a9a9, 0x00aaaaaa, 0x00ababab, 0x00acacac, 0x00adadad,
112*b2055c35SXin Li 0x00aeaeae, 0x00afafaf, 0x00b0b0b0, 0x00b1b1b1, 0x00b2b2b2, 0x00b3b3b3,
113*b2055c35SXin Li 0x00b4b4b4, 0x00b5b5b5, 0x00b6b6b6, 0x00b7b7b7, 0x00b8b8b8, 0x00b9b9b9,
114*b2055c35SXin Li 0x00bababa, 0x00bbbbbb, 0x00bcbcbc, 0x00bdbdbd, 0x00bebebe, 0x00bfbfbf,
115*b2055c35SXin Li 0x00c0c0c0, 0x00c1c1c1, 0x00c2c2c2, 0x00c3c3c3, 0x00c4c4c4, 0x00c5c5c5,
116*b2055c35SXin Li 0x00c6c6c6, 0x00c7c7c7, 0x00c8c8c8, 0x00c9c9c9, 0x00cacaca, 0x00cbcbcb,
117*b2055c35SXin Li 0x00cccccc, 0x00cdcdcd, 0x00cecece, 0x00cfcfcf, 0x00d0d0d0, 0x00d1d1d1,
118*b2055c35SXin Li 0x00d2d2d2, 0x00d3d3d3, 0x00d4d4d4, 0x00d5d5d5, 0x00d6d6d6, 0x00d7d7d7,
119*b2055c35SXin Li 0x00d8d8d8, 0x00d9d9d9, 0x00dadada, 0x00dbdbdb, 0x00dcdcdc, 0x00dddddd,
120*b2055c35SXin Li 0x00dedede, 0x00dfdfdf, 0x00e0e0e0, 0x00e1e1e1, 0x00e2e2e2, 0x00e3e3e3,
121*b2055c35SXin Li 0x00e4e4e4, 0x00e5e5e5, 0x00e6e6e6, 0x00e7e7e7, 0x00e8e8e8, 0x00e9e9e9,
122*b2055c35SXin Li 0x00eaeaea, 0x00ebebeb, 0x00ececec, 0x00ededed, 0x00eeeeee, 0x00efefef,
123*b2055c35SXin Li 0x00f0f0f0, 0x00f1f1f1, 0x00f2f2f2, 0x00f3f3f3, 0x00f4f4f4, 0x00f5f5f5,
124*b2055c35SXin Li 0x00f6f6f6, 0x00f7f7f7, 0x00f8f8f8, 0x00f9f9f9, 0x00fafafa, 0x00fbfbfb,
125*b2055c35SXin Li 0x00fcfcfc, 0x00fdfdfd, 0x00fefefe, 0x00ffffff }
126*b2055c35SXin Li };
127*b2055c35SXin Li
GetScale(uint32_t a,int inverse)128*b2055c35SXin Li static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
129*b2055c35SXin Li return kMultTables[!inverse][a];
130*b2055c35SXin Li }
131*b2055c35SXin Li
132*b2055c35SXin Li #else
133*b2055c35SXin Li
GetScale(uint32_t a,int inverse)134*b2055c35SXin Li static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
135*b2055c35SXin Li return inverse ? (255u << MFIX) / a : a * KINV_255;
136*b2055c35SXin Li }
137*b2055c35SXin Li
138*b2055c35SXin Li #endif // USE_TABLES_FOR_ALPHA_MULT
139*b2055c35SXin Li
WebPMultARGBRow_C(uint32_t * const ptr,int width,int inverse)140*b2055c35SXin Li void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
141*b2055c35SXin Li int x;
142*b2055c35SXin Li for (x = 0; x < width; ++x) {
143*b2055c35SXin Li const uint32_t argb = ptr[x];
144*b2055c35SXin Li if (argb < 0xff000000u) { // alpha < 255
145*b2055c35SXin Li if (argb <= 0x00ffffffu) { // alpha == 0
146*b2055c35SXin Li ptr[x] = 0;
147*b2055c35SXin Li } else {
148*b2055c35SXin Li const uint32_t alpha = (argb >> 24) & 0xff;
149*b2055c35SXin Li const uint32_t scale = GetScale(alpha, inverse);
150*b2055c35SXin Li uint32_t out = argb & 0xff000000u;
151*b2055c35SXin Li out |= Mult(argb >> 0, scale) << 0;
152*b2055c35SXin Li out |= Mult(argb >> 8, scale) << 8;
153*b2055c35SXin Li out |= Mult(argb >> 16, scale) << 16;
154*b2055c35SXin Li ptr[x] = out;
155*b2055c35SXin Li }
156*b2055c35SXin Li }
157*b2055c35SXin Li }
158*b2055c35SXin Li }
159*b2055c35SXin Li
WebPMultRow_C(uint8_t * WEBP_RESTRICT const ptr,const uint8_t * WEBP_RESTRICT const alpha,int width,int inverse)160*b2055c35SXin Li void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
161*b2055c35SXin Li const uint8_t* WEBP_RESTRICT const alpha,
162*b2055c35SXin Li int width, int inverse) {
163*b2055c35SXin Li int x;
164*b2055c35SXin Li for (x = 0; x < width; ++x) {
165*b2055c35SXin Li const uint32_t a = alpha[x];
166*b2055c35SXin Li if (a != 255) {
167*b2055c35SXin Li if (a == 0) {
168*b2055c35SXin Li ptr[x] = 0;
169*b2055c35SXin Li } else {
170*b2055c35SXin Li const uint32_t scale = GetScale(a, inverse);
171*b2055c35SXin Li ptr[x] = Mult(ptr[x], scale);
172*b2055c35SXin Li }
173*b2055c35SXin Li }
174*b2055c35SXin Li }
175*b2055c35SXin Li }
176*b2055c35SXin Li
177*b2055c35SXin Li #undef KINV_255
178*b2055c35SXin Li #undef HALF
179*b2055c35SXin Li #undef MFIX
180*b2055c35SXin Li
181*b2055c35SXin Li void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
182*b2055c35SXin Li void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
183*b2055c35SXin Li const uint8_t* WEBP_RESTRICT const alpha,
184*b2055c35SXin Li int width, int inverse);
185*b2055c35SXin Li
186*b2055c35SXin Li //------------------------------------------------------------------------------
187*b2055c35SXin Li // Generic per-plane calls
188*b2055c35SXin Li
WebPMultARGBRows(uint8_t * ptr,int stride,int width,int num_rows,int inverse)189*b2055c35SXin Li void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
190*b2055c35SXin Li int inverse) {
191*b2055c35SXin Li int n;
192*b2055c35SXin Li for (n = 0; n < num_rows; ++n) {
193*b2055c35SXin Li WebPMultARGBRow((uint32_t*)ptr, width, inverse);
194*b2055c35SXin Li ptr += stride;
195*b2055c35SXin Li }
196*b2055c35SXin Li }
197*b2055c35SXin Li
WebPMultRows(uint8_t * WEBP_RESTRICT ptr,int stride,const uint8_t * WEBP_RESTRICT alpha,int alpha_stride,int width,int num_rows,int inverse)198*b2055c35SXin Li void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
199*b2055c35SXin Li const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
200*b2055c35SXin Li int width, int num_rows, int inverse) {
201*b2055c35SXin Li int n;
202*b2055c35SXin Li for (n = 0; n < num_rows; ++n) {
203*b2055c35SXin Li WebPMultRow(ptr, alpha, width, inverse);
204*b2055c35SXin Li ptr += stride;
205*b2055c35SXin Li alpha += alpha_stride;
206*b2055c35SXin Li }
207*b2055c35SXin Li }
208*b2055c35SXin Li
209*b2055c35SXin Li //------------------------------------------------------------------------------
210*b2055c35SXin Li // Premultiplied modes
211*b2055c35SXin Li
212*b2055c35SXin Li // non dithered-modes
213*b2055c35SXin Li
214*b2055c35SXin Li // (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
215*b2055c35SXin Li // for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
216*b2055c35SXin Li // one can use instead: (x * a * 65793 + (1 << 23)) >> 24
217*b2055c35SXin Li #if 1 // (int)(x * a / 255.)
218*b2055c35SXin Li #define MULTIPLIER(a) ((a) * 32897U)
219*b2055c35SXin Li #define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
220*b2055c35SXin Li #else // (int)(x * a / 255. + .5)
221*b2055c35SXin Li #define MULTIPLIER(a) ((a) * 65793U)
222*b2055c35SXin Li #define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
223*b2055c35SXin Li #endif
224*b2055c35SXin Li
225*b2055c35SXin Li #if !WEBP_NEON_OMIT_C_CODE
ApplyAlphaMultiply_C(uint8_t * rgba,int alpha_first,int w,int h,int stride)226*b2055c35SXin Li static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first,
227*b2055c35SXin Li int w, int h, int stride) {
228*b2055c35SXin Li while (h-- > 0) {
229*b2055c35SXin Li uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
230*b2055c35SXin Li const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
231*b2055c35SXin Li int i;
232*b2055c35SXin Li for (i = 0; i < w; ++i) {
233*b2055c35SXin Li const uint32_t a = alpha[4 * i];
234*b2055c35SXin Li if (a != 0xff) {
235*b2055c35SXin Li const uint32_t mult = MULTIPLIER(a);
236*b2055c35SXin Li rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
237*b2055c35SXin Li rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
238*b2055c35SXin Li rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
239*b2055c35SXin Li }
240*b2055c35SXin Li }
241*b2055c35SXin Li rgba += stride;
242*b2055c35SXin Li }
243*b2055c35SXin Li }
244*b2055c35SXin Li #endif // !WEBP_NEON_OMIT_C_CODE
245*b2055c35SXin Li #undef MULTIPLIER
246*b2055c35SXin Li #undef PREMULTIPLY
247*b2055c35SXin Li
248*b2055c35SXin Li // rgbA4444
249*b2055c35SXin Li
250*b2055c35SXin Li #define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
251*b2055c35SXin Li
dither_hi(uint8_t x)252*b2055c35SXin Li static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
253*b2055c35SXin Li return (x & 0xf0) | (x >> 4);
254*b2055c35SXin Li }
255*b2055c35SXin Li
dither_lo(uint8_t x)256*b2055c35SXin Li static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
257*b2055c35SXin Li return (x & 0x0f) | (x << 4);
258*b2055c35SXin Li }
259*b2055c35SXin Li
multiply(uint8_t x,uint32_t m)260*b2055c35SXin Li static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
261*b2055c35SXin Li return (x * m) >> 16;
262*b2055c35SXin Li }
263*b2055c35SXin Li
ApplyAlphaMultiply4444_C(uint8_t * rgba4444,int w,int h,int stride,int rg_byte_pos)264*b2055c35SXin Li static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444,
265*b2055c35SXin Li int w, int h, int stride,
266*b2055c35SXin Li int rg_byte_pos /* 0 or 1 */) {
267*b2055c35SXin Li while (h-- > 0) {
268*b2055c35SXin Li int i;
269*b2055c35SXin Li for (i = 0; i < w; ++i) {
270*b2055c35SXin Li const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
271*b2055c35SXin Li const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
272*b2055c35SXin Li const uint8_t a = ba & 0x0f;
273*b2055c35SXin Li const uint32_t mult = MULTIPLIER(a);
274*b2055c35SXin Li const uint8_t r = multiply(dither_hi(rg), mult);
275*b2055c35SXin Li const uint8_t g = multiply(dither_lo(rg), mult);
276*b2055c35SXin Li const uint8_t b = multiply(dither_hi(ba), mult);
277*b2055c35SXin Li rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
278*b2055c35SXin Li rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
279*b2055c35SXin Li }
280*b2055c35SXin Li rgba4444 += stride;
281*b2055c35SXin Li }
282*b2055c35SXin Li }
283*b2055c35SXin Li #undef MULTIPLIER
284*b2055c35SXin Li
ApplyAlphaMultiply_16b_C(uint8_t * rgba4444,int w,int h,int stride)285*b2055c35SXin Li static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
286*b2055c35SXin Li int w, int h, int stride) {
287*b2055c35SXin Li #if (WEBP_SWAP_16BIT_CSP == 1)
288*b2055c35SXin Li ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 1);
289*b2055c35SXin Li #else
290*b2055c35SXin Li ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 0);
291*b2055c35SXin Li #endif
292*b2055c35SXin Li }
293*b2055c35SXin Li
294*b2055c35SXin Li #if !WEBP_NEON_OMIT_C_CODE
DispatchAlpha_C(const uint8_t * WEBP_RESTRICT alpha,int alpha_stride,int width,int height,uint8_t * WEBP_RESTRICT dst,int dst_stride)295*b2055c35SXin Li static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
296*b2055c35SXin Li int width, int height,
297*b2055c35SXin Li uint8_t* WEBP_RESTRICT dst, int dst_stride) {
298*b2055c35SXin Li uint32_t alpha_mask = 0xff;
299*b2055c35SXin Li int i, j;
300*b2055c35SXin Li
301*b2055c35SXin Li for (j = 0; j < height; ++j) {
302*b2055c35SXin Li for (i = 0; i < width; ++i) {
303*b2055c35SXin Li const uint32_t alpha_value = alpha[i];
304*b2055c35SXin Li dst[4 * i] = alpha_value;
305*b2055c35SXin Li alpha_mask &= alpha_value;
306*b2055c35SXin Li }
307*b2055c35SXin Li alpha += alpha_stride;
308*b2055c35SXin Li dst += dst_stride;
309*b2055c35SXin Li }
310*b2055c35SXin Li
311*b2055c35SXin Li return (alpha_mask != 0xff);
312*b2055c35SXin Li }
313*b2055c35SXin Li
DispatchAlphaToGreen_C(const uint8_t * WEBP_RESTRICT alpha,int alpha_stride,int width,int height,uint32_t * WEBP_RESTRICT dst,int dst_stride)314*b2055c35SXin Li static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
315*b2055c35SXin Li int alpha_stride, int width, int height,
316*b2055c35SXin Li uint32_t* WEBP_RESTRICT dst,
317*b2055c35SXin Li int dst_stride) {
318*b2055c35SXin Li int i, j;
319*b2055c35SXin Li for (j = 0; j < height; ++j) {
320*b2055c35SXin Li for (i = 0; i < width; ++i) {
321*b2055c35SXin Li dst[i] = alpha[i] << 8; // leave A/R/B channels zero'd.
322*b2055c35SXin Li }
323*b2055c35SXin Li alpha += alpha_stride;
324*b2055c35SXin Li dst += dst_stride;
325*b2055c35SXin Li }
326*b2055c35SXin Li }
327*b2055c35SXin Li
ExtractAlpha_C(const uint8_t * WEBP_RESTRICT argb,int argb_stride,int width,int height,uint8_t * WEBP_RESTRICT alpha,int alpha_stride)328*b2055c35SXin Li static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
329*b2055c35SXin Li int width, int height,
330*b2055c35SXin Li uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
331*b2055c35SXin Li uint8_t alpha_mask = 0xff;
332*b2055c35SXin Li int i, j;
333*b2055c35SXin Li
334*b2055c35SXin Li for (j = 0; j < height; ++j) {
335*b2055c35SXin Li for (i = 0; i < width; ++i) {
336*b2055c35SXin Li const uint8_t alpha_value = argb[4 * i];
337*b2055c35SXin Li alpha[i] = alpha_value;
338*b2055c35SXin Li alpha_mask &= alpha_value;
339*b2055c35SXin Li }
340*b2055c35SXin Li argb += argb_stride;
341*b2055c35SXin Li alpha += alpha_stride;
342*b2055c35SXin Li }
343*b2055c35SXin Li return (alpha_mask == 0xff);
344*b2055c35SXin Li }
345*b2055c35SXin Li
ExtractGreen_C(const uint32_t * WEBP_RESTRICT argb,uint8_t * WEBP_RESTRICT alpha,int size)346*b2055c35SXin Li static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb,
347*b2055c35SXin Li uint8_t* WEBP_RESTRICT alpha, int size) {
348*b2055c35SXin Li int i;
349*b2055c35SXin Li for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
350*b2055c35SXin Li }
351*b2055c35SXin Li #endif // !WEBP_NEON_OMIT_C_CODE
352*b2055c35SXin Li
353*b2055c35SXin Li //------------------------------------------------------------------------------
354*b2055c35SXin Li
HasAlpha8b_C(const uint8_t * src,int length)355*b2055c35SXin Li static int HasAlpha8b_C(const uint8_t* src, int length) {
356*b2055c35SXin Li while (length-- > 0) if (*src++ != 0xff) return 1;
357*b2055c35SXin Li return 0;
358*b2055c35SXin Li }
359*b2055c35SXin Li
HasAlpha32b_C(const uint8_t * src,int length)360*b2055c35SXin Li static int HasAlpha32b_C(const uint8_t* src, int length) {
361*b2055c35SXin Li int x;
362*b2055c35SXin Li for (x = 0; length-- > 0; x += 4) if (src[x] != 0xff) return 1;
363*b2055c35SXin Li return 0;
364*b2055c35SXin Li }
365*b2055c35SXin Li
AlphaReplace_C(uint32_t * src,int length,uint32_t color)366*b2055c35SXin Li static void AlphaReplace_C(uint32_t* src, int length, uint32_t color) {
367*b2055c35SXin Li int x;
368*b2055c35SXin Li for (x = 0; x < length; ++x) if ((src[x] >> 24) == 0) src[x] = color;
369*b2055c35SXin Li }
370*b2055c35SXin Li
371*b2055c35SXin Li //------------------------------------------------------------------------------
372*b2055c35SXin Li // Simple channel manipulations.
373*b2055c35SXin Li
MakeARGB32(int a,int r,int g,int b)374*b2055c35SXin Li static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
375*b2055c35SXin Li return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
376*b2055c35SXin Li }
377*b2055c35SXin Li
378*b2055c35SXin Li #ifdef WORDS_BIGENDIAN
PackARGB_C(const uint8_t * WEBP_RESTRICT a,const uint8_t * WEBP_RESTRICT r,const uint8_t * WEBP_RESTRICT g,const uint8_t * WEBP_RESTRICT b,int len,uint32_t * WEBP_RESTRICT out)379*b2055c35SXin Li static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
380*b2055c35SXin Li const uint8_t* WEBP_RESTRICT r,
381*b2055c35SXin Li const uint8_t* WEBP_RESTRICT g,
382*b2055c35SXin Li const uint8_t* WEBP_RESTRICT b,
383*b2055c35SXin Li int len, uint32_t* WEBP_RESTRICT out) {
384*b2055c35SXin Li int i;
385*b2055c35SXin Li for (i = 0; i < len; ++i) {
386*b2055c35SXin Li out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
387*b2055c35SXin Li }
388*b2055c35SXin Li }
389*b2055c35SXin Li #endif
390*b2055c35SXin Li
PackRGB_C(const uint8_t * WEBP_RESTRICT r,const uint8_t * WEBP_RESTRICT g,const uint8_t * WEBP_RESTRICT b,int len,int step,uint32_t * WEBP_RESTRICT out)391*b2055c35SXin Li static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
392*b2055c35SXin Li const uint8_t* WEBP_RESTRICT g,
393*b2055c35SXin Li const uint8_t* WEBP_RESTRICT b,
394*b2055c35SXin Li int len, int step, uint32_t* WEBP_RESTRICT out) {
395*b2055c35SXin Li int i, offset = 0;
396*b2055c35SXin Li for (i = 0; i < len; ++i) {
397*b2055c35SXin Li out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
398*b2055c35SXin Li offset += step;
399*b2055c35SXin Li }
400*b2055c35SXin Li }
401*b2055c35SXin Li
402*b2055c35SXin Li void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
403*b2055c35SXin Li void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
404*b2055c35SXin Li int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
405*b2055c35SXin Li uint8_t* WEBP_RESTRICT, int);
406*b2055c35SXin Li void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int,
407*b2055c35SXin Li uint32_t* WEBP_RESTRICT, int);
408*b2055c35SXin Li int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
409*b2055c35SXin Li uint8_t* WEBP_RESTRICT, int);
410*b2055c35SXin Li void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
411*b2055c35SXin Li uint8_t* WEBP_RESTRICT alpha, int size);
412*b2055c35SXin Li #ifdef WORDS_BIGENDIAN
413*b2055c35SXin Li void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
414*b2055c35SXin Li const uint8_t* b, int, uint32_t*);
415*b2055c35SXin Li #endif
416*b2055c35SXin Li void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
417*b2055c35SXin Li const uint8_t* WEBP_RESTRICT g,
418*b2055c35SXin Li const uint8_t* WEBP_RESTRICT b,
419*b2055c35SXin Li int len, int step, uint32_t* WEBP_RESTRICT out);
420*b2055c35SXin Li
421*b2055c35SXin Li int (*WebPHasAlpha8b)(const uint8_t* src, int length);
422*b2055c35SXin Li int (*WebPHasAlpha32b)(const uint8_t* src, int length);
423*b2055c35SXin Li void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color);
424*b2055c35SXin Li
425*b2055c35SXin Li //------------------------------------------------------------------------------
426*b2055c35SXin Li // Init function
427*b2055c35SXin Li
428*b2055c35SXin Li extern VP8CPUInfo VP8GetCPUInfo;
429*b2055c35SXin Li extern void WebPInitAlphaProcessingMIPSdspR2(void);
430*b2055c35SXin Li extern void WebPInitAlphaProcessingSSE2(void);
431*b2055c35SXin Li extern void WebPInitAlphaProcessingSSE41(void);
432*b2055c35SXin Li extern void WebPInitAlphaProcessingNEON(void);
433*b2055c35SXin Li
WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing)434*b2055c35SXin Li WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
435*b2055c35SXin Li WebPMultARGBRow = WebPMultARGBRow_C;
436*b2055c35SXin Li WebPMultRow = WebPMultRow_C;
437*b2055c35SXin Li WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C;
438*b2055c35SXin Li
439*b2055c35SXin Li #ifdef WORDS_BIGENDIAN
440*b2055c35SXin Li WebPPackARGB = PackARGB_C;
441*b2055c35SXin Li #endif
442*b2055c35SXin Li WebPPackRGB = PackRGB_C;
443*b2055c35SXin Li #if !WEBP_NEON_OMIT_C_CODE
444*b2055c35SXin Li WebPApplyAlphaMultiply = ApplyAlphaMultiply_C;
445*b2055c35SXin Li WebPDispatchAlpha = DispatchAlpha_C;
446*b2055c35SXin Li WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
447*b2055c35SXin Li WebPExtractAlpha = ExtractAlpha_C;
448*b2055c35SXin Li WebPExtractGreen = ExtractGreen_C;
449*b2055c35SXin Li #endif
450*b2055c35SXin Li
451*b2055c35SXin Li WebPHasAlpha8b = HasAlpha8b_C;
452*b2055c35SXin Li WebPHasAlpha32b = HasAlpha32b_C;
453*b2055c35SXin Li WebPAlphaReplace = AlphaReplace_C;
454*b2055c35SXin Li
455*b2055c35SXin Li // If defined, use CPUInfo() to overwrite some pointers with faster versions.
456*b2055c35SXin Li if (VP8GetCPUInfo != NULL) {
457*b2055c35SXin Li #if defined(WEBP_HAVE_SSE2)
458*b2055c35SXin Li if (VP8GetCPUInfo(kSSE2)) {
459*b2055c35SXin Li WebPInitAlphaProcessingSSE2();
460*b2055c35SXin Li #if defined(WEBP_HAVE_SSE41)
461*b2055c35SXin Li if (VP8GetCPUInfo(kSSE4_1)) {
462*b2055c35SXin Li WebPInitAlphaProcessingSSE41();
463*b2055c35SXin Li }
464*b2055c35SXin Li #endif
465*b2055c35SXin Li }
466*b2055c35SXin Li #endif
467*b2055c35SXin Li #if defined(WEBP_USE_MIPS_DSP_R2)
468*b2055c35SXin Li if (VP8GetCPUInfo(kMIPSdspR2)) {
469*b2055c35SXin Li WebPInitAlphaProcessingMIPSdspR2();
470*b2055c35SXin Li }
471*b2055c35SXin Li #endif
472*b2055c35SXin Li }
473*b2055c35SXin Li
474*b2055c35SXin Li #if defined(WEBP_HAVE_NEON)
475*b2055c35SXin Li if (WEBP_NEON_OMIT_C_CODE ||
476*b2055c35SXin Li (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
477*b2055c35SXin Li WebPInitAlphaProcessingNEON();
478*b2055c35SXin Li }
479*b2055c35SXin Li #endif
480*b2055c35SXin Li
481*b2055c35SXin Li assert(WebPMultARGBRow != NULL);
482*b2055c35SXin Li assert(WebPMultRow != NULL);
483*b2055c35SXin Li assert(WebPApplyAlphaMultiply != NULL);
484*b2055c35SXin Li assert(WebPApplyAlphaMultiply4444 != NULL);
485*b2055c35SXin Li assert(WebPDispatchAlpha != NULL);
486*b2055c35SXin Li assert(WebPDispatchAlphaToGreen != NULL);
487*b2055c35SXin Li assert(WebPExtractAlpha != NULL);
488*b2055c35SXin Li assert(WebPExtractGreen != NULL);
489*b2055c35SXin Li #ifdef WORDS_BIGENDIAN
490*b2055c35SXin Li assert(WebPPackARGB != NULL);
491*b2055c35SXin Li #endif
492*b2055c35SXin Li assert(WebPPackRGB != NULL);
493*b2055c35SXin Li assert(WebPHasAlpha8b != NULL);
494*b2055c35SXin Li assert(WebPHasAlpha32b != NULL);
495*b2055c35SXin Li assert(WebPAlphaReplace != NULL);
496*b2055c35SXin Li }
497