Unity 3D : TIFF 8bit / 16bit / II / MM 編碼器 範例

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

前言 :

簡易 TIFF 編碼器實現,可以編 8bit / 16bit 與 II / MM 排序,花了好幾天做的,湊合看吧

另外解碼器可以看我之前寫的這篇 : https://blog.csdn.net/weixin_38884324/article/details/81904939

執行結果 :

輸入 Texture2D ;輸出 TIFF 圖片。

这里写图片描述

EncodeTIFF.cs :

using System.IO;
using UnityEngine;

public class EncodeTIFF
{

    string order = "II";
    byte bit = 8;

    public void SetOrder(string order)
    {
        if (order != "MM" && order != "II")
        {
            throw new UnityException("Order Value Error !");
        }
        this.order = order;
    }

    public void SetBit(byte bit)
    {
        if (bit != 8 && bit != 16)
        {
            throw new UnityException("Bit Value Error !");
        }
        this.bit = bit;
    }

    uint[,,] pixels;
    Texture2D inputTexture;

    int width = 0;
    int height = 0;

    public void SetPixels(Texture2D inputTexture)
    {
        width = inputTexture.width;
        height = inputTexture.height;
        this.inputTexture = inputTexture;
    }

    // [ x, y, rgb ]
    public void SetPixels(uint[,,] pixels)
    {
        this.pixels = pixels;
        this.width = pixels.GetLength(0);
        this.height = pixels.GetLength(1);
    }

    public void Save(string path)
    {
        if (inputTexture != null)
        {
            if (bit == 16)
            {
                if (inputTexture.format != TextureFormat.RGBAHalf && inputTexture.format != TextureFormat.RGBAFloat)
                {
                    throw new UnityException("輸入的 Texture2D 格式錯誤。16bit 的 Texture2D 格式必須使用 TextureFormat.RGBAHalf 或 TextureFormat.RGBAFloat。");
                }
            }
        }

        // 圖片文件標頭 ( Image File Header 簡稱 IFH )
        byte[] ifh = GetIFH(order); // 目前只能支持 II

        byte dec = 13; // 可調 ( 多少 DE 就填多少 )
        uint valueOffsetStartIndex = 300; // 可調 ( valueOffset 的起點, 注意 : 該值要大於 8 + 2 + 12 * dec )
        uint ImageStartIndex = 1000; // 可調 ( 圖像起點, 注意 : 該值須大於 valueOffsetStartIndex )

        uint valueCount = 0; // 主要對 valueOffsetStartIndex 累加

        byte[] ifd = new byte[2 + 12 * dec];

        byte[] b = null;

        b = new byte[ifh.Length + ifd.Length + ImageStartIndex + width * height * 3 * (bit / 8)];

        int ifd_index = 0;

        // Add DE Count [ 一定要加 ]
        ifd_index = AddDEC(order, ifd, ifd_index, dec);

        // Add DE 1 : NewSubfileType
        ifd_index = AddDE(order, ifd, ifd_index, 254, 4, 1, 0);

        // Add DE 2 : Width [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 256, 4, 1, (uint)width);

        // Add DE 3 : Height [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 257, 4, 1, (uint)height);

        // Add DE 4 : BitsPerSample [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 258, 3, 3, valueOffsetStartIndex);

        if (order == "II")
        {
            b[valueOffsetStartIndex + valueCount++] = bit; // 每個像素幾 bit 
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = bit;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = bit;
            b[valueOffsetStartIndex + valueCount++] = 0;
        }
        else if (order == "MM")
        {
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = bit; // 每個像素幾 bit 
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = bit;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = bit;
        }

        // Add DE 5 : Compression
        ifd_index = AddDE(order, ifd, ifd_index, 259, 3, 1, 1);

        // Add DE 6 : PhotometricInterpretation [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 262, 3, 1, 2);

        // Add DE 7 : StripOffsets [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 273, 4, 1, ImageStartIndex);

        // Add DE 8 : Orientation
        ifd_index = AddDE(order, ifd, ifd_index, 274, 3, 1, 1);

        // Add DE 9 : SamplesPerPixel [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 277, 3, 1, 3);

        // Add DE 10 : RowsPerStrip
        ifd_index = AddDE(order, ifd, ifd_index, 278, 4, 1, (uint)height);

        // Add DE 11 : XResolution
        ifd_index = AddDE(order, ifd, ifd_index, 282, 5, 1, valueOffsetStartIndex + valueCount);

        if (order == "II")
        {
            b[valueOffsetStartIndex + valueCount++] = 72;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;

            b[valueOffsetStartIndex + valueCount++] = 1;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
        }
        else if (order == "MM")
        {
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 72;

            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 1;
        }



        // Add DE 12 : YResolution
        ifd_index = AddDE(order, ifd, ifd_index, 283, 5, 1, valueOffsetStartIndex + valueCount);

        if (order == "II")
        {
            b[valueOffsetStartIndex + valueCount++] = 72;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;

            b[valueOffsetStartIndex + valueCount++] = 1;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
        }
        else if (order == "MM")
        {
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 72;

            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 0;
            b[valueOffsetStartIndex + valueCount++] = 1;
        }

        // Add DE 13 : ResolutionUnit [ 一定要加 ]
        ifd_index = AddDE(order, ifd, ifd_index, 296, 3, 1, 2);

        // ----------------------------------------------------------------------------
        // Set Pixel :

        PixelsToByte(ImageStartIndex, b);

        // ----------------------------------------------------------------------------
        // Write To File :

        for (int i = 0; i < ifh.Length; i++)
        {
            b[i] = ifh[i];
        }

        for (int i = 0, k = 8; i < ifd.Length; i++, k++)
        {
            b[k] = ifd[i];
        }

        File.WriteAllBytes(path, b);
    }

