nothings / stb

stb single-file public domain libraries for C/C++
https://twitter.com/nothings
Other
26.72k stars 7.72k forks source link

`stb_image` return 3 channel when load 1 channel `bmp` #1486

Closed th1nk3r-ing closed 1 year ago

th1nk3r-ing commented 1 year ago

Test bmp file is gnu unifont bmp

nothings commented 1 year ago

are you passing 3 to stbi_load?

rygorous commented 1 year ago

I don't think 1-channel BMPs are even a thing?

AFAICT all BMPs with <=8 bits per pixel are palettized and we de-palettize on load which results in a 3-channel image unless you explicitly ask for 1 channel.

rygorous commented 1 year ago

If anything grayscale BMPs are pretty much just a convention where you send an 8-bit indexed image with an all-grayscale palette. We could detect this as 8-bit grayscale but currently we don't, and it would require stbi__bmp_info to read the full palette not just the headers.

nothings commented 1 year ago

To be clear, I tested and this image loaded as 1 channel by default.

th1nk3r-ing commented 1 year ago

To be clear, I tested and this image loaded as 1 channel by default.

here is more detail :

[int32_t imageLoad(ImageInfo *) 70] load image:[/sdcard/Android/data/com.think3r.AndroidOpenGLES/files/textures/unifont-15.0.06.bmp] OK! [4128 x 4160] @ 3 Chans

Here is the code of imageLoad() function :

int32_t imageLoad(ImageInfo * pstInfo)
{
    BASE_CHECK_TRUE_RET(NULL == pstInfo, -1);
    BASE_CHECK_TRUE_RET(0 == strlen((const char *)pstInfo->ps8FileName), -1);

    if (pstInfo->bBeFlipVertical) {
        stbi_set_flip_vertically_on_load(TRUE);
    } else {
        stbi_set_flip_vertically_on_load(FALSE);
    }

    pstInfo->pu8Data = stbi_load((char const *)pstInfo->ps8FileName,
                                &pstInfo->s32Width,
                                &pstInfo->s32Height,
                                &pstInfo->s32Channels,
                                0);
    if (pstInfo->pu8Data) {
        LOGW("[%s %d]  load image:[%s] OK! [%d x %d] @ %d Chans\n",
            __func__, __LINE__, pstInfo->ps8FileName, pstInfo->s32Width, pstInfo->s32Height, pstInfo->s32Channels);
        pstInfo->bBeVaild = TRUE;
        return OK;
    } else {
        pstInfo->bBeVaild = false;
        LOGW("[%s %d] ERR! Failed to load texture :[%s]\n", __func__, __LINE__, pstInfo->ps8FileName);
        return -2;
    }
}
th1nk3r-ing commented 1 year ago

If anything grayscale BMPs are pretty much just a convention where you send an 8-bit indexed image with an all-grayscale palette. We could detect this as 8-bit grayscale but currently we don't, and it would require stbi__bmp_info to read the full palette not just the headers.

Well, I don't know that. I will try. Thanks. PS: I just think the 1 from 4128 x 4160 x 1 is 1 channel. The title is wrong.

file unifont-15.0.06.bmp
unifont-15.0.06.bmp: PC bitmap, Windows 3.x format, 4128 x 4160 x 1, image size 2146560, resolution 4724 x 4724 px/m, 2 important colors, cbSize 2146622, bits offset 62
nothings commented 1 year ago

Whoops, I looked at the wrong variable in the debugger, it does indeed load as 3 channels. ryg's explanation is correct, there are no grayscale BMPs, there are only paletted BMPs. That palette might only have gray colors in it, but it's not part of the file format that it is "gray", and we're not going to check the palette to decide whether to report it as gray or not.

nothings commented 1 year ago

I just think the 1 from 4128 x 4160 x 1 is 1 channel. The title is wrong.

file unifont-15.0.06.bmp
unifont-15.0.06.bmp: PC bitmap, Windows 3.x format, 4128 x 4160 x 1, image size 2146560, resolution 4724 x 4724 px/m, 2 important colors, cbSize 2146622, bits offset 62

The output of file for BMP is WIDTH x HEIGHT x BITS-PER-PIXEL, not CHANNELS.

https://github.com/file/file/blob/a98c50fe474d83945450aad5a306c27ffbed26a9/magic/Magdir/images#L808 vs https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader