我如何在Linux的c++中读取JPEG和PNG像素?

时间:2023-01-24 21:22:49

I'm doing some image processing, and I'd like to individually read each pixel value in a JPEG and PNG images.

我正在进行一些图像处理,我想分别读取JPEG和PNG图像中的每个像素值。

In my deployment scenario, it would be awkward for me to use a 3rd party library (as I have restricted access on the target computer), but I'm assuming that there's no standard C or C++ library for reading JPEG/PNG...

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

So, if you know of a way of not using a library then great, if not then answers are still welcome!

所以,如果你知道一种不用图书馆的方法,那就太好了,如果不是,那么答案仍然是受欢迎的!

9 个解决方案

#1


20  

There is no standard library in the C-standard to read the file-formats.

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

However, most programs, especially on the linux platform use the same library to decode the image-formats:

然而,大多数程序,尤其是linux平台上的程序,使用相同的库来解码图像格式:

For jpeg it's libjpeg, for png it's libpng.

jpeg是libjpeg, png是libpng。

The chances that the libs are already installed is very high.

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

http://www.libpng.org

http://www.libpng.org

http://www.ijg.org

http://www.ijg.org

#2


19  

This is a small routine I digged from 10 year old source code (using libjpeg):

这是我从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;
}

#3


5  

For jpeg, there is already a library called libjpeg, and there is libpng for png. The good news is that they compile right in and so target machines will not need dll files or anything. The bad news is they are in C :(

对于jpeg,已经有一个名为libjpeg的库,还有用于png的libpng。好消息是它们可以直接编译,因此目标机器将不需要dll文件或任何东西。坏消息是他们在C:

Also, don't even think of trying to read the files yourself. If you want an easy-to-read format, use PPM instead.

同样,你也不要想自己去读这些文件。如果您想要一种易于阅读的格式,请使用PPM代替。

#4


4  

Unfortunately, jpeg format is compressed, so you would have to decompress it before reading individual pixels. This is a non-trivial task. If you can't use a library, you may want to refer to one to see how it's decompressing the image. There is an open-source library on sourceforge: CImg on sourceforge.

不幸的是,jpeg格式被压缩了,所以您必须在读取单个像素之前对其进行解压。这是一项重要的任务。如果您不能使用库,您可能希望引用一个库来查看它是如何解压缩映像的。在sourceforge上有一个开源的图书馆:CImg在sourceforge上。

#5


2  

Since it could use the exposure, I'll mention one other library to investigate: The IM Toolkit, which is hosted at Sourceforge. It is cross platform, and abstracts the file format completely away from the user, allowing an image to be loaded and processed without worrying about most of the details. It does support both PNG and JPEG out of the box, and can be extended with other import filters if needed.

由于它可能会使用公开,因此我将介绍另一个库:位于Sourceforge上的IM工具包。它是跨平台的,将文件格式从用户那里完全抽象出来,允许加载和处理图像,而不必担心大部分细节。它既支持PNG和JPEG,也可以在需要时使用其他导入过滤器进行扩展。

It comes with a large collection of image processing operators as well...

它还有大量的图像处理操作符……

It also has a good quality binding to Lua.

它与Lua的结合质量也很好。

#6


2  

As Nils pointed, there is no such thing as a C or C++ standard library for JPEG compression and image manipulation.

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

In case you'd be able to use a third party library, you may want to try GDAL which supports JPEG, PNG and tens of other formats, compressions and mediums.

如果您能够使用第三方库,您可能需要尝试GDAL,它支持JPEG、PNG以及其他几十种格式、压缩和中介。

Here is simple example that presents how to read pixel data from JPEG file using GDAL C++ API:

下面是一个简单的示例,演示如何使用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;
}

There is more complete GDAL API tutorial available.

还有更完整的GDAL API教程。

#7


1  

I've had good experiences with the DevIL library. It supports a wide range of image formats and follows a function-style very similar to OpenGL.

我在魔鬼图书馆有过很好的经历。它支持多种图像格式,并遵循与OpenGL非常相似的函数样式。

Granted, it is a library, but it's definitely worth a try.

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

#8


1  

Since the other answers already mention that you will most likely need to use a library, take a look at ImageMagick and see if it is possible to do what you need it to do. It comes with a variety of different ways to interface with the core functionality of ImageMagick, including libraries for almost every single programming language available.

因为其他的答案已经提到,你很可能需要使用一个库,看看ImageMagick,看看是否有可能做你需要它做的事情。它提供了多种与ImageMagick的核心功能交互的方法,包括几乎所有可用的编程语言的库。

Homepage: ImageMagick

主页:ImageMagick

#9


1  

