Search code examples
c++boostboost-gil

reading transparent images boost.gil C++


I have a image with a transparent background and I want to copy it over another image both images are png format I've tried using boost::gil::rgba8_image_t but it still copies the transparent image with a gray background instead. this is what I've used

#include <boost/gil.hpp>
#include <boost/gil/extension/io/png.hpp>
#include <boost/gil/extension/numeric/resample.hpp>
#include <boost/gil/extension/numeric/sampler.hpp>
#include <string>

namespace bg = boost::gil;

int main() {
    std::string target{"./jail.png"};
    std::string picture("./example_in.png");
    bg::rgba8_image_t jail;
    bg::rgba8_image_t temp;
    bg::read_and_convert_image(target, jail, bg::png_tag{});
    bg::rgba8_image_t pic(jail.dimensions());
    bg::read_and_convert_image(picture, temp, bg::png_tag{});
    bg::resize_view(bg::view(temp), bg::view(pic), bg::bilinear_sampler{});
    bg::copy_pixels(bg::view(jail), bg::view(pic));
    bg::write_view("out.png", bg::view(pic), bg::png_tag{});
}

Solution

  • Mmm. Reading this it seems to do exactly what you ask it:

    bg::resize_view(bg::view(temp), bg::view(pic), bg::bilinear_sampler{});
    

    This fills the pixels with a resized view of your input image. The new size matches exactly that of your jail. Now:

    bg::resize_view(bg::view(temp), bg::view(pic), bg::bilinear_sampler{});
    

    Copies all the pixels from the jail image over it. This replaces any pixels that you just filled from the resized input image.

    You output would look like

    enter image description here

    Note how the background is checkered. This is the conventional pattern to indicate transparency. That's not gray. It's just empty pixels with full transparency.

    What you presumably wanted was to keep the background pixels. There doesn't appear to be a highlevel pixel operation in Boost GIL¹, but you write it yourself:

    using Img = bg::rgba8_image_t;
    using Pix = Img::value_type;
    
    void overlay_combine(Img& pic, Img const& overlay) {
        assert(pic.dimensions() == overlay.dimensions());
        bg::transform_pixels(
            view(pic), const_view(overlay), view(pic),
            [](Pix const& a, Pix const& b) {
                return get_color(b, bg::alpha_t{})? b : a;
            });
    }
    

    Now you write main like:

    int main() {
        Img jail, polar;
        bg::read_and_convert_image("./jail_PNG16.png", jail, bg::png_tag{});
        bg::read_and_convert_image("./polar.png", polar, bg::png_tag{});
    
        Img pic(jail.dimensions());
        bg::resize_view(bg::view(polar), bg::view(pic), bg::bilinear_sampler{});
        overlay_combine(pic, jail);
    
        bg::write_view("out.png", bg::view(pic), bg::png_tag{});
    }
    

    And the result is:

    enter image description here

    You can guess where I got the polar.png :)

    ¹ see e.g. How to combine images with boost gil?