GTKMM - 为某些宽度绘制图像时出错
GTKMM - Error drawing image for some widths
我正在尝试使用适用于 C++ 的 Gtkmm window,cairo::context,gdk::pixbuf。我注意到对于某些宽度(在我的示例中为 298),我得到了一些水平黑线(与白色条纹交替)而不是我的图像。
对于其他宽度(在我的示例中为 300),我得到的是正常图像。 (我只是在示例中绘制了黄色背景)。
我做错了什么?我怎样才能正确绘制任何图像宽度?
我在 :
上发现了这种行为
windows10/msys2/gcc11.2/std=c++20
opensuse 15.2/gcc 11.2.1/std=c++17
并且在这两个上我都有库版本:
-I/usr/include/gtkmm-3.0 -L/usr/lib64 -I/usr/lib64/glibmm-2.4/include -I/usr/include/glibmm-2.4 -I/usr/lib64/glib-2.0/include -I/usr/include/glib-2.0 -I/usr/include/sigc++-2.0/ -I/usr/lib64/sigc++-2.0/include -I/usr/include/giomm-2.4 -I/usr/lib64/giomm-2.4/include -I/usr/include/gdkmm-3.0 -I/usr/lib64/gdkmm-3.0/include -I/usr/lib64/pangomm-1.4/include -I/usr/include/gtk-3.0/ -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairomm-1.0 -I/usr/include/cairomm-1.0/cairomm -I/usr/lib64/cairomm-1.0/include -I/usr/include/freetype2 -I/usr/lib64/gtkmm-3.0/包括 -I/usr/include/pangomm-1.4 -I/usr/include/harfbuzz -I/usr/include/atkmm-1.6 -I/usr/include/atk-1.0 -I/usr/lib64/atkmm-1.6/include -LC:/programs/msys64/mingw64/bin - lgtkmm-3.0 -lglibmm-2.4 -I/usr/include/sigc++-2.0 -lsigc-2.0 -lgdkmm-3.0 -latkmm-1.6 -lcairomm-1.0
这是我的代码:
#include <gtkmm/application.h>
#include <gtkmm/fixed.h>
#include <gdkmm/pixbuf.h>
#include <gtkmm/window.h>
#include <cairomm/context.h>
#include <giomm/resource.h>
#include <gdkmm/general.h>
#include <iostream>
class TesterWindow : public Gtk::Window
{
public:
TesterWindow()
{
int width = 298; // lines
// int width = 300; // yellow
int height = 300;
set_size_request(width, height);
try
{
m_image = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, width, height);
auto pixels = m_image->get_pixels();
int channels = 3;
for(int i = 0; i < width * height * channels; ++i)
{
switch(i % 3)
{
case 0 : pixels[i] = 255; break;
case 1 : pixels[i] = 255; break;
case 2 : pixels[i] = 0; break;
default : break;
}
}
}
catch(const Gio::ResourceError& ex)
{
std::cout << "ResourceError: " << ex.what() << std::endl;
}
catch(const Gdk::PixbufError& ex)
{
std::cout << "PixbufError: " << ex.what() << std::endl;
}
}
void show()
{
set_position(Gtk::WIN_POS_CENTER);
show_all_children();
}
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
if(!m_image) return false;
Gdk::Cairo::set_source_pixbuf(cr, m_image, 0, 0);
cr->paint();
return true;
}
private:
Glib::RefPtr<Gdk::Pixbuf> m_image;
};
int main(int argc, char** argv)
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
TesterWindow window;
window.show();
return app->run(window);
}
我已经习惯了图像行通常(并非总是)以特定对齐方式存储的事实。每当我看到一张图像错误地出现在条纹中时,我首先会检查行对齐方式。
带着这种怀疑,我寻找一些 gdkmm(或 Gdk)文档。相反,我在 Gdk 源代码中找到了注释。
channels = has_alpha ? 4 : 3;
rowstride = width * channels;
if (rowstride / channels != width || rowstride + 3 < 0) /* overflow */
return NULL;
/* Always align rows to 32-bit boundaries */
rowstride = (rowstride + 3) & ~3;
bytes = height * rowstride;
函数Gdk::Pixbuf::get_rowstride()可用于检索图像缓冲区中两个连续行之间的字节数。
OP 代码的修复可能如下所示:
auto pixels = m_image->get_pixels();
const int rowstride = m_image->get_rowstride();
const int channels = 3;
for (int y = 0; y < height; ++y) {
auto rowpixels = pixels + y * rowstride;
for (int x = 0; x < width * channels; x += channels) {
rowpixels[x + 0] = 255;
rowpixels[x + 1] = 255;
rowpixels[x + 2] = 0;
}
}
备注:
我稍微改造了一下内循环。 (我认为无分支内部循环体性能更友好。)
我没有编译也没有调试我的代码。请对它持保留态度。
我正在尝试使用适用于 C++ 的 Gtkmm window,cairo::context,gdk::pixbuf。我注意到对于某些宽度(在我的示例中为 298),我得到了一些水平黑线(与白色条纹交替)而不是我的图像。
对于其他宽度(在我的示例中为 300),我得到的是正常图像。 (我只是在示例中绘制了黄色背景)。
我做错了什么?我怎样才能正确绘制任何图像宽度?
我在 :
上发现了这种行为windows10/msys2/gcc11.2/std=c++20
opensuse 15.2/gcc 11.2.1/std=c++17
并且在这两个上我都有库版本:
-I/usr/include/gtkmm-3.0 -L/usr/lib64 -I/usr/lib64/glibmm-2.4/include -I/usr/include/glibmm-2.4 -I/usr/lib64/glib-2.0/include -I/usr/include/glib-2.0 -I/usr/include/sigc++-2.0/ -I/usr/lib64/sigc++-2.0/include -I/usr/include/giomm-2.4 -I/usr/lib64/giomm-2.4/include -I/usr/include/gdkmm-3.0 -I/usr/lib64/gdkmm-3.0/include -I/usr/lib64/pangomm-1.4/include -I/usr/include/gtk-3.0/ -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairomm-1.0 -I/usr/include/cairomm-1.0/cairomm -I/usr/lib64/cairomm-1.0/include -I/usr/include/freetype2 -I/usr/lib64/gtkmm-3.0/包括 -I/usr/include/pangomm-1.4 -I/usr/include/harfbuzz -I/usr/include/atkmm-1.6 -I/usr/include/atk-1.0 -I/usr/lib64/atkmm-1.6/include -LC:/programs/msys64/mingw64/bin - lgtkmm-3.0 -lglibmm-2.4 -I/usr/include/sigc++-2.0 -lsigc-2.0 -lgdkmm-3.0 -latkmm-1.6 -lcairomm-1.0
这是我的代码:
#include <gtkmm/application.h>
#include <gtkmm/fixed.h>
#include <gdkmm/pixbuf.h>
#include <gtkmm/window.h>
#include <cairomm/context.h>
#include <giomm/resource.h>
#include <gdkmm/general.h>
#include <iostream>
class TesterWindow : public Gtk::Window
{
public:
TesterWindow()
{
int width = 298; // lines
// int width = 300; // yellow
int height = 300;
set_size_request(width, height);
try
{
m_image = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, width, height);
auto pixels = m_image->get_pixels();
int channels = 3;
for(int i = 0; i < width * height * channels; ++i)
{
switch(i % 3)
{
case 0 : pixels[i] = 255; break;
case 1 : pixels[i] = 255; break;
case 2 : pixels[i] = 0; break;
default : break;
}
}
}
catch(const Gio::ResourceError& ex)
{
std::cout << "ResourceError: " << ex.what() << std::endl;
}
catch(const Gdk::PixbufError& ex)
{
std::cout << "PixbufError: " << ex.what() << std::endl;
}
}
void show()
{
set_position(Gtk::WIN_POS_CENTER);
show_all_children();
}
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
if(!m_image) return false;
Gdk::Cairo::set_source_pixbuf(cr, m_image, 0, 0);
cr->paint();
return true;
}
private:
Glib::RefPtr<Gdk::Pixbuf> m_image;
};
int main(int argc, char** argv)
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
TesterWindow window;
window.show();
return app->run(window);
}
我已经习惯了图像行通常(并非总是)以特定对齐方式存储的事实。每当我看到一张图像错误地出现在条纹中时,我首先会检查行对齐方式。
带着这种怀疑,我寻找一些 gdkmm(或 Gdk)文档。相反,我在 Gdk 源代码中找到了注释。
channels = has_alpha ? 4 : 3;
rowstride = width * channels;
if (rowstride / channels != width || rowstride + 3 < 0) /* overflow */
return NULL;
/* Always align rows to 32-bit boundaries */
rowstride = (rowstride + 3) & ~3;
bytes = height * rowstride;
函数Gdk::Pixbuf::get_rowstride()可用于检索图像缓冲区中两个连续行之间的字节数。
OP 代码的修复可能如下所示:
auto pixels = m_image->get_pixels();
const int rowstride = m_image->get_rowstride();
const int channels = 3;
for (int y = 0; y < height; ++y) {
auto rowpixels = pixels + y * rowstride;
for (int x = 0; x < width * channels; x += channels) {
rowpixels[x + 0] = 255;
rowpixels[x + 1] = 255;
rowpixels[x + 2] = 0;
}
}
备注:
我稍微改造了一下内循环。 (我认为无分支内部循环体性能更友好。)
我没有编译也没有调试我的代码。请对它持保留态度。