1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30#ifndef APPLESEED_FOUNDATION_IMAGE_PIXEL_H
31#define APPLESEED_FOUNDATION_IMAGE_PIXEL_H
32
33// appleseed.foundation headers.
34#include "foundation/math/scalar.h"
35#include "foundation/platform/types.h"
36#include "foundation/utility/otherwise.h"
37
38// appleseed.main headers.
39#include "main/dllsymbol.h"
40
41// OpenEXR headers.
42#include "foundation/platform/exrheaderguards.h"
43BEGIN_EXR_INCLUDES
44#include "OpenEXR/half.h"
45END_EXR_INCLUDES
46
47// Standard headers.
48#include <cassert>
49#include <cstddef>
50
51namespace foundation
52{
53
54// todo: apply jittering/dithering when converting to lower precision formats.
55// todo: throw exceptions for unsupported / invalid conversions.
56
57
58//
59// Supported pixel formats.
60//
61
62enum PixelFormat
63{
64 PixelFormatUInt8,
65 PixelFormatUInt16,
66 PixelFormatUInt32,
67 PixelFormatHalf,
68 PixelFormatFloat,
69 PixelFormatDouble
70};
71
72// Return a string identifying a pixel format.
73APPLESEED_DLLSYMBOL const char* pixel_format_name(const PixelFormat pixel_format);
74
75
76//
77// Pixel class, providing types and functions related to pixels.
78//
79
80class Pixel
81{
82 public:
83 // Return the size in bytes of a given pixel format.
84 static size_t size(PixelFormat format);
85
86 //
87 // The convert_*() methods below allow conversion of a given range of value
88 // in a given pixel format to another pixel format, with arbitrary striding
89 // in both source and destination. They take advantage of the fact that in
90 // most cases, either the source format or the destination format is known
91 // at compile time.
92
93 //
94 // The non-specialized versions of these methods are intentionally left
95 // unimplemented so that attempting to convert to or from a non-supported
96 // pixel format will result in a compilation error.
97 //
98
99 // Convert from templatized format to variable format.
100 template <typename T>
101 static void convert_to_format(
102 const T* src_begin, // points to the first value to convert
103 const T* src_end, // one beyond the last value to convert
104 const size_t src_stride, // source stride (in words)
105 const PixelFormat dest_format, // destination format
106 void* dest, // destination
107 const size_t dest_stride); // destination stride (in words)
108
109 // Convert from variable format to templatized format.
110 template <typename T>
111 static void convert_from_format(
112 const PixelFormat src_format, // source format
113 const void* src_begin, // points to the first value to convert
114 const void* src_end, // one beyond the last value to convert
115 const size_t src_stride, // source stride (in words)
116 T* dest, // destination
117 const size_t dest_stride); // destination stride (in words)
118
119 // Convert from variable format to variable format.
120 static void convert(
121 const PixelFormat src_format, // source format
122 const void* src_begin, // points to the first value to convert
123 const void* src_end, // one beyond the last value to convert
124 const size_t src_stride, // source stride (in words)
125 const PixelFormat dest_format, // destination format
126 void* dest, // destination
127 const size_t dest_stride); // destination stride (in words)
128
129 //
130 // The convert_and_shuffle() method allow conversion of a given range of pixels,
131 // with a given number of channels in a given pixel format, to a new set of
132 // pixels with potentially a different number of channels, in different order,
133 // in a different pixel format.
134 //
135 // Example: the following converts a set of pixels in RGBA order with one 32-bit
136 // float per channel to a new set of pixels in BGR order (omitting the alpha
137 // channel) with one 8-bit integer per channel:
138 //
139 // const size_t shuffle_table[4] = { 2, 1, 0, Pixel::SkipChannel };
140 //
141 // Pixel::convert_and_shuffle(
142 // PixelFormatFloat, // source format
143 // 4, // source channels
144 // src_begin, // source begin
145 // src_end, // source end
146 // PixelFormatUInt8, // destination format
147 // 3, // destination channels
148 // dest, // destination
149 // shuffle_table); // channel shuffling table
150 //
151
152 static void convert_and_shuffle(
153 const PixelFormat src_format, // source format
154 const size_t src_channels, // number of source channels
155 const void* src_begin, // points to the first value to convert
156 const void* src_end, // one beyond the last value to convert
157 const PixelFormat dest_format, // destination format
158 const size_t dest_channels, // number of destination channels
159 void* dest, // destination
160 const size_t* shuffle_table); // channel shuffling table
161
162 // Use this value in a channel shuffling table to indicate that a channel
163 // must be skipped.
164 static const size_t SkipChannel = ~0;
165
166 // Return the number of destination channels specified by a channel shuffling table.
167 static size_t get_dest_channel_count(
168 const size_t src_channels, // number of source channels
169 const size_t* shuffle_table); // channel shuffling table
170
171};
172
173
174//
175// Pixel class implementation.
176//
177
178inline size_t Pixel::size(PixelFormat format)
179{
180 switch (format)
181 {
182 case PixelFormatUInt8: return 1;
183 case PixelFormatUInt16: return 2;
184 case PixelFormatUInt32: return 4;
185 case PixelFormatHalf: return 2;
186 case PixelFormatFloat: return 4;
187 case PixelFormatDouble: return 8;
188 default:
189 assert(false);
190 return 0;
191 }
192}
193
194template <>
195inline void Pixel::convert_to_format<uint8>(
196 const uint8* src_begin,
197 const uint8* src_end,
198 const size_t src_stride,
199 const PixelFormat dest_format,
200 void* dest,
201 const size_t dest_stride)
202{
203 assert(src_begin);
204 assert(src_end);
205 assert(dest);
206
207 switch (dest_format)
208 {
209 case PixelFormatUInt8: // lossless uint8 -> uint8
210 {
211 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
212 for (const uint8* it = src_begin; it < src_end; it += src_stride)
213 {
214 *typed_dest = *it;
215 typed_dest += dest_stride;
216 }
217 }
218 break;
219
220 case PixelFormatUInt16: // lossless uint8 -> uint16
221 {
222 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
223 for (const uint8* it = src_begin; it < src_end; it += src_stride)
224 {
225 *typed_dest = static_cast<uint16>(*it) * (65535 / 255);
226 typed_dest += dest_stride;
227 }
228 }
229 break;
230
231 case PixelFormatUInt32: // lossless uint8 -> uint32
232 {
233 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
234 for (const uint8* it = src_begin; it < src_end; it += src_stride)
235 {
236 *typed_dest = static_cast<uint32>(*it) * (4294967295UL / 255);
237 typed_dest += dest_stride;
238 }
239 }
240 break;
241
242 case PixelFormatHalf: // lossless uint8 -> half
243 {
244 half* typed_dest = reinterpret_cast<half*>(dest);
245 for (const uint8* it = src_begin; it < src_end; it += src_stride)
246 {
247 *typed_dest = static_cast<half>(static_cast<float>(*it) * (1.0f / 255));
248 typed_dest += dest_stride;
249 }
250 }
251 break;
252
253 case PixelFormatFloat: // lossless uint8 -> float
254 {
255 float* typed_dest = reinterpret_cast<float*>(dest);
256 for (const uint8* it = src_begin; it < src_end; it += src_stride)
257 {
258 *typed_dest = static_cast<float>(*it) * (1.0f / 255);
259 typed_dest += dest_stride;
260 }
261 }
262 break;
263
264 case PixelFormatDouble: // lossless uint8 -> double
265 {
266 double* typed_dest = reinterpret_cast<double*>(dest);
267 for (const uint8* it = src_begin; it < src_end; it += src_stride)
268 {
269 *typed_dest = static_cast<double>(*it) * (1.0 / 255);
270 typed_dest += dest_stride;
271 }
272 }
273 break;
274
275 assert_otherwise;
276 }
277}
278
279template <>
280inline void Pixel::convert_to_format<uint16>(
281 const uint16* src_begin,
282 const uint16* src_end,
283 const size_t src_stride,
284 const PixelFormat dest_format,
285 void* dest,
286 const size_t dest_stride)
287{
288 assert(src_begin);
289 assert(src_end);
290 assert(dest);
291
292 switch (dest_format)
293 {
294 case PixelFormatUInt8: // lossy uint16 -> uint8
295 {
296 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
297 for (const uint16* it = src_begin; it < src_end; it += src_stride)
298 {
299 *typed_dest = static_cast<uint8>(*it >> 8);
300 typed_dest += dest_stride;
301 }
302 }
303 break;
304
305 case PixelFormatUInt16: // lossless uint16 -> uint16
306 {
307 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
308 for (const uint16* it = src_begin; it < src_end; it += src_stride)
309 {
310 *typed_dest = *it;
311 typed_dest += dest_stride;
312 }
313 }
314 break;
315
316 case PixelFormatUInt32: // lossless uint16 -> uint32
317 {
318 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
319 for (const uint16* it = src_begin; it < src_end; it += src_stride)
320 {
321 *typed_dest = static_cast<uint32>(*it) * (4294967295UL / 65535);
322 typed_dest += dest_stride;
323 }
324 }
325 break;
326
327 case PixelFormatHalf: // lossy uint16 -> half
328 {
329 half* typed_dest = reinterpret_cast<half*>(dest);
330 for (const uint16* it = src_begin; it < src_end; it += src_stride)
331 {
332 *typed_dest = static_cast<half>(static_cast<float>(*it) * (1.0f / 65535));
333 typed_dest += dest_stride;
334 }
335 }
336 break;
337
338 case PixelFormatFloat: // lossless uint16 -> float
339 {
340 float* typed_dest = reinterpret_cast<float*>(dest);
341 for (const uint16* it = src_begin; it < src_end; it += src_stride)
342 {
343 *typed_dest = static_cast<float>(*it) * (1.0f / 65535);
344 typed_dest += dest_stride;
345 }
346 }
347 break;
348
349 case PixelFormatDouble: // lossless uint16 -> double
350 {
351 double* typed_dest = reinterpret_cast<double*>(dest);
352 for (const uint16* it = src_begin; it < src_end; it += src_stride)
353 {
354 *typed_dest = static_cast<double>(*it) * (1.0 / 65535);
355 typed_dest += dest_stride;
356 }
357 }
358 break;
359
360 assert_otherwise;
361 }
362}
363
364template <>
365inline void Pixel::convert_to_format<uint32>(
366 const uint32* src_begin,
367 const uint32* src_end,
368 const size_t src_stride,
369 const PixelFormat dest_format,
370 void* dest,
371 const size_t dest_stride)
372{
373 assert(src_begin);
374 assert(src_end);
375 assert(dest);
376
377 switch (dest_format)
378 {
379 case PixelFormatUInt8: // lossy uint32 -> uint8
380 {
381 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
382 for (const uint32* it = src_begin; it < src_end; it += src_stride)
383 {
384 *typed_dest = static_cast<uint8>(*it >> 24);
385 typed_dest += dest_stride;
386 }
387 }
388 break;
389
390 case PixelFormatUInt16: // lossy uint32 -> uint16
391 {
392 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
393 for (const uint32* it = src_begin; it < src_end; it += src_stride)
394 {
395 *typed_dest = static_cast<uint16>(*it >> 16);
396 typed_dest += dest_stride;
397 }
398 }
399 break;
400
401 case PixelFormatUInt32: // lossless uint32 -> uint32
402 {
403 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
404 for (const uint32* it = src_begin; it < src_end; it += src_stride)
405 {
406 *typed_dest = *it;
407 typed_dest += dest_stride;
408 }
409 }
410 break;
411
412 case PixelFormatHalf: // lossy uint32 -> half
413 {
414 half* typed_dest = reinterpret_cast<half*>(dest);
415 for (const uint32* it = src_begin; it < src_end; it += src_stride)
416 {
417 *typed_dest = static_cast<half>(static_cast<float>(*it) * (1.0f / 4294967295UL));
418 typed_dest += dest_stride;
419 }
420 }
421 break;
422
423 case PixelFormatFloat: // lossy uint32 -> float
424 {
425 float* typed_dest = reinterpret_cast<float*>(dest);
426 for (const uint32* it = src_begin; it < src_end; it += src_stride)
427 {
428 *typed_dest = static_cast<float>(*it) * (1.0f / 4294967295UL);
429 typed_dest += dest_stride;
430 }
431 }
432 break;
433
434 case PixelFormatDouble: // lossless uint32 -> double
435 {
436 double* typed_dest = reinterpret_cast<double*>(dest);
437 for (const uint32* it = src_begin; it < src_end; it += src_stride)
438 {
439 *typed_dest = static_cast<double>(*it) * (1.0 / 4294967295UL);
440 typed_dest += dest_stride;
441 }
442 }
443 break;
444
445 assert_otherwise;
446 }
447}
448
449template <>
450inline void Pixel::convert_to_format<half>(
451 const half* src_begin,
452 const half* src_end,
453 const size_t src_stride,
454 const PixelFormat dest_format,
455 void* dest,
456 const size_t dest_stride)
457{
458 assert(src_begin);
459 assert(src_end);
460 assert(dest);
461
462 switch (dest_format)
463 {
464 case PixelFormatUInt8: // lossy half -> uint8
465 {
466 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
467 for (const half* it = src_begin; it < src_end; it += src_stride)
468 {
469 const float val = clamp(*it * 256.0f, 0.0f, 255.0f);
470 *typed_dest = truncate<uint8>(val);
471 typed_dest += dest_stride;
472 }
473 }
474 break;
475
476 case PixelFormatUInt16: // lossy half -> uint16
477 {
478 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
479 for (const half* it = src_begin; it < src_end; it += src_stride)
480 {
481 const float val = clamp(*it * 65536.0f, 0.0f, 65535.0f);
482 *typed_dest = truncate<uint16>(val);
483 typed_dest += dest_stride;
484 }
485 }
486 break;
487
488 case PixelFormatUInt32: // lossy half -> uint32
489 {
490 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
491 for (const half* it = src_begin; it < src_end; it += src_stride)
492 {
493 const double val = clamp(static_cast<double>(*it) * 4294967296.0, 0.0, 4294967295.0);
494 *typed_dest = truncate<uint32>(val);
495 typed_dest += dest_stride;
496 }
497 }
498 break;
499
500 case PixelFormatHalf: // lossless half -> half
501 {
502 half* typed_dest = reinterpret_cast<half*>(dest);
503 for (const half* it = src_begin; it < src_end; it += src_stride)
504 {
505 *typed_dest = *it;
506 typed_dest += dest_stride;
507 }
508 }
509 break;
510
511 case PixelFormatFloat: // lossless half -> float
512 {
513 float* typed_dest = reinterpret_cast<float*>(dest);
514 for (const half* it = src_begin; it < src_end; it += src_stride)
515 {
516 *typed_dest = static_cast<float>(*it);
517 typed_dest += dest_stride;
518 }
519 }
520 break;
521
522 case PixelFormatDouble: // lossless half -> double
523 {
524 double* typed_dest = reinterpret_cast<double*>(dest);
525 for (const half* it = src_begin; it < src_end; it += src_stride)
526 {
527 *typed_dest = static_cast<double>(*it);
528 typed_dest += dest_stride;
529 }
530 }
531 break;
532
533 assert_otherwise;
534 }
535}
536
537template <>
538inline void Pixel::convert_to_format<float>(
539 const float* src_begin,
540 const float* src_end,
541 const size_t src_stride,
542 const PixelFormat dest_format,
543 void* dest,
544 const size_t dest_stride)
545{
546 assert(src_begin);
547 assert(src_end);
548 assert(dest);
549
550 switch (dest_format)
551 {
552 case PixelFormatUInt8: // lossy float -> uint8
553 {
554 // todo: optimize this case using SSE?
555 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
556 for (const float* it = src_begin; it < src_end; it += src_stride)
557 {
558 const float val = clamp(*it * 256.0f, 0.0f, 255.0f);
559 *typed_dest = truncate<uint8>(val);
560 typed_dest += dest_stride;
561 }
562 }
563 break;
564
565 case PixelFormatUInt16: // lossy float -> uint16
566 {
567 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
568 for (const float* it = src_begin; it < src_end; it += src_stride)
569 {
570 const float val = clamp(*it * 65536.0f, 0.0f, 65535.0f);
571 *typed_dest = truncate<uint16>(val);
572 typed_dest += dest_stride;
573 }
574 }
575 break;
576
577 case PixelFormatUInt32: // lossy float -> uint32
578 {
579 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
580 for (const float* it = src_begin; it < src_end; it += src_stride)
581 {
582 const double val = clamp(static_cast<double>(*it) * 4294967296.0, 0.0, 4294967295.0);
583 *typed_dest = truncate<uint32>(val);
584 typed_dest += dest_stride;
585 }
586 }
587 break;
588
589 case PixelFormatHalf: // lossy float -> half
590 {
591 half* typed_dest = reinterpret_cast<half*>(dest);
592 for (const float* it = src_begin; it < src_end; it += src_stride)
593 {
594 *typed_dest = static_cast<half>(*it);
595 typed_dest += dest_stride;
596 }
597 }
598 break;
599
600 case PixelFormatFloat: // lossless float -> float
601 {
602 float* typed_dest = reinterpret_cast<float*>(dest);
603 for (const float* it = src_begin; it < src_end; it += src_stride)
604 {
605 *typed_dest = *it;
606 typed_dest += dest_stride;
607 }
608 }
609 break;
610
611 case PixelFormatDouble: // lossless float -> double
612 {
613 double* typed_dest = reinterpret_cast<double*>(dest);
614 for (const float* it = src_begin; it < src_end; it += src_stride)
615 {
616 *typed_dest = static_cast<double>(*it);
617 typed_dest += dest_stride;
618 }
619 }
620 break;
621
622 assert_otherwise;
623 }
624}
625
626template <>
627inline void Pixel::convert_to_format<double>(
628 const double* src_begin,
629 const double* src_end,
630 const size_t src_stride,
631 const PixelFormat dest_format,
632 void* dest,
633 const size_t dest_stride)
634{
635 assert(src_begin);
636 assert(src_end);
637 assert(dest);
638
639 switch (dest_format)
640 {
641 case PixelFormatUInt8: // lossy double -> uint8
642 {
643 uint8* typed_dest = reinterpret_cast<uint8*>(dest);
644 for (const double* it = src_begin; it < src_end; it += src_stride)
645 {
646 const double val = clamp(*it * 256.0, 0.0, 255.0);
647 *typed_dest = truncate<uint8>(val);
648 typed_dest += dest_stride;
649 }
650 }
651 break;
652
653 case PixelFormatUInt16: // lossy double -> uint16
654 {
655 uint16* typed_dest = reinterpret_cast<uint16*>(dest);
656 for (const double* it = src_begin; it < src_end; it += src_stride)
657 {
658 const double val = clamp(*it * 65536.0, 0.0, 65535.0);
659 *typed_dest = truncate<uint16>(val);
660 typed_dest += dest_stride;
661 }
662 }
663 break;
664
665 case PixelFormatUInt32: // lossy double -> uint32
666 {
667 uint32* typed_dest = reinterpret_cast<uint32*>(dest);
668 for (const double* it = src_begin; it < src_end; it += src_stride)
669 {
670 const double val = clamp(*it * 4294967296.0, 0.0, 4294967295.0);
671 *typed_dest = truncate<uint32>(val);
672 typed_dest += dest_stride;
673 }
674 }
675 break;
676
677 case PixelFormatHalf: // lossy double -> half
678 {
679 half* typed_dest = reinterpret_cast<half*>(dest);
680 for (const double* it = src_begin; it < src_end; it += src_stride)
681 {
682 *typed_dest = static_cast<half>(static_cast<float>(*it));
683 typed_dest += dest_stride;
684 }
685 }
686 break;
687
688 case PixelFormatFloat: // lossy double -> float
689 {
690 float* typed_dest = reinterpret_cast<float*>(dest);
691 for (const double* it = src_begin; it < src_end; it += src_stride)
692 {
693 *typed_dest = static_cast<float>(*it);
694 typed_dest += dest_stride;
695 }
696 }
697 break;
698
699 case PixelFormatDouble: // lossless double -> double
700 {
701 double* typed_dest = reinterpret_cast<double*>(dest);
702 for (const double* it = src_begin; it < src_end; it += src_stride)
703 {
704 *typed_dest = *it;
705 typed_dest += dest_stride;
706 }
707 }
708 break;
709
710 assert_otherwise;
711 }
712}
713
714template <>
715inline void Pixel::convert_from_format<uint8>(
716 const PixelFormat src_format,
717 const void* src_begin,
718 const void* src_end,
719 const size_t src_stride,
720 uint8* dest,
721 const size_t dest_stride)
722{
723 assert(src_begin);
724 assert(src_end);
725 assert(dest);
726
727 switch (src_format)
728 {
729 case PixelFormatUInt8: // lossless uint8 -> uint8
730 {
731 const uint8* it = reinterpret_cast<const uint8*>(src_begin);
732 for (; it < src_end; it += src_stride)
733 {
734 *dest = *it;
735 dest += dest_stride;
736 }
737 }
738 break;
739
740 case PixelFormatUInt16: // lossy uint16 -> uint8
741 {
742 const uint16* it = reinterpret_cast<const uint16*>(src_begin);
743 for (; it < reinterpret_cast<const uint16*>(src_end); it += src_stride)
744 {
745 *dest = static_cast<uint8>(*it >> 8);
746 dest += dest_stride;
747 }
748 }
749 break;
750
751 case PixelFormatUInt32: // lossy uint32 -> uint8
752 {
753 const uint32* it = reinterpret_cast<const uint32*>(src_begin);
754 for (; it < reinterpret_cast<const uint32*>(src_end); it += src_stride)
755 {
756 *dest = static_cast<uint8>(*it >> 24);
757 dest += dest_stride;
758 }
759 }
760 break;
761
762 case PixelFormatHalf: // lossy half -> uint8
763 {
764 const half* it = reinterpret_cast<const half*>(src_begin);
765 for (; it < reinterpret_cast<const half*>(src_end); it += src_stride)
766 {
767 const half val = static_cast<half>(clamp(*it * 256.0f, 0.0f, 255.0f));
768 *dest = truncate<uint8>(val);
769 dest += dest_stride;
770 }
771 }
772 break;
773
774 case PixelFormatFloat: // lossy float -> uint8
775 {
776 const float* it = reinterpret_cast<const float*>(src_begin);
777 for (; it < reinterpret_cast<const float*>(src_end); it += src_stride)
778 {
779 const float val = clamp(*it * 256.0f, 0.0f, 255.0f);
780 *dest = truncate<uint8>(val);
781 dest += dest_stride;
782 }
783 }
784 break;
785
786 case PixelFormatDouble: // lossy double -> uint8
787 {
788 const double* it = reinterpret_cast<const double*>(src_begin);
789 for (; it < reinterpret_cast<const double*>(src_end); it += src_stride)
790 {
791 const double val = clamp(*it * 256.0, 0.0, 255.0);
792 *dest = truncate<uint8>(val);
793 dest += dest_stride;
794 }
795 }
796 break;
797
798 assert_otherwise;
799 }
800}
801
802template <>
803inline void Pixel::convert_from_format<uint16>(
804 const PixelFormat src_format,
805 const void* src_begin,
806 const void* src_end,
807 const size_t src_stride,
808 uint16* dest,
809 const size_t dest_stride)
810{
811 assert(src_begin);
812 assert(src_end);
813 assert(dest);
814
815 switch (src_format)
816 {
817 case PixelFormatUInt8: // lossless uint8 -> uint16
818 {
819 const uint8* it = reinterpret_cast<const uint8*>(src_begin);
820 for (; it < reinterpret_cast<const uint8*>(src_end); it += src_stride)
821 {
822 *dest = static_cast<uint16>(*it) * (65535 / 255);
823 dest += dest_stride;
824 }
825 }
826 break;
827
828 case PixelFormatUInt16: // lossless uint16 -> uint16
829 {
830 const uint16* it = reinterpret_cast<const uint16*>(src_begin);
831 for (; it < reinterpret_cast<const uint16*>(src_end); it += src_stride)
832 {
833 *dest = *it;
834 dest += dest_stride;
835 }
836 }
837 break;
838
839 case PixelFormatUInt32: // lossy uint32 -> uint16
840 {
841 const uint32* it = reinterpret_cast<const uint32*>(src_begin);
842 for (; it < reinterpret_cast<const uint32*>(src_end); it += src_stride)
843 {
844 *dest = static_cast<uint16>(*it >> 16);
845 dest += dest_stride;
846 }
847 }
848 break;
849
850 case PixelFormatHalf: // lossy half -> uint16
851 {
852 const half* it = reinterpret_cast<const half*>(src_begin);
853 for (; it < reinterpret_cast<const half*>(src_end); it += src_stride)
854 {
855 const half val = static_cast<half>(clamp(*it * 65536.0f, 0.0f, 65535.0f));
856 *dest = truncate<uint16>(val);
857 dest += dest_stride;
858 }
859 }
860 break;
861
862 case PixelFormatFloat: // lossy float -> uint16
863 {
864 const float* it = reinterpret_cast<const float*>(src_begin);
865 for (; it < reinterpret_cast<const float*>(src_end); it += src_stride)
866 {
867 const float val = clamp(*it * 65536.0f, 0.0f, 65535.0f);
868 *dest = truncate<uint16>(val);
869 dest += dest_stride;
870 }
871 }
872 break;
873
874 case PixelFormatDouble: // lossy double -> uint16
875 {
876 const double* it = reinterpret_cast<const double*>(src_begin);
877 for (; it < reinterpret_cast<const double*>(src_end); it += src_stride)
878 {
879 const double val = clamp(*it * 65536.0, 0.0, 65535.0);
880 *dest = truncate<uint16>(val);
881 dest += dest_stride;
882 }
883 }
884 break;
885
886 assert_otherwise;
887 }
888}
889
890template <>
891inline void Pixel::convert_from_format<uint32>(
892 const PixelFormat src_format,
893 const void* src_begin,
894 const void* src_end,
895 const size_t src_stride,
896 uint32* dest,
897 const size_t dest_stride)
898{
899 assert(src_begin);
900 assert(src_end);
901 assert(dest);
902
903 switch (src_format)
904 {
905 case PixelFormatUInt8: // lossless uint8 -> uint32
906 {
907 const uint8* it = reinterpret_cast<const uint8*>(src_begin);
908 for (; it < reinterpret_cast<const uint8*>(src_end); it += src_stride)
909 {
910 *dest = static_cast<uint32>(*it) * (4294967295UL / 255);
911 dest += dest_stride;
912 }
913 }
914 break;
915
916 case PixelFormatUInt16: // lossless uint16 -> uint32
917 {
918 const uint16* it = reinterpret_cast<const uint16*>(src_begin);
919 for (; it < reinterpret_cast<const uint16*>(src_end); it += src_stride)
920 {
921 *dest = static_cast<uint32>(*it) * (4294967295UL / 65535);
922 dest += dest_stride;
923 }
924 }
925 break;
926
927 case PixelFormatUInt32: // lossless uint32 -> uint32
928 {
929 const uint32* it = reinterpret_cast<const uint32*>(src_begin);
930 for (; it < reinterpret_cast<const uint32*>(src_end); it += src_stride)
931 {
932 *dest = *it;
933 dest += dest_stride;
934 }
935 }
936 break;
937
938 case PixelFormatHalf: // lossy half -> uint32
939 {
940 const half* it = reinterpret_cast<const half*>(src_begin);
941 for (; it < reinterpret_cast<const half*>(src_end); it += src_stride)
942 {
943 const double val = clamp(static_cast<double>(*it) * 4294967296.0, 0.0, 4294967295.0);
944 *dest = truncate<uint32>(val);
945 dest += dest_stride;
946 }
947 }
948 break;
949
950 case PixelFormatFloat: // lossy float -> uint32
951 {
952 const float* it = reinterpret_cast<const float*>(src_begin);
953 for (; it < reinterpret_cast<const float*>(src_end); it += src_stride)
954 {
955 const double val = clamp(static_cast<double>(*it) * 4294967296.0, 0.0, 4294967295.0);
956 *dest = truncate<uint32>(val);
957 dest += dest_stride;
958 }
959 }
960 break;
961
962 case PixelFormatDouble: // lossy double -> uint32
963 {
964 const double* it = reinterpret_cast<const double*>(src_begin);
965 for (; it < reinterpret_cast<const double*>(src_end); it += src_stride)
966 {
967 const double val = clamp(*it * 4294967296.0, 0.0, 4294967295.0);
968 *dest = truncate<uint32>(val);
969 dest += dest_stride;
970 }
971 }
972 break;
973
974 assert_otherwise;
975 }
976}
977
978template <>
979inline void Pixel::convert_from_format<float>(
980 const PixelFormat src_format,
981 const void* src_begin,
982 const void* src_end,
983 const size_t src_stride,
984 float* dest,
985 const size_t dest_stride)
986{
987 assert(src_begin);
988 assert(src_end);
989 assert(dest);
990
991 switch (src_format)
992 {
993 case PixelFormatUInt8: // lossless uint8 -> float
994 {
995 const uint8* it = reinterpret_cast<const uint8*>(src_begin);
996 for (; it < reinterpret_cast<const uint8*>(src_end); it += src_stride)
997 {
998 *dest = static_cast<float>(*it) * (1.0f / 255);
999 dest += dest_stride;
1000 }
1001 }
1002 break;
1003
1004 case PixelFormatUInt16: // lossless uint16 -> float
1005 {
1006 const uint16* it = reinterpret_cast<const uint16*>(src_begin);
1007 for (; it < reinterpret_cast<const uint16*>(src_end); it += src_stride)
1008 {
1009 *dest = static_cast<float>(*it) * (1.0f / 65535);
1010 dest += dest_stride;
1011 }
1012 }
1013 break;
1014
1015 case PixelFormatUInt32: // lossy uint32 -> float
1016 {
1017 const uint32* it = reinterpret_cast<const uint32*>(src_begin);
1018 for (; it < reinterpret_cast<const uint32*>(src_end); it += src_stride)
1019 {
1020 *dest = static_cast<float>(*it) * (1.0f / 4294967295UL);
1021 dest += dest_stride;
1022 }
1023 }
1024 break;
1025
1026 case PixelFormatHalf: // lossless half -> float
1027 {
1028 const half* it = reinterpret_cast<const half*>(src_begin);
1029 for (; it < reinterpret_cast<const half*>(src_end); it += src_stride)
1030 {
1031 *dest = static_cast<float>(*it);
1032 dest += dest_stride;
1033 }
1034 }
1035 break;
1036
1037 case PixelFormatFloat: // lossless float -> float
1038 {
1039 const float* it = reinterpret_cast<const float*>(src_begin);
1040 for (; it < reinterpret_cast<const float*>(src_end); it += src_stride)
1041 {
1042 *dest = *it;
1043 dest += dest_stride;
1044 }
1045 }
1046 break;
1047
1048 case PixelFormatDouble: // lossy double -> float
1049 {
1050 const double* it = reinterpret_cast<const double*>(src_begin);
1051 for (; it < reinterpret_cast<const double*>(src_end); it += src_stride)
1052 {
1053 *dest = static_cast<float>(*it);
1054 dest += dest_stride;
1055 }
1056 }
1057 break;
1058
1059 assert_otherwise;
1060 }
1061}
1062
1063template <>
1064inline void Pixel::convert_from_format<double>(
1065 const PixelFormat src_format,
1066 const void* src_begin,
1067 const void* src_end,
1068 const size_t src_stride,
1069 double* dest,
1070 const size_t dest_stride)
1071{
1072 assert(src_begin);
1073 assert(src_end);
1074 assert(dest);
1075
1076 switch (src_format)
1077 {
1078 case PixelFormatUInt8: // lossless uint8 -> double
1079 {
1080 const uint8* it = reinterpret_cast<const uint8*>(src_begin);
1081 for (; it < reinterpret_cast<const uint8*>(src_end); it += src_stride)
1082 {
1083 *dest = static_cast<double>(*it) * (1.0 / 255);
1084 dest += dest_stride;
1085 }
1086 }
1087 break;
1088
1089 case PixelFormatUInt16: // lossless uint16 -> double
1090 {
1091 const uint16* it = reinterpret_cast<const uint16*>(src_begin);
1092 for (; it < reinterpret_cast<const uint16*>(src_end); it += src_stride)
1093 {
1094 *dest = static_cast<double>(*it) * (1.0 / 65535);
1095 dest += dest_stride;
1096 }
1097 }
1098 break;
1099
1100 case PixelFormatUInt32: // lossless uint32 -> double
1101 {
1102 const uint32* it = reinterpret_cast<const uint32*>(src_begin);
1103 for (; it < reinterpret_cast<const uint32*>(src_end); it += src_stride)
1104 {
1105 *dest = static_cast<double>(*it) * (1.0 / 4294967295UL);
1106 dest += dest_stride;
1107 }
1108 }
1109 break;
1110
1111 case PixelFormatHalf: // lossless half -> double
1112 {
1113 const half* it = reinterpret_cast<const half*>(src_begin);
1114 for (; it < reinterpret_cast<const half*>(src_end); it += src_stride)
1115 {
1116 *dest = static_cast<double>(*it);
1117 dest += dest_stride;
1118 }
1119 }
1120 break;
1121
1122 case PixelFormatFloat: // lossless float -> double
1123 {
1124 const float* it = reinterpret_cast<const float*>(src_begin);
1125 for (; it < reinterpret_cast<const float*>(src_end); it += src_stride)
1126 {
1127 *dest = static_cast<double>(*it);
1128 dest += dest_stride;
1129 }
1130 }
1131 break;
1132
1133 case PixelFormatDouble: // lossless double -> double
1134 {
1135 const double* it = reinterpret_cast<const double*>(src_begin);
1136 for (; it < reinterpret_cast<const double*>(src_end); it += src_stride)
1137 {
1138 *dest = *it;
1139 dest += dest_stride;
1140 }
1141 }
1142 break;
1143
1144 assert_otherwise;
1145 }
1146}
1147
1148inline void Pixel::convert(
1149 const PixelFormat src_format,
1150 const void* src_begin,
1151 const void* src_end,
1152 const size_t src_stride,
1153 const PixelFormat dest_format,
1154 void* dest,
1155 const size_t dest_stride)
1156{
1157 assert(src_begin);
1158 assert(src_end);
1159 assert(dest);
1160
1161 switch (src_format)
1162 {
1163 case PixelFormatUInt8: // uint8 -> destination format
1164 convert_to_format<uint8>(
1165 reinterpret_cast<const uint8*>(src_begin),
1166 reinterpret_cast<const uint8*>(src_end),
1167 src_stride,
1168 dest_format,
1169 dest,
1170 dest_stride);
1171 break;
1172
1173 case PixelFormatUInt16: // uint16 -> destination format
1174 convert_to_format<uint16>(
1175 reinterpret_cast<const uint16*>(src_begin),
1176 reinterpret_cast<const uint16*>(src_end),
1177 src_stride,
1178 dest_format,
1179 dest,
1180 dest_stride);
1181 break;
1182
1183 case PixelFormatUInt32: // uint32 -> destination format
1184 convert_to_format<uint32>(
1185 reinterpret_cast<const uint32*>(src_begin),
1186 reinterpret_cast<const uint32*>(src_end),
1187 src_stride,
1188 dest_format,
1189 dest,
1190 dest_stride);
1191 break;
1192
1193 case PixelFormatHalf: // half -> destination format
1194 convert_to_format<half>(
1195 reinterpret_cast<const half*>(src_begin),
1196 reinterpret_cast<const half*>(src_end),
1197 src_stride,
1198 dest_format,
1199 dest,
1200 dest_stride);
1201 break;
1202
1203 case PixelFormatFloat: // float -> destination format
1204 convert_to_format<float>(
1205 reinterpret_cast<const float*>(src_begin),
1206 reinterpret_cast<const float*>(src_end),
1207 src_stride,
1208 dest_format,
1209 dest,
1210 dest_stride);
1211 break;
1212
1213 case PixelFormatDouble: // double -> destination format
1214 convert_to_format<double>(
1215 reinterpret_cast<const double*>(src_begin),
1216 reinterpret_cast<const double*>(src_end),
1217 src_stride,
1218 dest_format,
1219 dest,
1220 dest_stride);
1221 break;
1222
1223 assert_otherwise;
1224 }
1225}
1226
1227} // namespace foundation
1228
1229#endif // !APPLESEED_FOUNDATION_IMAGE_PIXEL_H
1230