MTK Logo 逆向解析之 raw 转 bmp

文章目录

    • 1、分析源码
    • 2、c++ 版本源码
      • 2.1、编译指令
      • 2.2、回转 bmp 文件
    • 3、python 版本源码
      • 3.1、回转 bmp 文件
    • 4、java 版本源码
      • 4.1、回转 bmp 文件

相关文章

MTK Logo 逆向解析之 bin 转 rawx

MTK Logo 逆向解析之 rawx 全解压

终于来到最后一步啦,将 raw 转换为原始 bmp 文件,也就是我们在 alps\vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo

文件夹中对应的原始文件,掌握了这个就可以提取设备中的开机logo文件解析

话说在最后这个阶段卡了两星期吧,毕竟我的 c++ 很菜,都是边查边粘贴,总是卡在数据旋转那块,

最终还是通过群友的 AI 大法搞定了,还提供了三种版本的转换方式。话不多说,先来看看源码

1、分析源码

源码路径

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\tool\bmp_to_raw_dithering\

main.cpp 运行入口 仅关注这个

bmpdecoderhelper.cpp 标准 bmp 解析工具类,安装源码中默认也有

bmpdecoderhelper.h 头文件

Dither.c 没用到

整体代码很简单,就是读取 bmp 文件大小,解析 bmp 数据,按照 ARGB8888 格式存储到 raw 文件中

反解析只需要将流程逆过来就行

#include <iostream>
#include <fstream>
#include <vector>

#include "bmpdecoderhelper.h"

using namespace std;
using namespace image_codec;

//g++ -m32  main.cpp bmpdecoderhelper.cpp -o bmp_to_raw
// -------------------------------------------------------------------------------------

class BmpToLogo : public BmpDecoderCallback
{
public:
    BmpToLogo() : BmpDecoderCallback(), m_width(0), m_height(0) {}

    bool DoBmpToLogo(const char *bmpFilename, const char *logoFilename, bool append)
    {
        // Open input BMP file
        ifstream bmpFile;
        bmpFile.open(bmpFilename, ios::in | ios::binary);
        if (!bmpFile.is_open()) {
            cout << "open " << bmpFilename << " failed!" << endl;
            return false;
        }

        // Open output LOGO file
        ofstream logoFile;
        ios_base::openmode outMode = (ofstream::out | ofstream::binary);
        if (append) outMode |= ofstream::app;
        logoFile.open(logoFilename, outMode);
        if (!logoFile.is_open()) {
            cout << "open " << logoFilename << " failed!" << endl;
            return false;
        }

        // Read in BMP file content
        int bmpFileSize = GetFileSize(bmpFile);
        m_bitstream.resize(bmpFileSize);
        bmpFile.read(&m_bitstream[0], m_bitstream.size());

        // Decode BMP file to destination buffer
        BmpDecoderHelper bmpDec;
        bmpDec.DecodeImage(&m_bitstream[0], m_bitstream.size(), INT_MAX, this);

        // ConvertToRGB565();
        // ConvertToRGB565Dither();
        // Convert RGB888 buffer to RGB565
        ConvertToARGB8888();

        // Write to LOGO file
        // logoFile.write(&m_rgb565Buffer[0], m_rgb565Buffer.size());
        logoFile.write(&m_argb8888Buffer[0], m_argb8888Buffer.size());

        // Close Files
        bmpFile.close();
        logoFile.close();

        return true;
    }

    virtual uint8* SetSize(int width, int height)
    {
        m_width  = (uint32)width;
        m_height = (uint32)height;
        m_rgb888Buffer.resize(width * height * 3);
        m_rgb565Buffer.resize(width * height * 2);
        m_argb8888Buffer.resize(width * height * 4);

        return (uint8 *) &m_argb8888Buffer[0];
    }

private:
    int GetFileSize(ifstream& file)
    {
        ios::pos_type backup = file.tellg();
        file.seekg(0, std::ios::end);
        ios::pos_type size = file.tellg();
        file.seekg(backup, std::ios::beg);
        return (int)size;
    }

