将位图分块
最近由于工作需要,要实现一个简单的gis系统。要求能够显示同一区域的多种分辨率的地图。由于图片有大有小,当图片很大的时候如果将整张图片读入内存,将会消耗大量的内存,效率不高。所以考虑将大的图片切割成小块保存,根据显示时候的需要调用指定区域的图片,拼接起来显示。
下面是我切割图片的代码;仅供参考,希望能对大家有所帮助
BMPSpliter.h
1
// BMPSpliter.h: interface for the BMPSpliter class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
5
#if !defined(AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_)
6
#define AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_
7
8
#if _MSC_VER > 1000
9
#pragma once
10
#endif // _MSC_VER > 1000
11
class BMPSpliter : public CObject
12
{
13
public:
14
BOOL ReadFile();
15
16
void SetSourceFileName(CString fileName);
17
void SetDestDirectory(CString pdestDir);
18
void SetStartNumber(int startNumber);
19
20
21
BOOL Split(int XPxCount, int YPxCount);
22
BOOL ReadFile(CString fileName);
23
BMPSpliter();
24
virtual ~BMPSpliter();
25
private:
26
CString SourceFileName;
27
CString DestDirectory;
28
int StartNumber;
29
int GetTheLineOffset(int XNum, int XPxCount);
30
int GetOneLineSize(int XPxCount);
31
32
int GetTheTileSize(int XPxCount, int YPxCount);
33
LPBYTE GetTheTile( int XNum, int YNum,int XPxCount, int YPxCount );
34
LPBYTE lpbmpBody;
35
BITMAPINFO bitmapInfo;
36
BITMAPINFOHEADER bmpInfoHeader;
37
BITMAPFILEHEADER fileHeader;
38
BOOL WriteFile(CString fileName,LPBYTE bmpBody, int count, int height, int width);
39
40
};
41
42
#endif // !defined(AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_)
43
// BMPSpliter.h: interface for the BMPSpliter class.2
//3
//////////////////////////////////////////////////////////////////////4

5
#if !defined(AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_)6
#define AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_7

8
#if _MSC_VER > 10009
#pragma once10
#endif // _MSC_VER > 100011
class BMPSpliter : public CObject 12
{13
public:14
BOOL ReadFile();15
16
void SetSourceFileName(CString fileName);17
void SetDestDirectory(CString pdestDir);18
void SetStartNumber(int startNumber);19
20
21
BOOL Split(int XPxCount, int YPxCount);22
BOOL ReadFile(CString fileName);23
BMPSpliter();24
virtual ~BMPSpliter();25
private:26
CString SourceFileName;27
CString DestDirectory;28
int StartNumber;29
int GetTheLineOffset(int XNum, int XPxCount);30
int GetOneLineSize(int XPxCount);31
32
int GetTheTileSize(int XPxCount, int YPxCount);33
LPBYTE GetTheTile( int XNum, int YNum,int XPxCount, int YPxCount );34
LPBYTE lpbmpBody;35
BITMAPINFO bitmapInfo;36
BITMAPINFOHEADER bmpInfoHeader;37
BITMAPFILEHEADER fileHeader;38
BOOL WriteFile(CString fileName,LPBYTE bmpBody, int count, int height, int width);39
40
};41

42
#endif // !defined(AFX_BMPSPLITER_H__1B6BD900_9C6F_4BCD_8B77_2BC47F32D1D0__INCLUDED_)43

