ObjFW
Loading...
Searching...
No Matches
OFImage+Private.h
1/*
2 * Copyright (c) 2008-2026 Jonathan Schleifer <js@nil.im>
3 *
4 * All rights reserved.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License version 3.0 only,
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * version 3.0 for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * version 3.0 along with this program. If not, see
17 * <https://www.gnu.org/licenses/>.
18 */
19
20#import "OFImage.h"
21#import "OFColorSpace.h"
22
23OF_ASSUME_NONNULL_BEGIN
24
25static OF_INLINE void
26_OFReadRGB888Pixel(const uint8_t *pixels, size_t x, size_t y, size_t width,
27 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
28{
29 pixels += (x + y * width) * 3;
30
31 *red = pixels[0];
32 *green = pixels[1];
33 *blue = pixels[2];
34 *alpha = 255;
35}
36
37static OF_INLINE void
38_OFReadBGR888Pixel(const uint8_t *pixels, size_t x, size_t y, size_t width,
39 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
40{
41 pixels += (x + y * width) * 3;
42
43 *red = pixels[2];
44 *green = pixels[1];
45 *blue = pixels[0];
46 *alpha = 255;
47}
48
49static OF_INLINE void
50_OFReadRGBA8888Pixel(const uint32_t *pixels, size_t x, size_t y, size_t width,
51 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
52{
53 uint32_t value = pixels[x + y * width];
54
55 *red = (value & 0xFF000000) >> 24;
56 *green = (value & 0x00FF0000) >> 16;
57 *blue = (value & 0x0000FF00) >> 8;
58 *alpha = (value & 0x000000FF);
59}
60
61static OF_INLINE void
62_OFReadARGB8888Pixel(const uint32_t *pixels, size_t x, size_t y, size_t width,
63 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
64{
65 uint32_t value = pixels[x + y * width];
66
67 *red = (value & 0x00FF0000) >> 16;
68 *green = (value & 0x0000FF00) >> 8;
69 *blue = (value & 0x000000FF);
70 *alpha = (value & 0xFF000000) >> 24;
71}
72
73static OF_INLINE void
74_OFReadABGR8888Pixel(const uint32_t *pixels, size_t x, size_t y, size_t width,
75 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
76{
77 uint32_t value = pixels[x + y * width];
78
79 *red = (value & 0x000000FF);
80 *green = (value & 0x0000FF00) >> 8;
81 *blue = (value & 0x00FF0000) >> 16;
82 *alpha = (value & 0xFF000000) >> 24;
83}
84
85static OF_INLINE void
86_OFReadBGRA8888Pixel(const uint32_t *pixels, size_t x, size_t y, size_t width,
87 uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
88{
89 uint32_t value = pixels[x + y * width];
90
91 *red = (value & 0x0000FF00) >> 8;
92 *green = (value & 0x00FF0000) >> 16;
93 *blue = (value & 0xFF000000) >> 24;
94 *alpha = (value & 0x000000FF);
95}
96
97static OF_INLINE bool
98_OFReadPixelInt8(const void *pixels, OFPixelFormat format, size_t x, size_t y,
99 size_t width, uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha)
100{
101 switch (format) {
102 case OFPixelFormatRGB888:
103 _OFReadRGB888Pixel(pixels, x, y, width, red, green, blue,
104 alpha);
105 return true;
106 case OFPixelFormatBGR888:
107 _OFReadBGR888Pixel(pixels, x, y, width, red, green, blue,
108 alpha);
109 return true;
110 case OFPixelFormatRGBA8888:
111 _OFReadRGBA8888Pixel(pixels, x, y, width, red, green, blue,
112 alpha);
113 return true;
114 case OFPixelFormatARGB8888:
115 _OFReadARGB8888Pixel(pixels, x, y, width, red, green, blue,
116 alpha);
117 return true;
118 case OFPixelFormatABGR8888:
119 _OFReadABGR8888Pixel(pixels, x, y, width, red, green, blue,
120 alpha);
121 return true;
122 case OFPixelFormatBGRA8888:
123 _OFReadBGRA8888Pixel(pixels, x, y, width, red, green, blue,
124 alpha);
125 return true;
126 default:
127 return false;
128 }
129}
130
131static OF_INLINE void
132_OFReadRGB565Pixel(const uint16_t *pixels, size_t x, size_t y, size_t width,
133 float *red, float *green, float *blue, float *alpha)
134{
135 uint16_t value = pixels[x + y * width];
136
137 *red = ((value & 0xF800) >> 11) / 31.0f;
138 *green = ((value & 0x07E0) >> 5) / 63.0f;
139 *blue = (value & 0x001F) / 31.0f;
140 *alpha = 1.0f;
141}
142
143static OF_INLINE void
144_OFReadRGBA16161616FPPixel(const OFFloat16 *pixels, size_t x, size_t y,
145 size_t width, float *red, float *green, float *blue, float *alpha)
146{
147 *red = OFFloat16ToFloat(pixels[(x + y * width) * 4]);
148 *green = OFFloat16ToFloat(pixels[(x + y * width) * 4 + 1]);
149 *blue = OFFloat16ToFloat(pixels[(x + y * width) * 4 + 2]);
150 *alpha = OFFloat16ToFloat(pixels[(x + y * width) * 4 + 3]);
151}
152
153static OF_INLINE void
154_OFReadRGBA32323232FPPixel(const float *pixels, size_t x, size_t y,
155 size_t width, float *red, float *green, float *blue, float *alpha)
156{
157 *red = pixels[(x + y * width) * 4];
158 *green = pixels[(x + y * width) * 4 + 1];
159 *blue = pixels[(x + y * width) * 4 + 2];
160 *alpha = pixels[(x + y * width) * 4 + 3];
161}
162
163static OF_INLINE bool
164_OFReadPixel(const void *pixels, OFPixelFormat format, size_t x, size_t y,
165 size_t width, float *red, float *green, float *blue, float *alpha)
166{
167 uint8_t redInt8 = 0, greenInt8 = 0, blueInt8 = 0, alphaInt8 = 0;
168
169 switch (format) {
170 case OFPixelFormatRGB565:
171 _OFReadRGB565Pixel(pixels, x, y, width, red, green, blue,
172 alpha);
173 return true;
174 case OFPixelFormatRGBA16161616FP:
175 _OFReadRGBA16161616FPPixel(pixels, x, y, width, red, green,
176 blue, alpha);
177 return true;
178 case OFPixelFormatRGBA32323232FP:
179 _OFReadRGBA32323232FPPixel(pixels, x, y, width, red, green,
180 blue, alpha);
181 return true;
182 default:
183 break;
184 }
185
186 if OF_UNLIKELY (!_OFReadPixelInt8(pixels, format, x, y, width,
187 &redInt8, &greenInt8, &blueInt8, &alphaInt8))
188 return false;
189
190 *red = redInt8 / 255.0f;
191 *green = greenInt8 / 255.0f;
192 *blue = blueInt8 / 255.0f;
193 *alpha = alphaInt8 / 255.0f;
194
195 return true;
196}
197
198static OF_INLINE bool
199_OFReadAveragedPixel(const void *pixels, OFPixelFormat format, float x, float y,
200 size_t width, size_t clampX, size_t clampY,
202 float *red, float *green, float *blue, float *alpha)
203{
204 size_t xInt = x, yInt = y, nextXInt = xInt + 1, nextYInt = yInt + 1;
205 OF_ALIGN(16) OFVector4D vectors[4], averaged;
206 float scales[4];
207
208 if (x == xInt && y == yInt)
209 return _OFReadPixel(pixels, format, xInt, yInt, width,
210 red, green, blue, alpha);
211
212 if (nextXInt >= clampX || x == xInt)
213 nextXInt = xInt;
214 if (nextYInt >= clampY || y == yInt)
215 nextYInt = yInt;
216
217 if (!_OFReadPixel(pixels, format, xInt, yInt, width,
218 &vectors[0].x, &vectors[0].y, &vectors[0].z, &vectors[0].w))
219 return false;
220
221 if (!_OFReadPixel(pixels, format, nextXInt, yInt, width,
222 &vectors[1].x, &vectors[1].y, &vectors[1].z, &vectors[1].w))
223 return false;
224
225 if (!_OFReadPixel(pixels, format, xInt, nextYInt, width,
226 &vectors[2].x, &vectors[2].y, &vectors[2].z, &vectors[2].w))
227 return false;
228
229 if (!_OFReadPixel(pixels, format, nextXInt, nextYInt, width,
230 &vectors[3].x, &vectors[3].y, &vectors[3].z, &vectors[3].w))
231 return false;
232
233 scales[0] = (1.0f - (x - xInt)) * (1.0f - (y - yInt));
234 scales[1] = (x - xInt) * (1.0f - (y - yInt));
235 scales[2] = (1.0f - (x - xInt)) * (y - yInt);
236 scales[3] = (x - xInt) * (y - yInt);
237
238 if (EOTF != NULL)
239 EOTF(vectors, 4);
240
241 averaged = OFMakeVector4D(0.0f, 0.0f, 0.0f, 0.0f);
242 for (uint_fast8_t i = 0; i < 4; i++)
243 averaged = OFAddVectors4D(averaged,
244 OFMultiplyVector4D(vectors[i], scales[i]));
245
246 if (OETF != NULL)
247 OETF(&averaged, 1);
248
249 *red = averaged.x;
250 *green = averaged.y;
251 *blue = averaged.z;
252 *alpha = averaged.w;
253
254 return true;
255}
256
257static OF_INLINE void
258_OFWriteRGB888Pixel(uint8_t *pixels, size_t x, size_t y, size_t width,
259 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
260{
261 pixels += (x + y * width) * 3;
262
263 pixels[0] = red;
264 pixels[1] = green;
265 pixels[2] = blue;
266}
267
268static OF_INLINE void
269_OFWriteBGR888Pixel(uint8_t *pixels, size_t x, size_t y, size_t width,
270 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
271{
272 pixels += (x + y * width) * 3;
273
274 pixels[0] = blue;
275 pixels[1] = green;
276 pixels[2] = red;
277}
278
279static OF_INLINE void
280_OFWriteRGBA8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
281 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
282{
283 pixels[x + y * width] = (uint32_t)red << 24 | (uint32_t)green << 16 |
284 (uint32_t)blue << 8 | alpha;
285}
286
287static OF_INLINE void
288_OFWriteARGB8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
289 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
290{
291 pixels[x + y * width] = (uint32_t)alpha << 24 | (uint32_t)red << 16 |
292 (uint32_t)green << 8 | blue;
293}
294
295static OF_INLINE void
296_OFWriteABGR8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
297 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
298{
299 pixels[x + y * width] = (uint32_t)alpha << 24 | (uint32_t)blue << 16 |
300 (uint32_t)green << 8 | red;
301}
302
303static OF_INLINE void
304_OFWriteBGRA8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
305 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
306{
307 pixels[x + y * width] = (uint32_t)blue << 24 | (uint32_t)green << 16 |
308 (uint32_t)red << 8 | alpha;
309}
310
311static OF_INLINE bool
312_OFWritePixelInt8(void *pixels, OFPixelFormat format, size_t x, size_t y,
313 size_t width, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
314{
315 switch (format) {
316 case OFPixelFormatRGB888:
317 _OFWriteRGB888Pixel(pixels, x, y, width, red, green, blue,
318 alpha);
319 return true;
320 case OFPixelFormatRGBA8888:
321 _OFWriteRGBA8888Pixel(pixels, x, y, width, red, green, blue,
322 alpha);
323 return true;
324 case OFPixelFormatARGB8888:
325 _OFWriteARGB8888Pixel(pixels, x, y, width, red, green, blue,
326 alpha);
327 return true;
328 case OFPixelFormatBGR888:
329 _OFWriteBGR888Pixel(pixels, x, y, width, red, green, blue,
330 alpha);
331 return true;
332 case OFPixelFormatABGR8888:
333 _OFWriteABGR8888Pixel(pixels, x, y, width, red, green, blue,
334 alpha);
335 return true;
336 case OFPixelFormatBGRA8888:
337 _OFWriteBGRA8888Pixel(pixels, x, y, width, red, green, blue,
338 alpha);
339 return true;
340 default:
341 return false;
342 }
343}
344
345static OF_INLINE void
346_OFWriteRGB565Pixel(uint16_t *pixels, size_t x, size_t y, size_t width,
347 float red, float green, float blue, float alpha)
348{
349 uint8_t redInt, greenInt, blueInt;
350
351 if OF_UNLIKELY (red > 1.0f)
352 red = 1.0f;
353 else if OF_UNLIKELY (red < 0.0f)
354 red = 0.0f;
355 if OF_UNLIKELY (green > 1.0f)
356 green = 1.0f;
357 else if OF_UNLIKELY (green < 0.0f)
358 green = 0.0f;
359 if OF_UNLIKELY (blue > 1.0f)
360 blue = 1.0f;
361 else if OF_UNLIKELY (blue < 0.0f)
362 blue = 0.0f;
363 if OF_UNLIKELY (alpha > 1.0f)
364 alpha = 1.0f;
365
366 redInt = roundf(red * 31.0f);
367 greenInt = roundf(green * 63.0f);
368 blueInt = roundf(blue * 31.0f);
369
370 pixels[x + y * width] = (uint16_t)redInt << 11 |
371 (uint16_t)greenInt << 5 | blueInt;
372}
373
374static OF_INLINE void
375_OFWriteRGBA16161616FPPixel(OFFloat16 *pixels, size_t x, size_t y, size_t width,
376 float red, float green, float blue, float alpha)
377{
378 pixels[(x + y * width) * 4] = OFFloat16FromFloat(red);
379 pixels[(x + y * width) * 4 + 1] = OFFloat16FromFloat(green);
380 pixels[(x + y * width) * 4 + 2] = OFFloat16FromFloat(blue);
381 pixels[(x + y * width) * 4 + 3] = OFFloat16FromFloat(alpha);
382}
383
384static OF_INLINE void
385_OFWriteRGBA32323232FPPixel(float *pixels, size_t x, size_t y, size_t width,
386 float red, float green, float blue, float alpha)
387{
388 pixels[(x + y * width) * 4] = red;
389 pixels[(x + y * width) * 4 + 1] = green;
390 pixels[(x + y * width) * 4 + 2] = blue;
391 pixels[(x + y * width) * 4 + 3] = alpha;
392}
393
394static OF_INLINE bool
395_OFWritePixel(void *pixels, OFPixelFormat format, size_t x, size_t y,
396 size_t width, float red, float green, float blue, float alpha)
397{
398 switch (format) {
399 case OFPixelFormatRGB565:
400 _OFWriteRGB565Pixel(pixels, x, y, width, red, green, blue,
401 alpha);
402 return true;
403 case OFPixelFormatRGBA16161616FP:
404 _OFWriteRGBA16161616FPPixel(pixels, x, y, width, red, green,
405 blue, alpha);
406 return true;
407 case OFPixelFormatRGBA32323232FP:
408 _OFWriteRGBA32323232FPPixel(pixels, x, y, width, red, green,
409 blue, alpha);
410 return true;
411 default:
412 break;
413 }
414
415 if OF_UNLIKELY (red > 1.0f)
416 red = 1.0f;
417 else if OF_UNLIKELY (red < 0.0f)
418 red = 0.0f;
419 if OF_UNLIKELY (green > 1.0f)
420 green = 1.0f;
421 else if OF_UNLIKELY (green < 0.0f)
422 green = 0.0f;
423 if OF_UNLIKELY (blue > 1.0f)
424 blue = 1.0f;
425 else if OF_UNLIKELY (blue < 0.0f)
426 blue = 0.0f;
427 if OF_UNLIKELY (alpha > 1.0f)
428 alpha = 1.0f;
429 else if OF_UNLIKELY (alpha < 0.0f)
430 alpha = 0.0f;
431
432 return _OFWritePixelInt8(pixels, format, x, y, width,
433 roundf(red * 255.0f), roundf(green * 255.0f), roundf(blue * 255.0f),
434 roundf(alpha * 255.0f));
435}
436
437OF_DIRECT_MEMBERS
438@interface OFImage ()
439- (instancetype)of_init OF_METHOD_FAMILY(init);
440@end
441
442OF_ASSUME_NONNULL_END
void(* OFColorSpaceTransferFunction)(OFVector4D *vectors, size_t count)
A transfer function for a color space.
Definition OFColorSpace.h:42
static OF_INLINE OFVector4D OFMultiplyVector4D(OFVector4D vector, float scalar)
Multiplies the specified vector with a scalar.
Definition OFObject.h:646
static OF_INLINE OFVector4D OFAddVectors4D(OFVector4D vector1, OFVector4D vector2)
Adds the two specified vectors.
Definition OFObject.h:618
static OF_INLINE OFVector4D OF_CONST_FUNC OFMakeVector4D(float x, float y, float z, float w)
Creates a new OFVector4D.
Definition OFObject.h:578
A class representing an image.
Definition OFImage.h:117
__extension__ typedef _Float16 OFFloat16
A type for 16 bit floating point numbers.
Definition macros.h:961
A vector in 4D space.
Definition OFObject.h:557