Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: AirSAR Reader
4 : * Purpose: Implements read support for AirSAR Polarimetric data.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2007-2009, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_conv.h"
15 : #include "cpl_string.h"
16 : #include "cpl_vsi.h"
17 : #include "gdal_frmts.h"
18 : #include "gdal_pam.h"
19 :
20 : /************************************************************************/
21 : /* ==================================================================== */
22 : /* AirSARDataset */
23 : /* ==================================================================== */
24 : /************************************************************************/
25 :
26 : class AirSARRasterBand;
27 :
28 : class AirSARDataset final : public GDALPamDataset
29 : {
30 : friend class AirSARRasterBand;
31 :
32 : VSILFILE *fp;
33 :
34 : int nLoadedLine;
35 : GByte *pabyCompressedLine;
36 : double *padfMatrix;
37 :
38 : int nDataStart;
39 : int nRecordLength;
40 :
41 : CPLErr LoadLine(int iLine);
42 :
43 : static char **ReadHeader(VSILFILE *fp, int nFileOffset,
44 : const char *pszPrefix, int nMaxLines);
45 :
46 : public:
47 : AirSARDataset();
48 : ~AirSARDataset();
49 :
50 : static GDALDataset *Open(GDALOpenInfo *);
51 : };
52 :
53 : /************************************************************************/
54 : /* ==================================================================== */
55 : /* AirSARRasterBand */
56 : /* ==================================================================== */
57 : /************************************************************************/
58 :
59 : class AirSARRasterBand final : public GDALPamRasterBand
60 : {
61 : public:
62 : AirSARRasterBand(AirSARDataset *, int);
63 : ~AirSARRasterBand() override;
64 :
65 : CPLErr IReadBlock(int, int, void *) override;
66 : };
67 :
68 : /* locations of stokes matrix values within padfMatrix ... same order as they
69 : are computed in the document. */
70 :
71 : constexpr int M11 = 0;
72 : constexpr int M12 = 1;
73 : constexpr int M13 = 2;
74 : constexpr int M14 = 3;
75 : constexpr int M23 = 4;
76 : constexpr int M24 = 5;
77 : constexpr int M33 = 6;
78 : constexpr int M34 = 7;
79 : constexpr int M44 = 8;
80 : constexpr int M22 = 9;
81 :
82 : /************************************************************************/
83 : /* AirSARRasterBand() */
84 : /************************************************************************/
85 :
86 0 : AirSARRasterBand::AirSARRasterBand(AirSARDataset *poDSIn, int nBandIn)
87 :
88 : {
89 0 : poDS = poDSIn;
90 0 : nBand = nBandIn;
91 :
92 0 : nBlockXSize = poDS->GetRasterXSize();
93 0 : nBlockYSize = 1;
94 :
95 0 : if (this->nBand == 2 || this->nBand == 3 || this->nBand == 5)
96 0 : eDataType = GDT_CFloat32;
97 : else
98 0 : eDataType = GDT_Float32;
99 :
100 0 : switch (nBand)
101 : {
102 0 : case 1:
103 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_11");
104 0 : SetDescription("Covariance_11");
105 0 : eDataType = GDT_CFloat32;
106 0 : break;
107 :
108 0 : case 2:
109 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_12");
110 0 : SetDescription("Covariance_12");
111 0 : eDataType = GDT_CFloat32;
112 0 : break;
113 :
114 0 : case 3:
115 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_13");
116 0 : SetDescription("Covariance_13");
117 0 : eDataType = GDT_CFloat32;
118 0 : break;
119 :
120 0 : case 4:
121 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_22");
122 0 : SetDescription("Covariance_22");
123 0 : eDataType = GDT_CFloat32;
124 0 : break;
125 :
126 0 : case 5:
127 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_23");
128 0 : SetDescription("Covariance_23");
129 0 : eDataType = GDT_CFloat32;
130 0 : break;
131 :
132 0 : case 6:
133 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_33");
134 0 : SetDescription("Covariance_33");
135 0 : eDataType = GDT_CFloat32;
136 0 : break;
137 : }
138 0 : }
139 :
140 : /************************************************************************/
141 : /* ~AirSARRasterBand() */
142 : /************************************************************************/
143 :
144 0 : AirSARRasterBand::~AirSARRasterBand()
145 :
146 : {
147 0 : }
148 :
149 : /************************************************************************/
150 : /* IReadBlock() */
151 : /************************************************************************/
152 :
153 0 : CPLErr AirSARRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
154 : void *pImage)
155 : {
156 0 : float *pafLine = (float *)pImage;
157 0 : const double SQRT_2 = 1.4142135623730951;
158 :
159 0 : CPLErr eErr = ((AirSARDataset *)poDS)->LoadLine(nBlockYOff);
160 0 : if (eErr != CE_None)
161 0 : return eErr;
162 :
163 0 : double *padfMatrix = ((AirSARDataset *)poDS)->padfMatrix;
164 :
165 0 : if (nBand == 1) /* C11 */
166 : {
167 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
168 : {
169 0 : double *m = padfMatrix + 10 * iPixel;
170 :
171 0 : pafLine[iPixel * 2 + 0] = (float)(m[M11] + m[M22] + 2 * m[M12]);
172 0 : pafLine[iPixel * 2 + 1] = 0.0;
173 : }
174 : }
175 0 : else if (nBand == 2) /* C12 */
176 : {
177 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
178 : {
179 0 : double *m = padfMatrix + 10 * iPixel;
180 :
181 : // real
182 0 : pafLine[iPixel * 2 + 0] = (float)(SQRT_2 * (m[M13] + m[M23]));
183 :
184 : // imaginary
185 0 : pafLine[iPixel * 2 + 1] = (float)(-SQRT_2 * (m[M24] + m[M14]));
186 : }
187 : }
188 0 : else if (nBand == 3) /* C13 */
189 : {
190 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
191 : {
192 0 : double *m = padfMatrix + 10 * iPixel;
193 :
194 : // real
195 0 : pafLine[iPixel * 2 + 0] = (float)(2 * m[M33] + m[M22] - m[M11]);
196 :
197 : // imaginary
198 0 : pafLine[iPixel * 2 + 1] = (float)(-2 * m[M34]);
199 : }
200 : }
201 0 : else if (nBand == 4) /* C22 */
202 : {
203 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
204 : {
205 0 : double *m = padfMatrix + 10 * iPixel;
206 :
207 0 : pafLine[iPixel * 2 + 0] = (float)(2 * (m[M11] - m[M22]));
208 0 : pafLine[iPixel * 2 + 1] = 0.0;
209 : }
210 : }
211 0 : else if (nBand == 5) /* C23 */
212 : {
213 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
214 : {
215 0 : double *m = padfMatrix + 10 * iPixel;
216 :
217 : // real
218 0 : pafLine[iPixel * 2 + 0] = (float)(SQRT_2 * (m[M13] - m[M23]));
219 :
220 : // imaginary
221 0 : pafLine[iPixel * 2 + 1] = (float)(SQRT_2 * (m[M24] - m[M14]));
222 : }
223 : }
224 0 : else if (nBand == 6) /* C33 */
225 : {
226 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
227 : {
228 0 : double *m = padfMatrix + 10 * iPixel;
229 :
230 0 : pafLine[iPixel * 2 + 0] = (float)(m[M11] + m[M22] - 2 * m[M12]);
231 0 : pafLine[iPixel * 2 + 1] = 0.0;
232 : }
233 : }
234 :
235 0 : return CE_None;
236 : }
237 :
238 : /************************************************************************/
239 : /* ==================================================================== */
240 : /* AirSARDataset */
241 : /* ==================================================================== */
242 : /************************************************************************/
243 :
244 : /************************************************************************/
245 : /* AirSARDataset() */
246 : /************************************************************************/
247 :
248 0 : AirSARDataset::AirSARDataset()
249 : : fp(nullptr), nLoadedLine(-1), pabyCompressedLine(nullptr),
250 0 : padfMatrix(nullptr), nDataStart(0), nRecordLength(0)
251 : {
252 0 : }
253 :
254 : /************************************************************************/
255 : /* ~AirSARDataset() */
256 : /************************************************************************/
257 :
258 0 : AirSARDataset::~AirSARDataset()
259 :
260 : {
261 0 : FlushCache(true);
262 0 : CPLFree(pabyCompressedLine);
263 0 : CPLFree(padfMatrix);
264 :
265 0 : if (fp != nullptr)
266 : {
267 0 : VSIFCloseL(fp);
268 0 : fp = nullptr;
269 : }
270 0 : }
271 :
272 : /************************************************************************/
273 : /* LoadLine() */
274 : /************************************************************************/
275 :
276 0 : CPLErr AirSARDataset::LoadLine(int iLine)
277 :
278 : {
279 0 : if (iLine == nLoadedLine)
280 0 : return CE_None;
281 :
282 : /* -------------------------------------------------------------------- */
283 : /* allocate working buffers if we don't have them already. */
284 : /* -------------------------------------------------------------------- */
285 0 : if (pabyCompressedLine == nullptr)
286 : {
287 0 : pabyCompressedLine = (GByte *)VSI_MALLOC2_VERBOSE(nRasterXSize, 10);
288 :
289 0 : padfMatrix =
290 0 : (double *)VSI_MALLOC2_VERBOSE(10 * sizeof(double), nRasterXSize);
291 0 : if (pabyCompressedLine == nullptr || padfMatrix == nullptr)
292 : {
293 0 : CPLFree(pabyCompressedLine);
294 0 : CPLFree(padfMatrix);
295 0 : return CE_Failure;
296 : }
297 : }
298 :
299 0 : CPLAssert(nRecordLength == nRasterXSize * 10);
300 :
301 : /* -------------------------------------------------------------------- */
302 : /* Load raw compressed data. */
303 : /* -------------------------------------------------------------------- */
304 0 : if (VSIFSeekL(fp, nDataStart + iLine * nRecordLength, SEEK_SET) != 0 ||
305 0 : ((int)VSIFReadL(pabyCompressedLine, 10, nRasterXSize, fp)) !=
306 0 : nRasterXSize)
307 : {
308 0 : CPLError(CE_Failure, CPLE_FileIO,
309 : "Error reading %d bytes for line %d at offset %d.\n%s",
310 0 : nRasterXSize * 10, iLine, nDataStart + iLine * nRecordLength,
311 0 : VSIStrerror(errno));
312 0 : return CE_Failure;
313 : }
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Build stokes matrix */
317 : /* -------------------------------------------------------------------- */
318 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
319 : {
320 0 : double *M = padfMatrix + 10 * iPixel;
321 0 : signed char *byte = (signed char *)pabyCompressedLine + 10 * iPixel - 1;
322 0 : const double gen_fac = 1.0; // should we have a general scale factor?
323 :
324 0 : M[M11] = (byte[2] / 254.0 + 1.5) * pow(2.0, byte[1]) * gen_fac;
325 0 : M[M12] = byte[3] * M[M11] / 127.0;
326 0 : M[M13] = byte[4] * fabs((double)byte[4]) * M[M11] / (127 * 127);
327 0 : M[M14] = byte[5] * fabs((double)byte[5]) * M[M11] / (127 * 127);
328 0 : M[M23] = byte[6] * fabs((double)byte[6]) * M[M11] / (127 * 127);
329 0 : M[M24] = byte[7] * fabs((double)byte[7]) * M[M11] / (127 * 127);
330 0 : M[M33] = byte[8] * M[M11] / 127;
331 0 : M[M34] = byte[9] * M[M11] / 127;
332 0 : M[M44] = byte[10] * M[M11] / 127;
333 0 : M[M22] = M[M11] - M[M33] - M[M44];
334 : }
335 :
336 0 : return CE_None;
337 : }
338 :
339 : /************************************************************************/
340 : /* ReadHeader() */
341 : /* */
342 : /* Read the AirSAR header. We assume an equal sign separates */
343 : /* the keyword name from the value. If not, assume the last */
344 : /* "blank delimited" word is the value and everything else is a */
345 : /* keyword. */
346 : /* */
347 : /* The records are 50 characters each. Read till we get an all */
348 : /* blank record or some zero bytes. */
349 : /************************************************************************/
350 :
351 0 : char **AirSARDataset::ReadHeader(VSILFILE *fp, int nFileOffset,
352 : const char *pszPrefix, int nMaxLines)
353 :
354 : {
355 0 : char **papszHeadInfo = nullptr;
356 : char szLine[51];
357 :
358 0 : VSIFSeekL(fp, nFileOffset, SEEK_SET);
359 :
360 : /* ==================================================================== */
361 : /* Loop collecting one line at a time. */
362 : /* ==================================================================== */
363 0 : for (int iLine = 0; iLine < nMaxLines; iLine++)
364 : {
365 : /* --------------------------------------------------------------------
366 : */
367 : /* Read a 50 byte header record. */
368 : /* --------------------------------------------------------------------
369 : */
370 0 : if (VSIFReadL(szLine, 1, 50, fp) != 50)
371 : {
372 0 : CPLError(CE_Failure, CPLE_FileIO,
373 : "Read error collecting AirSAR header.");
374 0 : CSLDestroy(papszHeadInfo);
375 0 : return nullptr;
376 : }
377 :
378 0 : szLine[50] = '\0';
379 :
380 : /* --------------------------------------------------------------------
381 : */
382 : /* Is it all spaces, or does it have a zero byte? */
383 : /* --------------------------------------------------------------------
384 : */
385 0 : bool bAllSpaces = true;
386 0 : bool bHasIllegalChars = false;
387 :
388 0 : for (int i = 0; i < 50; i++)
389 : {
390 0 : if (szLine[i] == '\0')
391 0 : break;
392 :
393 0 : if (szLine[i] != ' ')
394 0 : bAllSpaces = false;
395 :
396 0 : if (((unsigned char *)szLine)[i] > 127 ||
397 0 : ((unsigned char *)szLine)[i] < 10)
398 0 : bHasIllegalChars = true;
399 : }
400 :
401 0 : if (bAllSpaces || bHasIllegalChars)
402 : break;
403 :
404 : /* --------------------------------------------------------------------
405 : */
406 : /* Find the pivot between the keyword name and value. */
407 : /* --------------------------------------------------------------------
408 : */
409 0 : int iPivot = -1;
410 :
411 0 : for (int i = 0; i < 50; i++)
412 : {
413 0 : if (szLine[i] == '=')
414 : {
415 0 : iPivot = i;
416 0 : break;
417 : }
418 : }
419 :
420 : // If no "=" found, split on first double white space
421 0 : if (iPivot == -1)
422 : {
423 0 : for (int i = 48; i >= 0; i--)
424 : {
425 0 : if (szLine[i] == ' ' && szLine[i + 1] == ' ')
426 : {
427 0 : iPivot = i;
428 0 : break;
429 : }
430 : }
431 : }
432 :
433 0 : if (iPivot == -1) // Yikes!
434 : {
435 0 : CPLDebug("AIRSAR", "No pivot in line `%s'.", szLine);
436 0 : CPLAssert(iPivot != -1);
437 0 : break;
438 : }
439 :
440 : /* --------------------------------------------------------------------
441 : */
442 : /* Trace ahead to the first non-white space value character. */
443 : /* --------------------------------------------------------------------
444 : */
445 0 : int iValue = iPivot + 1;
446 :
447 0 : while (iValue < 50 && szLine[iValue] == ' ')
448 0 : iValue++;
449 :
450 : /* --------------------------------------------------------------------
451 : */
452 : /* Strip any white space off the keyword. */
453 : /* --------------------------------------------------------------------
454 : */
455 0 : int iKeyEnd = iPivot - 1;
456 :
457 0 : while (iKeyEnd > 0 && szLine[iKeyEnd] == ' ')
458 0 : iKeyEnd--;
459 :
460 0 : szLine[iKeyEnd + 1] = '\0';
461 :
462 : /* --------------------------------------------------------------------
463 : */
464 : /* Convert spaces or colons into underscores in the key name. */
465 : /* --------------------------------------------------------------------
466 : */
467 0 : for (int i = 0; szLine[i] != '\0'; i++)
468 : {
469 0 : if (szLine[i] == ' ' || szLine[i] == ':' || szLine[i] == ',')
470 0 : szLine[i] = '_';
471 : }
472 :
473 : /* --------------------------------------------------------------------
474 : */
475 : /* Prefix key name with provided prefix string. */
476 : /* --------------------------------------------------------------------
477 : */
478 : char szPrefixedKeyName[55];
479 :
480 0 : snprintf(szPrefixedKeyName, sizeof(szPrefixedKeyName), "%s_%s",
481 : pszPrefix, szLine);
482 :
483 : papszHeadInfo =
484 0 : CSLSetNameValue(papszHeadInfo, szPrefixedKeyName, szLine + iValue);
485 : }
486 :
487 0 : return papszHeadInfo;
488 : }
489 :
490 : /************************************************************************/
491 : /* Open() */
492 : /************************************************************************/
493 :
494 34472 : GDALDataset *AirSARDataset::Open(GDALOpenInfo *poOpenInfo)
495 :
496 : {
497 34472 : if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 800)
498 30273 : return nullptr;
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* Check for AirSAR/ keyword. */
502 : /* -------------------------------------------------------------------- */
503 4199 : if (!STARTS_WITH_CI((char *)poOpenInfo->pabyHeader,
504 : "RECORD LENGTH IN BYTES"))
505 4199 : return nullptr;
506 :
507 0 : if (strstr((char *)poOpenInfo->pabyHeader, "COMPRESSED") == nullptr ||
508 0 : strstr((char *)poOpenInfo->pabyHeader, "JPL AIRCRAFT") == nullptr)
509 0 : return nullptr;
510 :
511 : /* -------------------------------------------------------------------- */
512 : /* Parse the header fields. We turn all the transform the */
513 : /* keywords by converting spaces to underscores so they will be */
514 : /* "well behaved" as metadata keywords. */
515 : /* -------------------------------------------------------------------- */
516 0 : char **papszMD = ReadHeader(poOpenInfo->fpL, 0, "MH", 20);
517 :
518 0 : if (papszMD == nullptr)
519 0 : return nullptr;
520 :
521 : /* -------------------------------------------------------------------- */
522 : /* Confirm the requested access is supported. */
523 : /* -------------------------------------------------------------------- */
524 0 : if (poOpenInfo->eAccess == GA_Update)
525 : {
526 0 : CPLError(CE_Failure, CPLE_NotSupported,
527 : "The AIRSAR driver does not support update access to existing"
528 : " datasets.\n");
529 0 : CSLDestroy(papszMD);
530 0 : return nullptr;
531 : }
532 : /* -------------------------------------------------------------------- */
533 : /* Create a corresponding GDALDataset. */
534 : /* -------------------------------------------------------------------- */
535 0 : AirSARDataset *poDS = new AirSARDataset();
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* Extract some key information. */
539 : /* -------------------------------------------------------------------- */
540 :
541 0 : poDS->nRasterXSize =
542 0 : atoi(CSLFetchNameValue(papszMD, "MH_NUMBER_OF_SAMPLES_PER_RECORD"));
543 0 : poDS->nRasterYSize =
544 0 : atoi(CSLFetchNameValue(papszMD, "MH_NUMBER_OF_LINES_IN_IMAGE"));
545 :
546 0 : poDS->nRecordLength =
547 0 : atoi(CSLFetchNameValue(papszMD, "MH_RECORD_LENGTH_IN_BYTES"));
548 :
549 0 : poDS->nDataStart =
550 0 : atoi(CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_FIRST_DATA_RECORD"));
551 :
552 : /* -------------------------------------------------------------------- */
553 : /* Adopt the openinfo file pointer. */
554 : /* -------------------------------------------------------------------- */
555 0 : poDS->fp = poOpenInfo->fpL;
556 0 : poOpenInfo->fpL = nullptr;
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Read and merge parameter header into metadata. Prefix */
560 : /* parameter header values with PH_. */
561 : /* -------------------------------------------------------------------- */
562 0 : int nPHOffset = 0;
563 :
564 0 : if (CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_PARAMETER_HEADER") !=
565 : nullptr)
566 : {
567 0 : nPHOffset = atoi(
568 : CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_PARAMETER_HEADER"));
569 0 : char **papszPHInfo = ReadHeader(poDS->fp, nPHOffset, "PH", 100);
570 :
571 0 : papszMD = CSLInsertStrings(papszMD, CSLCount(papszMD), papszPHInfo);
572 :
573 0 : CSLDestroy(papszPHInfo);
574 : }
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Read and merge calibration header into metadata. Prefix */
578 : /* parameter header values with CH_. */
579 : /* -------------------------------------------------------------------- */
580 0 : if (nPHOffset != 0)
581 : {
582 : char **papszCHInfo =
583 0 : ReadHeader(poDS->fp, nPHOffset + poDS->nRecordLength, "CH", 18);
584 :
585 0 : papszMD = CSLInsertStrings(papszMD, CSLCount(papszMD), papszCHInfo);
586 :
587 0 : CSLDestroy(papszCHInfo);
588 : }
589 :
590 : /* -------------------------------------------------------------------- */
591 : /* Assign metadata to dataset. */
592 : /* -------------------------------------------------------------------- */
593 0 : poDS->SetMetadata(papszMD);
594 0 : CSLDestroy(papszMD);
595 :
596 : /* -------------------------------------------------------------------- */
597 : /* Create band information objects. */
598 : /* -------------------------------------------------------------------- */
599 0 : poDS->SetBand(1, new AirSARRasterBand(poDS, 1));
600 0 : poDS->SetBand(2, new AirSARRasterBand(poDS, 2));
601 0 : poDS->SetBand(3, new AirSARRasterBand(poDS, 3));
602 0 : poDS->SetBand(4, new AirSARRasterBand(poDS, 4));
603 0 : poDS->SetBand(5, new AirSARRasterBand(poDS, 5));
604 0 : poDS->SetBand(6, new AirSARRasterBand(poDS, 6));
605 :
606 0 : poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SYMMETRIZED_COVARIANCE");
607 :
608 : /* -------------------------------------------------------------------- */
609 : /* Initialize any PAM information. */
610 : /* -------------------------------------------------------------------- */
611 0 : poDS->SetDescription(poOpenInfo->pszFilename);
612 0 : poDS->TryLoadXML();
613 :
614 0 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
615 :
616 0 : return poDS;
617 : }
618 :
619 : /************************************************************************/
620 : /* GDALRegister_AirSAR() */
621 : /************************************************************************/
622 :
623 1595 : void GDALRegister_AirSAR()
624 :
625 : {
626 1595 : if (GDALGetDriverByName("AirSAR") != nullptr)
627 302 : return;
628 :
629 1293 : GDALDriver *poDriver = new GDALDriver();
630 :
631 1293 : poDriver->SetDescription("AirSAR");
632 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
633 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "AirSAR Polarimetric Image");
634 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/airsar.html");
635 :
636 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
637 :
638 1293 : poDriver->pfnOpen = AirSARDataset::Open;
639 :
640 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
641 : }
|