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] = red << 24 | green << 16 | blue << 8 | alpha;
284}
285
286static OF_INLINE void
287_OFWriteARGB8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
288 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
289{
290 pixels[x + y * width] = alpha << 24 | red << 16 | green << 8 | blue;
291}
292
293static OF_INLINE void
294_OFWriteABGR8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
295 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
296{
297 pixels[x + y * width] = alpha << 24 | blue << 16 | green << 8 | red;
298}
299
300static OF_INLINE void
301_OFWriteBGRA8888Pixel(uint32_t *pixels, size_t x, size_t y, size_t width,
302 uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
303{
304 pixels[x + y * width] = blue << 24 | green << 16 | red << 8 | alpha;
305}
306
307static OF_INLINE bool
308_OFWritePixelInt8(void *pixels, OFPixelFormat format, size_t x, size_t y,
309 size_t width, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
310{
311 switch (format) {
312 case OFPixelFormatRGB888:
313 _OFWriteRGB888Pixel(pixels, x, y, width, red, green, blue,
314 alpha);
315 return true;
316 case OFPixelFormatRGBA8888:
317 _OFWriteRGBA8888Pixel(pixels, x, y, width, red, green, blue,
318 alpha);
319 return true;
320 case OFPixelFormatARGB8888:
321 _OFWriteARGB8888Pixel(pixels, x, y, width, red, green, blue,
322 alpha);
323 return true;
324 case OFPixelFormatBGR888:
325 _OFWriteBGR888Pixel(pixels, x, y, width, red, green, blue,
326 alpha);
327 return true;
328 case OFPixelFormatABGR8888:
329 _OFWriteABGR8888Pixel(pixels, x, y, width, red, green, blue,
330 alpha);
331 return true;
332 case OFPixelFormatBGRA8888:
333 _OFWriteBGRA8888Pixel(pixels, x, y, width, red, green, blue,
334 alpha);
335 return true;
336 default:
337 return false;
338 }
339}
340
341static OF_INLINE void
342_OFWriteRGB565Pixel(uint16_t *pixels, size_t x, size_t y, size_t width,
343 float red, float green, float blue, float alpha)
344{
345 uint8_t redInt, greenInt, blueInt;
346
347 if OF_UNLIKELY (red > 1.0f)
348 red = 1.0f;
349 else if OF_UNLIKELY (red < 0.0f)
350 red = 0.0f;
351 if OF_UNLIKELY (green > 1.0f)
352 green = 1.0f;
353 else if OF_UNLIKELY (green < 0.0f)
354 green = 0.0f;
355 if OF_UNLIKELY (blue > 1.0f)
356 blue = 1.0f;
357 else if OF_UNLIKELY (blue < 0.0f)
358 blue = 0.0f;
359 if OF_UNLIKELY (alpha > 1.0f)
360 alpha = 1.0f;
361
362 redInt = roundf(red * 31.0f);
363 greenInt = roundf(green * 63.0f);
364 blueInt = roundf(blue * 31.0f);
365
366 pixels[x + y * width] = redInt << 11 | greenInt << 5 | blueInt;
367}
368
369static OF_INLINE void
370_OFWriteRGBA16161616FPPixel(OFFloat16 *pixels, size_t x, size_t y, size_t width,
371 float red, float green, float blue, float alpha)
372{
373 pixels[(x + y * width) * 4] = OFFloat16FromFloat(red);
374 pixels[(x + y * width) * 4 + 1] = OFFloat16FromFloat(green);
375 pixels[(x + y * width) * 4 + 2] = OFFloat16FromFloat(blue);
376 pixels[(x + y * width) * 4 + 3] = OFFloat16FromFloat(alpha);
377}
378
379static OF_INLINE void
380_OFWriteRGBA32323232FPPixel(float *pixels, size_t x, size_t y, size_t width,
381 float red, float green, float blue, float alpha)
382{
383 pixels[(x + y * width) * 4] = red;
384 pixels[(x + y * width) * 4 + 1] = green;
385 pixels[(x + y * width) * 4 + 2] = blue;
386 pixels[(x + y * width) * 4 + 3] = alpha;
387}
388
389static OF_INLINE bool
390_OFWritePixel(void *pixels, OFPixelFormat format, size_t x, size_t y,
391 size_t width, float red, float green, float blue, float alpha)
392{
393 switch (format) {
394 case OFPixelFormatRGB565:
395 _OFWriteRGB565Pixel(pixels, x, y, width, red, green, blue,
396 alpha);
397 return true;
398 case OFPixelFormatRGBA16161616FP:
399 _OFWriteRGBA16161616FPPixel(pixels, x, y, width, red, green,
400 blue, alpha);
401 return true;
402 case OFPixelFormatRGBA32323232FP:
403 _OFWriteRGBA32323232FPPixel(pixels, x, y, width, red, green,
404 blue, alpha);
405 return true;
406 default:
407 break;
408 }
409
410 if OF_UNLIKELY (red > 1.0f)
411 red = 1.0f;
412 else if OF_UNLIKELY (red < 0.0f)
413 red = 0.0f;
414 if OF_UNLIKELY (green > 1.0f)
415 green = 1.0f;
416 else if OF_UNLIKELY (green < 0.0f)
417 green = 0.0f;
418 if OF_UNLIKELY (blue > 1.0f)
419 blue = 1.0f;
420 else if OF_UNLIKELY (blue < 0.0f)
421 blue = 0.0f;
422 if OF_UNLIKELY (alpha > 1.0f)
423 alpha = 1.0f;
424 else if OF_UNLIKELY (alpha < 0.0f)
425 alpha = 0.0f;
426
427 return _OFWritePixelInt8(pixels, format, x, y, width,
428 roundf(red * 255.0f), roundf(green * 255.0f), roundf(blue * 255.0f),
429 roundf(alpha * 255.0f));
430}
431
432OF_DIRECT_MEMBERS
433@interface OFImage ()
434- (instancetype)of_init OF_METHOD_FAMILY(init);
435@end
436
437OF_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:640
static OF_INLINE OFVector4D OFAddVectors4D(OFVector4D vector1, OFVector4D vector2)
Adds the two specified vectors.
Definition OFObject.h:612
static OF_INLINE OFVector4D OF_CONST_FUNC OFMakeVector4D(float x, float y, float z, float w)
Creates a new OFVector4D.
Definition OFObject.h:572
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:551