【C#】Base64url <-> Binary 相互変換
2019年10月7日
基本的に System.Convert を使えば Base64 <-> バイナリの相互変換出来ます。
Base64 → Base64URL
string base64url = base64.Replace('/','_').Replace('+','-');
Base64URL → Base64
string base64 = base64url.Replace('_','/').Replace('-','+');
Base64URL → binary
// 文字数を4の倍数にする
int surplus = base64.Length % 4; // 4でパディング
string padding = ( surplus > 0) ? new string( '=', 4 - surplus) : string.Empty; // パディングを = で埋める
// - を + に置換
// _ を / に置換
// 余白に = で埋める
byte[] data = System.Convert.FromBase64String( base64url.Replace('_','/').Replace('-','+') + padding);
return data;
binary → Base64URL
string base64 = System.Convert.ToBase64String( data);
// = を削除
// + を - に置換
// / を _ に置換
string base64url = base64.TrimEnd('=').Replace('+','-').Replace('/','_');
return base64url;
おまけ
最終的に Base64URL -> PNG が必要だったのでまとめました。
Unity などは Texture.LoadImage( png);
に突っ込めば HTTP 経由で画像をロードできます。
Base64URL → PNG
リトルエンディアン環境でしか c# を使ったことがないので、環境に合わせて変更してください。
static public byte[] signaturePNG { get{ return new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; }}
static public byte[] signatureIHDR{ get{ return new byte[]{ 0x49, 0x48, 0x44, 0x52 }; }}
public static bool Base64Url2Png(
out byte[] outPngData,
out uint outWidth,
out uint outHeight
)
{
try
{
// Base64URL -> Binary
int surplus = base64url.Length % 4;
string padding = ( surplus > 0) ? new string( '=', 4 - surplus) : string.Empty;
byte[] imageData = Convert.FromBase64String( base64url.Replace('_','/').Replace('-','+') + padding);
// PNG チェック
using( var memoryStream = new System.IO.MemoryStream( imageData))
{
if( memoryStream.Length < 32) throw new Exception(); // 異常ファイル
using( var reader = new System.IO.BinaryReader( memoryStream))
{
byte[] signature = reader.ReadBytes( 8);
if( !signature.SequenceEqual( signaturePNG)) throw new Exception(); // 異常ファイル
byte[] tmp = reader.ReadBytes( 4);
Array.Reverse( tmp); // Byte swapping Big endian → Little endian
var ihdr_length = System.BitConverter.ToUInt32( tmp, 0);
if( ihdr_length != 13) throw new Exception(); // 異常ファイル
signature = reader.ReadBytes( 4);
if( !signature.SequenceEqual( signatureIHDR)) throw new Exception(); // 異常ファイル
tmp = reader.ReadBytes( 4);
Array.Reverse( tmp);
var ihdr_width = System.BitConverter.ToUInt32( tmp, 0);
tmp = reader.ReadBytes( 4);
Array.Reverse( tmp);
var ihdr_height = System.BitConverter.ToUInt32( tmp, 0);
var ihdr_bitDepth = reader.ReadByte();
var ihdr_colorType = reader.ReadByte();
var ihdr_filter = reader.ReadByte();
var ihdr_interlace = reader.ReadByte();
tmp = reader.ReadBytes( 4);
Array.Reverse( tmp);
var ihdr_crc = System.BitConverter.ToUInt32( tmp, 0);
// 本来はcrcチェックするのが望ましい
outWidth = ihdr_width;
outHeight = ihdr_height;
outPngData = imageData;
}
}
}
catch( Exception e)
{
// 異常ファイル
outPngData = null;
outWidth = 0;
outHeight = 0;
return false;
}
return true;
}