Unity中图片和Base64字符串之间的转换

  大家好,我是阿赵。
  这次来讲一下在unity引擎里面,图片和base64字符串的互相转换问题。

一、图片传输的多种方式

  有时候我们需要把图片通过网络传输发送。
  在Unity里面,有不止一种方式可以实现,比如说,把图片的bytes通过WWWForm的方式来发送,这是Unity官方文档里面的方法:

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class WWWFormImage : MonoBehaviour
{

    public string screenShotURL= "http://www.my-server.com/cgi-bin/screenshot.pl";

    // Use this for initialization
    void Start()
    {
        StartCoroutine(UploadPNG());
    }

    IEnumerator UploadPNG()
    {
        // We should only read the screen after all rendering is complete
        yield return new WaitForEndOfFrame();

        // Create a texture the size of the screen, RGB24 format
        int width = Screen.width;
        int height = Screen.height;
        var tex = new Texture2D( width, height, TextureFormat.RGB24, false );

        // Read screen contents into the texture
        tex.ReadPixels( new Rect(0, 0, width, height), 0, 0 );
        tex.Apply();

        // Encode texture into PNG
        byte[] bytes = tex.EncodeToPNG();
        Destroy( tex );

        // Create a Web Form
        WWWForm form = new WWWForm();
        form.AddField("frameCount", Time.frameCount.ToString());
        form.AddBinaryData("fileUpload", bytes, "screenShot.png", "image/png");

        // Upload to a cgi script
        using (var w = UnityWebRequest.Post(screenShotURL, form))
        {
            yield return w.SendWebRequest();
            if (w.isNetworkError || w.isHttpError) {
                print(w.error);
            }
            else {
                print("Finished Uploading Screenshot");
            }
        }
    }
}

  但有时候传输的双方并不是都能自己决定,比如和第三方的服务商做通讯,他们只能支持明文字符串的发送。这个时候,也可以把图片转换成字符串,通过发送字符串来达到目的。

二、图片转Base64字符串

  比如我现在在Unity里面有这么一张图片
在这里插入图片描述

  值得注意的是,在Unity里面,需要读取图片的字节内容,必须是把Read/Write Enabled勾上,然后为了转换的时候是无损的,最好是把图片压缩关掉。把Power of 2关掉,以保持图片是原始分辨率。
  然后上代码:

static public string TexToString(Texture2D tex)
{
byte[] bs = tex.EncodeToPNG();
string base64String = System.Convert.ToBase64String(bs);
base64String = “data:image/png;base64,” + base64String;
return base64String;
}

  代码很简单,用EncodeToPNG把Texture2D转成byte[],然后再通过System.Convert.ToBase64String转成字符串而已。
  需要注意的有2点:
1、为什么要加上”data:image/png;base64,”?
  这是一个标准,加上这个头信息,会让接收方知道,现在收到的字符串是一张图片,png格式,并且转换成base64字符串了。如果收发双方都是你自己,你也可以不用加这个信息。
  这个信息对于图片解码本身是无意义的,所以接收方在把字符串转图片的时候,还需要把这段去掉。
2、base64包含特殊字符的问题
  由于base64字符串会包含一些特殊字符,比如”+”、”/”、”=”,这些字符串如果作为url的明文来发送,是会有问题的。
  为了解决这个问题,在发送的时候可以:
1.使用URLEncode转换
2.做字符替换
  我们这里不讨论这个特殊字符的问题。
  指定图片,运行之后,刚才那张图片就变成了这堆字符串了:

data:image/png;base64,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

三、Base64转图片

  从字符串转换回Texture2D:

static public Texture2D Base64StringToTex(string base64String)
{
    base64String = base64String.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");
    byte[] bytes = System.Convert.FromBase64String(base64String);
    Texture2D tex = new Texture2D(2, 2);
    tex.LoadImage(bytes);
    return tex;
}

  代码同样很简单,一开始的时候,将base64头部信息替换掉,保证下面转换的是纯base64的字符串。
  然后通过System.Convert.FromBase64String把字符串转换回byte[],最后通过LoadImage把byte[]加载成Texture2D。

四、当Base64字符串不完整的处理

  上面都是常规方法,下面是关于一些原理上的东西了。
  假如在某些情况下,base64的字符串的末尾出现了缺失,那么将会出现问题。在System.Convert.FromBase64String的时候,会报错:

