1 /******************************************************************************
2 *
3 * Name: georaster_dataset.cpp
4 * Project: Oracle Spatial GeoRaster Driver
5 * Purpose: Implement GeoRasterDataset Methods
6 * Author: Ivan Lucena [ivan.lucena at oracle.com]
7 *
8 ******************************************************************************
9 * Copyright (c) 2008, Ivan Lucena <ivan dot lucena at oracle dot com>
10 * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.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 "cpl_error.h"
32 #include "cpl_vsi_virtual.h"
33 #include "gdaljp2metadata.h"
34 #include "cpl_list.h"
35
36 #include "gdal.h"
37 #include "gdal_frmts.h"
38 #include "gdal_priv.h"
39 #include "ogr_spatialref.h"
40
41 #include "georaster_priv.h"
42
43 #include <memory>
44
45 CPL_CVSID("$Id: georaster_dataset.cpp 2676511214f0c767cd711dae3cf4b4ed7b16ab82 2021-09-29 14:34:00 -0400 fechen123 $")
46
47 // ---------------------------------------------------------------------------
48 // GeoRasterDataset()
49 // ---------------------------------------------------------------------------
50
GeoRasterDataset()51 GeoRasterDataset::GeoRasterDataset()
52 {
53 bGeoTransform = false;
54 bForcedSRID = false;
55 poGeoRaster = nullptr;
56 papszSubdatasets = nullptr;
57 adfGeoTransform[0] = 0.0;
58 adfGeoTransform[1] = 1.0;
59 adfGeoTransform[2] = 0.0;
60 adfGeoTransform[3] = 0.0;
61 adfGeoTransform[4] = 0.0;
62 adfGeoTransform[5] = 1.0;
63 pszProjection = nullptr;
64 poMaskBand = nullptr;
65 bApplyNoDataArray = false;
66 poJP2Dataset = nullptr;
67 }
68
69 // ---------------------------------------------------------------------------
70 // ~GeoRasterDataset()
71 // ---------------------------------------------------------------------------
72
~GeoRasterDataset()73 GeoRasterDataset::~GeoRasterDataset()
74 {
75 GeoRasterDataset::FlushCache();
76
77 poGeoRaster->FlushMetadata();
78
79 delete poGeoRaster;
80
81 if( poMaskBand )
82 {
83 delete poMaskBand;
84 }
85
86 if( poJP2Dataset )
87 {
88 delete poJP2Dataset;
89 }
90
91 CPLFree( pszProjection );
92 CSLDestroy( papszSubdatasets );
93 }
94
95 // ---------------------------------------------------------------------------
96 // Identify()
97 // ---------------------------------------------------------------------------
98
Identify(GDALOpenInfo * poOpenInfo)99 int GeoRasterDataset::Identify( GDALOpenInfo* poOpenInfo )
100 {
101 // -------------------------------------------------------------------
102 // Verify georaster prefix
103 // -------------------------------------------------------------------
104
105 char* pszFilename = poOpenInfo->pszFilename;
106
107 if( STARTS_WITH_CI(pszFilename, "georaster:") == false &&
108 STARTS_WITH_CI(pszFilename, "geor:") == false )
109 {
110 return false;
111 }
112
113 return true;
114 }
115
116 // ---------------------------------------------------------------------------
117 // Open()
118 // ---------------------------------------------------------------------------
119
Open(GDALOpenInfo * poOpenInfo)120 GDALDataset* GeoRasterDataset::Open( GDALOpenInfo* poOpenInfo )
121 {
122 // -------------------------------------------------------------------
123 // It should not have an open file pointer.
124 // -------------------------------------------------------------------
125
126 if( poOpenInfo->fpL != nullptr )
127 {
128 return nullptr;
129 }
130
131 // -------------------------------------------------------------------
132 // Check identification string and usage
133 // -------------------------------------------------------------------
134
135 if( ! Identify( poOpenInfo ) )
136 {
137 return nullptr;
138 }
139
140 // -------------------------------------------------------------------
141 // Create a GeoRaster wrapper object
142 // -------------------------------------------------------------------
143
144 GeoRasterWrapper* poGRW = GeoRasterWrapper::Open(
145 poOpenInfo->pszFilename,
146 poOpenInfo->eAccess == GA_Update );
147
148 if( ! poGRW )
149 {
150 return nullptr;
151 }
152
153 // -------------------------------------------------------------------
154 // Create a corresponding GDALDataset
155 // -------------------------------------------------------------------
156
157 GeoRasterDataset *poGRD = new GeoRasterDataset();
158
159 if( ! poGRD )
160 {
161 return nullptr;
162 }
163
164 poGRD->eAccess = poOpenInfo->eAccess;
165 poGRD->poGeoRaster = poGRW;
166
167 // -------------------------------------------------------------------
168 // List Subdatasets
169 // -------------------------------------------------------------------
170
171 if( ! poGRW->bUniqueFound )
172 {
173 if( poGRD->eAccess == GA_ReadOnly )
174 {
175 poGRD->SetSubdatasets( poGRW );
176
177 if( CSLCount( poGRD->papszSubdatasets ) == 0 )
178 {
179 delete poGRD;
180 poGRD = nullptr;
181 }
182 }
183 return (GDALDataset*) poGRD;
184 }
185
186 // -------------------------------------------------------------------
187 // Assign GeoRaster information
188 // -------------------------------------------------------------------
189
190 poGRD->poGeoRaster = poGRW;
191 poGRD->nRasterXSize = poGRW->nRasterColumns;
192 poGRD->nRasterYSize = poGRW->nRasterRows;
193 poGRD->nBands = poGRW->nRasterBands;
194
195 if( poGRW->bIsReferenced )
196 {
197 poGRD->adfGeoTransform[1] = poGRW->dfXCoefficient[0];
198 poGRD->adfGeoTransform[2] = poGRW->dfXCoefficient[1];
199 poGRD->adfGeoTransform[0] = poGRW->dfXCoefficient[2];
200 poGRD->adfGeoTransform[4] = poGRW->dfYCoefficient[0];
201 poGRD->adfGeoTransform[5] = poGRW->dfYCoefficient[1];
202 poGRD->adfGeoTransform[3] = poGRW->dfYCoefficient[2];
203 }
204
205 // -------------------------------------------------------------------
206 // Copy RPC values to RPC metadata domain
207 // -------------------------------------------------------------------
208
209 if( poGRW->phRPC )
210 {
211 char **papszRPC_MD = RPCInfoV2ToMD( poGRW->phRPC );
212 char **papszSanitazed = nullptr;
213
214 int i = 0;
215 int n = CSLCount( papszRPC_MD );
216
217 for( i = 0; i < n; i++ )
218 {
219 if ( STARTS_WITH_CI(papszRPC_MD[i], "MIN_LAT") ||
220 STARTS_WITH_CI(papszRPC_MD[i], "MIN_LONG") ||
221 STARTS_WITH_CI(papszRPC_MD[i], "MAX_LAT") ||
222 STARTS_WITH_CI(papszRPC_MD[i], "MAX_LONG") )
223 {
224 continue;
225 }
226 papszSanitazed = CSLAddString( papszSanitazed, papszRPC_MD[i] );
227 }
228
229 poGRD->SetMetadata( papszSanitazed, "RPC" );
230
231 CSLDestroy( papszRPC_MD );
232 CSLDestroy( papszSanitazed );
233 }
234
235 // -------------------------------------------------------------------
236 // Open for JPEG 2000 compression for reading
237 // -------------------------------------------------------------------
238
239 if( EQUAL( poGRW->sCompressionType.c_str(), "JP2-F" ) &&
240 poGRD->eAccess == GA_ReadOnly )
241 {
242 poGRD->JP2_Open( poOpenInfo->eAccess );
243
244 if( ! poGRD->poJP2Dataset )
245 {
246 delete poGRD;
247 return nullptr;
248 }
249 }
250
251 // -------------------------------------------------------------------
252 // Load mask band
253 // -------------------------------------------------------------------
254
255 poGRW->bHasBitmapMask = EQUAL( "TRUE", CPLGetXMLValue( poGRW->phMetadata,
256 "layerInfo.objectLayer.bitmapMask", "FALSE" ) );
257
258 if( poGRW->bHasBitmapMask )
259 {
260 poGRD->poMaskBand = new GeoRasterRasterBand( poGRD, 0, DEFAULT_BMP_MASK );
261 }
262
263 // -------------------------------------------------------------------
264 // Check for filter Nodata environment variable, default is YES
265 // -------------------------------------------------------------------
266
267 const char *pszGEOR_FILTER_NODATA =
268 CPLGetConfigOption( "GEOR_FILTER_NODATA_VALUES", "NO" );
269
270 if( ! EQUAL(pszGEOR_FILTER_NODATA, "NO") )
271 {
272 poGRD->bApplyNoDataArray = true;
273 }
274
275 // -------------------------------------------------------------------
276 // Create bands
277 // -------------------------------------------------------------------
278
279 int i = 0;
280
281 for( i = 1; i <= poGRD->nBands; i++ )
282 {
283 poGRD->SetBand( i, new GeoRasterRasterBand( poGRD, i, 0 ,
284 poGRD->poJP2Dataset) );
285 }
286
287 // -------------------------------------------------------------------
288 // Set IMAGE_STRUCTURE metadata information
289 // -------------------------------------------------------------------
290
291 if( poGRW->nBandBlockSize == 1 )
292 {
293 poGRD->SetMetadataItem( "INTERLEAVE", "BSQ", "IMAGE_STRUCTURE" );
294 }
295 else
296 {
297 if( EQUAL( poGRW->sInterleaving.c_str(), "BSQ" ) )
298 {
299 poGRD->SetMetadataItem( "INTERLEAVE", "BSQ", "IMAGE_STRUCTURE" );
300 }
301 else if( EQUAL( poGRW->sInterleaving.c_str(), "BIP" ) )
302 {
303 poGRD->SetMetadataItem( "INTERLEAVE", "PIB", "IMAGE_STRUCTURE" );
304 }
305 else if( EQUAL( poGRW->sInterleaving.c_str(), "BIL" ) )
306 {
307 poGRD->SetMetadataItem( "INTERLEAVE", "BIL", "IMAGE_STRUCTURE" );
308 }
309 }
310
311 poGRD->SetMetadataItem( "COMPRESSION", CPLGetXMLValue( poGRW->phMetadata,
312 "rasterInfo.compression.type", "NONE" ), "IMAGE_STRUCTURE" );
313
314 if( STARTS_WITH_CI(poGRW->sCompressionType.c_str(), "JPEG") )
315 {
316 poGRD->SetMetadataItem( "COMPRESSION_QUALITY",
317 CPLGetXMLValue( poGRW->phMetadata,
318 "rasterInfo.compression.quality", "undefined" ), "IMAGE_STRUCTURE" );
319 }
320
321 if( EQUAL( poGRW->sCellDepth.c_str(), "1BIT" ) )
322 {
323 poGRD->SetMetadataItem( "NBITS", "1", "IMAGE_STRUCTURE" );
324 }
325
326 if( EQUAL( poGRW->sCellDepth.c_str(), "2BIT" ) )
327 {
328 poGRD->SetMetadataItem( "NBITS", "2", "IMAGE_STRUCTURE" );
329 }
330
331 if( EQUAL( poGRW->sCellDepth.c_str(), "4BIT" ) )
332 {
333 poGRD->SetMetadataItem( "NBITS", "4", "IMAGE_STRUCTURE" );
334 }
335
336 // -------------------------------------------------------------------
337 // Set Metadata on "ORACLE" domain
338 // -------------------------------------------------------------------
339
340 char* pszDoc = CPLSerializeXMLTree( poGRW->phMetadata );
341
342 poGRD->SetMetadataItem( "TABLE_NAME", CPLSPrintf( "%s%s",
343 poGRW->sSchema.c_str(),
344 poGRW->sTable.c_str()), "ORACLE" );
345
346 poGRD->SetMetadataItem( "COLUMN_NAME",
347 poGRW->sColumn.c_str(), "ORACLE" );
348
349 poGRD->SetMetadataItem( "RDT_TABLE_NAME",
350 poGRW->sDataTable.c_str(), "ORACLE" );
351
352 poGRD->SetMetadataItem( "RASTER_ID", CPLSPrintf( "%lld",
353 poGRW->nRasterId ), "ORACLE" );
354
355 poGRD->SetMetadataItem( "SRID", CPLSPrintf( "%lld",
356 poGRW->nSRID ), "ORACLE" );
357
358 poGRD->SetMetadataItem( "WKT", poGRW->sWKText.c_str(), "ORACLE" );
359
360 poGRD->SetMetadataItem( "COMPRESSION",
361 poGRW->sCompressionType.c_str(), "ORACLE" );
362
363 poGRD->SetMetadataItem( "METADATA", pszDoc, "ORACLE" );
364
365 CPLFree( pszDoc );
366
367 // -------------------------------------------------------------------
368 // Return a GDALDataset
369 // -------------------------------------------------------------------
370
371 return (GDALDataset*) poGRD;
372 }
373
374 // ---------------------------------------------------------------------------
375 // JP2Open()
376 // ---------------------------------------------------------------------------
377
JP2_Open(GDALAccess)378 void GeoRasterDataset::JP2_Open( GDALAccess /* eAccess */ )
379 {
380 GDALDriver* poJP2Driver = nullptr;
381
382 static const char * const apszDrivers[] = { "JP2OPENJPEG", "JP2ECW", "JP2MRSID",
383 "JPEG2000", "JP2KAK", nullptr };
384
385 // Find at least one available JP2 driver
386
387 for( int iDriver = 0; apszDrivers[iDriver] != nullptr; iDriver++ )
388 {
389 poJP2Driver = (GDALDriver*) GDALGetDriverByName(apszDrivers[iDriver]);
390
391 if( poJP2Driver )
392 {
393 break;
394 }
395 }
396
397 // If JP2 driver is installed, try to open the LOB via VSIOCILOB handler
398
399 poJP2Dataset = nullptr;
400
401 if( poJP2Driver )
402 {
403 CPLString osDSName;
404
405 osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
406 poGeoRaster->poConnection->GetUser(),
407 poGeoRaster->poConnection->GetPassword(),
408 poGeoRaster->poConnection->GetServer(),
409 poGeoRaster->sDataTable.c_str(),
410 poGeoRaster->nRasterId );
411
412 CPLPushErrorHandler( CPLQuietErrorHandler );
413
414 poJP2Dataset = (GDALDataset*) GDALOpenEx( osDSName.c_str(),
415 GDAL_OF_RASTER,
416 apszDrivers,
417 nullptr, nullptr );
418
419 CPLPopErrorHandler();
420
421 if( ! poJP2Dataset )
422 {
423 CPLString osLastErrorMsg(CPLGetLastErrorMsg());
424 CPLError( CE_Failure, CPLE_AppDefined,
425 "Unable to open JPEG2000 image within GeoRaster dataset.\n%s",
426 osLastErrorMsg.c_str() );
427 }
428 }
429 else
430 {
431 CPLError( CE_Failure, CPLE_AppDefined,
432 "Unable to open JPEG2000 image within GeoRaster dataset.\n%s",
433 "No JPEG2000 capable driver (JP2OPENJPEG, "
434 "JP2ECW, JP2MRSID, etc...) is available." );
435 }
436 }
437
438 // ---------------------------------------------------------------------------
439 // JP2CreateCopy()
440 // ---------------------------------------------------------------------------
441
JP2_CreateCopy(GDALDataset * poJP2DS,char ** papszOptions,int * pnResolutions,GDALProgressFunc pfnProgress,void * pProgressData)442 void GeoRasterDataset::JP2_CreateCopy( GDALDataset* poJP2DS,
443 char** papszOptions,
444 int* pnResolutions,
445 GDALProgressFunc pfnProgress,
446 void* pProgressData )
447 {
448 GDALDriver* poJP2Driver = nullptr;
449
450 static const char * const apszDrivers[] = { "JP2OPENJPEG", "JP2ECW", "JP2MRSID",
451 "JPEG2000", "JP2KAK", nullptr };
452
453 // Find at least one available JP2 driver
454
455 for( int iDriver = 0; apszDrivers[iDriver] != nullptr; iDriver++ )
456 {
457 poJP2Driver = (GDALDriver*) GDALGetDriverByName(apszDrivers[iDriver]);
458
459 if( poJP2Driver )
460 {
461 break;
462 }
463 }
464
465 // If a JP2 driver is installed calls driver's CreateCopy
466
467 poJP2Dataset = nullptr;
468
469 if( poJP2Driver )
470 {
471 char** papszOpt = nullptr;
472
473 const char* pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKXSIZE" );
474
475 if( pszFetched )
476 {
477 papszOpt = CSLAddNameValue( papszOpt, "BLOCKXSIZE", pszFetched );
478 papszOpt = CSLAddNameValue( papszOpt, "TILE_HEIGHT", pszFetched );
479 }
480
481 CPLDebug("GEOR","JP2_BLOCKXSIZE %s", pszFetched );
482
483 pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKYSIZE" );
484
485 if( pszFetched )
486 {
487 papszOpt = CSLAddNameValue( papszOpt, "BLOCKYSIZE", pszFetched );
488 papszOpt = CSLAddNameValue( papszOpt, "TILE_WIDTH", pszFetched );
489 }
490
491 pszFetched = CSLFetchNameValue( papszOptions, "JP2_QUALITY" );
492
493 if( pszFetched )
494 {
495 papszOpt = CSLAddNameValue( papszOpt, "QUALITY", pszFetched );
496
497 if( STARTS_WITH_CI( pszFetched, "100" ) )
498 {
499 papszOpt = CSLAddNameValue( papszOpt, "REVERSIBLE", "TRUE" );
500 }
501
502 poGeoRaster->nCompressQuality = atoi( pszFetched );
503 }
504 else
505 {
506 poGeoRaster->nCompressQuality = 25; // JP2OpenJPEG default...
507 }
508
509 pszFetched = CSLFetchNameValue( papszOptions, "JP2_REVERSIBLE" );
510
511 if( pszFetched )
512 {
513 papszOpt = CSLAddNameValue( papszOpt, "REVERSIBLE", pszFetched );
514 }
515
516 pszFetched = CSLFetchNameValue( papszOptions, "JP2_RESOLUTIONS" );
517
518 if( pszFetched )
519 {
520 papszOpt = CSLAddNameValue( papszOpt, "RESOLUTIONS", pszFetched );
521 papszOpt = CSLAddNameValue( papszOpt, "RESOLUTIONS_LEVELS", pszFetched );
522 papszOpt = CSLAddNameValue( papszOpt, "LAYERS", pszFetched );
523 }
524
525 pszFetched = CSLFetchNameValue( papszOptions, "JP2_PROGRESSION" );
526
527 if( pszFetched )
528 {
529 papszOpt = CSLAddNameValue( papszOpt, "PROGRESSION", pszFetched );
530 }
531
532 papszOpt = CSLAddNameValue( papszOpt, "CODEC", "JP2" );
533 papszOpt = CSLAddNameValue( papszOpt, "GeoJP2", "NO" );
534 papszOpt = CSLAddNameValue( papszOpt, "GMLJP2", "NO" );
535 papszOpt = CSLAddNameValue( papszOpt, "YCBCR420", "NO" );
536 papszOpt = CSLAddNameValue( papszOpt, "TARGET", "0" );
537
538 CPLPushErrorHandler( CPLQuietErrorHandler );
539
540 CPLString osDSName;
541
542 osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
543 poGeoRaster->poConnection->GetUser(),
544 poGeoRaster->poConnection->GetPassword(),
545 poGeoRaster->poConnection->GetServer(),
546 poGeoRaster->sDataTable.c_str(),
547 poGeoRaster->nRasterId );
548
549 poJP2Dataset = (GDALDataset*) GDALCreateCopy( poJP2Driver,
550 osDSName.c_str(),
551 poJP2DS,
552 false,
553 (char**) papszOpt,
554 pfnProgress,
555 pProgressData );
556
557 CPLPopErrorHandler();
558
559 CSLDestroy( papszOpt );
560
561 if( ! poJP2Dataset )
562 {
563 CPLString osLastErrorMsg(CPLGetLastErrorMsg());
564 CPLError( CE_Failure, CPLE_AppDefined,
565 "Unable to copy JPEG2000 image within GeoRaster dataset.\n%s",
566 osLastErrorMsg.c_str() );
567 return;
568 }
569 }
570 else
571 {
572 CPLError( CE_Failure, CPLE_AppDefined,
573 "Unable to copy JPEG2000 image within GeoRaster dataset.\n%s",
574 "No JPEG2000 capable driver (JP2OPENJPEG, "
575 "JP2ECW, JP2MRSID, etc...) is available." );
576 return;
577 }
578
579 // Retrieve the number of resolutions based on the number of overviews
580
581 CPLPushErrorHandler( CPLQuietErrorHandler );
582
583 *pnResolutions = poJP2Dataset->GetRasterBand(1)->GetOverviewCount() + 1;
584
585 delete poJP2Dataset;
586
587 CPLPopErrorHandler(); // Avoid showing warning regards writing aux.xml file
588
589 poJP2Dataset = nullptr;
590 }
591
592 // ---------------------------------------------------------------------------
593 // JP2_CopyDirect()
594 // ---------------------------------------------------------------------------
595
JP2_CopyDirect(const char * pszJP2Filename,int * pnResolutions,GDALProgressFunc pfnProgress,void * pProgressData)596 boolean GeoRasterDataset::JP2_CopyDirect( const char* pszJP2Filename,
597 int* pnResolutions,
598 GDALProgressFunc pfnProgress,
599 void* pProgressData )
600 {
601 char** papszFileList = GetFileList();
602
603 if( CSLCount(papszFileList) == 0 )
604 {
605 CSLDestroy( papszFileList );
606 return false;
607 }
608
609 VSILFILE *fpInput = VSIFOpenL( pszJP2Filename, "r" );
610 VSILFILE *fpOutput = VSIFOpenL( papszFileList[0], "wb" );
611
612 size_t nCache = (size_t) ( GDALGetCacheMax() * 0.25 );
613
614 void *pBuffer = (GByte*) VSIMalloc( sizeof(GByte) * nCache );
615
616 GDALJP2Box oBox( fpInput );
617
618 (void) oBox.ReadFirst();
619
620 GUInt32 nLBox;
621 GUInt32 nTBox;
622
623 int nBoxCount = 0;
624
625 while( strlen(oBox.GetType()) > 0 )
626 {
627 nBoxCount++;
628
629 if( EQUAL( oBox.GetType(), "jp " ) ||
630 EQUAL( oBox.GetType(), "ftyp" ) ||
631 EQUAL( oBox.GetType(), "jp2h" ) )
632 {
633 size_t nDataLength = (size_t) oBox.GetDataLength();
634
635 size_t nSize = VSIFReadL( pBuffer, 1, nDataLength, fpInput);
636
637 if ( nSize != nDataLength )
638 {
639 CPLError( CE_Warning, CPLE_AppDefined,
640 "amount read differs from JP2 Box data length" );
641 }
642
643 nLBox = CPL_MSBWORD32( (int) nDataLength + 8 );
644
645 memcpy( &nTBox, oBox.GetType(), 4 );
646
647 VSIFWriteL( &nLBox, 4, 1, fpOutput );
648 VSIFWriteL( &nTBox, 4, 1, fpOutput );
649 VSIFWriteL( pBuffer, 1, nSize, fpOutput );
650 }
651
652 if( EQUAL( oBox.GetType(), "jp2c" ) )
653 {
654 size_t nCount = 0;
655 size_t nSize = 0;
656 size_t nDataLength = oBox.GetDataLength();
657
658 nLBox = CPL_MSBWORD32( (int) nDataLength + 8 );
659
660 memcpy( &nTBox, oBox.GetType(), 4 );
661
662 VSIFWriteL( &nLBox, 4, 1, fpOutput );
663 VSIFWriteL( &nTBox, 4, 1, fpOutput );
664
665 while( nCount < nDataLength )
666 {
667 size_t nChunk = (size_t) MIN( nCache, nDataLength - nCount );
668
669 nSize = VSIFReadL( pBuffer, 1, nChunk, fpInput );
670
671 if ( nSize != nChunk )
672 {
673 CPLError( CE_Warning, CPLE_AppDefined,
674 "amount read differs from JP2 data length" );
675 }
676
677 VSIFWriteL( pBuffer, 1, nSize, fpOutput );
678
679 nCount += nSize;
680
681 pfnProgress( (float) nCount / (float) nDataLength,
682 nullptr, pProgressData );
683 }
684 }
685
686 if( ! oBox.ReadNext() )
687 {
688 break;
689 }
690 }
691
692 VSIFCloseL( fpInput );
693 VSIFCloseL( fpOutput );
694
695 CSLDestroy( papszFileList );
696 CPLFree( pBuffer );
697
698 // Retrieve the number of resolutions based on the number of overviews
699
700 JP2_Open( GA_ReadOnly );
701
702 if( poJP2Dataset )
703 {
704 *pnResolutions = poJP2Dataset->GetRasterBand(1)->GetOverviewCount() + 1;
705
706 delete poJP2Dataset;
707 poJP2Dataset = nullptr;
708 }
709
710 return (nBoxCount > 0);
711 }
712
713 // ---------------------------------------------------------------------------
714 // JPG_CopyDirect()
715 // ---------------------------------------------------------------------------
716
JPEG_CopyDirect(const char * pszJPGFilename,GDALProgressFunc pfnProgress,void * pProgressData)717 boolean GeoRasterDataset::JPEG_CopyDirect( const char* pszJPGFilename,
718 GDALProgressFunc pfnProgress,
719 void* pProgressData )
720 {
721 OWConnection* poConnection = poGeoRaster->poConnection;
722 OCILobLocator* poLocator;
723
724 OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
725 "select rasterblock from %s where rasterid = %lld "
726 "and rownum = 1 for update",
727 poGeoRaster->sDataTable.c_str(),
728 poGeoRaster->nRasterId ) );
729
730 poStmt->Define( &poLocator );
731
732 if( poStmt->Execute() )
733 {
734 VSILFILE *fpInput = VSIFOpenL( pszJPGFilename, "r" );
735
736 size_t nCache = (size_t) ( GDALGetCacheMax() * 0.25 );
737
738 void *pBuffer = (GByte*) VSIMalloc( sizeof(GByte) * nCache );
739
740 VSIFSeekL( fpInput, 0L, SEEK_END);
741
742 size_t nCount = 0;
743 const size_t nDataLength = VSIFTellL( fpInput );
744
745 VSIFSeekL( fpInput, 0L, SEEK_SET );
746
747 GUIntBig nCurOff = 0;
748
749 while( nCount < nDataLength )
750 {
751 size_t nChunk = (size_t) MIN( nCache, nDataLength - nCount );
752
753 size_t nSize = VSIFReadL( pBuffer, 1, nChunk, fpInput );
754
755 if ( nSize != nChunk )
756 {
757 CPLError( CE_Warning, CPLE_AppDefined,
758 "amount read differs from JPG length" );
759 }
760
761 const auto nWrite = poStmt->WriteBlob( poLocator,
762 (void*) pBuffer,
763 (nCurOff + 1),
764 nSize );
765
766 nCurOff += nWrite;
767 nCount += nSize;
768
769 pfnProgress( (float) nCount / (float) nDataLength,
770 nullptr, pProgressData );
771 }
772
773 VSIFCloseL( fpInput );
774
775 CPLFree( pBuffer );
776
777 delete poStmt;
778
779 return true;
780 }
781
782 if( poLocator )
783 {
784 OWStatement::Free( &poLocator, 1 );
785 }
786
787 delete poStmt;
788
789 return false;
790 }
791
792 // ---------------------------------------------------------------------------
793 // GetFileList()
794 // ---------------------------------------------------------------------------
795
GetFileList()796 char** GeoRasterDataset::GetFileList()
797 {
798 char** papszFileList = nullptr;
799
800 if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
801 {
802 CPLString osDSName;
803
804 osDSName.Printf( "/vsiocilob/%s,%s,%s,%s,%lld,noext",
805 this->poGeoRaster->poConnection->GetUser(),
806 this->poGeoRaster->poConnection->GetPassword(),
807 this->poGeoRaster->poConnection->GetServer(),
808 this->poGeoRaster->sDataTable.c_str(),
809 this->poGeoRaster->nRasterId );
810
811 papszFileList = CSLAddString( papszFileList, osDSName.c_str() );
812 }
813
814 return papszFileList;
815 }
816
817 // ---------------------------------------------------------------------------
818 // Create()
819 // ---------------------------------------------------------------------------
820
Create(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)821 GDALDataset *GeoRasterDataset::Create( const char *pszFilename,
822 int nXSize,
823 int nYSize,
824 int nBands,
825 GDALDataType eType,
826 char **papszOptions )
827 {
828 // -------------------------------------------------------------------
829 // Check for supported Data types
830 // -------------------------------------------------------------------
831
832 const char* pszCellDepth = OWSetDataType( eType );
833
834 if( EQUAL( pszCellDepth, "Unknown" ) )
835 {
836 CPLError( CE_Failure, CPLE_AppDefined,
837 "Attempt to create GeoRaster with unsupported data type (%s)",
838 GDALGetDataTypeName( eType ) );
839 return nullptr;
840 }
841
842 // -------------------------------------------------------------------
843 // Open the Dataset
844 // -------------------------------------------------------------------
845
846 GeoRasterDataset* poGRD = (GeoRasterDataset*) GDALOpen( pszFilename, GA_Update );
847
848 if( ! poGRD )
849 {
850 return nullptr;
851 }
852
853 // -------------------------------------------------------------------
854 // Get the GeoRaster
855 // -------------------------------------------------------------------
856
857 GeoRasterWrapper* poGRW = poGRD->poGeoRaster;
858
859 if( ! poGRW )
860 {
861 delete poGRD;
862 return nullptr;
863 }
864
865 // -------------------------------------------------------------------
866 // Set basic information and default values
867 // -------------------------------------------------------------------
868
869 poGRW->nRasterColumns = nXSize;
870 poGRW->nRasterRows = nYSize;
871 poGRW->nRasterBands = nBands;
872 poGRW->sCellDepth = pszCellDepth;
873 poGRW->nRowBlockSize = DEFAULT_BLOCK_ROWS;
874 poGRW->nColumnBlockSize = DEFAULT_BLOCK_COLUMNS;
875 poGRW->nBandBlockSize = 1;
876
877 if( poGRW->bUniqueFound )
878 {
879 poGRW->PrepareToOverwrite();
880 }
881
882 // -------------------------------------------------------------------
883 // Check the create options to use in initialization
884 // -------------------------------------------------------------------
885
886 const char* pszFetched = "";
887 CPLCharUniquePtr pszDescription;
888 CPLCharUniquePtr pszInsert;
889 int nQuality = -1;
890
891 if( ! poGRW->sTable.empty() )
892 {
893 pszFetched = CSLFetchNameValue( papszOptions, "DESCRIPTION" );
894
895 if( pszFetched )
896 {
897 pszDescription.reset(CPLStrdup( pszFetched ));
898 }
899 }
900
901 if( poGRW->sTable.empty() )
902 {
903 poGRW->sTable = "GDAL_IMPORT";
904 poGRW->sDataTable = "GDAL_RDT";
905 }
906
907 if( poGRW->sColumn.empty() )
908 {
909 poGRW->sColumn = "RASTER";
910 }
911
912 pszFetched = CSLFetchNameValue( papszOptions, "INSERT" );
913
914 if( pszFetched )
915 {
916 pszInsert.reset(CPLStrdup( pszFetched ));
917 }
918
919 pszFetched = CSLFetchNameValue( papszOptions, "BLOCKXSIZE" );
920
921 if( pszFetched )
922 {
923 poGRW->nColumnBlockSize = atoi( pszFetched );
924 }
925
926 pszFetched = CSLFetchNameValue( papszOptions, "BLOCKYSIZE" );
927
928 if( pszFetched )
929 {
930 poGRW->nRowBlockSize = atoi( pszFetched );
931 }
932
933 pszFetched = CSLFetchNameValue( papszOptions, "NBITS" );
934
935 if( pszFetched != nullptr )
936 {
937 poGRW->sCellDepth = CPLSPrintf( "%dBIT", atoi( pszFetched ) );
938 }
939
940 pszFetched = CSLFetchNameValue( papszOptions, "COMPRESS" );
941
942 if( pszFetched != nullptr &&
943 ( EQUAL( pszFetched, "JPEG-F" ) ||
944 EQUAL( pszFetched, "JP2-F" ) ||
945 EQUAL( pszFetched, "DEFLATE" ) ) )
946 {
947 poGRW->sCompressionType = pszFetched;
948 }
949 else
950 {
951 poGRW->sCompressionType = "NONE";
952 }
953
954 pszFetched = CSLFetchNameValue( papszOptions, "QUALITY" );
955
956 if( pszFetched )
957 {
958 poGRW->nCompressQuality = atoi( pszFetched );
959 nQuality = poGRW->nCompressQuality;
960 }
961
962 pszFetched = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
963
964 bool bInterleve_ind = false;
965
966 if( pszFetched )
967 {
968 bInterleve_ind = true;
969
970 if( EQUAL( pszFetched, "BAND" ) || EQUAL( pszFetched, "BSQ" ) )
971 {
972 poGRW->sInterleaving = "BSQ";
973 }
974 if( EQUAL( pszFetched, "LINE" ) || EQUAL( pszFetched, "BIL" ) )
975 {
976 poGRW->sInterleaving = "BIL";
977 }
978 if( EQUAL( pszFetched, "PIXEL" ) || EQUAL( pszFetched, "BIP" ) )
979 {
980 poGRW->sInterleaving = "BIP";
981 }
982 }
983 else
984 {
985 if( EQUAL( poGRW->sCompressionType.c_str(), "NONE" ) == false )
986 {
987 poGRW->sInterleaving = "BIP";
988 }
989 }
990
991 pszFetched = CSLFetchNameValue( papszOptions, "BLOCKBSIZE" );
992
993 if( pszFetched )
994 {
995 poGRW->nBandBlockSize = atoi( pszFetched );
996 }
997 else
998 {
999 if( nBands == 3 || nBands == 4 )
1000 {
1001 poGRW->nBandBlockSize = nBands;
1002 }
1003 }
1004
1005 if( bInterleve_ind == false &&
1006 ( poGRW->nBandBlockSize == 3 || poGRW->nBandBlockSize == 4 ) )
1007 {
1008 poGRW->sInterleaving = "BIP";
1009 }
1010
1011 if( STARTS_WITH_CI(poGRW->sCompressionType.c_str(), "JPEG") )
1012 {
1013 if( ! EQUAL( poGRW->sInterleaving.c_str(), "BIP" ) )
1014 {
1015 CPLError( CE_Warning, CPLE_IllegalArg,
1016 "compress=JPEG assumes interleave=BIP" );
1017 poGRW->sInterleaving = "BIP";
1018 }
1019 }
1020
1021 pszFetched = CSLFetchNameValue( papszOptions, "BLOCKING" );
1022
1023 if( pszFetched )
1024 {
1025 if( EQUAL( pszFetched, "NO" ) )
1026 {
1027 poGRW->bBlocking = false;
1028 }
1029
1030 if( EQUAL( pszFetched, "OPTIMALPADDING" ) )
1031 {
1032 if( poGRW->poConnection->GetVersion() < 11 )
1033 {
1034 CPLError( CE_Warning, CPLE_IllegalArg,
1035 "BLOCKING=OPTIMALPADDING not supported on Oracle older than 11g" );
1036 }
1037 else
1038 {
1039 poGRW->bAutoBlocking = true;
1040 poGRW->bBlocking = true;
1041 }
1042 }
1043 }
1044
1045 // -------------------------------------------------------------------
1046 // Validate options
1047 // -------------------------------------------------------------------
1048
1049 if( pszDescription.get() && poGRW->bUniqueFound )
1050 {
1051 CPLError( CE_Failure, CPLE_IllegalArg,
1052 "Option (DESCRIPTION) cannot be used on a existing GeoRaster." );
1053 delete poGRD;
1054 return nullptr;
1055 }
1056
1057 if( pszInsert && poGRW->bUniqueFound )
1058 {
1059 CPLError( CE_Failure, CPLE_IllegalArg,
1060 "Option (INSERT) cannot be used on a existing GeoRaster." );
1061 delete poGRD;
1062 return nullptr;
1063 }
1064
1065 /* Compression JPEG-B is deprecated. It should be able to read but not
1066 * to create new GeoRaster on databases with that compression option.
1067 *
1068 * TODO: Remove that options on next release.
1069 */
1070
1071 if( EQUAL( poGRW->sCompressionType.c_str(), "JPEG-B" ) )
1072 {
1073 CPLError( CE_Failure, CPLE_IllegalArg,
1074 "Option (COMPRESS=%s) is deprecated and cannot be used.",
1075 poGRW->sCompressionType.c_str() );
1076 delete poGRD;
1077 return nullptr;
1078 }
1079
1080 if( EQUAL( poGRW->sCompressionType.c_str(), "JPEG-F" ) )
1081 {
1082 /* JPEG-F can only compress byte data type
1083 */
1084 if( eType != GDT_Byte )
1085 {
1086 CPLError( CE_Failure, CPLE_IllegalArg,
1087 "Option (COMPRESS=%s) can only be used with Byte data type.",
1088 poGRW->sCompressionType.c_str() );
1089 delete poGRD;
1090 return nullptr;
1091 }
1092
1093 /* JPEG-F can compress one band per block or 3 for RGB
1094 * or 4 for RGBA.
1095 */
1096 if( ( poGRW->nBandBlockSize != 1 &&
1097 poGRW->nBandBlockSize != 3 &&
1098 poGRW->nBandBlockSize != 4 ) ||
1099 ( ( poGRW->nBandBlockSize != 1 &&
1100 ( poGRW->nBandBlockSize != poGRW->nRasterBands ) ) ) )
1101 {
1102 CPLError( CE_Failure, CPLE_IllegalArg,
1103 "Option (COMPRESS=%s) requires BLOCKBSIZE to be 1 (for any "
1104 "number of bands), 3 (for 3 bands RGB) and 4 (for 4 bands RGBA).",
1105 poGRW->sCompressionType.c_str() );
1106 delete poGRD;
1107 return nullptr;
1108 }
1109
1110 // There is a limit on how big a compressed block can be.
1111 if( ( poGRW->nColumnBlockSize *
1112 poGRW->nRowBlockSize *
1113 poGRW->nBandBlockSize *
1114 ( GDALGetDataTypeSize( eType ) / 8 ) ) > ( 50 * 1024 * 1024 ) )
1115 {
1116 CPLError( CE_Failure, CPLE_IllegalArg,
1117 "Option (COMPRESS=%s) each data block must not exceed 50Mb. "
1118 "Consider reducing BLOCK{X,Y,B}XSIZE.",
1119 poGRW->sCompressionType.c_str() );
1120 delete poGRD;
1121 return nullptr;
1122 }
1123 }
1124
1125 if( EQUAL( poGRW->sCompressionType.c_str(), "DEFLATE" ) )
1126 {
1127 if( ( poGRW->nColumnBlockSize *
1128 poGRW->nRowBlockSize *
1129 poGRW->nBandBlockSize *
1130 ( GDALGetDataTypeSize( eType ) / 8 ) ) > ( 1024 * 1024 * 1024 ) )
1131 {
1132 CPLError( CE_Failure, CPLE_IllegalArg,
1133 "For (COMPRESS=%s) each data block must not exceed 1Gb. "
1134 "Consider reducing BLOCK{X,Y,B}XSIZE.",
1135 poGRW->sCompressionType.c_str() );
1136 delete poGRD;
1137 return nullptr;
1138 }
1139 }
1140
1141 // When the compression is JP2-F it should be just one block
1142
1143 if( EQUAL( poGRW->sCompressionType.c_str(), "JP2-F" ) )
1144 {
1145 poGRW->nRowBlockSize = poGRW->nRasterRows;
1146 poGRW->nColumnBlockSize = poGRW->nRasterColumns;
1147 poGRW->nBandBlockSize = poGRW->nRasterBands;
1148 poGRW->bBlocking = false;
1149 }
1150
1151 pszFetched = CSLFetchNameValue( papszOptions, "OBJECTTABLE" );
1152
1153 if( pszFetched )
1154 {
1155 int nVersion = poGRW->poConnection->GetVersion();
1156 if( nVersion <= 11 )
1157 {
1158 CPLError( CE_Failure, CPLE_IllegalArg,
1159 "Driver create-option OBJECTTABLE not "
1160 "supported on Oracle %d", nVersion );
1161 delete poGRD;
1162 return nullptr;
1163 }
1164 }
1165
1166 poGRD->poGeoRaster->bCreateObjectTable =
1167 CPLFetchBool( papszOptions, "OBJECTTABLE", false );
1168
1169 // -------------------------------------------------------------------
1170 // Create a SDO_GEORASTER object on the server
1171 // -------------------------------------------------------------------
1172
1173 const bool bSuccess = poGRW->Create( pszDescription.get(), pszInsert.get(), poGRW->bUniqueFound );
1174
1175 if( ! bSuccess )
1176 {
1177 delete poGRD;
1178 return nullptr;
1179 }
1180
1181 // -------------------------------------------------------------------
1182 // Prepare an identification string
1183 // -------------------------------------------------------------------
1184
1185 char szStringId[OWTEXT];
1186
1187 snprintf( szStringId, sizeof(szStringId), "georaster:%s,%s,%s,%s,%lld",
1188 poGRW->poConnection->GetUser(),
1189 poGRW->poConnection->GetPassword(),
1190 poGRW->poConnection->GetServer(),
1191 poGRW->sDataTable.c_str(),
1192 poGRW->nRasterId );
1193
1194 delete poGRD;
1195
1196 poGRD = (GeoRasterDataset*) GDALOpen( szStringId, GA_Update );
1197
1198 if( ! poGRD )
1199 {
1200 return nullptr;
1201 }
1202
1203 // -------------------------------------------------------------------
1204 // Load additional options
1205 // -------------------------------------------------------------------
1206
1207 pszFetched = CSLFetchNameValue( papszOptions, "VATNAME" );
1208
1209 if( pszFetched )
1210 {
1211 poGRW->sValueAttributeTab = pszFetched;
1212 }
1213
1214 pszFetched = CSLFetchNameValue( papszOptions, "SRID" );
1215
1216 if( pszFetched )
1217 {
1218 poGRD->bForcedSRID = true;
1219 poGRD->poGeoRaster->SetGeoReference( atoi( pszFetched ) );
1220 }
1221
1222 poGRD->poGeoRaster->bGenSpatialExtent =
1223 CPLFetchBool( papszOptions, "SPATIALEXTENT", TRUE );
1224
1225 pszFetched = CSLFetchNameValue( papszOptions, "EXTENTSRID" );
1226
1227 if( pszFetched )
1228 {
1229 poGRD->poGeoRaster->nExtentSRID = atoi( pszFetched );
1230 }
1231
1232 pszFetched = CSLFetchNameValue( papszOptions, "COORDLOCATION" );
1233
1234 if( pszFetched )
1235 {
1236 if( EQUAL( pszFetched, "CENTER" ) )
1237 {
1238 poGRD->poGeoRaster->eModelCoordLocation = MCL_CENTER;
1239 }
1240 else if( EQUAL( pszFetched, "UPPERLEFT" ) )
1241 {
1242 poGRD->poGeoRaster->eModelCoordLocation = MCL_UPPERLEFT;
1243 }
1244 else
1245 {
1246 CPLError( CE_Warning, CPLE_IllegalArg,
1247 "Incorrect COORDLOCATION (%s)", pszFetched );
1248 }
1249 }
1250
1251 if ( nQuality > 0 )
1252 {
1253 poGRD->poGeoRaster->nCompressQuality = nQuality;
1254 }
1255
1256 pszFetched = CSLFetchNameValue( papszOptions, "GENPYRAMID" );
1257
1258 if( pszFetched != nullptr )
1259 {
1260 if (!(EQUAL(pszFetched, "NN") ||
1261 EQUAL(pszFetched, "BILINEAR") ||
1262 EQUAL(pszFetched, "BIQUADRATIC") ||
1263 EQUAL(pszFetched, "CUBIC") ||
1264 EQUAL(pszFetched, "AVERAGE4") ||
1265 EQUAL(pszFetched, "AVERAGE16")))
1266 {
1267 CPLError( CE_Warning, CPLE_IllegalArg, "Wrong resample method for pyramid (%s)", pszFetched);
1268 }
1269
1270 poGRD->poGeoRaster->bGenPyramid = true;
1271 poGRD->poGeoRaster->sPyramidResampling = pszFetched;
1272 }
1273
1274 pszFetched = CSLFetchNameValue( papszOptions, "GENPYRLEVELS" );
1275
1276 if( pszFetched != nullptr )
1277 {
1278 poGRD->poGeoRaster->bGenPyramid = true;
1279 poGRD->poGeoRaster->nPyramidLevels = atoi(pszFetched);
1280 }
1281
1282 // -------------------------------------------------------------------
1283 // Return a new Dataset
1284 // -------------------------------------------------------------------
1285
1286 return (GDALDataset*) poGRD;
1287 }
1288
1289 // ---------------------------------------------------------------------------
1290 // CreateCopy()
1291 // ---------------------------------------------------------------------------
1292
CreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1293 GDALDataset *GeoRasterDataset::CreateCopy( const char* pszFilename,
1294 GDALDataset* poSrcDS,
1295 int bStrict,
1296 char** papszOptions,
1297 GDALProgressFunc pfnProgress,
1298 void* pProgressData )
1299 {
1300 (void) bStrict;
1301
1302 int nBands = poSrcDS->GetRasterCount();
1303 if (nBands == 0)
1304 {
1305 CPLError( CE_Failure, CPLE_NotSupported,
1306 "GeoRaster driver does not support source dataset with zero band.\n");
1307 return nullptr;
1308 }
1309
1310 GDALRasterBand* poBand = poSrcDS->GetRasterBand( 1 );
1311 GDALDataType eType = poBand->GetRasterDataType();
1312
1313 // -----------------------------------------------------------
1314 // Create a GeoRaster on the server or select one to overwrite
1315 // -----------------------------------------------------------
1316
1317 GeoRasterDataset *poDstDS =
1318 (GeoRasterDataset *) GeoRasterDataset::Create(
1319 pszFilename,
1320 poSrcDS->GetRasterXSize(),
1321 poSrcDS->GetRasterYSize(),
1322 poSrcDS->GetRasterCount(),
1323 eType, papszOptions );
1324
1325 if( poDstDS == nullptr )
1326 {
1327 return nullptr;
1328 }
1329
1330 // -----------------------------------------------------------
1331 // Copy information to the dataset
1332 // -----------------------------------------------------------
1333
1334 double adfTransform[6];
1335
1336 if ( poSrcDS->GetGeoTransform( adfTransform ) == CE_None )
1337 {
1338 if ( ! ( adfTransform[0] == 0.0 &&
1339 adfTransform[1] == 1.0 &&
1340 adfTransform[2] == 0.0 &&
1341 adfTransform[3] == 0.0 &&
1342 adfTransform[4] == 0.0 &&
1343 adfTransform[5] == 1.0 ) )
1344 {
1345 poDstDS->SetGeoTransform( adfTransform );
1346
1347 if( ! poDstDS->bForcedSRID ) /* forced by create option SRID */
1348 {
1349 poDstDS->SetSpatialRef( poSrcDS->GetSpatialRef() );
1350 }
1351 }
1352 }
1353
1354 // --------------------------------------------------------------------
1355 // Copy GCPs
1356 // --------------------------------------------------------------------
1357
1358 if( poSrcDS->GetGCPCount() > 0 )
1359 {
1360 poDstDS->SetGCPs( poSrcDS->GetGCPCount(),
1361 poSrcDS->GetGCPs(),
1362 poSrcDS->GetGCPSpatialRef() );
1363 }
1364
1365 // --------------------------------------------------------------------
1366 // Copy RPC
1367 // --------------------------------------------------------------------
1368
1369 char **papszRPCMetadata = GDALGetMetadata( poSrcDS, "RPC" );
1370
1371 if ( papszRPCMetadata != nullptr )
1372 {
1373 poDstDS->poGeoRaster->phRPC = (GDALRPCInfoV2*) VSICalloc( 1, sizeof(GDALRPCInfoV2) );
1374 CPL_IGNORE_RET_VAL(
1375 GDALExtractRPCInfoV2( papszRPCMetadata, poDstDS->poGeoRaster->phRPC ));
1376 }
1377
1378 // --------------------------------------------------------------------
1379 // Copy information to the raster bands
1380 // --------------------------------------------------------------------
1381
1382 for( int iBand = 1; iBand <= poSrcDS->GetRasterCount(); iBand++ )
1383 {
1384 GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand( iBand );
1385 GeoRasterRasterBand* poDstBand = (GeoRasterRasterBand*)
1386 poDstDS->GetRasterBand( iBand );
1387
1388 // ----------------------------------------------------------------
1389 // Copy Color Table
1390 // ----------------------------------------------------------------
1391
1392 GDALColorTable* poColorTable = poSrcBand->GetColorTable();
1393
1394 if( poColorTable )
1395 {
1396 poDstBand->SetColorTable( poColorTable );
1397 }
1398
1399 // ----------------------------------------------------------------
1400 // Copy statistics information, without median and mode.
1401 // ----------------------------------------------------------------
1402
1403 {
1404 double dfMin = 0.0;
1405 double dfMax = 0.0;
1406 double dfMean = 0.0;
1407 double dfStdDev = 0.0;
1408 if( poSrcBand->GetStatistics( false, false, &dfMin, &dfMax,
1409 &dfMean, &dfStdDev ) == CE_None )
1410 {
1411 poDstBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
1412
1413 /* That will not be recorded in the GeoRaster metadata since it
1414 * doesn't have median and mode, so those values are only useful
1415 * at runtime.
1416 */
1417 }
1418 }
1419
1420 // ----------------------------------------------------------------
1421 // Copy statistics metadata information, including median and mode.
1422 // ----------------------------------------------------------------
1423
1424 const char *pszMin = poSrcBand->GetMetadataItem( "STATISTICS_MINIMUM" );
1425 const char *pszMax = poSrcBand->GetMetadataItem( "STATISTICS_MAXIMUM" );
1426 const char *pszMean = poSrcBand->GetMetadataItem( "STATISTICS_MEAN" );
1427 const char *pszMedian = poSrcBand->GetMetadataItem( "STATISTICS_MEDIAN" );
1428 const char *pszMode = poSrcBand->GetMetadataItem( "STATISTICS_MODE" );
1429 const char *pszStdDev = poSrcBand->GetMetadataItem( "STATISTICS_STDDEV" );
1430 const char *pszSkipFX = poSrcBand->GetMetadataItem( "STATISTICS_SKIPFACTORX" );
1431 const char *pszSkipFY = poSrcBand->GetMetadataItem( "STATISTICS_SKIPFACTORY" );
1432
1433 if ( pszMin != nullptr && pszMax != nullptr && pszMean != nullptr &&
1434 pszMedian != nullptr && pszMode != nullptr && pszStdDev != nullptr )
1435 {
1436 const double dfMin = CPLScanDouble( pszMin, MAX_DOUBLE_STR_REP );
1437 const double dfMax = CPLScanDouble( pszMax, MAX_DOUBLE_STR_REP );
1438 const double dfMean = CPLScanDouble( pszMean, MAX_DOUBLE_STR_REP );
1439 const double dfMedian = CPLScanDouble( pszMedian, MAX_DOUBLE_STR_REP );
1440 const double dfMode = CPLScanDouble( pszMode, MAX_DOUBLE_STR_REP );
1441
1442 if ( ! ( ( dfMin > dfMax ) ||
1443 ( dfMean > dfMax ) || ( dfMean < dfMin ) ||
1444 ( dfMedian > dfMax ) || ( dfMedian < dfMin ) ||
1445 ( dfMode > dfMax ) || ( dfMode < dfMin ) ) )
1446 {
1447 if ( ! pszSkipFX )
1448 {
1449 pszSkipFX = pszSkipFY != nullptr ? pszSkipFY : "1";
1450 }
1451
1452 poDstBand->poGeoRaster->SetStatistics( iBand,
1453 pszMin, pszMax, pszMean,
1454 pszMedian, pszMode,
1455 pszStdDev, pszSkipFX );
1456 }
1457 }
1458
1459 // ----------------------------------------------------------------
1460 // Copy Raster Attribute Table (RAT)
1461 // ----------------------------------------------------------------
1462
1463 GDALRasterAttributeTableH poRAT = GDALGetDefaultRAT( poSrcBand );
1464
1465 if( poRAT != nullptr )
1466 {
1467 poDstBand->SetDefaultRAT( (GDALRasterAttributeTable*) poRAT );
1468 }
1469
1470 // ----------------------------------------------------------------
1471 // Copy NoData Value
1472 // ----------------------------------------------------------------
1473 int bHasNoDataValue = FALSE;
1474 const double dfNoDataValue = poSrcBand->GetNoDataValue( &bHasNoDataValue );
1475
1476 if( bHasNoDataValue )
1477 {
1478 poDstBand->SetNoDataValue( dfNoDataValue );
1479 }
1480 }
1481
1482 // --------------------------------------------------------------------
1483 // Copy actual imagery.
1484 // --------------------------------------------------------------------
1485
1486 int nXSize = poDstDS->GetRasterXSize();
1487 int nYSize = poDstDS->GetRasterYSize();
1488
1489 int nBlockXSize = 0;
1490 int nBlockYSize = 0;
1491
1492 poDstDS->GetRasterBand( 1 )->GetBlockSize( &nBlockXSize, &nBlockYSize );
1493
1494 // --------------------------------------------------------------------
1495 // JP2-F has one block with full image size. Use tile size instead
1496 // --------------------------------------------------------------------
1497
1498 const char* pszFetched = CSLFetchNameValue( papszOptions, "COMPRESS" );
1499
1500 if( pszFetched != nullptr && EQUAL( pszFetched, "JP2-F" ) )
1501 {
1502 nBlockXSize = DEFAULT_JP2_TILE_COLUMNS;
1503 nBlockYSize = DEFAULT_JP2_TILE_ROWS;
1504 pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKXSIZE" );
1505 if( pszFetched != nullptr )
1506 {
1507 nBlockXSize = atoi( pszFetched );
1508 }
1509 pszFetched = CSLFetchNameValue( papszOptions, "JP2_BLOCKYSIZE" );
1510 if( pszFetched != nullptr )
1511 {
1512 nBlockYSize = atoi( pszFetched );
1513 }
1514 }
1515
1516 // --------------------------------------------------------------------
1517 // Allocate memory buffer to read one block from one band
1518 // --------------------------------------------------------------------
1519
1520 void *pData = VSI_MALLOC3_VERBOSE( nBlockXSize, nBlockYSize,
1521 GDALGetDataTypeSizeBytes(eType) );
1522
1523 if( pData == nullptr )
1524 {
1525 delete poDstDS;
1526 return nullptr;
1527 }
1528
1529 CPLErr eErr = CE_None;
1530
1531 int nPixelSize = GDALGetDataTypeSize(
1532 poSrcDS->GetRasterBand(1)->GetRasterDataType() ) / 8;
1533
1534 if( EQUAL( poDstDS->poGeoRaster->sCompressionType.c_str(), "JPEG-F" ) &&
1535 nBlockXSize == nXSize && nBlockYSize == nYSize )
1536 {
1537 // --------------------------------------------------------------------
1538 // Load JPEG avoiding decompression/compression - direct copy
1539 // --------------------------------------------------------------------
1540
1541 const char* pszDriverName = poSrcDS->GetDriverName();
1542
1543 if ( EQUAL( pszDriverName, "JPEG" ) )
1544 {
1545 char** papszFileList = poSrcDS->GetFileList();
1546
1547 if ( poDstDS->JPEG_CopyDirect( papszFileList[0],
1548 pfnProgress,
1549 pProgressData ) )
1550 {
1551 CPLDebug("GEOR","JPEG Direct copy succeed");
1552 }
1553 }
1554
1555 }
1556 else if( EQUAL( poDstDS->poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
1557 {
1558 // --------------------------------------------------------------------
1559 // Load JP2K avoiding decompression/compression - direct copy
1560 // --------------------------------------------------------------------
1561
1562 boolean bJP2CopyDirectSucceed = false;
1563
1564 const char* pszDriverName = poSrcDS->GetDriverName();
1565
1566 int nJP2Resolution = -1;
1567
1568 if ( EQUAL( pszDriverName, "JP2OpenJPEG" ) &&
1569 poSrcDS->GetRasterBand(1)->GetColorTable() == nullptr )
1570 {
1571 // ---------------------------------------------------------------
1572 // Try to load the JP2 file directly
1573 // ---------------------------------------------------------------
1574
1575 char** papszFileList = poSrcDS->GetFileList();
1576
1577 bJP2CopyDirectSucceed = poDstDS->JP2_CopyDirect( papszFileList[0],
1578 &nJP2Resolution,
1579 pfnProgress,
1580 pProgressData );
1581
1582 }
1583
1584 if( ! bJP2CopyDirectSucceed )
1585 {
1586 // ---------------------------------------------------------------
1587 // Use VSIOCILOB to load using a resident JP2 driver
1588 // ---------------------------------------------------------------
1589
1590 poDstDS->JP2_CreateCopy( poSrcDS, /* JP2 dataset */
1591 papszOptions, /* options list */
1592 &nJP2Resolution, /* returned resolution */
1593 pfnProgress, /* progress function */
1594 pProgressData ); /* progress data */
1595
1596 }
1597
1598 // Number of pyramid levels is the number of resolutions - 1
1599
1600 poDstDS->poGeoRaster->SetMaxLevel( MAX( 1, nJP2Resolution - 1 ) );
1601 }
1602 else if( poDstDS->poGeoRaster->nBandBlockSize == 1)
1603 {
1604 // ----------------------------------------------------------------
1605 // Band order
1606 // ----------------------------------------------------------------
1607
1608 int nBandCount = poSrcDS->GetRasterCount();
1609
1610 for( int iBand = 1; iBand <= nBandCount; iBand++ )
1611 {
1612 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );
1613 GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
1614
1615 for( int iYOffset = 0, iYBlock = 0;
1616 iYOffset < nYSize;
1617 iYOffset += nBlockYSize, iYBlock++ )
1618 {
1619 const int nBlockRows = MIN( nBlockYSize, nYSize - iYOffset );
1620 for( int iXOffset = 0, iXBlock = 0;
1621 iXOffset < nXSize;
1622 iXOffset += nBlockXSize, iXBlock++ )
1623 {
1624
1625 const int nBlockCols = MIN( nBlockXSize, nXSize - iXOffset );
1626
1627 eErr = poSrcBand->RasterIO( GF_Read,
1628 iXOffset, iYOffset,
1629 nBlockCols, nBlockRows, pData,
1630 nBlockCols, nBlockRows, eType,
1631 nPixelSize,
1632 nPixelSize * nBlockXSize, nullptr );
1633
1634 if( eErr != CE_None )
1635 {
1636 return nullptr;
1637 }
1638
1639 eErr = poDstBand->WriteBlock( iXBlock, iYBlock, pData );
1640
1641 if( eErr != CE_None )
1642 {
1643 return nullptr;
1644 }
1645 }
1646
1647 if( ( eErr == CE_None ) && ( ! pfnProgress(
1648 ( ( iBand - 1) / (float) nBandCount ) +
1649 ( iYOffset + nBlockRows ) / (float) (nYSize * nBandCount),
1650 nullptr, pProgressData ) ) )
1651 {
1652 eErr = CE_Failure;
1653 CPLError( CE_Failure, CPLE_UserInterrupt,
1654 "User terminated CreateCopy()" );
1655 }
1656 }
1657 }
1658 }
1659 else
1660 {
1661 // ----------------------------------------------------------------
1662 // Block order
1663 // ----------------------------------------------------------------
1664
1665 poDstDS->poGeoRaster->SetWriteOnly( true );
1666
1667 for( int iYOffset = 0, iYBlock = 0;
1668 iYOffset < nYSize;
1669 iYOffset += nBlockYSize, iYBlock++ )
1670 {
1671 const int nBlockRows = MIN( nBlockYSize, nYSize - iYOffset );
1672 for( int iXOffset = 0, iXBlock = 0;
1673 iXOffset < nXSize;
1674 iXOffset += nBlockXSize, iXBlock++ )
1675 {
1676 const int nBlockCols = MIN( nBlockXSize, nXSize - iXOffset );
1677
1678 for( int iBand = 1;
1679 iBand <= poSrcDS->GetRasterCount();
1680 iBand++ )
1681 {
1682 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );
1683 GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
1684
1685 eErr = poSrcBand->RasterIO( GF_Read,
1686 iXOffset, iYOffset,
1687 nBlockCols, nBlockRows, pData,
1688 nBlockCols, nBlockRows, eType,
1689 nPixelSize,
1690 nPixelSize * nBlockXSize, nullptr );
1691
1692 if( eErr != CE_None )
1693 {
1694 return nullptr;
1695 }
1696
1697 eErr = poDstBand->WriteBlock( iXBlock, iYBlock, pData );
1698
1699 if( eErr != CE_None )
1700 {
1701 return nullptr;
1702 }
1703 }
1704 }
1705
1706 if( ( eErr == CE_None ) && ( ! pfnProgress(
1707 ( iYOffset + nBlockRows ) / (double) nYSize, nullptr,
1708 pProgressData ) ) )
1709 {
1710 eErr = CE_Failure;
1711 CPLError( CE_Failure, CPLE_UserInterrupt,
1712 "User terminated CreateCopy()" );
1713 }
1714 }
1715 }
1716
1717 CPLFree( pData );
1718
1719 // --------------------------------------------------------------------
1720 // Finalize
1721 // --------------------------------------------------------------------
1722
1723 poDstDS->FlushCache();
1724
1725 if( pfnProgress )
1726 {
1727 CPLDebug("GEOR", "Output dataset: (georaster:%s/%s@%s,%s,%lld) on %s%s,%s",
1728 poDstDS->poGeoRaster->poConnection->GetUser(),
1729 poDstDS->poGeoRaster->poConnection->GetPassword(),
1730 poDstDS->poGeoRaster->poConnection->GetServer(),
1731 poDstDS->poGeoRaster->sDataTable.c_str(),
1732 poDstDS->poGeoRaster->nRasterId,
1733 poDstDS->poGeoRaster->sSchema.c_str(),
1734 poDstDS->poGeoRaster->sTable.c_str(),
1735 poDstDS->poGeoRaster->sColumn.c_str() );
1736 }
1737
1738 return poDstDS;
1739 }
1740
1741 // ---------------------------------------------------------------------------
1742 // IRasterIO()
1743 // ---------------------------------------------------------------------------
1744
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)1745 CPLErr GeoRasterDataset::IRasterIO( GDALRWFlag eRWFlag,
1746 int nXOff, int nYOff, int nXSize, int nYSize,
1747 void *pData, int nBufXSize, int nBufYSize,
1748 GDALDataType eBufType,
1749 int nBandCount, int *panBandMap,
1750 GSpacing nPixelSpace, GSpacing nLineSpace,
1751 GSpacing nBandSpace,
1752 GDALRasterIOExtraArg* psExtraArg )
1753
1754 {
1755 if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
1756 {
1757 if( poJP2Dataset )
1758 {
1759 return poJP2Dataset->RasterIO( eRWFlag,
1760 nXOff, nYOff, nXSize, nYSize,
1761 pData, nBufXSize, nBufYSize, eBufType,
1762 nBandCount, panBandMap,
1763 nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
1764 }
1765 else
1766 {
1767 return CE_Failure;
1768 }
1769 }
1770 else
1771 {
1772 if( poGeoRaster->nBandBlockSize > 1 )
1773 {
1774 return GDALDataset::BlockBasedRasterIO( eRWFlag,
1775 nXOff, nYOff, nXSize, nYSize,
1776 pData, nBufXSize, nBufYSize, eBufType,
1777 nBandCount, panBandMap, nPixelSpace,
1778 nLineSpace, nBandSpace, psExtraArg );
1779 }
1780 else
1781 {
1782 return GDALDataset::IRasterIO( eRWFlag,
1783 nXOff, nYOff, nXSize, nYSize,
1784 pData, nBufXSize, nBufYSize, eBufType,
1785 nBandCount, panBandMap,
1786 nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
1787 }
1788 }
1789 }
1790
1791 // ---------------------------------------------------------------------------
1792 // FlushCache()
1793 // ---------------------------------------------------------------------------
1794
FlushCache()1795 void GeoRasterDataset::FlushCache()
1796 {
1797 GDALDataset::FlushCache();
1798 }
1799
1800 // ---------------------------------------------------------------------------
1801 // GetGeoTransform()
1802 // ---------------------------------------------------------------------------
1803
GetGeoTransform(double * padfTransform)1804 CPLErr GeoRasterDataset::GetGeoTransform( double *padfTransform )
1805 {
1806 if( poGeoRaster->phRPC )
1807 {
1808 return CE_Failure;
1809 }
1810
1811 if( poGeoRaster->nSRID == 0 )
1812 {
1813 return CE_Failure;
1814 }
1815
1816 memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1817
1818 bGeoTransform = true;
1819
1820 return CE_None;
1821 }
1822
1823 // ---------------------------------------------------------------------------
1824 // GetProjectionRef()
1825 // ---------------------------------------------------------------------------
1826
_GetProjectionRef(void)1827 const char* GeoRasterDataset::_GetProjectionRef( void )
1828 {
1829 if( poGeoRaster->phRPC )
1830 {
1831 return "";
1832 }
1833
1834 if( ! poGeoRaster->bIsReferenced )
1835 {
1836 return "";
1837 }
1838
1839 if( poGeoRaster->nSRID == UNKNOWN_CRS || poGeoRaster->nSRID == 0 )
1840 {
1841 return "";
1842 }
1843
1844 if( pszProjection )
1845 {
1846 return pszProjection;
1847 }
1848
1849 OGRSpatialReference oSRS;
1850
1851 // --------------------------------------------------------------------
1852 // Check if the SRID is a valid EPSG code
1853 // --------------------------------------------------------------------
1854
1855 CPLPushErrorHandler( CPLQuietErrorHandler );
1856
1857 if( oSRS.importFromEPSG( static_cast<int>(poGeoRaster->nSRID) ) == OGRERR_NONE )
1858 {
1859 /*
1860 * Ignores the WKT from Oracle and use the one from GDAL's
1861 * EPSG tables. That would ensure that other drivers/software
1862 * will recognize the parameters.
1863 */
1864
1865 if( oSRS.exportToWkt( &pszProjection ) == OGRERR_NONE )
1866 {
1867 CPLPopErrorHandler();
1868
1869 return pszProjection;
1870 }
1871 CPLFree(pszProjection);
1872 pszProjection = nullptr;
1873 }
1874
1875 CPLPopErrorHandler();
1876
1877 // --------------------------------------------------------------------
1878 // Try to interpreter the WKT text
1879 // --------------------------------------------------------------------
1880
1881 poGeoRaster->QueryWKText();
1882
1883 if( ! ( oSRS.importFromWkt( poGeoRaster->sWKText ) == OGRERR_NONE && oSRS.GetRoot() ) )
1884 {
1885 return poGeoRaster->sWKText;
1886 }
1887
1888 // ----------------------------------------------------------------
1889 // Decorate with Authority name
1890 // ----------------------------------------------------------------
1891
1892 if( strlen(poGeoRaster->sAuthority) > 0 )
1893 {
1894 oSRS.SetAuthority(oSRS.GetRoot()->GetValue(),
1895 poGeoRaster->sAuthority.c_str(), static_cast<int>(poGeoRaster->nSRID));
1896 }
1897
1898 int nSpher = OWParseEPSG( oSRS.GetAttrValue("GEOGCS|DATUM|SPHEROID") );
1899
1900 if( nSpher > 0 )
1901 {
1902 oSRS.SetAuthority( "GEOGCS|DATUM|SPHEROID", "EPSG", nSpher );
1903 }
1904
1905 int nDatum = OWParseEPSG( oSRS.GetAttrValue("GEOGCS|DATUM") );
1906
1907 if( nDatum > 0 )
1908 {
1909 oSRS.SetAuthority( "GEOGCS|DATUM", "EPSG", nDatum );
1910 }
1911
1912 // ----------------------------------------------------------------
1913 // Checks for Projection info
1914 // ----------------------------------------------------------------
1915
1916 const char *pszProjName = oSRS.GetAttrValue( "PROJECTION" );
1917
1918 if( pszProjName )
1919 {
1920 int nProj = OWParseEPSG( pszProjName );
1921
1922 // ----------------------------------------------------------------
1923 // Decorate with EPSG Authority
1924 // ----------------------------------------------------------------
1925
1926 if( nProj > 0 )
1927 {
1928 oSRS.SetAuthority( "PROJECTION", "EPSG", nProj );
1929 }
1930
1931 // ----------------------------------------------------------------
1932 // Translate projection names to GDAL's standards
1933 // ----------------------------------------------------------------
1934
1935 if ( EQUAL( pszProjName, "Transverse Mercator" ) )
1936 {
1937 oSRS.SetProjection( SRS_PT_TRANSVERSE_MERCATOR );
1938 }
1939 else if ( EQUAL( pszProjName, "Albers Conical Equal Area" ) )
1940 {
1941 oSRS.SetProjection( SRS_PT_ALBERS_CONIC_EQUAL_AREA );
1942 }
1943 else if ( EQUAL( pszProjName, "Azimuthal Equidistant" ) )
1944 {
1945 oSRS.SetProjection( SRS_PT_AZIMUTHAL_EQUIDISTANT );
1946 }
1947 else if ( EQUAL( pszProjName, "Miller Cylindrical" ) )
1948 {
1949 oSRS.SetProjection( SRS_PT_MILLER_CYLINDRICAL );
1950 }
1951 else if ( EQUAL( pszProjName, "Hotine Oblique Mercator" ) )
1952 {
1953 oSRS.SetProjection( SRS_PT_HOTINE_OBLIQUE_MERCATOR );
1954 }
1955 else if ( EQUAL( pszProjName, "Wagner IV" ) )
1956 {
1957 oSRS.SetProjection( SRS_PT_WAGNER_IV );
1958 }
1959 else if ( EQUAL( pszProjName, "Wagner VII" ) )
1960 {
1961 oSRS.SetProjection( SRS_PT_WAGNER_VII );
1962 }
1963 else if ( EQUAL( pszProjName, "Eckert IV" ) )
1964 {
1965 oSRS.SetProjection( SRS_PT_ECKERT_IV );
1966 }
1967 else if ( EQUAL( pszProjName, "Eckert VI" ) )
1968 {
1969 oSRS.SetProjection( SRS_PT_ECKERT_VI );
1970 }
1971 else if ( EQUAL( pszProjName, "New Zealand Map Grid" ) )
1972 {
1973 oSRS.SetProjection( SRS_PT_NEW_ZEALAND_MAP_GRID );
1974 }
1975 else if ( EQUAL( pszProjName, "Lambert Conformal Conic" ) )
1976 {
1977 oSRS.SetProjection( SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP );
1978 }
1979 else if ( EQUAL( pszProjName, "Lambert Azimuthal Equal Area" ) )
1980 {
1981 oSRS.SetProjection( SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA );
1982 }
1983 else if ( EQUAL( pszProjName, "Van der Grinten" ) )
1984 {
1985 oSRS.SetProjection( SRS_PT_VANDERGRINTEN );
1986 }
1987 else if ( EQUAL(
1988 pszProjName, "Lambert Conformal Conic (Belgium 1972)" ) )
1989 {
1990 oSRS.SetProjection( SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM );
1991 }
1992 else if ( EQUAL( pszProjName, "Cylindrical Equal Area" ) )
1993 {
1994 oSRS.SetProjection( SRS_PT_CYLINDRICAL_EQUAL_AREA );
1995 }
1996 else if ( EQUAL( pszProjName, "Interrupted Goode Homolosine" ) )
1997 {
1998 oSRS.SetProjection( SRS_PT_GOODE_HOMOLOSINE );
1999 }
2000 }
2001
2002 oSRS.exportToWkt( &pszProjection );
2003
2004 return pszProjection;
2005 }
2006
2007 // ---------------------------------------------------------------------------
2008 // SetGeoTransform()
2009 // ---------------------------------------------------------------------------
2010
SetGeoTransform(double * padfTransform)2011 CPLErr GeoRasterDataset::SetGeoTransform( double *padfTransform )
2012 {
2013 memcpy( adfGeoTransform, padfTransform, sizeof( double ) * 6 );
2014
2015 poGeoRaster->dfXCoefficient[0] = adfGeoTransform[1];
2016 poGeoRaster->dfXCoefficient[1] = adfGeoTransform[2];
2017 poGeoRaster->dfXCoefficient[2] = adfGeoTransform[0];
2018 poGeoRaster->dfYCoefficient[0] = adfGeoTransform[4];
2019 poGeoRaster->dfYCoefficient[1] = adfGeoTransform[5];
2020 poGeoRaster->dfYCoefficient[2] = adfGeoTransform[3];
2021
2022 bGeoTransform = true;
2023
2024 return CE_None;
2025 }
2026
2027 // ---------------------------------------------------------------------------
2028 // SetProjection()
2029 // ---------------------------------------------------------------------------
2030
_SetProjection(const char * pszProjString)2031 CPLErr GeoRasterDataset::_SetProjection( const char *pszProjString )
2032 {
2033 OGRSpatialReference oSRS;
2034
2035 OGRErr eOGRErr = oSRS.importFromWkt( pszProjString );
2036
2037 if( eOGRErr != OGRERR_NONE )
2038 {
2039 poGeoRaster->SetGeoReference( UNKNOWN_CRS );
2040
2041 return CE_Failure;
2042 }
2043
2044 // --------------------------------------------------------------------
2045 // Try to extract EPGS authority code
2046 // --------------------------------------------------------------------
2047
2048 const char *pszAuthName = nullptr;
2049 const char *pszAuthCode = nullptr;
2050
2051 if( oSRS.IsGeographic() )
2052 {
2053 pszAuthName = oSRS.GetAuthorityName( "GEOGCS" );
2054 pszAuthCode = oSRS.GetAuthorityCode( "GEOGCS" );
2055 }
2056 else if( oSRS.IsProjected() )
2057 {
2058 pszAuthName = oSRS.GetAuthorityName( "PROJCS" );
2059 pszAuthCode = oSRS.GetAuthorityCode( "PROJCS" );
2060 }
2061
2062 if( pszAuthName != nullptr && pszAuthCode != nullptr )
2063 {
2064 if( EQUAL( pszAuthName, "ORACLE" ) ||
2065 EQUAL( pszAuthName, "EPSG" ) )
2066 {
2067 poGeoRaster->SetGeoReference( atoi( pszAuthCode ) );
2068 return CE_None;
2069 }
2070 }
2071
2072 // ----------------------------------------------------------------
2073 // Convert SRS into old style format (SF-SQL 1.0)
2074 // ----------------------------------------------------------------
2075
2076 std::unique_ptr<OGRSpatialReference> poSRS2(oSRS.Clone());
2077
2078 double dfAngularUnits = poSRS2->GetAngularUnits( nullptr );
2079
2080 if( fabs(dfAngularUnits - 0.0174532925199433) < 0.0000000000000010 )
2081 {
2082 /* match the precision used on Oracle for that particular value */
2083
2084 poSRS2->SetAngularUnits( "Decimal Degree", 0.0174532925199433 );
2085 }
2086
2087 char* pszCloneWKT = nullptr;
2088
2089 const char* const apszOptions[] = { "FORMAT=SFSQL", nullptr };
2090 if( poSRS2->exportToWkt( &pszCloneWKT, apszOptions ) != OGRERR_NONE )
2091 {
2092 CPLFree(pszCloneWKT);
2093 return CE_Failure;
2094 }
2095
2096 const char *pszProjName = poSRS2->GetAttrValue( "PROJECTION" );
2097
2098 if( pszProjName )
2099 {
2100 // ----------------------------------------------------------------
2101 // Translate projection names to Oracle's standards
2102 // ----------------------------------------------------------------
2103
2104 if ( EQUAL( pszProjName, SRS_PT_TRANSVERSE_MERCATOR ) )
2105 {
2106 poSRS2->SetProjection( "Transverse Mercator" );
2107 }
2108 else if ( EQUAL( pszProjName, SRS_PT_ALBERS_CONIC_EQUAL_AREA ) )
2109 {
2110 poSRS2->SetProjection( "Albers Conical Equal Area" );
2111 }
2112 else if ( EQUAL( pszProjName, SRS_PT_AZIMUTHAL_EQUIDISTANT ) )
2113 {
2114 poSRS2->SetProjection( "Azimuthal Equidistant" );
2115 }
2116 else if ( EQUAL( pszProjName, SRS_PT_MILLER_CYLINDRICAL ) )
2117 {
2118 poSRS2->SetProjection( "Miller Cylindrical" );
2119 }
2120 else if ( EQUAL( pszProjName, SRS_PT_HOTINE_OBLIQUE_MERCATOR ) )
2121 {
2122 poSRS2->SetProjection( "Hotine Oblique Mercator" );
2123 }
2124 else if ( EQUAL( pszProjName, SRS_PT_WAGNER_IV ) )
2125 {
2126 poSRS2->SetProjection( "Wagner IV" );
2127 }
2128 else if ( EQUAL( pszProjName, SRS_PT_WAGNER_VII ) )
2129 {
2130 poSRS2->SetProjection( "Wagner VII" );
2131 }
2132 else if ( EQUAL( pszProjName, SRS_PT_ECKERT_IV ) )
2133 {
2134 poSRS2->SetProjection( "Eckert IV" );
2135 }
2136 else if ( EQUAL( pszProjName, SRS_PT_ECKERT_VI ) )
2137 {
2138 poSRS2->SetProjection( "Eckert VI" );
2139 }
2140 else if ( EQUAL( pszProjName, SRS_PT_NEW_ZEALAND_MAP_GRID ) )
2141 {
2142 poSRS2->SetProjection( "New Zealand Map Grid" );
2143 }
2144 else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP ) )
2145 {
2146 poSRS2->SetProjection( "Lambert Conformal Conic" );
2147 }
2148 else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA ) )
2149 {
2150 poSRS2->SetProjection( "Lambert Azimuthal Equal Area" );
2151 }
2152 else if ( EQUAL( pszProjName, SRS_PT_VANDERGRINTEN ) )
2153 {
2154 poSRS2->SetProjection( "Van der Grinten" );
2155 }
2156 else if ( EQUAL(
2157 pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM ) )
2158 {
2159 poSRS2->SetProjection( "Lambert Conformal Conic (Belgium 1972)" );
2160 }
2161 else if ( EQUAL( pszProjName, SRS_PT_CYLINDRICAL_EQUAL_AREA ) )
2162 {
2163 poSRS2->SetProjection( "Cylindrical Equal Area" );
2164 }
2165 else if ( EQUAL( pszProjName, SRS_PT_GOODE_HOMOLOSINE ) )
2166 {
2167 poSRS2->SetProjection( "Interrupted Goode Homolosine" );
2168 }
2169
2170 // ----------------------------------------------------------------
2171 // Translate projection's parameters to Oracle's standards
2172 // ----------------------------------------------------------------
2173
2174 char* pszStart = nullptr;
2175
2176 CPLFree( pszCloneWKT );
2177 pszCloneWKT = nullptr;
2178
2179 if( poSRS2->exportToWkt( &pszCloneWKT ) != OGRERR_NONE )
2180 {
2181 CPLFree(pszCloneWKT);
2182 return CE_Failure;
2183 }
2184
2185 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_AZIMUTH) ) != nullptr )
2186 {
2187 memcpy( pszStart, "Azimuth", strlen(SRS_PP_AZIMUTH) );
2188 }
2189
2190 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_CENTRAL_MERIDIAN) ) != nullptr )
2191 {
2192 memcpy( pszStart, "Central_Meridian",
2193 strlen(SRS_PP_CENTRAL_MERIDIAN) );
2194 }
2195
2196 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_EASTING) ) != nullptr )
2197 {
2198 memcpy( pszStart, "False_Easting", strlen(SRS_PP_FALSE_EASTING) );
2199 }
2200
2201 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_NORTHING) ) != nullptr )
2202 {
2203 memcpy( pszStart, "False_Northing",
2204 strlen(SRS_PP_FALSE_NORTHING) );
2205 }
2206
2207 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_CENTER) ) != nullptr )
2208 {
2209 memcpy( pszStart, "Latitude_Of_Center",
2210 strlen(SRS_PP_LATITUDE_OF_CENTER) );
2211 }
2212
2213 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_ORIGIN) ) != nullptr )
2214 {
2215 memcpy( pszStart, "Latitude_Of_Origin",
2216 strlen(SRS_PP_LATITUDE_OF_ORIGIN) );
2217 }
2218
2219 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LONGITUDE_OF_CENTER) ) != nullptr )
2220 {
2221 memcpy( pszStart, "Longitude_Of_Center",
2222 strlen(SRS_PP_LONGITUDE_OF_CENTER) );
2223 }
2224
2225 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_PSEUDO_STD_PARALLEL_1) ) != nullptr )
2226 {
2227 memcpy( pszStart, "Pseudo_Standard_Parallel_1",
2228 strlen(SRS_PP_PSEUDO_STD_PARALLEL_1) );
2229 }
2230
2231 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_SCALE_FACTOR) ) != nullptr )
2232 {
2233 memcpy( pszStart, "Scale_Factor", strlen(SRS_PP_SCALE_FACTOR) );
2234 }
2235
2236 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_1) ) != nullptr )
2237 {
2238 memcpy( pszStart, "Standard_Parallel_1",
2239 strlen(SRS_PP_STANDARD_PARALLEL_1) );
2240 }
2241
2242 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) != nullptr )
2243 {
2244 memcpy( pszStart, "Standard_Parallel_2",
2245 strlen(SRS_PP_STANDARD_PARALLEL_2) );
2246 }
2247
2248 if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) != nullptr )
2249 {
2250 memcpy( pszStart, "Standard_Parallel_2",
2251 strlen(SRS_PP_STANDARD_PARALLEL_2) );
2252 }
2253
2254 // ----------------------------------------------------------------
2255 // Fix Unit name
2256 // ----------------------------------------------------------------
2257
2258 if( ( pszStart = strstr(pszCloneWKT, "metre") ) != nullptr )
2259 {
2260 memcpy( pszStart, SRS_UL_METER, strlen(SRS_UL_METER) );
2261 }
2262 }
2263
2264 // --------------------------------------------------------------------
2265 // Tries to find a SRID compatible with the WKT
2266 // --------------------------------------------------------------------
2267
2268 OWConnection* poConnection = poGeoRaster->poConnection;
2269 OWStatement* poStmt = nullptr;
2270
2271 int nNewSRID = 0;
2272
2273 const char *pszFuncName = "FIND_GEOG_CRS";
2274
2275 if( poSRS2->IsProjected() )
2276 {
2277 pszFuncName = "FIND_PROJ_CRS";
2278 }
2279
2280 poStmt = poConnection->CreateStatement( CPLSPrintf(
2281 "DECLARE\n"
2282 " LIST SDO_SRID_LIST;"
2283 "BEGIN\n"
2284 " SELECT SDO_CS.%s('%s', null) into LIST FROM DUAL;\n"
2285 " IF LIST.COUNT() > 0 then\n"
2286 " SELECT LIST(1) into :out from dual;\n"
2287 " ELSE\n"
2288 " SELECT 0 into :out from dual;\n"
2289 " END IF;\n"
2290 "END;",
2291 pszFuncName,
2292 pszCloneWKT ) );
2293
2294 poStmt->BindName( ":out", &nNewSRID );
2295
2296 CPLPushErrorHandler( CPLQuietErrorHandler );
2297
2298 if( poStmt->Execute() )
2299 {
2300 CPLPopErrorHandler();
2301
2302 if ( nNewSRID > 0 )
2303 {
2304 poGeoRaster->SetGeoReference( nNewSRID );
2305 CPLFree( pszCloneWKT );
2306 delete poStmt;
2307 return CE_None;
2308 }
2309 }
2310 delete poStmt;
2311
2312 // --------------------------------------------------------------------
2313 // Search by simplified WKT or insert it as a user defined SRS
2314 // --------------------------------------------------------------------
2315
2316 int nCounter = 0;
2317
2318 poStmt = poConnection->CreateStatement( CPLSPrintf(
2319 "SELECT COUNT(*) FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
2320
2321 poStmt->Define( &nCounter );
2322
2323 CPLPushErrorHandler( CPLQuietErrorHandler );
2324
2325 if( poStmt->Execute() && nCounter > 0 )
2326 {
2327 delete poStmt;
2328
2329 poStmt = poConnection->CreateStatement( CPLSPrintf(
2330 "SELECT SRID FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
2331
2332 poStmt->Define( &nNewSRID );
2333
2334 if( poStmt->Execute() )
2335 {
2336 CPLPopErrorHandler();
2337
2338 poGeoRaster->SetGeoReference( nNewSRID );
2339 CPLFree( pszCloneWKT );
2340 delete poStmt;
2341 return CE_None;
2342 }
2343 }
2344
2345 CPLPopErrorHandler();
2346
2347 delete poStmt;
2348
2349 poStmt = poConnection->CreateStatement( CPLSPrintf(
2350 "DECLARE\n"
2351 " MAX_SRID NUMBER := 0;\n"
2352 "BEGIN\n"
2353 " SELECT MAX(SRID) INTO MAX_SRID FROM MDSYS.CS_SRS;\n"
2354 " MAX_SRID := MAX_SRID + 1;\n"
2355 " INSERT INTO MDSYS.CS_SRS (SRID, WKTEXT, CS_NAME)\n"
2356 " VALUES (MAX_SRID, '%s', '%s');\n"
2357 " SELECT MAX_SRID INTO :out FROM DUAL;\n"
2358 "END;",
2359 pszCloneWKT,
2360 oSRS.GetRoot()->GetChild(0)->GetValue() ) );
2361
2362 poStmt->BindName( ":out", &nNewSRID );
2363
2364 CPLErr eError = CE_None;
2365
2366 CPLPushErrorHandler( CPLQuietErrorHandler );
2367
2368 if( poStmt->Execute() )
2369 {
2370 CPLPopErrorHandler();
2371
2372 poGeoRaster->SetGeoReference( nNewSRID );
2373 }
2374 else
2375 {
2376 CPLPopErrorHandler();
2377
2378 poGeoRaster->SetGeoReference( UNKNOWN_CRS );
2379
2380 CPLError( CE_Warning, CPLE_UserInterrupt,
2381 "Insufficient privileges to insert reference system to "
2382 "table MDSYS.CS_SRS." );
2383
2384 eError = CE_Warning;
2385 }
2386
2387 CPLFree( pszCloneWKT );
2388
2389 delete poStmt;
2390
2391 return eError;
2392 }
2393
2394 /************************************************************************/
2395 /* GetMetadataDomainList() */
2396 /************************************************************************/
2397
GetMetadataDomainList()2398 char **GeoRasterDataset::GetMetadataDomainList()
2399 {
2400 return BuildMetadataDomainList(GDALDataset::GetMetadataDomainList(),
2401 TRUE,
2402 "SUBDATASETS", nullptr);
2403 }
2404
2405 // ---------------------------------------------------------------------------
2406 // GetMetadata()
2407 // ---------------------------------------------------------------------------
2408
GetMetadata(const char * pszDomain)2409 char **GeoRasterDataset::GetMetadata( const char *pszDomain )
2410 {
2411 if( pszDomain != nullptr && STARTS_WITH_CI(pszDomain, "SUBDATASETS") )
2412 return papszSubdatasets;
2413 else
2414 return GDALDataset::GetMetadata( pszDomain );
2415 }
2416
2417 // ---------------------------------------------------------------------------
2418 // Delete()
2419 // ---------------------------------------------------------------------------
2420
Delete(const char * pszFilename)2421 CPLErr GeoRasterDataset::Delete( const char* pszFilename )
2422 {
2423 (void) pszFilename;
2424 /***
2425 GeoRasterDataset* poGRD = nullptr;
2426
2427 poGRD = (GeoRasterDataset*) GDALOpen( pszFilename, GA_Update );
2428
2429 if( ! poGRD )
2430 {
2431 return CE_Failure;
2432 }
2433
2434 if( ! poGRD->poGeoRaster->Delete() )
2435 {
2436 return CE_Failure;
2437 }
2438 ***/
2439 return CE_None;
2440 }
2441
2442 // ---------------------------------------------------------------------------
2443 // SetSubdatasets()
2444 // ---------------------------------------------------------------------------
2445
SetSubdatasets(GeoRasterWrapper * poGRW)2446 void GeoRasterDataset::SetSubdatasets( GeoRasterWrapper* poGRW )
2447 {
2448 OWConnection* poConnection = poGRW->poConnection;
2449
2450 // -----------------------------------------------------------
2451 // List all the GeoRaster Tables of that User/Database
2452 // -----------------------------------------------------------
2453
2454 if( poGRW->sTable.empty() &&
2455 poGRW->sColumn.empty() )
2456 {
2457 OWStatement* poStmt = poConnection->CreateStatement(
2458 "SELECT DISTINCT TABLE_NAME, OWNER FROM ALL_SDO_GEOR_SYSDATA\n"
2459 " ORDER BY TABLE_NAME ASC" );
2460
2461 char szTable[OWNAME];
2462 char szOwner[OWNAME];
2463
2464 poStmt->Define( szTable );
2465 poStmt->Define( szOwner );
2466
2467 if( poStmt->Execute() )
2468 {
2469 int nCount = 1;
2470
2471 do
2472 {
2473 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2474 CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2475 CPLSPrintf( "geor:%s/%s@%s,%s.%s",
2476 poConnection->GetUser(), poConnection->GetPassword(),
2477 poConnection->GetServer(), szOwner, szTable ) );
2478
2479 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2480 CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2481 CPLSPrintf( "%s.Table=%s", szOwner, szTable ) );
2482
2483 nCount++;
2484 }
2485 while( poStmt->Fetch() );
2486 }
2487
2488 delete poStmt;
2489
2490 return;
2491 }
2492
2493 // -----------------------------------------------------------
2494 // List all the GeoRaster Columns of that Table
2495 // -----------------------------------------------------------
2496
2497 if( ! poGRW->sTable.empty() &&
2498 poGRW->sColumn.empty() )
2499 {
2500 OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
2501 "SELECT DISTINCT COLUMN_NAME, OWNER FROM ALL_SDO_GEOR_SYSDATA\n"
2502 " WHERE OWNER = UPPER('%s') AND TABLE_NAME = UPPER('%s')\n"
2503 " ORDER BY COLUMN_NAME ASC",
2504 poGRW->sOwner.c_str(),
2505 poGRW->sTable.c_str() ) );
2506
2507 char szColumn[OWNAME];
2508 char szOwner[OWNAME];
2509
2510 poStmt->Define( szColumn );
2511 poStmt->Define( szOwner );
2512
2513 if( poStmt->Execute() )
2514 {
2515 int nCount = 1;
2516
2517 do
2518 {
2519 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2520 CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2521 CPLSPrintf( "geor:%s/%s@%s,%s.%s,%s",
2522 poConnection->GetUser(), poConnection->GetPassword(),
2523 poConnection->GetServer(), szOwner,
2524 poGRW->sTable.c_str(), szColumn ) );
2525
2526 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2527 CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2528 CPLSPrintf( "Table=%s.%s Column=%s", szOwner,
2529 poGRW->sTable.c_str(), szColumn ) );
2530
2531 nCount++;
2532 }
2533 while( poStmt->Fetch() );
2534 }
2535
2536 delete poStmt;
2537
2538 return;
2539 }
2540
2541 // -----------------------------------------------------------
2542 // List all the rows that contains GeoRaster on Table/Column/Where
2543 // -----------------------------------------------------------
2544
2545 CPLString osAndWhere = "";
2546
2547 if( ! poGRW->sWhere.empty() )
2548 {
2549 osAndWhere = CPLSPrintf( "AND %s", poGRW->sWhere.c_str() );
2550 }
2551
2552 OWStatement* poStmt = poConnection->CreateStatement( CPLSPrintf(
2553 "SELECT T.%s.RASTERDATATABLE, T.%s.RASTERID, \n"
2554 " extractValue(t.%s.metadata, "
2555 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"ROW\"]/size','%s'),\n"
2556 " extractValue(t.%s.metadata, "
2557 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"COLUMN\"]/size','%s'),\n"
2558 " extractValue(t.%s.metadata, "
2559 "'/georasterMetadata/rasterInfo/dimensionSize[@type=\"BAND\"]/size','%s'),\n"
2560 " extractValue(t.%s.metadata, "
2561 "'/georasterMetadata/rasterInfo/cellDepth','%s'),\n"
2562 " extractValue(t.%s.metadata, "
2563 "'/georasterMetadata/spatialReferenceInfo/SRID','%s')\n"
2564 " FROM %s%s T\n"
2565 " WHERE %s IS NOT NULL %s\n"
2566 " ORDER BY T.%s.RASTERDATATABLE ASC,\n"
2567 " T.%s.RASTERID ASC",
2568 poGRW->sColumn.c_str(), poGRW->sColumn.c_str(),
2569 poGRW->sColumn.c_str(), OW_XMLNS,
2570 poGRW->sColumn.c_str(), OW_XMLNS,
2571 poGRW->sColumn.c_str(), OW_XMLNS,
2572 poGRW->sColumn.c_str(), OW_XMLNS,
2573 poGRW->sColumn.c_str(), OW_XMLNS,
2574 poGRW->sSchema.c_str(), poGRW->sTable.c_str(),
2575 poGRW->sColumn.c_str(), osAndWhere.c_str(),
2576 poGRW->sColumn.c_str(), poGRW->sColumn.c_str() ) );
2577
2578 char szDataTable[OWNAME];
2579 char szRasterId[OWNAME];
2580 char szRows[OWNAME];
2581 char szColumns[OWNAME];
2582 char szBands[OWNAME];
2583 char szCellDepth[OWNAME];
2584 char szSRID[OWNAME];
2585
2586 poStmt->Define( szDataTable );
2587 poStmt->Define( szRasterId );
2588 poStmt->Define( szRows );
2589 poStmt->Define( szColumns );
2590 poStmt->Define( szBands );
2591 poStmt->Define( szCellDepth );
2592 poStmt->Define( szSRID );
2593
2594 if( poStmt->Execute() )
2595 {
2596 int nCount = 1;
2597
2598 do
2599 {
2600 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2601 CPLSPrintf( "SUBDATASET_%d_NAME", nCount ),
2602 CPLSPrintf( "geor:%s/%s@%s,%s,%s",
2603 poConnection->GetUser(), poConnection->GetPassword(),
2604 poConnection->GetServer(), szDataTable, szRasterId ) );
2605
2606 const char* pszXBands = "";
2607
2608 if( ! EQUAL( szBands, "" ) )
2609 {
2610 pszXBands = CPLSPrintf( "x%s", szBands );
2611 }
2612
2613 papszSubdatasets = CSLSetNameValue( papszSubdatasets,
2614 CPLSPrintf( "SUBDATASET_%d_DESC", nCount ),
2615 CPLSPrintf( "[%sx%s%s] CellDepth=%s SRID=%s",
2616 szRows, szColumns, pszXBands,
2617 szCellDepth, szSRID ) );
2618
2619 nCount++;
2620 }
2621 while( poStmt->Fetch() );
2622 }
2623 delete poStmt;
2624 }
2625
GetGCPCount()2626 int GeoRasterDataset::GetGCPCount()
2627 {
2628 if ( poGeoRaster )
2629 {
2630 return poGeoRaster->nGCPCount;
2631 }
2632
2633 return 0;
2634 }
2635
2636 // ---------------------------------------------------------------------------
2637 // SetGCPs()
2638 // ---------------------------------------------------------------------------
2639
_SetGCPs(int nGCPCountIn,const GDAL_GCP * pasGCPListIn,const char * pszGCPProjection)2640 CPLErr GeoRasterDataset::_SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
2641 const char *pszGCPProjection )
2642 {
2643 if( GetAccess() == GA_Update )
2644 {
2645 poGeoRaster->SetGCP( nGCPCountIn, pasGCPListIn );
2646 SetProjection( pszGCPProjection );
2647 }
2648 else
2649 {
2650 CPLError(CE_Failure, CPLE_NotSupported,
2651 "SetGCPs() is only supported on GeoRaster insert or update.");
2652 return CE_Failure;
2653 }
2654
2655 return CE_None;
2656 }
2657
GetGCPs()2658 const GDAL_GCP* GeoRasterDataset::GetGCPs()
2659 {
2660 if( poGeoRaster->nGCPCount > 0 && poGeoRaster->pasGCPList )
2661 {
2662 return poGeoRaster->pasGCPList;
2663 }
2664
2665 return nullptr;
2666 }
2667
2668 // ---------------------------------------------------------------------------
2669 // GetGCPProjection()
2670 // ---------------------------------------------------------------------------
2671
_GetGCPProjection()2672 const char* GeoRasterDataset::_GetGCPProjection()
2673 {
2674 if( poGeoRaster && poGeoRaster->nGCPCount > 0 )
2675 return pszProjection;
2676 else
2677 return "";
2678 }
2679
2680 // ---------------------------------------------------------------------------
2681 // IBuildOverviews()
2682 // ---------------------------------------------------------------------------
2683
IBuildOverviews(const char * pszResampling,int nOverviews,int * panOverviewList,int nListBands,int * panBandList,GDALProgressFunc pfnProgress,void * pProgressData)2684 CPLErr GeoRasterDataset::IBuildOverviews( const char* pszResampling,
2685 int nOverviews,
2686 int* panOverviewList,
2687 int nListBands,
2688 int* panBandList,
2689 GDALProgressFunc pfnProgress,
2690 void* pProgressData )
2691 {
2692 (void) panBandList;
2693 (void) nListBands;
2694
2695 if( EQUAL( poGeoRaster->sCompressionType.c_str(), "JP2-F" ) )
2696 {
2697 return CE_None; // Ignore it, JP2 automatically has overviews
2698 }
2699
2700 // ---------------------------------------------------------------
2701 // Can't update on read-only access mode
2702 // ---------------------------------------------------------------
2703
2704 if( GetAccess() != GA_Update )
2705 {
2706 CPLError( CE_Failure, CPLE_AppDefined,
2707 "Can't build overviews/pyramids on read-only access." );
2708 return CE_Failure;
2709 }
2710
2711 // ---------------------------------------------------------------
2712 // Uses internal sdo_generatePyramid at PL/SQL?
2713 // ---------------------------------------------------------------
2714
2715 bool bInternal = true;
2716
2717 const char *pszGEOR_INTERNAL_PYR = CPLGetConfigOption( "GEOR_INTERNAL_PYR",
2718 "YES" );
2719
2720 if( EQUAL(pszGEOR_INTERNAL_PYR, "NO") )
2721 {
2722 bInternal = false;
2723 }
2724
2725 // -----------------------------------------------------------
2726 // Pyramids applies to the whole dataset not to a specific band
2727 // -----------------------------------------------------------
2728
2729 if( nBands < GetRasterCount())
2730 {
2731 CPLError( CE_Failure, CPLE_AppDefined,
2732 "Invalid GeoRaster Pyramids band selection" );
2733 return CE_Failure;
2734 }
2735
2736 // ---------------------------------------------------------------
2737 // Initialize progress reporting
2738 // ---------------------------------------------------------------
2739
2740 if( ! pfnProgress( 0.1, nullptr, pProgressData ) )
2741 {
2742 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
2743 return CE_Failure;
2744 }
2745
2746 // ---------------------------------------------------------------
2747 // Clear existing overviews
2748 // ---------------------------------------------------------------
2749
2750 if( nOverviews == 0 )
2751 {
2752 poGeoRaster->DeletePyramid();
2753 return CE_None;
2754 }
2755
2756 // -----------------------------------------------------------
2757 // Pyramids levels can not be treated individually
2758 // -----------------------------------------------------------
2759
2760 if( nOverviews > 0 )
2761 {
2762 int i;
2763 for( i = 1; i < nOverviews; i++ )
2764 {
2765 // -----------------------------------------------------------
2766 // Power of 2, starting on 2, e.g. 2, 4, 8, 16, 32, 64, 128
2767 // -----------------------------------------------------------
2768
2769 if( panOverviewList[0] != 2 ||
2770 ( panOverviewList[i] != panOverviewList[i-1] * 2 ) )
2771 {
2772 CPLError( CE_Failure, CPLE_AppDefined,
2773 "Invalid GeoRaster Pyramids levels." );
2774 return CE_Failure;
2775 }
2776 }
2777 }
2778
2779 // -----------------------------------------------------------
2780 // Re-sampling method:
2781 // NN, BILINEAR, AVERAGE4, AVERAGE16 and CUBIC
2782 // -----------------------------------------------------------
2783
2784 char szMethod[OWNAME];
2785
2786 if( EQUAL( pszResampling, "NEAREST" ) )
2787 {
2788 strcpy( szMethod, "NN" );
2789 }
2790 else if( STARTS_WITH_CI(pszResampling, "AVERAGE") )
2791 {
2792 strcpy( szMethod, "AVERAGE4" );
2793 }
2794 else
2795 {
2796 CPLError( CE_Failure, CPLE_AppDefined, "Invalid resampling method" );
2797 return CE_Failure;
2798 }
2799
2800 // -----------------------------------------------------------
2801 // Generate pyramids on poGeoRaster
2802 // -----------------------------------------------------------
2803
2804 if( ! poGeoRaster->GeneratePyramid( nOverviews, szMethod, bInternal ) )
2805 {
2806 CPLError( CE_Failure, CPLE_AppDefined, "Error generating pyramid" );
2807 return CE_Failure;
2808 }
2809
2810 // -----------------------------------------------------------
2811 // If Pyramid was done internally on the server exit here
2812 // -----------------------------------------------------------
2813
2814 if( bInternal )
2815 {
2816 pfnProgress( 1 , nullptr, pProgressData );
2817 return CE_None;
2818 }
2819
2820 // -----------------------------------------------------------
2821 // Load the pyramids data using GDAL methods
2822 // -----------------------------------------------------------
2823
2824 CPLErr eErr = CE_None;
2825
2826 int i = 0;
2827
2828 for( i = 0; i < nBands; i++ )
2829 {
2830 GeoRasterRasterBand* poBand = (GeoRasterRasterBand*) papoBands[i];
2831
2832 // -------------------------------------------------------
2833 // Clean up previous overviews
2834 // -------------------------------------------------------
2835
2836 int j = 0;
2837
2838 if( poBand->nOverviewCount && poBand->papoOverviews )
2839 {
2840 for( j = 0; j < poBand->nOverviewCount; j++ )
2841 {
2842 delete poBand->papoOverviews[j];
2843 }
2844 CPLFree( poBand->papoOverviews );
2845 }
2846
2847 // -------------------------------------------------------
2848 // Create new band's overviews list
2849 // -------------------------------------------------------
2850
2851 poBand->nOverviewCount = poGeoRaster->nPyramidMaxLevel;
2852 poBand->papoOverviews = (GeoRasterRasterBand**) VSIMalloc(
2853 sizeof(GeoRasterRasterBand*) * poBand->nOverviewCount );
2854
2855 for( j = 0; j < poBand->nOverviewCount; j++ )
2856 {
2857 poBand->papoOverviews[j] = new GeoRasterRasterBand(
2858 (GeoRasterDataset*) this, ( i + 1 ), ( j + 1 ) );
2859 }
2860 }
2861
2862 // -----------------------------------------------------------
2863 // Load band's overviews
2864 // -----------------------------------------------------------
2865
2866 for( i = 0; i < nBands; i++ )
2867 {
2868 GeoRasterRasterBand* poBand = (GeoRasterRasterBand*) papoBands[i];
2869
2870 void *pScaledProgressData = GDALCreateScaledProgress(
2871 i / (double) nBands, ( i + 1) / (double) nBands,
2872 pfnProgress, pProgressData );
2873
2874 eErr = GDALRegenerateOverviews(
2875 (GDALRasterBandH) poBand,
2876 poBand->nOverviewCount,
2877 (GDALRasterBandH*) poBand->papoOverviews,
2878 pszResampling,
2879 GDALScaledProgress,
2880 pScaledProgressData );
2881
2882 GDALDestroyScaledProgress( pScaledProgressData );
2883 }
2884
2885 return eErr;
2886 }
2887
2888 // ---------------------------------------------------------------------------
2889 // CreateMaskBand()
2890 // ---------------------------------------------------------------------------
2891
CreateMaskBand(int)2892 CPLErr GeoRasterDataset::CreateMaskBand( int /*nFlags*/ )
2893 {
2894 if( ! poGeoRaster->InitializeMask( DEFAULT_BMP_MASK,
2895 poGeoRaster->nRowBlockSize,
2896 poGeoRaster->nColumnBlockSize,
2897 poGeoRaster->nTotalRowBlocks,
2898 poGeoRaster->nTotalColumnBlocks,
2899 poGeoRaster->nTotalBandBlocks ) )
2900 {
2901 return CE_Failure;
2902 }
2903
2904 poGeoRaster->bHasBitmapMask = true;
2905
2906 return CE_None;
2907 }
2908
2909 /*****************************************************************************/
2910 /* GDALRegister_GEOR */
2911 /*****************************************************************************/
2912
GDALRegister_GEOR()2913 void CPL_DLL GDALRegister_GEOR()
2914
2915 {
2916 if( !GDAL_CHECK_VERSION( "GeoRaster driver" ) )
2917 return;
2918
2919 if( GDALGetDriverByName( "GeoRaster" ) != nullptr )
2920 return;
2921
2922 GDALDriver *poDriver = new GDALDriver();
2923
2924 poDriver->SetDescription( "GeoRaster" );
2925 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
2926 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Oracle Spatial GeoRaster" );
2927 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/georaster.html" );
2928 poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
2929 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2930 "Byte UInt16 Int16 UInt32 Int32 Float32 "
2931 "Float64 CFloat32 CFloat64" );
2932 poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2933 "<CreationOptionList>"
2934 " <Option name='DESCRIPTION' type='string' description='Table Description'/>"
2935 " <Option name='INSERT' type='string' description='Column Values'/>"
2936 " <Option name='BLOCKXSIZE' type='int' description='Column Block Size' "
2937 "default='512'/>"
2938 " <Option name='BLOCKYSIZE' type='int' description='Row Block Size' "
2939 "default='512'/>"
2940 " <Option name='BLOCKBSIZE' type='int' description='Band Block Size'/>"
2941 " <Option name='BLOCKING' type='string-select' default='YES'>"
2942 " <Value>YES</Value>"
2943 " <Value>NO</Value>"
2944 " <Value>OPTIMALPADDING</Value>"
2945 " </Option>"
2946 " <Option name='SRID' type='int' description='Overwrite EPSG code'/>"
2947 " <Option name='GENPYRAMID' type='string-select' "
2948 " description='Generate Pyramid, inform resampling method'>"
2949 " <Value>NN</Value>"
2950 " <Value>BILINEAR</Value>"
2951 " <Value>BIQUADRATIC</Value>"
2952 " <Value>CUBIC</Value>"
2953 " <Value>AVERAGE4</Value>"
2954 " <Value>AVERAGE16</Value>"
2955 " </Option>"
2956 " <Option name='GENPYRLEVELS' type='int' description='Number of pyramid level to generate'/>"
2957 " <Option name='OBJECTTABLE' type='boolean' "
2958 "description='Create RDT as object table'/>"
2959 " <Option name='SPATIALEXTENT' type='boolean' "
2960 "description='Generate Spatial Extent' "
2961 "default='TRUE'/>"
2962 " <Option name='EXTENTSRID' type='int' description='Spatial ExtentSRID code'/>"
2963 " <Option name='COORDLOCATION' type='string-select' default='CENTER'>"
2964 " <Value>CENTER</Value>"
2965 " <Value>UPPERLEFT</Value>"
2966 " </Option>"
2967 " <Option name='VATNAME' type='string' description='Value Attribute Table Name'/>"
2968 " <Option name='NBITS' type='int' description='BITS for sub-byte "
2969 "data types (1,2,4) bits'/>"
2970 " <Option name='INTERLEAVE' type='string-select'>"
2971 " <Value>BSQ</Value>"
2972 " <Value>BIP</Value>"
2973 " <Value>BIL</Value>"
2974 " </Option>"
2975 " <Option name='COMPRESS' type='string-select'>"
2976 " <Value>NONE</Value>"
2977 " <Value>JPEG-F</Value>"
2978 " <Value>JP2-F</Value>"
2979 " <Value>DEFLATE</Value>"
2980 " </Option>"
2981 " <Option name='QUALITY' type='int' description='JPEG quality 0..100' "
2982 "default='75'/>"
2983 " <Option name='JP2_QUALITY' type='string' description='For JP2-F compression, single quality value or comma separated list "
2984 "of increasing quality values for several layers, each in the 0-100 range' default='25'/>"
2985 " <Option name='JP2_BLOCKXSIZE' type='int' description='For JP2 compression, tile Width' default='1024'/>"
2986 " <Option name='JP2_BLOCKYSIZE' type='int' description='For JP2 compression, tile Height' default='1024'/>"
2987 " <Option name='JP2_REVERSIBLE' type='boolean' description='For JP2-F compression, True if the compression is reversible' default='false'/>"
2988 " <Option name='JP2_RESOLUTIONS' type='int' description='For JP2-F compression, Number of resolutions.' min='1' max='30'/>"
2989 " <Option name='JP2_PROGRESSION' type='string-select' description='For JP2-F compression, progression order' default='LRCP'>"
2990 " <Value>LRCP</Value>"
2991 " <Value>RLCP</Value>"
2992 " <Value>RPCL</Value>"
2993 " <Value>PCRL</Value>"
2994 " <Value>CPRL</Value>"
2995 " </Option>"
2996 "</CreationOptionList>" );
2997
2998 poDriver->pfnOpen = GeoRasterDataset::Open;
2999 poDriver->pfnCreate = GeoRasterDataset::Create;
3000 poDriver->pfnCreateCopy = GeoRasterDataset::CreateCopy;
3001 poDriver->pfnIdentify = GeoRasterDataset::Identify;
3002 poDriver->pfnDelete = GeoRasterDataset::Delete;
3003
3004 GetGDALDriverManager()->RegisterDriver( poDriver );
3005
3006 VSIInstallOCILobHandler();
3007 }
3008