Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Packing Images into EXE files and reading them out again?

Credits go to SiegeLord for helping out!
This thread is locked; no one can reply to it. rss feed Print
Packing Images into EXE files and reading them out again?
SomeoneElse
Member #14,288
May 2012

(Using Windows and Allegro 5.0.6 here)
I have some images I'd like to use in my program. While I can put them in a different folder from my program for organization, I'd really like to put them in the executable itself and read from it. Unfortunately, after hours of fruitless searching, I'm at a loss. I've found tools like dat2c and exedat, but they're both for Allegro 4. Is there any way to read images from the EXE file's resources into Allegro? I don't care too badly if it's platform specific, as long as it can be done.

SiegeLord
Member #7,827
October 2006
avatar

1. Base64 encode the files you need 2. Put the resultant strings into your program 3. Decode said strings into memory during program initialization 4. Use the memfile addon to map that memory as files 5. Use the _f prefixed function (`al_load_bitmap_f`) to load the images You can skip the Base64 step... but it'll probably be best if you don't in the long run.

EDIT: Actually nevermind, that was stupid. Just put the contents of your file into this kind of form:

const char my_bitmap = {0xff, 0x0f ...};

(you can write a simple program that fopen's the file and outputs a .c file with those contents).

Then you'd mount that my_bitmap pointer with the memfile addon and then use al_load_bitmap_f to load the actual bitmap.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Mark Oates
Member #1,146
March 2001
avatar

The downside is that that it will dramatically inflate the size of the file, so it's mostly only practical for smaller image files.

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

LennyLen
Member #5,313
December 2004
avatar

I wrote some code for extracting BMP files from .exe files into Allegro bitmaps. There's an A4.0 version that shouldn't be too difficult to update to A5.0. Unfortunately, my motherboard has died, so I can't upload it here, but the uploaded version in this thread should still work.

SiegeLord
Member #7,827
October 2006
avatar

The downside is that that it will dramatically inflate the size of the file, so it's mostly only practical for smaller image files.

Are you sure? For me the exe size increases exactly by the amount of the file I encode in the way I suggested in my post.

Here's the generator I used (haven't actually tested to see if it actually loads the files though :P):

#SelectExpand
1#include <stdlib.h> 2#include <stdio.h> 3#include <string.h> 4 5int main(int argc, char** argv) 6{ 7 if(argc < 3) 8 { 9 printf("Usage:\n%s infile outfile_no_ext\n", argv[0]); 10 exit(-1); 11 } 12 13 FILE* infile = fopen(argv[1], "r"); 14 if(infile == 0) 15 { 16 printf("Error opening %s for reading.\n", argv[1]); 17 exit(-1); 18 } 19 20 char* outfilename = malloc(strlen(argv[2] + 3)); 21 sprintf(outfilename, "%s.c", argv[2]); 22 FILE* outfile = fopen(outfilename, "w"); 23 if(outfile == 0) 24 { 25 printf("Error opening %s for writing.\n", outfilename); 26 exit(-1); 27 } 28 29 fputs("#include \"allegro5/allegro_memfile.h\"\n", outfile); 30 fputs("static const unsigned char _filedata[] = {", outfile); 31 32 unsigned char byte; 33 size_t size = 0; 34 while(fread(&byte, 1, 1, infile) == 1) 35 { 36 if(size > 0) 37 fputs(", ", outfile); 38 39 char hex[5]; 40 sprintf(hex, "0x%X", byte); 41 fputs(hex, outfile); 42 size++; 43 } 44 fputs("};\n", outfile); 45 46 char size_string[256]; 47 sprintf(size_string, "%zd", size); 48 49 fputs("ALLEGRO_FILE* load_", outfile); 50 fputs(argv[2], outfile); 51 fputs("()\n{\n return al_open_memfile((void*)_filedata, ", outfile); 52 fputs(size_string, outfile); 53 fputs(", \"w\");\n}\n", outfile); 54 55 fclose(infile); 56 fclose(outfile); 57}

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Matthew Leverton
Supreme Loser
January 1999
avatar

If he was referring to the size of the C source file vs the image file, then his observation is both true and irrelevant.

SomeoneElse
Member #14,288
May 2012

