JPEG support with ijg - getting access violation

5k views Asked by At

I was recently trying to update my game to store graphics in compressed formats (JPEG and PNG).

Whilst I ended up settling on a different library, my initial attempt was to incorporate ijg to do JPEG decompression. However, I was unable to get even the simplest console application to work and am wondering if anyone might be able to shed some light on the reasons why.

Here is my code, which is linked to the jpeg.lib that is part of the ijg packages:

#include "stdafx.h"
#include <stdio.h>
#include <assert.h>
#include <jpeglib.h>

int _tmain(int argc, _TCHAR* argv[])
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPARRAY buffer;
    int row_stride;

    //initialize error handling
    cinfo.err = jpeg_std_error(&jerr);

    //initialize the decompression
    jpeg_create_decompress(&cinfo);

    FILE* infile;
    errno_t err = fopen_s(&infile, "..\\Sample.jpg", "rb");
    assert(err == 0);

    //specify the input
    jpeg_stdio_src(&cinfo, infile);

    //read headers
    (void) jpeg_read_header(&cinfo, TRUE);

    return 0;
}

The problem is that the call to jpeg_read_header() fails with an access violation:

Unhandled exception at 0x7c91b1fa (ntdll.dll) in JPEGTest.exe: 0xC0000005: Access violation writing location 0x00000010.

Does anyone have any ideas what I might be doing wrong?

7

There are 7 answers

1
Tal Pressman On BEST ANSWER

I've just encountered the same problem (although I was trying to encode an image). Apparently, FILE* are not portable between DLLs so you can't use any libjpeg API that takes a FILE* as a parameter.

There are several solutions, but they all come down to having to rebuild the library:

  • Build the library as a static lib, and link it to your application. This is what I did, and it solved my problem.
  • Move the source/destination handlers out of libjpeg and into your application. Then you could build libjpeg as either a static lib or a DLL, whichever suits you. I'm not sure whether this would work, but it is the suggested solution in the "install.doc" file distributed with the source code.
0
schedar On

