C#合并BitMap图像生成超 * itmap
作者:记住我Gxy 发布时间:2023-12-08 18:24:11
标签:C#,合并,BitMap
当只需要两个图像合并的时候,可以简单的使用gdi+,把两个图像画到一个画布上面实现合并bitmap.
当需要将许多bitmap合并时,由于bitmap类限制,长度或宽度太大时会报异常,前面这种方法就行不通了。
由于bitmapp属于位图格式,了解图像格式后,发现,bitmap文件的第3-8位存储了文件大小信息,第19-22位存储了高度信息,第23-26位存储了宽度信息。文件头后面都是像素的argb,并无其它信息。于是,试想一下,如果把第二张图像的像素argb放到第一张后面,并修改第一张的文件头信息,是不是就可以实现文件合并了呢。事实证明:yes。
//设置文件头里面文件大小信息
public void SetBitmapFileSizeInfo(string filePath)
{
FileInfo fileInfo = new FileInfo(filePath);
long le = fileInfo.Length;
string hexSize = le.ToString("X").PadLeft(8, '0');
int size1 = Convert.ToInt32(hexSize.Substring(0, 2), 16);
int size2 = Convert.ToInt32(hexSize.Substring(2, 2), 16);
int size3 = Convert.ToInt32(hexSize.Substring(4, 2), 16);
int size4 = Convert.ToInt32(hexSize.Substring(6, 2), 16);
byte[] sizeBytes = new byte[] { (byte)size4, (byte)size3, (byte)size2, (byte)size1 };
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Write))
{
using (BinaryWriter r = new BinaryWriter(fs))
{
r.Seek(2, 0);
r.Write(sizeBytes, 0, sizeBytes.Length);
}
}
}
设置文件头里面文件长度和宽度信息
public void SetBitmapSizeInfo(string filePath,int width=0,int height=0)
{
if (height != 0)
{
string hexHeight = height.ToString("X").PadLeft(8, '0');
int h1 = Convert.ToInt32(hexHeight.Substring(0, 2), 16);
int h2 = Convert.ToInt32(hexHeight.Substring(2, 2), 16);
int h3 = Convert.ToInt32(hexHeight.Substring(4, 2), 16);
int h4 = Convert.ToInt32(hexHeight.Substring(6, 2), 16);
byte[] sizeHeight = new byte[] { (byte)h4, (byte)h3, (byte)h2, (byte)h1 };
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
{
using (BinaryWriter r = new BinaryWriter(fs))
{
r.Seek(22, 0);//高度保存位置
r.Write(sizeHeight, 0, sizeHeight.Length);
}
}
}
if (width != 0)
{
string hexWidth = height.ToString("X").PadLeft(8, '0');
int w1 = Convert.ToInt32(hexWidth.Substring(0, 2), 16);
int w2 = Convert.ToInt32(hexWidth.Substring(2, 2), 16);
int w3 = Convert.ToInt32(hexWidth.Substring(4, 2), 16);
int w4 = Convert.ToInt32(hexWidth.Substring(6, 2), 16);
byte[] sizeWidth = new byte[] { (byte)w4, (byte)w3, (byte)w2, (byte)w1 };
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
{
using (BinaryWriter r = new BinaryWriter(fs))
{
r.Seek(18, 0);//高度保存位置
r.Write(sizeWidth, 0, sizeWidth.Length);
}
}
}
}
合并多个bitmap文件,并生成一个最终文件
private void CreateBitMap(string tempPath,string imagePath)
{
string[] files = Directory.GetFiles(tempPath, "*.png");
Bitmap bmp;
int height=0;
for (int i = files.Length-1; i >0; i--)
{
string fileName = files[i];
bmp = new Bitmap(fileName);
if (i == files.Length - 1)
{
bmp.Save(imagePath, ImageFormat.Bmp);
height += bmp.Height;
bmp.Dispose();
continue;
}
else
{
byte[] bytes = GetImageRasterBytes(bmp, PixelFormat.Format32bppRgb);
using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Write))
{
fs.Seek(fs.Length, 0);
fs.Write(bytes, 0, bytes.Length);
}
height += bmp.Height;
bmp.Dispose();
}
}
SetBitmapFileSizeInfo(imagePath);
SetBitmapSizeInfo(imagePath, height: height);
//MessageBox.Show("合并成功");
}
private static byte[] GetImageRasterBytes(Bitmap bmp, PixelFormat format)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
byte[] bits = null;
try
{
// Lock the managed memory
BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, format);
// Declare an array to hold the bytes of the bitmap.
bits = new byte[bmpdata.Stride * bmpdata.Height];
// Copy the values into the array.
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, bits, 0, bits.Length);
// Release managed memory
bmp.UnlockBits(bmpdata);
}
catch
{
return null;
}
return bits;
}
来源:https://blog.csdn.net/qq_35669328/article/details/100696671


猜你喜欢
- Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。它与 JSP,Velocity,FreeMaker 等模
- 在Java的内存分配中,总共3种常量池:Java 常量池详解(二)class文件常量池 和 Java 常量池详解(三)class运行时常量池
- 之前学习oracle,简单的认为数据库只存在服务器端,学习安卓之后才发现原来android和Ios本身是“携带”数据库的——SQ
- 本文实例讲述了C#中数组段用法。分享给大家供大家参考。具体分析如下:1.数组段说明① 结构ArraySegment<T>表示数组
- 一、下载Xxl-Job源代码并导入本地并运行Github地址:https://github.com/xuxueli/xxl-job中文文档地
- 新建项目IDEA上方工具栏点击:文件->新建->模块此时的目录结构:需要在main文件夹下补全两个文件夹,点击main,右键-&
- 具体代码如下所示:<?xml version="1.0"?><LinearLayout android
- java接口返回参数按照请求参数进行排序在项目实际开发中可能遇到过这种问题,接口请求参数顺序是[a,b,c],结果返回的数据是[bObjec
- 题外话: 泛型与通配符是Java语法中比较难懂的两个语法,学习泛型和通配符的主要目的是能够看懂源码,实际使用的不多。1.泛型1.1泛型的用法
- 简述Preference是Android的控件之一,相对来说我们用的比较少,但在系统应用的Settings设置应用模块中大部分由Prefer
- 最近在公司用到外设,需要判断接入的外设的VendorId和ProductId,然后给大家说一下自己的学习成果把 ,首先我门可以通过andro
- 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数
- 在我们的程序中,经常会有一些耗时较长的运算,为了保证用户体验,不引起界面不响应,我们一般会采用多线程操作,让耗时操作在后台完成,完成后再进行
- 前言先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁
- 最近在做一个移动端HTML5的应用,使用到了上传功能,起初使用传统的上传方式上传手机拍照的照片,由于手机拍照出来的照片一般都是好几MB,所以
- 注:图片来源于网络SpringBoot作为业内公认的优秀开源框架,它的 * 是如何实现呢?在这里首先对一些基础组件进行分析;1、事件Appl
- 前言自 Java 7 以来,java 中的 switch 语句经历了快速发展。因此,在本文中,我们将通过示例讨论 switch 语句从 ja
- 前言在Android开发过程中,不管是写Demo还是实战项目中,都会打印一些日志用于记录数据,调试来着,Android中的日志工具类是Log
- this总要有个事物来代表类的当前对象,就像C++中的this指针一样,Java中的this关键字就是代表当前对象的引用。它有三个主要的作用
- 前言前面文章讲了消息是如何保存的以及consumeQueue与Index文件更新机制。随着消息的增加,Broker不可能一直保存所有消息,B