JPEG image rotation in C++ using libjpeg - c++

I am trying to rotate a JPEG image in C++ using libjpeg v9 based on the "Orientation" parameter present in EXIF metadata. I am able to get the "Orientation" parameter and on its basis, i am also able to rotate image into another file so that rotated image corresponds to "Orientation" value 1.
See code, which i have taken from "jpegtran.c" file and working fine(reading EXIF metadata code is not present):
#include <iostream>
#include <jpeglib.h>
#include <jerror.h>
#include "transupp.h"
void setTransformation(jpeg_transform_info *transformObj, JXFORM_CODE transformation){
transformObj->perfect = FALSE;
transformObj->trim = FALSE;
transformObj->force_grayscale = FALSE;
transformObj->crop = FALSE;
transformObj->transform = transformation;
}
void releaseRes(j_decompress_ptr srcPtr, j_compress_ptr destPtr){
jpeg_finish_compress(destPtr);
jpeg_destroy_compress(destPtr);
(void) jpeg_finish_decompress(srcPtr);
jpeg_destroy_decompress(srcPtr);
}
void rotateImage(const char *inputFilename, const char *outputFilename, JXFORM_CODE transformVal){
FILE *inputFile = fopen(inputFilename, "r");
if(inputFile==NULL){
std::cerr<<"ERROR: cannot open input file\n";
return;
}
struct jpeg_decompress_struct srcObj;
struct jpeg_error_mgr srcErrMgr;
struct jpeg_compress_struct destObj;
struct jpeg_error_mgr destErrMgr;
jvirt_barray_ptr *srcCoefArr;
jvirt_barray_ptr *destCoefArr;
//transformation object
jpeg_transform_info transformObj;
//set error handler
srcObj.err = jpeg_std_error(&srcErrMgr);
jpeg_create_decompress(&srcObj);
destObj.err = jpeg_std_error(&destErrMgr);
jpeg_create_compress(&destObj);
//set the transformation properties
setTransformation(&transformObj, transformVal);
jpeg_stdio_src(&srcObj, inputFile);
JCOPY_OPTION copyOpt = JCOPYOPT_DEFAULT;
jcopy_markers_setup(&srcObj, copyOpt);
(void) jpeg_read_header(&srcObj, TRUE);
if(!jtransform_request_workspace(&srcObj, &transformObj)){
std::cerr<<"Transformation is not perfect\n";
return;
}
srcCoefArr = jpeg_read_coefficients(&srcObj);
jpeg_copy_critical_parameters(&srcObj, &destObj);
destCoefArr = jtransform_adjust_parameters(&srcObj, &destObj, srcCoefArr, &transformObj);
FILE *outputFile = fopen(outputFilename, "wb");
if(outputFile==NULL){
std::cerr<<"ERROR: cannot open output file\n";
fclose(inputFile);
releaseRes(&srcObj, &destObj);
return;
}
jpeg_stdio_dest(&destObj, outputFile);
jpeg_write_coefficients(&destObj, destCoefArr);
jcopy_markers_execute(&srcObj, &destObj, copyOpt);
jtransform_execute_transformation(&srcObj, &destObj, srcCoefArr, &transformObj);
releaseRes(&srcObj, &destObj);
//close files
fclose(inputFile);
fclose(outputFile);
}
However, i do not want to store rotated image into another file and rather want to rotate in place into buffer or using temp buffer but without compression as in above code.
Below is the code to get the decompressed data into buffer:
void rotateImage(const char *filename){
FILE *file = fopen(filename, "r");
if(!file){
std::cerr<<"Error in reading file\n";
return;
}
struct jpeg_decompress_struct info;
struct jpeg_error_mgr jerr;
info.err = jpeg_std_error(&jerr);
jpeg_CreateDecompress(&info, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
jpeg_stdio_src(&info, file);
(void) jpeg_read_header(&info, TRUE);
jpeg_start_decompress(&info);
uint32_t channels = 3;
uint32_t rowStride = info.output_width * channels;
uint64_t dataSize = rowStride * info.output_height;
unsigned char *buffer = new unsigned char[dataSize];
unsigned char *rowData[1];
while(info.output_scanline < info.output_height){
//initial value of output_Scanline state var is 0
rowData[0] = buffer + info.output_scanline * rowStride;
jpeg_read_scanlines(&info, rowData, 1);
}
/*Now, i want to rotate this buffer (or with other temp buffer without compression as in
first code) as per "orientation", either 90, 180, 270*/
/* here */
jpeg_finish_decompress(&info);
jpeg_destroy_decompress(&info);
fclose(file);
delete buffer;
}
Though, i tried to rotate buffer using temp buffer (analogous to matrix rotation for non-square matrix) with following code for 90 degree:
//90 degree clockwise
unsigned char *tmpBuf = new unsigned char[dataSize];
int row = info.output_height;
int col = info.output_width;
for(int i=0; i<row; i+=1){
for(int j=0;j<col; j+=1){
//copied 3 bytes as each pixed takes 3 bytes for RGB
memcpy(tmpBuf + (j*row + row-i-1)*3, buffer + (i*col + j)*3, 3);
}
}
However, i believe, it is not correct way for rotating JPEG as the rotated data is not accepted by the application i am sending this data to(FYI, i am rotating it as per "Orientation" as application respect it). Which makes me believe that it is not the correct way to rotate JPEG image. As with first method, first rotating into compressed data and then decompressing again into buffer is accepted by the application i am sending data to. But, i think, it is not the better way to do it.
So, i need your help for this. Please let me know the step required to achieve it. Any code example or tutorials will also be helpful.
Thanks

Related

How to read binary data from dicom file?

How to read raw image data from uncompressed DICOM file and dump it to a file. I just use the following code for compressed files. using dcmtk library
dataSet->findAndGetElement(DCM_PixelData, element);
pixDataElem = OFstatic_cast(DcmPixelData*, element);
DcmPixelSequence *pixelSequence = NULL;
E_TransferSyntax tran_Syntax = EXS_Unknown;
const DcmRepresentationParameter *representation = NULL;
// Find the key that is needed to access the right representation of the data within DCMTK
pixDataElem->getOriginalRepresentationKey(tran_Syntax, representation);
//pixDataElem->getCurrentRepresentationKey(tran_Syntax, representation);
// Access original data representation and get result within pixel sequence
pixDataElem->getEncapsulatedRepresentation(tran_Syntax, representation, pixelSequence);
DcmPixelItem *pixelItem = NULL;
//Access the First frame by skipping the offset table...
pixelSequence->getItem(pixelItem, 1);
Uint8 *pixels = NULL;
pixDataElem = (DcmPixelData*)pixelItem;
pixDataElem->getUint8Array(pixels);
Uint8 *pixels = NULL;
pixDataElem->getUint8Array(pixels);
//Writing the Raw data to a file...
FILE *file;
file = fopen("D:\\DicomImage.jpeg", "wb");
fwrite(pixels, sizeof(char), imageSize, file);
cout << "File write Completed and the File is closed Successfully" << endl;
How can I raw image data from the uncompressed files with many frames in c++ using dcmtk library.....?
Basically, you can use the same code, but without compression (this is actually the easier case...)
dataSet->findAndGetElement(DCM_PixelData, element);
pixDataElem = OFstatic_cast(DcmPixelData*, element);
Uint8 *pixels = NULL;
pixDataElem->getUint8Array(pixels);
//Writing the Raw data to a file...
FILE *file;
file = fopen("D:\\DicomImage.raw", "wb");
// frameSize is the size of a single frame
fwrite(pixels + frameSize * frameIndex, sizeof(char), frameSize, file);
cout << "File write Completed and the File is closed Successfully" << endl;
(this is out of my head, so no guarantee for completeness)
What you get, is the raw binary data. If you want to create an image file like JPG from that, you need the respective image functionality, though that has nothing to do with dcmtk.
If you know that the images are not compressed, then you could access the first frame's raw data in this way with Imebra:
imebra::DataSet loadedDataSet = imebra::CodecFactory::Load("pathToFileName);
size_t imageWidth = loadedDataSet.getUint32(imebra::TagId(imebra::tagId_t::Columns_0028_0011), 0);
size_t imageHeight = loadedDataSet.getUint32(imebra::TagId(imebra::tagId_t::Rows_0028_0010), 0);
size_t channels = loadedDataSet.getUint32(imebra::TagId(imebra::tagId_t::SamplesPerPixel_0028_0002), 0);
size_t allocatedBits = loadedDataSet.getUint32(imebra::TagId(imebra::tagId_t::BitsAllocated_0028_0100), 0);
size_t totalSizeBytes = (imageWidth * imageHeight * allocatedBits * channels + 7) / 8;
ReadingDataHandlerNumeric rawData = loadedDataSet.getReadingDataHandlerNumeric(TagId(PixelData_7FE0_0010), 0);
size_t dataSize(0);
const char* pMemory = rawData.data(&dataSize);
// Now pMemory points to the raw data, dataSize holds the memory size
If you need the second frame or the images are compressed then you should use imebra::DataSet::getImage() and let imebra find the proper memory area and decompress the image for you.
Please note that consecutive uncompressed images are not aligned on byte boundary but the first bit of the second frame may be on the same byte containing the last bit of the first frame. For compressed images you may have to deal with a offset table pointing to the buffers containing the images.
Disclaimer: I'm the author of Imebra.

Reading .raw file containing Heightmap

I am using the libnoise library to generate a random terrain and saving it in a .raw file that has its elevation points measured in meters. This terrain file contains 16-bit signed big-endian values, in row-major order, ordered south to north. This is the code I am using for reading the file.
struct HeightMapType
{
float x, y, z;
float nx, ny, nz;
float r, g, b;
};
bool Terrain::LoadRawFile()
{
int error, i, j, index;
FILE* filePtr;
unsigned long long imageSize, count;
unsigned short* rawImage;
// Create the float array to hold the height map data.
m_heightMap = new HeightMapType[m_terrainWidth * m_terrainHeight];
if(!m_heightMap)
{
return false;
}
// Open the 16 bit raw height map file for reading in binary.
error = fopen_s(&filePtr, m_terrainFilename, "rb");
if(error != 0)
{
return false;
}
// Calculate the size of the raw image data.
imageSize = m_terrainHeight * m_terrainWidth;
// Allocate memory for the raw image data.
rawImage = new unsigned short[imageSize];
if(!rawImage)
{
return false;
}
// Read in the raw image data.
count = fread(rawImage, sizeof(unsigned short), imageSize, filePtr);
if(count != imageSize)
{
return false;
}
// Close the file.
error = fclose(filePtr);
if(error != 0)
{
return false;
}
// Copy the image data into the height map array.
for(j=0; j<m_terrainHeight; j++)
{
for(i=0; i<m_terrainWidth; i++)
{
index = (m_terrainWidth * j) + i;
// Store the height at this point in the height map array.
m_heightMap[index].y = (float)rawImage[index];
}
}
// Release the bitmap image data.
delete [] rawImage;
rawImage = 0;
// Release the terrain filename now that it has been read in.
delete [] m_terrainFilename;
m_terrainFilename = 0;
return true;
}
The code does not return any error but this is the result rendered: rawFileRendering.
I tested the code with another heightmap saved in a raw file (given by rastertek) and it works.
Do you know why the rendered scene is like this?
Thank you for your help.
Two problems:
You use unsigned short, but you said in the description that the numbers are signed. So you should use signed short instead
You don't do anything with endianness. If you are on a little endian machine, you should convert your values from big endian to little endian.
You can convert endianness with this:
short endianConvert(short x) {
unsigned short v = (unsigned short)x;
return (short)(v>>8|v<<8);
}

I am unable to load a .BMP image

I am new to opengl. I am trying to load an image using opengl. But I am unable to do so. It gives me this error:
*** Error in `./lena': double free or corruption (top) : 0x0000000001353070 ***
I don't know what I am doing wrong. My code has been given below. Actually it is not my code. I have seen it in another post in Stack Overflow by someone named Ollo.
#include <bits/stdc++.h>
#include <GL/glut.h>
using namespace std;
struct BITMAPFILEHEADER
{
int bfType; //specifies the file type
long long bfSize; //specifies the size in bytes of the bitmap file
int bfReserved1; //reserved; must be 0
int bfReserved2; //reserved; must be 0
long long bOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits
};
struct BITMAPINFOHEADER
{
long long biSize; //specifies the number of bytes required by the struct
long long biWidth; //specifies width in pixels
long long biHeight; //species height in pixels
int biPlanes; //specifies the number of color planes, must be 1
int biBitCount; //specifies the number of bit per pixel
long long biCompression;//spcifies the type of compression
long long biSizeImage; //size of image in bytes
long long biXPelsPerMeter; //number of pixels per meter in x axis
long long biYPelsPerMeter; //number of pixels per meter in y axis
long long biClrUsed; //number of colors used by th ebitmap
long long biClrImportant; //number of colors that are important
};
int main(void){
FILE *filePtr;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER *bitmapInfoHeader = new BITMAPINFOHEADER;
unsigned char *bitmapImage; //store image data
int imageIdx=0; //image index counter
unsigned char tempRGB; //our swap variable
filePtr = fopen("lena.bmp","rb");
if (filePtr == NULL)
cout << "ERROR!!! 1" << endl;
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER),1,filePtr);
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER),1,filePtr); // small edit. forgot to add the closing bracket at sizeof
//move file point to the begging of bitmap data
fseek(filePtr, bitmapFileHeader.bOffBits, SEEK_SET);
//allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
//verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
}
//read in the bitmap image data
fread(bitmapImage, bitmapInfoHeader->biSizeImage, 1, filePtr);
//make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
}
//swap the r and b values to get RGB (bitmap is BGR)
for (imageIdx = 0;imageIdx < bitmapInfoHeader->biSizeImage;imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
return 0;
}
This code that you got from another answer on StackOverflow has some awkward issues.
It checks to see if bitmapImage is 0 and if it is, it immediately calls free (...) on bitmapImage
It needs to return on failure in order to prevent crashing.
fread (...) does not change whether or not bitmapImage is NULL
Here are some minimum changes that you need to make:
if (filePtr == NULL) {
cout << "ERROR!!! 1" << endl;
return -1; // FAILURE, so return!
}
[...]
//allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
//verify memory allocation
if (!bitmapImage)
{
//free(bitmapImage); // This does not belong here!
fclose(filePtr);
return -2; // FAILURE, so return!
}
//read in the bitmap image data
fread(bitmapImage, bitmapInfoHeader->biSizeImage, 1, filePtr);
// THIS IS POINTLESS TOO, fread (...) is not going to change the address of
// bitmapImage.
/*
//make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
}
*/
//swap the r and b values to get RGB (bitmap is BGR)
for (imageIdx = 0;imageIdx < bitmapInfoHeader->biSizeImage;imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
As mentioned in my comment, you should not be writing your own code to read in a .bmp file (unless it's for an assignment, or something like that). You say you're on mint linux, so you might try either FreeImage or ImageMagick. The code you're using doesn't handle index color images, for example, and probably a host of other things.
that's how I load a BMP file of 24 bits per pixel, not for indexed colour bitmaps, download winbgim from here: http://www.mediafire.com/file/z9wnl0c70tiacqn/winbgim_DevCpp.zip/file, is in dev-c++, you probably have to load a couple of parameters for the linker, the path is: project, project options, parameters, and write: -lbgi -lgdi32 -luser32 -lcomdlg32 -luuid -loleaut32 -lole32 -mwindows -lwinmm, one thing more, after installing winbgim, go to dev c and create new project as console graphics application, this item must be in the project list if winbgim is properly installed,
I wrote "write to shared memory", because I wrote the file also in memory although I did not access the file this way, but from the same file
#include <winbgim.h>
#include <string.h>
#include<windows.h>
#include<stdio.h>
#include <stdlib.h>
const char *Filename;
BITMAPFILEHEADER FileHeader;
BITMAPINFOHEADER InfoHeader;
int k;
typedef struct{
BYTE colorr;
BYTE colorg;
BYTE colorb;
}cine;
cine color;
HANDLE hArch, hProy;
LPSTR base,puntero;
DWORD tam;
int main()
{
int gdriver=9;
int gmode=2;
// initgraph(&gdriver,&gmode, "");
cleardevice();
UnmapViewOfFile(base);
CloseHandle(hProy);
CloseHandle(hArch);
char *p;
char *base;
DWORD buf;
Filename="D:\\music\\IMSLP00795-BWV0971\\01.bmp";
int gd = DETECT, gm;
int x = 320, y = 240, radius;
k=0;
int i;
int j;
FILE *File=NULL;
if(!Filename)
{
MessageBox(NULL,"Konnte Filename nicht finden!","Error",MB_OK|MB_ICONERROR);
}
else
{
File=fopen("D:\\music\\IMSLP00795-BWV0971\\01.bmp","rb");
}
fread(&FileHeader,sizeof(BITMAPFILEHEADER),1,File);
if(FileHeader.bfType != 0x4D42)
{
MessageBox(NULL,"Ungültiges Bildformat!","Error",MB_OK|MB_ICONERROR);
exit(1);
}
printf("tamaño total del archivo %d\n",FileHeader.bfSize);
printf("comienzo del mapa de bits (imagen en pixels) en bits %d\n",FileHeader.bfOffBits);
buf=FileHeader.bfOffBits/8; //offset from the begining of BMP file (pixel array)
printf("comienzo del mapa de bits en bytes desde el origen del archivo %d\n",buf);
fread(&InfoHeader,sizeof(BITMAPINFOHEADER),1,File);
printf("horizontal resolution in pixels por metro %li\n",InfoHeader.biWidth);
printf("vertical resolution in pixels por metro %li\n",InfoHeader.biHeight);
printf("numero de bits por pixel %d", InfoHeader.biBitCount);
initwindow(InfoHeader.biWidth,InfoHeader.biHeight);
hArch = CreateFile("D:\\music\\IMSLP00795-BWV0971\\01.bmp", /* file name */
GENERIC_ALL , /* read/write access */
0, /* no sharing of the file */
NULL, /* default security */
OPEN_ALWAYS, /* open new or existing file */
FILE_ATTRIBUTE_NORMAL, /* routine file attributes */
NULL); /* no file template */
if (hArch==INVALID_HANDLE_VALUE){
fprintf(stderr,"no puede abrirse el archivo");
}
hProy = CreateFileMapping(hArch, /* file handle */
NULL, /* default security */
PAGE_READWRITE, /* read/write access to mapped pages */
0, /* map entire file */
0,
TEXT("SharedObject")); /* named shared memory object */
/* write to shared memory */
base=(LPSTR)MapViewOfFile(hProy,FILE_MAP_ALL_ACCESS,0,0,0);
tam=GetFileSize(hArch,NULL);
int cont=0;
puntero=base;
p=base+FileHeader.bfOffBits;
k=0;int t=0,v,l;
fseek(File,FileHeader.bfOffBits,SEEK_SET );
int read=0,read2=0;
k=0;
for( i=0; i<InfoHeader.biWidth; i++ ) {
fread(&color,sizeof(cine),1,File);
read += sizeof(cine);
printf( "Pixel %d: %3d %3d %3d\n", i+1, int(color.colorb), int(color.colorg), int(color.colorr) );
}
if( read % 4 != 0 ) {
read2 = 4 - (read%4);
printf( "Padding: %d bytes\n", read2 );
//fread( &color, read2, 1, File );
}
fseek(File,FileHeader.bfOffBits,SEEK_SET );
for (i=0;i<InfoHeader.biHeight;i++)
for(j=0;j<InfoHeader.biWidth ;j++)
{
fread(&color,sizeof(cine),1,File);
putpixel(j,InfoHeader.biHeight- i,COLOR(int(color.colorb),int(color.colorg),int(color.colorr)));
if(j==InfoHeader.biWidth-1&&read2!=0)fseek(File,read2,SEEK_CUR);
}
fclose(File);
UnmapViewOfFile(base);
CloseHandle(hProy);
CloseHandle(hArch);
getch();
}

C++: .bmp to byte array in a file

Yes i have been through the other questions that are related to this, but i found them not much help. They were some help but i am still a bit confused. So here what what i need to do:
We have a 132x65 screen. I have a 132x65 .bmp. I want to go through the .bmp and separate it into little 1x8 columns to get the binary of that 32-bit column. Then do that 132 times across, and do that 9 times down. Anything that is not white should be counted as a bit. example:
If the top left pixel of the picture is any color that is not white and the 7 pixels below that are white then that would be the first element of the array, the hex of that number, so the array would look like this:
array [] = { 0x01 } and then it would continue to fill through those 132 columns and then do it again for 9 "sections" of rows. And the file result would be ONLY that array in a separate file.
I understand the header format for this, i have read the wiki article on .bmp file formats, my main problem is i don't really know how to interact with the .bmp when i actually want it to go inside and interact with each pixel from the image. I really dont need the whole thing, but maybe just an example of grabbing each pixel from the .bmp and outputting the color of the pixel into a file or something. My c++ is a little rusty (been doing java and javscript lately).
If you want to read a known format BMP and don't care about how it's done (ie, internal-only thing) you can just take the BMP, ignore the header and use it as a pixel array. It is stored line by line starting at the bottom left. There are some detail snags for how it's packed but in my experience if you take a 32bpp image it can be completely ignored.
As a really simple example:
unsigned int *buffer;
void readfile() {
FILE *f = fopen("file.bmp", "rb");
buffer = new unsigned int[132*65];
fseek(f, 54);
fread(buffer, 132*65*4, 1, f);
fclose(f);
}
unsigned int getpixel(int x, int y) {
//assuming your x/y starts from top left, like I usually do
return buffer[(64 - y) * 132 + x];
}
I had the same problem, but by reading BMP file format description I wrote a function that reads a .BMP file and stores it into a array.
Maybe this function can help you:
unsigned int PIC::BinToNum(char *b,int bytes)
{
unsigned int tmpx = 0;
unsigned int pw = 1;
for(int i=0;i<bytes;i++)
{
tmpx += ((unsigned char)b[i]* pw);
pw = pw * 256;
}
return tmpx;
}
int PIC::Open(const char *path)
{
int pad = 0;
unsigned int sof = 0;
unsigned int tx = 0;
char tmp[4] = {0,0,0,0};
fstream file;
file.open(path,ios::in);
if(file.fail())
{
width=height=ColorBits=size=0;
return -1;
}
else
{
file.seekg(0,ios::beg);
file.read(tmp,2);
if(!(tmp[0] == 66 && tmp[1] == 77))
{
width=height=ColorBits=size=0;
return 0;
}
else
{
file.seekg(2,ios::beg); // 0x2 size
file.read(tmp,4);
size = BinToNum(tmp,4);
file.seekg(18,ios::beg); // 0x12 width
file.read(tmp,4);
width = BinToNum(tmp,4);
file.seekg(22,ios::beg); // 0x16 height
file.read(tmp,4);
height = BinToNum(tmp,4);
file.seekg(28,ios::beg); // 0x1C Bits per Pixel
file.read(tmp,2);
ColorBits = BinToNum(tmp,2);
file.seekg(10,ios::beg); // 0x0A start offset
file.read(tmp,4);
sof=BinToNum(tmp,4);
file.seekg(34,ios::beg); // 0x22 Padding
file.read(tmp,4);
pad = BinToNum(tmp,4);
pad = (int)(pad / height); // Compute Spacing in each row
pad = pad - (width*ColorBits/8);
// Initialize Matrix//
matrix = new(unsigned int[height*width]);
for(int h=height-1;h>=0;h--)
{
for(int w=0;w<=width-1;w++)
{
file.seekg(sof,ios::beg);
file.read(tmp,(int)(ColorBits/8));
tx = BinToNum(tmp,(int)(ColorBits/8));
matrix[(h*width)+w] = tx;
sof+=(int)(ColorBits/8);
}
sof +=pad;
}
}
}
file.close();
return 1;
}
Note:This functions is member of a class that i named it "PIC"...

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

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