22

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

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

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

Nick Bolton
  • 38,276
  • 70
  • 174
  • 242

9 Answers9

24

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

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

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

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

http://www.libpng.org

http://www.ijg.org

Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
20

This is a small routine I digged from 10 year old source code (using 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;
}
Étienne
  • 4,773
  • 2
  • 33
  • 58
Peter Parker
  • 29,093
  • 5
  • 52
  • 80
  • hi wat r the header files to be added for using libjpeg related functions? – suresh Mar 29 '09 at 17:56
  • It would be helpful to have a small example on how to call this function in a program. Where is the output stored and how? Actually, this function appears to have declaration errors, and also does not return anything. – user3236841 Apr 02 '22 at 02:00
7

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 :(

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

rlbond
  • 65,341
  • 56
  • 178
  • 228
  • 7
    How is it bad news that they're in C? It's much easier to use C libraries in C++ than C libraries in Perl, Python, Java, or C#. And much easier than trying to use any of those from C++. – Chris Lutz Mar 29 '09 at 05:16
  • I once had to write a JPEG decoder in Java for a class assignment. It was a murderous task (and Java didn't make it any easier, let me tell you that), but nevertheless gave me a lot of insight into the format and Huffman coding itself. Trying to do something like that yourself is certainly an overkill, unless you've got very tight memory/speed requirements, for example when coding for a severely limited embedded system. – Daniel Kamil Kozar Jul 09 '13 at 10:28
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.

Paul
  • 6,435
  • 4
  • 34
  • 45
2

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

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.

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

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

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
mloskot
  • 37,086
  • 11
  • 109
  • 136
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.

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

It also has a good quality binding to Lua.

RBerteig
  • 41,948
  • 7
  • 88
  • 128
1

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

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

Gigi
  • 4,953
  • 24
  • 25
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.

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

Daniel Sloof
  • 12,568
  • 14
  • 72
  • 106
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.

Homepage: ImageMagick

Community
  • 1
  • 1
X-Istence
  • 16,324
  • 6
  • 57
  • 74