    void ConvertToRGB565()
    {
        uint8  *rgb888 = (uint8*)  &m_rgb888Buffer[0];
        uint16 *rgb565 = (uint16*) &m_rgb565Buffer[0];
        uint32 R, G, B;

        for(uint32 i = 0; i < m_width * m_height; ++ i) {
            R = rgb888[0]; G = rgb888[1]; B = rgb888[2];
            *rgb565 = ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3);
            ++ rgb565;
            rgb888 += 3;
        }
    }
    
    void ConvertToARGB8888()
    {
        uint8  *rgb888   = (uint8*)  &m_rgb888Buffer[0];
        uint32 *argb8888 = (uint32*) &m_argb8888Buffer[0];
        uint32 R, G, B;

        for(uint32 i = 0; i < m_width * m_height; ++ i) {
            R = rgb888[0];
            G = rgb888[1]; 
            B = rgb888[2];
            *argb8888 = (0xFF << 24) | (R << 16) | (G << 8) | (B);
            ++argb8888;
            rgb888 += 3;
        }
    }

    #define CLIP_255(x) ((x)>255?255:(x))

    void ConvertToRGB565Dither(void) 
    {
        unsigned short DitherMatrix_3Bit_16[4] = {0x5140, 0x3726, 0x4051, 0x2637};
        unsigned int count = 0;
        unsigned int sr,sg,sb;
        unsigned int x, y;
        unsigned short dither_scan = 0;
        uint8  *src= (uint8*)  &m_rgb888Buffer[0];
        uint16 *dst= (uint16*) &m_rgb565Buffer[0];

        for(count = 0;count < m_width*m_height;count++)	
        {
            x = count % m_width;
            y = count / m_width;
            dither_scan = DitherMatrix_3Bit_16[(y) & 3];

            unsigned short dither = ((dither_scan >> (((x) & 3) << 2)) & 0xF);
            sr = ((CLIP_255(((*(src+0) + dither - (*(src+0) >> 5)))) >> (8 - 5)));
            sg = ((CLIP_255(((*(src+1) + (dither >> 1) - (*(src+1) >> 6)))) >> (8 - 6)));
            sb = ((CLIP_255(((*(src+2) + dither - (*(src+2) >> 5)))) >> (8 - 5)));
            printf("%3d,%3d,%3d|%3d,%3d,%3d|%3d,%3d,%3d|%d,%d|%d,%d\n",
                  (sr<<3)-*(src+0), (sg<<2)-*(src+1),(sb<<3)-*(src+2),
                   sr<<3,sg<<2,sb<<3,
                   *(src+0), *(src+1),*(src+2),
                   x,y,
                   dither_scan, dither);
            src += 3;

            *dst++ = ((uint16_t)((sr << (5 + 6)) | (sg << (5)) | (sb << 0)));
    	}
    }


private:
    vector<char> m_bitstream;
    vector<char> m_rgb888Buffer;
    vector<char> m_argb8888Buffer;
    vector<char> m_rgb565Buffer;
    uint32 m_width, m_height;
};

// -------------------------------------------------------------------------------------

int main(int argc, const char* argv[])
{
    if (argc < 3) {
        cout << endl << "[Usage] bmp_to_logo logofile bmpfile1 [bmpfile2] ..." << endl << endl;
        cout << "Example: bmp_to_logo fhd.raw fhd_uboot.bmp fhd_kernel.bmp ..." << endl << endl;
        return -1;
    }

    const char *logo_filename = argv[1];
    const char *bmp_filename  = argv[2];

    BmpToLogo bmpToLogo;
    if (!bmpToLogo.DoBmpToLogo(bmp_filename, logo_filename, false)) {
        return -2;
    }

    for (int i = 3; i < argc; ++ i) {
        bmp_filename = argv[i];
        if (!bmpToLogo.DoBmpToLogo(bmp_filename, logo_filename, true)) {
            return -2;
        }
    }
}

以下代码中宽、高值都需要替换为你自己的正确值,不然会转换不正常

2、c++ 版本源码

rawmain.cpp

