首页 > 解决方案 > 如何从 FLTK Fl__Image__Surface 获取具有透明背景的图像?

问题描述

我想绘制字符串或字符(离屏)并将其用作 Fl_Image 或 Fl_RGB_Image。基于此链接,我可以使用 Fl__Image__Surface 轻松完成此操作。Fl__Image__Surface 的问题是当我使用方法将其输出转换为图像(Fl_RGB_Image)时它不支持透明度image()。那么有什么方法可以实现这一目标吗?我可以在带有 BufferedImage的 Java Swing 上执行此操作,也可以在带有Canvas的Android中执行此操作,方法是使用 Bitmap.Config.ARGB_8888创建位图。

标签: c++transparencyfltk

解决方案


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

#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 给出了一个具有 3 个通道(r、g、b)的 Fl_RGB_Image,没有 alpha。我们通过创建一个临时向量来手动添加 alpha,查询数据(如果你知道你正在使用的颜色,可以通过仅检查来优化data[i] == 255。向量是一个 RAII 类型,其生命在范围结束时结束,所以我们只是mempcy 将向量中的数据存储到一个长寿命的 unsigned char 数组中,我们将其传递给 Fl_RGB_Image,指定深度为 4,考虑 alpha。

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


推荐阅读