2

I am trying to write a simple image file to disk using stb_image_write. I use the simplest test case : a 128 by 128 pixels RGB image.

I found this example online, and the guy seems to say that it works fine, plus it looks exactly like what I have been writing for 2 hours :

void save_image(int w, int h, int channels_num)
{

    int data[w * h * channels_num];

     int index = 0;
     for (int j = h - 1; j >= 0; --j)
     {
      for (int i = 0; i < w; ++i)
      {
       float r = (float)i / (float)w;
       float g = (float)j / (float)h;
       float b = 0.2f;
       int ir = int(255.0 * r);
       int ig = int(255.0 * g);
       int ib = int(255.0 * b);

       data[index++] = ir;
       data[index++] = ig;
       data[index++] = ib;
      }
     }

    stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, 100);
}

save_image(128, 128, 3);

The result should be a nice color gradient, but all I can get is a valid file with some vertical red, green, blue and black lines. Dimensions of the image are ok though. I really don't find the solution here. I am on linux Jessie. Could there be 'endianess' issue or something like that?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
gui2one
  • 160
  • 1
  • 1
  • 14
  • 4
    Try changing `int data[...]` to `unsigned char data[...]` (or better `uint8_t` from `stdint.h`). The manual seems to suggest it expects components packed together as bytes ("Each pixel contains 'comp' channels of data stored interleaved with 8-bits per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA.") – Botje May 08 '19 at 11:17
  • 3
    I recently answered another question about `stbi_write`. I believe your mistake is `int data[w * h * channels_num];` IMHO, it must be `unsigned char data[w * h * channels_num];`. (The other Q/A: [SO: how can I write pixel color data to a bmp image file with stb_image?](https://stackoverflow.com/a/55760080/7478597)) Btw. you are using a [VLA](https://en.wikipedia.org/wiki/Variable-length_array) which might be supported as extension of your compiler - it's not standard C++. (Use a `std::vector` instead.) – Scheff's Cat May 08 '19 at 11:18
  • Yes !! this was the issue , I changed int data[] to unsigned char data [ ] and that did the trick. Thanks a lot – gui2one May 08 '19 at 11:37

2 Answers2

3

The question was answered in the comments. I had to replace : int data[] by : unsigned char data[];

gui2one
  • 160
  • 1
  • 1
  • 14
2

=============== This part was not accurate. please see my solution part below ====

int data[w * h * channels_num]; is ok, that's not the reason you failed.

Change this line

stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, 100);

to

stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, w * sizeof(int));

You will get what you want. The last parameters, I believe it is stride. If so, stride means the offset between two lines. Based on your question, I assume you have 128 X 128 X 32bit color. Then stride will be w * sizeof(int).

If NOT, let me know.

Sorry I was in a hurry to rush to a meeting.

============ This part is the solution part ====

Yes,

int data[w * h * channels_num]; 

should be

unsigned char data[w * h * channels_num];

Plus,

stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, 100);

should be changed to

stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, w * channels_num);

Full solution

void save_image(int w, int h, int channels_num)
{
    unsigned char data[w * h * channels_num];

    int index = 0;
    for (int j = h - 1; j >= 0; --j)
    {
        for (int i = 0; i < w; ++i)
        {
            data[index++] = (unsigned char)(255.0 * i / w);
            data[index++] = (unsigned char)(255.0 * j / h);
            data[index++] = (unsigned char)(255.0 * 0.2);
        }
    }

    stbi_write_jpg("jpg_test_.jpg", w, h, channels_num, data, w * channels_num);
}
Tony
  • 632
  • 1
  • 4
  • 18
  • Sorry typo. should be w * sizeof(int). Just changed it. – Tony May 08 '19 at 11:27
  • No I think you're mistaken, this form seems to be for stbi_write_png – gui2one May 08 '19 at 11:35
  • _int data[w * h * channels_num]; is ok_ Really? This is not what I found in the doc. of this function in github: [stb_image_write.h](https://github.com/nothings/stb/blob/master/stb_image_write.h): _Each pixel contains 'comp' channels of data stored interleaved with 8-bits per channel_. Oops. I just realize that @Botje cited the exact same sentence... ;-) – Scheff's Cat May 08 '19 at 11:36