Commit 3754a516 for libheif
commit 3754a516d48ec1783dbdf37372a93fdc15133ff4
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Wed Mar 4 14:15:52 2026 +0100
add raw decoder files
diff --git a/heifio/decoder_raw.cc b/heifio/decoder_raw.cc
new file mode 100644
index 00000000..de97c144
--- /dev/null
+++ b/heifio/decoder_raw.cc
@@ -0,0 +1,219 @@
+/*
+ libheif example application "heif".
+
+ MIT License
+
+ Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#include "decoder_raw.h"
+#include <libheif/heif.h>
+#include <libheif/heif_uncompressed.h>
+#include <bit>
+#include <cstdio>
+#include <cstring>
+#include <vector>
+#include <memory>
+
+static struct heif_error heif_error_ok = {heif_error_Ok, heif_suberror_Unspecified, "Success"};
+
+
+bool parse_raw_pixel_type(const std::string& type_string,
+ heif_channel_datatype* out_datatype,
+ int* out_bit_depth)
+{
+ if (type_string == "uint8") {
+ *out_datatype = heif_channel_datatype_unsigned_integer;
+ *out_bit_depth = 8;
+ }
+ else if (type_string == "sint8") {
+ *out_datatype = heif_channel_datatype_signed_integer;
+ *out_bit_depth = 8;
+ }
+ else if (type_string == "uint16") {
+ *out_datatype = heif_channel_datatype_unsigned_integer;
+ *out_bit_depth = 16;
+ }
+ else if (type_string == "sint16") {
+ *out_datatype = heif_channel_datatype_signed_integer;
+ *out_bit_depth = 16;
+ }
+ else if (type_string == "uint32") {
+ *out_datatype = heif_channel_datatype_unsigned_integer;
+ *out_bit_depth = 32;
+ }
+ else if (type_string == "sint32") {
+ *out_datatype = heif_channel_datatype_signed_integer;
+ *out_bit_depth = 32;
+ }
+ else if (type_string == "float32") {
+ *out_datatype = heif_channel_datatype_floating_point;
+ *out_bit_depth = 32;
+ }
+ else if (type_string == "float64") {
+ *out_datatype = heif_channel_datatype_floating_point;
+ *out_bit_depth = 64;
+ }
+ else {
+ return false;
+ }
+ return true;
+}
+
+
+static void byte_swap_buffer(uint8_t* data, size_t num_elements, int bytes_per_element)
+{
+ for (size_t i = 0; i < num_elements; i++) {
+ uint8_t* elem = data + i * bytes_per_element;
+ for (int lo = 0, hi = bytes_per_element - 1; lo < hi; lo++, hi--) {
+ std::swap(elem[lo], elem[hi]);
+ }
+ }
+}
+
+
+heif_error loadRAW(const char* filename, const RawImageParameters& params, InputImage* input_image)
+{
+ if (params.width < 0 || params.height < 0) {
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw image width and height must not be negative"};
+ }
+
+ if (params.width == 0 && params.height == 0) {
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "At least one of --raw-width or --raw-height must be specified"};
+ }
+
+ if (params.datatype == heif_channel_datatype_undefined || params.bit_depth <= 0) {
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw image pixel type must be specified (use --raw-type)"};
+ }
+
+ int bytes_per_pixel = params.bit_depth / 8;
+
+ // Open file and get size
+ FILE* fp = fopen(filename, "rb");
+ if (!fp) {
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Cannot open raw input file"};
+ }
+
+ fseek(fp, 0, SEEK_END);
+ long file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if (file_size <= 0) {
+ fclose(fp);
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw input file is empty or unreadable"};
+ }
+
+ // Compute missing dimension from file size
+ int width = params.width;
+ int height = params.height;
+
+ if (width == 0) {
+ size_t row_bytes = static_cast<size_t>(height) * bytes_per_pixel;
+ if (static_cast<size_t>(file_size) % row_bytes != 0) {
+ fclose(fp);
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw file size is not divisible by height * bytes_per_pixel"};
+ }
+ width = static_cast<int>(static_cast<size_t>(file_size) / row_bytes);
+ }
+ else if (height == 0) {
+ size_t row_bytes = static_cast<size_t>(width) * bytes_per_pixel;
+ if (static_cast<size_t>(file_size) % row_bytes != 0) {
+ fclose(fp);
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw file size is not divisible by width * bytes_per_pixel"};
+ }
+ height = static_cast<int>(static_cast<size_t>(file_size) / row_bytes);
+ }
+
+ size_t expected_size = static_cast<size_t>(width) * height * bytes_per_pixel;
+
+ if (static_cast<size_t>(file_size) != expected_size) {
+ fclose(fp);
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Raw file size does not match width * height * bytes_per_pixel"};
+ }
+
+ // Read entire file
+ std::vector<uint8_t> buffer(expected_size);
+ size_t n = fread(buffer.data(), 1, expected_size, fp);
+ fclose(fp);
+
+ if (n != expected_size) {
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Failed to read raw input file"};
+ }
+
+ // Byte-swap from big-endian to host byte order if needed
+ if (params.big_endian && bytes_per_pixel > 1) {
+ if constexpr (std::endian::native == std::endian::little) {
+ byte_swap_buffer(buffer.data(), static_cast<size_t>(width) * height, bytes_per_pixel);
+ }
+ }
+
+ // Create image with nonvisual colorspace for typed component API
+ struct heif_image* image = nullptr;
+ heif_error err = heif_image_create(width, height,
+ heif_colorspace_nonvisual,
+ heif_chroma_undefined,
+ &image);
+ if (err.code != heif_error_Ok) {
+ return err;
+ }
+
+ uint32_t component_idx = 0;
+ err = heif_image_add_component(image, width, height,
+ heif_uncompressed_component_type_monochrome,
+ params.datatype, params.bit_depth,
+ &component_idx);
+ if (err.code != heif_error_Ok) {
+ heif_image_release(image);
+ return err;
+ }
+
+ // Get writable pointer and copy data row by row
+ size_t stride = 0;
+ uint8_t* plane = heif_image_get_component(image, component_idx, &stride);
+ if (!plane) {
+ heif_image_release(image);
+ return {heif_error_Invalid_input, heif_suberror_Unspecified,
+ "Failed to get component plane from image"};
+ }
+
+ size_t row_bytes = static_cast<size_t>(width) * bytes_per_pixel;
+ size_t stride_bytes = stride;
+
+ for (int y = 0; y < height; y++) {
+ memcpy(plane + y * stride_bytes,
+ buffer.data() + y * row_bytes,
+ row_bytes);
+ }
+
+ input_image->image = std::shared_ptr<heif_image>(image,
+ [](heif_image* img) { heif_image_release(img); });
+
+ return heif_error_ok;
+}
diff --git a/heifio/decoder_raw.h b/heifio/decoder_raw.h
new file mode 100644
index 00000000..b272e67d
--- /dev/null
+++ b/heifio/decoder_raw.h
@@ -0,0 +1,51 @@
+/*
+ libheif example application "heif".
+
+ MIT License
+
+ Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#ifndef LIBHEIF_DECODER_RAW_H
+#define LIBHEIF_DECODER_RAW_H
+
+#include "decoder.h"
+#include <libheif/heif_uncompressed_types.h>
+#include <string>
+
+struct RawImageParameters {
+ int width = 0;
+ int height = 0;
+ heif_channel_datatype datatype = heif_channel_datatype_undefined;
+ int bit_depth = 0;
+ bool big_endian = false;
+};
+
+// Maps a CLI string like "uint16" or "float32" to datatype + bit_depth.
+// Returns false if the string is not recognized.
+bool parse_raw_pixel_type(const std::string& type_string,
+ heif_channel_datatype* out_datatype,
+ int* out_bit_depth);
+
+LIBHEIF_API
+heif_error loadRAW(const char* filename, const RawImageParameters& params, InputImage* input_image);
+
+#endif //LIBHEIF_DECODER_RAW_H