1

我有一个从文件加载图像并成功创建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其作为大小参数传递。不幸的是,这也不起作用。

4

0 回答 0