I have been trying to read a bmp file with ifstream, however it works fine without debugging, when I run it in debug mode it fails. At the beginning I read 54 bytes of info, to get the height and the width of the picture, which are unfortunately -858993460 in debug mode, so the whole size of my picture overflows everytime, so I get a bad allocation error. I use VS 2013, could anyone help me out with this one ?
unsigned char* readBMP(char* filename)
{
int i;
char info[54];
std::ifstream ifs(filename, std::ifstream::binary);
ifs.read(info, 54);
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
char* data = new char[size]; // allocate 3 bytes per pixel
ifs.read(data, size);
ifs.close();
return (unsigned char*)data;
}
I guess you failed to open the file, so your read must been failed.
you can check: if (ifs.is_open()) { /* good*/}
you can also check: if(ifs.read(...)){/*good*/}
try this code:
unsigned char* readBMP(char* filename)
{
int i;
char info[54];
std::ifstream ifs(filename, std::ifstream::binary);
if(!ifs.is_open()){
std::cerr<<" failed to open file"<<std::endl;
return NULL;
}
if(!ifs.read(info, 54)) {
std::cerr<<" failed to read from file"<<std::endl;
return NULL;
}
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
char* data = new char[size]; // allocate 3 bytes per pixel
ifs.read(data, size);
ifs.close();
return (unsigned char*)data;
}
Related
I have a exercise. It says, that the C program should be able to read the information of a bitmap file and after that it should display the picture on console.
I have already written a code but when it does not work correctly.
When I debugged the code it looks like the heap is corrupted. I thinks I have a known glitch/mistake in ScanPixelline function.
I don't know how to fix it. Can someone help me to check it?
I am relatively new to C programming.
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "stdint.h"
#include "windows.h"
#pragma pack(1)
struct BMP
{
char Type[2]; //File type. Set to "BM".
int32_t Size; //Size in BYTES of the file.
int16_t Reserved1; //Reserved. Set to zero.
int16_t Reserved2; //Reserved. Set to zero.
int32_t OffSet; //Offset to the data.
int32_t headsize; //Size of rest of header. Set to 40.
int32_t Width; //Width of bitmap in pixels.
int32_t Height; // Height of bitmap in pixels.
int16_t Planes; //Number of Planes. Set to 1.
int16_t BitsPerPixel; //Number of Bits per pixels.
int32_t Compression; //Compression. Usually set to 0.
int32_t SizeImage; //Size in bytes of the bitmap.
int32_t XPixelsPreMeter; //Horizontal pixels per meter.
int32_t YPixelsPreMeter; //Vertical pixels per meter.
int32_t ColorsUsed; //Number of colors used.
int32_t ColorsImportant; //Number of "important" colors.
};
struct Color
{
unsigned char B;
unsigned char G;
unsigned char R;
};
struct ColorTable
{
Color *colors;
unsigned long length;
};
struct PixelArray
{
Color **pixels;
unsigned long rowCount;
unsigned long columnCount;
};
void readBMP(char *File_Name, BMP &a)
{
FILE *p = fopen(File_Name, "rb");
if (p == NULL)
{
printf("Can't open file!");
fclose(p);
return;
}
else
{
fread(&a, sizeof(BMP), 1, p);
}
fclose(p);
}
void Get_Inf(BMP a)
{
if (a.Type[0] != 'B' || a.Type[1] != 'M')
{
printf("This is not a BMP file");
}
else
{
printf("This is a BMP file\n");
printf("The size of this file is %lu bytes\n", a.Size);
printf("The witdth of this image is %lu pixels\n", a.Width);
printf("The height of this image is %lu pixels\n", a.Height);
printf("The number of bits per pixels in this image is %u\n", a.BitsPerPixel);
}
}
void scanBmpPixelLine(Color *&line, unsigned long length)
{
FILE *pointer_ = fopen("test.bmp", "rb");
line = new Color[length];
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
fclose(pointer_);
//file.read((char *)line, length * sizeof(Color));
}
void skipBmpPadding(char count)
{
FILE *pointer__ = fopen("test.bmp", "rb");
if (count == 0)
{
fclose(pointer__);
return;
}
char padding[3];
fread(&padding, sizeof(char), count, pointer__);
fclose(pointer__);
//file.read((char *)&padding, count);
}
void ReadPixelArray(BMP a, PixelArray &data)
{
FILE *pointer = fopen("test.bmp", "rb");
data.rowCount = a.Height;
data.columnCount = a.Width;
data.pixels = new Color*[data.rowCount];
char paddingCount = (4 - (a.Width * (a.BitsPerPixel / 8) % 4)) % 4;
fseek(pointer, 54, SEEK_SET);
for (int i = 0; i < data.rowCount; i++)
{
scanBmpPixelLine(data.pixels[data.rowCount - i - 1], a.Width);
skipBmpPadding(paddingCount);
}
}
void drawBmp(BMP a, PixelArray data)
{
HWND console = GetConsoleWindow();
HDC hdc = GetDC(console);
for (int i = 0; i < a.Height; i++)
for (int j = 0; j < a.Width; j++)
{
Color pixel = data.pixels[i][j];
SetPixel(hdc, j, i, RGB(pixel.R, pixel.G, pixel.B));
}
ReleaseDC(console, hdc);
}
void releaseBmpPixelArray(PixelArray data)
{
for (int i = 0; i < data.rowCount; i++)
delete[]data.pixels[i];
delete[]data.pixels;
}
int main()
{
char file_name[] = "test.bmp";
BMP a;
PixelArray data;
readBMP(file_name, a);
Get_Inf(a);
ReadPixelArray(a, data);
drawBmp(a, data);
releaseBmpPixelArray(data);
}
This function:
void scanBmpPixelLine(Color *&line, unsigned long length)
{
FILE *pointer_ = fopen("test.bmp", "rb");
line = new Color[length];
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
fclose(pointer_);
//file.read((char *)line, length * sizeof(Color));
}
For starters, the intent of the function appears to be to read one line of pixel data from the file. But instead, it's re-opening the file and reading from the beginning (where the header bytes are). I'm not sure if you are aware of that...
But the crash is a result of this line:
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
The second parameter, sizeof(Color), is the size of each element. The third parameter is the number of elements to read. The total bytes read from the file will be the multiplication of the second parameter by the third parameter. So you've redundantly multiplied by sizeof(Color) one too many times. The result is that it will overwrite the line buffer.
To fix, it should be:
fread(line, sizeof(Color), length, pointer_);
You probably want to pass the FILE* pointer obtained from your ReadPixelArray function into this function instead of re-opening the file for every line.
Another code review comment. You should just read the entire file into memory instead of redundantly opening and closing the file for each operation. Then parse the header and set a pointer to the first "line" after the header.
I creating a program that takes a file and ecrypts it, but now i'am with a problem opening the file to read, the fopen() always return 0.
void run(){
char buffer[260] = { '\0' };
GetWindowTextA(Path,buffer,260);
encryptFile(buffer, "C:\\Users\\DownD\\Desktop\\Some.dat");
}
I think the problem is somewhere on this function run(), because when replace the buffer array with some string for example, "C:\\Somefile.exe" replacing the function encryptFile() for:
encryptFile("C:\\Somefile.exe", "C:\\Users\\DownD\\Desktop\\Some.dat");.It reads the file nice and clean.
Here it is parts of the rest of the project.
int CCrypter::encryptFile(char* filePath, LPCSTR outFile)
{
unsigned char* data = NULL;
int cypherSize;
int fSize = readFile(data, filePath);
if (!fSize)
return 2;
unsigned char *ciphertext = new unsigned char[fSize];
cypherSize = encrypt(data, fSize, ciphertext);
if (!cypherSize)
return 3;
if (!Create_File(ciphertext, cypherSize, outFile))
return 4;
return 1;
}
int CCrypter::readFile(unsigned char *&buffer, const char* path)
{
int lenght = 0;
OutputDebugString(path);
FILE* input = fopen(path, "rb");
if (!input) // Input is always 0
return 0;
fseek(input, 0, SEEK_END);
lenght = ftell(input);
buffer = new unsigned char[lenght];
printf("%d", buffer);
ZeroMemory(buffer, lenght);
rewind(input);
if (!fread(buffer, 1, lenght, input))
return 0;
fclose(input);
return lenght;
}
Just to clarify, i'm using Multi-Byte Character Set
I solved the issue. The problem was that I had opened the file before and did not close it, that was why I was receiving permission denied.
#include <iostream>
#include <fstream> // for file I/O
#define WIDTH 128
#define HEIGHT 128
#include <cmath>
using namespace std;
typedef unsigned char unchar;
class MImage
{
///////////////////////////////////////////////////////////////////////////////////////read
public:
void readimage()
{
imageData = new unchar*[HEIGHT]; // create new array size: height of image.
for (int i = 0; i < HEIGHT; i++)
{
imageData[i] = new unchar[WIDTH]; //create matrix.
}
//image I/O
pInFile = new ifstream;
pInFile->open("L.bmp", ios::in | ios::binary); // open fileName and read as binary.
pInFile->read(reinterpret_cast<char*>(imageHeaderData), 1078); //read bmp header data into array.
for (int i = 0; i < HEIGHT; i++)
{
pInFile->read(reinterpret_cast<char*>(imageData[i]), WIDTH); //read row into each array entry.
}
pInFile->close(); //close stream.
}
public:
void write()
{
//smoothFilter();
pOutFile = new ofstream;
pOutFile->open("output.bmp", ios::out | ios::binary);
pOutFile->write(reinterpret_cast<char*>(imageHeaderData), 1078); //write header data onto output
for (int i = 0; i < HEIGHT; i++)
{
pOutFile->write(reinterpret_cast<char*>(imageData[i]), WIDTH); // write new image data.
}
pOutFile->close(); //close stream
}
public:
ifstream* pInFile;
ofstream* pOutFile;
unchar imageHeaderData[1078]; //.bmp header data with offset 1078. unchar** imageData;
};
int main()
{
MImage abc;
abc.readimage();
abc.write();
return 0;
}
I am unable to read image in a 2d array so that i could do some processing on it. i have used the code above but saved file is giving error.
what i am doing is first reading a .bmp file 128x128 then saving it in an other .bmp file. but when i try to open output file it gives error "file is corrupted or large in size"
Hope it helps ;)
I skipped error checking but you should add it to the final code. For writing a .bmp image, wirte BITMAPFILEHEADER first, then BITMAPINFOHEADER and at the end the actual raw data
FILE* filePtr;
int error;
unsigned int count;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
int imageSize;
unsigned char* bitmapImage;
// Open the height map file in binary.
error = fopen_s(&filePtr, filename, "rb");
// Read in the file header.
count = fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// Read in the bitmap info header.
count = fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// Save the dimensions of the terrain.
Width= bitmapInfoHeader.biWidth;
Height= bitmapInfoHeader.biHeight;
// Calculate the size of the bitmap image data.
imageSize = Width* Height* 3;
// Allocate memory for the bitmap image data.
bitmapImage = new unsigned char[imageSize];
// Move to the beginning of the bitmap data.
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// Read in the bitmap image data.
count = fread(bitmapImage, 1, imageSize, filePtr);
// Close the file.
error = fclose(filePtr);
Don't forget to delete bitmapImage or use std::vector instead
I'm getting a bytearray (32 bit or 16 bit) from a source.
If the size width is odd, the last pixel in each row needs to be dropped.
If the height is odd, the last row needs to be dropped.
If the height is negative the bitmap needs to be flipped vertically.
Here is my code so far:
m_pbmiLast = new BITMAPINFO(*m_pbmi);
m_pbmiLast->bmiHeader.biWidth = abs(m_pbmiLast->bmiHeader.biWidth) - (abs(m_pbmiLast->bmiHeader.biWidth) % 2);
m_pbmiLast->bmiHeader.biHeight = abs(m_pbmiLast->bmiHeader.biHeight) - (abs(m_pbmiLast->bmiHeader.biHeight) % 2);
int biWidth = m_pbmiLast->bmiHeader.biWidth;
int biHeight = m_pbmiLast->bmiHeader.biHeight;
int iAdjustedStride = ((((biWidth * m_pbmiLast->bmiHeader.biBitCount) + 31) & ~31) >> 3);
int iRealStride = ((((m_pbmi->bmiHeader.biWidth * m_pbmi->bmiHeader.biBitCount) + 31) & ~31) >> 3);
if (m_pbmi->bmiHeader.biHeight < 0) {
/* Copy the actual data */
int iLineOffsetSource = 0;
int iLineOffsetDest = (biHeight - 1) * iRealStride;
for (int i = 0; i < biHeight; ++i) {
memcpy(&pData[iLineOffsetDest], &m_inputBuffer[iLineOffsetSource], iAdjustedStride);
iLineOffsetSource += iRealStride;
iLineOffsetDest -= iRealStride;
}
} else {
int iLineOffset = 0;
for (int i = 0; i < biHeight; ++i) {
memcpy(&pData[iLineOffset], &m_inputBuffer[iLineOffset], iAdjustedStride);
iLineOffset += iRealStride;
}
}
It doesn't flip the bitmap, and when the bitmap is an odd width, it slants the bitmap.
Can be done like so.. I include the reading and writing just to make it an SSCCE. It has little to no error.
As for my comment about new BITMAPINFO. I was saying that you don't have to allocate such a small structure on the HEAP. Ditch the new part. The only allocation you need for a bitmap is the pixels. The header and other info does not need an allocation at all.
See the Flip function below.
#include <iostream>
#include <fstream>
#include <cstring>
#include <windows.h>
typedef struct
{
BITMAPFILEHEADER Header;
BITMAPINFO Info;
unsigned char* Pixels;
} BITMAPDATA;
void LoadBmp(const char* path, BITMAPDATA* Data)
{
std::ifstream hFile(path, std::ios::in | std::ios::binary);
if(hFile.is_open())
{
hFile.read((char*)&Data->Header, sizeof(Data->Header));
hFile.read((char*)&Data->Info, sizeof(Data->Info));
hFile.seekg(Data->Header.bfOffBits, std::ios::beg);
Data->Pixels = new unsigned char[Data->Info.bmiHeader.biSizeImage];
hFile.read((char*)Data->Pixels, Data->Info.bmiHeader.biSizeImage);
hFile.close();
}
}
void SaveBmp(const char* path, BITMAPDATA* Data)
{
std::ofstream hFile(path, std::ios::out | std::ios::binary);
if (hFile.is_open())
{
hFile.write((char*)&Data->Header, sizeof(Data->Header));
hFile.write((char*)&Data->Info, sizeof(Data->Info));
hFile.seekp(Data->Header.bfOffBits, std::ios::beg);
hFile.write((char*)Data->Pixels, Data->Info.bmiHeader.biSizeImage);
hFile.close();
}
}
void Flip(BITMAPDATA* Data)
{
unsigned short bpp = Data->Info.bmiHeader.biBitCount;
unsigned int width = std::abs(Data->Info.bmiHeader.biWidth);
unsigned int height = std::abs(Data->Info.bmiHeader.biHeight);
unsigned char* out = new unsigned char[Data->Info.bmiHeader.biSizeImage];
unsigned long chunk = (bpp > 24 ? width * 4 : width * 3 + width % 4);
unsigned char* dst = out;
unsigned char* src = Data->Pixels + chunk * (height - 1);
while(src != Data->Pixels)
{
std::memcpy(dst, src, chunk);
dst += chunk;
src -= chunk;
}
std::memcpy(dst, src, chunk); //for 24-bit.
std::swap(Data->Pixels, out);
delete[] out;
}
int main()
{
BITMAPDATA Data;
LoadBmp("C:/Users/Brandon/Desktop/Bar.bmp", &Data);
Flip(&Data);
SaveBmp("C:/Users/Brandon/Desktop/Foo.bmp", &Data);
delete[] Data.Pixels;
return 0;
}
The instructions for libjpeg-turbo here describes the TurboJPEG API thus: "This API wraps libjpeg-turbo and provides an easy-to-use interface for compressing and decompressing JPEG images in memory". Great, but are there some solid examples of using this API available? Just looking to decompress a fairly vanilla jpeg in memory.
I've found a few bits such as https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c, which appears to be using the TurboJPEG API, but are there any more solid/varied examples?
The source for libjpeg-turbo is well documented, so that does help.
Ok, I know that you did already solve your problem, but as some people, just like me, could be searching some simple example I will share what I created.
It is an example, compressing and decompressing an RGB image. Otherwise I think that the API documentation of TurboJPEG is quite easy to understand!
Compression:
#include <turbojpeg.h>
const int JPEG_QUALITY = 75;
const int COLOR_COMPONENTS = 3;
int _width = 1920;
int _height = 1080;
long unsigned int _jpegSize = 0;
unsigned char* _compressedImage = NULL; //!< Memory is allocated by tjCompress2 if _jpegSize == 0
unsigned char buffer[_width*_height*COLOR_COMPONENTS]; //!< Contains the uncompressed image
tjhandle _jpegCompressor = tjInitCompress();
tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
&_compressedImage, &_jpegSize, TJSAMP_444, JPEG_QUALITY,
TJFLAG_FASTDCT);
tjDestroy(_jpegCompressor);
//to free the memory allocated by TurboJPEG (either by tjAlloc(),
//or by the Compress/Decompress) after you are done working on it:
tjFree(&_compressedImage);
After that you have the compressed image in _compressedImage.
To decompress you have to do the following:
Decompression:
#include <turbojpeg.h>
long unsigned int _jpegSize; //!< _jpegSize from above
unsigned char* _compressedImage; //!< _compressedImage from above
int jpegSubsamp, width, height;
unsigned char buffer[width*height*COLOR_COMPONENTS]; //!< will contain the decompressed image
tjhandle _jpegDecompressor = tjInitDecompress();
tjDecompressHeader2(_jpegDecompressor, _compressedImage, _jpegSize, &width, &height, &jpegSubsamp);
tjDecompress2(_jpegDecompressor, _compressedImage, _jpegSize, buffer, width, 0/*pitch*/, height, TJPF_RGB, TJFLAG_FASTDCT);
tjDestroy(_jpegDecompressor);
Some random thoughts:
I just came back over this as I am writing my bachelor thesis, and I noticed that if you run the compression in a loop it is preferable to store the biggest size of the JPEG buffer to not have to allocate a new one every turn. Basically, instead of doing:
long unsigned int _jpegSize = 0;
tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
&_compressedImage, &_jpegSize, TJSAMP_444, JPEG_QUALITY,
TJFLAG_FASTDCT);
we would add an object variable, holding the size of the allocated memory long unsigned int _jpegBufferSize = 0; and before every compression round we would set the jpegSize back to that value:
long unsigned int jpegSize = _jpegBufferSize;
tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
&_compressedImage, &jpegSize, TJSAMP_444, JPEG_QUALITY,
TJFLAG_FASTDCT);
_jpegBufferSize = _jpegBufferSize >= jpegSize? _jpegBufferSize : jpegSize;
after the compression one would compare the memory size with the actual jpegSize and set it to the jpegSize if it is higher than the previous memory size.
I ended up using below code as a working example for both JPEG encoding and decoding. Best example that I can find, it's self-contained that initializes a dummy image and output the encoded image to a local file.
Below code is NOT my own, credit goes to https://sourceforge.net/p/libjpeg-turbo/discussion/1086868/thread/e402d36f/#8722 . Posting it here again to help anyone finds it's difficult to get libjpeg turbo working.
#include "turbojpeg.h"
#include <iostream>
#include <string.h>
#include <errno.h>
using namespace std;
int main(void)
{
unsigned char *srcBuf; //passed in as a param containing pixel data in RGB pixel interleaved format
tjhandle handle = tjInitCompress();
if(handle == NULL)
{
const char *err = (const char *) tjGetErrorStr();
cerr << "TJ Error: " << err << " UNABLE TO INIT TJ Compressor Object\n";
return -1;
}
int jpegQual =92;
int width = 128;
int height = 128;
int nbands = 3;
int flags = 0;
unsigned char* jpegBuf = NULL;
int pitch = width * nbands;
int pixelFormat = TJPF_GRAY;
int jpegSubsamp = TJSAMP_GRAY;
if(nbands == 3)
{
pixelFormat = TJPF_RGB;
jpegSubsamp = TJSAMP_411;
}
unsigned long jpegSize = 0;
srcBuf = new unsigned char[width * height * nbands];
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
srcBuf[(j * width + i) * nbands + 0] = (i) % 256;
srcBuf[(j * width + i) * nbands + 1] = (j) % 256;
srcBuf[(j * width + i) * nbands + 2] = (j + i) % 256;
}
}
int tj_stat = tjCompress2( handle, srcBuf, width, pitch, height,
pixelFormat, &(jpegBuf), &jpegSize, jpegSubsamp, jpegQual, flags);
if(tj_stat != 0)
{
const char *err = (const char *) tjGetErrorStr();
cerr << "TurboJPEG Error: " << err << " UNABLE TO COMPRESS JPEG IMAGE\n";
tjDestroy(handle);
handle = NULL;
return -1;
}
FILE *file = fopen("out.jpg", "wb");
if (!file) {
cerr << "Could not open JPEG file: " << strerror(errno);
return -1;
}
if (fwrite(jpegBuf, jpegSize, 1, file) < 1) {
cerr << "Could not write JPEG file: " << strerror(errno);
return -1;
}
fclose(file);
//write out the compress date to the image file
//cleanup
int tjstat = tjDestroy(handle); //should deallocate data buffer
handle = 0;
}
In the end I used a combination of random code found on the internet (e.g. https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c) and the .c and header files for libjeg-turbo, which are well documented.
This official API is a good information source aswell.
Here's a fragment of code what I use to load jpeg's from memory. Maybe it will require a bit of fixing, because I extracted it from different files in my project. It will load both - grayscale and rgb images (bpp will be set either to 1 or to 3).
struct Image
{
int bpp;
int width;
int height;
unsigned char* data;
};
struct jerror_mgr
{
jpeg_error_mgr base;
jmp_buf jmp;
};
METHODDEF(void) jerror_exit(j_common_ptr jinfo)
{
jerror_mgr* err = (jerror_mgr*)jinfo->err;
longjmp(err->jmp, 1);
}
METHODDEF(void) joutput_message(j_common_ptr)
{
}
bool Image_LoadJpeg(Image* image, unsigned char* img_data, unsigned int img_size)
{
jpeg_decompress_struct jinfo;
jerror_mgr jerr;
jinfo.err = jpeg_std_error(&jerr.base);
jerr.base.error_exit = jerror_exit;
jerr.base.output_message = joutput_message;
jpeg_create_decompress(&jinfo);
image->data = NULL;
if (setjmp(jerr.jmp)) goto bail;
jpeg_mem_src(&jinfo, img_data, img_size);
if (jpeg_read_header(&jinfo, TRUE) != JPEG_HEADER_OK) goto bail;
jinfo.dct_method = JDCT_FLOAT; // change this to JDCT_ISLOW on Android/iOS
if (!jpeg_start_decompress(&jinfo)) goto bail;
if (jinfo.num_components != 1 && jinfo.num_components != 3) goto bail;
image->data = new (std::nothrow) unsigned char [jinfo.output_width * jinfo.output_height * jinfo.output_components];
if (!image->data) goto bail;
{
JSAMPROW ptr = image->data;
while (jinfo.output_scanline < jinfo.output_height)
{
if (jpeg_read_scanlines(&jinfo, &ptr, 1) != 1) goto bail;
ptr += jinfo.output_width * jinfo.output_components;
}
}
if (!jpeg_finish_decompress(&jinfo)) goto bail;
image->bpp = jinfo.output_components;
image->width = jinfo.output_width;
image->height = jinfo.output_height;
jpeg_destroy_decompress(&jinfo);
return true;
bail:
jpeg_destroy_decompress(&jinfo);
if (image->data) delete [] data;
return false;
}