关于ArcSDE Raster的一些资料可以参见合金枪头的关于ArcSDE影像数据管理的系列文章。

本文包括访问ArcSDE Raster数据的三个应用,代码只是片段抽取,但是已经包括了该功能的所有代码。

1、获取ArcSDE中Raster数据列表
1 struct SdeRasterTableInfo
2 {
3     char TableName[SE_QUALIFIED_TABLE_NAME];
4     char RasterColumnName[SE_MAX_COLUMN_LEN];
5 };

 1 bool GetSdeRasterCatalog(SE_CONNECTION pConnection, std::vector<SdeRasterTableInfo> &rasterTables)
 2 {
 3     SE_RASCOLINFO *pRasterColumnList = 0;
 4     if (SE_rastercolumn_get_info_list(pConnection, &pRasterColumnList, &lRasterColumnCount) != SE_SUCCESS)
 5         return false;
 6 
 7     for (int i = 0; i < lRasterColumnCount; i++)
 8     {
 9         long privileges = 0;
10         if (SE_rascolinfo_get_access (pRasterColumnList[i], &privileges) != SE_SUCCESS)
11             continue;
12 
13         if (!(privileges & SE_SELECT_PRIVILEGE))
14             continue;
15 
16         SdeRasterTableInfo rasterTableInfo;
17 
18         // Get the raster table name and column name.
19         if (SE_rascolinfo_get_raster_column (pRasterColumnList[i],
20             rasterTableInfo.TableName, rasterTableInfo.RasterColumnName) != SE_SUCCESS)
21             continue;
22         
23         rasterTables.push_back(rasterTableInfo);
24     }
25 
26     SE_rastercolumn_free_info_list (lRasterColumnCount, pRasterColumnList);
27     
28     return true;
29 }


