I want to say, I have searched in the internet about this topic, but it doesn't apply to my situation.
I was doing modifications for a game that uses C and I'm editing the images for use for the game, but the images needs to be converted to c headers to make them work. The game is multi-platform, with builds for Windows and Android via NDK.
I've actually accomplished some of the editing with "Using .c/.h images exported with gimp in SDL" as my basis for my solution, using mbin2h, which converts any binary file into something that's fit for a C header. It worked for the Android build, but not for the main cross platform C build.
Here's an example code:
This is what mbin2h outputs usually:
0x89, 'P', 'N', 'G', 0xD, 0xA, 0x1A, 0xA, 0x0, 0x0, 0x0, 0xD, 'I', 'H', 'D', 'R'
Here's from the original source:
"\x89""PNG""\15\12\32\12\0\0\0\15""IHDR"
I don't know what program they used to convert the PNG to the header file. As some of you pointed out, it's a combination of hex, ASCII characters and octal values.
The question is how to convert the png to a header file similar to the original code? To make it easy for others to figure out, I've placed in the zip file the original image, the original header and the header generated by mbin2h: image problem.zip - 319.73
This is actually for OpenBOR and I only wanted to modify the menu image, but because I don't know how to program that well, so I'm going to need some help, sorry about that.
EDIT: I didn't see that there's an answer button, I'll put the answer up. Sorry guys.
Converting binary to C-compatible data is not that difficult, although I do wonder why the created structure is needlessly complex. Then again, if the rest of the source code expects this particular format, it's just a case of copying the original structure and filling in the right values.
.. it's a combination of hex, ASCII characters and octal values ..
That would only be to make the source file as short as possible. There is no further reason; the entire image could be written out as \x..
hex codes as well, or even decimals for that matter.
It was a nice additional challenge to make the header file as small as possible. Other than in the original, I made sure no single line exceeds 100 characters; still, by using more 'shortest alternatives', for the test image my code only produces 1,626 lines where the original has 1,921; 18% less!
Usage: programName input.png
It will replace the .png
part of the input file with .h
and write this output to the current folder. Works on OSX, and I guess it should compile on other *nix-like systems as well, as I tried to limit myself to Posix file I/O. Whether this does or does not include Windows is left as "exercise for the reader".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#define MAX_LINE_LENGTH 100
int main (int argc, char **argv)
{
FILE *f_in, *f_out;
char *name_ptr,*ptr;
off_t i;
struct stat st;
char out_name[FILENAME_MAX];
unsigned char png_byte, last_byte_octal, output_length;
if (argc != 2)
{
fprintf (stderr, "this requires an input file\n");
fclose (f_in);
fclose (f_out);
return -1;
}
f_in = fopen (argv[1], "rb");
if (!f_in)
{
fprintf (stderr, "this requires the input file to exist\n");
fclose (f_in);
fclose (f_out);
return -1;
}
if (stat(argv[1], &st))
{
fprintf (stderr, "this requires the input file to have no problems\n");
fclose (f_in);
fclose (f_out);
return -1;
}
name_ptr = strrchr (argv[1], '/'); // *nix path
if (!name_ptr)
name_ptr = strrchr (argv[1], '\\'); // Wind*ws path
if (name_ptr)
name_ptr++;
else
name_ptr = argv[1];
if (!*name_ptr || strlen(name_ptr) >= FILENAME_MAX)
{
fprintf (stderr, "this requires a reasonable length for the file name\n");
fclose (f_in);
fclose (f_out);
return -1;
}
strcpy (out_name, name_ptr);
ptr = out_name;
while (*ptr)
{
*ptr = tolower(*ptr);
ptr++;
}
ptr = strrchr (out_name, '.');
if (*ptr)
strcpy (ptr, ".h");
else
strcat (out_name, ".h");
f_out = fopen (out_name, "w");
if (!f_out)
{
fprintf (stderr, "this requires the output file to be created\n");
fclose (f_in);
fclose (f_out);
return -1;
}
fprintf (stderr, "creating %s, please hold on.\n", out_name);
ptr = out_name;
while (*ptr)
{
if (*ptr == '.') *ptr = '_';
ptr++;
}
for (i=0; i<2; i++)
{
fprintf (f_out, "#%s", !i ? "ifndef" : "define");
fprintf (f_out, " _");
ptr = out_name;
while (*ptr)
{
fprintf (f_out, "%c", toupper(*ptr));
ptr++;
}
fprintf (f_out, "_\n");
}
fprintf (f_out, "\n"
"static const struct {\n"
"\tsize_t size;\n"
"\tunsigned char data [%lu];\n"
"} ", (unsigned long)st.st_size);
ptr = name_ptr;
while (*ptr)
{
if (*ptr == '.')
fprintf (f_out, "_");
else
fprintf (f_out, "%c", tolower(*ptr));
ptr++;
}
fprintf (f_out, " = {\n"
"\t%lu,\n\"", (unsigned long)st.st_size);
last_byte_octal = 0;
output_length = 1;
for (i=0; i<st.st_size; i++)
{
png_byte = fgetc (f_in);
if (png_byte == '\\')
{
output_length += 2;
if (output_length >= MAX_LINE_LENGTH)
{
fprintf (f_out, "\"\n\"");
output_length = 3;
}
fprintf (f_out, "\\\\");
last_byte_octal = 0;
}
else if (png_byte == 9)
{
output_length += 2;
if (output_length >= MAX_LINE_LENGTH)
{
fprintf (f_out, "\"\n\"");
output_length = 3;
}
fprintf (f_out, "\\t");
last_byte_octal = 0;
} else if (png_byte < ' ' || png_byte == '\"')
{
output_length += (png_byte < 8) ? 2 : 3;
last_byte_octal = 1;
if (output_length >= MAX_LINE_LENGTH)
{
fprintf (f_out, "\"\n\"");
output_length = (png_byte < 8) ? 3 : 4;
}
fprintf (f_out, "\\%o", png_byte);
} else if (png_byte > '~')
{
output_length += 4;
if (output_length >= MAX_LINE_LENGTH)
{
fprintf (f_out, "\"\n\"");
output_length = 5;
}
fprintf (f_out, "\\x%X", png_byte);
last_byte_octal = 1;
} else
{
output_length += (last_byte_octal && isxdigit(png_byte)) ? 3 : 1;
if (output_length >= MAX_LINE_LENGTH)
{
fprintf (f_out, "\"\n\"");
output_length = 2;
last_byte_octal = 0;
}
if (last_byte_octal && isxdigit(png_byte))
fprintf (f_out, "\"\"");
fprintf (f_out, "%c", png_byte);
last_byte_octal = 0;
}
}
fprintf (f_out, "\"\n};\n\n#endif\n");
fclose (f_in);
fclose (f_out);
fprintf (stderr, "done.\n");
return 0;
}