Boost::GIL: 读取带 alpha 通道的 *.png 图像缺少抗锯齿

Boost::GIL: reading *.png image with alpha channel is missing antialiasing

我正在使用 boost 1.74。

所以,毫无例外地捕获和休息我的实际代码看起来像:

typedef std::vector<int32_t> FlatINT32TArr;

using PreviewImageT = bg::rgba8_image_t;
using PreviewViewT = bg::rgba8_view_t;
using PreviewPixelT = bg::rgba8_pixel_t;

void read_pixel_arr(FlatINT32TArr r_preview_flat_arr, const std::wstring& filepath)
{
  std::ifstream byte_stream(filepath, std::ios::binary);

  PreviewImageT image;

  bg::read_and_convert_image(
    byte_stream, image, bg::image_read_settings<bg::png_tag>());

  const int image_width = (int)image.width();
  const int image_height = (int)image.height();

  const int preview_pixel_count = image_width * image_height;

  PreviewViewT preview_view;
  PreviewPixelT* buff1 = new PreviewPixelT[preview_pixel_count];
  preview_view = bg::interleaved_view(
    image_width, image_height, buff1,
    image_width * sizeof(PreviewPixelT));

  bg::copy_and_convert_pixels(
    bg::flipped_up_down_view(const_view(image)), preview_view);

  r_preview_flat_arr = FlatINT32TArr(preview_pixel_count);
  memcpy(
    &r_preview_flat_arr[0],
    &preview_view[0],
    sizeof(PreviewPixelT) * preview_pixel_count
  );
}

它读取 *.png 图像文件并将其转换为 int32_t 数组。 (然后使用该数组生成 OpenGL 纹理)。

所以,原始图像文件是:

它是从 Adob​​e Illustrator 导出的,带有 alpha 通道,去隔行扫描。

这里我有几个我无法解决的问题:

- 这是结果。如您所见,图像像楼梯一样混叠,为什么?如何解决?

- 这是结果。如您所见,从图像底部到顶部是否还有一行。暂时通过导出去隔行图像解决了这个问题,但这不是最好的方法。我如何使用 gil 解决它?

再测试一次: 原始的(带 alpha 通道渐变):

结果:

在显示的转换后似乎有问题。

当我将预览数据保存为 PNG 时:

bg::write_view("output.png", preview_view, bg::png_tag{});

我得到了预期的输出:

这就是您在平面 int32 向量中复制的预览缓冲区 (buff1)。

Note also

  • the return parameter was passed by value, meaning it would not actually be changed by read_pixel_arr (added & for pass-by-reference)
  • there was a memory leak, because buff1 was never freed. Below, I fixed it with a unique_ptr.

Live On Coliru

void read_pixel_arr(FlatINT32TArr& r_preview_flat_arr, std::string filepath) {
    std::ifstream byte_stream(filepath, std::ios::binary);

    bg::image_read_settings<bg::png_tag> settings;
    //settings._read_transparency_data = true;

    PreviewImageT image;
    bg::read_and_convert_image(byte_stream, image, settings);

    auto width   = image.width();
    auto height  = image.height();
    auto npixels = width * height;

    auto buff1 = std::make_unique<PreviewPixelT[]>(npixels);
    auto preview_view = bg::interleaved_view(
            width, height, buff1.get(),
            width * sizeof(PreviewPixelT));
    assert(buff1.get() == &preview_view[0]); // checking understanding

    bg::copy_and_convert_pixels(
            bg::flipped_up_down_view(const_view(image)), preview_view);

    r_preview_flat_arr = FlatINT32TArr(npixels);
    memcpy(r_preview_flat_arr.data(), 
           buff1.get(),
           sizeof(PreviewPixelT) * npixels);

    bg::write_view("output.png", preview_view, bg::png_tag{});
}

int main() {
    FlatINT32TArr v(1 << 20);
    read_pixel_arr(v, "sample.png");
}

简化很多

使用read_image_info可以避免分配缓冲区3次并复制多次:

  1. 用于图像缓冲区(仅用于复制和检测width/height)
  2. 对于 buff1(最初也是泄露的)
  3. 对于平面阵列 (std::vector)

相反,让我们从文件信息中检测维度,然后直接读入平面数组:

auto flatvector_view(FlatINT32TArr& v, long width) {
    return bg::interleaved_view(
       width, v.size()/width,
       reinterpret_cast<PreviewPixelT*>(v.data()),
       width * sizeof(PreviewPixelT));
}

long read_pixel_arr(FlatINT32TArr& r_pixeldata, std::string filepath) {
    bg::image_read_settings<bg::png_tag> settings;
    auto info   = bg::read_image_info(filepath, settings);
    auto width  = info._info._width;
    auto height = info._info._height;
    r_pixeldata.resize(width * height);

    bg::read_and_convert_view(filepath,
        bg::flipped_up_down_view(flatvector_view(r_pixeldata, width)),
        settings);

    return width;
}

int main() {
    FlatINT32TArr v;
    auto width = read_pixel_arr(v, "sample.png");

    bg::write_view("output.png", flatvector_view(v, width), bg::png_tag{});
}

请注意 reinterpret_caststatic_assert 保护。它在逻辑上等同于您的 memcpy 双关语。