1 : /******************************************************************************
2 : * $Id: argdataset.cpp 24219 2012-04-11 21:02:14Z dzwarg $
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 24219 2012-04-11 21:02:14Z dzwarg $");
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 62 : ARGDataset::ARGDataset()
89 : {
90 62 : adfGeoTransform[0] = 0.0;
91 62 : adfGeoTransform[1] = 1.0;
92 62 : adfGeoTransform[2] = 0.0;
93 62 : adfGeoTransform[3] = 0.0;
94 62 : adfGeoTransform[4] = 0.0;
95 62 : adfGeoTransform[5] = 1.0;
96 62 : fpImage = NULL;
97 62 : }
98 :
99 : /************************************************************************/
100 : /* ~ARGDataset() */
101 : /************************************************************************/
102 :
103 62 : ARGDataset::~ARGDataset()
104 :
105 : {
106 62 : CPLFree(pszFilename);
107 :
108 62 : FlushCache();
109 62 : if( fpImage != NULL )
110 60 : VSIFCloseL( fpImage );
111 62 : }
112 :
113 : /************************************************************************/
114 : /* GetGeoTransform() */
115 : /************************************************************************/
116 :
117 18 : CPLErr ARGDataset::GetGeoTransform( double * padfTransform )
118 :
119 : {
120 18 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
121 :
122 18 : return CE_None;
123 : }
124 :
125 : /************************************************************************/
126 : /* GetJsonFilename() */
127 : /************************************************************************/
128 174 : CPLString GetJsonFilename(CPLString pszFilename)
129 : {
130 174 : return CPLSPrintf( "%s/%s.json", CPLGetDirname(pszFilename), CPLGetBasename(pszFilename) );
131 : }
132 :
133 : /************************************************************************/
134 : /* GetJsonObject() */
135 : /************************************************************************/
136 152 : json_object * GetJsonObject(CPLString pszFilename)
137 : {
138 152 : json_object * pJSONObject = NULL;
139 152 : CPLString pszJSONFilename = GetJsonFilename(pszFilename);
140 :
141 152 : pJSONObject = json_object_from_file((char *)pszJSONFilename.c_str());
142 152 : if (is_error(pJSONObject) || pJSONObject == NULL) {
143 : CPLDebug("ARGDataset", "GetJsonObject(): "
144 2 : "Could not parse JSON file.");
145 2 : return NULL;
146 : }
147 :
148 150 : return pJSONObject;
149 : }
150 :
151 : /************************************************************************/
152 : /* GetJsonValueStr() */
153 : /************************************************************************/
154 892 : const char * GetJsonValueStr(json_object * pJSONObject, CPLString pszKey)
155 : {
156 892 : json_object * pJSONItem = json_object_object_get(pJSONObject, pszKey.c_str());
157 892 : if (pJSONItem == NULL) {
158 : CPLDebug("ARGDataset", "GetJsonValueStr(): "
159 162 : "Could not find '%s' in JSON.", pszKey.c_str());
160 162 : return NULL;
161 : }
162 :
163 730 : return json_object_get_string(pJSONItem);
164 : }
165 :
166 : /************************************************************************/
167 : /* GetJsonValueDbl() */
168 : /************************************************************************/
169 682 : double GetJsonValueDbl(json_object * pJSONObject, CPLString pszKey)
170 : {
171 682 : const char *pszJSONStr = GetJsonValueStr(pJSONObject, pszKey.c_str());
172 : char *pszTmp;
173 : double fTmp;
174 682 : if (pszJSONStr == NULL) {
175 162 : return NAN;
176 : }
177 520 : pszTmp = (char *)pszJSONStr;
178 520 : fTmp = CPLStrtod(pszJSONStr, &pszTmp);
179 520 : 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 520 : return fTmp;
186 : }
187 :
188 : /************************************************************************/
189 : /* GetJsonValueInt() */
190 : /************************************************************************/
191 186 : int GetJsonValueInt(json_object * pJSONObject, CPLString pszKey)
192 : {
193 186 : double fTmp = GetJsonValueDbl(pJSONObject, pszKey.c_str());
194 186 : if (CPLIsNan(fTmp)) {
195 54 : return -1;
196 : }
197 :
198 132 : 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 22420 : int ARGDataset::Identify( GDALOpenInfo *poOpenInfo )
219 : {
220 : json_object * pJSONObject;
221 22420 : if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "arg")) {
222 22342 : return FALSE;
223 : }
224 :
225 78 : pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
226 78 : if (pJSONObject == NULL) {
227 2 : return FALSE;
228 : }
229 :
230 76 : if (is_error(pJSONObject)) {
231 0 : json_object_put(pJSONObject);
232 0 : pJSONObject = NULL;
233 :
234 0 : return FALSE;
235 : }
236 :
237 76 : json_object_put(pJSONObject);
238 76 : pJSONObject = NULL;
239 :
240 76 : return TRUE;
241 : }
242 :
243 : /************************************************************************/
244 : /* Open() */
245 : /************************************************************************/
246 3510 : GDALDataset *ARGDataset::Open( GDALOpenInfo * poOpenInfo )
247 : {
248 : json_object * pJSONObject;
249 : const char * pszJSONStr;
250 : char * pszLayer;
251 : /***** items from the json metadata *****/
252 3510 : GDALDataType eType = GDT_Unknown;
253 3510 : double fXmin = 0.0;
254 3510 : double fYmin = 0.0;
255 3510 : double fXmax = 0.0;
256 3510 : double fYmax = 0.0;
257 3510 : double fCellwidth = 1.0;
258 3510 : double fCellheight = 1.0;
259 3510 : double fXSkew = 0.0;
260 3510 : double fYSkew = 0.0;
261 3510 : int nRows = 0;
262 3510 : int nCols = 0;
263 3510 : int nSrs = 3857;
264 : /***** items from the json metadata *****/
265 3510 : int nPixelOffset = 0;
266 3510 : double fNoDataValue = NAN;
267 :
268 3510 : char * pszWKT = NULL;
269 3510 : OGRSpatialReference oSRS;
270 3510 : OGRErr nErr = OGRERR_NONE;
271 :
272 3510 : if ( !Identify( poOpenInfo ) )
273 3436 : return NULL;
274 :
275 : /* -------------------------------------------------------------------- */
276 : /* Check metadata settings in JSON. */
277 : /* -------------------------------------------------------------------- */
278 :
279 74 : pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
280 :
281 74 : if (is_error(pJSONObject)) {
282 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error parsing JSON.");
283 0 : json_object_put(pJSONObject);
284 0 : pJSONObject = NULL;
285 0 : return NULL;
286 : }
287 :
288 : // get the type (always 'arg')
289 74 : pszJSONStr = GetJsonValueStr(pJSONObject, "type");
290 74 : if (pszJSONStr == NULL ) {
291 : CPLError(CE_Failure, CPLE_AppDefined,
292 0 : "The ARG 'type' is missing from the JSON file.");
293 0 : json_object_put(pJSONObject);
294 0 : pJSONObject = NULL;
295 0 : return NULL;
296 : }
297 74 : else if (!EQUAL(pszJSONStr, "arg")) {
298 : CPLError(CE_Failure, CPLE_AppDefined,
299 0 : "The ARG 'type' is not recognized: '%s'.", pszJSONStr);
300 0 : json_object_put(pJSONObject);
301 0 : pJSONObject = NULL;
302 0 : return NULL;
303 : }
304 :
305 : // get the datatype
306 74 : pszJSONStr = GetJsonValueStr(pJSONObject, "datatype");
307 74 : if (pszJSONStr == NULL) {
308 : CPLError(CE_Failure, CPLE_AppDefined,
309 0 : "The ARG 'datatype' is missing from the JSON file.");
310 0 : json_object_put(pJSONObject);
311 0 : pJSONObject = NULL;
312 0 : return NULL;
313 : }
314 74 : else if (EQUAL(pszJSONStr, "int8")) {
315 : CPLDebug("ARGDataset", "Open(): "
316 8 : "int8 data is not supported in GDAL -- mapped to uint8");
317 8 : eType = GDT_Byte;
318 8 : nPixelOffset = 1;
319 8 : fNoDataValue = 128;
320 : }
321 66 : else if (EQUAL(pszJSONStr, "int16")) {
322 15 : eType = GDT_Int16;
323 15 : nPixelOffset = 2;
324 15 : fNoDataValue = -32767;
325 : }
326 51 : else if (EQUAL(pszJSONStr, "int32")) {
327 6 : eType = GDT_Int32;
328 6 : nPixelOffset = 4;
329 6 : fNoDataValue = -2e31;
330 : }
331 45 : else if (EQUAL(pszJSONStr, "uint8")) {
332 9 : eType = GDT_Byte;
333 9 : nPixelOffset = 1;
334 9 : fNoDataValue = 255;
335 : }
336 36 : else if (EQUAL(pszJSONStr, "uint16")) {
337 6 : eType = GDT_UInt16;
338 6 : nPixelOffset = 2;
339 6 : fNoDataValue = 65535;
340 : }
341 30 : else if (EQUAL(pszJSONStr, "uint32")) {
342 6 : eType = GDT_UInt32;
343 6 : nPixelOffset = 4;
344 6 : fNoDataValue = -2e31;
345 : }
346 24 : else if (EQUAL(pszJSONStr, "float32")) {
347 6 : eType = GDT_Float32;
348 6 : nPixelOffset = 4;
349 6 : fNoDataValue = NAN;
350 : }
351 18 : else if (EQUAL(pszJSONStr, "float64")) {
352 6 : eType = GDT_Float64;
353 6 : nPixelOffset = 8;
354 6 : fNoDataValue = NAN;
355 : }
356 : else {
357 24 : if (EQUAL(pszJSONStr, "int64") ||
358 : EQUAL(pszJSONStr, "uint64")) {
359 : CPLError(CE_Failure, CPLE_AppDefined,
360 12 : "The ARG 'datatype' is unsupported in GDAL: '%s'.", pszJSONStr);
361 : }
362 : else {
363 : CPLError(CE_Failure, CPLE_AppDefined,
364 0 : "The ARG 'datatype' is unknown: '%s'.", pszJSONStr);
365 : }
366 12 : json_object_put(pJSONObject);
367 12 : pJSONObject = NULL;
368 12 : return NULL;
369 : }
370 :
371 : // get the xmin of the bounding box
372 62 : fXmin = GetJsonValueDbl(pJSONObject, "xmin");
373 62 : if (CPLIsNan(fXmin)) {
374 : CPLError(CE_Failure, CPLE_AppDefined,
375 0 : "The ARG 'xmin' is missing or invalid.");
376 0 : json_object_put(pJSONObject);
377 0 : pJSONObject = NULL;
378 0 : return NULL;
379 : }
380 :
381 : // get the ymin of the bounding box
382 62 : fYmin = GetJsonValueDbl(pJSONObject, "ymin");
383 62 : if (CPLIsNan(fYmin)) {
384 : CPLError(CE_Failure, CPLE_AppDefined,
385 0 : "The ARG 'ymin' is missing or invalid.");
386 0 : json_object_put(pJSONObject);
387 0 : pJSONObject = NULL;
388 0 : return NULL;
389 : }
390 :
391 : // get the xmax of the bounding box
392 62 : fXmax = GetJsonValueDbl(pJSONObject, "xmax");
393 62 : if (CPLIsNan(fXmax)) {
394 : CPLError(CE_Failure, CPLE_AppDefined,
395 0 : "The ARG 'xmax' is missing or invalid.");
396 0 : json_object_put(pJSONObject);
397 0 : pJSONObject = NULL;
398 0 : return NULL;
399 : }
400 :
401 : // get the ymax of the bounding box
402 62 : fYmax = GetJsonValueDbl(pJSONObject, "ymax");
403 62 : if (CPLIsNan(fYmax)) {
404 : CPLError(CE_Failure, CPLE_AppDefined,
405 0 : "The ARG 'ymax' is missing or invalid.");
406 0 : json_object_put(pJSONObject);
407 0 : pJSONObject = NULL;
408 0 : return NULL;
409 : }
410 :
411 : // get the cell width
412 62 : fCellwidth = GetJsonValueDbl(pJSONObject, "cellwidth");
413 62 : if (CPLIsNan(fCellwidth)) {
414 : CPLError(CE_Failure, CPLE_AppDefined,
415 0 : "The ARG 'cellwidth' is missing or invalid.");
416 0 : json_object_put(pJSONObject);
417 0 : pJSONObject = NULL;
418 0 : return NULL;
419 : }
420 :
421 : // get the cell height
422 62 : fCellheight = GetJsonValueDbl(pJSONObject, "cellheight");
423 62 : if (CPLIsNan(fCellheight)) {
424 : CPLError(CE_Failure, CPLE_AppDefined,
425 0 : "The ARG 'cellheight' is missing or invalid.");
426 0 : json_object_put(pJSONObject);
427 0 : pJSONObject = NULL;
428 0 : return NULL;
429 : }
430 :
431 62 : fXSkew = GetJsonValueDbl(pJSONObject, "xskew");
432 62 : if (CPLIsNan(fXSkew)) {
433 : // not an error -- default to 0.0
434 54 : fXSkew = 0.0f;
435 : }
436 :
437 62 : fYSkew = GetJsonValueDbl(pJSONObject, "yskew");
438 62 : if (CPLIsNan(fYSkew)) {
439 : // not an error -- default to 0.0
440 54 : fYSkew = 0.0f;
441 : }
442 :
443 : // get the rows
444 62 : nRows = GetJsonValueInt(pJSONObject, "rows");
445 62 : if (nRows < 0) {
446 : CPLError(CE_Failure, CPLE_AppDefined,
447 0 : "The ARG 'rows' is missing or invalid.");
448 0 : json_object_put(pJSONObject);
449 0 : pJSONObject = NULL;
450 0 : return NULL;
451 : }
452 :
453 : // get the columns
454 62 : nCols = GetJsonValueInt(pJSONObject, "cols");
455 62 : if (nCols < 0) {
456 : CPLError(CE_Failure, CPLE_AppDefined,
457 0 : "The ARG 'cols' is missing or invalid.");
458 0 : json_object_put(pJSONObject);
459 0 : pJSONObject = NULL;
460 0 : return NULL;
461 : }
462 :
463 62 : nSrs = GetJsonValueInt(pJSONObject, "epsg");
464 62 : if (nSrs < 0) {
465 : // not an error -- default to web mercator
466 54 : nSrs = 3857;
467 : }
468 :
469 62 : nErr = oSRS.importFromEPSG(nSrs);
470 62 : if (nErr != OGRERR_NONE) {
471 0 : nErr = oSRS.importFromEPSG(3857);
472 :
473 0 : if (nErr == OGRERR_NONE) {
474 : CPLDebug("ARGDataset", "Open(): "
475 0 : "The EPSG provided did not import cleanly. Defaulting to EPSG:3857");
476 : }
477 : else {
478 : CPLError(CE_Failure, CPLE_AppDefined,
479 : "The 'epsg' value did not transate to a known spatial reference."
480 0 : " Please check the 'epsg' value and try again.");
481 :
482 0 : json_object_put(pJSONObject);
483 0 : pJSONObject = NULL;
484 :
485 0 : return NULL;
486 : }
487 : }
488 :
489 62 : nErr = oSRS.exportToWkt(&pszWKT);
490 62 : if (nErr != OGRERR_NONE) {
491 : CPLError(CE_Failure, CPLE_AppDefined,
492 : "The spatial reference is known, but could not be set on the "
493 0 : "dataset. Please check the 'epsg' value and try again.");
494 :
495 0 : json_object_put(pJSONObject);
496 0 : pJSONObject = NULL;
497 :
498 0 : return NULL;
499 : }
500 :
501 : // get the layer (always the file basename)
502 62 : pszJSONStr = GetJsonValueStr(pJSONObject, "layer");
503 62 : if (pszJSONStr == NULL) {
504 : CPLError(CE_Failure, CPLE_AppDefined,
505 0 : "The ARG 'layer' is missing from the JSON file.");
506 0 : json_object_put(pJSONObject);
507 0 : pJSONObject = NULL;
508 0 : return NULL;
509 : }
510 :
511 62 : pszLayer = CPLStrdup(pszJSONStr);
512 :
513 : // done with the json object now
514 62 : json_object_put(pJSONObject);
515 62 : pJSONObject = NULL;
516 :
517 : /* -------------------------------------------------------------------- */
518 : /* Create a corresponding GDALDataset. */
519 : /* -------------------------------------------------------------------- */
520 : ARGDataset *poDS;
521 :
522 62 : poDS = new ARGDataset();
523 :
524 124 : poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
525 62 : poDS->SetMetadataItem("LAYER",pszLayer,NULL);
526 62 : poDS->nRasterXSize = nCols;
527 62 : poDS->nRasterYSize = nRows;
528 62 : poDS->SetProjection( pszWKT );
529 :
530 : // done with the projection string
531 62 : CPLFree(pszWKT);
532 62 : CPLFree(pszLayer);
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Assume ownership of the file handled from the GDALOpenInfo. */
536 : /* -------------------------------------------------------------------- */
537 62 : poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
538 62 : if (poDS->fpImage == NULL)
539 : {
540 2 : delete poDS;
541 : CPLError(CE_Failure, CPLE_AppDefined,
542 2 : "Could not open dataset '%s'", poOpenInfo->pszFilename);
543 2 : return NULL;
544 : }
545 :
546 60 : poDS->adfGeoTransform[0] = fXmin;
547 60 : poDS->adfGeoTransform[1] = fCellwidth;
548 60 : poDS->adfGeoTransform[2] = fXSkew;
549 60 : poDS->adfGeoTransform[3] = fYmax;
550 60 : poDS->adfGeoTransform[4] = fYSkew;
551 60 : poDS->adfGeoTransform[5] = -fCellheight;
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Create band information objects. */
555 : /* -------------------------------------------------------------------- */
556 : RawRasterBand *poBand;
557 : #ifdef CPL_LSB
558 60 : int bNative = TRUE;
559 : #else
560 : int bNative = FALSE;
561 : #endif
562 :
563 : poBand = new RawRasterBand( poDS, 1, poDS->fpImage,
564 : 0, nPixelOffset, nPixelOffset * nCols,
565 60 : eType, bNative, TRUE );
566 60 : poDS->SetBand( 1, poBand );
567 :
568 60 : poBand->SetNoDataValue( fNoDataValue );
569 :
570 : /* -------------------------------------------------------------------- */
571 : /* Initialize any PAM information. */
572 : /* -------------------------------------------------------------------- */
573 60 : poDS->SetDescription( poOpenInfo->pszFilename );
574 60 : poDS->TryLoadXML();
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Check for overviews. */
578 : /* -------------------------------------------------------------------- */
579 60 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
580 :
581 60 : return( poDS );
582 : }
583 :
584 : /************************************************************************/
585 : /* CreateCopy() */
586 : /************************************************************************/
587 40 : GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
588 : GDALDataset * poSrcDS, int bStrict, char ** papszOptions,
589 : GDALProgressFunc pfnProgress, void * pProgressData )
590 : {
591 40 : int nBands = poSrcDS->GetRasterCount();
592 40 : int nXSize = poSrcDS->GetRasterXSize();
593 40 : int nYSize = poSrcDS->GetRasterYSize();
594 : int nXBlockSize, nYBlockSize, nPixelOffset;
595 : GDALDataType eType;
596 40 : CPLString pszJSONFilename;
597 40 : CPLString pszDataType;
598 40 : json_object * poJSONObject = NULL;
599 : double adfTransform[6];
600 40 : VSILFILE * fpImage = NULL;
601 40 : GDALRasterBand * poBand = NULL;
602 : GByte * pabyData;
603 40 : OGRSpatialReference oSRS;
604 40 : char * pszWKT = NULL;
605 40 : char ** pszTokens = NULL;
606 40 : const char * pszLayer = NULL;
607 40 : int nSrs = 0;
608 40 : OGRErr nErr = OGRERR_NONE;
609 :
610 40 : if( nBands != 1 )
611 : {
612 : CPLError( CE_Failure, CPLE_NotSupported,
613 10 : "ARG driver doesn't support %d bands. Must be 1 band.", nBands );
614 10 : return NULL;
615 : }
616 :
617 30 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
618 30 : if( eType == GDT_Unknown ||
619 : eType == GDT_CInt16 ||
620 : eType == GDT_CInt32 ||
621 : eType == GDT_CFloat32 ||
622 : eType == GDT_CFloat64 )
623 : {
624 : CPLError( CE_Failure, CPLE_NotSupported,
625 : "ARG driver doesn't support data type %s.",
626 8 : GDALGetDataTypeName(eType) );
627 8 : return NULL;
628 : }
629 22 : else if (eType == GDT_Int16) {
630 4 : pszDataType = "int16";
631 4 : nPixelOffset = 2;
632 : }
633 18 : else if (eType == GDT_Int32) {
634 2 : pszDataType = "int32";
635 2 : nPixelOffset = 4;
636 : }
637 16 : else if (eType == GDT_Byte) {
638 8 : pszDataType = "uint8";
639 8 : nPixelOffset = 1;
640 : }
641 8 : else if (eType == GDT_UInt16) {
642 2 : pszDataType = "uint16";
643 2 : nPixelOffset = 2;
644 : }
645 6 : else if (eType == GDT_UInt32) {
646 2 : pszDataType = "uint32";
647 2 : nPixelOffset = 4;
648 : }
649 4 : else if (eType == GDT_Float32) {
650 2 : pszDataType = "float32";
651 2 : nPixelOffset = 4;
652 : }
653 2 : else if (eType == GDT_Float64) {
654 2 : pszDataType = "float64";
655 2 : nPixelOffset = 8;
656 : }
657 :
658 22 : poSrcDS->GetGeoTransform( adfTransform );
659 :
660 22 : pszWKT = (char *)poSrcDS->GetProjectionRef();
661 22 : nErr = oSRS.importFromWkt(&pszWKT);
662 22 : if (nErr != OGRERR_NONE) {
663 : CPLError( CE_Failure, CPLE_NotSupported,
664 0 : "Cannot import spatial reference WKT from source dataset.");
665 0 : return NULL;
666 : }
667 :
668 22 : if (oSRS.GetAuthorityCode("PROJCS") != NULL) {
669 4 : nSrs = atoi(oSRS.GetAuthorityCode("PROJCS"));
670 : }
671 18 : else if (oSRS.GetAuthorityCode("GEOGCS") != NULL) {
672 14 : nSrs = atoi(oSRS.GetAuthorityCode("GEOGCS"));
673 : }
674 : else {
675 : // could not determine projected or geographic code
676 : // default to EPSG:3857 if no code could be found
677 4 : nSrs = 3857;
678 : }
679 :
680 : /********************************************************************/
681 : /* Create JSON companion file. */
682 : /********************************************************************/
683 22 : pszJSONFilename = GetJsonFilename(pszFilename);
684 22 : if (pszJSONFilename == NULL) {
685 : CPLError( CE_Failure, CPLE_NotSupported,
686 0 : "ARG driver can't determine filename for companion file.");
687 0 : return NULL;
688 : }
689 :
690 22 : poJSONObject = json_object_new_object();
691 :
692 22 : pszTokens = poSrcDS->GetMetadata();
693 22 : pszLayer = CSLFetchNameValue(pszTokens, "LAYER");
694 :
695 22 : if ( pszLayer == NULL) {
696 : // Set the layer
697 : json_object_object_add(poJSONObject, "layer", json_object_new_string(
698 : CPLGetBasename(pszJSONFilename)
699 20 : ));
700 : }
701 : else {
702 : // Set the layer
703 : json_object_object_add(poJSONObject, "layer", json_object_new_string(
704 : pszLayer
705 2 : ));
706 : }
707 :
708 : // Set the type
709 22 : json_object_object_add(poJSONObject, "type", json_object_new_string("arg"));
710 : // Set the datatype
711 22 : json_object_object_add(poJSONObject, "datatype", json_object_new_string(pszDataType));
712 : // Set the number of rows
713 22 : json_object_object_add(poJSONObject, "rows", json_object_new_int(nXSize));
714 : // Set the number of columns
715 22 : json_object_object_add(poJSONObject, "cols", json_object_new_int(nYSize));
716 : // Set the xmin
717 22 : json_object_object_add(poJSONObject, "xmin", json_object_new_double(adfTransform[0]));
718 : // Set the ymax
719 22 : json_object_object_add(poJSONObject, "ymax", json_object_new_double(adfTransform[3]));
720 : // Set the cellwidth
721 22 : json_object_object_add(poJSONObject, "cellwidth", json_object_new_double(adfTransform[1]));
722 : // Set the cellheight
723 22 : json_object_object_add(poJSONObject, "cellheight", json_object_new_double(-adfTransform[5]));
724 : // Set the xmax
725 22 : json_object_object_add(poJSONObject, "xmax", json_object_new_double(adfTransform[0] + nXSize * adfTransform[1]));
726 : // Set the ymin
727 22 : json_object_object_add(poJSONObject, "ymin", json_object_new_double(adfTransform[3] + nYSize * adfTransform[5]));
728 : // Set the xskew
729 22 : json_object_object_add(poJSONObject, "xskew", json_object_new_double(adfTransform[2]));
730 : // Set the yskew
731 22 : json_object_object_add(poJSONObject, "yskew", json_object_new_double(adfTransform[4]));
732 22 : if (nSrs > 0) {
733 : // Set the epsg
734 22 : json_object_object_add(poJSONObject, "epsg", json_object_new_int(nSrs));
735 : }
736 :
737 22 : if (json_object_to_file((char *)pszJSONFilename.c_str(), poJSONObject) < 0) {
738 : CPLError( CE_Failure, CPLE_NotSupported,
739 4 : "ARG driver can't write companion file.");
740 :
741 4 : json_object_put(poJSONObject);
742 4 : poJSONObject = NULL;
743 :
744 4 : return NULL;
745 : }
746 :
747 18 : json_object_put(poJSONObject);
748 18 : poJSONObject = NULL;
749 :
750 18 : fpImage = VSIFOpenL(pszFilename, "wb");
751 18 : if (fpImage == NULL)
752 : {
753 : CPLError( CE_Failure, CPLE_NotSupported,
754 0 : "ARG driver can't create data file %s.", pszFilename);
755 :
756 : // remove JSON file
757 0 : VSIUnlink( pszJSONFilename.c_str() );
758 :
759 0 : return NULL;
760 : }
761 :
762 : // only 1 raster band
763 18 : poBand = poSrcDS->GetRasterBand( 1 );
764 :
765 18 : poBand->GetBlockSize(&nXBlockSize, &nYBlockSize);
766 :
767 18 : pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize * nPixelOffset);
768 :
769 : // convert any blocks into scanlines
770 78 : for (int nYBlock = 0; nYBlock * nYBlockSize < nYSize; nYBlock++) {
771 1254 : for (int nYScanline = 0; nYScanline < nYBlockSize; nYScanline++) {
772 1194 : if ((nYScanline+1) + nYBlock * nYBlockSize > poBand->GetYSize() ) {
773 26 : continue;
774 : }
775 :
776 2336 : for (int nXBlock = 0; nXBlock * nXBlockSize < nXSize; nXBlock++) {
777 : int nXValid;
778 :
779 1168 : poBand->ReadBlock(nXBlock, nYBlock, pabyData);
780 :
781 1168 : if( (nXBlock+1) * nXBlockSize > poBand->GetXSize() )
782 0 : nXValid = poBand->GetXSize() - nXBlock * nXBlockSize;
783 : else
784 1168 : nXValid = nXBlockSize;
785 :
786 1168 : VSIFWriteL( pabyData + (nYScanline * nXBlockSize * nPixelOffset), nPixelOffset, nXValid, fpImage );
787 : }
788 : }
789 : }
790 :
791 18 : CPLFree( pabyData );
792 18 : VSIFCloseL( fpImage );
793 :
794 18 : return (GDALDataset *)GDALOpen( pszFilename, GA_ReadOnly );
795 : }
796 :
797 : /************************************************************************/
798 : /* GDALRegister_ARG() */
799 : /************************************************************************/
800 :
801 1135 : void GDALRegister_ARG()
802 : {
803 : GDALDriver *poDriver;
804 :
805 1135 : if( GDALGetDriverByName( "ARG" ) == NULL )
806 : {
807 1093 : poDriver = new GDALDriver();
808 :
809 1093 : poDriver->SetDescription( "ARG" );
810 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
811 1093 : "Azavea Raster Grid format" );
812 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
813 1093 : "frmt_various.html#ARG" );
814 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
815 :
816 1093 : poDriver->pfnIdentify = ARGDataset::Identify;
817 1093 : poDriver->pfnOpen = ARGDataset::Open;
818 1093 : poDriver->pfnCreateCopy = ARGDataset::CreateCopy;
819 :
820 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
821 : }
822 1135 : }
823 :
|