如何从 FLTK Fl__Image__Surface 获取透明背景的图像?

How to get image with transparent background from FLTK Fl__Image__Surface?

我想绘制字符串或字符(屏幕外)并将其用作 Fl_Image 或 Fl_RGB_Image。 基于 this link I can do that easily with Fl__Image__Surface. The problem with Fl__Image__Surface is that it does not support transparency when I convert its output to image (Fl_RGB_Image) using image() method. So is there any way I can achieve this? I can do that on Java Swing with BufferedImage, also in Android with Canvas by creating Bitmap 和 Bitmap.Config.ARGB_8888.

如果您更喜欢手动操作,可以尝试以下操作:

#include <FL/Enumerations.H>
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Device.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/fl_draw.H>
#include <cassert>
#include <vector>

Fl_RGB_Image *get_image(int w, int h) {
    // draw image on surface
    auto img_surf = new Fl_Image_Surface(w, h);
    Fl_Surface_Device::push_current(img_surf);
    // We'll use white to mask 255, 255, 255, see the loop
    fl_color(FL_WHITE);
    fl_rectf(0, 0, w, h);
    fl_color(FL_BLACK);
    fl_font(FL_HELVETICA_BOLD, 20);
    fl_draw("Hello", 100, 100);
    auto image = img_surf->image();
    delete img_surf;
    Fl_Surface_Device::pop_current();
    return image;
}

Fl_RGB_Image *get_transparent_image(const Fl_RGB_Image *image) {
    assert(image);
    // make image transparent
    auto data = (const unsigned char*)(*image->data());
    auto len = image->w() * image->h() * image->d(); // the depth is by default 3
    std::vector<unsigned char> temp;
    for (size_t i = 0; i < len; i++) {
        if (i > 0 && i % 3 == 0) {
            // check if the last 3 vals are the rgb values of white, add a 0 alpha
            if (data[i] == 255 && data[i - 1] == 255 && data[i - 2] == 255)
                temp.push_back(0);
            else
                // add a 255 alpha, making the black opaque
                temp.push_back(255);
            temp.push_back(data[i]);
        } else {
            temp.push_back(data[i]);
        }
    }
    temp.push_back(0);
    assert(temp.size() == image->w() * image->h() * 4);
    auto new_image_data = new unsigned char[image->w() * image->h() * 4];
    memcpy(new_image_data, temp.data(), image->w() * image->h() * 4);
    auto new_image = new Fl_RGB_Image(new_image_data, image->w(), image->h(), 4); // account for alpha
    return new_image;
}

int main() {
    auto win = new Fl_Double_Window(400, 300);
    auto box = new Fl_Box(0, 0, 400, 300);
    win->end();
    win->show();
    auto image = get_image(box->w(), box->h());
    auto transparent_image = get_transparent_image(image);
    delete image;
    box->image(transparent_image);
    box->redraw();
    return Fl::run();
}

想法是 Fl_Image_Surface 给出一个 Fl_RGB_Image 具有 3 个通道(r、g、b),没有 alpha。我们通过创建一个临时向量手动添加 alpha,查询数据(如果您只通过检查 data[i] == 255 就知道您正在使用的颜色,则可以进行优化。该向量是一种 RAII 类型,其生命周期结束时作用域,所以我们只是将向量中的数据存储到 long-lived unsigned char 数组,我们将其传递给 Fl_RGB_Image,指定深度为 4,考虑 alpha。

另一种选择是使用外部库,如 CImg(单个 header 库)将文本绘制到图像缓冲区,然后将该缓冲区传递给 Fl_RGB_Image。