#include <iostream>  
#include <fstream>  
#include <vector>  
  
using namespace std;  
  
#pragma pack(push, 1)  
  
typedef struct BITMAPFILEHEADER {  
    unsigned short bfType;  
    unsigned int bfSize;  
    unsigned short bfReserved1;  
    unsigned short bfReserved2;  
    unsigned int bfOffBits;  
} BITMAPFILEHEADER;  
  
typedef struct BITMAPINFOHEADER {  
    unsigned int biSize;  
    int biWidth;  
    int biHeight;  
    unsigned short biPlanes;  
    unsigned short biBitCount;  
    unsigned int biCompression;  
    unsigned int biSizeImage;  
    int biXPelsPerMeter;  
    int biYPelsPerMeter;  
    unsigned int biClrUsed;  
    unsigned int biClrImportant;  
} BITMAPINFOHEADER;  

typedef unsigned char  uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int   uint32_t;

typedef uint16_t uint16;
typedef uint8_t uint8;
typedef uint32_t uint32;

vector<char> m_bitstream;
vector<char> m_rgb888Buffer;
uint32 m_width = 800;
uint32 m_height = 1280;

#pragma pack(pop)  

int GetFileSize(ifstream& file)
{
    ios::pos_type backup = file.tellg();
    file.seekg(0, std::ios::end);
    ios::pos_type size = file.tellg();
    file.seekg(backup, std::ios::beg);
    return (int)size;
}


/*void ConvertToARGB8888()
{
    uint8  *rgb888   = (uint8*)  &m_rgb888Buffer[0];
    uint32 *argb8888 = (uint32*) &m_argb8888Buffer[0];
    uint32 R, G, B;

    for(uint32 i = 0; i < m_width * m_height; ++ i) {
        R = rgb888[0];
        G = rgb888[1]; 
        B = rgb888[2];
        *argb8888 = (0xFF << 24) | (R << 16) | (G << 8) | (B);
        ++argb8888;
        rgb888 += 3;
    }
}*/

void ConvertFromARGB8888() {  
    // uint32 *argb8888 = (uint32*) &m_argb8888Buffer[0];  
    uint32 *argb8888 = (uint32*) &m_bitstream[0];  
    uint8  *rgb888   = (uint8*)  &m_rgb888Buffer[0];  
    uint32 R, G, B, A;  
  
    //数据左右翻转了
    for(uint32 i = m_width * m_height - 1; i > 0; --i) {  
        // A = argb8888[i] >> 24;  
        R = (argb8888[i] >> 16);  
        G = (argb8888[i] >> 8);  
        B = argb8888[i];  
  
        rgb888[0] = B;  
        rgb888[1] = G;  
        rgb888[2] = R;  
        rgb888 += 3;
    }  

}


void ConvertFromARGB88882() {
    uint32 *argb8888 = (uint32*) &m_bitstream[0];  
    uint8  *rgb888   = (uint8*)  &m_rgb888Buffer[0];  
    uint32 R, G, B;  
    //bmp格式的位图区存储顺序是从下到上,从左到右
    for(int y = m_height - 1; y >= 0; --y) {  // 从最后一行开始,向上遍历
        for(uint32 x = 0; x < m_width; ++x) {  // 从每行的第一个像素开始,向右遍历
            uint32 i = y * m_width + x;
            R = (argb8888[i] >> 16) & 0xFF;  
            G = (argb8888[i] >> 8) & 0xFF;  
            B = argb8888[i] & 0xFF;  
            rgb888[0] = B;  
            rgb888[1] = G;  
            rgb888[2] = R;  
            rgb888 += 3;
        }
    }
}

