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

news2024/11/25 14:49:54

  大家好,我是阿赵。
  这次来讲一下在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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1591312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS4 页面路由

Index.ets: import router from ohos.routerclass RouterInfo {// 页面路径url: string// 页面标题title: stringconstructor(url: string, title: string) {this.url urlthis.title title} }Entry // 入口組件 Component struct Index {State message: string 页面列表// …

java快速幂算法

快速幂算法 参考视频(参考五角七边up大佬&#xff09; 幂运算的介绍 幂运算是指将一个数自身乘以自身多次的运算&#xff0c;其表达式为 a n a^n an&#xff0c;其中 a a a 是底数&#xff0c; n n n 是指数。 快速幂解释 快速幂算法是一种用于快速计算幂运算的算法&…

MySQL的基础操作(二)

目录 一.数据库约束 1.主键约束 (Primary Key) 2.唯一约束 (Unique) 3.外键约束 (Foreign Key): 4.检查约束(Check) 5.默认约束 (Default) 二.聚合查询 1.简单聚合函数 2.GROUP BY子句 3.HAVING子句 三.联合查询 1.内连接 2.左连接 3.右连接 4.子查询 5.合并查询…

OpenHarmony开发——CMake方式组织编译的库移植

概述 本文为OpenHarmony开发者提供一些组织编译形式比较常见&#xff08;CMakeLists、Makefile&#xff09;的三方库的移植指南&#xff0c;该指南当前仅适用于Hi3516DV300和Hi3518EV300两个平台&#xff0c;文中着重介绍各编译组织方式下工具链的设置方法以及如何将该库的编译…

NJU PA0

NJU PA0 使用教程提供的源再进行sudo apt install … 可能会出现 Unmet dependencies 此类报错 可以安装 aptitude sudo apt install aptitude sudo aptitude install <package>然后它会提示你&#xff0c;选 n 进行降级。再选 Y 确认 或者 将 /etc/apt/sources.list 下…

SpringSecurity登录时在哪里调用我们自定义的UserDetailsServiceImpl

SpringSecurity登录时在哪里调用我们自定义的UserDetailsServiceImpl 1、请求login方法 2、将用户的用户名和密码封装成一个对象&#xff0c;以便进行后续的认证操作 3、执行认证操作 4、调用providermanager类的authenticate 5.进入这一步就开始跟我们自定义实现的UserDet…

带头结点的双向循环链表操作集

分数 50 作者 伍建全 单位 重庆科技大学 本题要求实现一个带头结点的双向循环链表操作集。 函数接口定义&#xff1a; typedef int dataType;typedef struct _node {dataType data;struct _node *prev;//指向前驱的指针struct _node *next;//指向后继的指针 }node;typedef…

Windows安装MongoDB结合内网穿透轻松实现公网访问本地数据库

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

PandasAI的应用与实战解析(二):PandasAI使用流程与功能介绍

文章目录 1.使用PandasAI进行开发的流程2.配置文件解析3.支持的数据库类型4.支持的LLMs5.其他 PandasAI这个工具最突出的优点就是通过结合了Pandas和生成式LLMs&#xff0c;极大地为开发人员降低了工作量。 传统的开发调用流程&#xff08;数据分析相关&#xff09;&#xff1a…

秒杀购物商城核心服务 — 商品管理中心(前提设计概要)

秒杀购物商城核心服务 前提介绍商品中心中台支持系统-总体架构设计&#xff1a;商品与产品商品 类目属性类目定义前后台类目后台类目&#xff0c;关注标准化管理类目属性及分类 SKUSPU 属性库建设 前提介绍 在电商系统中&#xff0c;商品模型占据着举足轻重的地位&#xff0c…

AI赋能档案开放审核:实战

关注我们 - 数字罗塞塔计划 - 为进一步推进档案开放审核工作提质增效&#xff0c;结合近几年的业务探索、研究及项目实践&#xff0c;形成了一套较为成熟、高效的AI辅助档案开放审核解决方案&#xff0c;即以“AI人工”的人机协同模式引领档案开放审机制创新&#xff0c;在档…

TyG新文章!与胸痛的高发生率正相关 | NHANES数据库周报(4.10)

NHANES挖掘培训班来啦&#xff0c;就在4.20-21&#xff01; 郑老师团队2024年NHANES公共数据库挖掘培训班&#xff0c;由浅入深&#xff0c;零基础可学&#xff0c;欢迎报名&#xff01; 美国国家健康和营养检查调查&#xff08;NHANES&#xff09;是一项旨在评估美国成人和儿童…

Python通过socket搭建一个web服务器

目录 01、源码 02、运行结果 03、小结 Socket是一种计算机网络通信的一种机制&#xff0c;它允许不同计算机或进程之间通过网络进行数据传输和通信。Socket可以被看作是不同计算机之间的数据传输通道&#xff0c;通过这个通道&#xff0c;计算机之间可以进行双向的数据传输。…

区块链游戏:探索未来的可能性与挑战

区块链游戏是一种将区块链技术应用于游戏领域的创新产品&#xff0c;它为游戏行业带来了全新的模式和可能性。本文将深入探讨区块链游戏的优点、挑战和未来趋势&#xff0c;帮助读者了解这一新兴领域。 一、区块链游戏的优点 1. 公平性&#xff1a;区块链技术保证了游戏中的物…

LeetCode-Java:303、304区域检索(前缀和)

文章目录 题目303、区域和检索&#xff08;数组不可变&#xff09;304、二维区域和检索&#xff08;矩阵不可变&#xff09; 解①303&#xff0c;一维前缀和②304&#xff0c;二维前缀和 算法前缀和一维前缀和二维前缀和 题目 303、区域和检索&#xff08;数组不可变&#xff…

二叉树遍历算法和应用

二叉树是指度为 2 的树。它是一种最简单却又最重要的树&#xff0c;在计算机领域中有这广泛的应用。 二叉树的递归定义如下&#xff1a;二叉树是一棵空树&#xff0c;或者一棵由一个根节点和两棵互不相交的分别称为根节点的左子树和右子树所组成的非空树&#xff0c;左子树和右…

【数据结构】07查找

查找 1. 基本概念2. 顺序表查找2.1 顺序查找2.2 顺序查找优化-哨兵 3. 有序表查找3.1 折半查找&#xff08;二分查找&#xff09; 4. 分块查找&#xff08;索引顺序查找&#xff09;5. Hash表&#xff08;散列表&#xff09;5.1 散列函数的设计5.2 代码实现5.2.1 初始化Hash表5…

再谈C语言——理解指针(一)

内存和地址 内存 在讲内存和地址之前&#xff0c;我们想有个⽣活中的案例&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼⾥&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c; 如果想找到你&#xff0c;就得挨个房…

【C++11】异常知多少

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握C11异常 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff1a;C嘎嘎进阶 &g…

Ubuntu22.04 + ROS2 Humble的环境配置

Ubuntu22.04 ROS2 Humble的环境配置 文章目录 Ubuntu22.04 ROS2 Humble的环境配置(1) Set locale(2) Setup Sources(3)安装ROS2(4)检查是否成功安装 参考官方网站ROS2-Installation ROS2的各种版本及维护计划&#xff0c;可以参考ROS2-List of Distributions (1) Set locale…