将位图分块

最近由于工作需要,要实现一个简单的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

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


一个简单例子:
1    BMPSpliter spliter;
2    spliter.ReadFile("map\\Source.bmp");
3    spliter.SetDestDirectory("splitResult");
4    spliter.SetStartNumber(16);
5    spliter.Split(256,256);
原文地址:https://www.cnblogs.com/strinkbug/p/651212.html