diff --git a/.github/workflows/ubuntu-cmake-contrib.yml b/.github/workflows/ubuntu-cmake-contrib.yml index 771eacf..9480e93 100644 --- a/.github/workflows/ubuntu-cmake-contrib.yml +++ b/.github/workflows/ubuntu-cmake-contrib.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04] - contrib: [jsonnet, libtiff, pffft] + contrib: [jsonnet, libraw, libtiff, pffft] ignore-errors: [true] include: - compiler: clang diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 609e606..11a3687 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -18,15 +18,16 @@ set(SAPI_CONTRIB_SANDBOXES hunspell jsonnet libidn2 + libraw libtiff libxls libzip pffft turbojpeg uriparser + woff2 zopfli zstd - woff2 ) foreach(_contrib IN LISTS SAPI_CONTRIB_SANDBOXES) diff --git a/contrib/libraw/CMakeLists.txt b/contrib/libraw/CMakeLists.txt new file mode 100644 index 0000000..63aae6e --- /dev/null +++ b/contrib/libraw/CMakeLists.txt @@ -0,0 +1,79 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.13..3.22) + +project(sapi_libraw CXX) +include(CTest) +include(GoogleTest) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if (NOT TARGET sapi::sapi) + set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree") + add_subdirectory("${SAPI_ROOT}" + "${CMAKE_BINARY_DIR}/sandboxed-api-build" + EXCLUDE_FROM_ALL) +endif() + +FetchContent_Declare( libraw + GIT_REPOSITORY https://github.com/LibRaw/LibRaw.git + GIT_TAG a077aac05190530f22af4254a1e31745876d007f # 2022-06-03 +) +FetchContent_MakeAvailable(libraw) + +set(LIBRAW_PATH "${libraw_SOURCE_DIR}" CACHE STRING "" FORCE) +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +FetchContent_Declare(libraw_cmake + GIT_REPOSITORY https://github.com/LibRaw/LibRaw-cmake.git + GIT_TAG b82a1b0101b1e7264eb3113f1e6c1ba2372ebb7f # 2021-11-18 +) +FetchContent_MakeAvailable(libraw_cmake) + +configure_file(raw.gen.h.in raw.gen.h) + +add_sapi_library(sapi_libraw + FUNCTIONS libraw_init + libraw_open_file + libraw_unpack + libraw_close + + libraw_subtract_black + + libraw_cameraList + libraw_cameraCount + + libraw_COLOR + libraw_get_raw_height + libraw_get_raw_width + + INPUTS "${CMAKE_BINARY_DIR}/raw.gen.h" + + LIBRARY raw + LIBRARY_NAME LibRaw + NAMESPACE "" +) +add_library(sapi_contrib::libraw ALIAS sapi_libraw) +target_include_directories(sapi_libraw INTERFACE + "${PROJECT_BINARY_DIR}" +) + +if(SAPI_BUILD_EXAMPLES) + add_subdirectory(example) +endif() + +if(BUILD_TESTING AND SAPI_BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/contrib/libraw/example/CMakeLists.txt b/contrib/libraw/example/CMakeLists.txt new file mode 100644 index 0000000..eed3c6c --- /dev/null +++ b/contrib/libraw/example/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable(sapi_minilibraw + main.cc + ../utils/utils_libraw.cc +) +target_link_libraries(sapi_minilibraw + PRIVATE sapi_libraw + sapi::logging + sapi::sapi +) diff --git a/contrib/libraw/example/main.cc b/contrib/libraw/example/main.cc new file mode 100644 index 0000000..23962e8 --- /dev/null +++ b/contrib/libraw/example/main.cc @@ -0,0 +1,163 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may !use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "absl/status/statusor.h" +#include "contrib/libraw/sandboxed.h" +#include "contrib/libraw/utils/utils_libraw.h" +#include "sandboxed_api/util/logging.h" + +void PrintUsage(const char* name) { + std::cout << "Dump (small) selecton of RAW file as tab-separated text file\n" + << "Usage: " << name + << " inputfile COL ROW [CHANNEL] [width] [height]\n" + " COL - start column\n" + " ROW - start row\n" + " CHANNEL - raw channel to dump, default is 0 (red for rggb)\n" + " width - area width to dump, default is 16\n" + " height - area height to dump, default is 4\n"; +} + +uint16_t SubtractBlack(uint16_t val, unsigned int bl) { + return val > bl ? val - bl : 0; +} + +int main(int argc, char* argv[]) { + sapi::InitLogging(argv[0]); + if (argc < 4) { + PrintUsage(argv[0]); + return EXIT_FAILURE; + } + + int colstart = atoi(argv[2]); // NOLINT(runtime/deprecated_fn) + int rowstart = atoi(argv[3]); // NOLINT(runtime/deprecated_fn) + int channel = 0; + if (argc > 4) { + channel = atoi(argv[4]); // NOLINT(runtime/deprecated_fn) + } + int width = 16; + if (argc > 5) { + width = atoi(argv[5]); // NOLINT(runtime/deprecated_fn) + } + int height = 4; + if (argc > 6) { + height = atoi(argv[6]); // NOLINT(runtime/deprecated_fn) + } + if (width < 1 || height < 1) { + PrintUsage(argv[0]); + return EXIT_FAILURE; + } + + sapi::v::ConstCStr file_name(argv[1]); + absl::Status status; + LibRawSapiSandbox sandbox(file_name.GetData()); + + status = sandbox.Init(); + if (!status.ok()) { + std::cerr << "Unable to start sandbox: " << status.message() << "\n"; + return EXIT_FAILURE; + } + + LibRaw lr(&sandbox, argv[1]); + if (!lr.CheckIsInit().ok()) { + std::cerr << "Unable init LibRaw: " << lr.CheckIsInit().message(); + return EXIT_FAILURE; + } + + status = lr.OpenFile(); + if (!status.ok()) { + std::cerr << "Unable to open file " << argv[1] << ": " << status.message(); + return EXIT_FAILURE; + } + + if ((lr.GetColorCount() == 1 && channel > 0) || (channel > 3)) { + std::cerr << "Incorrect CHANNEL specified: " << channel << "\n"; + return EXIT_FAILURE; + } + + status = lr.Unpack(); + if (!status.ok()) { + std::cerr << "Unable to unpack file " << argv[1] << status.message(); + return EXIT_FAILURE; + } + + status = lr.SubtractBlack(); + if (!status.ok()) { + std::cerr << "Unable to subtract black level: " << status.message(); + // ok, but different output + } + + absl::StatusOr> rawdata = lr.RawData(); + if (!rawdata.ok()) { + std::cerr << "Unable to get raw data: " << rawdata.status().message(); + return EXIT_FAILURE; + } + + absl::StatusOr raw_height = lr.GetRawHeight(); + absl::StatusOr raw_width = lr.GetRawWidth(); + if (!raw_height.ok() || !raw_width.ok()) { + std::cerr << "Unable to get raw image sizes"; + return EXIT_FAILURE; + } + + // header + std::cout << argv[1] << "\t" << colstart << "-" << rowstart << "-" << width + << "x" << height << "\t" + << "channel: " << channel << "\n"; + std::cout << std::setw(6) << "R\\C"; + for (int col = colstart; col < colstart + width && col < *raw_width; col++) { + std::cout << std::setw(6) << col; + } + std::cout << "\n"; + + // dump raw to output + for (int row = rowstart; row < rowstart + height && row < *raw_height; + ++row) { + int rcolors[48]; + if (lr.GetColorCount() > 1) { + absl::StatusOr color; + for (int c = 0; c < 48; c++) { + color = lr.COLOR(row, c); + if (color.ok()) rcolors[c] = *color; + } + } else { + memset(rcolors, 0, sizeof(rcolors)); + } + std::cout << std::setw(6) << row; + + for (int col = colstart; col < colstart + width && col < *raw_width; + ++col) { + int idx = row * lr.GetImgData().sizes.raw_pitch / 2 + col; + + if (rcolors[col % 48] == channel) { + absl::StatusOr cblack = lr.GetCBlack(channel); + if (!cblack.ok()) { + std::cerr << "Unable to get cblack for channel " << channel << ": " + << cblack.status().message(); + return EXIT_FAILURE; + } + std::cout << std::setw(6) << SubtractBlack((*rawdata).at(idx), *cblack); + } else { + std::cout << " -"; + } + } + std::cout << "\n"; + } + + return EXIT_SUCCESS; +} diff --git a/contrib/libraw/files/img.raw b/contrib/libraw/files/img.raw new file mode 100644 index 0000000..0a05358 Binary files /dev/null and b/contrib/libraw/files/img.raw differ diff --git a/contrib/libraw/raw.gen.h.in b/contrib/libraw/raw.gen.h.in new file mode 100644 index 0000000..eeddbe6 --- /dev/null +++ b/contrib/libraw/raw.gen.h.in @@ -0,0 +1,25 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CONTRIB_LIBRAW_RAW_GEN_H +#define CONTRIB_LIBRAW_RAW_GEN_H + +#include + +#define __time_t uint64_t +#define time_t uint64_t + +#include "${libraw_SOURCE_DIR}/libraw/libraw.h" + +#endif // CONTRIB_LIBRAW_RAW_GEN_H diff --git a/contrib/libraw/sandboxed.h b/contrib/libraw/sandboxed.h new file mode 100644 index 0000000..808b185 --- /dev/null +++ b/contrib/libraw/sandboxed.h @@ -0,0 +1,49 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CONTRIB_LIBRAW_SANDBOXED_H_ +#define CONTRIB_LIBRAW_SANDBOXED_H_ + +#include +#include + +#include +#include + +#include "sapi_libraw.sapi.h" // NOLINT(build/include) + +class LibRawSapiSandbox : public LibRawSandbox { + public: + explicit LibRawSapiSandbox(std::string file_name) + : file_name_(std::move(file_name)) {} + + private: + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + return sandbox2::PolicyBuilder() + .AllowDynamicStartup() + .AllowOpen() + .AllowRead() + .AllowWrite() + .AllowSystemMalloc() + .AllowExit() + .AllowSyscalls({__NR_recvmsg}) + .AddFile(file_name_, /*is_ro=*/true) + .BuildOrDie(); + } + + std::string file_name_; +}; + +#endif // CONTRIB_LIBRAW_SANDBOXED_H_ diff --git a/contrib/libraw/test/CMakeLists.txt b/contrib/libraw/test/CMakeLists.txt new file mode 100644 index 0000000..d9bb61f --- /dev/null +++ b/contrib/libraw/test/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable(sapi_libraw_test + libraw_test.cc + ../utils/utils_libraw.cc +) +target_link_libraries(sapi_libraw_test PRIVATE + sapi_libraw + sapi::test_main + sapi::temp_file +) + +gtest_discover_tests(sapi_libraw_test PROPERTIES + ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/files" +) diff --git a/contrib/libraw/test/libraw_test.cc b/contrib/libraw/test/libraw_test.cc new file mode 100644 index 0000000..ab202d6 --- /dev/null +++ b/contrib/libraw/test/libraw_test.cc @@ -0,0 +1,187 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "contrib/libraw/sandboxed.h" +#include "contrib/libraw/utils/utils_libraw.h" +#include "sandboxed_api/util/path.h" +#include "sandboxed_api/util/status_matchers.h" +#include "sandboxed_api/util/temp_file.h" + +namespace { + +using ::sapi::IsOk; + +const struct TestVariant { + std::string filename; + ushort raw_height; + ushort raw_width; + int COLOR[4][4]; + int color_values[4][4]; +} kTestData[] = {{.filename = "img.raw", + .raw_height = 540, + .raw_width = 960, + .COLOR = + { + {0, 1, 0, 1}, + {3, 2, 3, 2}, + {0, 1, 0, 1}, + {3, 2, 3, 2}, + }, + .color_values = { + {548, 1285, 554, 1253}, + {1290, 789, 1279, 788}, + {551, 1303, 549, 1253}, + {1265, 809, 1257, 779}, + }}}; + +class LibRawBase : public testing::Test { + protected: + std::string GetTestFilePath(const std::string& filename) { + return sapi::file::JoinPath(test_dir_, filename); + } + + void SetUp() override; + + const char* test_dir_; +}; + +class LibRawTestFiles : public LibRawBase, + public testing::WithParamInterface {}; + +void LibRawBase::SetUp() { + test_dir_ = getenv("TEST_FILES_DIR"); + ASSERT_NE(test_dir_, nullptr); +} + +TEST_P(LibRawTestFiles, TestOpen) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + SAPI_ASSERT_OK(lr.OpenFile()); +} + +TEST_P(LibRawTestFiles, TestUnpack) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + SAPI_ASSERT_OK(lr.OpenFile()); + SAPI_ASSERT_OK(lr.Unpack()); +} + +TEST_P(LibRawTestFiles, TestSize) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + SAPI_ASSERT_OK(lr.OpenFile()); + SAPI_ASSERT_OK(lr.Unpack()); + + SAPI_ASSERT_OK_AND_ASSIGN(ushort raw_height, lr.GetRawHeight()); + SAPI_ASSERT_OK_AND_ASSIGN(ushort raw_width, lr.GetRawWidth()); + + EXPECT_EQ(raw_height, tv.raw_height); + EXPECT_EQ(raw_width, tv.raw_width); +} + +TEST_P(LibRawTestFiles, TestCameraList) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + + SAPI_ASSERT_OK_AND_ASSIGN(std::vector camera_list, lr.GetCameraList()); + + EXPECT_FALSE(camera_list.empty()); +} + +TEST_P(LibRawTestFiles, TestColor) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + SAPI_ASSERT_OK(lr.OpenFile()); + SAPI_ASSERT_OK(lr.Unpack()); + + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + SAPI_ASSERT_OK_AND_ASSIGN(int color, lr.COLOR(row, col)); + EXPECT_EQ(color, tv.COLOR[row][col]); + } + } +} + +TEST_P(LibRawTestFiles, TestSubtractBlack) { + const TestVariant& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibRawSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + LibRaw lr(&sandbox, test_file_path); + SAPI_ASSERT_OK(lr.CheckIsInit()); + SAPI_ASSERT_OK(lr.OpenFile()); + SAPI_ASSERT_OK(lr.Unpack()); + SAPI_ASSERT_OK(lr.SubtractBlack()); + + libraw_data_t lr_data = lr.GetImgData(); + + SAPI_ASSERT_OK_AND_ASSIGN(std::vector rawdata, lr.RawData()); + + for (int row = 0; row < 4; ++row) { + unsigned rcolors[48]; + if (lr_data.idata.colors > 1) { + for (int c = 0; c < 48; c++) { + SAPI_ASSERT_OK_AND_ASSIGN(int color, lr.COLOR(row, c)); + rcolors[c] = color; + } + } else { + memset(rcolors, 0, sizeof(rcolors)); + } + + for (int col = 0; col < 4; col++) { + int raw_idx = row * lr.GetImgData().sizes.raw_pitch / 2 + col; + unsigned black_level = lr_data.color.cblack[rcolors[col % 48]]; + int color_value = + rawdata[raw_idx] > black_level ? rawdata[raw_idx] - black_level : 0; + EXPECT_EQ(color_value, tv.color_values[row][col]); + } + } +} + +INSTANTIATE_TEST_SUITE_P(LibRawBase, LibRawTestFiles, + testing::ValuesIn(kTestData)); + +} // namespace diff --git a/contrib/libraw/utils/utils_libraw.cc b/contrib/libraw/utils/utils_libraw.cc new file mode 100644 index 0000000..756b376 --- /dev/null +++ b/contrib/libraw/utils/utils_libraw.cc @@ -0,0 +1,159 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "contrib/libraw/utils/utils_libraw.h" + +#include "contrib/libraw/sandboxed.h" + +absl::Status LibRaw::InitLibRaw() { + SAPI_ASSIGN_OR_RETURN(libraw_data_t * lr_data, api_.libraw_init(0)); + + sapi_libraw_data_t_.SetRemote(lr_data); + SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&sapi_libraw_data_t_)); + + return absl::OkStatus(); +} + +LibRaw::~LibRaw() { + if (sapi_libraw_data_t_.GetRemote() != nullptr) { + api_.libraw_close(sapi_libraw_data_t_.PtrNone()).IgnoreError(); + } +} + +absl::Status LibRaw::CheckIsInit() { return init_status_; } + +bool LibRaw::IsInit() { return CheckIsInit().ok(); } + +libraw_data_t LibRaw::GetImgData() { return sapi_libraw_data_t_.data(); } + +absl::Status LibRaw::OpenFile() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + sapi::v::CStr file_name(file_name_.c_str()); + + SAPI_ASSIGN_OR_RETURN(int error_code, + api_.libraw_open_file(sapi_libraw_data_t_.PtrAfter(), + file_name.PtrBefore())); + + if (error_code != LIBRAW_SUCCESS) { + return absl::UnavailableError( + absl::string_view(std::to_string(error_code))); + } + + return absl::OkStatus(); +} + +absl::Status LibRaw::Unpack() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + SAPI_ASSIGN_OR_RETURN(int error_code, + api_.libraw_unpack(sapi_libraw_data_t_.PtrAfter())); + if (error_code != LIBRAW_SUCCESS) { + return absl::UnavailableError( + absl::string_view(std::to_string(error_code))); + } + + return absl::OkStatus(); +} + +absl::Status LibRaw::SubtractBlack() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + return api_.libraw_subtract_black(sapi_libraw_data_t_.PtrAfter()); +} + +absl::StatusOr> LibRaw::GetCameraList() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + int size; + SAPI_ASSIGN_OR_RETURN(size, api_.libraw_cameraCount()); + + std::vector buf(size); + sapi::v::Array camera_list(buf.data(), buf.size()); + + char** sapi_camera_list; + SAPI_ASSIGN_OR_RETURN(sapi_camera_list, api_.libraw_cameraList()); + + camera_list.SetRemote(sapi_camera_list); + SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&camera_list)); + + return buf; +} + +absl::StatusOr LibRaw::COLOR(int row, int col) { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + int color; + SAPI_ASSIGN_OR_RETURN( + color, api_.libraw_COLOR(sapi_libraw_data_t_.PtrNone(), row, col)); + + return color; +} + +absl::StatusOr LibRaw::GetRawHeight() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + ushort height; + SAPI_ASSIGN_OR_RETURN( + height, api_.libraw_get_raw_height(sapi_libraw_data_t_.PtrNone())); + + return height; +} + +absl::StatusOr LibRaw::GetRawWidth() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + ushort width; + SAPI_ASSIGN_OR_RETURN( + width, api_.libraw_get_raw_width(sapi_libraw_data_t_.PtrNone())); + + return width; +} + +absl::StatusOr LibRaw::GetCBlack(int channel) { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + if (channel < 0 || >= LIBRAW_CBLACK_SIZE) { + return absl::OutOfRangeError(absl::string_view( + std::to_string(channel) + " is out of range for array with size " + + std::to_string(LIBRAW_CBLACK_SIZE))); + } + + return GetImgData().color.cblack[channel]; + + ushort width; + SAPI_ASSIGN_OR_RETURN( + width, api_.libraw_get_raw_width(sapi_libraw_data_t_.PtrNone())); + + return width; +} + +int LibRaw::GetColorCount() { return GetImgData().idata.colors; } + +absl::StatusOr> LibRaw::RawData() { + SAPI_RETURN_IF_ERROR(CheckIsInit()); + + int raw_height; + int raw_width; + SAPI_ASSIGN_OR_RETURN(raw_height, GetRawHeight()); + SAPI_ASSIGN_OR_RETURN(raw_width, GetRawWidth()); + int size = raw_height * raw_width; + std::vector buf(size); + sapi::v::Array rawdata(buf.data(), buf.size()); + + rawdata.SetRemote(sapi_libraw_data_t_.data().rawdata.raw_image); + SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&rawdata)); + + return buf; +} diff --git a/contrib/libraw/utils/utils_libraw.h b/contrib/libraw/utils/utils_libraw.h new file mode 100644 index 0000000..021ca22 --- /dev/null +++ b/contrib/libraw/utils/utils_libraw.h @@ -0,0 +1,80 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CONTRIB_LIBRAW_UTILS_UTILS_LIBRAW_H_ +#define CONTRIB_LIBRAW_UTILS_UTILS_LIBRAW_H_ + +#include + +#include "contrib/libraw/sandboxed.h" + +enum LibRaw_errors { + LIBRAW_SUCCESS = 0, + LIBRAW_UNSPECIFIED_ERROR = -1, + LIBRAW_FILE_UNSUPPORTED = -2, + LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE = -3, + LIBRAW_OUT_OF_ORDER_CALL = -4, + LIBRAW_NO_THUMBNAIL = -5, + LIBRAW_UNSUPPORTED_THUMBNAIL = -6, + LIBRAW_INPUT_CLOSED = -7, + LIBRAW_NOT_IMPLEMENTED = -8, + LIBRAW_UNSUFFICIENT_MEMORY = -100007, + LIBRAW_DATA_ERROR = -100008, + LIBRAW_IO_ERROR = -100009, + LIBRAW_CANCELLED_BY_CALLBACK = -100010, + LIBRAW_BAD_CROP = -100011, + LIBRAW_TOO_BIG = -100012, + LIBRAW_MEMPOOL_OVERFLOW = -100013 +}; + +class LibRaw { + public: + LibRaw(LibRawSapiSandbox* sandbox, const std::string& file_name) + : sandbox_(CHECK_NOTNULL(sandbox)), + api_(sandbox_), + file_name_(file_name) { + init_status_ = InitLibRaw(); + } + + ~LibRaw(); + + absl::Status CheckIsInit(); + bool IsInit(); + + libraw_data_t GetImgData(); + absl::StatusOr> RawData(); + + absl::Status OpenFile(); + absl::Status Unpack(); + absl::Status SubtractBlack(); + absl::StatusOr> GetCameraList(); + absl::StatusOr COLOR(int row, int col); + absl::StatusOr GetRawHeight(); + absl::StatusOr GetRawWidth(); + absl::StatusOr GetCBlack(int channel); + int GetColorCount(); + + private: + absl::Status InitLibRaw(); + + LibRawSapiSandbox* sandbox_; + LibRawApi api_; + absl::Status init_status_; + + std::string file_name_; + + sapi::v::Struct sapi_libraw_data_t_; +}; + +#endif // CONTRIB_LIBRAW_UTILS_UTILS_LIBRAW_H_