int main(int argc, const char* argv[]) {  

    if (argc < 3) {
        cout << endl << "[Usage] raw_to_bmp rawfile bmpfile " << endl << endl;
        cout << "Example: raw_to_bmp logo.raw logo.bmp " << endl << endl;
        return -1;
    }

    const char *rawFilename  = argv[1];
    ifstream rawFile;
    rawFile.open(rawFilename, ios::in | ios::binary);
    if (!rawFile.is_open()) {
        cout << "open " << rawFilename << " failed!" << endl;
        return -1;
    }

    int rawFileSize = GetFileSize(rawFile);
    m_bitstream.resize(rawFileSize);
    rawFile.read(&m_bitstream[0], m_bitstream.size());
    
    m_rgb888Buffer.resize(m_width * m_height * 3);
    // m_argb8888Buffer.resize(width * height * 4);

    ConvertFromARGB88882();

    // 创建BMP文件头和信息头  
    BITMAPFILEHEADER fileHeader = {0x4D42, 54 + m_bitstream.size(), 0, 0, 54};  
    BITMAPINFOHEADER infoHeader = {40, m_width, m_height, 1, 24, 0, m_bitstream.size(), 0, 0, 0, 0};  
  
    // 创建BMP文件并写入头和数据  
    const char *bmpFilename  = argv[2];

    ofstream outputFile(bmpFilename, ios::binary);  
    if (!outputFile) {  
        cout << "open " << bmpFilename << " failed!" << endl; 
        return -1;  
    }  
    outputFile.write(reinterpret_cast<char*>(&fileHeader), sizeof(fileHeader));  
    outputFile.write(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));  
    // outputFile.write(data.data(), data.size());  
    // outputFile.write(&m_bitstream[0], m_bitstream.size());  
    outputFile.write(&m_rgb888Buffer[0], m_rgb888Buffer.size());  
    outputFile.close();  
  
    return 0;  
}

2.1、编译指令

g++ -m32 rawmain.cpp -o raw_to_bmp

raw_to_bmp下载

2.2、回转 bmp 文件

使用方法

[Usage] raw_to_bmp rawfile bmpfile

Example: raw_to_bmp logo.raw logo.bmp

3、python 版本源码

raw_to_bmp.py

# coding=UTF-8
import struct

#使用方法
#python raw_to_bmp.py input.raw

# 图像的宽度和高度
WIDTH = 800
HEIGHT = 1280

# BMP文件头和信息头的大小
FILE_HEADER_SIZE = 14
INFO_HEADER_SIZE = 40

