高分救助 C#读取1G以上的大图

lianru1987cuiguo 2009-09-29 04:04:06
各位大侠:
小弟遇到一个问题,郁闷了几天了。费话不多说了。。
问题是我在读取一张1G以上的大图,用Bitmap MyBitmap = new Bitmap(Filename);和其它的直接读图片到内存都会造成out of memory的异常。于是乎我想到了用filestream流来读取。可是我又对BMP图片的算法不是怎么了解。怎么读取大图的一部份并显示在pictruebox 里面?向大伙儿求救了啊。
...全文
966 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
lwzj12 2010-05-04
  • 打赏
  • 举报
回复
文件大小偏移
int filesizeOffset = 0x0002;
//数据区偏移
int dataOffset = 0x000A;
//图像宽度偏移
int widthOffset = 0x0012;
//图像高度偏移
int heightOffset = 0x0016;
//位数偏移
int bitOffset = 0x001C;
//是否压缩偏移
int compressOffset = 0x001E;
//数据区大小偏移
int datasizeOffset = 0x0022;

int width = 0;
int height = 0;
int fileheadsize = 0;
int dataseize = 0;
int offset = 0;
//读取待切分文件
string file = "c:\\1.bmp";
FileInfo fi = new FileInfo(file);
FileStream fs = fi.OpenRead();

