cpngjpegstb-image

STB Image Writing JPEG Incorrectly


i was working on my pixel art editor in C/C++ which was a fork of sixel till then saving the image as jpeg worked completely fine until i re-wrote my application to use SDL2 (so i don't have to deal with graphics APIs directly).

when i finally ported the application i realized my 2 functions WritePngFromCanvas & WriteJpgFromCanvas were broken because they took unsigned 8 bit integer pixel array whereas after porting to SDL2 my pixel array was 32 bit unsigned integer.

i simply used a for-loop to "convert" each 32 bit pixel comprised of rgba to 8 byte separate r, g, b & a values.

my WritePngFromCanvas worked but my WriteJpgFromCanvas function always wrote the image in a weird "format" like this is the image i was trying to write:

Image trying to write

and this was the Image that was written:

Image Written

This is my WriteJpgFromCanvas function:

void WriteJpgFromCanvas(const char *filepath, int *canvas_dims, Uint32* data) {
    unsigned char* pixels = (unsigned char*)malloc(canvas_dims[0] * canvas_dims[1] * 4 * sizeof(unsigned char));
    memset(pixels, 0, canvas_dims[0] * canvas_dims[1] * 4 * sizeof(unsigned char));

    unsigned char* ptr;
    for (int y = 0; y < canvas_dims[1]; y++) {
        for (int x = 0; x < canvas_dims[0]; x++) {
            Uint32* pixel = GetPixel(x, y, data);
            ptr = pixels + ((y * canvas_dims[0] + x) * 4);
            *(ptr+0) = (*pixel & 0xFF000000) >> 24;  // R
            *(ptr+1) = (*pixel & 0x00FF0000) >> 16;  // G
            *(ptr+2) = (*pixel & 0x0000FF00) >> 8;   // B
            *(ptr+3) = (*pixel & 0x000000FF);        // A
        }
    }

    stbi_write_jpg(filepath, canvas_dims[0], canvas_dims[1], 4, data, 100);
    free(pixels);
}

Remarks:


Solution

  • The displayed runtime left shift of a negative value indicates that the data is in an unexpected format. And indeed the function stbi_write_jpg is called with the unconverted data when looking at the presented code.

    You need to call stbi_write_jpg with the converted data, which is called pixel in your code shown.

    So the correct call should look like this:

    stbi_write_jpg(filepath, canvas_dims[0], canvas_dims[1], 4, pixel, 100);