Lagrange
Loading...
Searching...
No Matches
io_helpers.h
1/*
2 * Copyright 2025 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/Logger.h>
15#include <lagrange/image/Array3D.h>
16#include <lagrange/image/View3D.h>
17#include <lagrange/image_io/exr.h>
18#include <lagrange/image_io/load_image.h>
19#include <lagrange/scene/Scene.h>
20#include <lagrange/utils/assert.h>
21
22#include <algorithm>
23
24using Array3Df = lagrange::image::experimental::Array3D<float>;
25using View3Df = lagrange::image::experimental::View3D<float>;
26using ConstView3Df = lagrange::image::experimental::View3D<const float>;
27
28template <size_t NumChannels, typename Precision>
29Array3Df convert_from(const lagrange::image_io::LoadImageResult& img)
30{
31 size_t width = img.width;
32 size_t height = img.height;
33 Array3Df result =
35
36 using SourcePixel =
37 std::conditional_t<NumChannels == 1, Precision, Eigen::Vector<Precision, NumChannels>>;
38 using TargetPixel =
39 std::conditional_t<NumChannels == 1, float, Eigen::Vector<float, NumChannels>>;
40
42 img.storage,
43 img.storage->get_full_size()(0) / sizeof(SourcePixel),
44 img.storage->get_full_size()(1),
45 sizeof(SourcePixel),
46 1,
47 0,
48 0);
49
50 lagrange::image::ImageView<TargetPixel> target_view(width, height, 1);
51 la_runtime_assert(target_view.convert_from(source_view, 1));
52
53 for (size_t x = 0; x < width; ++x) {
54 for (size_t y = 0; y < height; ++y) {
55 auto pixel = target_view(x, y);
56 if constexpr (NumChannels == 1) {
57 result(x, y, 0) = pixel;
58 } else {
59 for (size_t c = 0; c < NumChannels; ++c) {
60 result(x, y, c) = pixel[c];
61 }
62 }
63 }
64 }
65
66 return result;
67}
68
69template <size_t NumChannels>
70Array3Df convert_from(const lagrange::image_io::LoadImageResult& img)
71{
72 switch (img.precision) {
73 case lagrange::image::ImagePrecision::float32: return convert_from<NumChannels, float>(img);
74 case lagrange::image::ImagePrecision::float64: return convert_from<NumChannels, double>(img);
75 case lagrange::image::ImagePrecision::uint8:
76 return convert_from<NumChannels, unsigned char>(img);
77 case lagrange::image::ImagePrecision::int8: return convert_from<NumChannels, char>(img);
78 case lagrange::image::ImagePrecision::uint32: return convert_from<NumChannels, uint32_t>(img);
79 case lagrange::image::ImagePrecision::int32: return convert_from<NumChannels, int32_t>(img);
80 case lagrange::image::ImagePrecision::float16:
81 return convert_from<NumChannels, Eigen::half>(img);
82 default: throw std::runtime_error("Unsupported precision");
83 }
84}
85
86inline Array3Df load_image(const lagrange::fs::path& path)
87{
88 auto img = lagrange::image_io::load_image(path);
89
90 switch (img.channel) {
91 case lagrange::image::ImageChannel::one: return convert_from<1>(img);
92 case lagrange::image::ImageChannel::three: return convert_from<3>(img);
93 case lagrange::image::ImageChannel::four: return convert_from<4>(img);
94 default: throw std::runtime_error("Unsupported number of channels");
95 }
96}
97
98inline void save_image(lagrange::fs::path path, View3Df image)
99{
100 if (path.extension() != ".exr") {
101 lagrange::logger().warn("Only .exr output files are supported. Saving as .exr.");
102 path = path.replace_extension(".exr");
103 }
104
105 using namespace lagrange::image;
106
107 const size_t width = image.extent(0);
108 const size_t height = image.extent(1);
109 const size_t num_channels = image.extent(2);
110
111 std::vector<float> scanline(width * height * num_channels);
112 for (size_t x = 0; x < width; ++x) {
113 for (size_t y = 0; y < height; ++y) {
114 for (size_t c = 0; c < num_channels; ++c) {
115 scanline[y * width * num_channels + x * num_channels + c] = image(x, y, c);
116 }
117 }
118 }
119
120 lagrange::image_io::save_image_exr(
121 path,
122 static_cast<const void*>(scanline.data()),
123 static_cast<int>(width),
124 static_cast<int>(height),
125 static_cast<int>(num_channels),
126 lagrange::image_io::TinyexrPixelType::float32);
127}
128
129inline void sort_paths(std::vector<lagrange::fs::path>& paths)
130{
131 auto original = paths;
132 std::sort(paths.begin(), paths.end());
133 if (!std::is_sorted(original.begin(), original.end())) {
134 lagrange::logger().warn("Input filenames were not sorted. Using sorted order.");
135 }
136}
Definition ImageView.h:56
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
Array3D< T > create_image(size_t width, size_t height, size_t num_channels)
Create an image with the given dimensions and number of channels.
Definition Array3D.h:46
Basic image data structure.
Definition load_image.h:28