Файл PNG растет в Unity после применения загруженной текстуры и конвертируется обратно в PNG через EncodeToPNG - PullRequest
0 голосов
/ 09 ноября 2018

Просто для тестирования я скачал файл PNG через http (в данном случае с сервера JIRA через API)

Для запроса 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!");
}

В резюме проблема заключается в обратном и обратном преобразовании в

(DownloadHandlerTexture) www.downloadHandler).texture

и

((Texture2D) TestTexture).EncodeToPNG();

Результат выглядит так

вверху оригинальное изображение; внизу перезагруженный.

Как вы можете видеть, оно увеличивается с 40kb до 59kb, то есть с коэффициентом 1,475. То же самое относится к файлам большего размера, так что 844kb вырос до 1,02Mb.

Итак, мой вопрос

Почему загруженное изображение больше EncodeToPNG(), чем исходное изображение?

и

Существует ли какое-либо сжатие, которое можно / нужно использовать для данных PNG для архивирования того же уровня сжатия (если сжатие является проблемой вообще)?

Сначала я подумал, что может быть разная глубина цвета, но оба изображения RGBA-32bit

enter image description here


Update

Вот два изображения

оригинал (40 КБ) (взят из здесь )

enter image description here

повторно загружено (59kb)

enter image description here


Обновление 2

Я повторил тест с файлом JPG и EncodeToJPG(), и результат кажется еще хуже:

enter image description here

вверху оригинальное изображение; внизу перезагруженный.

На этот раз оно увеличилось с 27kb до 98kb, так что множитель 2,63. Как ни странно, размер файла также был постоянным 98kb независимо от того, что я указывал в качестве параметра quality для EncodeToJPG().

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

читать здесь кажется, что, хотя вы можете импортировать png, то, что у вас есть в вашем проекте, становится текстурой или файлом спрайта, и эти добавленные данные увеличивают его размер. дополнительные байты, которые вы видите, поступают из информации, прикрепленной к png редактором, чтобы упростить процесс загрузки Unity и позволить вам устанавливать различные параметры для импорта. размер вашего файла может резко измениться в зависимости от выбранных вами настроек.

0 голосов
/ 12 ноября 2018

Если вы точно осмотрите оба файла PNG, вы заметите разницу. Оба имеют одинаковое разрешение, одинаковую битовую глубину, некоторое количество каналов, и оба не чересстрочные.

Однако исходное изображение содержит только одну IDAT секцию , которая содержит 41370 байт закодированных данных.

Изображение, созданное в Unity, содержит 8 IDAT разделов: 7 x 8192 байта и один 2860 байтов, всего 60204 байта.

В спецификации PNG есть примечание:

Допускается несколько блоков IDAT, чтобы кодировщики могли работать с фиксированным объемом памяти; обычно размер фрагмента соответствует размеру буфера кодера.

Кроме того, данные, содержащиеся в этих IDAT разделах, не обязательно являются одинаковыми для одних и тех же исходных изображений. Эти секции IDAT содержат необработанные байтовые данные, которые сначала предварительно фильтруются , а затем кодируются с использованием сжатия zlib.

Таким образом, кодер PNG может выбрать алгоритм предварительной фильтрации из 5 доступных:

Type    Name

0       None
1       Sub
2       Up
3       Average
4       Paeth

Кроме того, сжатие zlib можно настроить для размера окна сжатия, который также может быть выбран кодером PNG.

Проверка потоков zlib дает следующие результаты:

  • оба файла используют сжатие "deflate" с одинаковым размером окна 32k
  • флаги сжатия, однако, различны - исходный файл имеет уровень сжатия 1 (быстрый алгоритм), тогда как кодированный файл Unity имеет уровень сжатия 0 (самый быстрый алгоритм).

Это объясняет различия в двоичных данных и размере данных.

Кажется, что вы не можете контролировать PNG-кодер Unity, поэтому, к сожалению, вы не можете заставить его выбрать другой zlib алгоритм.

Полагаю, то же самое происходит с файлами JPEG - кодер просто выбирает более быстрый алгоритм, который создает файл большего размера.

Если вы хотите полностью контролировать PNG-кодирование в Unity, вам необходимо реализовать собственный PNG-кодер. Например. здесь, на форуме Unity , есть пример такого кодировщика PNG, который использует библиотеку zlib.net. Вы можете точно настроить кодировку, например указав алгоритм сжатия zlib.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...