• Welcome to Dark Bit Factory & Gravity.
 

C++ loading PNG files

Started by SoldierBoy, August 30, 2007

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

SoldierBoy

ok, I've searched and searched and searched....and have yet to find a clean, usable, C++ PNG reader!!!!

What does everyone here use to load images in?

I'm really seeking just something easy.  Something that doesn't have a huge library attatched to it.

I'm using PixelToaster for my display buffer.  I'm happy with my performance at the moment, but want to do some additional testing.

HELP please? :)

BTW, I was a member here years ago....Hello Shockwave and Clyde and Everyone else!!!
SoldierBoy/ICC2007
Infinity Never Returned haha

Jim

You can use libpng+zlib, but that can be difficult.  Another possibility is to check out D3DX image loading.

Yet another possibility is I think Windows OleLoadPicture() can do it, here's a snippet out of some code I wrote

class Sprite
{
public:
~Sprite();
Sprite(const char *);
private:
void *read_bmp(const char *filename, long *lenp=NULL);
unsigned int *pix;
unsigned int width, height;
};
void *Sprite::read_bmp(const char *filename, long *lenp)
{
FILE *f;
long len;
void *file=NULL;

fopen_s(&f, filename, "rb");
if (f)
{
fseek(f, 0, SEEK_END);
len = ftell(f);
if (lenp) *lenp = len;
fseek(f, 0, SEEK_SET);

file = new char[len];
if (file)
fread(file, 1, len, f);

fclose(f);
}
return file;
}

Sprite::Sprite(const char *fname)
{
HDC hdc;
static struct
{
BITMAPINFO bmpi;
RGBQUAD masks[3];
} header;
IPicture *picture=NULL;
HBITMAP bmp;
ULONG cnt;

memset(&header.bmpi, 0, sizeof header.bmpi);
header.bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

bmp = (HBITMAP)LoadImage(NULL, fname, IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);

if (!bmp)
{
IStream *istm;
HRESULT err;
HGLOBAL hMem;
void *lpMem;
long size;
void *img;

img = read_bmp(fname, &size);
assert(img);
hMem = GlobalAlloc(GMEM_MOVEABLE, size);
assert(hMem);
lpMem = GlobalLock(hMem);
assert(lpMem);
memcpy(lpMem, img, size);
GlobalUnlock(hMem);
delete [] img;

err = CreateStreamOnHGlobal(hMem, FALSE, &istm);
assert(err == S_OK);
err = OleLoadPicture(istm, size, TRUE, IID_IPicture, (void **)&picture);
GlobalFree(hMem);
assert(err == S_OK);
cnt = istm->Release();
picture->get_Handle((OLE_HANDLE*)&bmp);
}

hdc = GetDC(NULL);

GetDIBits(hdc, bmp, 0,0, NULL, &header.bmpi, 0);

width = header.bmpi.bmiHeader.biWidth;
height = header.bmpi.bmiHeader.biHeight;

pix = new unsigned int[width * height];
assert(pix != NULL);

header.bmpi.bmiHeader.biBitCount = 32;
GetDIBits(hdc, bmp, 0, height, pix, &header.bmpi, DIB_RGB_COLORS);

ReleaseDC(NULL, hdc);

if (picture)
cnt = picture->Release();
else
DeleteObject(bmp);

//bitmaps are stored upside down (doh!)
unsigned int *line0 = pix;
unsigned int *lineN = pix+(height-1)*width;
unsigned int *tmpln = new unsigned int[width];
unsigned int y;
for (y = 0; y < height/2; y++)
{
memcpy(tmpln, line0, width * sizeof *pix);
memcpy(line0, lineN, width * sizeof *pix);
memcpy(lineN, tmpln, width * sizeof *pix);
line0 += width;
lineN -= width;
}
delete [] tmpln;
}


That probably won't compile right out of the box, but it shows the technique.  It should load nearly all Windows format images too.

Welcome back to the forum!

Jim
Challenge Trophies Won:

SoldierBoy

Thanks Jim!  I was hoping you would reply! :)  And thank you for the welcome back.....

I was really hoping that someone had just a complete source file for reading, but oh well. :)

I initially went the libpng route, and even found a C++ wrapper for it, but then again, it was incomplete.....

Even just using libpng, seemed overtly complex. 

And the ultimate goal of this is to have 1 file exe, which seems to be the latest rage around here.

I'm not in this to make a 1k or 4k....haha.....so I don't really care about filesize too much.

I just want the cleanliness(???) of it all.

My job brought me into this C++ world.  So I thought I would try and bring C++ into my demo (hobby) world....hahaha

But I tell you what, its so tempting to jump into the FREEBASIC world, since even it has pnglib includes and samples.....

I'll most definately be checking out that source you posted.

Thank you!
SoldierBoy/ICC 1995-2007
Even non-Legends Live On!


Jim

You'll need these includes