Wow, SiegeLord's method seems rather straight-forward now that I see what's going on. But, it requires a separate program and only works with bitmaps and simple data/text. As Mark pointed out, it requires a huge c file, and if you want to change it, you have to recompile the entire program connected to it (because you have to #include it to reference it).

However, while browsing the Allegro source code (I can't even remember why), I came up with another idea. What if I just made an extension, in a sense, that created ALLEGRO_FILE instances that could read from the EXE's resources themselves? I made some code that should do just that. I hope. I'll test it out in the morning and let you know how it goes, but if it works it should let you include any kind of data file in the resources of the EXE and read them through Allegro's normal functions without anything more complicated than setting an RC definition. Plus, if you make changes, you're only recompiling the RC script, so it's faster. :D (right? I think this is how the C++ linker works)

(I'd post the code here, but it'd be 200 lines. I think that's a little much.)

Arthur Kalliokoski
Second in Command
February 2005
avatar

NASM can include binary blobs, you'd have to relink whenever it changed. I did this just last week with a 4+Mb text file to avoid having to get the file size, malloc(), read in in, etc. It was to test a word wrap function on the king james bible.

#SelectExpand
1incbin.asm 2 3section .data 4 5global TEXTER 6global ENDTEXT 7 8TEXTER: 9incbin "kjv12.txt" 10ENDTEXT: 11
12***********************
13 14relevant parts of t.c 15 16extern char TEXTER; 17extern char ENDTEXT; 18 19result = wrap(&TEXTER,&finallines,&ENDTEXT-&TEXTER,TEXTLEN);

They all watch too much MSNBC... they get ideas.

SiegeLord
Member #7,827
October 2006
avatar

But, it requires a separate program

And what do you think dat2c was :P.

Quote:

only works with bitmaps and simple data/text

It works for any file type. The only issue is that you have to use it through the Allegro file routines. This means it can be any file Allegro can read, but also any file other libraries can read as long as you can override their file interface.

Quote:

(because you have to #include it to reference it).

Ever heard of header files? It'll work for this method too, I just didn't include a header generation code in my code. It'll just contain the ALLEGRO_FILE* load_foo(); function.

Quote:

read them through Allegro's normal functions without anything more complicated than setting an RC definition.

So it'll have the same limitations as my method :P.

EDIT: Also, are these resource scripts even available under Linux? The method I presented is 100% cross-platform as far as I can tell.

I also looked around a bit, and turns out there is a Linux program does more or less what my little code snipped did:

xdd -i some_file out.c

It'll produce the same static array (and a length variable) as my code, but without the nice loading function.

Lastly, it turns out you can directly encode a file into an object file bypassing the compilation step. This time the exact procedure is compiler specific, so if you're not using GCC it might be a bit too much: linky.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

SomeoneElse
Member #14,288
May 2012

Hehe, I was really tired last night when I posted that. *embarrassed Yes, your method does work with any file-type and mine has the same limitations as yours, if not more. I suppose what I was getting at was that with your method, the file has to be run through an external program and included as a C file (a header file can be used for compiling efficiency), which is a little less straight-forward than simply including it in the resource files. It is, however, more cross-platform compatible as well as much better protected than mine, and it works just as well. Thank you very much, that was very helpful! :) I'm sorry if my ill-formed words offended you. :-[

So, conclusion (for easy searches): To pack an image/other file into an EXE/other executable and still use it in Allegro 5, include the file as a byte[] constant in a C file in your code and use the memfile addon to pretend it's a file. Continue with normal Allegro functions.

P.S., I tested my program this morning and it worked! :D I could include any kind of data file in the resources and read it out perfectly fine. I didn't try to break it, but it works fine for normal operations. Accessing EXE resources may be useful in any case, so if anyone wants the code I'll be glad to hand it out. It's just a C file and a header.

Mark Oates
Member #1,146
March 2001
avatar

If he was referring to the size of the C source file vs the image file, then his observation is both true and irrelevant.

Unless you're distributing the source. But yes, that's what I was saying.

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

Audric
Member #907
January 2001

There is a method with GCC, it works on Windows, Linux etc:
ld -r -b binary -o myimage.o myimage.png
Add myimage.o when linking, and in your program, the data will be stored at the following address:
extern char * binary_myimage_png_start;

Arthur Kalliokoski
Second in Command
February 2005
avatar

Audric said:

ld -r -b binary -o myimage.o myimage.png

:o

Thanks!

They all watch too much MSNBC... they get ideas.

Mark Oates
Member #1,146
March 2001
avatar

Audric said:

ld -r -b binary -o myimage.o myimage.png

boom.

there it is.

8-)

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

Arthur Kalliokoski
Second in Command
February 2005
avatar

I was thinking the ld method couldn't give information on the size of the binary blob, but this SO page says it can. It could be inconvenient with namespaces though, seeing as how the variable names depend on the filename.

They all watch too much MSNBC... they get ideas.

weapon_S
Member #7,859
October 2006
avatar

If I understand correctly, the data will be loaded into memory as if it were a global variable. It might be nifty, if somebody would know a way to access a tar or (uncompressed) zip archive this way (only one file gets linked in; file system like access).

SiegeLord
Member #7,827
October 2006
avatar

weapon_S said:

It might be nifty, if somebody would know a way to access a tar or (uncompressed) zip archive this way (only one file gets linked in; file system like access).

PhysFS has a function for this, PHYSFS_mountMemory. You'd mount that memory, setup the PhysFS interface via the PhysFS addon and every function in Allegro will work transparently with that archive.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

weapon_S
Member #7,859
October 2006
avatar

Go to: