I am unable to load a .BMP image - c++

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

Related

JPEG image rotation in C++ using libjpeg

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

Memory leak in jpeg compression. Bug or my mistake?

I wrote an npm module for capturing webcam input on linux. The captured frame in yuyv format is converted to rgb24 and after compressed to a jpeg image. In the jpeg compression there appears to be a memory leak. So the usage of memory increases continuously.
Image* rgb24_to_jpeg(Image *img, Image *jpeg) { // img = RGB24
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jerr.trace_level = 10;
jpeg_create_compress(&cinfo);
unsigned char *imgd = new unsigned char[img->size];
long unsigned int size = 0;
jpeg_mem_dest(&cinfo, &imgd, &size);
cinfo.image_width = img->width;
cinfo.image_height = img->height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, true);
jpeg_start_compress(&cinfo, true);
int row_stride = cinfo.image_width * 3;
JSAMPROW row_pointer[1];
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
// size += 512; // TODO: actual value to expand jpeg buffer... JPEG header?
if (jpeg->data == NULL) {
jpeg->data = (unsigned char *) malloc(size);
} else {
jpeg->data = (unsigned char *) realloc(jpeg->data, size);
}
memcpy(jpeg->data, imgd, size);
delete[] imgd;
jpeg->size = size;
return jpeg;
}
The rgb24 and jpeg buffers are reallocated on every cycle. So it looks like the leak is inside libjpeg layer. Is this true or I simply made a mistake somewhere in the code?
Note: the compressed image shall not be saved as a file, since the data might be used for live streaming.
You are using the jpeg_mem_dest in a wrong way - the second parameter is pointer to pointer to char because it is actually set by the library and then you must free it after you are done. Now you are initializing it with a pointer, it gets overwritten and you free the memory region allocated by the library but the original memory region is leaked.
This is how you should change your function:
Image* rgb24_to_jpeg(Image *img, Image *jpeg) { // img = RGB24
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jerr.trace_level = 10;
jpeg_create_compress(&cinfo);
unsigned char *imgd = 0;
long unsigned int size = 0;
cinfo.image_width = img->width;
cinfo.image_height = img->height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, true);
jpeg_mem_dest(&cinfo, &imgd, &size); // imgd will be set by the library
jpeg_start_compress(&cinfo, true);
int row_stride = cinfo.image_width * 3;
JSAMPROW row_pointer[1];
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
// size += 512; // TODO: actual value to expand jpeg buffer... JPEG header?
if (jpeg->data == NULL) {
jpeg->data = (unsigned char *) malloc(size);
} else if (jpeg->size != size) {
jpeg->data = (unsigned char *) realloc(jpeg->data, size);
}
memcpy(jpeg->data, imgd, size);
free(imgd); // dispose of imgd when you are done
jpeg->size = size;
return jpeg;
}
This snippet form jpeg_mem_dest explains the memory management:
if (*outbuffer == NULL || *outsize == 0) {
/* Allocate initial buffer */
dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);
if (dest->newbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
*outsize = OUTPUT_BUF_SIZE;
}
So, if you pass a an empty pointer or a zero sized buffer the library will perform an allocation for you. Thus - another approach is also to set the size correctly and then you can use the originally supplied pointer
In my case I did not solve the issue with previous answer, there was no way to free the memory image pointer, the only way to do that was reserving enough memory to the image and that way the library will not reserve memory and I have the control over the memory and is on the same heap of my application and not on the library's heap, here is my example:
//previous code...
struct jpeg_compress_struct cinfo;
//reserving the enough memory for my image (width * height)
unsigned char* _image = (unsigned char*)malloc(Width * Height);
//putting the reserved size into _imageSize
_imageSize = Width * Height;
//call the function like this:
jpeg_mem_dest(&cinfo, &_image, &_imageSize);
................
//releasing the reserved memory
free(_image);
NOTE: if you put _imageSize = 0, the library will assume that you have not reserve memory and the own library will do it.. so you need to put in _imageSize the amount of bytes reserved in _image
That way you have total control over the reserved memory and you can release it whenever you want in your software..

Get HBITMAPs For *ALL* Sizes and Depths of a File Type Icon (C++)