    void PixelsToByte(uint index, byte[] b)
    {
        //---------------------------------------------------------------
        // 8 Bit (II / MM)
        if (bit == 8)
        {
            if (inputTexture != null)
            {
                // 從 Texture2D 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        Color c = inputTexture.GetPixel(x, mY);

                        b[index + 0] = (byte)(c.r * 255);
                        b[index + 1] = (byte)(c.g * 255);
                        b[index + 2] = (byte)(c.b * 255);

                        index += 3;
                    }
                }
            }
            else
            {
                // 從 int[,,] 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        b[index + 0] = (byte)pixels[x, mY, 0];
                        b[index + 1] = (byte)pixels[x, mY, 1];
                        b[index + 2] = (byte)pixels[x, mY, 2];

                        index += 3;
                    }
                }
            }
        }
        //---------------------------------------------------------------
        // 16 Bit (II)
        else if (order == "II" && bit == 16)
        {
            if (inputTexture != null)
            {
                // 從 Texture2D 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        Color c = inputTexture.GetPixel(x, mY);

                        byte[] R = ToByte2((ushort)(c.r * 65535));
                        byte[] G = ToByte2((ushort)(c.g * 65535));
                        byte[] B = ToByte2((ushort)(c.b * 65535));

                        b[index + 0] = R[1];
                        b[index + 1] = R[0];

                        b[index + 2] = G[1];
                        b[index + 3] = G[0];

                        b[index + 4] = B[1];
                        b[index + 5] = B[0];

                        index += 6;
                    }
                }
            }
            else
            {
                // 從 int[,,] 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        byte[] R = ToByte2((ushort)pixels[x, mY, 0]);
                        byte[] G = ToByte2((ushort)pixels[x, mY, 1]);
                        byte[] B = ToByte2((ushort)pixels[x, mY, 2]);

                        b[index + 0] = R[1];
                        b[index + 1] = R[0];

                        b[index + 2] = G[1];
                        b[index + 3] = G[0];

                        b[index + 4] = B[1];
                        b[index + 5] = B[0];

                        index += 6;
                    }
                }
            }
        }
        //---------------------------------------------------------------
        // 16 Bit (MM)
        else if (order == "MM" && bit == 16)
        {
            if (inputTexture != null)
            {
                // 從 Texture2D 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        Color c = inputTexture.GetPixel(x, mY);

                        byte[] R = ToByte2((ushort)(c.r * 65535));
                        byte[] G = ToByte2((ushort)(c.g * 65535));
                        byte[] B = ToByte2((ushort)(c.b * 65535));

                        b[index + 0] = R[0];
                        b[index + 1] = R[1];

                        b[index + 2] = G[0];
                        b[index + 3] = G[1];

                        b[index + 4] = B[0];
                        b[index + 5] = B[1];

                        index += 6;
                    }
                }
            }
            else
            {
                // 從 int[,,] 寫入
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int mY = height - 1 - y;

                        byte[] R = ToByte2((ushort)pixels[x, mY, 0]);
                        byte[] G = ToByte2((ushort)pixels[x, mY, 1]);
                        byte[] B = ToByte2((ushort)pixels[x, mY, 2]);

                        b[index + 0] = R[0];
                        b[index + 1] = R[1];

                        b[index + 2] = G[0];
                        b[index + 3] = G[1];

                        b[index + 4] = B[0];
                        b[index + 5] = B[1];

                        index += 6;
                    }
                }
            }
        }
    }


    byte[] ToByte2(ushort value) // 輸入 : 0~65535,輸出 MM 排序 byte[]
    {
        return new byte[] { (byte)((value & 0xFF00) >> 8), (byte)(value & 0x00FF) };
    }

    byte[] ToByte4(uint value) // 輸入 : 0~4294967295,輸出 MM 排序 byte[]
    {
        return new byte[] { (byte)((value & 0xFF000000) >> 24), (byte)((value & 0x00FF0000) >> 16), (byte)((value & 0x0000FF00) >> 8), (byte)(value & 0x000000FF) };
    }

    byte[] GetIFH(string order)
    {
        byte[] ifh = new byte[8];

        if (order == "II")
        {
            ifh[0] = 0x49; // Byte Order : 0x49 = I
            ifh[1] = 0x49; // Byte Order : 0x49 = I
            ifh[2] = 0x2A; // Version
            ifh[3] = 0x00; // Version
            ifh[4] = 0x08; // Offset to first IFD
            ifh[5] = 0x00; // Offset to first IFD
            ifh[6] = 0x00; // Offset to first IFD
            ifh[7] = 0x00; // Offset to first IFD
        }
        else if (order == "MM")
        {
            ifh[0] = 0x4D; // Byte Order : 0x4D = M
            ifh[1] = 0x4D; // Byte Order : 0x4D = M
            ifh[2] = 0x00; // Version
            ifh[3] = 0x2A; // Version
            ifh[4] = 0x00; // Offset to first IFD
            ifh[5] = 0x00; // Offset to first IFD
            ifh[6] = 0x00; // Offset to first IFD
            ifh[7] = 0x08; // Offset to first IFD
        }
        else
        {
            throw new UnityException("Order Value Error !");
        }
        return ifh;
    }

    int AddDEC(string order, byte[] ifd, int index, ushort dec)
    {
        byte[] decBytes = ToByte2(dec);
        if (order == "II")
        {
            ifd[index++] = decBytes[1];
            ifd[index++] = decBytes[0];
        }
        else if (order == "MM")
        {
            ifd[index++] = decBytes[0];
            ifd[index++] = decBytes[1];
        }
        else
        {
            throw new UnityException("Order Value Error !");
        }
        return index;
    }

    int AddDE(string order, byte[] ifd, int index, ushort tag, ushort type, uint length, uint valueOffset)
    {
        byte[] _tag = ToByte2(tag);
        byte[] _type = ToByte2(type);
        byte[] _length = ToByte4(length);
        byte[] _valueOffset = null;

        if (order == "II")
        {
            ifd[index + 0] = _tag[1];
            ifd[index + 1] = _tag[0];
            ifd[index + 2] = _type[1];
            ifd[index + 3] = _type[0];
            ifd[index + 4] = _length[3];
            ifd[index + 5] = _length[2];
            ifd[index + 6] = _length[1];
            ifd[index + 7] = _length[0];

            if (type == 1)
            {
                // 未實現
            }
            else if (type == 2)
            {
                // 未實現
            }
            else if (type == 3)
            {
                if (length <= 2)
                {
                    _valueOffset = ToByte2((ushort)valueOffset);
                    ifd[index + 8] = _valueOffset[1];
                    ifd[index + 9] = _valueOffset[0];
                    ifd[index + 10] = 0;
                    ifd[index + 11] = 0;
                }
                else
                {
                    _valueOffset = ToByte4(valueOffset);
                    ifd[index + 8] = _valueOffset[3];
                    ifd[index + 9] = _valueOffset[2];
                    ifd[index + 10] = _valueOffset[1];
                    ifd[index + 11] = _valueOffset[0];
                }
            }
            else if (type == 4)
            {
                _valueOffset = ToByte4(valueOffset);
                ifd[index + 8] = _valueOffset[3];
                ifd[index + 9] = _valueOffset[2];
                ifd[index + 10] = _valueOffset[1];
                ifd[index + 11] = _valueOffset[0];
            }
            else if (type == 5)
            {
                _valueOffset = ToByte4(valueOffset);
                ifd[index + 8] = _valueOffset[3];
                ifd[index + 9] = _valueOffset[2];
                ifd[index + 10] = _valueOffset[1];
                ifd[index + 11] = _valueOffset[0];
            }
        }
        else if (order == "MM")
        {
            ifd[index + 0] = _tag[0];
            ifd[index + 1] = _tag[1];
            ifd[index + 2] = _type[0];
            ifd[index + 3] = _type[1];
            ifd[index + 4] = _length[0];
            ifd[index + 5] = _length[1];
            ifd[index + 6] = _length[2];
            ifd[index + 7] = _length[3];


            if (type == 1)
            {
                // 未實現
            }
            else if (type == 2)
            {
                // 未實現
            }
            else if (type == 3)
            {
                if (length <= 2)
                {
                    _valueOffset = ToByte2((ushort)valueOffset);
                    ifd[index + 8] = _valueOffset[0];
                    ifd[index + 9] = _valueOffset[1];
                    ifd[index + 10] = 0;
                    ifd[index + 11] = 0;
                }
                else
                {
                    _valueOffset = ToByte4(valueOffset);
                    ifd[index + 8] = _valueOffset[0];
                    ifd[index + 9] = _valueOffset[1];
                    ifd[index + 10] = _valueOffset[2];
                    ifd[index + 11] = _valueOffset[3];
                }
            }
            else if (type == 4)
            {
                _valueOffset = ToByte4(valueOffset);
                ifd[index + 8] = _valueOffset[0];
                ifd[index + 9] = _valueOffset[1];
                ifd[index + 10] = _valueOffset[2];
                ifd[index + 11] = _valueOffset[3];
            }
            else if (type == 5)
            {
                _valueOffset = ToByte4(valueOffset);
                ifd[index + 8] = _valueOffset[0];
                ifd[index + 9] = _valueOffset[1];
                ifd[index + 10] = _valueOffset[2];
                ifd[index + 11] = _valueOffset[3];
            }
        }
        else
        {
            throw new UnityException("Order Value Error !");
        }
        return index += 12;
    }
}

猜你喜欢

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