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>;
26
27template <size_t NumChannels, typename Precision>
28Array3Df convert_from(const lagrange::image_io::LoadImageResult& img)
29{
30 size_t width = img.width;
31 size_t height = img.height;
32 Array3Df result =
34
35 using SourcePixel =
36 std::conditional_t<NumChannels == 1, Precision, Eigen::Vector<Precision, NumChannels>>;
37 using TargetPixel =
38 std::conditional_t<NumChannels == 1, float, Eigen::Vector<float, NumChannels>>;
39
41 img.storage,
42 img.storage->get_full_size()(0) / sizeof(SourcePixel),
43 img.storage->get_full_size()(1),
44 sizeof(SourcePixel),
45 1,
46 0,
47 0);
48
49 lagrange::image::ImageView<TargetPixel> target_view(width, height, 1);
50 la_runtime_assert(target_view.convert_from(source_view, 1));
51
52 for (size_t x = 0; x < width; ++x) {
53 for (size_t y = 0; y < height; ++y) {
54 auto pixel = target_view(x, y);
55 if constexpr (NumChannels == 1) {
56 result(x, y, 0) = pixel;
57 } else {
58 for (size_t c = 0; c < NumChannels; ++c) {
59 result(x, y, c) = pixel[c];
60 }
61 }
62 }
63 }
64
65 return result;
66}
67
68template <size_t NumChannels>
69Array3Df convert_from(const lagrange::image_io::LoadImageResult& img)
70{
71 switch (img.precision) {
72 case lagrange::image::ImagePrecision::float32: return convert_from<NumChannels, float>(img);
73 case lagrange::image::ImagePrecision::float64: return convert_from<NumChannels, double>(img);
74 case lagrange::image::ImagePrecision::uint8:
75 return convert_from<NumChannels, unsigned char>(img);
76 case lagrange::image::ImagePrecision::int8: return convert_from<NumChannels, char>(img);
77 case lagrange::image::ImagePrecision::uint32: return convert_from<NumChannels, uint32_t>(img);
78 case lagrange::image::ImagePrecision::int32: return convert_from<NumChannels, int32_t>(img);
79 case lagrange::image::ImagePrecision::float16:
80 return convert_from<NumChannels, Eigen::half>(img);
81 default: throw std::runtime_error("Unsupported precision");
82 }
83}
84
85inline Array3Df load_image(const lagrange::fs::path& path)
86{
87 auto img = lagrange::image_io::load_image(path);
88
89 switch (img.channel) {
90 case lagrange::image::ImageChannel::one: return convert_from<1>(img);
91 case lagrange::image::ImageChannel::three: return convert_from<3>(img);
92 case lagrange::image::ImageChannel::four: return convert_from<4>(img);
93 default: throw std::runtime_error("Unsupported number of channels");
94 }
95}
96
97inline void save_image(lagrange::fs::path path, View3Df image)
98{
99 if (path.extension() != ".exr") {
100 lagrange::logger().warn("Only .exr output files are supported. Saving as .exr.");
101 path = path.replace_extension(".exr");
102 }
103
104 using namespace lagrange::image;
105
106 const size_t width = image.extent(0);
107 const size_t height = image.extent(1);
108 const size_t num_channels = image.extent(2);
109
110 std::vector<float> scanline(width * height * num_channels);
111 for (size_t x = 0; x < width; ++x) {
112 for (size_t y = 0; y < height; ++y) {
113 for (size_t c = 0; c < num_channels; ++c) {
114 scanline[y * width * num_channels + x * num_channels + c] = image(x, y, c);
115 }
116 }
117 }
118
119 lagrange::image_io::save_image_exr(
120 path,
121 static_cast<const void*>(scanline.data()),
122 static_cast<int>(width),
123 static_cast<int>(height),
124 static_cast<int>(num_channels),
125 lagrange::image_io::TinyexrPixelType::float32);
126}
127
128inline void sort_paths(std::vector<lagrange::fs::path>& paths)
129{
130 auto original = paths;
131 std::sort(paths.begin(), paths.end());
132 if (!std::is_sorted(original.begin(), original.end())) {
133 lagrange::logger().warn("Input filenames were not sorted. Using sorted order.");
134 }
135}
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:22