1 : /******************************************************************************
2 : * $Id: argdataset.cpp 24855 2012-08-25 21:12:55Z rouault $
3 : *
4 : * Project: Azavea Raster Grid format driver.
5 : * Purpose: Implements support for reading and writing Azavea Raster Grid
6 : * format.
7 : * Author: David Zwarg <dzwarg@azavea.com>
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2012, David Zwarg <dzwarg@azavea.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "rawdataset.h"
32 : #include "cpl_string.h"
33 : #include "jsonc/json.h"
34 : #include "jsonc/json_util.h"
35 : #include <ogr_spatialref.h>
36 :
37 : CPL_CVSID("$Id: argdataset.cpp 24855 2012-08-25 21:12:55Z rouault $");
38 :
39 : #define MAX_FILENAME_LEN 4096
40 :
41 : #ifndef NAN
42 : # ifdef HUGE_VAL
43 : # define NAN (HUGE_VAL * 0.0)
44 : # else
45 :
46 : static float CPLNaN(void)
47 : {
48 : float fNan;
49 : int nNan = 0x7FC00000;
50 : memcpy(&fNan, &nNan, 4);
51 : return fNan;
52 : }
53 :
54 : # define NAN CPLNaN()
55 : # endif
56 : #endif
57 :
58 : /************************************************************************/
59 : /* ==================================================================== */
60 : /* ARGDataset */
61 : /* ==================================================================== */
62 : /************************************************************************/
63 :
64 : class ARGDataset : public RawDataset
65 : {
66 : VSILFILE *fpImage; // image data file.
67 :
68 : double adfGeoTransform[6];
69 : char * pszFilename;
70 :
71 : public:
72 : ARGDataset();
73 : ~ARGDataset();
74 :
75 : CPLErr GetGeoTransform( double * padfTransform );
76 :
77 : static int Identify( GDALOpenInfo * );
78 : static GDALDataset *Open( GDALOpenInfo * );
79 : static GDALDataset *CreateCopy( const char *, GDALDataset *, int,
80 : char **, GDALProgressFunc, void *);
81 : virtual char ** GetFileList(void);
82 : };
83 :
84 : /************************************************************************/
85 : /* ARGDataset() */
86 : /************************************************************************/
87 :
88 48 : ARGDataset::ARGDataset()
89 : {
90 48 : adfGeoTransform[0] = 0.0;
91 48 : adfGeoTransform[1] = 1.0;
92 48 : adfGeoTransform[2] = 0.0;
93 48 : adfGeoTransform[3] = 0.0;
94 48 : adfGeoTransform[4] = 0.0;
95 48 : adfGeoTransform[5] = 1.0;
96 48 : fpImage = NULL;
97 48 : }
98 :
99 : /************************************************************************/
100 : /* ~ARGDataset() */
101 : /************************************************************************/
102 :
103 48 : ARGDataset::~ARGDataset()
104 :
105 : {
106 48 : CPLFree(pszFilename);
107 :
108 48 : FlushCache();
109 48 : if( fpImage != NULL )
110 46 : VSIFCloseL( fpImage );
111 48 : }
112 :
113 : /************************************************************************/
114 : /* GetGeoTransform() */
115 : /************************************************************************/
116 :
117 25 : CPLErr ARGDataset::GetGeoTransform( double * padfTransform )
118 :
119 : {
120 25 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
121 :
122 25 : return CE_None;
123 : }
124 :
125 : /************************************************************************/
126 : /* GetJsonFilename() */
127 : /************************************************************************/
128 141 : CPLString GetJsonFilename(CPLString pszFilename)
129 : {
130 141 : return CPLSPrintf( "%s/%s.json", CPLGetDirname(pszFilename), CPLGetBasename(pszFilename) );
131 : }
132 :
133 : /************************************************************************/
134 : /* GetJsonObject() */
135 : /************************************************************************/
136 122 : json_object * GetJsonObject(CPLString pszFilename)
137 : {
138 122 : json_object * pJSONObject = NULL;
139 122 : CPLString pszJSONFilename = GetJsonFilename(pszFilename);
140 :
141 122 : pJSONObject = json_object_from_file((char *)pszJSONFilename.c_str());
142 122 : if (pJSONObject == (struct json_object*)error_ptr(-1) || pJSONObject == NULL) {
143 : CPLDebug("ARGDataset", "GetJsonObject(): "
144 8 : "Could not parse JSON file.");
145 8 : return NULL;
146 : }
147 :
148 114 : return pJSONObject;
149 : }
150 :
151 : /************************************************************************/
152 : /* GetJsonValueStr() */
153 : /************************************************************************/
154 688 : const char * GetJsonValueStr(json_object * pJSONObject, CPLString pszKey)
155 : {
156 688 : json_object * pJSONItem = json_object_object_get(pJSONObject, pszKey.c_str());
157 688 : if (pJSONItem == NULL) {
158 : CPLDebug("ARGDataset", "GetJsonValueStr(): "
159 105 : "Could not find '%s' in JSON.", pszKey.c_str());
160 105 : return NULL;
161 : }
162 :
163 583 : return json_object_get_string(pJSONItem);
164 : }
165 :
166 : /************************************************************************/
167 : /* GetJsonValueDbl() */
168 : /************************************************************************/
169 528 : double GetJsonValueDbl(json_object * pJSONObject, CPLString pszKey)
170 : {
171 528 : const char *pszJSONStr = GetJsonValueStr(pJSONObject, pszKey.c_str());
172 : char *pszTmp;
173 : double fTmp;
174 528 : if (pszJSONStr == NULL) {
175 105 : return NAN;
176 : }
177 423 : pszTmp = (char *)pszJSONStr;
178 423 : fTmp = CPLStrtod(pszJSONStr, &pszTmp);
179 423 : if (pszTmp == pszJSONStr) {
180 : CPLDebug("ARGDataset", "GetJsonValueDbl(): "
181 0 : "Key value is not a numeric value: %s:%s", pszKey.c_str(), pszTmp);
182 0 : return NAN;
183 : }
184 :
185 423 : return fTmp;
186 : }
187 :
188 : /************************************************************************/
189 : /* GetJsonValueInt() */
190 : /************************************************************************/
191 144 : int GetJsonValueInt(json_object * pJSONObject, CPLString pszKey)
192 : {
193 144 : double fTmp = GetJsonValueDbl(pJSONObject, pszKey.c_str());
194 144 : if (CPLIsNan(fTmp)) {
195 35 : return -1;
196 : }
197 :
198 109 : return (int)fTmp;
199 : }
200 :
201 : /************************************************************************/
202 : /* GetFileList() */
203 : /************************************************************************/
204 0 : char ** ARGDataset::GetFileList()
205 : {
206 0 : char **papszFileList = GDALPamDataset::GetFileList();
207 0 : CPLString pszJSONFilename = GetJsonFilename(pszFilename);
208 :
209 0 : papszFileList = CSLAddString( papszFileList, pszJSONFilename );
210 :
211 0 : return papszFileList;
212 : }
213 :
214 : /************************************************************************/
215 : /* Identify() */
216 : /************************************************************************/
217 :
218 11963 : int ARGDataset::Identify( GDALOpenInfo *poOpenInfo )
219 : {
220 : json_object * pJSONObject;
221 11963 : if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "arg")) {
222 11897 : return FALSE;
223 : }
224 :
225 66 : pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
226 66 : if (pJSONObject == NULL) {
227 8 : return FALSE;
228 : }
229 :
230 58 : json_object_put(pJSONObject);
231 58 : pJSONObject = NULL;
232 :
233 58 : return TRUE;
234 : }
235 :
236 : /************************************************************************/
237 : /* Open() */
238 : /************************************************************************/
239 1832 : GDALDataset *ARGDataset::Open( GDALOpenInfo * poOpenInfo )
240 : {
241 : json_object * pJSONObject;
242 : const char * pszJSONStr;
243 : char * pszLayer;
244 : /***** items from the json metadata *****/
245 1832 : GDALDataType eType = GDT_Unknown;
246 1832 : double fXmin = 0.0;
247 1832 : double fYmin = 0.0;
248 1832 : double fXmax = 0.0;
249 1832 : double fYmax = 0.0;
250 1832 : double fCellwidth = 1.0;
251 1832 : double fCellheight = 1.0;
252 1832 : double fXSkew = 0.0;
253 1832 : double fYSkew = 0.0;
254 1832 : int nRows = 0;
255 1832 : int nCols = 0;
256 1832 : int nSrs = 3857;
257 : /***** items from the json metadata *****/
258 1832 : int nPixelOffset = 0;
259 1832 : double fNoDataValue = NAN;
260 :
261 1832 : char * pszWKT = NULL;
262 1832 : OGRSpatialReference oSRS;
263 1832 : OGRErr nErr = OGRERR_NONE;
264 :
265 1832 : if ( !Identify( poOpenInfo ) )
266 1776 : return NULL;
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* Check metadata settings in JSON. */
270 : /* -------------------------------------------------------------------- */
271 :
272 56 : pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
273 :
274 56 : if (pJSONObject == NULL) {
275 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error parsing JSON.");
276 0 : return NULL;
277 : }
278 :
279 : // get the type (always 'arg')
280 56 : pszJSONStr = GetJsonValueStr(pJSONObject, "type");
281 56 : if (pszJSONStr == NULL ) {
282 : CPLError(CE_Failure, CPLE_AppDefined,
283 0 : "The ARG 'type' is missing from the JSON file.");
284 0 : json_object_put(pJSONObject);
285 0 : pJSONObject = NULL;
286 0 : return NULL;
287 : }
288 56 : else if (!EQUAL(pszJSONStr, "arg")) {
289 : CPLError(CE_Failure, CPLE_AppDefined,
290 0 : "The ARG 'type' is not recognized: '%s'.", pszJSONStr);
291 0 : json_object_put(pJSONObject);
292 0 : pJSONObject = NULL;
293 0 : return NULL;
294 : }
295 :
296 : // get the datatype
297 56 : pszJSONStr = GetJsonValueStr(pJSONObject, "datatype");
298 56 : if (pszJSONStr == NULL) {
299 : CPLError(CE_Failure, CPLE_AppDefined,
300 0 : "The ARG 'datatype' is missing from the JSON file.");
301 0 : json_object_put(pJSONObject);
302 0 : pJSONObject = NULL;
303 0 : return NULL;
304 : }
305 56 : else if (EQUAL(pszJSONStr, "int8")) {
306 : CPLDebug("ARGDataset", "Open(): "
307 5 : "int8 data is not supported in GDAL -- mapped to uint8");
308 5 : eType = GDT_Byte;
309 5 : nPixelOffset = 1;
310 5 : fNoDataValue = 128;
311 : }
312 51 : else if (EQUAL(pszJSONStr, "int16")) {
313 10 : eType = GDT_Int16;
314 10 : nPixelOffset = 2;
315 10 : fNoDataValue = -32767;
316 : }
317 41 : else if (EQUAL(pszJSONStr, "int32")) {
318 5 : eType = GDT_Int32;
319 5 : nPixelOffset = 4;
320 5 : fNoDataValue = -2e31;
321 : }
322 36 : else if (EQUAL(pszJSONStr, "uint8")) {
323 8 : eType = GDT_Byte;
324 8 : nPixelOffset = 1;
325 8 : fNoDataValue = 255;
326 : }
327 28 : else if (EQUAL(pszJSONStr, "uint16")) {
328 5 : eType = GDT_UInt16;
329 5 : nPixelOffset = 2;
330 5 : fNoDataValue = 65535;
331 : }
332 23 : else if (EQUAL(pszJSONStr, "uint32")) {
333 5 : eType = GDT_UInt32;
334 5 : nPixelOffset = 4;
335 5 : fNoDataValue = -2e31;
336 : }
337 18 : else if (EQUAL(pszJSONStr, "float32")) {
338 5 : eType = GDT_Float32;
339 5 : nPixelOffset = 4;
340 5 : fNoDataValue = NAN;
341 : }
342 13 : else if (EQUAL(pszJSONStr, "float64")) {
343 5 : eType = GDT_Float64;
344 5 : nPixelOffset = 8;
345 5 : fNoDataValue = NAN;
346 : }
347 : else {
348 16 : if (EQUAL(pszJSONStr, "int64") ||
349 : EQUAL(pszJSONStr, "uint64")) {
350 : CPLError(CE_Failure, CPLE_AppDefined,
351 8 : "The ARG 'datatype' is unsupported in GDAL: '%s'.", pszJSONStr);
352 : }
353 : else {
354 : CPLError(CE_Failure, CPLE_AppDefined,
355 0 : "The ARG 'datatype' is unknown: '%s'.", pszJSONStr);
356 : }
357 8 : json_object_put(pJSONObject);
358 8 : pJSONObject = NULL;
359 8 : return NULL;
360 : }
361 :
362 : // get the xmin of the bounding box
363 48 : fXmin = GetJsonValueDbl(pJSONObject, "xmin");
364 48 : if (CPLIsNan(fXmin)) {
365 : CPLError(CE_Failure, CPLE_AppDefined,
366 0 : "The ARG 'xmin' is missing or invalid.");
367 0 : json_object_put(pJSONObject);
368 0 : pJSONObject = NULL;
369 0 : return NULL;
370 : }
371 :
372 : // get the ymin of the bounding box
373 48 : fYmin = GetJsonValueDbl(pJSONObject, "ymin");
374 48 : if (CPLIsNan(fYmin)) {
375 : CPLError(CE_Failure, CPLE_AppDefined,
376 0 : "The ARG 'ymin' is missing or invalid.");
377 0 : json_object_put(pJSONObject);
378 0 : pJSONObject = NULL;
379 0 : return NULL;
380 : }
381 :
382 : // get the xmax of the bounding box
383 48 : fXmax = GetJsonValueDbl(pJSONObject, "xmax");
384 48 : if (CPLIsNan(fXmax)) {
385 : CPLError(CE_Failure, CPLE_AppDefined,
386 0 : "The ARG 'xmax' is missing or invalid.");
387 0 : json_object_put(pJSONObject);
388 0 : pJSONObject = NULL;
389 0 : return NULL;
390 : }
391 :
392 : // get the ymax of the bounding box
393 48 : fYmax = GetJsonValueDbl(pJSONObject, "ymax");
394 48 : if (CPLIsNan(fYmax)) {
395 : CPLError(CE_Failure, CPLE_AppDefined,
396 0 : "The ARG 'ymax' is missing or invalid.");
397 0 : json_object_put(pJSONObject);
398 0 : pJSONObject = NULL;
399 0 : return NULL;
400 : }
401 :
402 : // get the cell width
403 48 : fCellwidth = GetJsonValueDbl(pJSONObject, "cellwidth");
404 48 : if (CPLIsNan(fCellwidth)) {
405 : CPLError(CE_Failure, CPLE_AppDefined,
406 0 : "The ARG 'cellwidth' is missing or invalid.");
407 0 : json_object_put(pJSONObject);
408 0 : pJSONObject = NULL;
409 0 : return NULL;
410 : }
411 :
412 : // get the cell height
413 48 : fCellheight = GetJsonValueDbl(pJSONObject, "cellheight");
414 48 : if (CPLIsNan(fCellheight)) {
415 : CPLError(CE_Failure, CPLE_AppDefined,
416 0 : "The ARG 'cellheight' is missing or invalid.");
417 0 : json_object_put(pJSONObject);
418 0 : pJSONObject = NULL;
419 0 : return NULL;
420 : }
421 :
422 48 : fXSkew = GetJsonValueDbl(pJSONObject, "xskew");
423 48 : if (CPLIsNan(fXSkew)) {
424 : // not an error -- default to 0.0
425 35 : fXSkew = 0.0f;
426 : }
427 :
428 48 : fYSkew = GetJsonValueDbl(pJSONObject, "yskew");
429 48 : if (CPLIsNan(fYSkew)) {
430 : // not an error -- default to 0.0
431 35 : fYSkew = 0.0f;
432 : }
433 :
434 : // get the rows
435 48 : nRows = GetJsonValueInt(pJSONObject, "rows");
436 48 : if (nRows < 0) {
437 : CPLError(CE_Failure, CPLE_AppDefined,
438 0 : "The ARG 'rows' is missing or invalid.");
439 0 : json_object_put(pJSONObject);
440 0 : pJSONObject = NULL;
441 0 : return NULL;
442 : }
443 :
444 : // get the columns
445 48 : nCols = GetJsonValueInt(pJSONObject, "cols");
446 48 : if (nCols < 0) {
447 : CPLError(CE_Failure, CPLE_AppDefined,
448 0 : "The ARG 'cols' is missing or invalid.");
449 0 : json_object_put(pJSONObject);
450 0 : pJSONObject = NULL;
451 0 : return NULL;
452 : }
453 :
454 48 : nSrs = GetJsonValueInt(pJSONObject, "epsg");
455 48 : if (nSrs < 0) {
456 : // not an error -- default to web mercator
457 35 : nSrs = 3857;
458 : }
459 :
460 48 : nErr = oSRS.importFromEPSG(nSrs);
461 48 : if (nErr != OGRERR_NONE) {
462 0 : nErr = oSRS.importFromEPSG(3857);
463 :
464 0 : if (nErr == OGRERR_NONE) {
465 : CPLDebug("ARGDataset", "Open(): "
466 0 : "The EPSG provided did not import cleanly. Defaulting to EPSG:3857");
467 : }
468 : else {
469 : CPLError(CE_Failure, CPLE_AppDefined,
470 : "The 'epsg' value did not transate to a known spatial reference."
471 0 : " Please check the 'epsg' value and try again.");
472 :
473 0 : json_object_put(pJSONObject);
474 0 : pJSONObject = NULL;
475 :
476 0 : return NULL;
477 : }
478 : }
479 :
480 48 : nErr = oSRS.exportToWkt(&pszWKT);
481 48 : if (nErr != OGRERR_NONE) {
482 : CPLError(CE_Failure, CPLE_AppDefined,
483 : "The spatial reference is known, but could not be set on the "
484 0 : "dataset. Please check the 'epsg' value and try again.");
485 :
486 0 : json_object_put(pJSONObject);
487 0 : pJSONObject = NULL;
488 :
489 0 : return NULL;
490 : }
491 :
492 : // get the layer (always the file basename)
493 48 : pszJSONStr = GetJsonValueStr(pJSONObject, "layer");
494 48 : if (pszJSONStr == NULL) {
495 : CPLError(CE_Failure, CPLE_AppDefined,
496 0 : "The ARG 'layer' is missing from the JSON file.");
497 0 : json_object_put(pJSONObject);
498 0 : pJSONObject = NULL;
499 0 : return NULL;
500 : }
501 :
502 48 : pszLayer = CPLStrdup(pszJSONStr);
503 :
504 : // done with the json object now
505 48 : json_object_put(pJSONObject);
506 48 : pJSONObject = NULL;
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* Create a corresponding GDALDataset. */
510 : /* -------------------------------------------------------------------- */
511 : ARGDataset *poDS;
512 :
513 48 : poDS = new ARGDataset();
514 :
515 96 : poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
516 48 : poDS->SetMetadataItem("LAYER",pszLayer,NULL);
517 48 : poDS->nRasterXSize = nCols;
518 48 : poDS->nRasterYSize = nRows;
519 48 : poDS->SetProjection( pszWKT );
520 :
521 : // done with the projection string
522 48 : CPLFree(pszWKT);
523 48 : CPLFree(pszLayer);
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* Assume ownership of the file handled from the GDALOpenInfo. */
527 : /* -------------------------------------------------------------------- */
528 48 : poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
529 48 : if (poDS->fpImage == NULL)
530 : {
531 2 : delete poDS;
532 : CPLError(CE_Failure, CPLE_AppDefined,
533 2 : "Could not open dataset '%s'", poOpenInfo->pszFilename);
534 2 : return NULL;
535 : }
536 :
537 46 : poDS->adfGeoTransform[0] = fXmin;
538 46 : poDS->adfGeoTransform[1] = fCellwidth;
539 46 : poDS->adfGeoTransform[2] = fXSkew;
540 46 : poDS->adfGeoTransform[3] = fYmax;
541 46 : poDS->adfGeoTransform[4] = fYSkew;
542 46 : poDS->adfGeoTransform[5] = -fCellheight;
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Create band information objects. */
546 : /* -------------------------------------------------------------------- */
547 : RawRasterBand *poBand;
548 :
549 : #ifdef CPL_LSB
550 46 : int bNative = FALSE;
551 : #else
552 : int bNative = TRUE;
553 : #endif
554 :
555 : poBand = new RawRasterBand( poDS, 1, poDS->fpImage,
556 : 0, nPixelOffset, nPixelOffset * nCols,
557 46 : eType, bNative, TRUE );
558 46 : poDS->SetBand( 1, poBand );
559 :
560 46 : poBand->SetNoDataValue( fNoDataValue );
561 :
562 : /* -------------------------------------------------------------------- */
563 : /* Initialize any PAM information. */
564 : /* -------------------------------------------------------------------- */
565 46 : poDS->SetDescription( poOpenInfo->pszFilename );
566 46 : poDS->TryLoadXML();
567 :
568 : /* -------------------------------------------------------------------- */
569 : /* Check for overviews. */
570 : /* -------------------------------------------------------------------- */
571 46 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
572 :
573 46 : return( poDS );
574 : }
575 :
576 : /************************************************************************/
577 : /* CreateCopy() */
578 : /************************************************************************/
579 28 : GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
580 : GDALDataset * poSrcDS, int bStrict, char ** papszOptions,
581 : GDALProgressFunc pfnProgress, void * pProgressData )
582 : {
583 28 : int nBands = poSrcDS->GetRasterCount();
584 28 : int nXSize = poSrcDS->GetRasterXSize();
585 28 : int nYSize = poSrcDS->GetRasterYSize();
586 : int nXBlockSize, nYBlockSize, nPixelOffset;
587 : GDALDataType eType;
588 28 : CPLString pszJSONFilename;
589 28 : CPLString pszDataType;
590 28 : json_object * poJSONObject = NULL;
591 : double adfTransform[6];
592 28 : GDALRasterBand * poSrcBand = NULL;
593 28 : RawRasterBand * poDstBand = NULL;
594 28 : VSILFILE * fpImage = NULL;
595 : void * pabyData;
596 28 : OGRSpatialReference oSRS;
597 28 : char * pszWKT = NULL;
598 28 : char ** pszTokens = NULL;
599 28 : const char * pszLayer = NULL;
600 28 : int nSrs = 0;
601 28 : OGRErr nErr = OGRERR_NONE;
602 : CPLErr eErr;
603 :
604 28 : if( nBands != 1 )
605 : {
606 : CPLError( CE_Failure, CPLE_NotSupported,
607 5 : "ARG driver doesn't support %d bands. Must be 1 band.", nBands );
608 5 : return NULL;
609 : }
610 :
611 23 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
612 23 : if( eType == GDT_Unknown ||
613 : eType == GDT_CInt16 ||
614 : eType == GDT_CInt32 ||
615 : eType == GDT_CFloat32 ||
616 : eType == GDT_CFloat64 )
617 : {
618 : CPLError( CE_Failure, CPLE_NotSupported,
619 : "ARG driver doesn't support data type %s.",
620 4 : GDALGetDataTypeName(eType) );
621 4 : return NULL;
622 : }
623 19 : else if (eType == GDT_Int16) {
624 3 : pszDataType = "int16";
625 3 : nPixelOffset = 2;
626 : }
627 16 : else if (eType == GDT_Int32) {
628 2 : pszDataType = "int32";
629 2 : nPixelOffset = 4;
630 : }
631 14 : else if (eType == GDT_Byte) {
632 6 : pszDataType = "uint8";
633 6 : nPixelOffset = 1;
634 : }
635 8 : else if (eType == GDT_UInt16) {
636 2 : pszDataType = "uint16";
637 2 : nPixelOffset = 2;
638 : }
639 6 : else if (eType == GDT_UInt32) {
640 2 : pszDataType = "uint32";
641 2 : nPixelOffset = 4;
642 : }
643 4 : else if (eType == GDT_Float32) {
644 2 : pszDataType = "float32";
645 2 : nPixelOffset = 4;
646 : }
647 2 : else if (eType == GDT_Float64) {
648 2 : pszDataType = "float64";
649 2 : nPixelOffset = 8;
650 : }
651 :
652 19 : poSrcDS->GetGeoTransform( adfTransform );
653 :
654 19 : pszWKT = (char *)poSrcDS->GetProjectionRef();
655 19 : nErr = oSRS.importFromWkt(&pszWKT);
656 19 : if (nErr != OGRERR_NONE) {
657 : CPLError( CE_Failure, CPLE_NotSupported,
658 0 : "Cannot import spatial reference WKT from source dataset.");
659 0 : return NULL;
660 : }
661 :
662 19 : if (oSRS.GetAuthorityCode("PROJCS") != NULL) {
663 10 : nSrs = atoi(oSRS.GetAuthorityCode("PROJCS"));
664 : }
665 9 : else if (oSRS.GetAuthorityCode("GEOGCS") != NULL) {
666 7 : nSrs = atoi(oSRS.GetAuthorityCode("GEOGCS"));
667 : }
668 : else {
669 : // could not determine projected or geographic code
670 : // default to EPSG:3857 if no code could be found
671 2 : nSrs = 3857;
672 : }
673 :
674 : /********************************************************************/
675 : /* Create JSON companion file. */
676 : /********************************************************************/
677 19 : pszJSONFilename = GetJsonFilename(pszFilename);
678 19 : if (pszJSONFilename == NULL) {
679 : CPLError( CE_Failure, CPLE_NotSupported,
680 0 : "ARG driver can't determine filename for companion file.");
681 0 : return NULL;
682 : }
683 :
684 19 : poJSONObject = json_object_new_object();
685 :
686 19 : pszTokens = poSrcDS->GetMetadata();
687 19 : pszLayer = CSLFetchNameValue(pszTokens, "LAYER");
688 :
689 19 : if ( pszLayer == NULL) {
690 : // Set the layer
691 : json_object_object_add(poJSONObject, "layer", json_object_new_string(
692 : CPLGetBasename(pszJSONFilename)
693 10 : ));
694 : }
695 : else {
696 : // Set the layer
697 : json_object_object_add(poJSONObject, "layer", json_object_new_string(
698 : pszLayer
699 9 : ));
700 : }
701 :
702 : // Set the type
703 19 : json_object_object_add(poJSONObject, "type", json_object_new_string("arg"));
704 : // Set the datatype
705 19 : json_object_object_add(poJSONObject, "datatype", json_object_new_string(pszDataType));
706 : // Set the number of rows
707 19 : json_object_object_add(poJSONObject, "rows", json_object_new_int(nYSize));
708 : // Set the number of columns
709 19 : json_object_object_add(poJSONObject, "cols", json_object_new_int(nXSize));
710 : // Set the xmin
711 19 : json_object_object_add(poJSONObject, "xmin", json_object_new_double(adfTransform[0]));
712 : // Set the ymax
713 19 : json_object_object_add(poJSONObject, "ymax", json_object_new_double(adfTransform[3]));
714 : // Set the cellwidth
715 19 : json_object_object_add(poJSONObject, "cellwidth", json_object_new_double(adfTransform[1]));
716 : // Set the cellheight
717 19 : json_object_object_add(poJSONObject, "cellheight", json_object_new_double(-adfTransform[5]));
718 : // Set the xmax
719 19 : json_object_object_add(poJSONObject, "xmax", json_object_new_double(adfTransform[0] + nXSize * adfTransform[1]));
720 : // Set the ymin
721 19 : json_object_object_add(poJSONObject, "ymin", json_object_new_double(adfTransform[3] + nYSize * adfTransform[5]));
722 : // Set the xskew
723 19 : json_object_object_add(poJSONObject, "xskew", json_object_new_double(adfTransform[2]));
724 : // Set the yskew
725 19 : json_object_object_add(poJSONObject, "yskew", json_object_new_double(adfTransform[4]));
726 19 : if (nSrs > 0) {
727 : // Set the epsg
728 19 : json_object_object_add(poJSONObject, "epsg", json_object_new_int(nSrs));
729 : }
730 :
731 19 : if (json_object_to_file((char *)pszJSONFilename.c_str(), poJSONObject) < 0) {
732 : CPLError( CE_Failure, CPLE_NotSupported,
733 2 : "ARG driver can't write companion file.");
734 :
735 2 : json_object_put(poJSONObject);
736 2 : poJSONObject = NULL;
737 :
738 2 : return NULL;
739 : }
740 :
741 17 : json_object_put(poJSONObject);
742 17 : poJSONObject = NULL;
743 :
744 17 : fpImage = VSIFOpenL(pszFilename, "wb");
745 17 : if (fpImage == NULL)
746 : {
747 : CPLError( CE_Failure, CPLE_NotSupported,
748 0 : "ARG driver can't create data file %s.", pszFilename);
749 :
750 : // remove JSON file
751 0 : VSIUnlink( pszJSONFilename.c_str() );
752 :
753 0 : return NULL;
754 : }
755 :
756 : // only 1 raster band
757 17 : poSrcBand = poSrcDS->GetRasterBand( 1 );
758 :
759 : #ifdef CPL_LSB
760 17 : int bNative = FALSE;
761 : #else
762 : int bNative = TRUE;
763 : #endif
764 :
765 : poDstBand = new RawRasterBand( fpImage, 0, nPixelOffset,
766 17 : nPixelOffset * nXSize, eType, bNative, nXSize, nYSize, TRUE, FALSE);
767 :
768 17 : poSrcBand->GetBlockSize(&nXBlockSize, &nYBlockSize);
769 :
770 17 : pabyData = CPLMalloc(nXBlockSize * nPixelOffset);
771 :
772 : // convert any blocks into scanlines
773 55 : for (int nYBlock = 0; nYBlock * nYBlockSize < nYSize; nYBlock++) {
774 651 : for (int nYScanline = 0; nYScanline < nYBlockSize; nYScanline++) {
775 613 : if ((nYScanline+1) + nYBlock * nYBlockSize > poSrcBand->GetYSize() ) {
776 13 : continue;
777 : }
778 :
779 1200 : for (int nXBlock = 0; nXBlock * nXBlockSize < nXSize; nXBlock++) {
780 : int nXValid;
781 :
782 600 : if( (nXBlock+1) * nXBlockSize > poSrcBand->GetXSize() )
783 0 : nXValid = poSrcBand->GetXSize() - nXBlock * nXBlockSize;
784 : else
785 600 : nXValid = nXBlockSize;
786 :
787 : eErr = poSrcBand->RasterIO(GF_Read, nXBlock * nXBlockSize,
788 : nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
789 600 : 1, eType, 0, 0);
790 :
791 600 : if (eErr != CE_None) {
792 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error reading.");
793 :
794 0 : CPLFree( pabyData );
795 0 : delete poDstBand;
796 0 : VSIFCloseL( fpImage );
797 :
798 0 : return NULL;
799 : }
800 :
801 : eErr = poDstBand->RasterIO(GF_Write, nXBlock * nXBlockSize,
802 : nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
803 600 : 1, eType, 0, 0);
804 :
805 600 : if (eErr != CE_None) {
806 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error writing.");
807 :
808 0 : CPLFree( pabyData );
809 0 : delete poDstBand;
810 0 : VSIFCloseL( fpImage );
811 :
812 0 : return NULL;
813 : }
814 : }
815 : }
816 : }
817 :
818 17 : CPLFree( pabyData );
819 17 : delete poDstBand;
820 17 : VSIFCloseL( fpImage );
821 :
822 17 : return (GDALDataset *)GDALOpen( pszFilename, GA_ReadOnly );
823 : }
824 :
825 : /************************************************************************/
826 : /* GDALRegister_ARG() */
827 : /************************************************************************/
828 :
829 610 : void GDALRegister_ARG()
830 : {
831 : GDALDriver *poDriver;
832 :
833 610 : if( GDALGetDriverByName( "ARG" ) == NULL )
834 : {
835 588 : poDriver = new GDALDriver();
836 :
837 588 : poDriver->SetDescription( "ARG" );
838 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
839 588 : "Azavea Raster Grid format" );
840 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
841 588 : "frmt_various.html#ARG" );
842 588 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
843 :
844 588 : poDriver->pfnIdentify = ARGDataset::Identify;
845 588 : poDriver->pfnOpen = ARGDataset::Open;
846 588 : poDriver->pfnCreateCopy = ARGDataset::CreateCopy;
847 :
848 588 : GetGDALDriverManager()->RegisterDriver( poDriver );
849 : }
850 610 : }
851 :
|