如何在Linux上用C ++读取JPEG和PNG像素?

我正在做一些image processing,我想单独读取JPEG和PNG图像中的每个像素值。

在我的部署场景中,使用第三方库(因为我在目标计算机上有限制访问)对我来说会很尴尬,但是我假设没有用于读取JPEG / PNG的标准C或C ++库…

所以,如果你知道一个使用图书馆的方法,那么很好,如果不是,那么答案仍然是值得欢迎的!

C标准中没有标准库来读取文件格式。

但是,大多数程序,特别是在Linux平台上,使用相同的库来解码图像格式:

对于JPEG,它是libjpeg,PNG是libpng。

libs已经安装的可能性非常高。

http://www.libpng.org

http://www.ijg.org

这是我从10岁的源代码挖掘出来的一个小例程(使用libjpeg):

#include <jpeglib.h> int loadJpg(const char* Name) { unsigned char a, r, g, b; int width, height; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE * infile; /* source file */ JSAMPARRAY pJpegBuffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ if ((infile = fopen(Name, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", Name); return 0; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); width = cinfo.output_width; height = cinfo.output_height; unsigned char * pDummy = new unsigned char [width*height*4]; unsigned char * pTest = pDummy; if (!pDummy) { printf("NO MEM FOR JPEG CONVERT!\n"); return 0; } row_stride = width * cinfo.output_components; pJpegBuffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, pJpegBuffer, 1); for (int x = 0; x < width; x++) { a = 0; // alpha value is not supported on jpg r = pJpegBuffer[0][cinfo.output_components * x]; if (cinfo.output_components > 2) { g = pJpegBuffer[0][cinfo.output_components * x + 1]; b = pJpegBuffer[0][cinfo.output_components * x + 2]; } else { g = r; b = r; } *(pDummy++) = b; *(pDummy++) = g; *(pDummy++) = r; *(pDummy++) = a; } } fclose(infile); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); BMap = (int*)pTest; Height = height; Width = width; Depth = 32; } 

对于jpeg,已经有一个名为libjpeg的库,并且有png的libpng 。 好消息是他们编译正确,所以目标机器不需要DLL文件或任何东西。 坏消息是他们在C 🙁

另外,甚至不要试图自己读取 文件 。 如果您想要一个易于阅读的格式,请改用PPM 。

不幸的是,JPEG格式是压缩的,所以你必须在读取单个像素之前解压缩它。 这是一个不平凡的任务。 如果你不能使用库,你可能想引用一个来看看它是如何解压图像。 sourceforge 上有一个开源的库: sourceforge上的CImg。

由于它可以使用这种风险,我会提到另外一个图书馆来进行调查: IM Toolkit ,在Sourceforge上托管。 它是跨平台的,并将文件格式从用户中完全抽象出来,允许加载和处理图像,而不用担心大部分细节。 它确实支持PNG和JPEG两种格式,如果需要,可以使用其他导入过滤器进行扩展。

它配备了大量的图像处理操作员以及…

它也有一个很好的质量绑定到Lua 。

正如Nils所指出的,对于JPEG压缩和图像处理来说,不存在C或C ++标准库。

如果你能够使用第三方库,你可能想尝试支持JPEG,PNG和其他几十种其他格式,压缩和媒体的GDAL 。

下面是一个简单的例子,介绍如何使用GDAL C ++ API从JPEG文件读取像素数据:

 #include <gdal_priv.h> #include <cassert> #include <iostream> #include <string> #include <vector> int main() { GDALAllRegister(); // once per application // Assume 3-band image with 8-bit per pixel per channel (24-bit depth) std::string const file("/home/mloskot/test.jpg"); // Open file with image data GDALDataset* ds = static_cast<GDALDataset*>(GDALOpen(file.c_str(), GA_ReadOnly)); assert(0 != ds); // Example 1 - Read multiple bands at once, assume 8-bit depth per band { int const ncols = ds->GetRasterXSize(); int const nrows = ds->GetRasterYSize(); int const nbands = ds->GetRasterCount(); int const nbpp = GDALGetDataTypeSize(GDT_Byte) / 8; std::vector<unsigned char> data(ncols * nrows * nbands * nbpp); CPLErr err = ds->RasterIO(GF_Read, 0, 0, ncols, nrows, &data[0], ncols, nrows, GDT_Byte, nbands, 0, 0, 0, 0); assert(CE_None == err); // ... use data } // Example 2 - Read first scanline by scanline of 1 band only, assume 8-bit depth per band { GDALRasterBand* band1 = ds->GetRasterBand(1); assert(0 != band1); int const ncols = band1->GetXSize(); int const nrows = band1->GetYSize(); int const nbpp = GDALGetDataTypeSize(GDT_Byte) / 8; std::vector<unsigned char> scanline(ncols * nbpp); for (int i = 0; i < nrows; ++i) { CPLErr err = band1->RasterIO(GF_Read, 0, 0, ncols, 1, &scanline[0], ncols, 1, GDT_Byte, 0, 0); assert(CE_None == err); // ... use scanline } } return 0; } 

有更完整的GDAL API教程可用。

我已经有了与DevIL图书馆的良好经验。 它支持多种图像格式,并遵循与OpenGL非常相似的功能风格。

当然,这是一个图书馆,但绝对值得一试。

由于其他答案已经提到,你很可能需要使用库,看看ImageMagick ,看看是否有可能做你需要做的。 它具有多种不同的方法来与ImageMagick的核心功能进行交互,包括几乎所有可用编程语言的库。

主页: ImageMagick

如果速度不是问题,你可以尝试LodePNG ,采取极简主义的方式来加载和保存PNG。

甚至可以从同一个作者的picoPNG开始,它是一个函数中的独立png加载器。