Framwork/Assets/Scripts/Runtime/Test/ImageConverter.cs

166 lines
5.7 KiB
C#
Raw Normal View History

2025-07-02 10:24:01 +08:00
using UnityEngine;
using System.IO;
using BitMiracle.LibTiff.Classic;
public class ImageConverter : MonoBehaviour
{
public string pngPath;
public string tiffPath;
[ContextMenu("PngToTiff")]
void PNG()
{
PngToTiff(pngPath, tiffPath);
}
[ContextMenu("TiffToPng")]
void TIFF()
{
TiffToPng(tiffPath, pngPath);
}
// 检查纹理是否包含透明通道
private static bool HasTransparency(Texture2D tex)
{
Color32[] pixels = tex.GetPixels32();
for (int i = 0; i < pixels.Length; i++)
{
if (pixels[i].a < 255)
return true;
}
return false;
}
// PNG 转 TIFF (完整支持透明通道)
public static void PngToTiff(string pngPath, string tiffPath, int compression = 5)
{
// 加载PNG文件
byte[] pngBytes = File.ReadAllBytes(pngPath);
Texture2D sourceTex = new Texture2D(2, 2, TextureFormat.RGBA32, false);
sourceTex.LoadImage(pngBytes);
// 检查是否包含透明通道
bool hasAlpha = HasTransparency(sourceTex);
int channels = hasAlpha ? 4 : 3;
// 准备TIFF图像数据
byte[] tiffData = new byte[sourceTex.width * sourceTex.height * channels];
int pixelIndex = 0;
// 垂直翻转并处理像素数据Unity是左下原点TIFF是左上原点
for (int y = sourceTex.height - 1; y >= 0; y--)
{
for (int x = 0; x < sourceTex.width; x++)
{
Color32 pixel = sourceTex.GetPixel(x, y);
tiffData[pixelIndex++] = pixel.r;
tiffData[pixelIndex++] = pixel.g;
tiffData[pixelIndex++] = pixel.b;
if (hasAlpha)
{
tiffData[pixelIndex++] = pixel.a;
}
}
}
// 创建TIFF文件
using (Tiff tiff = Tiff.Open(tiffPath, "w"))
{
// 设置基本参数
tiff.SetField(TiffTag.IMAGEWIDTH, sourceTex.width);
tiff.SetField(TiffTag.IMAGELENGTH, sourceTex.height);
tiff.SetField(TiffTag.SAMPLESPERPIXEL, channels);
tiff.SetField(TiffTag.BITSPERSAMPLE, 8);
tiff.SetField(TiffTag.ROWSPERSTRIP, sourceTex.height);
tiff.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
tiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
// 设置光度解释RGB或带Alpha的RGB
tiff.SetField(TiffTag.PHOTOMETRIC, hasAlpha ? Photometric.RGB : Photometric.MINISBLACK);
// 设置Alpha通道信息
if (hasAlpha)
{
ushort[] extrasamples = { (ushort)ExtraSample.UNASSALPHA };
tiff.SetField(TiffTag.EXTRASAMPLES, extrasamples.Length, extrasamples);
}
// 设置压缩
if (compression > 0)
{
tiff.SetField(TiffTag.COMPRESSION, Compression.ADOBE_DEFLATE);
tiff.SetField(TiffTag.ZIPQUALITY, compression);
}
else
{
tiff.SetField(TiffTag.COMPRESSION, Compression.NONE);
}
// 写入图像数据
tiff.WriteEncodedStrip(0, tiffData, tiffData.Length);
}
}
// TIFF 转 PNG (支持透明通道)
public static void TiffToPng(string tiffPath, string pngPath, bool preserveAlpha = true)
{
using (Tiff tiff = Tiff.Open(tiffPath, "r"))
{
int width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
int height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
int channels = tiff.GetField(TiffTag.SAMPLESPERPIXEL)[0].ToInt();
// 检查是否有额外通道如Alpha
FieldValue[] extraSamples = tiff.GetField(TiffTag.EXTRASAMPLES);
bool hasAlpha = extraSamples != null && extraSamples.Length > 0 &&
extraSamples[0].ToInt() == (int)ExtraSample.UNASSALPHA;
// 读取图像数据
byte[] buffer = new byte[width * height * channels];
for (int i = 0; i < height; i++)
{
tiff.ReadScanline(buffer, i * width * channels, i, 0);
}
// 创建Texture2D
TextureFormat format = preserveAlpha && (channels == 4 || hasAlpha)
? TextureFormat.RGBA32
: TextureFormat.RGB24;
Texture2D tex = new Texture2D(width, height, format, false);
// 填充像素 (垂直翻转)
Color32[] colors = new Color32[width * height];
for (int y = 0; y < height; y++)
{
int flippedY = height - 1 - y;
for (int x = 0; x < width; x++)
{
int bufferIndex = (y * width + x) * channels;
int colorIndex = flippedY * width + x;
byte r = buffer[bufferIndex];
byte g = buffer[bufferIndex + 1];
byte b = buffer[bufferIndex + 2];
byte a = (byte)255;
// 处理Alpha通道
if (preserveAlpha && (channels == 4 || hasAlpha))
{
a = channels == 4 ? buffer[bufferIndex + 3] : (hasAlpha ? buffer[bufferIndex + 3] : (byte)255);
}
colors[colorIndex] = new Color32(r, g, b, a);
}
}
tex.SetPixels32(colors);
tex.Apply();
// 保存为PNG
File.WriteAllBytes(pngPath, tex.EncodeToPNG());
}
}
}