gpt4 book ai didi

c# - 应用下载的纹理后,PNG 文件在 Unity 中增长并通过 EncodeToPNG 转换回 PNG

转载 作者:行者123 更新时间:2023-12-02 02:52:37 26 4
gpt4 key购买 nike

为了测试,我通过 http 下载了一个 PNG 文件(在本例中是通过 API 从 JIRA 服务器下载的)

对于http请求,我有一个相当“标准”的类HttpFileManager,我只是为了完整性而添加:

public static class HttpFileManager
{

public void DownloadImage(string url, Action<Texture> successCallback = null, Credentials credentials = null, Action<UnityWebRequest> errorCallback = null)
{
StartCoroutine(DownloadImageProcess(url, successCallback, credentials, errorCallback));
}

private static IEnumerator DownloadImageProcess(string url, Action<Texture> successCallback, Credentials credentials, Action<UnityWebRequest> errorCallback)
{
var www = UnityWebRequestTexture.GetTexture(url);

if (credentials != null)
{
// This simply adds some headers to the request required for JIRA api
// it is not relevant for this question
AddCredentials(www, credentials);
}

yield return www.SendWebRequest();

if (www.isNetworkError || www.isHttpError)
{
Debug.LogErrorFormat("Download from {0} failed with {1}", url, www.error);
errorCallback?.Invoke(www);
}
else
{
Debug.LogFormat("Download from {0} complete!", url);
successCallback?.Invoke(((DownloadHandlerTexture) www.downloadHandler).texture);
}
}

public static void UploadFile(byte[] rawData, string url, Action<UnityWebRequest> successcallback, Credentials credentials, Action<UnityWebRequest> errorCallback)

private static IEnumerator UploadFileProcess(byte[] rawData, string url, Action<UnityWebRequest> successCallback, Credentials credentials, Action<UnityWebRequest> errorCallback)
{
var form = new WWWForm();
form.AddBinaryData("file",rawData,"Test.png");

var www = UnityWebRequest.Post(url, form);

www.SetRequestHeader("Accept", "application/json");

if (credentials != null)
{
// This simply adds some headers to the request required for JIRA api
// it is not relevant for this question
AddCredentials(www, credentials);
}

yield return www.SendWebRequest();

if (www.isNetworkError || www.isHttpError)
{
Debug.LogErrorFormat("Upload to {0} failed with code {1} {2}", url, www.responseCode, www.error);
errorCallback?.Invoke(www);
}
else
{
Debug.LogFormat("Upload to {0} complete!", url);
successCallback?.Invoke(www);
}
}
}

稍后在我的脚本中我会这样做

public Texture TestTexture;

// Begin the download
public void DownloadTestImage()
{
_httpFileManager.DownloadImage(ImageGetURL, DownloadImageSuccessCallback, _credentials);
}

// After Download store the Texture
private void DownloadImageSuccessCallback(Texture newTexture)
{
TestTexture = newTexture;
}

// Start the upload
public void UploadTestImage()
{
var data = ((Texture2D) TestTexture).EncodeToPNG();

_httpFileManager.UploadFile(data, ImagePostUrl, UploadSuccessCallback, _credentials);
}

// After Uploading
private static void UploadSuccessCallback(UnityWebRequest www)
{
Debug.Log("Upload worked!");
}

在resume中,问题在于for和back转换

(DownloadHandlerTexture) www.downloadHandler).texture

((Texture2D) TestTexture).EncodeToPNG();

结果看起来像这样

顶部是原始图像;底部是重新上传的。

如您所见,它从 40kb 增长到 59kb,增长了 1,475 倍。这同样适用于较大的文件,因此 844kb 增长到 1,02Mb

所以我的问题是

为什么EncodeToPNG()后上传的图片比原始图片大?

是否可以/应该对 PNG 数据使用任何压缩,以便归档相同的压缩级别(如果压缩是问题所在)?

首先我认为颜色深度可能不同,但两个图像都是 RGBA-32 位

enter image description here

<小时/>

更新

这是两张图片

原始(40kb)(取自 here )

enter image description here

重新上传(59kb)

enter image description here

<小时/>

更新2

我用 JPG 文件和 EncodeToJPG() 重复测试,结果似乎更糟:

enter image description here

顶部是原始图像;底部是重新上传的。

这次它从 27kb 变为 98kb,因此因子 2,63。奇怪的是,无论我将什么作为 EncodeToJPG()quality 参数,文件大小也都是恒定的 98kb

最佳答案

如果您仔细检查这两个 PNG 文件,您会注意到其中的差异。它们都具有相同的分辨率、相同的位深度、一定数量的 channel ,并且都不是隔行扫描。

然而,原始图像只包含一个 IDAT section它保存 41370 字节的编码数据。

来自 Unity 的图像包含 8 个 IDAT 部分:7 x 8192 字节和 1 个 2860 字节,总共 60204 字节。

在PNG规范中,有一条注释:

Multiple IDAT chunks are allowed so that encoders can work in a fixed amount of memory; typically the chunk size will correspond to the encoder's buffer size.

此外,对于相同的源图像,这些 IDAT 部分中包含的数据不一定完全相同。这些 IDAT 部分保存第一个 pre-filtered 的原始字节数据。然后encoded使用zlib压缩。

因此,PNG 编码器可以从 5 种可用的预过滤算法中选择:

Type    Name

0 None
1 Sub
2 Up
3 Average
4 Paeth

此外,zlib压缩可以配置压缩窗口大小,也可以由PNG编码器选择。

检查 zlib 流会给出以下结果:

  • 两个文件都使用“deflate”压缩,窗口大小相同为 32k
  • 但是,压缩标志不同 - 原始文件的压缩级别为 1(快速算法),而 Unity 编码的文件的压缩级别为 0(最快算法)。

这解释了二进制数据和数据大小的差异。

您似乎无法控制 Unity 的 PNG 编码器,因此遗憾的是您无法强制它选择其他 zlib 算法。

我想,JPEG 文件也会发生同样的情况 - 编码器只是选择更快的算法来生成更大的文件。

如果您想在 Unity 中完全控制 PNG 编码,您需要实现自己的 PNG 编码器。例如。 here on Unity forum ,有一个使用 zlib.net 库的 PNG 编码器示例。您可以微调编码,例如通过指定 zlib 压缩算法。

关于c# - 应用下载的纹理后,PNG 文件在 Unity 中增长并通过 EncodeToPNG 转换回 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53216075/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com