If speed is not a problem you can try LodePNG that take a very minimalist approach to PNG loading and saving.

如果速度不是问题,您可以尝试LodePNG,采用非常简单的方法加载和保存PNG。

Or even go with picoPNG from the same author that is a self-contained png loader in a function.

甚至可以使用picoPNG,它来自于函数中的一个自包含png装入器。

#1


20  

There is no standard library in the C-standard to read the file-formats.

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

However, most programs, especially on the linux platform use the same library to decode the image-formats:

然而,大多数程序,尤其是linux平台上的程序,使用相同的库来解码图像格式:

For jpeg it's libjpeg, for png it's libpng.

jpeg是libjpeg, png是libpng。

The chances that the libs are already installed is very high.

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

http://www.libpng.org

http://www.libpng.org

http://www.ijg.org

http://www.ijg.org

#2


19  

This is a small routine I digged from 10 year old source code (using libjpeg):

这是我从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;
}

#3


5  

For jpeg, there is already a library called libjpeg, and there is libpng for png. The good news is that they compile right in and so target machines will not need dll files or anything. The bad news is they are in C :(

对于jpeg,已经有一个名为libjpeg的库,还有用于png的libpng。好消息是它们可以直接编译,因此目标机器将不需要dll文件或任何东西。坏消息是他们在C:

Also, don't even think of trying to read the files yourself. If you want an easy-to-read format, use PPM instead.

同样,你也不要想自己去读这些文件。如果您想要一种易于阅读的格式,请使用PPM代替。

#4


4  

Unfortunately, jpeg format is compressed, so you would have to decompress it before reading individual pixels. This is a non-trivial task. If you can't use a library, you may want to refer to one to see how it's decompressing the image. There is an open-source library on sourceforge: CImg on sourceforge.

不幸的是,jpeg格式被压缩了,所以您必须在读取单个像素之前对其进行解压。这是一项重要的任务。如果您不能使用库,您可能希望引用一个库来查看它是如何解压缩映像的。在sourceforge上有一个开源的图书馆:CImg在sourceforge上。

#5


2  

Since it could use the exposure, I'll mention one other library to investigate: The IM Toolkit, which is hosted at Sourceforge. It is cross platform, and abstracts the file format completely away from the user, allowing an image to be loaded and processed without worrying about most of the details. It does support both PNG and JPEG out of the box, and can be extended with other import filters if needed.

由于它可能会使用公开,因此我将介绍另一个库:位于Sourceforge上的IM工具包。它是跨平台的,将文件格式从用户那里完全抽象出来,允许加载和处理图像,而不必担心大部分细节。它既支持PNG和JPEG,也可以在需要时使用其他导入过滤器进行扩展。

It comes with a large collection of image processing operators as well...

它还有大量的图像处理操作符……

It also has a good quality binding to Lua.

它与Lua的结合质量也很好。

#6


2  

As Nils pointed, there is no such thing as a C or C++ standard library for JPEG compression and image manipulation.

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

In case you'd be able to use a third party library, you may want to try GDAL which supports JPEG, PNG and tens of other formats, compressions and mediums.

如果您能够使用第三方库,您可能需要尝试GDAL,它支持JPEG、PNG以及其他几十种格式、压缩和中介。

Here is simple example that presents how to read pixel data from JPEG file using GDAL C++ API:

下面是一个简单的示例,演示如何使用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;
}

There is more complete GDAL API tutorial available.

还有更完整的GDAL API教程。

#7


1  

I've had good experiences with the DevIL library. It supports a wide range of image formats and follows a function-style very similar to OpenGL.

我在魔鬼图书馆有过很好的经历。它支持多种图像格式,并遵循与OpenGL非常相似的函数样式。

Granted, it is a library, but it's definitely worth a try.

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

#8


1  

Since the other answers already mention that you will most likely need to use a library, take a look at ImageMagick and see if it is possible to do what you need it to do. It comes with a variety of different ways to interface with the core functionality of ImageMagick, including libraries for almost every single programming language available.

因为其他的答案已经提到,你很可能需要使用一个库,看看ImageMagick,看看是否有可能做你需要它做的事情。它提供了多种与ImageMagick的核心功能交互的方法,包括几乎所有可用的编程语言的库。

Homepage: ImageMagick

主页:ImageMagick

#9


1  

If speed is not a problem you can try LodePNG that take a very minimalist approach to PNG loading and saving.

如果速度不是问题,您可以尝试LodePNG,采用非常简单的方法加载和保存PNG。

Or even go with picoPNG from the same author that is a self-contained png loader in a function.

甚至可以使用picoPNG,它来自于函数中的一个自包含png装入器。