ObjFW
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 
23 OF_ASSUME_NONNULL_BEGIN
24 
25 static 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 
37 static 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 
49 static 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 
61 static 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 
73 static 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 
85 static 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 
97 static 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 
131 static 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 
143 static 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 
153 static 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 
163 static 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 
198 static 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 
257 static 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 
268 static 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 
279 static 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 
287 static 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 
295 static 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 
303 static 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 
311 static 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 
345 static 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 
374 static 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 
384 static 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 
394 static 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 
437 OF_DIRECT_MEMBERS
438 @interface OFImage ()
439 - (instancetype)of_init OF_METHOD_FAMILY(init);
440 @end
441 
442 OF_ASSUME_NONNULL_END
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
instancetype init()
Initializes an already allocated object.
Definition: OFObject.m:674
__extension__ typedef _Float16 OFFloat16
A type for 16 bit floating point numbers.
Definition: macros.h:961
void(* OFColorSpaceTransferFunction)(OFVector4D *vectors, size_t count)
A transfer function for a color space.
Definition: OFColorSpace.h:42
A vector in 4D space.
Definition: OFObject.h:557
A class representing an image.
Definition: OFImage.h:115