我有一个从文件加载图像并成功创建opengl纹理的函数。
/**
* @brief Loads a texture from file and generates an OpenGL texture from it.
*
* @param filename Path to the image file.
* @param out_texture Texture id the results are bound to.
* @param out_width Value pointer the resulting image width is written to.
* @param out_height Value pointer the resulting image height is written to.
* @param flip_image Stb indicator for flipping the image.
* @return true Image has been successfully loaded.
* @return false Failed loading the image.
*/
bool LoadTextureFromFile(const char *filename, GLuint *out_texture, int *out_width, int *out_height, bool flip_image = false)
{
// Load from file
int image_width = 0;
int image_height = 0;
stbi_set_flip_vertically_on_load(flip_image);
unsigned char *image_data = stbi_load(filename, &image_width, &image_height, NULL, 4);
if (image_data == NULL)
{
std::cout << "ERROR::Tools::GLHelper::LoadTextureFromFile - Failed to load image from file '" << filename << "'." << std::endl;
stbi_image_free(image_data);
return false;
}
// Create a OpenGL texture identifier
GLuint image_texture;
glGenTextures(1, &image_texture);
glBindTexture(GL_TEXTURE_2D, image_texture);
// Set texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glGenerateMipmap(GL_TEXTURE_2D);
*out_texture = image_texture;
*out_width = image_width;
*out_height = image_height;
stbi_image_free(image_data);
return true;
}
我想要做的是通过stbi_load
上面的方法加载图像并将其保存为 BLOB 到 sqlite。之后我希望能够加载相同的 blob 并在单独的函数中从它创建一个 opengl 纹理。
在第一步中,我创建了一个只加载图像的函数:
unsigned char *ImageDataFromFile(const char *filename)
{
int image_width = 0;
int image_height = 0;
unsigned char *image_data = stbi_load(filename, &image_width, &image_height, NULL, 4);
if (image_data == NULL)
{
std::cout << "ERROR::Tools::GLHelper::LoadTextureFromFile - Failed to load image from file '" << filename << "'." << std::endl;
stbi_image_free(image_data);
}
return image_data;
}
在下一步中,我想将此数据存储到我的 sqlite 数据库中:
void DBConnector::AddImage(std::string name, unsigned char *data)
{
sqlite3_stmt *stmt;
int err = sqlite3_prepare_v2(db, "INSERT INTO images (name, img_data) VALUES (?, ?)", -1, &stmt, NULL);
if (err != SQLITE_OK)
{
std::cout << "ERROR::DATA::DBConnector - Failed to prepare sqlite3 statement: \n"
<< sqlite3_errmsg(db) << std::endl;
}
sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_blob(stmt, 2, data, -1, SQLITE_TRANSIENT);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
return;
}
最后,我将各个部分连接起来:
unsigned char *image_data = Tools::FileHelper::ImageDataFromFile(selected_filepath.c_str());
db->AddImage("Foo", image_data);
发生的情况是看似任意的数据最终会出现在数据库中,这绝对不是图像数据。有时条目只是空的。
我怀疑我处理的返回类型stbi_load
不正确,将随机内存数据强制输入数据库。从 stbi 文档中提取:
图像加载器的返回值是一个指向像素数据的“unsigned char *”。
据我了解,我只是将接受的数组指针传递给sqlite3_bind_blob
它。那么为什么它适用于一个而不适用于另一个呢?或者错误源可能在其他地方?const void *
glTexImage2D
编辑
我还尝试了别的东西。通常我在调用 ie 时通过 -1 作为 size sqlite3_bind_text
,因为调用会自动搜索空终止符。所以我认为在调用时我可能必须以字节为单位传递正确的大小,sqlite3_bind_blob
因为那里可能没有终结符。因此,对于具有 3 个通道的 225 x 225 大小的图像,我将225 * 225 * 3
其作为大小参数传递。不幸的是,这也不起作用。