【问题标题】:SDL embed image inside program executableSDL 在程序可执行文件中嵌入图像
【发布时间】:2013-08-27 15:27:15
【问题描述】:

是否可以使用可在运行时使用的 SDL 在程序中嵌入图像。

例如,我有一个程序在启动时会显示一个包含徽标和版权信息的启动画面。而不是将此图像放在位图文件中并使用 SDL_LoadBMP 将其加载到 SDL_Surface。我想将图像嵌入到程序二进制文件中,以阻止有人可能更改启动图像和版权名称。

有人对如何做到这一点有任何建议吗?示例代码会很棒。

【问题讨论】:

  • 顺便说一句:如果有人想改变他们的启动画面,他们就会改变你的启动画面。这不应该是你这样做的唯一动机。
  • 这是真的,如果有人真的想要他们可能会。但是我的另一个动机是该程序是一个小工具,需要便携且易于计算机技能较少的人使用,因此将整个程序作为单个文件比必须保存的小图像文件夹更可取在正确的位置。
  • 这当然应该是可能的(不是微不足道的,而是可能的)。在我看来,正确配置的SDL_RWOps 连同对SDL_LoadBMP_RW() 的调用可以从您配置它的任何位置提取图像,包括在编译时构建的静态内部缓冲区。这是否“解决”了您发现的问题是另一回事。
  • 刚刚看了一下这些是如何工作的,并且根据我的理解,如果我在源代码中将位图图像转换为字符数组。我可以使用这些命令让它在运行时从 const 变量中加载位图?
  • @Scott 没错,对于获取该静态图像的方法,Dietrich 在下面提供了一些选项。一旦您在可执行文件中获得了 bin 格式的静态图像,只需设置一个 SDL_RWOps 以使用使用该图像作为其数据“源”的自定义功能集(由您编写)。你明白了。

标签: c++ c image bitmap sdl


【解决方案1】:

您可以将图像导出为 .xpm 格式(在 gimp 中)并将其包含到您的代码中。但是您需要 SDL_Image.h 才能将其加载为 SDL_Surface。

就像在this doc 中一样,非常简单:

//To create a surface from an XPM image included in C source, use:

SDL_Surface *IMG_ReadXPMFromArray(char **xpm);

C/C++ 示例:

#include <SDL/SDL.h>
#include "test.xpm"
#include <SDL/SDL_image.h>

SDL_Surface *image;
SDL_Surface *screen;

int main(int argc, char **argv)
{
    SDL_Init(SDL_INIT_EVERYTHING);
    screen = SDL_SetVideoMode(800,600,32,SDL_SWSURFACE);
    image = IMG_ReadXPMFromArray(test_xpm); //the .xpm image is a char array. "test_xpm" is the name of the char array
    SDL_Rect offset;
    offset.x = 0;
    offset.y = 0;
    SDL_BlitSurface(image,NULL,screen,&offset);
    SDL_Flip(screen);
    SDL_Delay(5000);


    return 0;
}

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    使用 gimp,您可以将图像保存为 c 代码。

    【讨论】:

    • 这是真的,但是 gimp 只导出原始像素数据。而我需要以正确的图像格式保存文件以在 SDL 中使用。
    【解决方案3】:

    在可执行文件中嵌入文件很容易,但有一些问题,有几种方法可以做到这一点,包括一些可移植和不可移植的方法。

    将图片转换为C代码

    在 C 中编写一个脚本,将图像转换为一个常量数组。该脚本在 Python 中看起来像这样:

    #!/usr/bin/env python3
    print("static const unsigned char IMAGE_DATA[] = {{{}}};".format(
            ",".join(str(b) for b in open("myimage.bmp", "rb").read())))
    

    只需将输出通过管道传输到*.h 文件,并从另一个文件中包含该文件。你可以通过sizeof(IMAGE_DATA)获取文件的大小。

    优点:便携

    缺点:需要安装Python,如果数组对于编译器来说太大则不起作用,需要在构建系统中添加自定义步骤

    将图像转换为目标文件

    这更依赖于平台。在具有 GNU binutils 工具链的平台(例如 Linux)上,您可以使用 objcopy,我认为 bin2obj 适用于 Microsoft 工具链。

    优势:无处不在

    缺点:不可移植,需要在构建系统中添加自定义步骤,自定义步骤可能很难正确完成

    在 GNU binutils 工具链上,使用 objcopy

    objcopy 程序允许您将binary 指定为输入格式,但随后您需要明确指定体系结构...因此您必须针对可执行文件的 i386 和 x64 版本修改命令。

    $ objcopy --input binary --output elf32-i386 --binary-architecture i386 \
        myimage.bmp myimage.o
    

    您可以使用以下声明从 C 中获取数据:

    // Ignore the fact that these are char...
    extern char _binary_myimage_bmp_start, _binary_myimage_bmp_end;
    
    #define MYIMAGE_DATA ((void *) &_binary_myimage_bmp_start)
    #define MYIMAGE_SIZE \
        ((size_t) (&_binary_myimage_bmp_end - &_binary_myimage_bmp_start))
    

    使用汇编指令

    自相矛盾的是,在汇编程序中嵌入静态文件相当容易。汇编程序通常有类似 .incbin 的指令(适用于 GAS 和 YASM)。

    优势:无处不在

    缺点:不可移植,不同平台的汇编语法不同

    (Windows) 将文件作为资源嵌入

    在 Windows 上,您可以在 EXE 中嵌入资源,然后使用库调用获取资源。

    优点:如果您在 Windows 上,可能最简单

    缺点:仅适用于 Windows

    【讨论】:

    • 我曾考虑在 Windows 上使用资源,但是我的程序是跨平台的,所以我一直在寻找更通用的解决方案。由于我缺乏汇编知识并且图像很小,我想我可以使用“将图像转换为 C”选项。但是,如果您能指出正确的方向,我不介意更多地了解目标文件方法。我的主要开发平台是linux。
    • 当然,我添加了更多关于如何使用objcopy的说明。
    • 非常感谢。这个问题将成为我编程的一个非常有用的资源。我非常感激:D
    • ...或者您可以将图像保存为 ppm,将 ppm 加载程序添加到项目中,并将图像作为文本字符串嵌入到您的代码中。您可以使用跨平台的 Qt 4 资源系统并支持将图像嵌入到应用程序中。
    • 太棒了!但是当我得到 image.h 文件时,我如何在 c++ 中使用它?例如,通常在qt中,我可以只为图像文件路径设置一个字符串,(string str1 = str0 + "splash.png";QPixmap pixmap(str1.c_str());)。我现在应该如何处理image.h 文件?谢谢
    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多