1 : /******************************************************************************
2 : * $Id: blxdataset.cpp 17664 2009-09-21 21:16:45Z rouault $
3 : *
4 : * Project: BLX Driver
5 : * Purpose: GDAL BLX support.
6 : * Author: Henrik Johansson, henrik@johome.net
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2006, Henrik Johansson <henrik@johome.net>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ******************************************************************************
29 : *
30 : */
31 :
32 : #include "gdal_pam.h"
33 : #include "cpl_string.h"
34 :
35 : CPL_CVSID("$Id: blxdataset.cpp 17664 2009-09-21 21:16:45Z rouault $");
36 :
37 : CPL_C_START
38 : #include <blx.h>
39 : CPL_C_END
40 :
41 : CPL_C_START
42 : void GDALRegister_BLX(void);
43 : CPL_C_END
44 :
45 : class BLXDataset : public GDALDataset
46 : {
47 : friend class BLXRasterBand;
48 :
49 : CPLErr GetGeoTransform( double * padfTransform );
50 : const char *GetProjectionRef();
51 :
52 : blxcontext_t *blxcontext;
53 :
54 : int nOverviewCount;
55 : int bIsOverview;
56 : BLXDataset *papoOverviewDS[BLX_OVERVIEWLEVELS];
57 :
58 : public:
59 : BLXDataset();
60 : ~BLXDataset();
61 :
62 : static GDALDataset *Open( GDALOpenInfo * );
63 : };
64 :
65 : class BLXRasterBand : public GDALRasterBand
66 110 : {
67 : int overviewLevel;
68 : public:
69 : BLXRasterBand( BLXDataset *, int, int overviewLevel=0 );
70 :
71 : virtual double GetNoDataValue( int *pbSuccess = NULL );
72 : virtual GDALColorInterp GetColorInterpretation(void);
73 : virtual int GetOverviewCount();
74 : virtual GDALRasterBand *GetOverview( int );
75 :
76 : virtual CPLErr IReadBlock( int, int, void * );
77 : };
78 :
79 8432 : GDALDataset *BLXDataset::Open( GDALOpenInfo * poOpenInfo )
80 :
81 : {
82 : // --------------------------------------------------------------------
83 : // First that the header looks like a BLX header
84 : // --------------------------------------------------------------------
85 8432 : if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 102 )
86 8326 : return NULL;
87 :
88 106 : if(!blx_checkheader((char *)poOpenInfo->pabyHeader))
89 95 : return NULL;
90 :
91 : // --------------------------------------------------------------------
92 : // Create a corresponding GDALDataset.
93 : // --------------------------------------------------------------------
94 : BLXDataset *poDS;
95 :
96 11 : poDS = new BLXDataset();
97 :
98 : // --------------------------------------------------------------------
99 : // Open BLX file
100 : // --------------------------------------------------------------------
101 11 : poDS->blxcontext = blx_create_context();
102 11 : blxopen(poDS->blxcontext, poOpenInfo->pszFilename, "rb");
103 :
104 11 : if(poDS->blxcontext==NULL)
105 0 : return NULL;
106 :
107 11 : if ((poDS->blxcontext->cell_xsize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0 ||
108 : (poDS->blxcontext->cell_ysize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0)
109 : {
110 0 : delete poDS;
111 0 : return NULL;
112 : }
113 :
114 : // Update dataset header from BLX context
115 11 : poDS->nRasterXSize = poDS->blxcontext->xsize;
116 11 : poDS->nRasterYSize = poDS->blxcontext->ysize;
117 :
118 : // --------------------------------------------------------------------
119 : // Create band information objects.
120 : // --------------------------------------------------------------------
121 11 : poDS->nBands = 1;
122 11 : poDS->SetBand( 1, new BLXRasterBand( poDS, 1 ));
123 :
124 : // Create overview bands
125 11 : poDS->nOverviewCount = BLX_OVERVIEWLEVELS;
126 110 : for(int i=0; i < poDS->nOverviewCount; i++) {
127 44 : poDS->papoOverviewDS[i] = new BLXDataset();
128 44 : poDS->papoOverviewDS[i]->blxcontext = poDS->blxcontext;
129 44 : poDS->papoOverviewDS[i]->bIsOverview = TRUE;
130 44 : poDS->papoOverviewDS[i]->nRasterXSize = poDS->nRasterXSize >> (i+1);
131 44 : poDS->papoOverviewDS[i]->nRasterYSize = poDS->nRasterYSize >> (i+1);
132 44 : poDS->nBands = 1;
133 88 : poDS->papoOverviewDS[i]->SetBand(1, new BLXRasterBand( poDS->papoOverviewDS[i], 1, i+1));
134 : }
135 :
136 : /* -------------------------------------------------------------------- */
137 : /* Confirm the requested access is supported. */
138 : /* -------------------------------------------------------------------- */
139 11 : if( poOpenInfo->eAccess == GA_Update )
140 : {
141 0 : delete poDS;
142 : CPLError( CE_Failure, CPLE_NotSupported,
143 : "The BLX driver does not support update access to existing"
144 0 : " datasets.\n" );
145 0 : return NULL;
146 : }
147 :
148 11 : return( poDS );
149 : }
150 :
151 55 : BLXDataset::BLXDataset() {
152 55 : blxcontext = NULL;
153 55 : bIsOverview = FALSE;
154 55 : nOverviewCount = 0;
155 :
156 55 : for(int i=0; i < nOverviewCount; i++)
157 0 : papoOverviewDS[i]=NULL;
158 55 : }
159 :
160 110 : BLXDataset::~BLXDataset() {
161 55 : if(!bIsOverview) {
162 11 : if(blxcontext) {
163 11 : blxclose(blxcontext);
164 11 : blx_free_context(blxcontext);
165 : }
166 55 : for(int i=0; i < nOverviewCount; i++)
167 44 : if(papoOverviewDS[i])
168 44 : delete papoOverviewDS[i];
169 : }
170 110 : }
171 :
172 :
173 8 : CPLErr BLXDataset::GetGeoTransform( double * padfTransform )
174 :
175 : {
176 8 : padfTransform[0] = blxcontext->lon;
177 8 : padfTransform[1] = blxcontext->pixelsize_lon;
178 8 : padfTransform[2] = 0.0;
179 8 : padfTransform[3] = blxcontext->lat;
180 8 : padfTransform[4] = 0.0;
181 8 : padfTransform[5] = blxcontext->pixelsize_lat;
182 :
183 8 : return CE_None;
184 : }
185 :
186 6 : const char *BLXDataset::GetProjectionRef()
187 : {
188 6 : return( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]]" );
189 : }
190 :
191 55 : BLXRasterBand::BLXRasterBand( BLXDataset *poDS, int nBand, int overviewLevel )
192 :
193 : {
194 55 : BLXDataset *poGDS = (BLXDataset *) poDS;
195 :
196 55 : this->poDS = poDS;
197 55 : this->nBand = nBand;
198 55 : this->overviewLevel = overviewLevel;
199 :
200 55 : eDataType = GDT_Int16;
201 :
202 55 : nBlockXSize = poGDS->blxcontext->cell_xsize >> overviewLevel;
203 55 : nBlockYSize = poGDS->blxcontext->cell_ysize >> overviewLevel;
204 55 : }
205 :
206 1 : int BLXRasterBand::GetOverviewCount()
207 : {
208 1 : BLXDataset *poGDS = (BLXDataset *) poDS;
209 :
210 1 : return poGDS->nOverviewCount;
211 : }
212 :
213 4 : GDALRasterBand *BLXRasterBand::GetOverview( int i )
214 : {
215 4 : BLXDataset *poGDS = (BLXDataset *) poDS;
216 :
217 4 : if( i < 0 || i >= poGDS->nOverviewCount )
218 0 : return NULL;
219 : else
220 4 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
221 : }
222 :
223 192 : CPLErr BLXRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
224 : void * pImage )
225 :
226 : {
227 192 : BLXDataset *poGDS = (BLXDataset *) poDS;
228 :
229 192 : if(blx_readcell(poGDS->blxcontext, nBlockYOff, nBlockXOff, (short *)pImage, nBlockXSize*nBlockYSize*2, overviewLevel) == NULL) {
230 : CPLError(CE_Failure, CPLE_AppDefined,
231 0 : "Failed to read BLX cell");
232 0 : return CE_Failure;
233 : }
234 :
235 192 : return CE_None;
236 : }
237 :
238 6 : double BLXRasterBand::GetNoDataValue( int * pbSuccess )
239 : {
240 6 : if (pbSuccess)
241 6 : *pbSuccess = TRUE;
242 6 : return BLX_UNDEF;
243 : }
244 :
245 0 : GDALColorInterp BLXRasterBand::GetColorInterpretation(void) {
246 0 : return GCI_GrayIndex;
247 : }
248 :
249 : /* TODO: check if georeference is the same as for BLX files, WGS84
250 : */
251 : static GDALDataset *
252 18 : BLXCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
253 : int bStrict, char ** papszOptions,
254 : GDALProgressFunc pfnProgress, void * pProgressData )
255 :
256 : {
257 18 : int nBands = poSrcDS->GetRasterCount();
258 18 : int nXSize = poSrcDS->GetRasterXSize();
259 18 : int nYSize = poSrcDS->GetRasterYSize();
260 :
261 18 : int zscale = 1;
262 18 : int fillundef = 1, fillundefval = 0;
263 18 : int endian = LITTLEENDIAN;
264 :
265 : // --------------------------------------------------------------------
266 : // Some rudimentary checks
267 : // --------------------------------------------------------------------
268 18 : if( nBands != 1 )
269 : {
270 : CPLError( CE_Failure, CPLE_NotSupported,
271 : "BLX driver doesn't support %d bands. Must be 1 (grey) ",
272 5 : nBands );
273 5 : return NULL;
274 : }
275 :
276 13 : if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int16 && bStrict )
277 : {
278 : CPLError( CE_Failure, CPLE_NotSupported,
279 : "BLX driver doesn't support data type %s. "
280 : "Only 16 bit byte bands supported.\n",
281 : GDALGetDataTypeName(
282 10 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
283 :
284 10 : return NULL;
285 : }
286 :
287 3 : if( (nXSize % 128 != 0) || (nYSize % 128 != 0) ) {
288 : CPLError( CE_Failure, CPLE_NotSupported,
289 1 : "BLX driver doesn't support dimensions that are not a multiple of 128.\n");
290 :
291 1 : return NULL;
292 : }
293 :
294 : // --------------------------------------------------------------------
295 : // What options has the user selected?
296 : // --------------------------------------------------------------------
297 2 : if( CSLFetchNameValue(papszOptions,"ZSCALE") != NULL ) {
298 0 : zscale = atoi(CSLFetchNameValue(papszOptions,"ZSCALE"));
299 0 : if( zscale < 1 ) {
300 : CPLError( CE_Failure, CPLE_IllegalArg,
301 : "ZSCALE=%s is not a legal value in the range >= 1.",
302 0 : CSLFetchNameValue(papszOptions,"ZSCALE") );
303 0 : return NULL;
304 : }
305 : }
306 :
307 2 : if( CSLFetchNameValue(papszOptions,"FILLUNDEF") != NULL
308 : && EQUAL(CSLFetchNameValue(papszOptions,"FILLUNDEF"),"NO") )
309 0 : fillundef = 0;
310 : else
311 2 : fillundef = 1;
312 :
313 2 : if( CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") != NULL ) {
314 0 : fillundefval = atoi(CSLFetchNameValue(papszOptions,"FILLUNDEFVAL"));
315 0 : if( (fillundefval < -32768) || (fillundefval > 32767) ) {
316 : CPLError( CE_Failure, CPLE_IllegalArg,
317 : "FILLUNDEFVAL=%s is not a legal value in the range -32768, 32767.",
318 0 : CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") );
319 0 : return NULL;
320 : }
321 : }
322 2 : if( CSLFetchNameValue(papszOptions,"BIGENDIAN") != NULL
323 : && !EQUAL(CSLFetchNameValue(papszOptions,"BIGENDIAN"),"NO") )
324 1 : endian = BIGENDIAN;
325 :
326 :
327 :
328 : // --------------------------------------------------------------------
329 : // Create the dataset.
330 : // --------------------------------------------------------------------
331 : blxcontext_t *ctx;
332 :
333 : // Create a BLX context
334 2 : ctx = blx_create_context();
335 :
336 : // Setup BLX parameters
337 2 : ctx->cell_rows = nYSize / ctx->cell_ysize;
338 2 : ctx->cell_cols = nXSize / ctx->cell_xsize;
339 2 : ctx->zscale = zscale;
340 2 : ctx->fillundef = fillundef;
341 2 : ctx->fillundefval = fillundefval;
342 2 : ctx->endian = endian;
343 :
344 2 : if(blxopen(ctx, pszFilename, "wb")) {
345 : CPLError( CE_Failure, CPLE_OpenFailed,
346 : "Unable to create blx file %s.\n",
347 0 : pszFilename );
348 0 : return NULL;
349 : }
350 :
351 : // --------------------------------------------------------------------
352 : // Loop over image, copying image data.
353 : // --------------------------------------------------------------------
354 : GInt16 *pabyTile;
355 2 : CPLErr eErr=CE_None;
356 :
357 2 : pabyTile = (GInt16 *) CPLMalloc( sizeof(GInt16)*ctx->cell_xsize*ctx->cell_ysize );
358 :
359 2 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
360 0 : eErr = CE_Failure;
361 :
362 10 : for(int i=0; (i < ctx->cell_rows) && (eErr == CE_None); i++)
363 40 : for(int j=0; j < ctx->cell_cols; j++) {
364 : blxdata *celldata;
365 32 : GDALRasterBand * poBand = poSrcDS->GetRasterBand( 1 );
366 : eErr = poBand->RasterIO( GF_Read, j*ctx->cell_xsize, i*ctx->cell_ysize,
367 : ctx->cell_xsize, ctx->cell_ysize,
368 : pabyTile, ctx->cell_xsize, ctx->cell_ysize, GDT_Int16,
369 32 : 0, 0 );
370 32 : if(eErr >= CE_Failure)
371 0 : break;
372 32 : celldata = pabyTile;
373 32 : if (blx_writecell(ctx, celldata, i, j) != 0)
374 : {
375 0 : eErr = CE_Failure;
376 0 : break;
377 : }
378 :
379 32 : if ( ! pfnProgress( 1.0 * (i * ctx->cell_cols + j) / (ctx->cell_rows * ctx->cell_cols), NULL, pProgressData ))
380 : {
381 0 : eErr = CE_Failure;
382 0 : break;
383 : }
384 : }
385 :
386 2 : pfnProgress( 1.0, NULL, pProgressData );
387 :
388 2 : CPLFree( pabyTile );
389 :
390 : double adfGeoTransform[6];
391 2 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
392 : {
393 2 : ctx->lon = adfGeoTransform[0];
394 2 : ctx->lat = adfGeoTransform[3];
395 2 : ctx->pixelsize_lon = adfGeoTransform[1];
396 2 : ctx->pixelsize_lat = adfGeoTransform[5];
397 : }
398 :
399 2 : blxclose(ctx);
400 2 : blx_free_context(ctx);
401 :
402 2 : if (eErr == CE_None)
403 2 : return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
404 : else
405 0 : return NULL;
406 : }
407 :
408 :
409 338 : void GDALRegister_BLX()
410 :
411 : {
412 : GDALDriver *poDriver;
413 :
414 338 : if( GDALGetDriverByName( "BLX" ) == NULL )
415 : {
416 336 : poDriver = new GDALDriver();
417 :
418 336 : poDriver->SetDescription( "BLX" );
419 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
420 336 : "Magellan topo (.blx)" );
421 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
422 336 : "frmt_various.html#BLX" );
423 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "blx" );
424 :
425 336 : poDriver->pfnOpen = BLXDataset::Open;
426 336 : poDriver->pfnCreateCopy = BLXCreateCopy;
427 :
428 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
429 : }
430 338 : }
431 :
|