JPEG支持问题:使用ijg时出现访问冲突错误

3
我最近尝试更新 我的游戏,将图形存储为压缩格式(JPEG和PNG)。
虽然我最终选择了另一个库,但我最初的尝试是使用 ijg 来进行JPEG解压缩。然而,我无法使甚至最简单的控制台应用程序工作,并且想知道是否有人能够阐明原因。
这是我的代码,它链接到 ijg 包中的 jpeg.lib
#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;
}

问题在于调用 jpeg_read_header() 时出现了访问冲突导致失败:

未处理的异常 0xC0000005:访问位置 0x00000010 时写入权限错误, 在 JPEGTest.exe 中的 0x7c91b1fa (ntdll.dll)。

有人有任何想法我可能做错了什么吗?

1个问题--为什么你要两次初始化错误处理? - Marcin
我的错 - 我会更新我的帖子。 - Kent Boogaart
7个回答

7
我刚遇到了同样的问题(尽管我试图对图像进行编码)。显然,FILE*在DLL之间不可移植,因此您无法使用任何以FILE*作为参数的libjpeg API。
有几种解决方案,但它们都归结为必须重新构建库:
- 将库构建为静态库,并将其链接到您的应用程序。这就是我所做的,它解决了我的问题。 - 将源/目标处理程序从libjpeg中移出,并将其放入您的应用程序中。然后,您可以将libjpeg构建为静态库或DLL,以适合您的需要。我不确定这是否有效,但这是随源代码一起分发的“install.doc”文件中建议的解决方案。

为了后代,jpeglib支持使用自定义I/O处理程序,这意味着您不必重新构建库。然而,这通常比首先重建库更困难。 - André Caron

5

我同意Hernán的观点。这不是一个好的接口(我认为内部代码本身可能很好),除非你真的需要低级别的工作(甚至可能根本不需要)。我认为ImageMagick可能更好。他们有一个“MagickWand”C接口,更高级别,而且支持更多格式。

然而,我对libjpeg的接口很好奇,所以我基于您的示例程序以及libjpeg.docIJG exampleUSING THE IJG JPEG LIBRARY,得到了一个令我满意的测试程序。无论如何,这是代码。它只打印出每行的尺寸和第一个像素的RGB值。

我很惊讶你用我的代码会出错。它对我来说很好用,并且没有任何警告。还有其他人可以测试一下吗?

#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;
}

我知道ijg可能不是最好的库。正如我的问题中所述,我已经选择了另一个库。但是,我只是想理解这个问题。当我运行你的代码时,我仍然会得到相同的错误。 - Kent Boogaart
我知道已经过去了四年,但您有没有关于如何像上面的代码一样“写入”RGB值到JPEG的建议? - Yeezus

2

以下是一种无需重建库的解决方法:像André Caron所述,制作替换I/O函数,但在其中仅使用标准stdio函数。

我过去编写的下面代码可能会有所帮助。 它是为libpng编写的,但我相信在libjpeg中做同样的事情很容易。

我将此添加到了代码中:

    png_set_write_fn (png_ptr,file,replwrite,replflush);

然后创建替换函数:

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));
}

这对我总是有效的。实际上,我所做的是告诉libpng:“嘿,不要使用你的.dll指向的MSVCR的写函数,而是使用来自我程序中使用的MSVCR的这些函数,即fwrite和fflush”。你可以看到这基本上是一个兼容性问题。

我希望这个方法或类似的方法可以解决问题。


1

从给出的代码示例中很难看出访问冲突的原因。如果您可以包含一个带符号的堆栈跟踪,那么这将有助于确定问题所在。 需要验证的一件事是,.LIB 和 .EXE 项目的对齐设置是否一致,否则结构体/类成员可能不在编译器期望的位置,这通常会导致严重问题。


没错。libjpeg非常稳定,本身不应该导致内存违规。问题应该是与libjpeg无关的外部因素引起的。 - PolyThinker

0

这里有一个经过测试的函数

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);
}

0

为了处理多种格式的图像,我向您推荐DevIL库http://openil.sourceforge.net/。这是一个很好的选择,因为我用它很多次都取得了很好的结果。请注意,它的语法类似于OpenGL。

功能列表:

支持加载以下文件格式:

  • .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

支持保存以下文件格式:

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

库特点

  • 可移植,支持Windows、Mac OS X和*nix。
  • OpenGL风格的语法。
  • 使用图像名称而不是丑陋的指针。
  • 从文件、文件流或内存“块”加载。
  • 通过ilGetData()和ilSetData()直接访问数据。
  • 支持亮度、rgb(a)、bgr(a)和颜色索引图像。
  • 支持3种不同的每通道比特数。
  • 在所有格式和数据类型之间进行转换(包括调色板)。
  • 在加载图像时,如果需要,支持用户定义的自动转换。
  • 保存图像时自动转换(如果需要)。
  • 如果需要,将颜色索引图像自动转换为真彩色图像。
  • 在保存时可控压缩。
  • 维护可以推送和弹出的状态堆栈。
  • 完全支持3D纹理体积(3D图像)。
  • 验证图像。
  • 支持图层。
  • 支持mipmaps。
  • 支持动画。
  • 用户指定的清除颜色。
  • 如果加载失败,可以加载默认图像。
  • 用户指定的提示。
  • 使用关键颜色。
  • 支持在另一张图像上叠加图像。
  • 允许用户指定自己的加载和保存回调,甚至覆盖默认回调。
  • 支持用户指定的读取和写入函数。
  • Delphi支持。
  • Visual Basic支持。
  • Linux支持。
  • 可以选择使用哪些功能来创建较小的dll。
  • 选择是否使用Intel Jpeg库或libjpeg。
  • 大量的效果和过滤器可应用于图像,如浮雕和边缘检测。
  • 图像可以调整大小,甚至可以放在更大的背景上(扩大画布)。
  • 支持OpenGL、Allegro、Windows GDI和DirectX API。

0

这个问题已经存在了将近10年,但与作者发布的完全相同的情况今天也发生在了我身上(我正在使用Visual Studio 2013)。

最初我尝试使用GnuWin32中的libjpeg库:http://gnuwin32.sourceforge.net/packages/jpeg.htm,但是我得到了相同的错误。 然后注意到这是一个相当古老的libJpeg“版本6b”(2005年)。 对我有用的是通过NuGet包管理器安装libJpeg:

Install-Package libjpeg -Version 9.2.0.1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接