1 /******************************************************************************
2 *
3 * File : pgchipdataset.cpp
4 * Project: PGCHIP Driver
5 * Purpose: GDALDataset code for POSTGIS CHIP/GDAL Driver
6 * Author: Benjamin Simon, noumayoss@gmail.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2005, Benjamin Simon, noumayoss@gmail.com
10 * Copyright (c) 2008, Even Rouault <even dot rouault at mines-paris dot org>
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 * Revision 1.1 2005/08/29 bsimon
32 * New
33 *
34 */
35
36 #include "pgchip.h"
37
38 /* Define to enable debugging info */
39 /*#define PGCHIP_DEBUG 1*/
40
41 CPL_C_START
42 void GDALRegister_PGCHIP(void);
43 CPL_C_END
44
45
46 /************************************************************************/
47 /* ==================================================================== */
48 /* PGCHIPDataset */
49 /* ==================================================================== */
50 /************************************************************************/
51
52
53 /************************************************************************/
54 /* PGCHIPDataset() */
55 /************************************************************************/
56
PGCHIPDataset()57 PGCHIPDataset::PGCHIPDataset(){
58
59 hPGConn = NULL;
60 pszTableName = NULL;
61 pszDSName = NULL;
62 PGCHIP = NULL;
63
64 bGeoTransformValid = FALSE;
65 adfGeoTransform[0] = 0.0;
66 adfGeoTransform[1] = 1.0;
67 adfGeoTransform[2] = 0.0;
68 adfGeoTransform[3] = 0.0;
69 adfGeoTransform[4] = 0.0;
70 adfGeoTransform[5] = 1.0;
71
72 SRID = -1;
73 pszProjection = CPLStrdup("");
74
75 bHaveNoData = FALSE;
76 dfNoDataValue = -1;
77 }
78
79 /************************************************************************/
80 /* ~PGCHIPDataset() */
81 /************************************************************************/
82
~PGCHIPDataset()83 PGCHIPDataset::~PGCHIPDataset(){
84
85 if( hPGConn != NULL )
86 {
87 /* XXX - mloskot: After the connection is closed, valgrind still
88 * reports 36 bytes definitely lost, somewhere in the libpq.
89 */
90 PQfinish( hPGConn );
91 hPGConn = NULL;
92 }
93
94 CPLFree(pszProjection);
95 CPLFree(pszTableName);
96 CPLFree(pszDSName);
97 CPLFree(PGCHIP);
98 }
99
100 /************************************************************************/
101 /* GetGeoTransform() */
102 /************************************************************************/
103
GetGeoTransform(double * padfTransform)104 CPLErr PGCHIPDataset::GetGeoTransform( double * padfTransform ){
105
106 memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
107
108 if( bGeoTransformValid )
109 return CE_None;
110 else
111 return CE_Failure;
112 }
113
114 /************************************************************************/
115 /* GetProjectionRef() */
116 /************************************************************************/
117
GetProjectionRef()118 const char *PGCHIPDataset::GetProjectionRef(){
119
120 char szCommand[1024];
121 PGresult *hResult;
122
123 if(SRID == -1)
124 {
125 return "";
126 }
127
128 /* -------------------------------------------------------------------- */
129 /* Reading proj */
130 /* -------------------------------------------------------------------- */
131
132 sprintf( szCommand,"SELECT srtext FROM spatial_ref_sys where SRID=%d",SRID);
133
134 hResult = PQexec(hPGConn,szCommand);
135
136 if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
137 && PQntuples(hResult) > 0 )
138 {
139 CPLFree(pszProjection);
140 pszProjection = CPLStrdup(PQgetvalue(hResult,0,0));
141 }
142
143 if( hResult )
144 PQclear( hResult );
145
146 return pszProjection;
147 }
148
149 /************************************************************************/
150 /* PGChipOpenConnection() */
151 /************************************************************************/
152
153 static
PGChipOpenConnection(const char * pszFilename,char ** ppszTableName,const char ** ppszDSName,int bExitOnMissingTable,int * pbExistTable,int * pbHasNameCol)154 PGconn* PGChipOpenConnection(const char* pszFilename, char** ppszTableName, const char** ppszDSName,
155 int bExitOnMissingTable, int* pbExistTable, int *pbHasNameCol)
156 {
157 char *pszConnectionString;
158 PGconn *hPGConn;
159 PGresult *hResult = NULL;
160 int i=0;
161 int bHavePostGIS;
162 char *pszTableName;
163 char szCommand[1024];
164
165 if( pszFilename == NULL || !EQUALN(pszFilename,"PG:",3))
166 return NULL;
167
168 pszConnectionString = CPLStrdup(pszFilename);
169
170 /* -------------------------------------------------------------------- */
171 /* Try to establish connection. */
172 /* -------------------------------------------------------------------- */
173 while(pszConnectionString[i] != '\0')
174 {
175
176 if(pszConnectionString[i] == '#')
177 pszConnectionString[i] = ' ';
178 else if(pszConnectionString[i] == '%')
179 {
180 pszConnectionString[i] = '\0';
181 break;
182 }
183 i++;
184 }
185
186 hPGConn = PQconnectdb( pszConnectionString + 3 );
187 if( hPGConn == NULL || PQstatus(hPGConn) == CONNECTION_BAD )
188 {
189 CPLError( CE_Failure, CPLE_AppDefined,
190 "PGconnectcb failed.\n%s",
191 PQerrorMessage(hPGConn) );
192 PQfinish(hPGConn);
193 CPLFree(pszConnectionString);
194 return NULL;
195 }
196
197 /* -------------------------------------------------------------------- */
198 /* Test to see if this database instance has support for the */
199 /* PostGIS Geometry type. If so, disable sequential scanning */
200 /* so we will get the value of the gist indexes. */
201 /* -------------------------------------------------------------------- */
202
203 hResult = PQexec(hPGConn,
204 "SELECT oid FROM pg_type WHERE typname = 'geometry'" );
205
206 if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
207 && PQntuples(hResult) > 0 )
208 {
209 bHavePostGIS = TRUE;
210 }
211
212 if( hResult )
213 PQclear( hResult );
214
215 if(!bHavePostGIS){
216 CPLError( CE_Failure, CPLE_AppDefined,
217 "Can't find geometry type, is Postgis correctly installed ?\n");
218 PQfinish(hPGConn);
219 CPLFree(pszConnectionString);
220 return NULL;
221 }
222
223 /* -------------------------------------------------------------------- */
224 /* Try opening the layer */
225 /* -------------------------------------------------------------------- */
226
227 if( strstr(pszFilename, "layer=") != NULL )
228 {
229 pszTableName = CPLStrdup( strstr(pszFilename, "layer=") + 6 );
230 }
231 else
232 {
233 pszTableName = CPLStrdup("unknown_layer");
234 }
235
236 char* pszDSName = strstr(pszTableName, "%name=");
237 if (pszDSName)
238 {
239 *pszDSName = '\0';
240 pszDSName += 6;
241 }
242 else
243 pszDSName = "unknown_name";
244
245 sprintf( szCommand,
246 "select b.attname from pg_class a,pg_attribute b where a.oid=b.attrelid and a.relname='%s' and b.attname='raster';",
247 pszTableName);
248
249 hResult = PQexec(hPGConn,szCommand);
250
251 if( ! (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK && PQntuples(hResult) > 0) )
252 {
253 if (pbExistTable)
254 *pbExistTable = FALSE;
255
256 if (bExitOnMissingTable)
257 {
258 if (hResult)
259 PQclear( hResult );
260 CPLFree(pszConnectionString);
261 CPLFree(pszTableName);
262 PQfinish(hPGConn);
263 return NULL;
264 }
265 }
266 else
267 {
268 if (pbExistTable)
269 *pbExistTable = TRUE;
270
271 sprintf( szCommand,
272 "select b.attname from pg_class a,pg_attribute b where a.oid=b.attrelid and a.relname='%s' and b.attname='name';",
273 pszTableName);
274
275 if (hResult)
276 PQclear( hResult );
277 hResult = PQexec(hPGConn,szCommand);
278 if (PQresultStatus(hResult) == PGRES_TUPLES_OK && PQntuples(hResult) > 0)
279 {
280 if (pbHasNameCol)
281 *pbHasNameCol = TRUE;
282 }
283 else
284 {
285 if (pbHasNameCol)
286 *pbHasNameCol = FALSE;
287 }
288 }
289
290 if (hResult)
291 PQclear( hResult );
292
293 if (ppszTableName)
294 *ppszTableName = pszTableName;
295 else
296 CPLFree(pszTableName);
297
298 if (ppszDSName)
299 *ppszDSName = pszDSName;
300
301 CPLFree(pszConnectionString);
302
303 return hPGConn;
304 }
305
306
307
308 /************************************************************************/
309 /* Open() */
310 /************************************************************************/
311
Open(GDALOpenInfo * poOpenInfo)312 GDALDataset *PGCHIPDataset::Open( GDALOpenInfo * poOpenInfo ){
313
314 char szCommand[1024];
315 PGresult *hResult = NULL;
316 PGCHIPDataset *poDS = NULL;
317 char *chipStringHex;
318
319 unsigned char *chipdata;
320 int t;
321 char *pszTableName = NULL;
322 const char *pszDSName = NULL;
323 int bHasNameCol = FALSE;
324
325 PGconn* hPGConn = PGChipOpenConnection(poOpenInfo->pszFilename, &pszTableName, &pszDSName, TRUE, NULL, &bHasNameCol);
326
327 if( hPGConn == NULL)
328 return NULL;
329
330 poDS = new PGCHIPDataset();
331 poDS->hPGConn = hPGConn;
332 poDS->pszTableName = pszTableName;
333 poDS->pszDSName = CPLStrdup(pszDSName);
334
335 /* -------------------------------------------------------------------- */
336 /* Read the chip */
337 /* -------------------------------------------------------------------- */
338
339 hResult = PQexec(poDS->hPGConn, "BEGIN");
340
341 if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
342 {
343 PQclear( hResult );
344 if (bHasNameCol)
345 sprintf( szCommand,
346 "SELECT raster FROM %s WHERE name = '%s' LIMIT 1 ",
347 poDS->pszTableName, poDS->pszDSName);
348 else
349 sprintf( szCommand,
350 "SELECT raster FROM %s LIMIT 1",
351 poDS->pszTableName);
352
353 hResult = PQexec(poDS->hPGConn,szCommand);
354 }
355
356 if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
357 {
358 CPLError( CE_Failure, CPLE_AppDefined,
359 "%s", PQerrorMessage(poDS->hPGConn) );
360 if (hResult)
361 PQclear( hResult );
362 delete poDS;
363 return NULL;
364 }
365
366 if (PQntuples(hResult) == 0)
367 {
368 PQclear( hResult );
369 delete poDS;
370 return NULL;
371 }
372
373 chipStringHex = PQgetvalue(hResult, 0, 0);
374
375 if (chipStringHex == NULL)
376 {
377 PQclear( hResult );
378 delete poDS;
379 return NULL;
380 }
381
382 int stringlen = strlen((char *)chipStringHex);
383
384 // Allocating memory for chip
385 chipdata = (unsigned char *) CPLMalloc(stringlen/2);
386
387 for (t=0;t<stringlen/2;t++){
388 chipdata[t] = parse_hex( &chipStringHex[t*2]) ;
389 }
390
391 // Chip assigment
392 poDS->PGCHIP = (CHIP *)chipdata;
393 poDS->SRID = poDS->PGCHIP->SRID;
394
395 if (poDS->PGCHIP->bvol.xmin != 0 && poDS->PGCHIP->bvol.ymin != 0 &
396 poDS->PGCHIP->bvol.xmax != 0 && poDS->PGCHIP->bvol.ymax != 0)
397 {
398 poDS->bGeoTransformValid = TRUE;
399
400 poDS->adfGeoTransform[0] = poDS->PGCHIP->bvol.xmin;
401 poDS->adfGeoTransform[3] = poDS->PGCHIP->bvol.ymax;
402 poDS->adfGeoTransform[1] = (poDS->PGCHIP->bvol.xmax - poDS->PGCHIP->bvol.xmin) / poDS->PGCHIP->width;
403 poDS->adfGeoTransform[5] = - (poDS->PGCHIP->bvol.ymax - poDS->PGCHIP->bvol.ymin) / poDS->PGCHIP->height;
404 }
405
406 #ifdef PGCHIP_DEBUG
407 poDS->printChipInfo(*(poDS->PGCHIP));
408 #endif
409
410 PQclear( hResult );
411
412 hResult = PQexec(poDS->hPGConn, "COMMIT");
413 PQclear( hResult );
414
415 /* -------------------------------------------------------------------- */
416 /* Verify that there's no unknown field set. */
417 /* -------------------------------------------------------------------- */
418
419 if ( poDS->PGCHIP->future[0] != 0 ||
420 poDS->PGCHIP->future[1] != 0 ||
421 poDS->PGCHIP->future[2] != 0 ||
422 poDS->PGCHIP->future[3] != 0 )
423 {
424 CPLError( CE_Failure, CPLE_AppDefined,
425 "Unsupported CHIP format (future field bytes != 0)\n");
426 delete poDS;
427 return NULL;
428 }
429
430 if ( poDS->PGCHIP->compression != 0 )
431 {
432 CPLError( CE_Failure, CPLE_AppDefined,
433 "Compressed CHIP unsupported\n");
434 delete poDS;
435 return NULL;
436 }
437
438 /* -------------------------------------------------------------------- */
439 /* Set some information from the file that is of interest. */
440 /* -------------------------------------------------------------------- */
441
442 poDS->nRasterXSize = poDS->PGCHIP->width;
443 poDS->nRasterYSize = poDS->PGCHIP->height;
444 poDS->nBands = 1; // (int)poDS->PGCHIP->future[0];
445 //poDS->nBitDepth = (int)poDS->PGCHIP->future[1];
446 poDS->nColorType = PGCHIP_COLOR_TYPE_GRAY; //(int)poDS->PGCHIP->future[2];
447
448 switch (poDS->PGCHIP->datatype)
449 {
450 case 5: // 24bit integer
451 poDS->nBitDepth = 24;
452 break;
453 case 6: // 16bit integer
454 poDS->nBitDepth = 16;
455 break;
456 case 8:
457 poDS->nBitDepth = 8;
458 break;
459 case 1: // float32
460 case 7: // 16bit ???
461 case 101: // float32 (NDR)
462 case 105: // 24bit integer (NDR)
463 case 106: // 16bit integer (NDR)
464 case 107: // 16bit ??? (NDR)
465 case 108: // 8bit ??? (NDR) [ doesn't make sense ]
466 default :
467 CPLError( CE_Failure, CPLE_AppDefined,
468 "Under development : CHIP datatype %d unsupported.\n",
469 poDS->PGCHIP->datatype);
470 break;
471 }
472
473
474 /* -------------------------------------------------------------------- */
475 /* Create band information objects. */
476 /* -------------------------------------------------------------------- */
477 for( int iBand = 0; iBand < poDS->nBands; iBand++ )
478 poDS->SetBand( iBand+1, new PGCHIPRasterBand( poDS, iBand+1 ) );
479
480
481 /* -------------------------------------------------------------------- */
482 /* Is there a palette? Note: we should also read back and */
483 /* apply transparency values if available. */
484 /* -------------------------------------------------------------------- */
485 CPLAssert (poDS->nColorType != PGCHIP_COLOR_TYPE_PALETTE);
486 if( poDS->nColorType == PGCHIP_COLOR_TYPE_PALETTE )
487 {
488 unsigned char *pPalette;
489 int nColorCount = 0;
490 int sizePalette = 0;
491 int offsetColor = -1;
492 GDALColorEntry oEntry;
493
494 nColorCount = (int)poDS->PGCHIP->compression;
495 pPalette = (unsigned char *)chipdata + sizeof(CHIP);
496 sizePalette = nColorCount * sizeof(pgchip_color);
497
498 poDS->poColorTable = new GDALColorTable();
499
500 for( int iColor = 0; iColor < nColorCount; iColor++ )
501 {
502 oEntry.c1 = pPalette[offsetColor++];
503 oEntry.c2 = pPalette[offsetColor++];
504 oEntry.c3 = pPalette[offsetColor++];
505 oEntry.c4 = pPalette[offsetColor++];
506
507 poDS->poColorTable->SetColorEntry( iColor, &oEntry );
508 }
509 }
510
511 return( poDS );
512 }
513
514
515 /************************************************************************/
516 /* PGCHIPCreateCopy() */
517 /************************************************************************/
PGCHIPCreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)518 static GDALDataset * PGCHIPCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
519 int bStrict, char ** papszOptions,
520 GDALProgressFunc pfnProgress, void * pProgressData ){
521
522
523 PGconn *hPGConn;
524 char *pszTableName = NULL;
525 const char *pszDSName = NULL;
526 char* pszCommand;
527 PGresult *hResult;
528 char *pszProjection;
529 int SRID;
530 GDALColorTable *poCT= NULL;
531 int bTableExists = FALSE;
532 int bHasNameCol = FALSE;
533
534 int nXSize = poSrcDS->GetRasterXSize();
535 int nYSize = poSrcDS->GetRasterYSize();
536 int nBands = poSrcDS->GetRasterCount();
537
538 /* -------------------------------------------------------------------- */
539 /* Some some rudimentary checks */
540 /* -------------------------------------------------------------------- */
541
542 /* check number of bands */
543 if( nBands != 1 && nBands != 4)
544 {
545 CPLError( CE_Failure, CPLE_NotSupported,
546 "Under development : PGCHIP driver doesn't support %d bands. Must be 1 or 4\n", nBands );
547
548 return NULL;
549 }
550
551 if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
552 && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt16)
553 {
554 CPLError( CE_Failure, CPLE_NotSupported,
555 "Under development : PGCHIP driver doesn't support data type %s. "
556 "Only eight bit (Byte) and sixteen bit (UInt16) bands supported.\n",
557 GDALGetDataTypeName(
558 poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
559
560 return NULL;
561 }
562
563 hPGConn = PGChipOpenConnection(pszFilename, &pszTableName, &pszDSName, FALSE, &bTableExists, &bHasNameCol);
564
565 /* Check Postgis connection string */
566 if( hPGConn == NULL){
567 CPLError( CE_Failure, CPLE_NotSupported,
568 "Cannont connect to %s.\n", pszFilename);
569 return NULL;
570 }
571
572 /* -------------------------------------------------------------------- */
573 /* Setup some parameters. */
574 /* -------------------------------------------------------------------- */
575
576 int nBitDepth;
577 GDALDataType eType;
578 int storageChunk;
579 int nColorType=0;
580
581
582 if( nBands == 1 && poSrcDS->GetRasterBand(1)->GetColorTable() == NULL ){
583 nColorType = PGCHIP_COLOR_TYPE_GRAY;
584 }
585 else if( nBands == 1 ){
586 nColorType = PGCHIP_COLOR_TYPE_PALETTE;
587 }
588 else if( nBands == 4 ){
589 nColorType = PGCHIP_COLOR_TYPE_RGB_ALPHA;
590 }
591
592 if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt16 )
593 {
594 eType = GDT_Byte;
595 nBitDepth = 8;
596 }
597 else
598 {
599 eType = GDT_UInt16;
600 nBitDepth = 16;
601 }
602
603 storageChunk = nBitDepth/8;
604
605 //printf("nBands = %d, nBitDepth = %d\n",nBands,nBitDepth);
606
607 pszCommand = (char*)CPLMalloc(1024);
608
609 if(!bTableExists){
610 sprintf( pszCommand,
611 "CREATE TABLE %s(raster chip, name varchar)",
612 pszTableName);
613
614 hResult = PQexec(hPGConn,pszCommand);
615 bHasNameCol = TRUE;
616 }
617 else
618 {
619 if (bHasNameCol)
620 sprintf( pszCommand,
621 "DELETE FROM %s WHERE name = '%s'", pszTableName, pszDSName);
622 else
623 sprintf( pszCommand,
624 "DELETE FROM %s", pszTableName);
625
626 hResult = PQexec(hPGConn,pszCommand);
627 }
628
629 if( hResult && (PQresultStatus(hResult) == PGRES_COMMAND_OK || PQresultStatus(hResult) == PGRES_TUPLES_OK)){
630 PQclear( hResult );
631 }
632 else {
633 CPLError( CE_Failure, CPLE_AppDefined,
634 "%s", PQerrorMessage(hPGConn) );
635 PQfinish( hPGConn );
636 hPGConn = NULL;
637 return NULL;
638 }
639
640 /* -------------------------------------------------------------------- */
641 /* Projection, finding SRID */
642 /* -------------------------------------------------------------------- */
643
644 pszProjection = (char *)poSrcDS->GetProjectionRef();
645 SRID = -1;
646
647 if( !EQUALN(pszProjection,"GEOGCS",6)
648 && !EQUALN(pszProjection,"PROJCS",6)
649 && !EQUALN(pszProjection,"+",6)
650 && !EQUAL(pszProjection,"") )
651 {
652 CPLError( CE_Failure, CPLE_AppDefined,
653 "Only OGC WKT Projections supported for writing to Postgis.\n"
654 "%s not supported.",
655 pszProjection );
656 }
657
658
659 if( pszProjection[0]=='+')
660 sprintf( pszCommand,"SELECT SRID FROM spatial_ref_sys where proj4text=%s",pszProjection);
661 else
662 sprintf( pszCommand,"SELECT SRID FROM spatial_ref_sys where srtext=%s",pszProjection);
663
664 hResult = PQexec(hPGConn,pszCommand);
665
666 if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
667 && PQntuples(hResult) > 0 ){
668
669 SRID = atoi(PQgetvalue(hResult,0,0));
670
671 }
672
673 // Try to find SRID via EPSG number
674 if (SRID == -1 && strcmp(pszProjection,"") != 0){
675
676 char *buf;
677 char epsg[16];
678 memset(epsg,0,16);
679 const char *workingproj = pszProjection;
680
681 while( (buf = strstr(workingproj,"EPSG")) != 0){
682 workingproj = buf+4;
683 }
684
685 int iChar = 0;
686 workingproj = workingproj + 3;
687
688
689 while(workingproj[iChar] != '"' && iChar < 15){
690 epsg[iChar] = workingproj[iChar];
691 iChar++;
692 }
693
694 if(epsg[0] != 0){
695 SRID = atoi(epsg);
696 }
697 }
698 else{
699 CPLError( CE_Failure, CPLE_AppDefined,
700 "Projection %s not found in spatial_ref_sys table. SRID will be set to -1.\n",
701 pszProjection );
702
703 SRID = -1;
704 }
705
706 if( hResult )
707 PQclear( hResult );
708
709
710 /* -------------------------------------------------------------------- */
711 /* Write palette if there is one. Technically, I think it is */
712 /* possible to write 16bit palettes for PNG, but we will omit */
713 /* this for now. */
714 /* -------------------------------------------------------------------- */
715
716 unsigned char *pPalette = NULL;
717 int bHaveNoData = FALSE;
718 double dfNoDataValue = -1;
719 int nbColors = 0,bFoundTrans = FALSE;
720 size_t sizePalette = 0;
721
722 if( nColorType == PGCHIP_COLOR_TYPE_PALETTE )
723 {
724
725 GDALColorEntry sEntry;
726 int iColor;
727 int offsetColor = -1;
728
729 poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
730 nbColors = poCT->GetColorEntryCount();
731
732 sizePalette += sizeof(pgchip_color) * poCT->GetColorEntryCount();
733
734 pPalette = (unsigned char *) CPLMalloc(sizePalette);
735
736
737 for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ )
738 {
739 poCT->GetColorEntryAsRGB( iColor, &sEntry );
740 if( sEntry.c4 != 255 )
741 bFoundTrans = TRUE;
742
743 pPalette[offsetColor++] = (unsigned char) sEntry.c1;
744 pPalette[offsetColor++] = (unsigned char) sEntry.c2;
745 pPalette[offsetColor++] = (unsigned char) sEntry.c3;
746
747
748 if( bHaveNoData && iColor == (int) dfNoDataValue ){
749 pPalette[offsetColor++] = 0;
750 }
751 else{
752 pPalette[offsetColor++] = (unsigned char) sEntry.c4;
753 }
754 }
755 }
756
757
758 /* -------------------------------------------------------------------- */
759 /* Initialize CHIP Structure */
760 /* -------------------------------------------------------------------- */
761
762 CHIP PGCHIP;
763
764 memset(&PGCHIP,0,sizeof(PGCHIP));
765
766 PGCHIP.factor = 1.0;
767 PGCHIP.endian_hint = 1;
768 PGCHIP.compression = 0; // nbColors; // To cope with palette extra information : <header><palette><data>
769 PGCHIP.height = nYSize;
770 PGCHIP.width = nXSize;
771 PGCHIP.SRID = SRID;
772 PGCHIP.future[0] = 0; // nBands; //nBands is stored in future variable
773 PGCHIP.future[1] = 0; // nBitDepth; //nBitDepth is stored in future variable
774 PGCHIP.future[2] = 0; // nColorType; //nBitDepth is stored in future variable
775 PGCHIP.future[3] = 0; // nbColors; // Useless as we store nbColors in the "compression" integer
776 PGCHIP.data = NULL; // Serialized Form
777
778 double adfGeoTransform[6];
779 if (GDALGetGeoTransform(poSrcDS, adfGeoTransform) == CE_None)
780 {
781 if (adfGeoTransform[2] == 0 &&
782 adfGeoTransform[4] == 0 &&
783 adfGeoTransform[5] < 0)
784 {
785 PGCHIP.bvol.xmin = adfGeoTransform[0];
786 PGCHIP.bvol.ymax = adfGeoTransform[3];
787 PGCHIP.bvol.xmax = adfGeoTransform[0] + nXSize * adfGeoTransform[1];
788 PGCHIP.bvol.ymin = adfGeoTransform[3] + nYSize * adfGeoTransform[5];
789 }
790 else
791 {
792 CPLError( CE_Warning, CPLE_AppDefined,
793 "Could not write geotransform.\n" );
794 }
795 }
796
797 // PGCHIP.size changes if there is a palette.
798 // Is calculated by Postgis when inserting anyway
799 PGCHIP.size = sizeof(CHIP) - sizeof(void*) + (nYSize * nXSize * storageChunk * nBands) + sizePalette;
800
801 switch(nBitDepth)
802 {
803 case 8:
804 PGCHIP.datatype = 8; // NDR|XDR ?
805 break;
806 case 16:
807 PGCHIP.datatype = 6; // NDR|XDR ?
808 break;
809 case 24:
810 PGCHIP.datatype = 5; // NDR|XDR ?
811 break;
812 default:
813 CPLError( CE_Failure, CPLE_AppDefined,"Under development : ERROR STORAGE CHUNK SIZE NOT SUPPORTED\n");
814 break;
815 }
816
817 #ifdef PGCHIP_DEBUG
818 PGCHIPDataset::printChipInfo(PGCHIP);
819 #endif
820
821 /* -------------------------------------------------------------------- */
822 /* Loop over image */
823 /* -------------------------------------------------------------------- */
824
825 CPLErr eErr;
826 size_t lineSize = nXSize * storageChunk * nBands;
827
828 // allocating data buffer
829 GByte *data = (GByte *) CPLMalloc( nYSize * lineSize);
830
831 for( int iLine = 0; iLine < nYSize; iLine++ ){
832 for( int iBand = 0; iBand < nBands; iBand++ ){
833
834 GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
835
836 eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
837 data + (iBand*storageChunk) + iLine * lineSize,
838 nXSize, 1, eType,
839 nBands * storageChunk,
840 lineSize );
841 }
842 }
843
844
845 /* -------------------------------------------------------------------- */
846 /* Write Header, Palette and Data */
847 /* -------------------------------------------------------------------- */
848
849 char *result;
850 size_t j=0;
851
852 // Calculating result length (*2 -> Hex form, +1 -> end string)
853 size_t size_result = (PGCHIP.size * 2) + 1;
854
855 // memory allocation
856 result = (char *) CPLMalloc( size_result * sizeof(char));
857
858 // Assign chip
859 GByte *header = (GByte *)&PGCHIP;
860
861 // Copy header into result string
862 for(j=0; j<sizeof(PGCHIP)-sizeof(void*); j++) {
863 pgch_deparse_hex( header[j], (unsigned char*)&(result[j*2]));
864 }
865
866 // Copy Palette into result string if required
867 size_t offsetPalette = (sizeof(PGCHIP)-sizeof(void*)) * 2;
868 if(nColorType == PGCHIP_COLOR_TYPE_PALETTE && sizePalette>0){
869 for(j=0;j<sizePalette;j++){
870 pgch_deparse_hex( pPalette[j], (unsigned char *)&result[offsetPalette + (j*2)]);
871 }
872 }
873
874 // Copy data into result string
875 size_t offsetData = offsetPalette + sizePalette * 2;
876 for(j=0;j<(nYSize * lineSize);j++){
877 pgch_deparse_hex( data[j], (unsigned char *)&result[offsetData + (j*2)]);
878 }
879
880
881 // end string
882 result[offsetData + j*2] = '\0';
883
884
885 /* -------------------------------------------------------------------- */
886 /* Inserting Chip */
887 /* -------------------------------------------------------------------- */
888
889 // Second allocation to cope with data size
890 CPLFree(pszCommand);
891 pszCommand = (char *)CPLMalloc(PGCHIP.size*2 + 256);
892
893 hResult = PQexec(hPGConn, "BEGIN");
894
895 if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
896 {
897
898 PQclear( hResult );
899 if (bHasNameCol)
900 sprintf( pszCommand,
901 "INSERT INTO %s(raster, name) values('%s', '%s')",
902 pszTableName,result, pszDSName);
903 else
904 sprintf( pszCommand,
905 "INSERT INTO %s(raster) values('%s')",
906 pszTableName,result);
907
908
909 hResult = PQexec(hPGConn,pszCommand);
910
911 }
912
913 CPLFree(pszTableName); pszTableName = NULL;
914
915 if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK ){
916 PQclear( hResult );
917 }
918 else {
919 CPLError( CE_Failure, CPLE_AppDefined,
920 "%s", PQerrorMessage(hPGConn) );
921 CPLFree(pszCommand); pszCommand = NULL;
922 PQfinish( hPGConn );
923 hPGConn = NULL;
924 return NULL;
925 }
926
927 hResult = PQexec(hPGConn, "COMMIT");
928 PQclear( hResult );
929
930 CPLFree( pszCommand ); pszCommand = NULL;
931 CPLFree( pPalette ); pPalette = NULL;
932 CPLFree( data ); data = NULL;
933 CPLFree( result ); result = NULL;
934
935 PQfinish( hPGConn );
936 hPGConn = NULL;
937
938 return (GDALDataset *)GDALOpen(pszFilename,GA_Update);
939 }
940
941
942 /************************************************************************/
943 /* Display CHIP information */
944 /************************************************************************/
printChipInfo(const CHIP & c)945 void PGCHIPDataset::printChipInfo(const CHIP& c){
946
947 //if(this->PGCHIP != NULL){
948 printf("\n---< CHIP INFO >----\n");
949 printf("CHIP.datatype = %d\n", c.datatype);
950 printf("CHIP.compression = %d\n", c.compression);
951 printf("CHIP.size = %d\n", c.size);
952 printf("CHIP.factor = %f\n", c.factor);
953 printf("CHIP.width = %d\n", c.width);
954 printf("CHIP.height = %d\n", c.height);
955 //printf("CHIP.future[0] (nBands?) = %d\n", (int)c.future[0]);
956 //printf("CHIP.future[1] (nBitDepth?) = %d\n", (int)c.future[1]);
957 printf("--------------------\n");
958 //}
959 }
960
961 /************************************************************************/
962 /* PGCHIPDelete */
963 /************************************************************************/
PGCHIPDelete(const char * pszFilename)964 static CPLErr PGCHIPDelete(const char* pszFilename)
965 {
966 return CE_None;
967 }
968
969 /************************************************************************/
970 /* GDALRegister_PGCHIP() */
971 /************************************************************************/
GDALRegister_PGCHIP()972 void GDALRegister_PGCHIP(){
973
974 GDALDriver *poDriver;
975
976 if( GDALGetDriverByName( "PGCHIP" ) == NULL )
977 {
978 poDriver = new GDALDriver();
979
980 poDriver->SetDescription( "PGCHIP" );
981 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
982 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
983 "Postgis CHIP raster" );
984
985 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
986 "Byte UInt16" );
987
988 poDriver->pfnOpen = PGCHIPDataset::Open;
989 poDriver->pfnCreateCopy = PGCHIPCreateCopy;
990 poDriver->pfnDelete = PGCHIPDelete;
991
992 GetGDALDriverManager()->RegisterDriver( poDriver );
993 }
994 }
995
996