tags:

views:

4003

answers:

8

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!

+10  A: 

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
+3  A: 

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
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
+2  A: 

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.

Colin
+4  A: 

this is a small routine i digged from 10 year old source code (using libjpg):

#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");
    reurn 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;
Depht = 32;
}
Peter Parker
+1 Waw thanks a lot! Will consider for answer. :)
nbolton
hi wat r the header files to be added for using libjpeg related functions?
suresh
#include <jpeglib.h>
nbolton
added the header..
Peter Parker
A: 

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
+1  A: 

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

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

X-Istence
A: 

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.

mloskot