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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/694080/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:09:58  来源:igfitidea点击:

How do I read JPEG and PNG pixels in C++ on Linux?

c++clinuxpngjpeg

提问by Nick Bolton

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

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

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

因此,如果您知道一种使用库的方法,那就太好了,如果不知道,那么仍然欢迎回答!

采纳答案by Nils Pipenbrinck

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

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

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

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

http://www.libpng.org

http://www.libpng.org

http://www.ijg.org

http://www.ijg.org

回答by rlbond

For jpeg, there is already a library called libjpeg, and there is libpngfor 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,且有libpng的对PNG。好消息是它们可以直接编译,因此目标机器不需要 dll 文件或任何东西。坏消息是它们在 C 中 :(

Also, don't even think of trying to readthe filesyourself. If you want an easy-to-read format, use PPMinstead.

此外,甚至不要想尝试自己阅读文件。如果您想要易于阅读的格式,请改用PPM

回答by Colin

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有一个开源库:sourceforge上的CImg。

回答by Peter Parker

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

回答by Daniel Sloof

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

我在DevIL库方面有很好的经验。它支持多种图像格式,并遵循与 OpenGL 非常相似的函数风格。

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

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

回答by RBerteig

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.

由于它可以使用曝光,我将提到另一个要调查的库:IM Toolkit,它托管在Sourceforge 上。它是跨平台的,并且将文件格式完全从用户中抽象出来,允许加载和处理图像而无需担心大多数细节。它开箱即用地支持 PNG 和 JPEG,并且可以根据需要使用其他导入过滤器进行扩展。

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

它还配备了大量的图像处理运算符......

It also has a good quality binding to Lua.

它还具有良好的质量绑定到Lua

回答by X-Istence

Since the other answers already mention that you will most likely need to use a library, take a look at ImageMagickand 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

回答by mloskot

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 GDALwhich supports JPEG, PNG and tens of other formats, compressions and mediums.

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

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

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

回答by Gigi

If speed is not a problemyou can try LodePNGthat 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 加载器。