Line | Count | Source |
1 | | // Copyright 2020 Joe Drago. All rights reserved. |
2 | | // SPDX-License-Identifier: BSD-2-Clause |
3 | | |
4 | | #include "avif/internal.h" |
5 | | |
6 | | #include <assert.h> |
7 | | #include <string.h> |
8 | | |
9 | | void avifFillAlpha(const avifAlphaParams * params) |
10 | 12.5k | { |
11 | 12.5k | if (params->dstDepth > 8) { |
12 | 3.08k | const uint16_t maxChannel = (uint16_t)((1 << params->dstDepth) - 1); |
13 | 3.08k | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
14 | 2.29M | for (uint32_t j = 0; j < params->height; ++j) { |
15 | 2.29M | uint8_t * dstPixel = dstRow; |
16 | 432M | for (uint32_t i = 0; i < params->width; ++i) { |
17 | 430M | *((uint16_t *)dstPixel) = maxChannel; |
18 | 430M | dstPixel += params->dstPixelBytes; |
19 | 430M | } |
20 | 2.29M | dstRow += params->dstRowBytes; |
21 | 2.29M | } |
22 | 9.46k | } else { |
23 | | // In this case, (1 << params->dstDepth) - 1 is always equal to 255. |
24 | 9.46k | const uint8_t maxChannel = 255; |
25 | 9.46k | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
26 | 2.67M | for (uint32_t j = 0; j < params->height; ++j) { |
27 | 2.66M | uint8_t * dstPixel = dstRow; |
28 | 689M | for (uint32_t i = 0; i < params->width; ++i) { |
29 | 686M | *dstPixel = maxChannel; |
30 | 686M | dstPixel += params->dstPixelBytes; |
31 | 686M | } |
32 | 2.66M | dstRow += params->dstRowBytes; |
33 | 2.66M | } |
34 | 9.46k | } |
35 | 12.5k | } |
36 | | |
37 | | void avifReformatAlpha(const avifAlphaParams * params) |
38 | 251 | { |
39 | 251 | const int srcMaxChannel = (1 << params->srcDepth) - 1; |
40 | 251 | const int dstMaxChannel = (1 << params->dstDepth) - 1; |
41 | 251 | const float srcMaxChannelF = (float)srcMaxChannel; |
42 | 251 | const float dstMaxChannelF = (float)dstMaxChannel; |
43 | | |
44 | 251 | if (params->srcDepth == params->dstDepth) { |
45 | | // no depth rescale |
46 | | |
47 | 168 | if (params->srcDepth > 8) { |
48 | | // no depth rescale, uint16_t -> uint16_t |
49 | |
|
50 | 0 | const uint8_t * srcRow = ¶ms->srcPlane[params->srcOffsetBytes]; |
51 | 0 | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
52 | 0 | for (uint32_t j = 0; j < params->height; ++j) { |
53 | 0 | const uint8_t * srcPixel = srcRow; |
54 | 0 | uint8_t * dstPixel = dstRow; |
55 | 0 | for (uint32_t i = 0; i < params->width; ++i) { |
56 | 0 | *((uint16_t *)dstPixel) = *((const uint16_t *)srcPixel); |
57 | 0 | srcPixel += params->srcPixelBytes; |
58 | 0 | dstPixel += params->dstPixelBytes; |
59 | 0 | } |
60 | 0 | srcRow += params->srcRowBytes; |
61 | 0 | dstRow += params->dstRowBytes; |
62 | 0 | } |
63 | 168 | } else { |
64 | | // no depth rescale, uint8_t -> uint8_t |
65 | | |
66 | 168 | const uint8_t * srcRow = ¶ms->srcPlane[params->srcOffsetBytes]; |
67 | 168 | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
68 | 112k | for (uint32_t j = 0; j < params->height; ++j) { |
69 | 112k | const uint8_t * srcPixel = srcRow; |
70 | 112k | uint8_t * dstPixel = dstRow; |
71 | 10.0M | for (uint32_t i = 0; i < params->width; ++i) { |
72 | 9.91M | *dstPixel = *srcPixel; |
73 | 9.91M | srcPixel += params->srcPixelBytes; |
74 | 9.91M | dstPixel += params->dstPixelBytes; |
75 | 9.91M | } |
76 | 112k | srcRow += params->srcRowBytes; |
77 | 112k | dstRow += params->dstRowBytes; |
78 | 112k | } |
79 | 168 | } |
80 | 168 | } else { |
81 | | // depth rescale |
82 | | |
83 | 83 | if (params->srcDepth > 8) { |
84 | 83 | if (params->dstDepth > 8) { |
85 | | // depth rescale, uint16_t -> uint16_t |
86 | | |
87 | 83 | const uint8_t * srcRow = ¶ms->srcPlane[params->srcOffsetBytes]; |
88 | 83 | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
89 | 63.3k | for (uint32_t j = 0; j < params->height; ++j) { |
90 | 63.2k | const uint8_t * srcPixel = srcRow; |
91 | 63.2k | uint8_t * dstPixel = dstRow; |
92 | 12.3M | for (uint32_t i = 0; i < params->width; ++i) { |
93 | 12.3M | int srcAlpha = *((const uint16_t *)srcPixel); |
94 | 12.3M | float alphaF = (float)srcAlpha / srcMaxChannelF; |
95 | 12.3M | int dstAlpha = (int)(0.5f + (alphaF * dstMaxChannelF)); |
96 | 12.3M | dstAlpha = AVIF_CLAMP(dstAlpha, 0, dstMaxChannel); |
97 | 12.3M | *((uint16_t *)dstPixel) = (uint16_t)dstAlpha; |
98 | 12.3M | srcPixel += params->srcPixelBytes; |
99 | 12.3M | dstPixel += params->dstPixelBytes; |
100 | 12.3M | } |
101 | 63.2k | srcRow += params->srcRowBytes; |
102 | 63.2k | dstRow += params->dstRowBytes; |
103 | 63.2k | } |
104 | 83 | } else { |
105 | | // depth rescale, uint16_t -> uint8_t |
106 | |
|
107 | 0 | const uint8_t * srcRow = ¶ms->srcPlane[params->srcOffsetBytes]; |
108 | 0 | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
109 | 0 | for (uint32_t j = 0; j < params->height; ++j) { |
110 | 0 | const uint8_t * srcPixel = srcRow; |
111 | 0 | uint8_t * dstPixel = dstRow; |
112 | 0 | for (uint32_t i = 0; i < params->width; ++i) { |
113 | 0 | int srcAlpha = *((const uint16_t *)srcPixel); |
114 | 0 | float alphaF = (float)srcAlpha / srcMaxChannelF; |
115 | 0 | int dstAlpha = (int)(0.5f + (alphaF * dstMaxChannelF)); |
116 | 0 | dstAlpha = AVIF_CLAMP(dstAlpha, 0, dstMaxChannel); |
117 | 0 | *dstPixel = (uint8_t)dstAlpha; |
118 | 0 | srcPixel += params->srcPixelBytes; |
119 | 0 | dstPixel += params->dstPixelBytes; |
120 | 0 | } |
121 | 0 | srcRow += params->srcRowBytes; |
122 | 0 | dstRow += params->dstRowBytes; |
123 | 0 | } |
124 | 0 | } |
125 | 83 | } else { |
126 | | // If (srcDepth == 8), dstDepth must be >8 otherwise we'd be in the (params->srcDepth == params->dstDepth) block above. |
127 | 0 | assert(params->dstDepth > 8); |
128 | | |
129 | | // depth rescale, uint8_t -> uint16_t |
130 | 0 | const uint8_t * srcRow = ¶ms->srcPlane[params->srcOffsetBytes]; |
131 | 0 | uint8_t * dstRow = ¶ms->dstPlane[params->dstOffsetBytes]; |
132 | 0 | for (uint32_t j = 0; j < params->height; ++j) { |
133 | 0 | const uint8_t * srcPixel = srcRow; |
134 | 0 | uint8_t * dstPixel = dstRow; |
135 | 0 | for (uint32_t i = 0; i < params->width; ++i) { |
136 | 0 | int srcAlpha = *srcPixel; |
137 | 0 | float alphaF = (float)srcAlpha / srcMaxChannelF; |
138 | 0 | int dstAlpha = (int)(0.5f + (alphaF * dstMaxChannelF)); |
139 | 0 | dstAlpha = AVIF_CLAMP(dstAlpha, 0, dstMaxChannel); |
140 | 0 | *((uint16_t *)dstPixel) = (uint16_t)dstAlpha; |
141 | 0 | srcPixel += params->srcPixelBytes; |
142 | 0 | dstPixel += params->dstPixelBytes; |
143 | 0 | } |
144 | 0 | srcRow += params->srcRowBytes; |
145 | 0 | dstRow += params->dstRowBytes; |
146 | 0 | } |
147 | 0 | } |
148 | 83 | } |
149 | 251 | } |
150 | | |
151 | | avifResult avifRGBImagePremultiplyAlpha(avifRGBImage * rgb) |
152 | 0 | { |
153 | | // no data |
154 | 0 | if (!rgb->pixels || !rgb->rowBytes) { |
155 | 0 | return AVIF_RESULT_REFORMAT_FAILED; |
156 | 0 | } |
157 | | |
158 | | // no alpha. |
159 | 0 | if (!avifRGBFormatHasAlpha(rgb->format)) { |
160 | 0 | return AVIF_RESULT_INVALID_ARGUMENT; |
161 | 0 | } |
162 | | |
163 | 0 | avifResult libyuvResult = avifRGBImagePremultiplyAlphaLibYUV(rgb); |
164 | 0 | if (libyuvResult != AVIF_RESULT_NOT_IMPLEMENTED) { |
165 | 0 | return libyuvResult; |
166 | 0 | } |
167 | | |
168 | 0 | assert(rgb->depth >= 8 && rgb->depth <= 16); |
169 | |
|
170 | 0 | uint32_t max = (1 << rgb->depth) - 1; |
171 | 0 | float maxF = (float)max; |
172 | |
|
173 | 0 | if (rgb->depth > 8) { |
174 | 0 | if (rgb->format == AVIF_RGB_FORMAT_RGBA || rgb->format == AVIF_RGB_FORMAT_BGRA) { |
175 | 0 | uint8_t * row = rgb->pixels; |
176 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
177 | 0 | uint16_t * pixel = (uint16_t *)row; |
178 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
179 | 0 | uint16_t a = pixel[3]; |
180 | 0 | if (a >= max) { |
181 | | // opaque is no-op |
182 | 0 | } else if (a == 0) { |
183 | | // result must be zero |
184 | 0 | pixel[0] = 0; |
185 | 0 | pixel[1] = 0; |
186 | 0 | pixel[2] = 0; |
187 | 0 | } else { |
188 | | // a < maxF is always true now, so we don't need clamp here |
189 | 0 | pixel[0] = (uint16_t)avifRoundf((float)pixel[0] * (float)a / maxF); |
190 | 0 | pixel[1] = (uint16_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
191 | 0 | pixel[2] = (uint16_t)avifRoundf((float)pixel[2] * (float)a / maxF); |
192 | 0 | } |
193 | 0 | pixel += 4; |
194 | 0 | } |
195 | 0 | row += rgb->rowBytes; |
196 | 0 | } |
197 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_ARGB || rgb->format == AVIF_RGB_FORMAT_ABGR) { |
198 | 0 | uint8_t * row = rgb->pixels; |
199 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
200 | 0 | uint16_t * pixel = (uint16_t *)row; |
201 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
202 | 0 | uint16_t a = pixel[0]; |
203 | 0 | if (a >= max) { |
204 | 0 | } else if (a == 0) { |
205 | 0 | pixel[1] = 0; |
206 | 0 | pixel[2] = 0; |
207 | 0 | pixel[3] = 0; |
208 | 0 | } else { |
209 | 0 | pixel[1] = (uint16_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
210 | 0 | pixel[2] = (uint16_t)avifRoundf((float)pixel[2] * (float)a / maxF); |
211 | 0 | pixel[3] = (uint16_t)avifRoundf((float)pixel[3] * (float)a / maxF); |
212 | 0 | } |
213 | 0 | pixel += 4; |
214 | 0 | } |
215 | 0 | row += rgb->rowBytes; |
216 | 0 | } |
217 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_GRAYA) { |
218 | 0 | uint8_t * row = rgb->pixels; |
219 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
220 | 0 | uint16_t * pixel = (uint16_t *)row; |
221 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
222 | 0 | uint16_t a = pixel[1]; |
223 | 0 | if (a >= max) { |
224 | | // opaque is no-op |
225 | 0 | } else if (a == 0) { |
226 | | // result must be zero |
227 | 0 | pixel[0] = 0; |
228 | 0 | } else { |
229 | | // a < maxF is always true now, so we don't need clamp here |
230 | 0 | pixel[0] = (uint16_t)avifRoundf((float)pixel[0] * (float)a / maxF); |
231 | 0 | } |
232 | 0 | pixel += 2; |
233 | 0 | } |
234 | 0 | row += rgb->rowBytes; |
235 | 0 | } |
236 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_AGRAY) { |
237 | 0 | uint8_t * row = rgb->pixels; |
238 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
239 | 0 | uint16_t * pixel = (uint16_t *)row; |
240 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
241 | 0 | uint16_t a = pixel[0]; |
242 | 0 | if (a >= max) { |
243 | 0 | } else if (a == 0) { |
244 | 0 | pixel[1] = 0; |
245 | 0 | } else { |
246 | 0 | pixel[1] = (uint16_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
247 | 0 | } |
248 | 0 | pixel += 2; |
249 | 0 | } |
250 | 0 | row += rgb->rowBytes; |
251 | 0 | } |
252 | 0 | } else { |
253 | 0 | return AVIF_RESULT_NOT_IMPLEMENTED; |
254 | 0 | } |
255 | 0 | } else { |
256 | 0 | if (rgb->format == AVIF_RGB_FORMAT_RGBA || rgb->format == AVIF_RGB_FORMAT_BGRA) { |
257 | 0 | uint8_t * row = rgb->pixels; |
258 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
259 | 0 | uint8_t * pixel = row; |
260 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
261 | 0 | uint8_t a = pixel[3]; |
262 | | // uint8_t can't exceed 255 |
263 | 0 | if (a == max) { |
264 | 0 | } else if (a == 0) { |
265 | 0 | pixel[0] = 0; |
266 | 0 | pixel[1] = 0; |
267 | 0 | pixel[2] = 0; |
268 | 0 | } else { |
269 | 0 | pixel[0] = (uint8_t)avifRoundf((float)pixel[0] * (float)a / maxF); |
270 | 0 | pixel[1] = (uint8_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
271 | 0 | pixel[2] = (uint8_t)avifRoundf((float)pixel[2] * (float)a / maxF); |
272 | 0 | } |
273 | 0 | pixel += 4; |
274 | 0 | } |
275 | 0 | row += rgb->rowBytes; |
276 | 0 | } |
277 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_ARGB || rgb->format == AVIF_RGB_FORMAT_ABGR) { |
278 | 0 | uint8_t * row = rgb->pixels; |
279 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
280 | 0 | uint8_t * pixel = row; |
281 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
282 | 0 | uint8_t a = pixel[0]; |
283 | 0 | if (a == max) { |
284 | 0 | } else if (a == 0) { |
285 | 0 | pixel[1] = 0; |
286 | 0 | pixel[2] = 0; |
287 | 0 | pixel[3] = 0; |
288 | 0 | } else { |
289 | 0 | pixel[1] = (uint8_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
290 | 0 | pixel[2] = (uint8_t)avifRoundf((float)pixel[2] * (float)a / maxF); |
291 | 0 | pixel[3] = (uint8_t)avifRoundf((float)pixel[3] * (float)a / maxF); |
292 | 0 | } |
293 | 0 | pixel += 4; |
294 | 0 | } |
295 | 0 | row += rgb->rowBytes; |
296 | 0 | } |
297 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_GRAYA) { |
298 | 0 | uint8_t * row = rgb->pixels; |
299 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
300 | 0 | uint8_t * pixel = row; |
301 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
302 | 0 | uint8_t a = pixel[1]; |
303 | | // uint8_t can't exceed 255 |
304 | 0 | if (a == max) { |
305 | 0 | } else if (a == 0) { |
306 | 0 | pixel[0] = 0; |
307 | 0 | } else { |
308 | 0 | pixel[0] = (uint8_t)avifRoundf((float)pixel[0] * (float)a / maxF); |
309 | 0 | } |
310 | 0 | pixel += 2; |
311 | 0 | } |
312 | 0 | row += rgb->rowBytes; |
313 | 0 | } |
314 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_AGRAY) { |
315 | 0 | uint8_t * row = rgb->pixels; |
316 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
317 | 0 | uint8_t * pixel = row; |
318 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
319 | 0 | uint8_t a = pixel[0]; |
320 | 0 | if (a == max) { |
321 | 0 | } else if (a == 0) { |
322 | 0 | pixel[1] = 0; |
323 | 0 | } else { |
324 | 0 | pixel[1] = (uint8_t)avifRoundf((float)pixel[1] * (float)a / maxF); |
325 | 0 | } |
326 | 0 | pixel += 2; |
327 | 0 | } |
328 | 0 | row += rgb->rowBytes; |
329 | 0 | } |
330 | 0 | } else { |
331 | 0 | return AVIF_RESULT_NOT_IMPLEMENTED; |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | 0 | return AVIF_RESULT_OK; |
336 | 0 | } |
337 | | |
338 | | avifResult avifRGBImageUnpremultiplyAlpha(avifRGBImage * rgb) |
339 | 0 | { |
340 | | // no data |
341 | 0 | if (!rgb->pixels || !rgb->rowBytes) { |
342 | 0 | return AVIF_RESULT_REFORMAT_FAILED; |
343 | 0 | } |
344 | | |
345 | | // no alpha. |
346 | 0 | if (!avifRGBFormatHasAlpha(rgb->format)) { |
347 | 0 | return AVIF_RESULT_REFORMAT_FAILED; |
348 | 0 | } |
349 | | |
350 | 0 | avifResult libyuvResult = avifRGBImageUnpremultiplyAlphaLibYUV(rgb); |
351 | 0 | if (libyuvResult != AVIF_RESULT_NOT_IMPLEMENTED) { |
352 | 0 | return libyuvResult; |
353 | 0 | } |
354 | | |
355 | 0 | assert(rgb->depth >= 8 && rgb->depth <= 16); |
356 | |
|
357 | 0 | uint32_t max = (1 << rgb->depth) - 1; |
358 | 0 | float maxF = (float)max; |
359 | |
|
360 | 0 | if (rgb->depth > 8) { |
361 | 0 | if (rgb->format == AVIF_RGB_FORMAT_RGBA || rgb->format == AVIF_RGB_FORMAT_BGRA) { |
362 | 0 | uint8_t * row = rgb->pixels; |
363 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
364 | 0 | uint16_t * pixel = (uint16_t *)row; |
365 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
366 | 0 | uint16_t a = pixel[3]; |
367 | 0 | if (a >= max) { |
368 | | // opaque is no-op |
369 | 0 | } else if (a == 0) { |
370 | | // prevent division by zero |
371 | 0 | pixel[0] = 0; |
372 | 0 | pixel[1] = 0; |
373 | 0 | pixel[2] = 0; |
374 | 0 | } else { |
375 | 0 | float c1 = avifRoundf((float)pixel[0] * maxF / (float)a); |
376 | 0 | float c2 = avifRoundf((float)pixel[1] * maxF / (float)a); |
377 | 0 | float c3 = avifRoundf((float)pixel[2] * maxF / (float)a); |
378 | 0 | pixel[0] = (uint16_t)AVIF_MIN(c1, maxF); |
379 | 0 | pixel[1] = (uint16_t)AVIF_MIN(c2, maxF); |
380 | 0 | pixel[2] = (uint16_t)AVIF_MIN(c3, maxF); |
381 | 0 | } |
382 | 0 | pixel += 4; |
383 | 0 | } |
384 | 0 | row += rgb->rowBytes; |
385 | 0 | } |
386 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_ARGB || rgb->format == AVIF_RGB_FORMAT_ABGR) { |
387 | 0 | uint8_t * row = rgb->pixels; |
388 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
389 | 0 | uint16_t * pixel = (uint16_t *)row; |
390 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
391 | 0 | uint16_t a = pixel[0]; |
392 | 0 | if (a >= max) { |
393 | 0 | } else if (a == 0) { |
394 | 0 | pixel[1] = 0; |
395 | 0 | pixel[2] = 0; |
396 | 0 | pixel[3] = 0; |
397 | 0 | } else { |
398 | 0 | float c1 = avifRoundf((float)pixel[1] * maxF / (float)a); |
399 | 0 | float c2 = avifRoundf((float)pixel[2] * maxF / (float)a); |
400 | 0 | float c3 = avifRoundf((float)pixel[3] * maxF / (float)a); |
401 | 0 | pixel[1] = (uint16_t)AVIF_MIN(c1, maxF); |
402 | 0 | pixel[2] = (uint16_t)AVIF_MIN(c2, maxF); |
403 | 0 | pixel[3] = (uint16_t)AVIF_MIN(c3, maxF); |
404 | 0 | } |
405 | 0 | pixel += 4; |
406 | 0 | } |
407 | 0 | row += rgb->rowBytes; |
408 | 0 | } |
409 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_GRAYA) { |
410 | 0 | uint8_t * row = rgb->pixels; |
411 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
412 | 0 | uint16_t * pixel = (uint16_t *)row; |
413 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
414 | 0 | uint16_t a = pixel[1]; |
415 | 0 | if (a >= max) { |
416 | | // opaque is no-op |
417 | 0 | } else if (a == 0) { |
418 | | // prevent division by zero |
419 | 0 | pixel[0] = 0; |
420 | 0 | } else { |
421 | 0 | float c1 = avifRoundf((float)pixel[0] * maxF / (float)a); |
422 | 0 | pixel[0] = (uint16_t)AVIF_MIN(c1, maxF); |
423 | 0 | } |
424 | 0 | pixel += 2; |
425 | 0 | } |
426 | 0 | row += rgb->rowBytes; |
427 | 0 | } |
428 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_AGRAY) { |
429 | 0 | uint8_t * row = rgb->pixels; |
430 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
431 | 0 | uint16_t * pixel = (uint16_t *)row; |
432 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
433 | 0 | uint16_t a = pixel[0]; |
434 | 0 | if (a >= max) { |
435 | 0 | } else if (a == 0) { |
436 | 0 | pixel[1] = 0; |
437 | 0 | } else { |
438 | 0 | float c1 = avifRoundf((float)pixel[1] * maxF / (float)a); |
439 | 0 | pixel[1] = (uint16_t)AVIF_MIN(c1, maxF); |
440 | 0 | } |
441 | 0 | pixel += 2; |
442 | 0 | } |
443 | 0 | row += rgb->rowBytes; |
444 | 0 | } |
445 | 0 | } else { |
446 | 0 | return AVIF_RESULT_NOT_IMPLEMENTED; |
447 | 0 | } |
448 | 0 | } else { |
449 | 0 | if (rgb->format == AVIF_RGB_FORMAT_RGBA || rgb->format == AVIF_RGB_FORMAT_BGRA) { |
450 | 0 | uint8_t * row = rgb->pixels; |
451 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
452 | 0 | uint8_t * pixel = row; |
453 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
454 | 0 | uint8_t a = pixel[3]; |
455 | 0 | if (a == max) { |
456 | 0 | } else if (a == 0) { |
457 | 0 | pixel[0] = 0; |
458 | 0 | pixel[1] = 0; |
459 | 0 | pixel[2] = 0; |
460 | 0 | } else { |
461 | 0 | float c1 = avifRoundf((float)pixel[0] * maxF / (float)a); |
462 | 0 | float c2 = avifRoundf((float)pixel[1] * maxF / (float)a); |
463 | 0 | float c3 = avifRoundf((float)pixel[2] * maxF / (float)a); |
464 | 0 | pixel[0] = (uint8_t)AVIF_MIN(c1, maxF); |
465 | 0 | pixel[1] = (uint8_t)AVIF_MIN(c2, maxF); |
466 | 0 | pixel[2] = (uint8_t)AVIF_MIN(c3, maxF); |
467 | 0 | } |
468 | 0 | pixel += 4; |
469 | 0 | } |
470 | 0 | row += rgb->rowBytes; |
471 | 0 | } |
472 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_ARGB || rgb->format == AVIF_RGB_FORMAT_ABGR) { |
473 | 0 | uint8_t * row = rgb->pixels; |
474 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
475 | 0 | uint8_t * pixel = row; |
476 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
477 | 0 | uint8_t a = pixel[0]; |
478 | 0 | if (a == max) { |
479 | 0 | } else if (a == 0) { |
480 | 0 | pixel[1] = 0; |
481 | 0 | pixel[2] = 0; |
482 | 0 | pixel[3] = 0; |
483 | 0 | } else { |
484 | 0 | float c1 = avifRoundf((float)pixel[1] * maxF / (float)a); |
485 | 0 | float c2 = avifRoundf((float)pixel[2] * maxF / (float)a); |
486 | 0 | float c3 = avifRoundf((float)pixel[3] * maxF / (float)a); |
487 | 0 | pixel[1] = (uint8_t)AVIF_MIN(c1, maxF); |
488 | 0 | pixel[2] = (uint8_t)AVIF_MIN(c2, maxF); |
489 | 0 | pixel[3] = (uint8_t)AVIF_MIN(c3, maxF); |
490 | 0 | } |
491 | 0 | pixel += 4; |
492 | 0 | } |
493 | 0 | row += rgb->rowBytes; |
494 | 0 | } |
495 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_GRAYA) { |
496 | 0 | uint8_t * row = rgb->pixels; |
497 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
498 | 0 | uint8_t * pixel = row; |
499 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
500 | 0 | uint8_t a = pixel[1]; |
501 | 0 | if (a == max) { |
502 | 0 | } else if (a == 0) { |
503 | 0 | pixel[0] = 0; |
504 | 0 | } else { |
505 | 0 | float c1 = avifRoundf((float)pixel[0] * maxF / (float)a); |
506 | 0 | pixel[0] = (uint8_t)AVIF_MIN(c1, maxF); |
507 | 0 | } |
508 | 0 | pixel += 2; |
509 | 0 | } |
510 | 0 | row += rgb->rowBytes; |
511 | 0 | } |
512 | 0 | } else if (rgb->format == AVIF_RGB_FORMAT_AGRAY) { |
513 | 0 | uint8_t * row = rgb->pixels; |
514 | 0 | for (uint32_t j = 0; j < rgb->height; ++j) { |
515 | 0 | uint8_t * pixel = row; |
516 | 0 | for (uint32_t i = 0; i < rgb->width; ++i) { |
517 | 0 | uint8_t a = pixel[0]; |
518 | 0 | if (a == max) { |
519 | 0 | } else if (a == 0) { |
520 | 0 | pixel[1] = 0; |
521 | 0 | } else { |
522 | 0 | float c1 = avifRoundf((float)pixel[1] * maxF / (float)a); |
523 | 0 | pixel[1] = (uint8_t)AVIF_MIN(c1, maxF); |
524 | 0 | } |
525 | 0 | pixel += 2; |
526 | 0 | } |
527 | 0 | row += rgb->rowBytes; |
528 | 0 | } |
529 | 0 | } else { |
530 | 0 | return AVIF_RESULT_NOT_IMPLEMENTED; |
531 | 0 | } |
532 | 0 | } |
533 | | |
534 | 0 | return AVIF_RESULT_OK; |
535 | 0 | } |