166 lines
5.7 KiB
C#
166 lines
5.7 KiB
C#
|
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());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|