FormatException: Invalid length for a Base-64 char array or string.

  这是因为Base64字符串的长度应该是4的倍数的,但由于缺失了字符串,导致长度不对。
这个时候,就需要把base64字符串补齐:

base64String = base64String.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");
int mod = base64String.Length % 4;
if(mod>0&&mod>2)
{
    base64String += new string('=', 4 - mod);
}
else
{
    if(mod>0)
    {
        base64String += new string('A', 4 - mod);
    }
}

  为什么是这样补?在base64里面,等号=代表的是空,A代表的是0。当字符串长度不是4的倍数,我们求余数,如果余数是2,我们就补2个空,也就是加2个等号。但这里有一个规则,等号最多只能是2个,如果超过2个,就会报错:

FormatException: The input is not a valid Base-64 string as it
contains a non-base 64 character, more than two padding characters, or
an illegal character among the padding characters.

  所以如果缺超过2个字符的时候,就已经不是补等号可以解决了,所以我这里直接补0。补0当然也是不对的,不过不用急,由于补空已经不能解决的时候,其实补什么都是不行的,所以下面还需要后续的处理。
  先来了解一下,假如一张图片EncodeToPNG转换成byte[]时,这堆byte[]有什么特点?
  首先,这堆byte[]会是以这些byte开头的:

137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0

  然后,到了最后,是以这些byte结尾的:

0,0,0,0,73,69,78,68,174,66,96,130

  知道了这个规则之后,我们就可以做这样的处理了:
1、由于开头一般不会缺失,所以我们可以不管
2、后面这一段固定的结尾,如果缺了,Unity会解析不出来,多了无所谓。所以我们可以针对转换出来的byte[]作检查,看看是不是包含0,0,0,0,73,69,78,68,174,66,96,130的。只要包含就行,不需要一定以它结尾。后面多出来的byte不影响解析。
3、如果发现不包含完整的结尾byte,那么就检查一下是不是缺了某一段,或者是整段没有了。然后,把它们补齐就行了。
4、由于结尾是12个字节,对应的是9个字符,所以base64缺失在9个字符以内,都可以这样补齐。
于是代码会变成这样:

static public Texture2D Base64StringToTex(string base64String)
{
    base64String = base64String.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");
    int mod = base64String.Length % 4;
    if (mod > 0 && mod > 2)
    {
        base64String += new string('=', 4 - mod);
    }
    else
    {
        if (mod > 0)
        {
            base64String += new string('A', 4 - mod);
        }
    }

    byte[] bytes = System.Convert.FromBase64String(base64String);
    bytes = CheckFormatBytes(bytes);
    Texture2D tex = new Texture2D(2, 2);
    tex.LoadImage(bytes);
    return tex;
}

static private byte[] endBs = new byte[]{ 73, 69, 78, 68, 174, 66, 96, 130 };
static public byte[] CheckFormatBytes(byte[] bs)
{
    List<byte> origList = new List<byte>();
    for(int i = 0;i<bs.Length;i++)
    {
        origList.Add(bs[i]);
    }
    int lastIndex = -1;
    int checkIndex = -1;
    bool isFormat = true;
    int firstIndex = -1;
    for(int i = 0;i<endBs.Length;i++)
    {
        if(i==0)
        {
            lastIndex = origList.LastIndexOf(endBs[i]);
            if(lastIndex<0)
            {
                isFormat = false;
                break;
            }
            else
            {
                firstIndex = lastIndex;
                checkIndex = i;
            }
        }
        else
        {
            int curIndex = origList.LastIndexOf(endBs[i]);
            if(curIndex<0||curIndex-lastIndex!=1)
            {
                isFormat = false;
                break;
            }
            else
            {
                checkIndex = i;
                lastIndex = curIndex;
            }
        }
    }
    if(isFormat == true)
    {
        return bs;
    }
    else
    {
        if(checkIndex>=0)
        {
            origList.RemoveRange(firstIndex, origList.Count - firstIndex);
        }
        for (int i = 0; i < endBs.Length; i++)
        {
            origList.Add(endBs[i]);
        }
    }
    return origList.ToArray();
}
  • 33
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值