BMPSpliter.cpp
1
// BMPSpliter.cpp: implementation of the BMPSpliter class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
//////////////////////////////////////////////////////////////////////////
5
//只能构处理24位色以上的图片。
6
//用户只要指定要切割的图片,以及切割后图片的宽度和高度,该类即会按照从左到右、
7
//从下到上的顺序来切割图片;
8
//通过SetDestDirectory()用户可以指定切割后图片的存放目录;
9
//通过SetStartNumber()可以指定切割后图片的起始编号;
10
//////////////////////////////////////////////////////////////////////////
11
#include "stdafx.h"
12
#include "SplitBMP.h"
13
#include "BMPSpliter.h"
14
#include <math.h>
15
#ifdef _DEBUG
16
#undef THIS_FILE
17
static char THIS_FILE[]=__FILE__;
18
#define new DEBUG_NEW
19
#endif
20
21
//////////////////////////////////////////////////////////////////////
22
// Construction/Destruction
23
//////////////////////////////////////////////////////////////////////
24
25
BMPSpliter::BMPSpliter()
26
{
27
SetStartNumber(0);
28
lpbmpBody = NULL;
29
SetDestDirectory("map");
30
SetSourceFileName("");
31
}
32
33
BMPSpliter::~BMPSpliter()
34
{
35
if(lpbmpBody!=NULL)
36
delete [] lpbmpBody;
37
lpbmpBody =NULL;
38
}
39
40
BOOL BMPSpliter::ReadFile(CString fileName)
41
{
42
SetSourceFileName(fileName);
43
return ReadFile();
44
}
45
46
BOOL BMPSpliter::Split( int XPxCount, int YPxCount )
47
{
48
if(lpbmpBody == NULL)
49
return FALSE;
50
if(SourceFileName.IsEmpty())
51
return FALSE;
52
double temp = XPxCount;
53
int XCount = (int)ceil(bmpInfoHeader.biWidth/temp);
54
temp = YPxCount;
55
int YCount = (int)ceil(bmpInfoHeader.biHeight/temp);
56
LPBYTE bmpBody;
57
CString fileName;
58
CString msg;
59
for (int j = 0; j <YCount ; j++)
60
{
61
for (int i = 0; i <XCount ; i++)
62
{
63
bmpBody = GetTheTile(i,j, XPxCount,YPxCount);
64
fileName.Format("%s\\%d.bmp",DestDirectory,i+j*XCount+this->StartNumber);
65
if (!WriteFile(fileName,bmpBody,GetTheTileSize(XPxCount,YPxCount),XPxCount,YPxCount))
66
{
67
msg.Format("%s 写入失败!",fileName);
68
//messagePrinter(msg);
69
return FALSE;
70
}
71
}
72
}
73
return TRUE;
74
// return WriteFile("map\\A.bmp",lpbmpBody,bmpInfoHeader.biSizeImage,bmpInfoHeader.biHeight,bmpInfoHeader.biWidth);
75
}
76
77
BOOL BMPSpliter::WriteFile(CString fileName,LPBYTE bmpBody, int count, int height, int width)
78
{
79
CFile file;
80
if (!file.Open(fileName,CFile::modeCreate|CFile::modeWrite))
81
return FALSE;
82
BITMAPFILEHEADER header = this->fileHeader;
83
header.bfSize = 54 + count;
84
BITMAPINFOHEADER infoHeader = this->bmpInfoHeader;
85
infoHeader.biHeight = height;
86
infoHeader.biWidth = width;
87
infoHeader.biSizeImage = count;
88
try
89
{
90
file.Seek(0,CFile::begin);
91
file.Write( (LPVOID)&header, sizeof(BITMAPFILEHEADER));
92
file.Write( (LPVOID)&infoHeader, sizeof(BITMAPINFOHEADER));
93
file.Write( (LPVOID)bmpBody, count);
94
file.Flush();
95
}
96
catch (CException* e)
97
{
98
file.Close();
99
return FALSE;
100
}
101
file.Close();
102
return TRUE;
103
}
104
105
106
107
LPBYTE BMPSpliter::GetTheTile( int XNum, int YNum,int XPxCount, int YPxCount )
108
{
109
//根据参数计算要读取的区域
110
//如果超越了原图的边界,用空白补齐;
111
LPBYTE lpbody= NULL;
112
int count = GetOneLineSize(XPxCount);
113
count = count * YPxCount;
114
lpbody = (LPBYTE) new char[count];
115
FillMemory(lpbody,count,0xFF);
116
int StartPos = GetOneLineSize(bmpInfoHeader.biWidth)*YPxCount*YNum + (bmpInfoHeader.biBitCount/8)*XPxCount*XNum;
117
int OneLineOffset = GetTheLineOffset(XNum, XPxCount);
118
int LineStartPos = 0;
119
for (int i = 0; i < YPxCount ; i++)
120
{
121
LineStartPos = StartPos + GetOneLineSize(bmpInfoHeader.biWidth)*i;
122
CopyMemory(&lpbody[GetOneLineSize(XPxCount)*i],&lpbmpBody[LineStartPos],OneLineOffset);
123
}
124
return lpbody;
125
126
}
127
128
int BMPSpliter::GetTheTileSize( int XPxCount, int YPxCount )
129
{
130
//根据参数来计算该Tile的图像体的大小。
131
int result = GetOneLineSize(XPxCount);
132
result = result*YPxCount;
133
return result;
134
}
135
136
137
int BMPSpliter::GetOneLineSize(int XPxCount)
138
{
139
int result = (((XPxCount*bmpInfoHeader.biBitCount)+31)>>5)<<2;
140
return result;
141
}
142
143
int BMPSpliter::GetTheLineOffset(int XNum, int XPxCount)
144
{
145
int result = XPxCount*(bmpInfoHeader.biBitCount/8);
146
int sourceBmpLengthPerLine = bmpInfoHeader.biWidth*(bmpInfoHeader.biBitCount/8);
147
if( result*(XNum+1)>sourceBmpLengthPerLine)
148
result = sourceBmpLengthPerLine - (result*XNum);
149
return result;
150
}
151
152
153
void BMPSpliter::SetStartNumber(int startNumber)
154
{
155
StartNumber = startNumber;
156
}
157
158
void BMPSpliter::SetDestDirectory(CString destDir )
159
{
160
this->DestDirectory = destDir;
161
CFileFind ff;
162
if(!ff.FindFile(DestDirectory+"\\*.*"))
163
CreateDirectory(DestDirectory+"\\",NULL);
164
}
165
166
void BMPSpliter::SetSourceFileName(CString fileName)
167
{
168
SourceFileName = fileName;
169
}
170
171
BOOL BMPSpliter::ReadFile()
172
{
173
CFile file;
174
file.Open(SourceFileName,CFile::modeRead);
175
try
176
{
177
int counts = file.Read((LPVOID)&fileHeader,sizeof(BITMAPFILEHEADER));
178
if (counts!=sizeof(BITMAPFILEHEADER))
179
throw new CException;
180
if(fileHeader.bfType != 0x4d42)
181
throw new CException;
182
//文件头信息->位图信息->位图数据
183
//bfOffBits为从文件开始到数据内容之间的距离
184
int size = fileHeader.bfOffBits - sizeof(BITMAPFILEHEADER);
185
//bmpInfoHeader = (LPBITMAPINFOHEADER) new char[size];
186
// BITMAPINFOHEADER和颜色表
187
counts = file.Read(&bmpInfoHeader, sizeof(BITMAPINFOHEADER));
188
if (counts!=sizeof(BITMAPINFOHEADER))
189
throw new CException;
190
//如果为16位色或者更小,则无法处理
191
if(bmpInfoHeader.biBitCount<=16)
192
throw new CException;
193
//如果图像是压缩的,则也无法处理
194
if(bmpInfoHeader.biCompression !=BI_RGB)
195
throw new CException;
196
//读取图像内容
197
file.Seek(fileHeader.bfOffBits,CFile::begin);
198
lpbmpBody = (LPBYTE)new char[bmpInfoHeader.biSizeImage];
199
counts = file.Read(lpbmpBody,bmpInfoHeader.biSizeImage);
200
}
201
catch (CException* e)
202
{
203
AfxMessageBox("Read File Error");
204
return FALSE;
205
}
206
return TRUE;
207
}
208
// BMPSpliter.cpp: implementation of the BMPSpliter class.2
//3
//////////////////////////////////////////////////////////////////////4
//////////////////////////////////////////////////////////////////////////5
//只能构处理24位色以上的图片。6
//用户只要指定要切割的图片,以及切割后图片的宽度和高度,该类即会按照从左到右、7
//从下到上的顺序来切割图片;8
//通过SetDestDirectory()用户可以指定切割后图片的存放目录;9
//通过SetStartNumber()可以指定切割后图片的起始编号;10
//////////////////////////////////////////////////////////////////////////11
#include "stdafx.h"12
#include "SplitBMP.h"13
#include "BMPSpliter.h"14
#include <math.h>15
#ifdef _DEBUG16
#undef THIS_FILE17
static char THIS_FILE[]=__FILE__;18
#define new DEBUG_NEW19
#endif20