byte[] buff = new byte[4];
//数据区偏移量
fs.Seek(dataOffset, SeekOrigin.Begin);
int nBytesRead = fs.Read(buff, 0, buff.Length);
fileheadsize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区偏移:"+fileheadsize);
//宽度
fs.Seek(widthOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
width = BitConverter.ToInt32(buff, 0);
Console.WriteLine("宽度:" + width);
//高度
fs.Seek(heightOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
height = BitConverter.ToInt32(buff, 0);
Console.WriteLine("高度:" + height);
//位数
fs.Seek(bitOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("位数:"+offset);
//是否压缩
fs.Seek(compressOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("压缩:" + offset);
//数据区大小
fs.Seek(datasizeOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
dataseize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区大小:" + dataseize);

//读取图像下半部分,写入11.bmp
FileStream fs1 = new FileStream("c:\\11.bmp",FileMode.OpenOrCreate);
//复制文件头
fs.Seek(0,SeekOrigin.Begin);
byte[] filehead = new byte[fileheadsize];
fs.Read(filehead, 0, fileheadsize);
fs1.Write(filehead, 0, fileheadsize);
//复制数据
byte[] data = new byte[dataseize/2];
fs.Seek(fileheadsize, SeekOrigin.Begin);
fs.Read(data, 0, data.Length);
fs1.Write(data, 0, data.Length);

//修改高度,因为是水平切分,所以不需修改宽度
byte[] b = new byte[4];
b = BitConverter.GetBytes(height/2);
fs1.Seek(heightOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);
//修改数据区大小
b = new byte[4];
b = BitConverter.GetBytes(dataseize/ 2);
fs1.Seek(datasizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//修改文件大小
b = new byte[4];
b = BitConverter.GetBytes(fs1.Length);
fs1.Seek(filesizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//关闭对象
fs.Close();
fs1.Flush();
fs1.Close();
Console.Read();



竖直切分怎么做,我做了一下,怎么不行,切分出来的结果好象有失误


int filesizeOffset = 0x0002;
//数据区偏移
int dataOffset = 0x000A;
//图像宽度偏移
int widthOffset = 0x0012;
//图像高度偏移
int heightOffset = 0x0016;
//位数偏移
int bitOffset = 0x001C;
//是否压缩偏移
int compressOffset = 0x001E;
//数据区大小偏移
int datasizeOffset = 0x0022;

int width = 0;
int height = 0;
int fileheadsize = 0;
int dataseize = 0;
int offset = 0;
//读取待切分文件




//Image img = Image.FromFile("c:\\1aa.jpg");
//img.Save("c:\\1aa.bmp",ImageFormat.Bmp );
string file = "c:\\aa32.bmp";

FileInfo fi = new FileInfo(file);
FileStream fs = fi.OpenRead();

byte[] buff = new byte[4];
//数据区偏移量
fs.Seek(dataOffset, SeekOrigin.Begin);
int nBytesRead = fs.Read(buff, 0, buff.Length);
fileheadsize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区偏移:" + fileheadsize);
//宽度
fs.Seek(widthOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
width = BitConverter.ToInt32(buff, 0);
Console.WriteLine("宽度:" + width);
//高度
fs.Seek(heightOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
height = BitConverter.ToInt32(buff, 0);
Console.WriteLine("高度:" + height);
//位数
fs.Seek(bitOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("位数:" + offset);
//是否压缩
fs.Seek(compressOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("压缩:" + offset);
//数据区大小
fs.Seek(datasizeOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
dataseize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区大小:" + dataseize);

//读取图像下半部分,写入11.bmp
FileStream fs1 = new FileStream("c:\\22.bmp", FileMode.OpenOrCreate);
//复制文件头
fs.Seek(0, SeekOrigin.Begin);
byte[] filehead = new byte[fileheadsize];
fs.Read(filehead, 0, fileheadsize);
fs1.Write(filehead, 0, fileheadsize);
//复制数据
byte[] data = new byte[dataseize / 2];
fs.Seek(fileheadsize, SeekOrigin.Begin);
fs.Read(data, 0, data.Length);
fs1.Write(data, 0, data.Length);


//修改宽度,因为是水平切分
byte[] b = new byte[4];
b = BitConverter.GetBytes(width / 2);
fs1.Seek(widthOffset, SeekOrigin.Begin);

fs1.Write(b, 0, buff.Length);

//修改高度,因为是水平切分,所以不需修改宽度
//byte[] b = new byte[4];
//b = BitConverter.GetBytes(height / 2);
//fs1.Seek(heightOffset, SeekOrigin.Begin);
//fs1.Write(b, 0, buff.Length);




//修改数据区大小
b = new byte[4];
b = BitConverter.GetBytes(dataseize / 2);
fs1.Seek(datasizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//修改文件大小
b = new byte[4];
b = BitConverter.GetBytes(fs1.Length);
fs1.Seek(filesizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//关闭对象
fs.Close();
fs1.Flush();
fs1.Close();
Console.Read();
}
}

期待高手解决?
huaxia2007081161 2010-04-16
  • 打赏
  • 举报
回复
请问楼主,宽度该如何处理呢,我处理宽的时候一直有错,显示的图像为重叠的错位像。
麻烦知道的同志告知一下
dzq138 2009-12-28
  • 打赏
  • 举报
回复
哎,我现在要解JPEG的大图.更烦.....
小范f-li.cn 2009-09-29
  • 打赏
  • 举报
回复
lg
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 lsd123 的回复:]
.
[/Quote]

哈哈,别无语咯。。
lsd123 2009-09-29
  • 打赏
  • 举报
回复
.
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
结贴给分了,哈哈,谢谢各位的热心。。。特别是 shalen520 ,有没有联系方式,请教请教。。
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
谢谢,已经很够了。。辛苦了
shalen520 2009-09-29
  • 打赏
  • 举报
回复

//文件大小偏移
int filesizeOffset = 0x0002;
//数据区偏移
int dataOffset = 0x000A;
//图像宽度偏移
int widthOffset = 0x0012;
//图像高度偏移
int heightOffset = 0x0016;
//位数偏移
int bitOffset = 0x001C;
//是否压缩偏移
int compressOffset = 0x001E;
//数据区大小偏移
int datasizeOffset = 0x0022;

int width = 0;
int height = 0;
int fileheadsize = 0;
int dataseize = 0;
int offset = 0;
//读取待切分文件
string file = "c:\\1.bmp";
FileInfo fi = new FileInfo(file);
FileStream fs = fi.OpenRead();

byte[] buff = new byte[4];
//数据区偏移量
fs.Seek(dataOffset, SeekOrigin.Begin);
int nBytesRead = fs.Read(buff, 0, buff.Length);
fileheadsize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区偏移:"+fileheadsize);
//宽度
fs.Seek(widthOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
width = BitConverter.ToInt32(buff, 0);
Console.WriteLine("宽度:" + width);
//高度
fs.Seek(heightOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
height = BitConverter.ToInt32(buff, 0);
Console.WriteLine("高度:" + height);
//位数
fs.Seek(bitOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("位数:"+offset);
//是否压缩
fs.Seek(compressOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
offset = BitConverter.ToInt32(buff, 0);
Console.WriteLine("压缩:" + offset);
//数据区大小
fs.Seek(datasizeOffset, SeekOrigin.Begin);
fs.Read(buff, 0, buff.Length);
dataseize = BitConverter.ToInt32(buff, 0);
Console.WriteLine("数据区大小:" + dataseize);

//读取图像下半部分,写入11.bmp
FileStream fs1 = new FileStream("c:\\11.bmp",FileMode.OpenOrCreate);
//复制文件头
fs.Seek(0,SeekOrigin.Begin);
byte[] filehead = new byte[fileheadsize];
fs.Read(filehead, 0, fileheadsize);
fs1.Write(filehead, 0, fileheadsize);
//复制数据
byte[] data = new byte[dataseize/2];
fs.Seek(fileheadsize, SeekOrigin.Begin);
fs.Read(data, 0, data.Length);
fs1.Write(data, 0, data.Length);

//修改高度,因为是水平切分,所以不需修改宽度
byte[] b = new byte[4];
b = BitConverter.GetBytes(height/2);
fs1.Seek(heightOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);
//修改数据区大小
b = new byte[4];
b = BitConverter.GetBytes(dataseize/ 2);
fs1.Seek(datasizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//修改文件大小
b = new byte[4];
b = BitConverter.GetBytes(fs1.Length);
fs1.Seek(filesizeOffset, SeekOrigin.Begin);
fs1.Write(b, 0, buff.Length);

//关闭对象
fs.Close();
fs1.Flush();
fs1.Close();
Console.Read();


写得比较随意,直接截了个屏存为24位位图来做的,异常处理什么的也没做,变量命名也不规范,你参考下吧~
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 falconfei 的回复:]
谁生成的,就让谁将图片分割了不就解决了。
[/Quote]

楼上的老兄没有看懂你的意思哦,呵呵
极地_雪狼 2009-09-29
  • 打赏
  • 举报
回复
谁生成的,就让谁将图片分割了不就解决了。
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
高手出现了,能不能把你的代码贴出来参考一下啊。
shalen520 2009-09-29
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 lianru1987cuiguo 的回复:]
嗯,个人觉得应该给每一个区块再给个bmp的头和尾


[/Quote]

这个是肯定的,直接复制大图的文件头给小图,然后修改文件大小,数据区大小,数据区偏移量,宽度,高度,接着写入位图数据就可以了

刚用屏幕截图试了一下filestream方式,很容易
三水青 2009-09-29
  • 打赏
  • 举报
回复
首先,得用工具(具体什么工具忘了)把图片切割成256x256或512x512的大小,显示的时候只加载当前要显示的图片,然后算出切割后每张图的四个顶点的经纬度。还有要注意,图片是逐层放大的,所以要有很多层,而且每层的文件夹和文件夹里的图片的命名都要有规则的。这个算法好像叫金字塔算法。以前做过,现在好久没搞这个了。
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
嗯,个人觉得应该给每一个区块再给个bmp的头和尾

wojiaochenglong 2009-09-29
  • 打赏
  • 举报
回复
如果用六楼朋友的方法,对fileStream.length分份是有问题的,这个还需要经过计算,不是简单的就可以算出来的而且图片会有断裂
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 zzxap 的回复:]
可以参考c#屏幕截图http://blog.19lou.com/?uid-10047532-action-viewspace-itemid-3865531
[/Quote]

谢谢,正在研究你发的网站
zzxap 2009-09-29
  • 打赏
  • 举报
回复
可以参考c#屏幕截图http://blog.19lou.com/?uid-10047532-action-viewspace-itemid-3865531
lianru1987cuiguo 2009-09-29
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 shalen520 的回复:]
bmp的格式很清楚了,如果没压缩的话,还是比较容易的

先读取文件头来得到图像大小,然后根据块大小来计算分多少块

然后根据像素的位数,计算每一块小图每一行的起始/结束像素在文件流中的偏移,来读取小图;使用偏移量的话,就不需要加载整个文件

需要注意的是:数据区的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素
[/Quote]

谢谢大师,把思路说得很明确了,我按这个思路来做看看。欢迎大家继续讨论,最后如果成功我会发布源码,供大家下载。呵呵
zzxap 2009-09-29
  • 打赏
  • 举报
回复
可以获取图片的坐标区域,然后显示这一部分
加载更多回复(18)

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