The OpenD Programming Language

1 /**
2 Scanline conversion public API. This is used both internally and externally, because converting
3 a whole row of pixels at once is a rather common operations.
4 
5 Copyright: Copyright Guillaume Piolat 2023
6 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 */
8 module gamut.scanline;
9 
10 
11 import core.stdc.string: memcpy;
12 
13 
14 
15 @system:
16 nothrow:
17 @nogc:
18 
19 /// All scanlines conversion functions follow this signature:
20 ///   inScan pointer to first pixel of input scanline
21 ///   outScan pointer to first pixel of output scanline
22 ///
23 /// Type information, user data information, must be given by context.
24 /// Such a function assumes no overlap in memory between input and output scanlines.
25 alias scanlineConversionFunction_t = void function(const(ubyte)* inScan, ubyte* outScan, int width, void* userData);
26 
27 
28 
29 //
30 // FROM xxxx TO rgb8
31 // (used in eg. the TGA encoder)
32 
33 void scanline_convert_l8_to_rgb8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
34 {
35     ubyte* outb = outScan;
36     for (int x = 0; x < width; ++x)
37     {
38         ubyte b = inScan[x];
39         *outb++ = b;
40         *outb++ = b;
41         *outb++ = b;
42     }
43 }
44 
45 void scanline_convert_rgb8_to_rgb8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
46 {
47     memcpy(outScan, inScan, width * 3);
48 }
49 
50 //
51 // FROM xxxx TO rgba8
52 // 
53 
54 void scanline_convert_l8_to_rgba8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
55 {
56     ubyte* outb = outScan;
57     for (int x = 0; x < width; ++x)
58     {
59         ubyte b = inScan[x];
60         *outb++ = b;
61         *outb++ = b;
62         *outb++ = b;
63         *outb++ = 255;
64     }
65 }
66 void scanline_convert_la8_to_rgba8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
67 {
68     ubyte* outb = outScan;
69     for (int x = 0; x < width; ++x)
70     {
71         ubyte b = inScan[x*2];
72         *outb++ = b;
73         *outb++ = b;
74         *outb++ = b;
75         *outb++ = inScan[x*2+1];
76     }
77 }
78 void scanline_convert_rgb8_to_rgba8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
79 {
80     ubyte* outb = outScan;
81     for (int x = 0; x < width; ++x)
82     {
83         *outb++ = inScan[x*3+0];
84         *outb++ = inScan[x*3+1];
85         *outb++ = inScan[x*3+2];
86         *outb++ = 255;
87     }
88 }
89 
90 //
91 // FROM rgba8 TO xxxx
92 //
93 
94 /// Convert a row of pixel from RGBA 8-bit (0 to 255) to L 8-bit (0 to 255).
95 void scanline_convert_rgba8_to_l8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
96 {
97     for (int x = 0; x < width; ++x)
98     {
99         outScan[x] = inScan[4*x];
100     }
101 }
102 
103 /// Convert a row of pixel from RGBA 8-bit (0 to 255) to LA 8-bit (0 to 255).
104 void scanline_convert_rgba8_to_la8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
105 {
106     for (int x = 0; x < width; ++x)
107     {
108         outScan[2*x+0] = inScan[4*x+0];
109         outScan[2*x+1] = inScan[4*x+3];
110     }
111 }
112 
113 /// Convert a row of pixel from RGBA 8-bit (0 to 255) to RGB 8-bit (0 to 255).
114 void scanline_convert_rgba8_to_rgb8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
115 {
116     for (int x = 0; x < width; ++x)
117     {
118         outScan[3*x+0] = inScan[4*x+0];
119         outScan[3*x+1] = inScan[4*x+1];
120         outScan[3*x+2] = inScan[4*x+2];
121     }
122 }
123 
124 /// Convert a row of pixel from RGBA 8-bit (0 to 255) to RGBA 8-bit (0 to 255).
125 void scanline_convert_rgba8_to_rgba8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
126 {
127     memcpy(outScan, inScan, width * 4 * ubyte.sizeof);
128 }
129 
130 //
131 // FROM xxxx TO rgbaf32
132 //
133 
134 void scanline_convert_l8_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
135 {
136     const(ubyte)* s = inScan;
137     float* outp = cast(float*) outScan;
138     for (int x = 0; x < width; ++x)
139     {
140         float b = s[x] / 255.0f;
141         *outp++ = b;
142         *outp++ = b;
143         *outp++ = b;
144         *outp++ = 1.0f;
145     }
146 }
147 
148 void scanline_convert_l16_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
149 {
150     const(ushort)* s = cast(const(ushort)*) inScan;
151     float* outp = cast(float*) outScan;
152     for (int x = 0; x < width; ++x)
153     {
154         float b = s[x] / 65535.0f;
155         *outp++ = b;
156         *outp++ = b;
157         *outp++ = b;
158         *outp++ = 1.0f;
159     }
160 }
161 
162 void scanline_convert_lf32_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
163 {
164     const(float)* s = cast(const(float)*) inScan;
165     float* outp = cast(float*) outScan;
166     for (int x = 0; x < width; ++x)
167     {
168         float b = s[x];
169         *outp++ = b;
170         *outp++ = b;
171         *outp++ = b;
172         *outp++ = 1.0f;
173     }
174 }
175 
176 void scanline_convert_la8_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
177 {
178     const(ubyte)* s = inScan;
179     float* outp = cast(float*) outScan;
180     for (int x = 0; x < width; ++x)
181     {
182         float b = *s++ / 255.0f;
183         float a = *s++ / 255.0f;
184         *outp++ = b;
185         *outp++ = b;
186         *outp++ = b;
187         *outp++ = a;
188     }
189 }
190 
191 void scanline_convert_la16_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
192 {
193     const(ushort)* s = cast(const(ushort)*) inScan;
194     float* outp = cast(float*) outScan;
195     for (int x = 0; x < width; ++x)
196     {
197         float b = *s++ / 65535.0f;
198         float a = *s++ / 65535.0f;
199         *outp++ = b;
200         *outp++ = b;
201         *outp++ = b;
202         *outp++ = a;
203     }
204 }
205 
206 void scanline_convert_laf32_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
207 {
208     const(float)* s = cast(const(float)*) inScan;
209     float* outp = cast(float*) outScan;
210     for (int x = 0; x < width; ++x)
211     {
212         float b = *s++;
213         float a = *s++;
214         *outp++ = b;
215         *outp++ = b;
216         *outp++ = b;
217         *outp++ = a;
218     }
219 }
220 
221 void scanline_convert_rgb8_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
222 {
223     const(ubyte)* s = inScan;
224     float* outp = cast(float*) outScan;
225     for (int x = 0; x < width; ++x)
226     {
227         float r = *s++ / 255.0f;
228         float g = *s++ / 255.0f;
229         float b = *s++ / 255.0f;
230         *outp++ = r;
231         *outp++ = g;
232         *outp++ = b;
233         *outp++ = 1.0f;
234     }
235 }
236 
237 void scanline_convert_rgb16_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
238 {
239     const(ushort)* s = cast(const(ushort)*) inScan;
240     float* outp = cast(float*) outScan;
241     for (int x = 0; x < width; ++x)
242     {
243         float r = *s++ / 65535.0f;
244         float g = *s++ / 65535.0f;
245         float b = *s++ / 65535.0f;
246         *outp++ = r;
247         *outp++ = g;
248         *outp++ = b;
249         *outp++ = 1.0f;
250     }
251 }
252 
253 void scanline_convert_rgbf32_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
254 {
255     const(float)* s = cast(const(float)*) inScan;
256     float* outp = cast(float*) outScan;
257     for (int x = 0; x < width; ++x)
258     {
259         float r = *s++;
260         float g = *s++;
261         float b = *s++;
262         *outp++ = r;
263         *outp++ = g;
264         *outp++ = b;
265         *outp++ = 1.0f;
266     }
267 }
268 
269 void scanline_convert_rgba8_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
270 {
271     const(ubyte)* s = inScan;
272     float* outp = cast(float*) outScan;
273     for (int x = 0; x < width; ++x)
274     {
275         float r = *s++ / 255.0f;
276         float g = *s++ / 255.0f;
277         float b = *s++ / 255.0f;
278         float a = *s++ / 255.0f;
279         *outp++ = r;
280         *outp++ = g;
281         *outp++ = b;
282         *outp++ = a;
283     }
284 }
285 
286 void scanline_convert_rgba16_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
287 {
288     const(ushort)* s = cast(const(ushort)*) inScan;
289     float* outp = cast(float*) outScan;
290     for (int x = 0; x < width; ++x)
291     {
292         float r = *s++ / 65535.0f;
293         float g = *s++ / 65535.0f;
294         float b = *s++ / 65535.0f;
295         float a = *s++ / 65535.0f;
296         *outp++ = r;
297         *outp++ = g;
298         *outp++ = b;
299         *outp++ = a;
300     }
301 }
302 
303 //
304 // FROM rgbaf32 TO xxxx
305 //
306 
307 /// Convert a row of pixel from RGBA 32-bit float (0 to 1.0) float to L 8-bit (0 to 255).
308 void scanline_convert_rgbaf32_to_l8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
309 {
310     const(float)* inp = cast(const(float)*)inScan; 
311     ubyte* s = outScan;
312     for (int x = 0; x < width; ++x)
313     {
314         ubyte b = cast(ubyte)(0.5f + (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) * 255.0f / 3.0f);
315         *s++ = b;
316     }
317 }
318 
319 /// Convert a row of pixel from RGBA 32-bit float (0 to 1.0) float to L 16-bit (0 to 65535).
320 void scanline_convert_rgbaf32_to_l16(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
321 {
322     const(float)* inp = cast(const(float)*)inScan; 
323     ushort* s = cast(ushort*) outScan;
324     for (int x = 0; x < width; ++x)
325     {
326         ushort b = cast(ushort)(0.5f + (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) * 65535.0f / 3.0f);
327         *s++ = b;
328     }
329 }
330 
331 
332 /// Convert a row of pixel from RGBA 32-bit float (0 to 1.0) float to L 32-bit float (0 to 1.0).
333 void scanline_convert_rgbaf32_to_lf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
334 {
335     const(float)* inp = cast(const(float)*)inScan; 
336     float* s = cast(float*) outScan;
337     for (int x = 0; x < width; ++x)
338     {
339         float b = (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) / 3.0f;
340         *s++ = b;
341     }
342 }
343 
344 /// Convert a row of pixel from RGBA 32-bit float (0 to 1.0) to LA 16-bit (0 to 65535).
345 void scanline_convert_rgbaf32_to_la8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
346 {
347     // Issue #21, workaround for DMD optimizer.
348     version(DigitalMars) pragma(inline, false);
349 
350     const(float)* inp = cast(const(float)*)inScan; 
351     ubyte* s = outScan;
352     for (int x = 0; x < width; ++x)
353     {
354         ubyte b = cast(ubyte)(0.5f + (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) * 255.0f / 3.0f);
355         ubyte a = cast(ubyte)(0.5f + inp[4*x+3] * 255.0f);
356         *s++ = b;
357         *s++ = a;
358     }
359 }
360 
361 /// Convert a row of pixel from RGBA 32-bit float (0 to 1.0) to LA 16-bit (0 to 65535).
362 void scanline_convert_rgbaf32_to_la16(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
363 {
364     const(float)* inp = cast(const(float)*) inScan;
365     ushort* s = cast(ushort*) outScan;    
366     for (int x = 0; x < width; ++x)
367     {
368         ushort b = cast(ushort)(0.5f + (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) * 65535.0f / 3.0f);
369         ushort a = cast(ushort)(0.5f + inp[4*x+3] * 65535.0f);
370         *s++ = b;
371         *s++ = a;
372     }
373 }
374 
375 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to LA 32-bit float (0 to 1).
376 void scanline_convert_rgbaf32_to_laf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
377 {
378     const(float)* inp = cast(const(float)*) inScan;
379     float* s = cast(float*) outScan;
380     for (int x = 0; x < width; ++x)
381     {
382         float b = (inp[4*x+0] + inp[4*x+1] + inp[4*x+2]) / 3.0f;
383         float a = inp[4*x+3];
384         *s++ = b;
385         *s++ = a;
386     }
387 }
388 
389 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGB 8-bit (0 to 255).
390 void scanline_convert_rgbaf32_to_rgb8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
391 {
392     const(float)* inp = cast(const(float)*) inScan;
393     ubyte* s = outScan;
394 
395     for (int x = 0; x < width; ++x)
396     {
397         ubyte r = cast(ubyte)(0.5f + inp[4*x+0] * 255.0f);
398         ubyte g = cast(ubyte)(0.5f + inp[4*x+1] * 255.0f);
399         ubyte b = cast(ubyte)(0.5f + inp[4*x+2] * 255.0f);
400         *s++ = r;
401         *s++ = g;
402         *s++ = b;
403     }
404 }
405 
406 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGB 16-bit (0 to 65535).
407 void scanline_convert_rgbaf32_to_rgb16(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
408 {
409     const(float)* inp = cast(const(float)*) inScan;
410     ushort* s = cast(ushort*) outScan;
411     for (int x = 0; x < width; ++x)
412     {
413         ushort r = cast(ushort)(0.5f + inp[4*x+0] * 65535.0f);
414         ushort g = cast(ushort)(0.5f + inp[4*x+1] * 65535.0f);
415         ushort b = cast(ushort)(0.5f + inp[4*x+2] * 65535.0f);
416         *s++ = r;
417         *s++ = g;
418         *s++ = b;
419     }
420 }
421 
422 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGB 16-bit (0 to 65535).
423 void scanline_convert_rgbaf32_to_rgbf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
424 {
425     const(float)* inp = cast(const(float)*) inScan;
426     float* s = cast(float*) outScan;
427     for (int x = 0; x < width; ++x)
428     {
429         *s++ = inp[4*x+0];
430         *s++ = inp[4*x+1];
431         *s++ = inp[4*x+2];
432     }
433 }
434 
435 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGBA 8-bit (0 to 255).
436 void scanline_convert_rgbaf32_to_rgba8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
437 {
438     const(float)* inp = cast(const(float)*) inScan;
439     ubyte* s = outScan;
440     for (int x = 0; x < width; ++x)
441     {
442         ubyte r = cast(ubyte)(0.5f + inp[4*x+0] * 255.0f);
443         ubyte g = cast(ubyte)(0.5f + inp[4*x+1] * 255.0f);
444         ubyte b = cast(ubyte)(0.5f + inp[4*x+2] * 255.0f);
445         ubyte a = cast(ubyte)(0.5f + inp[4*x+3] * 255.0f);
446         *s++ = r;
447         *s++ = g;
448         *s++ = b;
449         *s++ = a;
450     }
451 }
452 
453 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGBA 16-bit (0 to 65535).
454 void scanline_convert_rgbaf32_to_rgba16(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
455 {
456     const(float)* inp = cast(const(float)*) inScan;
457     ushort* s = cast(ushort*)outScan;
458     for (int x = 0; x < width; ++x)
459     {
460         ushort r = cast(ushort)(0.5f + inp[4*x+0] * 65535.0f);
461         ushort g = cast(ushort)(0.5f + inp[4*x+1] * 65535.0f);
462         ushort b = cast(ushort)(0.5f + inp[4*x+2] * 65535.0f);
463         ushort a = cast(ushort)(0.5f + inp[4*x+3] * 65535.0f);
464         *s++ = r;
465         *s++ = g;
466         *s++ = b;
467         *s++ = a;
468     }
469 }
470 
471 /// Convert a row of pixel from RGBA 32-bit float (0 to 1) to RGBA 32-bit float.
472 void scanline_convert_rgbaf32_to_rgbaf32(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
473 {
474     memcpy(outScan, inScan, width * 4 * float.sizeof);
475 }
476 
477 
478 //
479 // BMP ordering functions
480 //
481 
482 /// Convert a row of pixel from RGBA 8-bit (0 to 255) to BGRA 8-bit (0 to 255).
483 void scanline_convert_rgba8_to_bgra8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
484 {
485     for (int x = 0; x < width; ++x)
486     {
487         outScan[4*x+0] = inScan[4*x+2];
488         outScan[4*x+1] = inScan[4*x+1];
489         outScan[4*x+2] = inScan[4*x+0];
490         outScan[4*x+3] = inScan[4*x+3];
491     }
492 }
493 ///ditto
494 alias scanline_convert_bgra8_to_rgba8 = scanline_convert_rgba8_to_bgra8;
495 
496 /// Convert a row of pixel from RGB 8-bit (0 to 255) to BGR 8-bit (0 to 255).
497 void scanline_convert_rgb8_to_bgr8(const(ubyte)* inScan, ubyte* outScan, int width, void* userData = null)
498 {
499     for (int x = 0; x < width; ++x)
500     {
501         outScan[3*x+0] = inScan[3*x+2];
502         outScan[3*x+1] = inScan[3*x+1];
503         outScan[3*x+2] = inScan[3*x+0];
504     }
505 }
506 ///ditto
507 alias scanline_convert_bgr8_to_rgb8 = scanline_convert_rgb8_to_bgr8;