unity texture2d EncodeToJPG 透明黑色
unity texture2d EncodeToJPG transparent black
我有一个纹理用户绘制(在移动设备上),我想将其编码为 jpg 以便用户可以与之共享,但我发现编码的 jpg 中的透明部分将是黑色的:
虽然我希望 jpg 是这样的:
但我没有找到 texture2d.EncodeToJPG()
的任何覆盖方法来执行此操作。
有什么想法吗?
注意
鸟的翅膀是专门为 Color.white
绘制的,因此在编码的 jpg 中它可能是白色的。
现在进场
我终于通过以下方式完成了这项工作:
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
blackTransparent.a = 0;
for(int i = 0;i < pixels.Length; i++)
{
if(pixels[i] == blackTransparent)
{
pixels[i] = Color.white;
}
}
text.SetPixels32(pixels);
text.Apply();
但这会遍历纹理的所有像素,如果有人有更好的方法,请告诉我们。
这种方法的问题:
我们发现使用上面的代码在jpg上会有一些边缘(遇到黑线时),可能需要一些图形处理知识来解决这个问题?
这是我们如何将图像加载到 texture2d(根据评论要求)
Texture2D text = new Texture2D(1, 1, TextureFormat.PVRTC_RGBA4, false);
byte[] imagebytes = null;
string path = "image/path/sample.png";
if (System.IO.File.Exists(path))
{
Debug.Log(" really load file from " + path);
imagebytes = System.IO.File.ReadAllBytes(path);
}
text.LoadImage(imagebytes, false);
您可以尝试编码成PNG。 JPG 无法渲染透明度。
就像:
texture2d.EncodeToPNG();
如果应用程序 运行 在 Microsoft OS 你也可以使用 this 转换成 jpg
对于您的第一个问题编辑,询问如何改进循环遍历所有像素的代码,您可以。只需将 for(int i = 0;i < pixels.Length; i++)
替换为 for (int i = 0; i < pixels.Length; i += 4)
,然后访问循环内从 i+0
到 i+3
的每个索引。循环速度大约 4x。
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
Color overwriteColor = Color.white;
blackTransparent.a = 0;
for (int i = 0; i < pixels.Length; i += 4)
{
if (pixels[i] == blackTransparent)
pixels[i] = overwriteColor;
if (pixels[i + 1] == blackTransparent)
pixels[i + 1] = overwriteColor;
if (pixels[i + 2] == blackTransparent)
pixels[i + 2] = overwriteColor;
if (pixels[i + 3] == blackTransparent)
pixels[i + 3] = overwriteColor;
}
text.SetPixels32(pixels);
text.Apply(true);
尽管如此,这两个代码都会 运行 出现与您第二次编辑中提到的相同的锯齿线问题。
要修复它,请不要将像素直接与 ==
符号进行比较。使用一个函数,让您使用阈值来比较颜色而不仅仅是数字。 This 是我在 Unity 中用来比较 RGB 颜色的函数,我建议你开始使用它。
然后您必须手动检查 alpha 是否低于或等于某个值。 90
的值似乎对此很有效。
这是脚本的样子:
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
for (int i = 0; i < pixels.Length; i += 4)
{
checkPixel(ref pixels[i], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 1], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 2], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 3], blackTransparent, Color.white, 600);
}
text.SetPixels32(pixels);
text.Apply();
函数checkPixel
和ColourDistance
函数:
void checkPixel(ref Color32 pixel1, Color32 pixel2, Color32 newColor, int threshold)
{
if (ColourDistance(pixel1, pixel2) <= threshold)
{
if (pixel1.a <= 90)
{
pixel1 = Color.white;
}
}
}
private static double ColourDistance(Color32 c1, Color32 c2)
{
double rmean = (c1.r + c2.r) / 2;
int r = c1.r - c2.r;
int g = c1.g - c2.g;
int b = c1.b - c2.b;
double weightR = 2 + rmean / 256;
double weightG = 4.0;
double weightB = 2 + (255 - rmean) / 256;
return Math.Sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
}
这是结果:
还有待改进
我有一个纹理用户绘制(在移动设备上),我想将其编码为 jpg 以便用户可以与之共享,但我发现编码的 jpg 中的透明部分将是黑色的:
虽然我希望 jpg 是这样的:
但我没有找到 texture2d.EncodeToJPG()
的任何覆盖方法来执行此操作。
有什么想法吗?
注意
鸟的翅膀是专门为 Color.white
绘制的,因此在编码的 jpg 中它可能是白色的。
现在进场
我终于通过以下方式完成了这项工作:
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
blackTransparent.a = 0;
for(int i = 0;i < pixels.Length; i++)
{
if(pixels[i] == blackTransparent)
{
pixels[i] = Color.white;
}
}
text.SetPixels32(pixels);
text.Apply();
但这会遍历纹理的所有像素,如果有人有更好的方法,请告诉我们。
这种方法的问题:
我们发现使用上面的代码在jpg上会有一些边缘(遇到黑线时),可能需要一些图形处理知识来解决这个问题?
这是我们如何将图像加载到 texture2d(根据评论要求)
Texture2D text = new Texture2D(1, 1, TextureFormat.PVRTC_RGBA4, false);
byte[] imagebytes = null;
string path = "image/path/sample.png";
if (System.IO.File.Exists(path))
{
Debug.Log(" really load file from " + path);
imagebytes = System.IO.File.ReadAllBytes(path);
}
text.LoadImage(imagebytes, false);
您可以尝试编码成PNG。 JPG 无法渲染透明度。
就像:
texture2d.EncodeToPNG();
如果应用程序 运行 在 Microsoft OS 你也可以使用 this 转换成 jpg
对于您的第一个问题编辑,询问如何改进循环遍历所有像素的代码,您可以。只需将 for(int i = 0;i < pixels.Length; i++)
替换为 for (int i = 0; i < pixels.Length; i += 4)
,然后访问循环内从 i+0
到 i+3
的每个索引。循环速度大约 4x。
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
Color overwriteColor = Color.white;
blackTransparent.a = 0;
for (int i = 0; i < pixels.Length; i += 4)
{
if (pixels[i] == blackTransparent)
pixels[i] = overwriteColor;
if (pixels[i + 1] == blackTransparent)
pixels[i + 1] = overwriteColor;
if (pixels[i + 2] == blackTransparent)
pixels[i + 2] = overwriteColor;
if (pixels[i + 3] == blackTransparent)
pixels[i + 3] = overwriteColor;
}
text.SetPixels32(pixels);
text.Apply(true);
尽管如此,这两个代码都会 运行 出现与您第二次编辑中提到的相同的锯齿线问题。
要修复它,请不要将像素直接与 ==
符号进行比较。使用一个函数,让您使用阈值来比较颜色而不仅仅是数字。 This 是我在 Unity 中用来比较 RGB 颜色的函数,我建议你开始使用它。
然后您必须手动检查 alpha 是否低于或等于某个值。 90
的值似乎对此很有效。
这是脚本的样子:
Color32[] pixels = text.GetPixels32();
Color blackTransparent = Color.black;
for (int i = 0; i < pixels.Length; i += 4)
{
checkPixel(ref pixels[i], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 1], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 2], blackTransparent, Color.white, 600);
checkPixel(ref pixels[i + 3], blackTransparent, Color.white, 600);
}
text.SetPixels32(pixels);
text.Apply();
函数checkPixel
和ColourDistance
函数:
void checkPixel(ref Color32 pixel1, Color32 pixel2, Color32 newColor, int threshold)
{
if (ColourDistance(pixel1, pixel2) <= threshold)
{
if (pixel1.a <= 90)
{
pixel1 = Color.white;
}
}
}
private static double ColourDistance(Color32 c1, Color32 c2)
{
double rmean = (c1.r + c2.r) / 2;
int r = c1.r - c2.r;
int g = c1.g - c2.g;
int b = c1.b - c2.b;
double weightR = 2 + rmean / 256;
double weightG = 4.0;
double weightB = 2 + (255 - rmean) / 256;
return Math.Sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
}
这是结果:
还有待改进