diff --git a/satdump_cfg.json b/satdump_cfg.json index 1796d1065..60dab6b9d 100644 --- a/satdump_cfg.json +++ b/satdump_cfg.json @@ -167,6 +167,10 @@ [ "qoi", "Quite OK Image (*.qoi)" + ], + [ + "h5", + "HDF5 (*.h5)" ] ], "description": "Image format for raw image products\n\n - png: PNG Image (recommended)\n - j2k: JPEG 2000\n - jpg: JPEG Image (not recommended; may result\n in low-quality composites and projections)\n - pbm : Really fast, but will result is very big files\n - qoi: A very fast image format with compression.\n 8-bit only!" diff --git a/src-core/CMakeLists.txt b/src-core/CMakeLists.txt index d828b3f25..e8a28e9d2 100644 --- a/src-core/CMakeLists.txt +++ b/src-core/CMakeLists.txt @@ -275,6 +275,12 @@ else() target_compile_definitions(satdump_core PUBLIC VOLK_NO_volk_32fc_x2_add_32fc="1") endif() endif() + + find_package(PkgConfig) + pkg_check_modules(HDF5 hdf5) + target_include_directories(satdump_core PUBLIC ${HDF5_INCLUDE_DIRS}) + target_link_directories(satdump_core PUBLIC ${HDF5_LIBRARY_DIRS}) + target_link_libraries(satdump_core PUBLIC hdf5 hdf5_hl hdf5_cpp) endif() if(APPLE) diff --git a/src-core/image/io.cpp b/src-core/image/io.cpp index 2c2f15f71..1806598c8 100644 --- a/src-core/image/io.cpp +++ b/src-core/image/io.cpp @@ -28,6 +28,8 @@ namespace satdump load_tiff(img, file); else if (signature[0] == 'q' && signature[1] == 'o' && signature[2] == 'i' && signature[3] == 'f') load_qoi(img, file); + else if (signature[1] == 'H' && signature[2] == 'D' && signature[3] == 'F') + load_hdf(img, file); } void load_img(Image &img, uint8_t *buffer, int size) @@ -55,6 +57,8 @@ namespace satdump save_tiff(img, file); else if (file.find(".qoi") != std::string::npos) save_qoi(img, file); + else if (file.find(".h5") != std::string::npos) + save_hdf(img, file); } void save_img_safe(Image &img, std::string file, bool fast) @@ -79,7 +83,7 @@ namespace satdump // Do nothing if there's already an extension if (file->find(".png") != std::string::npos || file->find(".jpeg") != std::string::npos || file->find(".jpg") != std::string::npos || file->find(".j2k") != std::string::npos || file->find(".pgm") != std::string::npos || file->find(".pbm") != std::string::npos || file->find(".ppm") != std::string::npos || file->find(".tif") != std::string::npos || - file->find(".tiff") != std::string::npos || file->find(".gtif") != std::string::npos || file->find(".qoi") != std::string::npos) + file->find(".tiff") != std::string::npos || file->find(".gtif") != std::string::npos || file->find(".qoi") != std::string::npos || file->find(".h5") != std::string::npos) return true; // Otherwise, load the user setting diff --git a/src-core/image/io.h b/src-core/image/io.h index 895f39d88..6da2f9012 100644 --- a/src-core/image/io.h +++ b/src-core/image/io.h @@ -90,6 +90,7 @@ namespace satdump * @param file filepath to save the image to with extension */ void save_pbm(Image &img, std::string file); + void save_hdf(Image &img, std::string file); /** * @brief Load an image from a PBM (and similar) file. @@ -98,6 +99,7 @@ namespace satdump * @param file filepath to load the image from */ void load_pbm(Image &img, std::string file); + void load_hdf(Image &img, std::string file); /** * @brief Save an image to a JPEG2000 file. diff --git a/src-core/image/io/hdfio.cpp b/src-core/image/io/hdfio.cpp new file mode 100644 index 000000000..2063e9f7f --- /dev/null +++ b/src-core/image/io/hdfio.cpp @@ -0,0 +1,85 @@ +#include "../io.h" +#include "H5Zpublic.h" +#include "core/exception.h" +#include "image/image.h" +#include "logger.h" +#include +#include +#include +#include + +#include + +namespace satdump +{ + namespace image + { + void save_hdf(Image &img, std::string file) + { + auto d_depth = img.depth(); + auto d_channels = img.channels(); + auto d_height = img.height(); + auto d_width = img.width(); + + if (img.size() == 0 || d_height == 0) // Make sure we aren't just gonna crash + { + logger->trace("Tried to save empty HDF!"); + return; + } + + H5::H5File hfile(file, H5F_ACC_TRUNC); + + hsize_t fdim[] = {d_height, d_width, (size_t)d_channels}; // dim sizes of ds (on disk) + H5::DataSpace fspace(3, fdim); + + H5::DSetCreatPropList plist; + plist.setDeflate(6); + /// plist.setFillValue(H5::PredType::NATIVE_INT, &fillvalue); + + hsize_t fdims[] = {d_height / 4, d_width / 4, 1}; + plist.setChunk(3, fdims); + + if (d_depth > 8) + { + H5::DataSet dataset(hfile.createDataSet("image", H5::PredType::NATIVE_UINT16, fspace, plist)); + dataset.write(img.raw_data(), H5::PredType::NATIVE_UINT16); + } + else + { + H5::DataSet dataset(hfile.createDataSet("image", H5::PredType::NATIVE_UINT8, fspace, plist)); + dataset.write(img.raw_data(), H5::PredType::NATIVE_UINT8); + } + } + + void load_hdf(Image &img, std::string file) + { + if (!std::filesystem::exists(file)) + return; + + H5::H5File hfile(file, H5F_ACC_RDONLY); + + H5::DataSet s = hfile.openDataSet("image"); + + if (s.getSpace().getSimpleExtentNdims() != 3) + { + logger->error("Rank is not 3!"); + return; + } + + hsize_t image_dims[3]; + s.getSpace().getSimpleExtentDims(image_dims); + logger->critical("%d %d %d", image_dims[1], image_dims[0], image_dims[2]); + + if (s.getDataType() == H5::PredType::NATIVE_UINT16) + { + img = image::Image(16, image_dims[1], image_dims[0], image_dims[2]); + s.read(img.raw_data(), H5::PredType::NATIVE_UINT16); + } + else + { + img = image::Image(8, image_dims[1], image_dims[0], image_dims[2]); + s.read(img.raw_data(), H5::PredType::NATIVE_UINT8); + } + } + } // namespace image +} // namespace satdump \ No newline at end of file