Dnf资源分析与提取工具(附代码)
生活随笔
收集整理的這篇文章主要介紹了
Dnf资源分析与提取工具(附代码)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Dnf資源包格式分析,參考的是這篇文章:http://blog.csdn.net/leexuany/article/details/3849051
提取工具的代碼我放到github上了:https://github.com/langresser/dnfextrator
雖然上文已經有比較詳盡的分析了,但是真正實現好一個資源提取工具還是花了我兩天的時間。這里把需要注意的地方記錄下來。
1、npk包的格式:
解npk包非常好處理,讀取完NPK_Header緊接著根據里面的count數目循環讀取NPK_Index,讀取完畢后,就可以根據里面的offset定位到指定位置讀取img文件?,F在的dnf包npk包內的文件名是加密過的,要用decord_flag異或NPK_Index中的name才能獲取實際文件名。decord_flag總共有256個字節,剩余部分用"DNF"三個字母填滿,最后一個字節置0。讀取文件名時可以像這樣解密:
char temp[256] = {0}; fread(temp, 256, 1, fp); for (int i = 0; i < 256; ++i) {index.name[i] = temp[i] ^ decord_flag[i]; }
2、img文件格式:
struct NImgF_Header {char flag[16]; // 文件標石"Neople Img File"int index_size; // 索引表大小,以字節為單位int unknown1;int unknown2;int index_count;// 索引表數目 };struct NImgF_Index {unsigned int dwType; //目前已知的類型有 0x0E(1555格式) 0x0F(4444格式) 0x10(8888格式) 0x11(不包含任何數據,可能是指內容同上一幀)unsigned int dwCompress; // 目前已知的類型有 0x06(zlib壓縮) 0x05(未壓縮)int width; // 寬度int height; // 高度int size; // 壓縮時size為壓縮后大小,未壓縮時size為轉換成8888格式時占用的內存大小int key_x; // X關鍵點,當前圖片在整圖中的X坐標int key_y; // Y關鍵點,當前圖片在整圖中的Y坐標int max_width; // 整圖的寬度int max_height; // 整圖的高度,有此數據是為了對齊精靈 };
img文件也是一系列圖片的合集,它里面還包含很多有用的信息,比如圖片的坐標(用于對齊),這個數據是我們想正常使用這個圖片所必須的。也正是由于現有的工具都沒有提供方便的批量導出和該數據的處理功能,我才想自己寫個提取工具的。
img文件是由一個header+多個連續的索引表+實際圖片數據組成的。讀取圖片數據需要跳過header(固定大小)和索引表(header.index_size標識)。
我們讀取的文件大小是由NImgF_Index.size決定的,如果dwCompress為6則表示圖片有經過zlib壓縮,這時size表示壓縮后大小。如果為5表示沒有壓縮,這時size表示轉換成8888格式所占內存大小(也就是說,如果dwType為0x0e或是0x0f,size要除2)
如果有壓縮,需要zlib解壓:
int ret = uncompress(temp_zlib_data, &zlib_len, temp_file_data, size);注意,temp_zlib_data是一個足夠大的緩存區,zlib_len傳入的是緩存區的大小。
讀取完的數據是圖片像素數據,接下來要寫入到png圖片中(看個人需要bmp什么的也可以)
libpng的使用(包含顏色格式之間的轉換代碼):
FILE *fp = fopen(file_name, "wb"); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); if (setjmp(png_jmpbuf(png_ptr))) { printf("[write_png_file] Error during init_io"); return; } png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) { printf("[write_png_file] Error during writing header"); return; } png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) { printf("[write_png_file] Error during writing bytes"); return; }row_pointers = (png_bytep*)malloc(height*sizeof(png_bytep)); for(int i = 0; i < height; i++) { row_pointers[i] = (png_bytep)malloc(sizeof(unsigned char)* 4 * width); for(int j = 0; j < width; ++j) { // png is rgbaswitch (type){case ARGB_1555://1555row_pointers[i][j * 4 + 0] = ((data[i * width * 2 + j * 2 + 1] & 127) >> 2) << 3; // red row_pointers[i][j * 4 + 1] = (((data[i * width * 2 + j * 2 + 1] & 0x0003) << 3) | ((data[i * width * 2 + j * 2] >> 5) & 0x0007)) << 3; // green row_pointers[i][j * 4 + 2] = (data[i * width * 2 + j * 2] & 0x003f) << 3; // blue row_pointers[i][j * 4 + 3] = (data[i * width * 2 + j * 2 + 1] >> 7) == 0 ? 0 : 255; // alphabreak;case ARGB_4444://4444row_pointers[i][j * 4 + 0] = (data[i * width * 2 + j * 2 + 1] & 0x0f) << 4; // red row_pointers[i][j * 4 + 1] = ((data[i * width * 2 + j * 2 + 0] & 0xf0) >> 4) << 4; // green row_pointers[i][j * 4 + 2] = (data[i * width * 2 + j * 2 + 0] & 0x0f) << 4;; // blue row_pointers[i][j * 4 + 3] = ((data[i * width * 2 + j * 2 + 1] & 0xf0) >> 4) << 4; // alphabreak;case ARGB_8888://8888row_pointers[i][j * 4 + 0] = data[i * width * 4 + j * 4 + 2]; // redrow_pointers[i][j * 4 + 1] = data[i * width * 4 + j * 4 + 1]; // greenrow_pointers[i][j * 4 + 2] = data[i * width * 4 + j * 4 + 0]; // bluerow_pointers[i][j * 4 + 3] = data[i * width * 4 + j * 4 + 3]; // alphabreak;case ARGB_NONE:// 占位,無圖片資源break;default:printf("error known type:%d\n", type);break;}} } png_write_image(png_ptr, row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) {printf("[write_png_file] Error during end of write"); return; } png_write_end(png_ptr, NULL); // 別忘記釋放內存png_destroy_write_struct(&png_ptr, &info_ptr);/* cleanup heap allocation */ for (int j=0; j < height; j++) free(row_pointers[j]); free(row_pointers); fclose(fp);
總結
以上是生活随笔為你收集整理的Dnf资源分析与提取工具(附代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 比特币base58源码解析_中本聪源码早
- 下一篇: linux命令无视错误,llinux 的