21
//////////////////////////////////////////////////////////////////////22
// Construction/Destruction23
//////////////////////////////////////////////////////////////////////24

25
BMPSpliter::BMPSpliter()26
{27
SetStartNumber(0); 28
lpbmpBody = NULL;29
SetDestDirectory("map");30
SetSourceFileName("");31
}32

33
BMPSpliter::~BMPSpliter()34
{35
if(lpbmpBody!=NULL)36
delete [] lpbmpBody;37
lpbmpBody =NULL;38
}39

40
BOOL BMPSpliter::ReadFile(CString fileName)41
{42
SetSourceFileName(fileName);43
return ReadFile(); 44
}45

46
BOOL BMPSpliter::Split( int XPxCount, int YPxCount )47
{48
if(lpbmpBody == NULL)49
return FALSE;50
if(SourceFileName.IsEmpty())51
return FALSE;52
double temp = XPxCount;53
int XCount = (int)ceil(bmpInfoHeader.biWidth/temp);54
temp = YPxCount;55
int YCount = (int)ceil(bmpInfoHeader.biHeight/temp);56
LPBYTE bmpBody;57
CString fileName;58
CString msg;59
for (int j = 0; j <YCount ; j++)60
{61
for (int i = 0; i <XCount ; i++)62
{63
bmpBody = GetTheTile(i,j, XPxCount,YPxCount); 64
fileName.Format("%s\\%d.bmp",DestDirectory,i+j*XCount+this->StartNumber);65
if (!WriteFile(fileName,bmpBody,GetTheTileSize(XPxCount,YPxCount),XPxCount,YPxCount))66
{67
msg.Format("%s 写入失败!",fileName);68
//messagePrinter(msg);69
return FALSE;70
}71
}72
}73
return TRUE;74
// return WriteFile("map\\A.bmp",lpbmpBody,bmpInfoHeader.biSizeImage,bmpInfoHeader.biHeight,bmpInfoHeader.biWidth);75
}76

