同系列文章:
用户通过浏览器将图像数据上传到服务器,然后由服务器下发到嵌入式设备。设备只能显示16位Bitmap图像。
下面为桌面端采用WPF实现图像编码与复原,以方便设备固件和服务器端分别调试:
/* ---------------------------------------------------------- * 文件名称:BitmapUtil.cs * * 作者:秦建辉 * * MSN:splashcn@msn.com * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * Visual Studio V2010 * .NET Framework 4 Client Profile * * 版本历史: * V1.0 2012年08月02日 * 将原始图像转换为16位图像的Base64编码字符串 * 从16位图像的Base64编码字符串复原图像 ------------------------------------------------------------ */ using System; using System.Windows.Media; using System.Windows.Media.Imaging; namespace Splash.Imaging { public static class BitmapUtil { /// <summary> /// 将原始图像转换为16位图像的Base64编码字符串 /// </summary> /// <param name="bs">要转换的图像源</param> /// <param name="isBigEndian">字节序是否为大端</param> /// <returns>16位图像内容的Base64编码字符串</returns> /// <remarks>16位图像格式为Bgr565</remarks> public static String ToBgr565Base64String(this BitmapSource bs, Boolean isBigEndian = false) { // 将像素格式统一到Bgr32,并提取图像数据 Int32 PixelHeight = bs.PixelHeight; // 图像高度 Int32 PixelWidth = bs.PixelWidth; // 图像宽度 Int32 Stride = PixelWidth << 2; // 扫描行跨距 Byte[] Bgr24Pixels = new Byte[PixelHeight * Stride]; if (bs.Format == PixelFormats.Bgr32 || bs.Format == PixelFormats.Bgra32) { // 拷贝像素数据 bs.CopyPixels(Bgr24Pixels, Stride, 0); } else { // 先进行像素格式转换,再拷贝像素数据 new FormatConvertedBitmap(bs, PixelFormats.Bgr32, null, 0).CopyPixels(Bgr24Pixels, Stride, 0); } // Bgr565格式为 RRRRR GGGGGG BBBBB Byte[] Bgr565Pixels = new Byte[(PixelHeight * PixelWidth) << 1]; Int32 Loc = 0; for (Int32 y = 0; y < PixelHeight; y++) { Int32 Index = y * Stride; for (Int32 x = 0; x < PixelWidth; x++) { Byte B = Bgr24Pixels[Index++]; Byte G = Bgr24Pixels[Index++]; Byte R = Bgr24Pixels[Index++]; Index++; // 跳过A分量 if(isBigEndian) { // 第一字节为高字节 Bgr565Pixels[Loc++] = (Byte)((R & 0xf8) | ((G >> 5) & 7)); Bgr565Pixels[Loc++] = (Byte)(((G << 3) & 0xe0) | ((B >> 3) & 0x1f)); } else { // 第一字节为低字节 Bgr565Pixels[Loc++] = (Byte)(((G << 3) & 0xe0) | ((B >> 3) & 0x1f)); Bgr565Pixels[Loc++] = (Byte)((R & 0xf8) | ((G >> 5) & 7)); } } } return Convert.ToBase64String(Bgr565Pixels); } /// <summary> /// 将原始图像转换为16位图像的Base64编码字符串 /// </summary> /// <param name="bs">要转换的图像源</param> /// <param name="isBigEndian">字节序是否为大端</param> /// <returns>16位图像内容的Base64编码字符串</returns> /// <remarks>16位图像格式为Bgr555</remarks> public static String ToBgr555Base64String(this BitmapSource bs, Boolean isBigEndian = false) { // 将像素格式统一到Bgr32,并提取图像数据 Int32 PixelHeight = bs.PixelHeight; // 图像高度 Int32 PixelWidth = bs.PixelWidth; // 图像宽度 Int32 Stride = PixelWidth << 2; // 扫描行跨距 Byte[] Bgr24Pixels = new Byte[PixelHeight * Stride]; if (bs.Format == PixelFormats.Bgr32 || bs.Format == PixelFormats.Bgra32) { // 拷贝像素数据 bs.CopyPixels(Bgr24Pixels, Stride, 0); } else { // 先进行像素格式转换,再拷贝像素数据 new FormatConvertedBitmap(bs, PixelFormats.Bgr32, null, 0).CopyPixels(Bgr24Pixels, Stride, 0); } // Bgr555格式为 X RRRRR GGGGG BBBBB Byte[] Bgr555Pixels = new Byte[(PixelHeight * PixelWidth) << 1]; Int32 Loc = 0; for (Int32 y = 0; y < PixelHeight; y++) { Int32 Index = y * Stride; for (Int32 x = 0; x < PixelWidth; x++) { Byte B = Bgr24Pixels[Index++]; Byte G = Bgr24Pixels[Index++]; Byte R = Bgr24Pixels[Index++]; Index++; // 跳过A分量 if (isBigEndian) { // 第一字节为高字节 Bgr555Pixels[Loc++] = (Byte)(((R >> 1) & 0x7c) | ((G >> 6) & 3)); Bgr555Pixels[Loc++] = (Byte)(((G << 2) & 0xe0) | ((B >> 3) & 0x1f)); } else { // 第一字节为低字节 Bgr555Pixels[Loc++] = (Byte)(((G << 2) & 0xe0) | ((B >> 3) & 0x1f)); Bgr555Pixels[Loc++] = (Byte)(((R >> 1) & 0x7c) | ((G >> 6) & 3)); } } } return Convert.ToBase64String(Bgr555Pixels); } /// <summary> /// 从16位图像的 Base64 编码字符串复原图像 /// </summary> /// <param name="width">图像宽度</param> /// <param name="height">图像高度</param> /// <param name="s">图像数据编码字符串</param> /// <param name="isBigEndian">字节序是否是大端</param> /// <returns>复原的图像</returns> /// <remarks>16位图像格式为Bgr565</remarks> public static BitmapSource CreateImageFromBgr565Base64String(Int32 width, Int32 height, String s, Boolean isBigEndian = false) { Byte[] Source = Convert.FromBase64String(s); if (Source.Length != (width * height) << 1) return null; // 生成16位图像像素数组 Int32 Stride = (((width << 1) + 3) >> 2) << 2; // 要求4字节对齐 Byte[] Pixels = new Byte[height * Stride]; for (Int32 y = 0; y < height; y++) { Int32 Index = y * Stride; for (Int32 x = 0; x < width; x++) { Byte b1 = Source[Index]; Byte b2 = Source[Index +1]; if (isBigEndian) { Pixels[Index++] = b2; Pixels[Index++] = b1; } else { Pixels[Index++] = b1; Pixels[Index++] = b2; } } } // 生成图像 return BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgr565, null, Pixels, Stride); } /// <summary> /// 从16位图像的 Base64 编码字符串复原图像 /// </summary> /// <param name="width">图像宽度</param> /// <param name="height">图像高度</param> /// <param name="s">图像数据编码字符串</param> /// <param name="isBigEndian">字节序是否是大端</param> /// <returns>复原的图像</returns> /// <remarks>16位图像格式为Bgr555</remarks> public static BitmapSource CreateImageFromBgr555Base64String(Int32 width, Int32 height, String s, Boolean isBigEndian = false) { Byte[] Source = Convert.FromBase64String(s); if (Source.Length != (width * height) << 1) return null; // 生成16位图像像素数组 Int32 Stride = (((width << 1) + 3) >> 2) << 2; // 要求4字节对齐 Byte[] Pixels = new Byte[height * Stride]; for (Int32 y = 0; y < height; y++) { Int32 Index = y * Stride; for (Int32 x = 0; x < width; x++) { Byte b1 = Source[Index]; Byte b2 = Source[Index + 1]; if (isBigEndian) { Pixels[Index++] = b2; Pixels[Index++] = b1; } else { Pixels[Index++] = b1; Pixels[Index++] = b2; } } } // 生成图像 return BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgr555, null, Pixels, Stride); } } }