需要帮助在读取JPEG文件使用libjpeg
Need help in reading JPEG file using libjpeg
我按照libjpeg示例文件中的示例代码进行操作,但是我无法读取图像数据。
我有下面的结构体,我创建了这个结构体的一个实例。
struct ImageData {
unsigned char *pixels;
long width;
long height;
};
ImageData *imageData;
下面是我的read_JPEG_file函数:
int read_JPEG_file (char * filename)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
/* More stuff */
FILE * infile; /* source file */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %sn", filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
(void) jpeg_read_header(&cinfo, TRUE);
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
/* Step 5: Start decompressor */
(void) jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
imageData = new ImageData;
imageData->width = cinfo.output_width;
imageData->height = cinfo.output_height;
imageData->pixels = new unsigned char [cinfo.output_width * cinfo.output_height * cinfo.output_components];
long counter = 0;
//step 6, read the image line by line
while (cinfo.output_scanline < cinfo.output_height) {
//IT ALWAYS crash ON THIS JPEG_READ_SCANLINES FUNCTION CALL BELOW
(void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY)(imageData->pixels), 1);
counter +=row_stride;
}
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&cinfo);
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
fclose(infile);
/* And we're done! */
return 1;
}
在上面的步骤6中,这个JPEG_READ_SCANLINES函数总是失败。我在那条线上收到了"EXC_BAD_ACCESS"信号。
有没有人有任何想法,或者有一些工作的例子在阅读。jpg文件与libjpeg,你可以在这里分享?我已经检查了我的imageData->像素的大小,并将其与jpeg文件本身的大小进行了比较,它具有相同的大小。这个变量的内存也是动态分配的,所以我知道这不是内存问题。
任何想法?
下面是读取jpeg图像的示例:
/***************************************************
To read a jpg image file and download
it as a texture map for openGL
Derived from Tom Lane's example.c
-- Obtain & install jpeg stuff from web
(jpeglib.h, jerror.h jmore.h, jconfig.h,jpeg.lib)
****************************************************/
#include <jpeglib.h>
#include <jerror.h>
//================================
GLuint LoadJPEG(char* FileName)
//================================
{
unsigned long x, y;
unsigned int texture_id;
unsigned long data_size; // length of the file
int channels; // 3 =>RGB 4 =>RGBA
unsigned int type;
unsigned char * rowptr[1]; // pointer to an array
unsigned char * jdata; // data for the image
struct jpeg_decompress_struct info; //for our jpeg info
struct jpeg_error_mgr err; //the error handler
FILE* file = fopen(FileName, "rb"); //open the file
info.err = jpeg_std_error(& err);
jpeg_create_decompress(& info); //fills info structure
//if the jpeg file doesn't load
if(!file) {
fprintf(stderr, "Error reading JPEG file %s!", FileName);
return 0;
}
jpeg_stdio_src(&info, file);
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;
channels = info.num_components;
type = GL_RGB;
if(channels == 4) type = GL_RGBA;
data_size = x * y * 3;
//--------------------------------------------
// read scanlines one at a time & put bytes
// in jdata[] array. Assumes an RGB image
//--------------------------------------------
jdata = (unsigned char *)malloc(data_size);
while (info.output_scanline < info.output_height) // loop
{
// Enable jpeg_read_scanlines() to fill our jdata array
rowptr[0] = (unsigned char *)jdata + // secret to method
3* info.output_width * info.output_scanline;
jpeg_read_scanlines(&info, rowptr, 1);
}
//---------------------------------------------------
jpeg_finish_decompress(&info); //finish decompressing
//----- create OpenGL tex map (omit if not needed) --------
glGenTextures(1,&texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
gluBuild2DMipmaps(GL_TEXTURE_2D,3,x,y,GL_RGB,GL_UNSIGNED_BYTE,jdata);
jpeg_destroy_decompress(&info);
fclose(file); //close the file
free(jdata);
return texture_id; // for OpenGL tex maps
}
jpeg_read_scanlines函数接收一个指针数组(不是像imageData->pixels那样的像素直接指针)。所以我们应该先创建一个JSAMPARRAY:
int buffer_height = 1;
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * buffer_height);
buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
在你的代码中,你用"cinfo"创建了一个"缓冲区"。Mem -> alloc_array ",但你从不使用它。最后一步是传递"buffer"作为jpeg_read_scanlines的参数:
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(imageData->pixels+counter, buffer[0], row_stride);
counter += row_stride;
}
看到我们正在使用"imageData->pixels+counter",而不仅仅是"imageData->pixels"在你的代码。通过这种方式,我们在整个"imageData->pixels"内存块中逐行写入。
就像dacap说的,它期待一个JSAMPARRAY。也就是说,如果愿意,可以直接写入imageData->pixels数组。你只需要做这样的事情:
// Allocate imageData->pixels to be the correct size, start decompress and all
// that jazz, like you did in your code. Skip allocating buffer though.
// ...
JSAMPROW output_data;
unsigned int scanline_len = cinfo.output_width * cinfo.output_components;
unsigned int scanline_count = 0;
while (cinfo.output_scanline < cinfo.output_height)
{
output_data = (imageData->pixels + (scanline_count * scanline_len));
jpeg_read_scanlines(&cinfo, &output_data, 1);
scanline_count++;
}
您可以完全跳过分配缓冲区。使用内存可以很好地工作,但是如果没有必要,为什么要进行额外的复制呢?
下面是Jim整理的代码版本。它还使用cim作为输出格式,这使得如何提取RGB值更加明确。
CImg<unsigned char> *ReadJpegIntoCImg( const char *path )
{
FILE *file = fopen( path, "rb" );
if ( file == NULL )
{
return NULL;
}
struct jpeg_decompress_struct info; //for our jpeg info
struct jpeg_error_mgr err; //the error handler
info.err = jpeg_std_error( &err );
jpeg_create_decompress( &info ); //fills info structure
jpeg_stdio_src( &info, file );
jpeg_read_header( &info, true );
jpeg_start_decompress( &info );
unsigned int w = info.output_width;
unsigned int h = info.output_height;
unsigned int numChannels = info.num_components; // 3 = RGB, 4 = RGBA
unsigned long dataSize = w * h * numChannels;
// read RGB(A) scanlines one at a time into jdata[]
unsigned char *data = (unsigned char *)malloc( dataSize );
unsigned char* rowptr;
while ( info.output_scanline < h )
{
rowptr = data + info.output_scanline * w * numChannels;
jpeg_read_scanlines( &info, &rowptr, 1 );
}
jpeg_finish_decompress( &info );
jpeg_destroy_decompress( &info );
fclose( file );
// this code block is only if you happen to want output in CImg format, but is illustrative
CImg<unsigned char> *image = new CImg<unsigned char>( w, h, 1, numChannels );
for ( int x = 0 ; x < w ; x++ )
{
for ( int y = 0 ; y < h ; y++ )
{
for ( int c = 0 ; c < numChannels ; c++ )
{
*image->data( x, y, 0, c ) = data[ y * w * numChannels + x * numChannels + c ];
}
}
}
free( data );
return image;
}
另外,对于那些可能被我同样的问题困住的人来说,当从c++使用libjpeg时,重要的是要有一个包含
的jpeglib.h版本。#ifdef __cplusplus
extern "C" {
#endif
我使用的文件版本没有这个,并且得到链接错误。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 如何使用ndk-build.cmd构建Android.so文件
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 读取文件并输入到矢量中
- 在C++中查找文件
- c++库的公共头文件中应该包含什么
- 在Visual Studio C++2017中链接libjpeg-turbo要包含哪些文件
- JPEG编码位图(BMP)图像从文件使用libjpeg / C++
- (C/C++) libjpeg,缺少"Release.obj"文件
- 提供带有libjpeg的自定义文件IO
- libjpegTurbo: libjpeg-62文件无法识别
- 需要帮助在读取JPEG文件使用libjpeg