Skip to content

Commit

Permalink
Robust image I/O (#6765)
Browse files Browse the repository at this point in the history
- Use file signatures (beginning bytes) instead of filename extension (png/jpg) to select decoder. jpg files with png extension and vice versa are read correctly.
- Catch libjpeg errors and report as normal Open3D exceptions. Change Open3D warnings to errors (exceptions) on jpeg I/O error.
- Simplify demo_scene example
- Clear image on read error
- Fix for github release macOS bug.
  • Loading branch information
ssheorey committed May 12, 2024
1 parent 008cfb7 commit bf48b45
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 271 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ jobs:
tar_file="open3d-${GITHUB_SHA}-docs.tar.gz"
rm -rf ${tar_file}
# Docs in docs/_out/html
tar -C docs/_out -czf ${tar_file} html
tar -C docs/_out -cvzf ${tar_file} html
echo "Waiting for other release assets..."
this_sha=$(echo ${GITHUB_SHA} | cut -c 1-6)
Expand All @@ -110,7 +110,6 @@ jobs:
echo "\nAll assets ready. Removing release assets except from last 3 commits: ${last_shas[@]}"
release_assets=($(gh release view main-devel --json assets --jq '.assets[] | .name'))
last_shas=($(git log --pretty=format:%h --abbrev-commit -n 3))
echo "Waiting for all assets to be ready..."
for relass in "${release_assets[@]}"; do
found=false
for last_sha in "${last_shas[@]}"; do
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,6 @@ jobs:
path: open3d-*-app-macosx-10_15-universal2.zip
if-no-files-found: error

- name: Checkout source code
uses: actions/checkout@v4
- name: Update viewer devel release
if: ${{ github.ref == 'refs/heads/main' }}
env:
Expand Down
56 changes: 30 additions & 26 deletions cpp/open3d/io/ImageIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@

#include "open3d/io/ImageIO.h"

#include <array>
#include <fstream>
#include <unordered_map>

#include "open3d/utility/FileSystem.h"
#include "open3d/utility/Logging.h"

namespace open3d {
namespace io {

namespace {
using namespace io;

static const std::unordered_map<
std::string,
std::function<bool(const std::string &, geometry::Image &)>>
file_extension_to_image_read_function{
{"png", ReadImageFromPNG},
{"jpg", ReadImageFromJPG},
{"jpeg", ReadImageFromJPG},
};
using signature_decoder_t =
std::pair<std::string,
std::function<bool(const std::string &, geometry::Image &)>>;
static const std::array<signature_decoder_t, 2> signature_decoder_list{
{{"\x89\x50\x4e\x47\xd\xa\x1a\xa", ReadImageFromPNG},
{"\xFF\xD8\xFF", ReadImageFromJPG}}};
static constexpr uint8_t MAX_SIGNATURE_LEN = 8;

static const std::unordered_map<
std::string,
Expand All @@ -34,11 +35,8 @@ static const std::unordered_map<
{"jpg", WriteImageToJPG},
{"jpeg", WriteImageToJPG},
};

} // unnamed namespace

namespace io {

std::shared_ptr<geometry::Image> CreateImageFromFile(
const std::string &filename) {
auto image = std::make_shared<geometry::Image>();
Expand All @@ -47,21 +45,27 @@ std::shared_ptr<geometry::Image> CreateImageFromFile(
}

bool ReadImage(const std::string &filename, geometry::Image &image) {
std::string filename_ext =
utility::filesystem::GetFileExtensionInLowerCase(filename);
if (filename_ext.empty()) {
utility::LogWarning(
"Read geometry::Image failed: missing file extension.");
return false;
}
auto map_itr = file_extension_to_image_read_function.find(filename_ext);
if (map_itr == file_extension_to_image_read_function.end()) {
utility::LogWarning(
"Read geometry::Image failed: file extension {} unknown",
filename_ext);
return false;
std::string signature_buffer(MAX_SIGNATURE_LEN, 0);
std::ifstream file(filename, std::ios::binary);
file.read(&signature_buffer[0], MAX_SIGNATURE_LEN);
std::string err_msg;
if (!file) {
err_msg = "Read geometry::Image failed for file {}. I/O error.";
} else {
file.close();
for (const auto &signature_decoder : signature_decoder_list) {
if (signature_buffer.compare(0, signature_decoder.first.size(),
signature_decoder.first) == 0) {
return signature_decoder.second(filename, image);
}
}
err_msg =
"Read geometry::Image failed for file {}. Unknown file "
"signature, only PNG and JPG are supported.";
}
return map_itr->second(filename, image);
image.Clear();
utility::LogWarning(err_msg.c_str(), filename);
return false;
}

bool WriteImage(const std::string &filename,
Expand Down
9 changes: 8 additions & 1 deletion cpp/open3d/io/ImageIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,18 @@ bool WriteImageToJPG(const std::string &filename,
const geometry::Image &image,
int quality = kOpen3DImageIODefaultQuality);

/// The general entrance for reading an Image from memory
/// Read a PNG image from memory.
/// \param image_data_ptr the pointer to image data in memory.
/// \param image_data_size the size of image data in memory.
/// \return return true if the read function is successful, false otherwise.
bool ReadPNGFromMemory(const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image);

/// Read a JPG image from memory.
/// \param image_data_ptr the pointer to image data in memory.
/// \param image_data_size the size of image data in memory.
/// \return return true if the read function is successful, false otherwise.
bool ReadJPGFromMemory(const unsigned char *image_data_ptr,
size_t image_data_size,
geometry::Image &image);
Expand Down
Loading

0 comments on commit bf48b45

Please sign in to comment.