Reputation: 13002
I have a small demo executable wrote in C++ that depends only on one 5kb PNG image being loaded before it can run, which is used for a pixel text I made. Because of this one file, I would need to give out a ZIP archive instead of just one executable file, which creates enough friction between download and 'play' that I believe would dissuade some from trying it out.
My question is, is there anyway to embed the PNG file (and any other file really) into the Executable or source code so that it is a single file, and the executable can use it?
I have the ability to parse the PNG as a byte stream, so it does not need converted to pixel data.
Thanks in advance! (Other questions with a similar title to this exist, but they and their answers seem to get into more specific issues and weren't very helpful)
edit:The compiler is Visual C++ 2010 and this is on Windows (though I would want to avoid windows specific utilities for this)
edit2: Alf's answer seemed like the most portable method, so I quickly wrote a function to parse the PNG file into a TXT or header file that could be read as a unsigned char
array. It appears to be identical in this form to the PNG file itself, but my png loader won't accept the array. When loading it from memory, the PNG parser takes a (void * buffer, size_t length)
if it matters.
The code if you wanted to see, but I'll still accept other answers if you think they're better than this method:
void compileImagePNGtoBinary(char * filename, char * output){
FILE * file = fopen(filename, "rb");
FILE * out = fopen(output, "w");
unsigned char buffer[32];
size_t count;
fprintf(out, "#pragma once \n\n static unsigned char TEXT_PNG_BYTES[] = { ");
while(!feof(file)){
count = fread(buffer, 1, 32, file);
for(int n = 0; n < count; ++n){
fprintf(out, "0x%02X, ", buffer[n]);
};
};
fprintf(out, "};");
fclose(file);
fclose(out);
};
Final Edit: ImageMagick which Alf also mentioned did exactly what I needed of it, thanks!
Upvotes: 34
Views: 44058
Reputation: 31519
I'll mention #embed
for completeness and hoping this will "soon" be a (standard) reality.
C23 (the C, not C++ programming language) has already incorporated such a functionality as a language feature allowing you to write:
int main (int, char*[]) {
static const char sound_signature[] = {
#embed <sdk/jump.wav>
// ^^^^^^^^^^^^^^^^^^
};
static_assert((sizeof(sound_signature) / sizeof(*sound_signature)) >= 4,
"There should be at least 4 elements in this array.");
return 0;
}
For a C++ project, having a C subcomponent just for this use case might be a stretch, unless your application heavily requires embedding data in some way. My intuition is that implementations will "quietly" make this available to C++ even before it's in the standard. You can read more on the topic at the feature's author blog (where the above example was borrowed from).
Bear in mind that the exact same feature was being pursued even earlier for C++ but made it into the C standard first. A paper (for c++26 probably) is available here suggesting the following sytnax:
#include <embed>
constexpr std::span<const std::byte> fxaa_binary = std::embed("fxaa.spirv");
i.e. avoiding the preprocessor altogether.
Upvotes: 7
Reputation: 165
If I want to embed static data into an executable, I would package it into a .lib/.a file or a header file as an array of unsigned chars. That's if you are looking for a portable approach. I have created a command line tool that does both actually here. All you have to do is list files, and pick option -l64 to output a 64bit library file along with a header that includes all pointers to each data.
You can explore more options as well.for example, this option:
>BinPack image.png -j -hx
will output the data of image.png into a header file, as hexadecimal and lines will be justified per -j option.
const unsigned char BP_icon[] = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
0x00,0x00,0x01,0xed,0x00,0x00,0x01,0xed,0x08,0x06,0x00,0x00,0x00,0x34,0xb4,0x26,
0xfb,0x00,0x00,0x02,0xf1,0x7a,0x54,0x58,0x74,0x52,0x61,0x77,0x20,0x70,0x72,0x6f,
0x66,0x69,0x6c,0x65,0x20,0x74,0x79,0x70,0x65,0x20,0x65,0x78,0x69,0x66,0x00,0x00,
0x78,0xda,0xed,0x96,0x5d,0x92,0xe3,0x2a,0x0c,0x85,0xdf,0x59,0xc5,0x2c,0x01,0x49,
0x08,0x89,0xe5,0x60,0x7e,0xaa,0xee,0x0e,0xee,0xf2,0xef,0x01,0x3b,0x9e,0x4e,0xba,
0xbb,0x6a,0xa6,0x66,0x5e,0x6e,0x55,0x4c,0x8c,0x88,0x0c,0x07,0xd0,0x27,0x93,0x84,
0xf1,0xef,0x3f,0x33,0xfc,0xc0,0x45,0xc5,0x52,0x48,0x6a,0x9e,0x4b,0xce,0x11,0x57,
0x2a,0xa9,0x70,0x45,0xc3,0xe3,0x79,0xd5,0x5d,0x53,0x4c,0xbb,0xde,0xd7,0xe8,0x57,
0x8b,0x9e,0xfd,0xe1,0x7e,0xc0,0xb0,0x02,0x2b,0xe7,0x03,0xcf,0xa7,0xa5,0x87,0xff,
0x1a,0xf0,0xb0,0x54,0xd1,0xd2,0x0f,0x42,0xde,0xae,0x07,0xc7,0xf3,0x83,0x92,0x4e,
0xcb,0xfe,0x22,0xc4,0xa7,0x91,0xb5,0xa2,0xd5,0xee,0x97,0x50,0xb9,0x84,0x84,0xcf,
0x07,0x74,0x09,0xd4,0x73,0x5b,0x31,0x17,0xb7,0x8f,0x5b,0x38,0xc6,0x69,0xaf}
Upvotes: 3
Reputation: 7122
I came here looking for a bash script, so that I can generate the C array of bytes in a mostly-cross-platform compatible way (I depend on mingw bash for my windows builds anyway) without having to compile a helper tool or depend on any tools that don't come standard with a normal bash shell. Here's my take:
#!/bin/sh
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
OUT_FILE="$SCRIPT_DIR/src/alloverse_binary_schema.h"
BINARY_FILE="$SCRIPT_DIR/include/allonet/schema/alloverse.bfbs"
VAR_NAME="alloverse_schema"
echo "static const unsigned char ${VAR_NAME}_bytes[] = {" > "$OUT_FILE"
hexdump -ve '1/1 "0x%02x, "' "$BINARY_FILE" >> "$OUT_FILE"
echo "0x00}; static const int ${VAR_NAME}_size = sizeof(${VAR_NAME}_bytes); " >> "$OUT_FILE"
I can then just #include this from the C file where I use it, and use foo_bytes
and foo_size
as needed:
#include "alloverse_binary_schema.h"
bool allo_initialize(void)
{
g_alloschema = reflection_Schema_as_root(alloverse_schema_bytes);
}
This script should be adaptable to your needs by adjusting OUT_FILE
, BINARY_FILE
and VAR_NAME
(perhaps taking them as arguments to the script).
Upvotes: 0
Reputation: 308158
You can embed any arbitrary file into your program resources: (MSDN) User-Defined Resource.
A user-defined resource-definition statement defines a resource that contains application-specific data. The data can have any format and can be defined either as the content of a given file (if the filename parameter is given) or as a series of numbers and strings (if the raw-data block is specified).
nameID typeID filename
The filename specifies the name of a file containing the binary data of the resource. The contents of the file are included as the resource. RC does not interpret the binary data in any way. It is the programmer's responsibility to ensure that the data is properly aligned for the target computer architecture.
Once you've done that you can use the LoadResource function to access the bytes contained in the file.
Upvotes: 6
Reputation: 17266
On linux I use this. It's based off a few examples I found when trying to do some 4k demos, albeit modified a bit. I believe it can work on windows too, but not with the default VS inline assembly. My workaround is #defining a macro to either use this code or the windows resource system that @MarkRansom suggests (quite painful to get working, but does work eventually).
//USAGE: call BINDATA(name, file.txt) and access the char array &name.
#ifndef EMBED_DATA_H
#define EMBED_DATA_H
#ifdef _WIN32
//#error The VS ASM compiler won't work with this, but you can get external ones to do the trick
#define BINDATA #error BINDATA requires nasm
#else
__asm__(
".altmacro\n" \
".macro binfile p q\n" \
" .global \\p\n" \
"\\p:\n" \
" .incbin \\q\n" \
"\\p&_end:\n" \
" .byte 0\n" \
" .global \\p&_len\n" \
"\\p&_len:\n" \
" .int(\\p&_end - \\p)\n" \
".endm\n\t"
);
#ifdef __cplusplus
extern "C" {
#endif
#define BINDATA(n, s) \
__asm__("\n\n.data\n\tbinfile " #n " \"" #s "\"\n"); \
extern char n; \
extern int n##_len;
#ifdef __cplusplus
}
#endif
#endif
#endif
Upvotes: 2
Reputation: 68033
Look at XD:
Finally, xd can read a binary file and emit a C language data declaration which contains the data from the file. This is handy when you wish to embed binary data within C programs.
Personally, I'd use resources for windows, but if you require a truly portable way that doesn't involve knowledge of the executable format, this is the way to go. PNG, JPG, whatever...
Upvotes: 15
Reputation: 145269
A portable way is to define a function like
typedef unsigned char Byte;
Byte const* pngFileData()
{
static Byte const data =
{
// Byte data generated by a helper program.
};
return data;
}
Then all you have to do is to write a little helper program that reads the PNG file as binary and generates the C++ curly braces initializer text. Edit: @awoodland has pointed out in comment to the question, that ImageMagick has such a little helper program…
Of course, for a Windows-specific program, instead use the ordinary Windows resource scheme.
Cheers & hth.,
Upvotes: 20
Reputation: 48330
Base64 encode the file and put it in a string somewhere in your code ;)
Upvotes: 9
Reputation: 146910
This is executable-format dependent, which means inherently operating system/compiler dependent. Windows offers the Resources system for this as mentioned in this question.
Upvotes: 4