def create_bmp_header(width, height):
    # 计算图像数据大小
    data_size = width * height * 3  # RGB888

    # 创建BMP文件头
    file_header = struct.pack('<2sIHHI', b'BM', FILE_HEADER_SIZE + INFO_HEADER_SIZE + data_size, 0, 0, FILE_HEADER_SIZE + INFO_HEADER_SIZE)

    # 创建BMP信息头
    info_header = struct.pack('

3.1、回转 bmp 文件

使用方法

python raw_to_bmp.py input.raw

4、java 版本源码

RawToBitMap.java

/**
 * Created by cczheng on 2023/9/14.
 * 

* https://www.cnblogs.com/chenrui7/p/4561020.html *

* https://www.bilibili.com/read/cv15459784/ */ public class RawToBitMap { /** * 从流中读取数组 * * @param stream 输入流 * @return */ public static byte[] readByteArrayFormStream(InputStream stream) { try { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); int len = 0; byte[] tmp = new byte[1024]; while ((len = stream.read(tmp)) != -1) { outStream.write(tmp, 0, len); } byte[] data = outStream.toByteArray(); Log.d("bmp", "data length=" + data.length); return data; } catch (IOException e) { e.printStackTrace(); return new byte[0]; } } /** * 8位灰度转Bitmap *

* 图像宽度必须能被4整除 * * @param data 裸数据 * @param width 图像宽度 * @param height 图像高度 * @return */ public static Bitmap convert8bit(byte[] data, int width, int height) { byte[] Bits = new byte[data.length * 4]; //RGBA 数组 int i; for (i = 0; i < data.length; i++) { // 原理:4个字节表示一个灰度,则RGB = 灰度值,最后一个Alpha = 0xff; Bits[i * 4] = Bits[i * 4 + 1] = Bits[i * 4 + 2] = data[i]; Bits[i * 4 + 3] = -1; //0xff } // Bitmap.Config.ARGB_8888 表示:图像模式为8位 Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bmp.copyPixelsFromBuffer(ByteBuffer.wrap(Bits)); return bmp; } /** * 24位灰度转Bitmap *

* 图像宽度必须能被4整除 * * @param data 裸数据 * @param width 图像宽度 * @param height 图像高度 * @return */ public static Bitmap convert24bit(byte[] data, int width, int height) { int i; /*void ConvertToARGB8888() { uint8 *rgb888 = (uint8*) &m_rgb888Buffer[0]; uint32 *argb8888 = (uint32*) &m_argb8888Buffer[0]; uint32 R, G, B; for(uint32 i = 0; i < m_width * m_height; ++ i) { R = rgb888[0]; G = rgb888[1]; B = rgb888[2]; *argb8888 = (0xFF << 24) | (R << 16) | (G << 8) | (B); ++argb8888; rgb888 += 3; } }*/ /*int[] iData = new int[data.length / 3]; //RGBA 数组// data.length / 3 表示 3位为一组 for (i = 0; i < data.length / 3; i++) {// 原理:24位是有彩色的,所以要复制3位,最后一位Alpha = 0xff; // iData[i] = (((int) data[i * 3]) << 16) + (((int) data[i * 3 + 1]) << 8) + data[i * 3 + 2] + 0xff000000; // iData[i] = (((int) data[i * 3]) >> 16) + (((int) data[i * 3 + 1]) >> 8) + data[i * 3 + 2] + 0xff000000; iData[i] = data[i * 3] | 0xff + (((int) data[i * 3 + 1] | 0xff) >> 8) + (((int) data[i * 3 + 2] | 0xff ) >> 16) +0xff; } Bitmap bmp = Bitmap.createBitmap(iData, width, height, Bitmap.Config.ARGB_8888);*/ byte[] Bits = new byte[data.length * 3]; byte A, R, G, B; for (i = 0; i < data.length / 3; i++) { R = data[i * 3]; G = data[i * 3 + 1]; B = data[i * 3 + 2]; // A = -1; //int color = (A & 0xff) << 24 | (B & 0xff) << 16 | (G & 0xff) << 8 | (R & 0xff); Bits[i * 3] = R; Bits[i * 3 + 1] = G; Bits[i * 3 + 2] = B; // Bits[i * 3 + 3] = A; } Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bmp.copyPixelsFromBuffer(ByteBuffer.wrap(Bits)); return bmp; } private static byte[] parseRGBByte(byte argb8888) { byte[] rdata = new byte[4]; rdata[0] = (byte) ((argb8888 >> 24) & 0xFF); // 获取A通道的值 rdata[1] = (byte) ((argb8888 >> 16) & 0xFF); // 获取R通道的值 rdata[2] = (byte) ((argb8888 >> 8) & 0xFF); // 获取G通道的值 rdata[3] = (byte) ((argb8888) & 0xFF); // 获取B通道的值 return rdata; } /** * 8位灰度转Bitmap * * @param stream 输入流 * @param width 图像宽度 * @param height 图像高度 * @return */ public static Bitmap convert8bit(InputStream stream, int width, int height) { return convert8bit(readByteArrayFormStream(stream), width, height); } /** * 24位灰度转Bitmap * * @param stream 输入流 * @param width 图像宽度 * @param height 图像高度 * @return */ public static Bitmap convert24bit(InputStream stream, int width, int height) { Bitmap bitmap = convert24bit(readByteArrayFormStream(stream), width, height); saveBmp2Sdcard(bitmap); return bitmap; } private static void saveBmp2Sdcard(Bitmap bitmap) { File mSubFolder = new File( "/sdcard/DCIM/"); if (!mSubFolder.exists()) { mSubFolder.mkdir(); } String s = "test.png"; File f = new File(mSubFolder.getAbsolutePath(), s); FileOutputStream fos = null; try { fos = new FileOutputStream(f); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }

4.1、回转 bmp 文件

使用方法

try {
Bitmap bitmap = RawToBitMap.convert24bit(getAssets().open(“input.raw”), 800, 1280);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}

你可能感兴趣的:(开机Logo,动画,mtk,logo)