版权声明:本文为博主 ( 黃彥霖 ) 原创文章,未经博主允许不得转载。 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;
}
}