1

I have the following code running on windows 10 in QT Creator, I am trying to write rgb formatted data to a jpeg file using the libjpeg-turbo library

#include <stdio.h>
#include <jpeglib.h>

void writeJpeg(const char *filename, std::vector<unsigned char> &image, uint w, uint h) {
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE *outfile;
    JSAMPROW row_pointer[1];
    int row_stride;

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_compress(&cinfo);

    if ((outfile = fopen(filename, "wb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    exit(1);
    }
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = w;
    cinfo.image_height = h;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, 100, true);


    jpeg_start_compress(&cinfo, true);


    row_stride = w * 3;

    JSAMPLE *arr = image.data();


    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }



    jpeg_finish_compress(&cinfo);

    fclose(outfile);


    jpeg_destroy_compress(&cinfo);
}

and get SIGSEGV on (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); in this portion of the code

while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }

I have tried debugging, but im not entirely sure what the best way to do that is.

I have found out that it crashes after 15 iterations of the loop and my best guess is that I have converted the data poorly from the vector into the pointer array.

Anyways, I cannot figure out how to better allocate the memory or if this is even the problem

Any ideas on what I'm doing wrong plus any tips on how to actually debug this in the future would be greatly appreciated.

EDIT

I changed true to TRUE and printed out every byte in the array like so

while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];

        QString out = "";
        for (int i = 0; i<row_stride; i++)
            out += QString::number(row_pointer[0][i]) + " ";
        qDebug() << "\n\n==============" << cinfo.next_scanline << "==============\n\n";
        qDebug() << out;


        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }

and after stepping through its execution, it is able to output all the bytes, yet still crashes on write_jpeg_scanlines

I also noticed some random text being printed out at the end of each scanline ex: 255 255 255 25520003200!-�U3 on row 12

255 255 255 255eencoded�/�Rf on row 13

231 230 230 255,autoder�)�Pu on row 15, the data where it crashes

not sure if this is just garbage at the end of the pointer, or a symptom of qDebug but it could confirm antons idea of corrupted image data

  • Can you try smaller values of `row_stride`? Try half of what you're currently using which is `w * 3`. Try maybe `( w * 3 ) / 2 `. I'm more interested in if that stops the `segfault` then if the image is correctly produced. – WBuck Aug 30 '21 at 22:07
  • i tried setting ```row_stride = (w*3)/2;``` and also changed the while loop to be ```cinfo.next_scanline < cinfo.image_height/2``` both still resulted in a segfault. I also tried dividing both the width and the height by two at the start of the function which also lead to a fault. – Ethan Armstrong Aug 30 '21 at 23:21
  • I just tried setting the ```w``` and ```h``` to ```1``` at the beginning of the function and the program no longer faults on ```jpeg_write_scanlines``` and instead at ```jpeg_finish_compress``` – Ethan Armstrong Aug 30 '21 at 23:22

2 Answers2

1

I see nothing wrong in your code, except C++ bool value true is passed instead of C value TRUE in these calls:

    jpeg_set_quality(&cinfo, 100, true);
    ...
    jpeg_start_compress(&cinfo, true);

It may lead to weird crashes sometimes.

Also, the first thing I would try in this case - what if just to output somewhere all the bytes of every row arr[cinfo.next_scanline * row_stride] - does it crash? If it does, possibly you have error in other code preparing the image data.

UPD.: most probably the problem with original code was #include <jpeglib.h> - that should force to search for jpeglib.h in system directories instead of the libjpeg-turbo directories. That could be solved by using #include "jpeglib.h" and specifying the path to libjpeg-turbo include directory to compiler.

Anton Malyshev
  • 8,686
  • 2
  • 27
  • 45
  • I updated the question, What do you think the best way to fill the array with data, probably all 255 bytes, to rule out the corrupted data – Ethan Armstrong Aug 30 '21 at 21:26
  • @EthanArmstrong then probably it's just an error with libjpeg integration itself, like you used headers from one version and binaries from another – Anton Malyshev Aug 31 '21 at 10:28
0

Thanks for all of the help, As @AntonMalyshev pointed out, the issue was an incorrect use of libjpeg.

First off I have libjpeg-turbo installed and while it includes a library for libjpeg im sure a better practice would be to just install libjpeg directly. I ended up using #include <turbojpeg.h>.

Secondly, the example code I posted, seems to be only compatible with base libjpeg Using this post and the libjpeg-turbo api I was able to come up with a solution that works.

Thanks, Ethan

  • Glad that you've found the solution. However I used the exact same code as yours with libjpeg-turbo and it worked. The libjpeg-turbo contains two API variants - the one compatible with libjpeg ("jpeglib.h) and its own ("turbojpeg.h"). When you use the first one though, you need to make sure that you are including "jpeglib.h" from libjpeg-turbo version you use, not from the system or other libjpeg/libjpeg-turbo version. – Anton Malyshev Sep 01 '21 at 10:25
  • I updated the answer with the information how to fix the original code. – Anton Malyshev Sep 01 '21 at 10:33
  • Yep, your exactly right, I have an old install of libjpeg installed. – Ethan Armstrong Sep 01 '21 at 10:35