简体   繁体   中英

Properly display images with OpenGL if the image is loaded by Resource.rc file

I have two choices. I can read my image pinmap.jpg from Resource.rc or read the image from STBI_Image library.

// Simple helper function to load an image into a OpenGL texture with common settings
inline bool ReadImageFromResource(GLuint* out_texture, int width, int height) {
    // Locate the resource in the application's executable.
    HRSRC imageResHandle = FindResource(
        NULL,             // This component.
        MAKEINTRESOURCE(IDR_IMAGE1),   // Resource name.
        L"Image");        // Resource type.
    HRESULT hr = (imageResHandle ? S_OK : E_FAIL);

    // Load the resource to the HGLOBAL.
    HGLOBAL imageResDataHandle = NULL;
    if (SUCCEEDED(hr)) {
        imageResDataHandle = LoadResource(NULL, imageResHandle);
        hr = (imageResDataHandle ? S_OK : E_FAIL);
    }

    // Lock the resource to retrieve memory pointer.
    LPVOID image_data = NULL;
    if (SUCCEEDED(hr)) {
        image_data = LockResource(imageResDataHandle);
        UnlockResource(imageResDataHandle);
        hr = (image_data ? S_OK : E_FAIL);
    }

    if (image_data == NULL)
        return false;

    // Create a OpenGL texture identifier
    GLuint image_texture;
    glGenTextures(1, &image_texture);
    glBindTexture(GL_TEXTURE_2D, image_texture);

    // Setup filtering parameters for display
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same

    // Upload pixels into texture
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data);
    *out_texture = image_texture;
    return true;
}

The results is:

在此处输入图像描述

When I read the image from STBI-library, then the image looks like this:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

// Simple helper function to load an image into a OpenGL texture with common settings
inline bool ReadImageFromSTBI(const char* filename, GLuint* out_texture, int* out_width, int* out_height)
{
    // Load from file
    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)
        return false;

    // Create a OpenGL texture identifier
    GLuint image_texture;
    glGenTextures(1, &image_texture);
    glBindTexture(GL_TEXTURE_2D, image_texture);

    // Setup filtering parameters for display
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same

    // Upload pixels into texture
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
    stbi_image_free(image_data);

    *out_texture = image_texture;
    *out_width = image_width;
    *out_height = image_height;

    return true;
}

You see the difference between the color and the image above is shifted due to the C to the left. It should be at the right side of the image. Notice that the image above is displayed with GL_RBG and this image is displayed with GL_RGBA . Else, I cannot display the image.

在此处输入图像描述

Question:

It seems to be different data depending on how I load the data of the image. I have looked at the data of the image. The variable image_data differes.

How do I properly display images with OpenGL if the image is loaded by Resource.rc file and not loaded by file such as STBI-library?

LoadResource does not decode, decompress, or interpret the resource data in any way. What you get in your image_data is a pointer to a memory block that contains exactly the contents of your pinmap.jpg file.

Interestingly, what you have is a BITMAP rather than an actual JPEG file. If it wasn't, you'd get a bunch of noise instead of anything resembling your image. From what my crystal ball tells me, you imported that once has been JPEG into the resource editor with the "Add Resource > Import..." function of Visual Studio. When done that way, it converts the file to a BITMAP, overwriting the original on disk. (Seriously, Microsoft, what were you smoking??)

The results you observe thus can be explained as follows:

  • The horizontal wrap-around offset is due to the BITMAP file and info headers at the beginning of the resource.
  • The colors are off because of the BGR <-> RGB mismatch.

If you want to keep the resource as JPEG, you can add it by manually editing the rc file, or by reverting the file after Visual Studio is done with messing it up. However, if you choose this route, you must decompress the JPEG (because OpenGL expects plain RGB data rather than JPEG). One way would be to call stbi_load_from_memory on that image_data you got from LockResource . Stbi will decompress the JPEG into RGB (in that order).

If you want to keep working with the BITMAP resource, then all you need is to skip the headers and flip the channels.

For skipping the headers you parse the BITMAPFILEHEADER that's located at image_data . The offset to the pixel data is in the bfOffBits field in the header:

actual_image_data = (char*)image_data + ((BITMAPFILEHEADER*)image_data)->bfOffBits;

For fixing the channel order you can pass GL_BGR for the format parameter ( not the internalformat !!) of glTexImage2D :

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, actual_image_data);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM