2014-09-07 1 views
0

Я хочу сказать, что я искал в Интернете об этой теме, но это не относится к моей ситуации.преобразование png в c заголовок для sdl

Я делал изменения для игры, в которой используется C, и я редактирую изображения для использования в игре, но изображения нужно преобразовать в заголовки c, чтобы заставить их работать. Игра является многоплатформенной, со сборками для Windows и Android через NDK.

Я на самом деле выполнил некоторые изменения с помощью «Using .c/.h images exported with gimp in SDL» в качестве основы для моего решения, используя mbin2h, который преобразует любой двоичный файл в то, что подходит для заголовка C. Он работал для сборки Android, но не для основной кросс-платформы C build.

Вот пример кода:

Это то, что mbin2h выходы обычно:

0x89, 'P', 'N', 'G', 0xD, 0xA, 0x1A, 0xA, 0x0, 0x0, 0x0, 0xD, 'I', 'H', 'D', 'R' 

Вот из первоисточника:

"\x89""PNG""\15\12\32\12\0\0\0\15""IHDR" 

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

Вопрос в том, как преобразовать png в заголовочный файл, аналогичный исходному коду? Чтобы сделать это проще для других, я поместил в zip-файл исходное изображение, исходный заголовок и заголовок, сгенерированный mbin2h: image problem.zip - 319.73

Это на самом деле для OpenBOR, и я только хотел изменить меню но из-за того, что я не знаю, как правильно программировать, так что мне понадобится помощь, извините.

EDIT: Я не видел, что есть кнопка ответа, я отвечу ответ. Извините ребята.

+0

Предложите добавить к сообщению вопрос. – chux

+0

«... используя mbin2h, и это сработало». Так в чем проблема? –

+0

@ Code-Apprentice - Исправлен вопрос, он работал над сборкой Android, но не на основных сборках, включая окна. –

ответ

0

Преобразование двоичных данных в C-совместимые данные не , что сложно, хотя я действительно удивляюсь, почему созданная структура излишне сложна. Опять же, если остальная часть исходного кода ожидает этот конкретный формат, это всего лишь случай копирования исходной структуры и заполнения правильных значений.

.. it's a combination of hex, ASCII characters and octal values ..

Это было бы только для того, чтобы сделать исходный файл как можно короче. Нет никакой дополнительной причины; все изображение может быть выписано как шестнадцатеричные коды \x.., или даже десятичные числа в этом отношении.

Это была приятная дополнительная задача, чтобы сделать файл заголовка как можно меньшим. Кроме оригинала, я убедился, что ни одна строка не превышает 100 символов; все же, используя более «кратчайшие альтернативы», для тестового изображения мой код производит только 1626 строк, в которых оригинал имеет 1921; На 18% меньше!

Использование: ProgramName input.png

Он заменит .png часть входного файла с .h и записать этот вывод в текущей папке. Работает на OSX, и я думаю, он должен компилироваться и в других * nix-подобных системах, поскольку я пытался ограничить себя вложением/выводом Posix. Включает ли это или не включает Windows, как «упражнение для читателя».

#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"); 
     return -1; 
    } 

    f_in = fopen (argv[1], "rb"); 
    if (!f_in) 
    { 
     fprintf (stderr, "this requires the input file to exist\n"); 
     return -1; 
    } 

    if (stat(argv[1], &st)) 
    { 
     fprintf (stderr, "this requires the input file to have no problems\n"); 
     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"); 
     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"); 
     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; 
} 
+0

Может ли он быть скомпилирован через mingw? Если это так, он может работать на окнах. Я попробую это. –

+0

Это действительно сработало! Я скомпилировал его в Mingw и после этого использовал его на png, и это сработало! Это то же самое, что и исходный код и меньше. –

+0

Рад слышать, как он работал и на других системах! Файл можно сделать * чуть-чуть меньшим, используя '\ n' и' \ r' (которые теперь представлены в восьмеричном формате '\ 12' и' \ 15') и путем проверки символа * next * при записи шестнадцатеричный или восьмеричный, но это всего лишь косметика, и окончательный размер двоичного файла всегда будет таким же! – usr2564301

2

Я не знаю, что mbin2h есть (даже если я думаю, что он делает). Я предлагаю вам изменить вашу сборку (например, ваш Makefile), чтобы сгенерировать image.cdata файл с командой, как, возможно,

mbin2h image.png > image.cdata 

затем файл C, содержащий (вблизи его начала, и с некоторыми другими функциями позже)

const char image_data[] = { 
    #include "image.cdata" 
    }; 

Затем вызовите соответствующие процедуры, используя image_data и, возможно, sizeof(image_data); вероятно, в соответствии с this answer что-то похожее на

SDL_RWops * z = SDL_RWFromMem(image_data,sizeof(image_data)); 

Конечно, этот код должен появиться в том же файле, что и C const char image_data[] определение выше (и после что определение).

PS. Как 5gon12eder answered вы должны предпочесть hexdump вашему mbin2h

+0

mbin2h - это еще одна программа, которая преобразует двоичные файлы в заголовки C, она создается другим человеком, а не мной. Я просто использовал его для преобразования PNG в c-заголовок, совместимый с портом android OpenBOR. Программа была предложена в [Вопросе о стоп-потоке, который я опубликовал выше.] (Http://stackoverflow.com/questions/21149247/using-ch-images-exported-with-gimp-in-sdl?lq=1) –

+0

Спасибо! Я мог бы не использовать ваш метод, но он вдохновил меня на решение проблемы. –

1

В дополнение к @ BasileStarynkevitch отвечают и в ответ на ваш комментарий с просьбой о «сценарии»: Вы можете генерировать сказал включаемый файл image.cdata например, с помощью утилиты Posix hexdump.В вашем файле:

image.cdata: image.png 
    hexdump --format='8/1 " 0x%02x," "\n"' $< > [email protected] 

Формат шестнадцатеричного формата, конечно, не самый эффективный из пространства. Прочитайте man hexdump, если вы чувствуете желание улучшить это.

+0

Дополнено то, что вы сказали, это на самом деле похоже на то, что mbin2h выдает, за исключением того, что он также выделяет размер массива. Спасибо за дополнение @ 5gon12eder! Вы на самом деле дали мне идею для решения –

0

Я решил это наконец! Как было предложено @Basile и @ 5gon12eder, я использовал то, что я сделал так же в андроиде сборки:

char openbor_menu_480x272_png[32851]={ 
    ... 
}; 

Я сказал, что она полукокс и добавил размер массива к нему. ... - выход mbin2h. Метод hexdump также работает, но вам может потребоваться вычислить размер массива вручную.

Затем я нашел код, используемый для декодирования заголовка изображения в коде OpenBor и сделал так:

// Read Logo or Menu from Array. 
if(!type) 
    bgscreen = pngToScreen(isWide ? (void*) openbor_logo_480x272_png.data : (void*) openbor_logo_320x240_png.data); 
else 
    //CRxTRDude - Removed '.data' since it doesn't use it anyway. 
    bgscreen = pngToScreen(isWide ? (void*) openbor_menu_480x272_png : (void*) openbor_menu_320x240_png); 

Я не изменить логотип картины, так что он остается как таковые.

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

Но так получилось, что @Jongware фактически создал сценарий C, который на самом деле выглядел похожим на заголовок c оригинала и работает! Он также сказал, что причина в том, что это так, ради размера, это дает меньший результат, чем на самом деле mbin2h.

"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"

Он был верен, хотя с одной стороны, размер заголовка было уменьшить до 18%, но, когда он составлен, хотя, размер APK не изменился, хотя, но приятно отметить, что это на самом деле хорошая работа, чтобы воспроизвести исходный код и сделать его менее значительным.

В любом случае, спасибо, ребята, за ответ, и я сожалею, если меня неправильно поняли.