This question is almost 10 years now, but exactly the same what author posted happened to me today (I'm using Visual Studio 2013).

Initially I tried to use the libjpeg library from GnuWin32: http://gnuwin32.sourceforge.net/packages/jpeg.htm and was getting the same error. Then noticed this is a "version 6b" of libJpeg, which is quite old now (2005) What worked for me was installing libJpeg through nuget pacakge manager:

Install-Package libjpeg -Version 9.2.0.1

0
Thanasis Papoutsidakis On

Here is a workaround without having to rebuild the library: Make replacement I/O functions, as André Caron stated, but have nothing in them but the standard stdio functions.

The code below I made in the past might help. It is written for libpng, but I believe it is easy to do the same in libjpeg.

I added this to the code:

    png_set_write_fn (png_ptr,file,replwrite,replflush);

Then created the replacement functions:

void replwrite (png_structp png_ptr, png_bytep data, png_size_t length)
{
    fwrite (data,1,length,(FILE*) png_get_io_ptr(png_ptr));
}

void replflush (png_structp png_ptr)
{
    fflush ((FILE*) png_get_io_ptr(png_ptr));
}

It always works for me. What I'm actually doing is telling libpng, "Hey, don't use the write functions from the MSVCR that your .dll points to, use these ones, that come from the MSVCR I use in my program, fwrite and fflush". You see it's basically a compatibility issue.

I hope this or something like this will solve the problem.

0
Mehdi Benkirane On

here is a tested function

void test(char FileName[])
{
    unsigned long x, y;
    struct jpeg_decompress_struct info; //for our jpeg info
    struct jpeg_error_mgr err;           //the error handler
    JSAMPARRAY buffer;
    FILE* infile;
    //initialize error handling
    info.err = jpeg_std_error(& err);     

    infile = fopen(FileName, "rb");  //open the file

    //if the jpeg file doesn't load
    if(!infile) {
    fprintf(stderr, "Error reading JPEG file %s!", FileName);
        // printf("Error reading JPEG file %s!", FileName);
        //return 0;
    }

    //initialize the decompression
    jpeg_create_decompress(&info);


    //specify the input
    jpeg_stdio_src(&info, infile);    

    //read headers
    jpeg_read_header(&info, TRUE);   // read jpeg file header

    jpeg_start_decompress(&info);    // decompress the file

    //set width and height
    x = info.output_width;
    y = info.output_height;

    printf("x value is %ul", x);
    printf("x value is %ul", y);
}
1
Henk On

It's difficult to see the cause of the access violation from the code sample given. If you can include a stack trace (with symbols) that would help identify the issue. One thing to verify is that the alignment settings for the .LIB and .EXE projects are consistent, this will often lead to nasty problems as struct/class members are not where the compiler expects them to be.

0
Hernán On

To work with images in multiple formats, let me recommend you DevIL as a library http://openil.sourceforge.net/. It's an excellent choice, as I've used it many times with excellent results. Beware that it's syntax is OpenGL-like.

The list of features:

Supports loading of:

  • .bmp
  • .cut
  • .dcx
  • .dds
  • .exr
  • .ico
  • .icns
  • .gif
  • .jpg
  • .jp2
  • .lbm
  • .lif
  • .mdl
  • .pcd
  • .pcx
  • .pic
  • .png
  • .pnm
  • .psd
  • .psp
  • .raw
  • .sgi
  • .tga
  • .tif
  • .wal
  • .act
  • .pal
  • .hdr
  • Doom graphics

Supports saving of:

  • .bmp
  • .dds
  • .jpg
  • .pcx
  • .png
  • .pnm
  • .raw
  • .sgi
  • .tga
  • .tif
  • .pal

Library Features

  • Portable, supports Windows, Mac OS X and *nix.
  • OpenGL-style syntax.
  • Use of image names instead of ugly pointers.
  • Loading from files, file streams or memory "lumps".
  • Direct access to data through ilGetData() and ilSetData().
  • Support for luminance, rgb(a), bgr(a) and colour-indexed images.
  • Support for 3 different numbers of bits per channel.
  • Conversion between all formats and datatypes (including palettes).
  • User-defined automatic conversions if desired when loading images.
  • Automatic conversion when saving images if needed.
  • Automatic conversion of colour-indexed images to truecolour images if desired.
  • Controllable compression when saving.
  • Maintains a state stack that can be pushed and popped.
  • Full support for 3d texture volumes (3d images).
  • Validation of images.
  • Support for layers.
  • Support for mipmaps.
  • Support for animations.
  • User-specified clear colour.
  • Can load a default image if loading fails.
  • User-specified hints.
  • Use of key colours.
  • Support for overlaying an image on top of another.
  • Allows the user to specify their own loading and saving callbacks, even overriding the default ones.
  • Support for user-specified read and write functions.
  • Delphi support.
  • Visual Basic support.
  • Linux support.
  • Can pick and choose which features will be used to create smaller dlls.
  • Choose whether to use the Intel Jpeg Library or libjpeg.
  • A whole host of effects and filters to apply to images, such as embossing and edge detection.
  • Images can be resized or even be put on a larger background (enlarged canvas).
  • OpenGL, Allegro, Windows GDI and DirectX API support.
2
Matthew Flaschen On

I agree with Hernán. This is not a good interface (I think the internal code itself is probably good), unless you really need to work low-level (and maybe not even then). I think ImageMagick is probably better. They have a "MagickWand" C interface that is more high level, not to mention that it supports many more formats.

However, I was curious about libjpeg's interface, so I got a test program working to my satisfaction, based on your example program as well as libjpeg.doc, the IJG example, and USING THE IJG JPEG LIBRARY. Anyway, here's the code. It just prints out the dimensions, and the RGB of the first pixel of every row.

I am very surprised you get an error with my code. It works fine for me, and compiles without any warnings. Can someone else test it?

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

int main(int argc, char* argv[])
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPARRAY buffer;
    int row_stride;

    //initialize error handling
    cinfo.err = jpeg_std_error(&jerr);

    FILE* infile;
    infile = fopen("Sample.jpg", "rb");
    assert(infile != NULL);

    //initialize the decompression
    jpeg_create_decompress(&cinfo);

    //specify the input
    jpeg_stdio_src(&cinfo, infile);

    //read headers
    (void) jpeg_read_header(&cinfo, TRUE);

    jpeg_start_decompress(&cinfo);

    printf("width: %d, height: %d\n", cinfo.output_width, cinfo.output_height);

    row_stride = cinfo.output_width * cinfo.output_components;

    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    JSAMPLE firstRed, firstGreen, firstBlue; // first pixel of each row, recycled
    while (cinfo.output_scanline < cinfo.output_height)
    {
    (void)jpeg_read_scanlines(&cinfo, buffer, 1);
    firstRed = buffer[0][0];
    firstBlue = buffer[0][1];
    firstGreen = buffer[0][2];
    printf("R: %d, G: %d, B: %d\n", firstRed, firstBlue, firstGreen);
    }

    jpeg_finish_decompress(&cinfo);

    return 0;
}