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

问题描述

我想绘制字符串或字符(屏幕外)并将其用作 Fl_Image 或 Fl_RGB_Image。 基于 this link,我可以使用 Fl__Image__Surface 轻松做到这一点。 Fl__Image__Surface 的问题在于,当我使用 image() 方法将其输出转换为图像 (Fl_RGB_Image) 时,它不支持透明度。那么有什么办法可以实现这一目标吗?我可以在 Java Swing 上用 BufferedImage 做到这一点,也可以在 Android 上用 Canvas 通过用 Bitmap.Config.ARGB_8888 创建 Bitmap 来做到这一点。

解决方法

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

#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,see the loop
    fl_color(FL_WHITE);
    fl_rectf(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,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 给出一个带有 3 个通道(r、g、b)的 Fl_RGB_Image,没有 alpha。我们通过创建一个临时向量来手动添加 alpha,查询数据(如果您仅通过检查 data[i] == 255 就知道正在使用的颜色,则可以进行优化。向量是一种 RAII 类型,其生命周期结束于范围,所以我们只是将向量中的数据存储到一个长期存在的无符号字符数组中,然后将其传递给指定深度为 4 的 Fl_RGB_Image,考虑 alpha。

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