Search code examples
boostboost-pythonboost-gil

How to read image info from python bytes string using Boost::GIL?


I write a function to read image width and height from file header

int read_image_dimensions() {
    namespace bg = boost::gil;

    std::string filepath = "image.png";
    std::ifstream byte_stream(filepath, std::ios::binary);

    int width = 0, height = 0;
    bg::image_read_info<bg::png_tag> png_tag_info;

    png_tag_info = bg::read_image_info(byte_stream, bg::image_read_settings<bg::png_tag>())._info;
    width = png_tag_info._width; height = png_tag_info._height;

    std::cout << width << "x" << height << std::endl;
    return 0;
}

And I have no idea how to read image info from python bytes Image data taken from Blender API, it was same as writen in image file.

using namespace boost::python;

int read_image_dimensions(object &image) {
    object image_packed_file = extract<object>(image.attr("packed_file"));
    object packed_data = extract<object>(image_packed_file.attr("data"));
    size_t packed_size = extract<size_t>(image_packed_file.attr("size"));

    // ... 
}

Solution

  • So, ignoring the python stuff, let's just assume you got a hold of the bytes in some way:

    std::vector<char> pydata;
    

    Then you can simply create a stream of that. There are multiple ways to achieve that, but let me use Boost Iostreams in an effort to be efficient about it:

    io::stream<io::array_source> byte_stream(pydata.data(), pydata.size());
    

    That's all. The rest is what you had.

    Live Demo

    This demonstrates that my profile picture is 200x200 pixels:

    #include <boost/gil/extension/io/png.hpp>
    #include <boost/iostreams/device/array.hpp>
    #include <boost/iostreams/stream.hpp>
    #include <iostream>
    
    namespace bg = boost::gil;
    namespace io = boost::iostreams;
    
    extern std::vector<char> pydata;
    
    int main() {
        io::stream<io::array_source> byte_stream(pydata.data(), pydata.size());
    
        auto info = bg::read_image_info(
                byte_stream,
                bg::image_read_settings<bg::png_tag>())
            ._info;
    
        std::cout << "Dimensions: " << info._width << "x" << info._height << "\n";
    }
    
    static char const polar_bear[] {
      "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d"
      "\x49\x48\x44\x52\x00\x00\x00\xc8\x00\x00\x00\xc8"
      "\x08\x06\x00\x00\x00\xad\x58\xae\x9e\x00\x00\x20"
      "\x00\x49\x44\x41\x54\x78\x9c\x94\xbd\x59\xb3\x2d"
      "\xcb\x71\x1e\xf6\x65\x56\x75\xf7\x5a\x7b\xef\x73"
      "\xee\x39\x77\xc0\x9d\x31\x03\xc4\x44\xc0\x00\x88"
      // 5623 lines snipped...
      "\x45\x4e\x44\xae\x42\x60\x82"
    };
    
    std::vector<char> pydata { std::begin(polar_bear), std::end(polar_bear) };
    

    Prints

    Dimensions: 200x200