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();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python+Requests模拟发送GET请求

模拟发送GET请求 前置条件&#xff1a;导入requests库 一、发送不带参数的get请求 代码如下&#xff1a; 以百度首页为例 import requests# 发送get请求 response requests.get(url"http://www.baidu.com") print(response.content.decode("utf-8"))…

数据结构之单链表的相关知识点及应用

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构 目录 链表的概念及结构 链表与顺序表的区别与优劣势 链表的分类 单链表的实现 单链表中增加节点 单链表中尾插数据 打印单链…

研发岗-面临统信UOS系统配置总结

第一步 获取root权限 配置环境等都需要用到root权限&#xff0c;所以我们先获取到root权限&#xff0c;方便下面的操作 下载软件 在UOS应用商店下载的所需应用 版本都比较低 安装node 官网下载了【arm64】的包&#xff0c;解压到指定文件夹&#xff0c;设置链接&#xff0…

jmeter监听器大家都会用,但我这个妙招能让你提早一小时下班!

使用过 jmeter 的同学&#xff0c;应该都会使用监听器&#xff0c;在每个监听器中&#xff0c;都会有一个“所有数据写入一个文件”的功能&#xff0c;那这个功能应该怎么用呢&#xff1f;今天&#xff0c;我们就来讲讲这个功能的使用。 几乎所有的监听器都有这样一个功能。 那…

spring boot admin搭建,监控springboot程序运行状况

新建一个spring boot web项目&#xff0c;添加以下依赖 <dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.3.0</version></dependency> <dependency&…

动态内存;

目录 1.malloc; 简要介绍&#xff1a; 如何使用&#xff1a; free函数&#xff1a; 2.calloc; 简要介绍&#xff1a; 与malloc的区别&#xff1a; 3.realloc; 简要介绍&#xff1a; 如何使用&#xff1a; 4.动态内存常见错误&#xff1b; 1.malloc; 简要介绍&#x…

M12设备端面板安装连接器板后安装(前锁)L扣

M12设备端面板安装连接器板后安装(前锁)L扣 优势 -100% 电气测试及插拔测试-对于紧凑型设备&#xff1a;可在有限空间内传输很高的功率-密封圈受过度拧紧保护&#xff0c;实现长期可靠的密封 标准 IEC61076-2-111 锁紧方式 螺纹锁紧 订单料号 P/N: L-KYF12K4Z-PG9-M-L0.…

【SERVERLESS】AWS Lambda上实操

通过Serverless的发展历程及带给我们的挑战&#xff0c;引出我们改如何改变思路&#xff0c;化繁为简&#xff0c;趋利避害&#xff0c;更好的利用其优势&#xff0c;来释放企业效能&#xff0c;为创造带来无限可能。 一 Serverless概述 无服务器计算近年来与云原生计算都是在…

「2024」React 状态管理入门

概念 简单来说&#xff0c;状态指的是某一时刻应用中的数据或界面的呈现。这些数据可能包括用户填写表单的信息、应用内的用户偏好设置、应用的页面/路由状态、或者任何其他可能改变UI的信息。 状态管理是前端开发中处理用户界面(UI)状态的过程&#xff0c;在复杂应用中尤其重…

【算法分析与设计】全排列

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给定一个不含重复数字的整数数组 nums &#xff0c;返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 示例 示例 1&#xff1…

(笔记)KEIL经常碰到的错误(持续整理)

KEIL常碰到的错误 一、ERROR报错1、Build时报错 Error: L6218E2、Build时报错 error 653、Default Compiler Version 54、core_cm3.h(1213): error: unknown type name inline 二、调试与仿真1、keil5软件仿真没有实时波形2、调试模式时&#xff0c;程序前没有灰块3、Periphera…

Python分组数据并保存到单独的文件中

当处理大型数据集时&#xff0c;通常需要将数据分组&#xff0c;并将每个分组的数据保存到单独的文件中。下面是一个使用 Python 中的 pandas 库来实现这一目标的示例代码。 步骤 1: 导入所需的库 import os import pandas as pd步骤 2: 读取 Excel 数据 # 读取 Excel 数据 …

关于Unity使用DLL的说法

最近在研究一些构建依赖相关的&#xff0c;特别是Unity在不同平台上使用第三方类库时候的问题。简单查了一下资料&#xff0c;其实不难理解&#xff0c;这里只是简单的记录一下&#xff0c;弄明白一个简单的道理就行了。 为什么有的第三方库(DoTween),NewtonSoft等的dll库&…

SF58-ASEMI适配器二极管SF58

编辑&#xff1a;ll SF58-ASEMI适配器二极管SF58 型号&#xff1a;SF58 品牌&#xff1a;ASEMI 封装&#xff1a;DO-27 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;5A 最大循环峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;600V 最大正向电压&…

根据状态转移图实现时序电路

描述 某同步时序电路的状态转换图如下&#xff0c;→上表示“C/Y”&#xff0c;圆圈内为现态&#xff0c;→指向次态。 请使用D触发器和必要的逻辑门实现此同步时序电路&#xff0c;用Verilog语言描述。 如图所示&#xff1a; 电路的接口如下图所示&#xff0c;C是单bit数据…

视频号小店好做吗?普通人没有货源,也可以做吗?

大家好&#xff0c;我是电商糖果 视频号小店作为2022年才出来的电商黑马项目&#xff0c;吸引了不少正在找创业项目的朋友。 这里面也有很多没有接触过电商&#xff0c;没有货源的普通人。 于是不少朋友就问糖果&#xff0c;如果普通人没有货源可以做吗&#xff1f;小店好做…

【回溯】Leetcode 51. N 皇后【困难】

N 皇后 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。…

CSS3 立体 3D 变换

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 ✍CSS3 立体 3D 变换&#x1f48e;1 坐标轴&#x1f48e;2 perspective 透视视…

cesium 平滑显示billboard 透明度

描述&#xff1a;加载billboard的时候&#xff0c;要么是显示&#xff0c;要么是隐藏&#xff0c;不能平滑的显示&#xff0c;有个从不显示到显示的过程 解决方案&#xff1a;创建billboard的时候给一个color&#xff0c;颜色为(255,255,255)&#xff0c;透明度从0-1 let opaci…

CSS设置内外边距

目录 内边距&#xff08;paddingj&#xff09;&#xff1a; 前言&#xff1a; 设置内边距&#xff1a; 外边距&#xff08;margin&#xff09;&#xff1a; 前言&#xff1a; 设置外边距&#xff1a; 补充(折叠)&#xff1a; 内边距&#xff08;padding&#xff09;&#…