77
BOOL BMPSpliter::WriteFile(CString fileName,LPBYTE bmpBody, int count, int height, int width)78
{79
CFile file;80
if (!file.Open(fileName,CFile::modeCreate|CFile::modeWrite))81
return FALSE;82
BITMAPFILEHEADER header = this->fileHeader;83
header.bfSize = 54 + count;84
BITMAPINFOHEADER infoHeader = this->bmpInfoHeader;85
infoHeader.biHeight = height;86
infoHeader.biWidth = width;87
infoHeader.biSizeImage = count;88
try89
{90
file.Seek(0,CFile::begin);91
file.Write( (LPVOID)&header, sizeof(BITMAPFILEHEADER));92
file.Write( (LPVOID)&infoHeader, sizeof(BITMAPINFOHEADER));93
file.Write( (LPVOID)bmpBody, count);94
file.Flush(); 95
}96
catch (CException* e)97
{ 98
file.Close(); 99
return FALSE;100
} 101
file.Close();102
return TRUE;103
}104

105

106

107
LPBYTE BMPSpliter::GetTheTile( int XNum, int YNum,int XPxCount, int YPxCount )108
{109
//根据参数计算要读取的区域110
//如果超越了原图的边界,用空白补齐;111
LPBYTE lpbody= NULL;112
int count = GetOneLineSize(XPxCount);113
count = count * YPxCount;114
lpbody = (LPBYTE) new char[count];115
FillMemory(lpbody,count,0xFF);116
int StartPos = GetOneLineSize(bmpInfoHeader.biWidth)*YPxCount*YNum + (bmpInfoHeader.biBitCount/8)*XPxCount*XNum;117
int OneLineOffset = GetTheLineOffset(XNum, XPxCount);118
int LineStartPos = 0;119
for (int i = 0; i < YPxCount ; i++)120
{121
LineStartPos = StartPos + GetOneLineSize(bmpInfoHeader.biWidth)*i;122
CopyMemory(&lpbody[GetOneLineSize(XPxCount)*i],&lpbmpBody[LineStartPos],OneLineOffset);123
} 124
return lpbody;125

126
}127

128
int BMPSpliter::GetTheTileSize( int XPxCount, int YPxCount )129
{130
//根据参数来计算该Tile的图像体的大小。131
int result = GetOneLineSize(XPxCount);132
result = result*YPxCount;133
return result;134
}135

136

137
int BMPSpliter::GetOneLineSize(int XPxCount)138
{139
int result = (((XPxCount*bmpInfoHeader.biBitCount)+31)>>5)<<2;140
return result;141
}142

143
int BMPSpliter::GetTheLineOffset(int XNum, int XPxCount)144
{145
int result = XPxCount*(bmpInfoHeader.biBitCount/8);146
int sourceBmpLengthPerLine = bmpInfoHeader.biWidth*(bmpInfoHeader.biBitCount/8);147
if( result*(XNum+1)>sourceBmpLengthPerLine)148
result = sourceBmpLengthPerLine - (result*XNum);149
return result;150
}151

152

153
void BMPSpliter::SetStartNumber(int startNumber)154
{155
StartNumber = startNumber;156
}157

158
void BMPSpliter::SetDestDirectory(CString destDir )159
{160
this->DestDirectory = destDir;161
CFileFind ff;162
if(!ff.FindFile(DestDirectory+"\\*.*"))163
CreateDirectory(DestDirectory+"\\",NULL); 164
}165

166
void BMPSpliter::SetSourceFileName(CString fileName)167
{168
SourceFileName = fileName;169
}170

171
BOOL BMPSpliter::ReadFile()172
{173
CFile file;174
file.Open(SourceFileName,CFile::modeRead);175
try176
{177
int counts = file.Read((LPVOID)&fileHeader,sizeof(BITMAPFILEHEADER));178
if (counts!=sizeof(BITMAPFILEHEADER))179
throw new CException;180
if(fileHeader.bfType != 0x4d42) 181
throw new CException;182
//文件头信息->位图信息->位图数据183
//bfOffBits为从文件开始到数据内容之间的距离184
int size = fileHeader.bfOffBits - sizeof(BITMAPFILEHEADER);185
//bmpInfoHeader = (LPBITMAPINFOHEADER) new char[size];186
// BITMAPINFOHEADER和颜色表187
counts = file.Read(&bmpInfoHeader, sizeof(BITMAPINFOHEADER));188
if (counts!=sizeof(BITMAPINFOHEADER))189
throw new CException;190
//如果为16位色或者更小,则无法处理191
if(bmpInfoHeader.biBitCount<=16)192
throw new CException;193
//如果图像是压缩的,则也无法处理194
if(bmpInfoHeader.biCompression !=BI_RGB)195
throw new CException;196
//读取图像内容197
file.Seek(fileHeader.bfOffBits,CFile::begin);198
lpbmpBody = (LPBYTE)new char[bmpInfoHeader.biSizeImage];199
counts = file.Read(lpbmpBody,bmpInfoHeader.biSizeImage);200
}201
catch (CException* e)202
{203
AfxMessageBox("Read File Error");204
return FALSE;205
}206
return TRUE;207
}208

一个简单例子:
1
BMPSpliter spliter;
2
spliter.ReadFile("map\\Source.bmp");
3
spliter.SetDestDirectory("splitResult");
4
spliter.SetStartNumber(16);
5
spliter.Split(256,256);
BMPSpliter spliter;2
spliter.ReadFile("map\\Source.bmp");3
spliter.SetDestDirectory("splitResult");4
spliter.SetStartNumber(16);5
spliter.Split(256,256);



浙公网安备 33010602011771号