Dan*_*ann 2 bytearray bitmap unity-game-engine
我想从byte []创建一个位图。我的问题是我无法BitmapSource在Unity中使用,如果我使用Unity,则会MemoryStream收到错误消息。
我尝试了这个:
Bitmap bitmap = new Bitmap(512, 424);
var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size),
ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Marshal.Copy(arrayData, 0, data.Scan0, arrayData.Length);
bitmap.UnlockBits(data);
Run Code Online (Sandbox Code Playgroud)
它可以工作,但是我得到的位图是错误的。有人可以向我解释原因并为我找到解决方案吗?
这可以是两件事,也许可以结合起来:坐标系的选择和Endianness
有一个惯例(我相信是通用的)可以从左到右列出像素,但是没有一个关于垂直方向的。尽管某些程序和API的Y坐标底部为零,然后向上增大,但其他程序和API却恰好相反。我不知道您从哪里来的byte[],但是有些API允许您在写入,读取或使用纹理时配置像素方向。否则,您将必须手动重新排列行。
字节顺序也是如此;ARGB有时表示蓝色是最后一个字节,有时是第一个字节。某些类(例如BitConverter)也具有内置解决方案。
Unity使用big-endian,自下而上的纹理。实际上,Unity在后台处理了大量此类工作,并且在导入位图文件时必须重新排序行并翻转字节。Unity还提供了LoadImage和EncodeToPNG之类的方法来解决这两个问题。
为了说明发生了什么byte[],此示例代码以三种不同的方式保存了同一张图片(但是您需要将它们导入为Truecolor才能在Unity中正确看到它们):
using UnityEngine;
using UnityEditor;
using System.Drawing;
using System.Drawing.Imaging;
public class CreateTexture2D : MonoBehaviour {
public void Start () {
int texWidth = 4, texHeight = 4;
// Raw 4x4 bitmap data, in bottom-up big-endian ARGB byte order. It's transparent black for the most part.
byte[] rawBitmap = new byte[] {
// Red corner (bottom-left) is written first
255,255,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
255,0,0,255, 255,0,0,255, 255,0,0,255, 255,0,0,255
//Blue border (top) is the last "row" of the array
};
// We create a Texture2D from the rawBitmap
Texture2D texture = new Texture2D(texWidth, texHeight, TextureFormat.ARGB32, false);
texture.LoadRawTextureData(rawBitmap);
texture.Apply();
// 1.- We save it directly as a Unity asset (btw, this is useful if you only use it inside Unity)
UnityEditor.AssetDatabase.CreateAsset(texture, "Assets/TextureAsset.asset");
// 2.- We save the texture to a file, but letting Unity handle formatting
byte[] textureAsPNG = texture.EncodeToPNG();
System.IO.File.WriteAllBytes(Application.dataPath + "/EncodedByUnity.png", textureAsPNG);
// 3.- Rearrange the rawBitmap manually into a top-down small-endian ARGB byte order. Then write to a Bitmap, and save to disk.
// Bonus: This permutation is it's own inverse, so it works both ways.
byte[] rearrangedBM = new byte[rawBitmap.Length];
for (int row = 0; row < texHeight; row++)
for (int col = 0; col < texWidth; col++)
for (int i = 0; i < 4; i++)
rearrangedBM[row * 4 * texWidth + 4 * col + i] = rawBitmap[(texHeight - 1 - row) * 4 * texWidth + 4 * col + (3 - i)];
Bitmap bitmap = new Bitmap(texWidth, texHeight, PixelFormat.Format32bppArgb);
var data = bitmap.LockBits(new Rectangle(0, 0, texWidth, texHeight), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(rearrangedBM, 0, data.Scan0, rearrangedBM.Length);
bitmap.UnlockBits(data);
bitmap.Save(Application.dataPath + "/SavedBitmap.png", ImageFormat.Png);
}
}
Run Code Online (Sandbox Code Playgroud)