Unity 3D : 實作 BMP 編碼器 ( 以 Byte 字節編碼 )

版权声明:本文为博主 ( 黃彥霖 ) 原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38884324/article/details/80612470

前言 :

Unity 3D 的 Texturd2D 只有 PNG, JPG, EXR 這三種編碼,如果你想要 BMP 編碼,無外乎只能依靠第三方庫,不然就是自己實作編碼器…

我這裡採取了後者,俗話說不要重複造輪子,但這句對我行不通…,因為我要的是 ” 跨平台 ” 阿,你的輪子可以跨平台 ? ( 笑 ) ,弄懂算法,你想要移植到哪個平台都行,Android / Linux / Windows / iOS / MacOSX / 嵌入式系統 / 單晶片 / FPGA …. ,最好有哪個第三方 Library 這些系統都能跨拉哈,因為我的工作比較特殊,會同時做 軟件 & 硬件 ,所以弄懂算法然後跨平台是必須的。但是如果沒有特殊原因,能用第三方庫就用的三方庫吧,畢竟也省時省力。

對了,建議你可以一起看我之前寫的文章 ” BMP解碼器 ”

https://blog.csdn.net/weixin_38884324/article/details/80609858

然後我們先來看執行結果吧 !

執行結果 :

好吧,我承認這張有放跟沒放一樣… 基本上執行後就會輸出一張 BMP 格式的圖片…

这里写图片描述

C # :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class NewBehaviourScript2 : MonoBehaviour
{
    public Texture2D inputImg; // 請從外面拉一張圖片進來 ( # 重要 : 請記得將圖片設置為"可讀寫")

    void Start()
    {
        int fileSize = SaveToBMP("C:/FFMPEG/XXX.bmp", inputImg); // 保存到這路徑,按照你自己的需求改吧
        print("保存成功,檔案大小:" + fileSize);
    }

    byte[] file;

    // return : 保存 BMP 後,返回文件大小
    int SaveToBMP(string savePath, Texture2D img)
    {
        // --------------------------------------------------------------------------
        // 計算圖像寬度佔多少 Byte
        // BMP 規定圖像寬度 Byte 數量必須是4的倍數,不足處末尾全補零

        int yu = img.width * 3 % 4;
        yu = yu != 0 ? 4 - yu : yu;
        int bytePerLine = img.width * 3 + yu;

        // --------------------------------------------------------------------------
        // 初始化一些參數

        int fileHeaderSize = 14; // 文件標頭大小
        int infoHeaderSize = 40; // 訊息標頭大小
        int headerSize = fileHeaderSize + infoHeaderSize;
        int allColorSize = bytePerLine * img.height; // 圖像總 Byte 數量
        int fileSize = headerSize + allColorSize; // 檔案最終大小

        file = new byte[fileSize];

        // --------------------------------------------------------------------------
        // BMP File : File Header

        file[0] = 0x42; // ASCII : B
        file[1] = 0x4D; // ASCII : M
        SetIntTo4Byte(0x0002, fileSize); // File Size
        SetIntTo4Byte(0x000A, headerSize); // 頭檔大小

        // --------------------------------------------------------------------------
        // BMP File : Info Header

        SetIntTo4Byte(0x000E, infoHeaderSize); // Info Headder Size
        SetIntTo4Byte(0x0012, img.width); // Width
        SetIntTo4Byte(0x0016, img.height); // Height
        SetIntTo2Byte(0x001A, 1); // Planes
        SetIntTo2Byte(0x001C, 24); // BitCount
        SetIntTo4Byte(0x001E, 0); // Compression : 壓縮方式設為不壓縮
        SetIntTo4Byte(0x0022, allColorSize); // SizeImage : 圖像大小 (不包含標頭)
        SetIntTo4Byte(0x0026, 3780); // XPelsPerMeter
        SetIntTo4Byte(0x002A, 3780); // YPelsPerMeter
        SetIntTo4Byte(0x002E, 0); // ClrUsed
        SetIntTo4Byte(0x0032, 0); // ClrImportant

        // --------------------------------------------------------------------------
        // BMP File : Colors Data

        Color32[] colors = inputImg.GetPixels32();

        for (int y = 0, k = 0; y < img.height; y++)
        {
            for (int x = 0, i = 0; x < img.width; x++, k++)
            {
                Color32 color = colors[k];
                int index = headerSize + y * bytePerLine;

                file[index + i++] = color.b;
                file[index + i++] = color.g;
                file[index + i++] = color.r;
            }
        }

        File.WriteAllBytes(savePath, file);

        return fileSize;
    }

    void SetIntTo2Byte(int offset, int value)
    {
        file[offset] = (byte)(value & 0x000000FF);
        file[offset + 1] = (byte)((value & 0x0000FF00) >> 8);
    }

    void SetIntTo4Byte(int offset, int value)
    {
        file[offset] = (byte)(value & 0x000000FF);
        file[offset + 1] = (byte)((value & 0x0000FF00) >> 8);
        file[offset + 2] = (byte)((value & 0x00FF0000) >> 16);
        file[offset + 3] = (byte)((value & 0xFF000000) >> 24);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38884324/article/details/80612470