逆向工程和渲染旧图像格式 .CEL

逆向工程 二元分析 文件格式
2021-07-01 22:00:28

我想对titltext.cel .CEL 图像格式进行逆向工程并在 SDL2 中呈现它。我碰巧对我正在使用的 CEL 文件有所了解。我知道它应该是字母表和一些符号的精灵表。

.CEL 图像格式是一种非常精简的格式,标题信息非常少。

谷歌搜索 让我找到了一些.CEL 规范.CEL 规范 2 文档,这些文档似乎有这个想法,但我认为缺少加载多个框架的内容。从文档中,我可以知道 CEL 图像中有多少帧以及第一帧从哪里开始。

知道第一帧从哪里开始我以为我可以绕过剥离的图像标题

图片标题:

37 00 00 00 E4 00 00 00 78 03 00 00 D6 05 00 00 
18 08 00 00 B2 0A 00 00 02 0D 00 00 F8 0E 00 00 
9D 11 00 00 07 14 00 00 4D 15 00 00 CB 16 00 00 
04 19 00 00 9E 1A 00 00 1E 1E 00 00 ED 20 00 00 
59 24 00 00 4C 26 00 00 78 29 00 00 E7 2B 00 00 
1C 2E 00 00 18 30 00 00 AF 32 00 00 EC 34 00 00 
BF 38 00 00 88 3B 00 00 8F 3D 00 00 EE 3F 00 00 
4B 41 00 00 8E 43 00 00 D6 45 00 00 B4 47 00 00 
06 4A 00 00 28 4C 00 00 E9 4D 00 00 4C 50 00 00 
67 52 00 00 A9 55 00 00 09 57 00 00 D6 58 00 00 
37 5C 00 00 19 5F 00 00 56 60 00 00 F4 61 00 00 
A1 63 00 00 5D 64 00 00 93 65 00 00 B6 66 00 00 
59 67 00 00 6A 68 00 00 7F 69 00 00 86 6A 00 00 
70 6B 00 00 13 6C 00 00 A2 6C 00 00 8A 6E 00 00 
45 70 00 00

在图像标题/第一帧开始之后。

D2 D2 D2 D2 D2 D2 D2 D2 D2 F9 03 F5 F4 F4 F3 03 F4 F4 F5
EC FD 07 F5 F5 F5 F5 F5 ED ......

>

根据文档,第一个 DWORD 是 .CEL 中的 FRAMES 数量。这是 0x37,它是十进制的 55,这似乎是准确的。据我了解,其余的只是框架位置。据我所知,每一帧的宽度应该为 45,高度为 46 像素。由于图像是 8 位颜色,这意味着每种颜色将是 1 个字节。

另外,我听说这些旧的图像类型被称为调色板或有助于改变颜色的东西。

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>


SDL_Window *window; // SDL MAIN WINDOW
SDL_Renderer *renderer;
SDL_Texture *texture;


int SCREEN_WIDTH = 1920;
int SCREEN_HEIGHT = 1080;
SDL_Event e;
bool quit = false;


/** 32-bit in-memory backbuffer surface */
SDL_Surface *surface;
/** 8-bit surface wrapper around #gpBuffer */
SDL_Surface *pal_surface;
/** Currently active palette */
SDL_Palette *palette;
SDL_Texture* texture;


FILE* CELFILE;

unsigned char CELBuffer [3000];

// The CEL dementions I am trying to open are 
// W 46 Height 45 Width 55 FRAMES
void LoadCEL (char * Path){


CELFILE = fopen(Path, "rb"); 


int CELHEADERSIZE = 228;
int CELFRAMESIZE  = 2070;    

//The Header Appears to be 228 bytes in size.  I want to put a frame into CELBuffer 
//  
// I am assuming to get the size of the first framee I need a size of 2017 (45 * 55) ;

    unsigned char c;

    for (int i = 0;  i < (CELFRAMESIZE+CELHEADERSIZE) ; i++){
        if(i > CELHEADERSIZE ){
        c  = fgetc(CELFILE);

        CELBuffer[i] = c;
        printf("CELFILE HEADR %02x \n" ,CELBuffer[i]  & 0xff);

        }

    }   

    void *  pCELBuffer = CELBuffer; 
    surface = SDL_CreateRGBSurfaceFrom( pCELBuffer , 45, 55, 8,1 ,0, 0, 0, 0xff); 
    texture = SDL_CreateTextureFromSurface(renderer, surface);

}

