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());
|
||
}
|
||
}
|
||
} |