Compiler: MinGW/GCC
I'm trying to get the HICON of a file type based on what icon windows has registered for that file type, and then grab all of the HICON's images.
The problem is, I can't seem to get anything other than the 32x32 or 16x16 icon. Also, I've looked at GetIconInfoEx() but that function doesn't allow me to choose the icon size that I'm wanting, it just sort of arbitrarily pukes up whatever Windows feels like handing me at the time.
I want to at least have all of the 16x16, 32x32, and 48x48 icons, but I would really enjoy being able to extract every size that's in the HICON that I pass in.
Here's the code I'm currently working with (copy and pasted most of this from the web and stitched it together):
HBITMAP GetFileTypeIcon(const char* ext, int type, int depth)
{
HICON hIcon;
SHFILEINFO sfi= {0};
UINT flag = SHGFI_ICON|SHGFI_USEFILEATTRIBUTES;
int wh = 16;
switch(type)
{
default:
case FILE_ICON_SIZE_16:
{
wh = 16; flag|=SHGFI_SMALLICON;
}
break;
case FILE_ICON_SIZE_32:
{
wh = 32; flag|=SHGFI_LARGEICON;
}
break;
case FILE_ICON_SIZE_48:
{
wh = 48; flag|=SHGFI_SYSICONINDEX;
}
break;
case FILE_ICON_SIZE_256:
{
wh = 256; flag|=SHGFI_SYSICONINDEX;
}
break;
}
HRESULT hr = SHGetFileInfo(ext,FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),flag);
if(SUCCEEDED(hr))
{
if((type == FILE_ICON_SIZE_48) || (type == FILE_ICON_SIZE_256))
{
// THIS PART DOESN'T COMPILE: undeclared function/indentifiers
// HIMAGELIST* imageList;
// hr = SHGetImageList(((type == FILE_ICON_SIZE_256)?SHIL_JUMBO:SHIL_EXTRALARGE), IID_IImageList, (void**)&imageList);
// if(SUCCEEDED(hr))
// {
// //Get the icon we need from the list. Note that the HIMAGELIST we retrieved
// //earlier needs to be casted to the IImageList interface before use.
// hr = ((IImageList*)imageList)->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon);
// }
}
else
{
hIcon=sfi.hIcon;
}
}
// Convert to an HBITMAP (to get it out of the icon...)
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, wh, wh);
HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
DrawIconEx(hMemDC, 0, 0, hIcon, wh, wh, 0, NULL, DI_NORMAL);
SelectObject(hMemDC, hOrgBMP);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
DestroyIcon(hIcon);
return hMemBmp;
}
I don't even know what to do about color depths. I'll hazard a guess: make a DC that has a certain color depth (rather than just a compatible DC) and pass that into DrawIconEx()?
Edit: I answered my own question after much research/work.
See my answer below for a way to find and parse the raw icon data.
I basically had to do everything myself (with the help of the web, Stack Overflow, and several MSDN articles) so I think I'll just post my own solution here.
I ended up parsing the registry to find the locations of the icons of each previously registered file extension, since the API functions that should have easily gotten me the information I wanted have some... problems.
After that I spent several days manually observing the data formats at hand by observing output of an icon program, and with this information in hand I was able to construct an image loader.
I used Allegro game library to make dealing with BITMAP images easier - Win32/GDI is a bit too much to deal with and would have made the code exorbitantly messy.
Finding the Icon Location and Index:
(1) Look for extension under HKEY_CLASSES_ROOT, eg HKCR\.foo\(default) = "foofile"
(2) Default data of this is the next key to look at, eg HKCR\foofile\
(3) Default data here is the description eg HKCR\foofile\(default) = "Foo Document"
(4) The icon location may be in one of two places that I know of:
Either in HKCR\foofile\DefaultIcon\(default) or there may be an entry something like HKCR\foofile\CurVer\(default) = "foofile.1" which tells you to look at the key HKCR\foofile.1\DefaultIcon\(default) for the icon location.
Parsing the Icon Location String:
The string is simply a path followed by a comma, white space, possibly a negative sign, and a number indicating the "index" of the icon.
Here's the big gotcha: Let the icon index be N. If N is negative (might want to check for negative zeros!), it is a resource ID within the file specified. If N is positive, it means to find the N'th icon within the file, but the icon is not necessarily at resource ID number N.
Parsing Icon Structures Manually:
This is the bulk of the code and time spent, but it works beautifully. First off, here's the data formats for the various sections of color and mask data.
Data Block Formats:
32bit ... Color Data:
====================================================================================
Little Endian 4 byte ARGB values.
The rows are stored in reverse order (bottom to top).
24bit ... Color Data:
====================================================================================
Little Endian 3 byte RGB values.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
16bit ... Color Data:
====================================================================================
Little Endian 2 byte RGB values. 5 bits each with MSB = 0.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
8bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 256 palette entries.
If number of colors is reported as zero, assume 256 color entires.
The Pixels are 1 byte index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
4bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 16 palette entries.
If number of colors is reported as zero, assume 16 color entires.
The Pixels are nybble-length index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).
Mask Data:
====================================================================================
Is a string of bytes with mask bits starting at MSB and going towards LSB.
There are ((imagewidth+31)>>5) DWORDS per row in *BIG ENDIAN* order.
Like the color data, there is a set of DWORDS for each row.
The rows are stored in reverse order (bottom to top).
Set unused padding bits/pixels at end of each row to 1.
0 indicates opaque and 1 indicates transparent.
1bit ... XOR Mask, AND Mask, & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There should be exactly 2 palette entries: usually 0x00000000 and 0x00FFFFFF.
The two masks follow the Mask Data format decribed above.
The following results from combining two mask bits:
XOR AND RESULT:
0 0 Color #0 (Black)
0 1 Transparent
1 0 Color #1 (White)
1 1 Invert Destination Bitmap
Of course I wouldn't have left it at this. There's code to be had!
The following code will load up and convert all of the icon images for a given icon location to a vector of 32bpp BITMAPs. If loading a given image fails, it will simply just not be added to the vector (or, in the case of a corrupt icon, it will most likely generate a corrupted image, so be careful).
The code does not support the "invert" color in monochrome images, and will just generate a different color that still has zero alpha.
WARNING: Some psuedo-code is included to shorten things to just the essentials.
Icon Loader Code (Supports: EXE, DLL, 32bit ICL, ICO):
// Code written by Simion32.
// Please feel free to use it anywhere.
// Credit would be nice but isn't required.
#include "include.h" //std::vectors and whatever else you need
#include <allegro.h>
#include <winalleg.h> //Allegro and Win32
#include "Shellapi.h"
// In the following block, the (required!!) pragmas
// force correct data alignment. Needed in at least GCC.
#pragma pack( push, 1 )
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
typedef struct
{
BITMAPINFOHEADER icHeader; // DIB header
RGBQUAD icColors[1]; // Color table
BYTE icXOR[1]; // DIB bits for XOR mask
BYTE icAND[1]; // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;
#pragma pack( pop)
#pragma pack( push, 2 )
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // total size of the RT_ICON resource referenced by the nID member.
WORD nID; // resourceID of RT_ICON (LockResource to obtain a pointer to its ICONIMAGE)
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop )
uint32_t Convert16BitToARGB(uint16_t value)
{
return (0xFF000000|((value >> 7) & 0x0000F8)|((value << 6) & 0x00F800)|((value << 19) & 0xF80000));
}
uint32_t GetMaskBit(uint8_t* data, int x, int y, int w, int h)
{
uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
return ((~(data[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) & 1) * 0xFFFFFFFF);
}
uint32_t GetColorMonochrome(uint8_t* xordata, uint8_t* anddata, int x, int y, int w, int h, uint32_t* pal)
{
uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
uint32_t xor_bit = (((xordata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) << 1) & 2);
uint32_t and_bit = (((anddata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) ) & 1);
uint32_t value = (xor_bit | and_bit);
return pal[value];
}
BITMAP* CreateBmp32bppFromIconResData(void* data, int size, int depth, int w, int h, int colors)
{
char* pngheader = "\211PNG\r\n\032\n";
char* cpd = (char*)data;
bool is_png = ((cpd[0]==pngheader[0])
&& (cpd[1]==pngheader[1])
&& (cpd[2]==pngheader[2])
&& (cpd[3]==pngheader[3])
&& (cpd[4]==pngheader[4])
&& (cpd[5]==pngheader[5])
&& (cpd[6]==pngheader[6])
&& (cpd[7]==pngheader[7]));
if(is_png)
{
//###########################################################
//# PSEUDO-CODE: Somehow convert the PNG file into a bitmap.
BITMAP* result = ConvertPngFileToBmp32bpp(data, size);
return result;
}
else
{
uint32_t ignore_size = ((BITMAPINFOHEADER*)(data))->biSize;
BITMAP* bmp = create_bitmap_ex(32,w,h);
uint32_t pixel_count = (w * h);
uint32_t color_data_size = ((((((w * depth)+7) >> 3) +3) & ~3) * h);
switch(depth)
{
default: return bmp; break;
case 32:
{
uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,src[0]);
src++;
}
//There should never be any padding to jump over here.
}
return bmp;
}
break;
case 24:
{
uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,((src[0] & 0x00FFFFFF) | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
src++;
src = (uint32_t*)(((uint8_t*)src)-1); //go back a byte due to packing
padding_checker += 3;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src = (uint32_t*)(((uint8_t*)src)+1);
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 16:
{
//Note: there might be a color table present! ignore it.
uint16_t* src = (uint16_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,Convert16BitToARGB(src[0]) & GetMaskBit(bitmask, xx, yy, w, h));
src++;
padding_checker += 2;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src = (uint16_t*)(((uint8_t*)src)+1);
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 8:
{
if(colors > 256) colors = 256; //Color Count must be restricted to 256 entries at the most.
if(colors <= 0) colors = 256; //Color Count might be reported as zero. This means 256.
uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
uint8_t color = src[0];
if(color < colors){
_putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
}else{
_putpixel32(bmp,xx,yy,0x00FF00FF);
}
src++;
padding_checker++;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 4:
{
if(colors > 16) colors = 16; //Color Count must be restricted to 16 entries at the most.
if(colors <= 0) colors = 16; //Color Count might be reported as zero. This means 16.
uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
int padding_checker = 0;
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
uint8_t color = src[0];
if(xx & 1) color = ( color & 0x0F);
else color = ((color >> 4) & 0x0F);
if(color < colors){
_putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
}else{
_putpixel32(bmp,xx,yy,0x00FF00FF);
}
if(xx & 1)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
//if the pointer hasn't incremented to the next byte yet, do so.
if(w & 1) //odd width
{
src++;
padding_checker++;
padding_checker &= 3;
}
//This loop jumps over any padding bytes.
while(padding_checker)
{
src++;
padding_checker++;
padding_checker &= 3;
}
}
return bmp;
}
break;
case 1:
{
if(colors > 2) colors = 2; //Color Count must be restricted to 2 entries at the most.
if(colors <= 0) colors = 2; //Color Count might be reported as zero. This means 2.
uint32_t* pal = (uint32_t*)(((uint8_t*)data) + ignore_size);
uint8_t* bitmaskXOR = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
uint8_t* bitmaskAND = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
uint32_t ret_colors[4] = {pal[0]|0xFF000000, 0x00FF00FF, pal[1]|0xFF000000, 0x0000FF00};
for(int yy = h-1; yy >= 0; --yy){
for(int xx = 0; xx < w; ++xx){
_putpixel32(bmp,xx,yy,GetColorMonochrome(bitmaskXOR, bitmaskAND, xx, yy, w, h, ret_colors));
}
}
return bmp;
}
break;
}
return bmp;
}
}
vector< BITMAP* > ResourceToBitmapVector(HMODULE hm, HRSRC hr, bool is_group_icon)
{
vector< BITMAP* > results;
if(is_group_icon)
{
HGLOBAL hg = LoadResource(hm,hr);
GRPICONDIR* gd = (GRPICONDIR*)LockResource(hg);
if(gd->idType == 1)
{
for(int i = 0; i < gd->idCount; ++i)
{
//WARNING: The GRPICONDIRENTRY's data might be wrong!
GRPICONDIRENTRY* ie = (GRPICONDIRENTRY*)&(gd->idEntries[i]);
HRSRC ihr = FindResource(hm,MAKEINTRESOURCE(ie->nID),RT_ICON);
if(ihr != NULL)
{
HGLOBAL ihg = LoadResource(hm,ihr);
void* data = (void*)LockResource(ihg);
DWORD size = SizeofResource(hm,ihr);
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
}
}
}
else
{
HGLOBAL ihg = LoadResource(hm,hr);
void* data = (void*)LockResource(ihg);
DWORD size = SizeofResource(hm,hr);
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
return results;
}
vector< BITMAP* > IconFileToBitmapVector(void* icon_data, uint32_t icon_size)
{
vector< BITMAP* > results;
ICONDIR* gd = (ICONDIR*)icon_data;
if(gd->idType == 1)
{
for(int i = 0; i < gd->idCount; ++i)
{
//WARNING: The ICONDIRENTRY's data might be wrong!
DWORD offset = gd->idEntries[i].dwImageOffset;
DWORD size = gd->idEntries[i].dwBytesInRes;
void* data = (void*)(((uint8_t*)icon_data) + ((uint32_t)offset));
uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
}
}
return results;
}
vector< BITMAP* > UnearthIconResource(string& file, bool self_refrence, bool res_index, int index)
{
#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x00000010
//prevents a negative indexing error
// (the boolean res_index handles whether it's icon index VS resource ID)
index = abs(index);
vector< BITMAP* > results; //array of results to return (pointers to 32bpp images)
//extract and 'demangle' the file extension by convertng to lowercase.
string ext = get_file_extension(file.c_str());
for(int i = 0; i < ext.size(); ++i) ext[i] = tolower(ext[i]);
bool is_icl = false;
if((ext == "exe") || (ext == "dll") || (ext == "scr") || (is_icl = (ext == "icl")))
{
// Portable Executable Resource (works for both DLL and EXE)
// Also works for any 32bit Icon Library (Microangelo Studio?)
HMODULE hm = LoadLibraryEx(file.c_str(), NULL,
(DONT_RESOLVE_DLL_REFERENCES | LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_AS_DATAFILE));
if(hm != NULL)
{
HRSRC hr;
if(!self_refrence)
{
if(res_index)
{
//The icon we want is at the resource ID (==index)
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(index),RT_GROUP_ICON);
if(hr == NULL)
{
hr = FindResource(hm,MAKEINTRESOURCE(index),RT_ICON);
is_single_icon = (hr != NULL);
}
if(hr != NULL)
{
results = ResourceToBitmapVector(hm, hr, !is_single_icon);
}
}
else
{
//The icon we want is the (index)'th icon in the file
//We must preform a manual search for the resource ID!
//WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
for(int nicon = 0, i = 0; i < 0x8000; ++i)
{
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
if(hr != NULL)
{
if(nicon == index)
{
results = ResourceToBitmapVector(hm, hr, true);
break;
}
nicon++;
}
}
}
}
else
{
//The icon we want is the "first" icon in the file.
//Happens when location is a %1.
//We must preform a manual search for the resource ID!
//WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
for(int i = 0; i < 0x8000; ++i)
{
bool is_single_icon = false;
hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
if(hr != NULL)
{
results = ResourceToBitmapVector(hm, hr, true);
break;
}
}
}
FreeLibrary(hm);
}
else /*if(is_icl)
{//OH NOES. We have to load a *16bit* .icl file!
//not supported yet. sorry. left as another excecise to the programmer.
}*/
}
else if(ext == "ico")
{
//Single Icon File
//###################################################
//# PSEUDO-CODE: Do the file loading yourself ;)
void* data_pointer = NULL;
uint32_t data_size = 0;
if(data_pointer = MyLoadFile(file.c_str(), &data_size))
{
if(data_size)
{
results = IconFileToBitmapVector((void*)data_pointer, data_size);
}
}
MyCloseFile(data_pointer);
}
return results;
}
I think that almost covers it all...
One last thing I should mention: Be sure to ignore the size and bit depth information coming from the icon directory entries. They can often be wrong. I've seen a few 256-color images reported as 24bit, causing data corruption inside the image loader.
Wow, talk about reinventing the wheel!
With all due respect, this code is so bloated for nothing. I (and probably thousands of others) achieved the exact same result with 1/10 of this code. Also, this solution contains many inaccuracies.
Here's a quick run-down:
Why parse the registry manually? You state the API has some problems; like what? I've used reg parsing API extensively and never had a problem! The Indexing vs ResID logic is correct though.
Why do all the icon to bitmap conversions manually? This can be achieved with 3 to 5 lines of code using the right Icon API calls. Here's a complete reference.
Why limit the conversion to 32bpp? Again, using the right APIs will generate a device dependent hIcon handle with the max color bit-depth supported by that device. Check out the CreateIconFromResourceEx() API function. All you need to do is combine it with the Find/Load/Lock Resource APIs that you're already using. Using this technique will load icons of any size and color depth (from monochrome up to alpha-channel 32bpp icons).
Finally, regarding the search for icon resources by group (RT_GROUP_ICON), or by single icons (RT_ICON), and matching for a given index instead of resource, it could be done much more efficiently using EnumResourceNames(). It might be that you've failed to account for string resource identifiers when parsing the Enum return, because it seems you've omitted such case in your manual search and match procedure. This might be the source of your problems with EnumResourceNames(). It works perfectly fine for me and for others in countless online samples. At the very least, the "manual" search should match up to 0xFFFF rather than 0x8000. Res IDs are recommended in the 0x0001 to 0x8000 range, but legal in the 0x0000 to 0xFFFF range.
If it does have not to be platform independent:
a bit time ago i wrote a little class that reads a file and extract all icons.
It retreives a std::vector with HICONs.
With GetIconInfo you can retreive the HBITMAP for pixeldata an pixelmask.
The function is a little bit heuristic. It scans the binary Data for a typical icon begin and tries to load them.
The function also works on dlls, exe or icl (16bit dlls that just contain icon resources)
#ifndef __ICON_LIST_H__
#define __ICON_LIST_H__
#include <windows.h>
#include <vector>
class IconFile: public std::vector<HICON>{
public:
IconFile(){};
IconFile(std::string i_filename){
addIconsFromFile(i_filename);
};
int addIconsFromFile(std::string i_fileName){
int iCount=0;
HANDLE file = CreateFile( i_fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(file!=INVALID_HANDLE_VALUE){
int size = GetFileSize(file,NULL);
DWORD actRead;
BYTE* buffer = new BYTE[size];
ReadFile(file, buffer, size, &actRead, NULL);
CloseHandle(file);
int ind = -1;
for(int p = 0; p< size-4; ++p){
if(buffer[p]==40 && buffer[p+1]==0 && buffer[p+2]==0 && buffer[p+3]==0){
HICON icon = CreateIconFromResourceEx(&buffer[p], size-p, true, 0x00030000,0,0,0);
if(icon){
++iCount;
this->push_back(icon);
}
}
}
delete[] buffer;
}
return iCount;
};
};
#endif //__ICON_LIST_H__

Getting incorrect width when decoding bitmap

I have an error with my source code which basically causes bitmap images to appear too wide. for example it will print the width and the height and the height is perfect (256) and the width should also be 256 but the programs says it is billions of pixels wide and it is different everytime. here is the source code.
#include "glob.h"
/* Image type - contains height, width, and data */
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL){
printf("bitmap Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data\n");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
printf("Error reading image data from %s.\n", filename);
return 0;
}
for (i=0; i<size; i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 0;
}
// Load Bitmaps And Convert To Textures
void glob::LoadGLTextures() {
// Load Texture
Image *image1;
// allocate space for texture
image1 = (Image *) malloc(sizeof(Image));
if (image1 == NULL) {
printf("(image1 == NULL)\n");
exit(0);
}
ImageLoad("data/textures/NeHe.bmp", image1);
// Create Texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
};
glob.h is this:
#ifndef GLOB_H_INCLUDED
#define GLOB_H_INCLUDED
#include <iostream>
#include <stdlib.h>
#include <stdio.h> // Header file for standard file i/o.
#include <GL/glx.h> /* this includes the necessary X headers */
#include <GL/gl.h>
//#include <GL/glut.h> // Header File For The GLUT Library
//#include <GL/glu.h> // Header File For The GLu32 Library
#include <X11/X.h> /* X11 constant (e.g. TrueColor) */
#include <X11/keysym.h>
class glob {
bool Running;
GLuint texture; //make an array when we start using more then 1
Display *dpy;
Window win;
XEvent event;
GLboolean doubleBuffer;
GLboolean needRedraw;
GLfloat xAngle, yAngle, zAngle;
float camera_x, camera_y, camera_z;
public:
glob();
int OnExecute();
public:
int init(int argc, char **argv);
void LoadGLTextures();
void OnEvent();
void redraw(void);
};
#endif // GLOB_H_INCLUDED
can any body help me fix this problem?
Lots of things could be going wrong.
If it's a very old file, it could have a BITMAPCOREHEADER which has size fields that are only 2 bytes each.
Is your machine little endian? BMP files are stored little endian.
Note that height may be negative, (which implies it's a top-down bitmap instead of a bottom up one). If you interpret a small negative number as an unsigned 32-bit int, you'll see values in the billions.
Also, your seek to the actual pixel data assumes that it starts right after the bitmap header. This is common, but not required. The file header contains the offset of the actual pixel data. (Microsoft documentation calls this the "bitmap bits" or the "color data".)
I recommend doing a hex dump of the beginning of your file and step through it by hand to make sure all your offsets and assumptions are correct. Feel free to paste the beginning of a hex dump into your question.
Are you on Windows? Can you just call LoadImage?

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