Как встроить файл в исполняемый файл? - PullRequest
25 голосов
/ 02 сентября 2011

У меня есть небольшой демонстрационный исполняемый файл, написанный на C ++, который зависит только от одного 5-килобайтного PNG-изображения, загружаемого до его запуска, которое используется для созданного мной пиксельного текста.Из-за этого одного файла мне нужно было бы выдавать ZIP-архив вместо одного исполняемого файла, что создает достаточное трение между загрузкой и «воспроизведением», которое, как мне кажется, отговорило бы некоторых попробовать его.

Myвопрос в том, есть ли способ вставить файл PNG (и любой другой файл) в исполняемый файл или исходный код, чтобы он представлял собой один файл, и исполняемый файл может использовать его?

У меня есть возможность анализировать PNG как поток байтов, поэтому его не нужно преобразовывать в пиксельные данные.

Заранее спасибо!(Существуют и другие вопросы с похожим названием, но они и их ответы, похоже, затрагивают более конкретные проблемы и не очень помогают)

edit : компилятор Visual C ++ 2010и это в Windows (хотя я бы хотел для этого избежать специальных утилит для Windows)

edit2 : ответ Альфа показался мне наиболее переносимым методом, поэтому я быстро написал функцию для анализаФайл PNG в TXT или заголовочный файл, который может быть прочитан как массив unsigned char.Похоже, в этой форме он идентичен самому файлу PNG, но мой загрузчик png не примет массив.При загрузке из памяти анализатор PNG принимает (void * buffer, size_t length), если это имеет значение.

Код, если вы хотите увидеть, но я все равно приму другие ответы, если вы считаете, что они лучше, чем этот метод:

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

};

Окончательное редактирование : ImageMagick , о котором также упоминал Альф, сделало именно то, что мне было нужно, спасибо!

Ответы [ 6 ]

10 голосов
/ 02 сентября 2011

Переносимый способ - определить функцию, такую ​​как

typedef unsigned char Byte;

Byte const* pngFileData()
{
    static Byte const data =
    {
        // Byte data generated by a helper program.
    };
    return data;
}

Тогда все, что вам нужно сделать, это написать небольшую вспомогательную программу, которая читает файл PNG в двоичном виде и генерирует текст инициализатора фигурных скобок C ++. Редактировать : @awoodland указал в комментарии на вопрос, что ImageMagick имеет такую ​​маленькую вспомогательную программу & hellip;

Конечно, для программы, специфичной для Windows, вместо этого используйте обычную схему ресурсов Windows.

Приветствия & hth.,

9 голосов
/ 02 сентября 2011

Посмотрите на XD:

http://www.fourmilab.ch/xd/

Наконец, xd может читать двоичный файл и выдавать данные на языке C декларация, которая содержит данные из файла. Это удобно, когда Вы хотите встроить двоичные данные в программы на Си.

Лично я бы использовал ресурсы для окон, но если вам нужен действительно переносимый способ, который не требует знания исполняемого формата, то этот путь можно использовать. PNG, JPG, что угодно ...

5 голосов
/ 02 сентября 2011

Base64 закодируйте файл и поместите его в строку где-нибудь в вашем коде;)

4 голосов
/ 02 сентября 2011

Это зависит от формата исполняемого файла, что означает неотъемлемую часть операционной системы / компилятора.Windows предлагает систему ресурсов для этого, как указано в этот вопрос .

3 голосов
/ 02 сентября 2011

Вы можете встроить любой произвольный файл в ресурсы вашей программы: (MSDN) Пользовательский ресурс .

Пользовательский оператор определения ресурса определяет ресурс, который содержитданные для конкретного приложения.Данные могут иметь любой формат и могут быть определены либо как содержимое данного файла (если задан параметр имени файла), либо как последовательность чисел и строк (если указан блок необработанных данных).

nameID typeID filename

Имя файла указывает имя файла, содержащего двоичные данные ресурса.Содержимое файла включено в качестве ресурса.RC никак не интерпретирует двоичные данные.Ответственность за правильное выравнивание данных для архитектуры целевого компьютера лежит на программисте.

После того, как вы это сделаете, вы можете использовать функцию LoadResource для доступа к байтам.содержится в файле.

0 голосов
/ 25 октября 2013

На Linux я использую это. Он основан на нескольких примерах, которые я нашел, когда пытался сделать несколько демонстраций 4k, хотя и немного модифицированных. Я считаю, что он может работать и на Windows, но не с встроенной сборкой VS по умолчанию. Мой обходной путь # определение макроса для использования этого кода или системы ресурсов Windows, которую предлагает @ MarkRansom (довольно больно работать, но в конечном итоге работает).

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