void Create_SDL_Window()
{

    SDL_Init(SDL_INIT_EVERYTHING);
    IMG_Init(IMG_INIT_PNG);
        window = SDL_CreateWindow("Test Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    renderer = SDL_CreateRenderer(window, -1, 0);
    printf("Window And Renderer Created!\n");
}


int main(){

LoadCEL("/home/james/Desktop/titltext.cel");

Create_SDL_Window();
printf("THIS WORKD\n");


while (!quit){  
        SDL_RenderPresent(renderer);


while (SDL_PollEvent(&e)){
    //If user closes the window
    if (e.type == SDL_QUIT){
        quit = true;
    }
    //If user presses any key
    if (e.type == SDL_KEYDOWN){
    //  quit = true;
    }
    //If user clicks the mouse
    if (e.type == SDL_MOUSEBUTTONDOWN){
    /// quit = true;
        }
    }   
    SDL_RenderClear(renderer);
    //renderTexture(image, renderer, x, y);
    SDL_RenderPresent(renderer);

}

}

任何帮助深表感谢。

1个回答

无法告诉您CEL格式究竟是什么,但从我所看到的来看:

  • 偏移到帧表明帧约600个字节长(0x378-0xe4=6600x5d6-0x378=606等)
  • 由于图像尺寸为 45*46=2070,因此必须将每帧压缩为 600 字节
  • 这是一个老游戏(正如你提到的使用调色板),解压后一个像素表示为一个字节。每个字节都是调色板表的索引。
  • 调色板表似乎没有存储在CEL文件中,游戏单独存储调色板。Palette 是一个长度为 256 个元素的数组,每个元素存储 R、G 和 B 的 3 个值。完整的调色板是 768 字节,但游戏可能只存储完整调色板的子集。例如,索引 1-127 用于精灵,索引 128-255 用于背景。游戏如何决定使用调色板并没有硬性规定。每个级别也可能使用不同的调色板。搜索PAL768 字节长的文件或文件,它们可能是适合您的调色板。
  • 第一个文档描述了如何解压缩框架,按照段落“5.3 命令”

你的情况下的命令:

  • 0xd2: 0x100-0xd2=46 个透明像素(46 是宽度,所以整个扫描线是透明的)
  • 0xd2: 0x100-0xd2=46 个透明像素
  • ...
  • 0xf9: 0x100-0xf9=7个透明像素,这是一个不完整的扫描线,更多的像素要跟随......
  • 0x03: 块命令,根据文档不确定,但看起来3+1字节是像素数据(`0xf5、0xf4、0xf4、0xd4)。所有块命令都是我的猜测,我可能完全错了。
  • 0x03: 块命令,3+1字节为像素数据 ( 0xf4, 0xf4, 0xf5, 0xec)
  • 0xfd: 0x100-0xfd=3 个透明像素
  • 0x07:块命令?,7+1字节是像素数据(0xf5, ...,0xf3`)
  • 0x06:块命令?,6+1字节是像素数据(0xf4, ...,0xef`)
  • 0xfe: 0x100-0xfe=2 个透明像素
  • 等等。

一旦您设法处理所有命令,您就可以将索引放入该调色板表中。即使您没有调色板,您也可以假装它是灰度图像并像这样渲染图像。您应该能够识别精灵的形状。

解压缩算法,尤其是块命令似乎是棘手的部分,因此您可能要做的是下载一些暗黑破坏神编辑器并尝试提供您自己的精灵以查看您的精灵如何被压缩。

如果失败或工作量太大,您可以随时反汇编游戏甚至编辑器,看看它们是如何解压CEL文件的。

编辑此工具似乎正在加载CEL文件,可以帮助您了解格式。查看readFrame()readFrame2()功能。这些似乎并不关心块命令,但同时似乎不能 100% 使用您的文件(只需阅读源代码)。看起来你有很多事情要调查。:)

它还包含您可以使用的调色板文件