• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // After editing this file, run "go generate" in the parent directory.
2 
3 // Copyright 2017 The Wuffs Authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //    https://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 // ---------------- Images
18 
19 const uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {
20     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
21     0x08, 0x0A, 0x0C, 0x10, 0x18, 0x20, 0x30, 0x40,
22 };
23 
24 static uint64_t  //
wuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)25 wuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,
26                                      wuffs_base__slice_u8 dst_palette,
27                                      wuffs_base__slice_u8 src) {
28   return wuffs_base__slice_u8__copy_from_slice(dst, src);
29 }
30 
31 static uint64_t  //
wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)32 wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,
33                                      wuffs_base__slice_u8 dst_palette,
34                                      wuffs_base__slice_u8 src) {
35   if (dst_palette.len != 1024) {
36     return 0;
37   }
38   size_t dst_len3 = dst.len / 3;
39   size_t len = dst_len3 < src.len ? dst_len3 : src.len;
40   uint8_t* d = dst.ptr;
41   uint8_t* s = src.ptr;
42   size_t n = len;
43 
44   // N is the loop unroll count.
45   const int N = 4;
46 
47   // The comparison in the while condition is ">", not ">=", because with ">=",
48   // the last 4-byte store could write past the end of the dst slice.
49   //
50   // Each 4-byte store writes one too many bytes, but a subsequent store will
51   // overwrite that with the correct byte. There is always another store,
52   // whether a 4-byte store in this loop or a 1-byte store in the next loop.
53   while (n > N) {
54     wuffs_base__store_u32le(
55         d + (0 * 3),
56         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
57     wuffs_base__store_u32le(
58         d + (1 * 3),
59         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
60     wuffs_base__store_u32le(
61         d + (2 * 3),
62         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
63     wuffs_base__store_u32le(
64         d + (3 * 3),
65         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
66 
67     s += 1 * N;
68     d += 3 * N;
69     n -= (size_t)(1 * N);
70   }
71 
72   while (n >= 1) {
73     uint32_t color =
74         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));
75     d[0] = (uint8_t)(color >> 0);
76     d[1] = (uint8_t)(color >> 8);
77     d[2] = (uint8_t)(color >> 16);
78 
79     s += 1 * 1;
80     d += 3 * 1;
81     n -= (size_t)(1 * 1);
82   }
83 
84   return len;
85 }
86 static uint64_t  //
wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)87 wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,
88                                      wuffs_base__slice_u8 dst_palette,
89                                      wuffs_base__slice_u8 src) {
90   if (dst_palette.len != 1024) {
91     return 0;
92   }
93   size_t dst_len4 = dst.len / 4;
94   size_t len = dst_len4 < src.len ? dst_len4 : src.len;
95   uint8_t* d = dst.ptr;
96   uint8_t* s = src.ptr;
97   size_t n = len;
98 
99   // N is the loop unroll count.
100   const int N = 4;
101 
102   while (n >= N) {
103     wuffs_base__store_u32le(
104         d + (0 * 4),
105         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
106     wuffs_base__store_u32le(
107         d + (1 * 4),
108         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
109     wuffs_base__store_u32le(
110         d + (2 * 4),
111         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
112     wuffs_base__store_u32le(
113         d + (3 * 4),
114         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
115 
116     s += 1 * N;
117     d += 4 * N;
118     n -= (size_t)(1 * N);
119   }
120 
121   while (n >= 1) {
122     wuffs_base__store_u32le(
123         d + (0 * 4),
124         wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
125 
126     s += 1 * 1;
127     d += 4 * 1;
128     n -= (size_t)(1 * 1);
129   }
130 
131   return len;
132 }
133 
134 static uint64_t  //
wuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 src)135 wuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,
136                                            wuffs_base__slice_u8 src) {
137   size_t len4 = (dst.len < src.len ? dst.len : src.len) / 4;
138   uint8_t* d = dst.ptr;
139   uint8_t* s = src.ptr;
140 
141   size_t n = len4;
142   while (n--) {
143     uint8_t b0 = s[0];
144     uint8_t b1 = s[1];
145     uint8_t b2 = s[2];
146     uint8_t b3 = s[3];
147     d[0] = b2;
148     d[1] = b1;
149     d[2] = b0;
150     d[3] = b3;
151     s += 4;
152     d += 4;
153   }
154   return len4 * 4;
155 }
156 
157 wuffs_base__status  //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler * p,wuffs_base__pixel_format dst_format,wuffs_base__slice_u8 dst_palette,wuffs_base__pixel_format src_format,wuffs_base__slice_u8 src_palette)158 wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
159                                     wuffs_base__pixel_format dst_format,
160                                     wuffs_base__slice_u8 dst_palette,
161                                     wuffs_base__pixel_format src_format,
162                                     wuffs_base__slice_u8 src_palette) {
163   if (!p) {
164     return wuffs_base__error__bad_receiver;
165   }
166 
167   // TODO: support many more formats.
168 
169   uint64_t (*func)(wuffs_base__slice_u8 dst, wuffs_base__slice_u8 dst_palette,
170                    wuffs_base__slice_u8 src) = NULL;
171 
172   switch (src_format) {
173     case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
174       switch (dst_format) {
175         case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:
176         case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:
177         case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
178           if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
179               1024) {
180             break;
181           }
182           func = wuffs_base__pixel_swizzler__copy_1_1;
183           break;
184         case WUFFS_BASE__PIXEL_FORMAT__BGR:
185           if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
186               1024) {
187             break;
188           }
189           func = wuffs_base__pixel_swizzler__copy_3_1;
190           break;
191         case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
192         case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
193         case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
194           if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
195               1024) {
196             break;
197           }
198           func = wuffs_base__pixel_swizzler__copy_4_1;
199           break;
200         case WUFFS_BASE__PIXEL_FORMAT__RGB:
201           if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,
202                                                          src_palette) != 1024) {
203             break;
204           }
205           func = wuffs_base__pixel_swizzler__copy_3_1;
206           break;
207         case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
208         case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
209         case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
210           if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,
211                                                          src_palette) != 1024) {
212             break;
213           }
214           func = wuffs_base__pixel_swizzler__copy_4_1;
215           break;
216         default:
217           break;
218       }
219       break;
220 
221     default:
222       break;
223   }
224 
225   p->private_impl.func = func;
226   return func ? NULL : wuffs_base__error__unsupported_option;
227 }
228 
229 uint64_t  //
wuffs_base__pixel_swizzler__swizzle_interleaved(const wuffs_base__pixel_swizzler * p,wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)230 wuffs_base__pixel_swizzler__swizzle_interleaved(
231     const wuffs_base__pixel_swizzler* p,
232     wuffs_base__slice_u8 dst,
233     wuffs_base__slice_u8 dst_palette,
234     wuffs_base__slice_u8 src) {
235   if (p && p->private_impl.func) {
236     return (*(p->private_impl.func))(dst, dst_palette, src);
237   }
238   return 0;
239 }
240