2、获取指定Raster数据的元数据
 1 struct SdeRasterSpec
 2 {
 3     long   ImageWidth;
 4     long   ImageHeight;
 5     
 6     double OriginX;
 7     double OriginY;
 8     
 9     double MinX;
10     double MinY;
11     double MaxX;
12     double MaxY;
13 };

  1 LONG GetSdeRasterSpec(SE_CONNECTION pConnection, 
  2     const string& tableName, const string& rasterColumn, const string& where
  3     SdeRasterSpec &rasterSpec)
  4 {
  5     // Get raster column info.
  6     SE_RASCOLINFO rasColInfo = 0;
  7     LONG rc = SE_rascolinfo_create(&rasColInfo);
  8     if (rc != SE_SUCCESS)
  9         return rc;
 10 
 11     LONG rasterColumnId = 0;
 12 
 13     do
 14     {
 15         rc = SE_rastercolumn_get_info_by_name(pConnection, tableName.c_str(), rasterColumn.c_str(), rasColInfo);
 16         if (rc != SE_SUCCESS)
 17             break;
 18 
 19         // Get raster column ID.
 20         rc = SE_rascolinfo_get_id(rasColInfo, &rasterColumnId);
 21         if (rc != SE_SUCCESS)
 22             break;
 23     }
 24     while(0);
 25 
 26     SE_rascolinfo_free(rasColInfo);
 27 
 28     if (rc != SE_SUCCESS)
 29         return rc;
 30 
 31     // Get raster ID.
 32     LONG rasterId = -1;
 33     rc = FetchRasterID(pConnection, tableName, rasterColumn, where&rasterId);
 34     if (rasterId == -1)
 35         return rc;
 36 
 37     // Get raster info.
 38     SE_RASTERINFO rasterInfo = 0;
 39     rc = SE_rasterinfo_create(&rasterInfo);
 40     if (rc != SE_SUCCESS)
 41         return rc;
 42 
 43     rc = SE_raster_get_info_by_id(pConnection, rasterColumnId, rasterId, rasterInfo);
 44     if (rc != SE_SUCCESS)
 45     {
 46         SE_rasterinfo_free(rasterInfo);
 47         return rc;
 48     }
 49 
 50     // Get raster band info list.
 51     SE_RASBANDINFO *rasterBands = 0;
 52     LONG bandCount = 0;
 53     rc = SE_raster_get_bands(pConnection, rasterInfo, &rasterBands, &bandCount);
 54     if (rc != SE_SUCCESS)
 55     {
 56         SE_rasterinfo_free (rasterInfo);
 57         return rc;
 58     }
 59 
 60     SE_rasterinfo_free(rasterInfo);
 61 
 62     // Get the raster band size and origin.
 63     LFLOAT bandOriginX = 0.0, bandOriginY = 0.0;
 64     LONG bandWidth = 0, bandHeight = 0;
 65     SE_ENVELOPE rasterEnv;
 66     if (bandCount > 0)
 67     {
 68         rc = SE_rasbandinfo_get_tile_origin(rasterBands[0], &rasterSpec.OriginX, &rasterSpec.OriginY);
 69 
 70         if (rc == SE_SUCCESS)
 71             rc = SE_rasbandinfo_get_band_size (rasterBands[0], &rasterSpec.ImageWidth, &rasterSpec.ImageHeight);
 72 
 73         if (rc == SE_SUCCESS)
 74             rc = SE_rasbandinfo_get_extent (rasterBands[0], &rasterEnv);
 75     }
 76 
 77     SE_rasterband_free_info_list(bandCount, rasterBands);
 78 
 79     if (rc == SE_SUCCESS)
 80     {
 81         rasterSpec.MinX = rasterEvn.minx;
 82         rasterSpec.MinY = rasterEvn.miny;
 83         rasterSpec.MaxX = rasterEvn.maxx;
 84         rasterSpec.MaxY = rasterEvn.maxy;
 85     }
 86 
 87     return rc;
 88 }
 89 
 90 LONG FetchRasterID (SE_CONNECTION pConnection, const string& tableName, 
 91     const string& rasterColumn, const string& where, LONG *rasterId) 
 92 {
 93     *rasterId = -1;
 94 
 95     SE_STREAM stream = 0;
 96     LONG rc = SE_stream_create (pConnection, &stream);
 97     if (rc != SE_SUCCESS)
 98         return rc;
 99 
100     // Set up SQL statement.
101     CHAR sqlstmt[128];
102     if (where.empty())
103         sprintf (sqlstmt,"SELECT %s FROM %s", rasterColumn.c_str(), tableName.c_str());
104     else
105         sprintf (sqlstmt,"SELECT %s FROM %s WHERE %s", rasterColumn.c_str(), tableName.c_str(), where.c_str());
106 
107     do
108     {
109         rc = SE_stream_prepare_sql (stream, sqlstmt);
110         if (rc != SE_SUCCESS)
111             break;
112 
113         // Bind the rasterId variable to receive the output of the stream.
114         SHORT raster_ind= SE_IS_NULL_VALUE;
115         rc = SE_stream_bind_output_column (stream, 1, (void *)rasterId, &raster_ind);
116         if (rc != SE_SUCCESS)
117             break;
118 
119         // Execute the query.
120         rc = SE_stream_execute (stream);
121         if (rc != SE_SUCCESS)
122             break;
123 
124         // Fetch the result from the cursor.
125         rc = SE_stream_fetch (stream);
126         if (rc == SE_SUCCESS || rc == SE_FINISHED) 
127         {
128             // If the query sets the indicator to NULL.
129             if (raster_ind == SE_IS_NULL_VALUE) 
130                 *rasterId = -1;
131         }
132     }
133     while(0);
134 
135     SE_stream_free (stream);
136 
137     return rc;
138 }