#include <windows.h>
#include <ole2.h>
#include <ocidl.h>
#include <olectl.h>
#include <gl/gl.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>


It's really simple then to load a png, you just have


Sprite *myimage;
myimage = new Sprite("file.png");


Then
myimage->img points to the 32bit pixels.

Jim
Challenge Trophies Won:

ninogenio

i have done it the hard way with libpng and zlib before give me till later and ill post up a working loader its a bit of a faffle doing it this way though.
Challenge Trophies Won:

va!n

i think using the windows OLE stuff is the best way... and you dont have bloody filesizes ^^
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

ninogenio

here is one the hard way its done in dev c using jims double buffered gdi window libpng and zlib ive made it as simple as i can and its fairly practical.

hope it helps.

http://dbfinteractive.com/index.php?action=tpmod;dl=item64
Challenge Trophies Won:

taj

D3DX loads pngs, jpgs and of course :-P bmps. Given its 3-4 lines of code to setup DX and 2-3 lines of code to load an image, I dont think it gets any smaller or easier.

Then you go into dll hell of course :-)
Challenge Trophies Won:

SoldierBoy

Thanks for everybody's help!

Jim, nenogenio, va!n, chris

Thanks guys, I'm going to look at both of those options!

Thanks again.

This is how I ended up doing it:
included this file into my project: http://nothings.org/stb_image.c

and wrote this function to load a .png and put into my buffer:


bool loadPNG( std::string filename,  int & width, int & height, int &bitdepth, vector<Pixel> & pixels){

unsigned int index = 0;

unsigned char *data = stbi_load((char *)filename.c_str(), &width, &height, &bitdepth, 0);
if (!data) return false;
// convert 24 bit image pixels to floating point color

pixels.resize( width * height );

for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
Pixel & pixel = pixels[index];

pixel.r = data[index*3+0] * 1.0f / 255.0f;
pixel.g = data[index*3+1] * 1.0f / 255.0f;
pixel.b = data[index*3+2] * 1.0f / 255.0f;
pixel.a = data[index*3+3] * 1.0f / 255.0f;

++index;

}
}

return true;
}




I've attatched the stb_image.c file to this post.  Maybe it will of some use to others....

Thanks!
SoldierBoy/ICC2007


SoldierBoy

Helps if I actually attach the damn file...

Here it is.

SB/ICC207


taj

Interesting find soldier boy (karma++). My guess is STB stands for set top box which is my business. We only ever use PNG and JPG so this code is very cool for us. It could save loads of space over libpng and libjpg which are just overkill and hellishly difficult to use.

Chris
Challenge Trophies Won:

va!n

@SoldierBoy:
Thanks and K++ for sharing your source.  :goodpost:
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Jim

Wow!  Cracking bit of code that!  I wrote one for jpeg a few years ago, which is about 10th the size of jpeg6b (but slower), but this does PNG and TGA too :D
K+
Jim
Challenge Trophies Won:

Shockwave

How to get a load of good Karma and make a lot of programmers happy in one hit!
Thanks very much for posting the code, it will help a lot of people as everyone needs to load pictures at some point.
Shockwave ^ Codigos
Challenge Trophies Won:

SoldierBoy

Thanks for the Karma guys!

I take no credit for the code, its just some random shit that Google found.

But thanks for Sean Barrett for the public domain code that we can all use.

Look for more from me, when I get these Pixels Toasting.....

SoldierBoy/ICC 2007


nystep

wow :)

i've been fighting with libpng and zlib, and more recently with the free independant jpeg group to get a png and jpeg reader. It took aaaages to make the png low level reader work fine. I can't beleive that it can be made so simple in OLE. great work Jim.

just in case you're interrested, my image loader stands there, but it requires external libraries of course :/ :
http://glsilent.svn.sourceforge.net/viewvc/glsilent/src/img/img_Image.cxx?revision=10&view=markup

you can feel free of browsing also arround all my engine sources. i doubt the opengl wrapper will make anyone interrested, this engine is getting old fashioned. I've been thinking of doing some redesign from scratch, but i don't know if i should make a software 3d engine and play with it on symbian/psp/nds, or switch to managed dx and c#.

wait and see..

Jim

Thanks for posting!

Jim
Challenge Trophies Won:

ninogenio

#17
@jim ive implimented your olepicture loader and it all builds fine but when i run it get an assert error from olepictureload so i think the my stream isnt in the right format but my png images are all just 24 bit microsoft paint png`s that my libpng loader works fine with.

it says in msdn that olepictureload can only be used for BMP (bitmap), WMF (metafile), or ICO (icon) format but im guessing you can pass it others?.
Challenge Trophies Won:

Jim

JPG too, at the very least.

Jim
Challenge Trophies Won:

ninogenio

i must have screwd up my png images then, ill do some other test`s, cheers for the great loader btw!
Challenge Trophies Won: