最近由于工作需要,要实现一个简单的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
11class BMPSpliter : public CObject
12{
13public:
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();
25private:
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
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
11class BMPSpliter : public CObject
12{
13public:
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();
25private:
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
17static char THIS_FILE[]=__FILE__;
18#define new DEBUG_NEW
19#endif
20
21//////////////////////////////////////////////////////////////////////
22// Construction/Destruction
23//////////////////////////////////////////////////////////////////////
24
25BMPSpliter::BMPSpliter()
26{
27 SetStartNumber(0);
28 lpbmpBody = NULL;
29 SetDestDirectory("map");
30 SetSourceFileName("");
31}
32
33BMPSpliter::~BMPSpliter()
34{
35 if(lpbmpBody!=NULL)
36 delete [] lpbmpBody;
37 lpbmpBody =NULL;
38}
39
40BOOL BMPSpliter::ReadFile(CString fileName)
41{
42 SetSourceFileName(fileName);
43 return ReadFile();
44}
45
46BOOL 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
77BOOL 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
107LPBYTE 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
128int BMPSpliter::GetTheTileSize( int XPxCount, int YPxCount )
129{
130 //根据参数来计算该Tile的图像体的大小。
131 int result = GetOneLineSize(XPxCount);
132 result = result*YPxCount;
133 return result;
134}
135
136
137int BMPSpliter::GetOneLineSize(int XPxCount)
138{
139 int result = (((XPxCount*bmpInfoHeader.biBitCount)+31)>>5)<<2;
140 return result;
141}
142
143int 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
153void BMPSpliter::SetStartNumber(int startNumber)
154{
155 StartNumber = startNumber;
156}
157
158void BMPSpliter::SetDestDirectory(CString destDir )
159{
160 this->DestDirectory = destDir;
161 CFileFind ff;
162 if(!ff.FindFile(DestDirectory+"\\*.*"))
163 CreateDirectory(DestDirectory+"\\",NULL);
164}
165
166void BMPSpliter::SetSourceFileName(CString fileName)
167{
168 SourceFileName = fileName;
169}
170
171BOOL 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
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
17static char THIS_FILE[]=__FILE__;
18#define new DEBUG_NEW
19#endif
20
21//////////////////////////////////////////////////////////////////////
22// Construction/Destruction
23//////////////////////////////////////////////////////////////////////
24
25BMPSpliter::BMPSpliter()
26{
27 SetStartNumber(0);
28 lpbmpBody = NULL;
29 SetDestDirectory("map");
30 SetSourceFileName("");
31}
32
33BMPSpliter::~BMPSpliter()
34{
35 if(lpbmpBody!=NULL)
36 delete [] lpbmpBody;
37 lpbmpBody =NULL;
38}
39
40BOOL BMPSpliter::ReadFile(CString fileName)
41{
42 SetSourceFileName(fileName);
43 return ReadFile();
44}
45
46BOOL 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
77BOOL 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
107LPBYTE 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
128int BMPSpliter::GetTheTileSize( int XPxCount, int YPxCount )
129{
130 //根据参数来计算该Tile的图像体的大小。
131 int result = GetOneLineSize(XPxCount);
132 result = result*YPxCount;
133 return result;
134}
135
136
137int BMPSpliter::GetOneLineSize(int XPxCount)
138{
139 int result = (((XPxCount*bmpInfoHeader.biBitCount)+31)>>5)<<2;
140 return result;
141}
142
143int 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
153void BMPSpliter::SetStartNumber(int startNumber)
154{
155 StartNumber = startNumber;
156}
157
158void BMPSpliter::SetDestDirectory(CString destDir )
159{
160 this->DestDirectory = destDir;
161 CFileFind ff;
162 if(!ff.FindFile(DestDirectory+"\\*.*"))
163 CreateDirectory(DestDirectory+"\\",NULL);
164}
165
166void BMPSpliter::SetSourceFileName(CString fileName)
167{
168 SourceFileName = fileName;
169}
170
171BOOL 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
一个简单例子:
1 BMPSpliter spliter;
2 spliter.ReadFile("map\\Source.bmp");
3 spliter.SetDestDirectory("splitResult");
4 spliter.SetStartNumber(16);
5 spliter.Split(256,256);
2 spliter.ReadFile("map\\Source.bmp");
3 spliter.SetDestDirectory("splitResult");
4 spliter.SetStartNumber(16);
5 spliter.Split(256,256);