3、读取指定范围的Raster数据,并输出为PNG格式
  1 #ifndef __SDERASTERCLIP_H__
  2 #define __SDERASTERCLIP_H__
  3 
  4 #include "sderaster.h"
  5 #include "png.h"                         // for libpng
  6 
  7 class CSdeRasterClip
  8 {
  9 public:
 10     CSdeRasterClip(int nClipWidth, int nClipHeight, int nSourceWidth, int nSourceHeight)
 11     {
 12         m_pBuffer = 0;
 13         
 14         m_nClipWidth = nClipWidth;
 15         m_nClipHeight = nClipHeight;
 16         m_nSourceWidth = nSourceWidth;
 17         m_nSourceHeight = nSourceHeight;
 18     }
 19 
 20     ~CSdeRasterClip()
 21     {
 22         delete[] m_pBuffer;
 23     }
 24 
 25     bool Clip(SE_CONNECTION pConnection, 
 26         const string& tableName, const string& rasterColumn, const string& where)
 27     {
 28         bool bSuccess = false;
 29 
 30         try
 31         {
 32             LONG rc = ClipImage(pConnection, tableName, rasterColumn, where);
 33             if (rc == SE_SUCCESS)
 34             {
 35                 unsigned char **pRow = (unsigned char **)m_pBuffer;
 36             
 37                 // Write image buffer to png stream.
 38                 return WritePNG (pRow, m_nImageWidth, m_nImageHeight, 8, PNG_COLOR_TYPE_RGB);
 39             }
 40         }
 41         catch (const char *msg)
 42         {
 43             //
 44         }
 45         catch ()
 46         {
 47             //
 48         }
 49 
 50         return false;
 51     }
 52 
 53 private:
 54 
 55     LONG ClipImage(CXrbStream &tStream, SE_CONNECTION pConnection, 
 56         const string& tableName, const string& rasterColumn, const string& where)
 57     {
 58         // Create the queryinfo structure
 59         SE_QUERYINFO queryinfo = 0;
 60         LONG rc = SE_queryinfo_create (&queryinfo);
 61         if (rc != SE_SUCCESS)
 62         {
 63             return rc;
 64         }
 65 
 66         do
 67         {
 68             // Set query tables.
 69             const CHAR *tables[1];
 70             tables[0]= tableName.c_str();
 71 
 72             rc = SE_queryinfo_set_tables (queryinfo, 1, tables, NULL); 
 73             if (rc != SE_SUCCESS)
 74                 break;
 75 
 76             // Set query columns.
 77             const CHAR *columns[1];
 78             columns[0= rasterColumn.c_str();
 79 
 80             rc = SE_queryinfo_set_columns (queryinfo, 1, columns); 
 81             if (rc != SE_SUCCESS)
 82                 break;
 83 
 84             // Set query where clause.
 85             if (!where.empty())
 86             {
 87                 rc = SE_queryinfo_set_where_clause(queryinfo, where.c_str());
 88                 if (rc != SE_SUCCESS)
 89                     break;
 90             }
 91         }
 92         while(0);
 93 
 94         if (rc != SE_SUCCESS)
 95         {
 96             SE_queryinfo_free (queryinfo);
 97             return rc;
 98         }
 99 
100         // Create query stream
101         SE_STREAM stream = 0;
102         rc = SE_stream_create (pConnection, &stream);
103         if (rc != SE_SUCCESS)
104         {
105             SE_queryinfo_free (queryinfo);
106             return rc;
107         }
108 
109         // initializes query stream using query info.
110         rc = SE_stream_query_with_info (stream, queryinfo);
111         if (rc != SE_SUCCESS)
112         {
113             SE_queryinfo_free (queryinfo);
114             SE_stream_free (stream);
115             return rc;
116         }
117 
118         SE_queryinfo_free (queryinfo);
119 
120         SE_RASTERATTR raster_attrib = 0;
121         rc = SE_rasterattr_create (&raster_attrib, FALSE);
122         if (rc != SE_SUCCESS)
123         {
124             SE_stream_free (stream);
125             return rc;
126         }
127 
128         // Bind the rasterId variable to receive the output of the stream.
129         SHORT raster_ind= SE_IS_NULL_VALUE;
130         rc = SE_stream_bind_output_column (stream, 1, raster_attrib, &raster_ind);
131         if (rc != SE_SUCCESS)
132         {
133             SE_stream_free (stream);
134             SE_rasterattr_free (raster_attrib);
135             return rc;
136         }
137 
138         // Execute the query.
139         rc = SE_stream_execute (stream);
140         if (SE_SUCCESS == rc) 
141         {
142             // Fetch each record of the business table //
143             rc = SE_stream_fetch (stream);
144 
145             if (SE_FINISHED != rc) 
146             { 
147                 if (raster_ind == SE_IS_NOT_NULL_VALUE)
148                 {
149                     rc = GetRasterData(pConnection, stream, raster_attrib);
150                 }
151             }
152         }
153 
154         SE_stream_free (stream);
155         SE_rasterattr_free (raster_attrib);
156 
157         return rc;
158     }
159 
160     LONG GetRasterData(SE_CONNECTION connection, SE_STREAM stream, SE_RASTERATTR raster_attrib)
161     {
162         // determine number of images in pyramid
163         BOOL bSkipLevel = TRUE;
164         LONG nPyramidSize = 0;
165         LONG rc = SE_rasterattr_get_max_level ( raster_attrib, &nPyramidSize, &bSkipLevel);
166         if (rc != SE_SUCCESS)
167             return rc;
168 
169         // determine which image should be used
170         int nLevel = GetPyramidLevel(nPyramidSize);
171 
172         SE_ENVELOPE raster_env;
173         LFLOAT dOffsetX = 0.0, dOffsetY = 0.0;
174 
175         rc = SE_rasterattr_get_extent_by_level (raster_attrib, &raster_env, &dOffsetX, 
176             &dOffsetY, nLevel);
177         if (rc != SE_SUCCESS)
178             return rc;
179 
180         rc = SE_rasterattr_get_tile_size (raster_attrib, &m_nTileWidth, &m_nTileHeight);
181         if (rc != SE_SUCCESS)
182             return rc;
183 
184         LONG nBandsCount = 0;
185         LONG nSourceImageWidth = 0;
186         LONG nSourceImageHeight = 0;
187         LONG nSourceImageOffsetX = 0;
188         LONG nSourceImageOffsetY = 0;
189         rc = SE_rasterattr_get_image_size_by_level(raster_attrib, 
190             &nSourceImageWidth, 
191             &nSourceImageHeight, 
192             &nSourceImageOffsetX,
193             &nSourceImageOffsetY,
194             &nBandsCount,
195             nLevel);
196         if (rc != SE_SUCCESS)
197             return rc;
198 
199         // calculate the pixel cell size in world coordinates
200         LFLOAT nCellSize = (raster_env.maxx - raster_env.minx) / (nSourceImageWidth - 1);
201 
202         LONG nPixelType;
203         rc = SE_rasterattr_get_pixel_type (raster_attrib, &nPixelType);
204         if (rc != SE_SUCCESS)
205             return rc;
206 
207         // Dot not support other pixel type now.
208         if (nPixelType != SE_PIXEL_TYPE_8BIT_U) 
209             return SE_FAILURE;
210 
211         // compute the real world coordinate width and height
212         LFLOAT coord_tile_width = nCellSize * m_nTileWidth;
213         LFLOAT coord_tile_height = nCellSize * m_nTileHeight;
214 
215         LONG pixels_per_tile = m_nTileWidth * m_nTileHeight;
216 
217         // The testing code only request the full image.
218         LONG minx = raster_env.minx;
219         LONG maxx = raster_env.maxx;
220         LONG miny = raster_env.miny;
221         LONG maxy = raster_env.maxy;
222 
223         LONG relminx = (LONG) ((minx - (raster_env.minx - dOffsetX)) / coord_tile_width); 
224         LONG relmaxx = (LONG) ((maxx - (raster_env.minx - dOffsetX)) / coord_tile_width);
225         LONG relminy = (LONG) (((raster_env.maxy + dOffsetY) - maxy) / coord_tile_height);
226         LONG relmaxy = (LONG) (((raster_env.maxy + dOffsetY) - miny) / coord_tile_height);
227 
228         LONG nNumTilesX = relmaxx - relminx + 1;
229         LONG nNumTilesY = relmaxy - relminy + 1;
230 
231         m_nImageWidth = nNumTilesX * m_nTileWidth;
232         m_nImageHeight = nNumTilesY * m_nTileHeight;
233         
234         rc = SE_rasterattr_get_num_bands (raster_attrib, &nBandsCount);
235         if (rc != SE_SUCCESS)
236             return rc;
237 
238         //if (nBandsCount != 1 && nBandsCount != 3)
239         //    return;
240 
241         
242         SE_RASCONSTRAINT rasconstraint = 0;
243         rc = SE_rasconstraint_create (&rasconstraint);
244         if (rc != SE_SUCCESS)
245             return rc;
246 
247         SE_RASTILEINFO rastile_info = 0;
248         rc = SE_rastileinfo_create (&rastile_info);
249         if (rc != SE_SUCCESS)
250         {
251             SE_rasconstraint_free (rasconstraint);
252             return rc;
253         }
254 
255         do
256         {
257             rc =  SE_rasconstraint_set_envelope (rasconstraint, relminx, relminy, relmaxx, relmaxy);
258             if (rc != SE_SUCCESS)
259                 break;
260 
261             LONG aBandArray[3= {1,2,3};
262 
263             rc = SE_rasconstraint_set_bands ( rasconstraint, nBandsCount, aBandArray);
264             if (rc != SE_SUCCESS)
265                 break;
266 
267             rc = SE_rasconstraint_set_interleave (rasconstraint, SE_RASTER_INTERLEAVE_BSQ);
268             if (rc != SE_SUCCESS)
269                 break;
270 
271             rc = SE_rasconstraint_set_level (rasconstraint, nLevel);
272             if (rc != SE_SUCCESS)
273                 break;
274 
275             rc = SE_stream_query_raster_tile (stream, rasconstraint);
276             if (rc != SE_SUCCESS)
277                 break;
278         }
279         while(0);
280 
281         if (rc != SE_SUCCESS)
282         {
283             SE_rasconstraint_free (rasconstraint);
284             SE_rastileinfo_free (rastile_info);
285             return rc;
286         }
287 
288         int nBitesPerPixel = nPixelType >> 3;
289 
290         int nImageBytesPerPixel = 3;
291         // bytes across source tile
292         int nTileByteWidth = (m_nTileWidth * nBitesPerPixel + 7/ 8;//m_nTileWidth;
293         // bytes across tile when copied to output image buffer
294         int nBufferTileByteWidth = m_nTileWidth * nImageBytesPerPixel;
295         // width of output buffer in bytes
296         int nBufferByteWidth = nBufferTileByteWidth * nNumTilesX;
297 
298         // bytes in output buffer for complete row of tiles
299         int nBufferTileByteRow = nBufferByteWidth * m_nTileHeight;
300 
301         if (m_pBuffer != 0) delete[] m_pBuffer;
302 
303         m_pBuffer = new unsigned char[(m_nImageHeight * sizeof(char*)) + (nBufferTileByteRow * nNumTilesY)];
304 
305         // create pointer to actual image data
306         unsigned char *pBufferImage = m_pBuffer + (m_nImageHeight * sizeof(char*));
307 
308         // create pointer to tile buffer
309         unsigned char *pSingleTile = NULL;
310 
311         LONG length = 0;
312         LONG rasterband_id = 0;
313         LONG row = 0;
314         LONG column = 0;
315 
316         while (rc == SE_SUCCESS)
317         {
318             rc = SE_stream_get_raster_tile (stream, rastile_info);
319             if (rc != SE_SUCCESS)
320                 break;
321 
322             rc = SE_rastileinfo_get_band_id (rastile_info, &rasterband_id);
323             if (rc != SE_SUCCESS)
324                 break;
325 
326             rc = SE_rastileinfo_get_rowcol (rastile_info, &row, &column);
327             if (rc != SE_SUCCESS)
328                 break;
329 
330             rc = SE_rastileinfo_get_pixel_data (rastile_info, (void**)&pSingleTile, &length);
331             if (rc != SE_SUCCESS)
332                 break;
333 
334             unsigned char *pDst = pBufferImage + row * nBufferTileByteRow + column * nBufferTileByteWidth;
335             unsigned char *pSrc = pSingleTile;
336             for (int k = 0; k < m_nTileHeight; k++)
337             {
338                 ExpandBits(pDst, pSrc, pSrc + nTileByteWidth, rasterband_id % 3);
339 
340                 pSrc += nTileByteWidth;
341                 pDst += nBufferByteWidth;
342             }
343         }
344 
345         SE_rasconstraint_free (rasconstraint);
346         SE_rastileinfo_free (rastile_info);
347 
348         if (rc == SE_FINISHED)
349             rc = SE_SUCCESS;
350 
351         // Create array of row pointers at beginning of buffer for png write.
352         if (rc == SE_SUCCESS)
353         {
354             unsigned char **pCurPtr = (unsigned char **)m_pBuffer;
355             unsigned char **pEndPtr = pCurPtr + m_nImageHeight;
356             unsigned char *pCurSrc = pBufferImage;
357 
358             while (pCurPtr < pEndPtr)
359             {
360                 *pCurPtr = pCurSrc;
361                 pCurSrc += nBufferByteWidth;
362                 pCurPtr++;
363             }
364         }
365 
366         return rc;
367     }
368 
369     void ExpandBits(unsigned char *pDst, unsigned char *pSrc, unsigned char *pEndSrc, int nBits)
370     {
371         unsigned char *pCurSrc = pSrc;
372         unsigned char *pCurDst = pDst;
373         unsigned char pixel;
374 
375         switch (nBits)
376         {
377         case 1//r
378             for (; pCurSrc<pEndSrc; pCurSrc++)
379             {
380                 pixel = *pCurSrc;
381 
382                 *pCurDst = pixel & 0xff;
383                 pCurDst++;
384                 *pCurDst = 0;
385                 pCurDst++;
386                 *pCurDst = 0;
387                 pCurDst++;
388             }
389             break;
390 
391         case 2//g
392             for (; pCurSrc<pEndSrc; pCurSrc++)
393             {
394                 pixel = *pCurSrc;
395                 pCurDst++;
396                 *pCurDst = pixel & 0xff;
397                 pCurDst++;
398                 *pCurDst = 0;
399                 pCurDst++;
400             }
401             break;
402 
403         case 3//b
404             for (; pCurSrc<pEndSrc; pCurSrc++)
405             {
406                 pixel = *pCurSrc;
407                 pCurDst++;
408                 pCurDst++;
409                 *pCurDst = pixel & 0xff;
410                 pCurDst++;
411             }
412             break;
413 
414         default:
415             break;
416         }
417     }
418 
419     /**//**
420      * Get the zero-based index to the pyramid image that best fits the dimensions
421      * @return index in the pyramid
422      */
423     int GetPyramidLevel(int nMaxLevel)
424     {
425         int nWidthRatio = m_nSourceWidth/m_nClipWidth;
426         int nHeightRatio = m_nSourceHeight/m_nClipHeight;
427         int nRatio = (nWidthRatio < nHeightRatio)? nWidthRatio : nHeightRatio;
428         int nLevel = 0;
429         while (nRatio >>= 1) nLevel++;
430         if (nLevel > nMaxLevel) return nMaxLevel;
431         return nLevel;
432     }
433 
434     static void stdio_write_func (png_structp png, png_bytep data, png_size_t size)
435     {
436         FILE *fp;
437 
438         fp = (FILE *)png_get_io_ptr (png);
439         while (size) {
440         size_t ret = fwrite (data, 1, size, fp);
441         size -= ret;
442         data += ret;
443         if (size && ferror (fp))
444             png_error(png, "Write Error");
445         }
446     }
447 
448     bool WritePNG( const char *outputFile, unsigned char **pRows, 
449         int nWidth, int nHeight, int nBitDepth, 
450         int nColorType, int nFilterType = PNG_FILTER_TYPE_DEFAULT) 
451     {
452         png_structp   pPngPtr = 0;
453         png_infop     pInfoPtr = 0;
454 
455         FILE *fp = 0;
456 
457         fp = fopen (outputFile, "wb");
458         if (fp == 0)
459             return false;
460 
461 
462         pPngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, 00);
463         if (pPngPtr)
464         {
465             pInfoPtr = png_create_info_struct(pPngPtr);
466             if (pInfoPtr)
467             {
468                 png_set_IHDR(pPngPtr, pInfoPtr, nWidth, nHeight,
469                         nBitDepth, nColorType, PNG_INTERLACE_NONE,
470                         PNG_COMPRESSION_TYPE_DEFAULT, nFilterType);
471 
472                 // set up write functions
473                 png_set_write_fn(pPngPtr, fp, stdio_write_func, NULL);
474 
475                 // write header
476                 png_write_info(pPngPtr, pInfoPtr);
477 
478                 png_color_16 white;
479                 white.red = 0xff;
480                 white.blue = 0xff;
481                 white.green = 0xff;
482 
483                 png_set_bKGD (pPngPtr, pInfoPtr, &white);
484 
485                 // write image
486                 png_write_image(pPngPtr, pRows);
487 
488                 // finish write
489                 png_write_end(pPngPtr, 0);
490 
491                 // destroy structures
492                 png_destroy_write_struct(&pPngPtr, &pInfoPtr);
493 
494                 fclose (fp);
495                 return true;
496             }
497             else
498             {
499                 png_destroy_write_struct(&pPngPtr, &pInfoPtr);
500                 fclose (fp);
501 
502             }
503         }
504         return false;
505     }
506 
507     /**//** Buffer for image data. */
508     unsigned char *m_pBuffer;
509 
510     LONG m_nTileWidth;
511     LONG m_nTileHeight;
512     
513     int m_nImageWidth;
514     int m_nImageHeight;
515 
516     int m_nClipWidth;
517     int m_nClipHeight;
518     int m_nSourceWidth;
519     int m_nSourceHeight;
520 };
521 
522 #endif //__SDERASTERCLIP_H__


:本来这篇本章很早就写了,但是一直没有时间来总结一下,现在开始着手三维GIS方面的开发,看来以后一段时间将更加忙,也没有时间来更新Blog了,所以干脆将这篇草稿直接发布了,也许对一些有需要的朋友所有帮助。