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 纹理)。
所以,原始图像文件是:
它是从 Adobe 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
.
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次并复制多次:
- 用于图像缓冲区(仅用于复制和检测width/height)
- 对于
buff1
(最初也是泄露的)
- 对于平面阵列 (
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_cast
由 static_assert
保护。它在逻辑上等同于您的 memcpy
双关语。
我正在使用 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 纹理)。
所以,原始图像文件是:
它是从 Adobe Illustrator 导出的,带有 alpha 通道,去隔行扫描。
这里我有几个我无法解决的问题:
- 子采样。
- 隔行扫描。
再测试一次: 原始的(带 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 aunique_ptr
.
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次并复制多次:
- 用于图像缓冲区(仅用于复制和检测width/height)
- 对于
buff1
(最初也是泄露的) - 对于平面阵列 (
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_cast
由 static_assert
保护。它在逻辑上等同于您的 memcpy
双关语。