/src/gdal/frmts/jaxapalsar/jaxapalsardataset.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: PALSAR JAXA imagery reader |
4 | | * Purpose: Support for PALSAR L1.1/1.5 imagery and appropriate metadata from |
5 | | * JAXA and JAXA-supported ground stations (ASF, ESA, etc.). This |
6 | | * driver does not support ERSDAC products. |
7 | | * Author: Philippe Vachon <philippe@cowpig.ca> |
8 | | * |
9 | | ****************************************************************************** |
10 | | * Copyright (c) 2007, Philippe P. Vachon <philippe@cowpig.ca> |
11 | | * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com> |
12 | | * |
13 | | * SPDX-License-Identifier: MIT |
14 | | ****************************************************************************/ |
15 | | |
16 | | #include "gdal_frmts.h" |
17 | | #include "gdal_pam.h" |
18 | | #include "gdal_driver.h" |
19 | | #include "gdal_drivermanager.h" |
20 | | #include "gdal_openinfo.h" |
21 | | #include "gdal_cpp_functions.h" |
22 | | |
23 | | #if defined(_WIN32) |
24 | | #define SEP_STRING "\\" |
25 | | #else |
26 | 0 | #define SEP_STRING "/" |
27 | | #endif |
28 | | |
29 | | /* read binary fields */ |
30 | | #ifdef CPL_LSB |
31 | | #define READ_WORD(f, x) \ |
32 | 0 | do \ |
33 | 0 | { \ |
34 | 0 | VSIFReadL(&(x), 4, 1, (f)); \ |
35 | 0 | (x) = CPL_SWAP32((x)); \ |
36 | 0 | } while (false); |
37 | | #define READ_SHORT(f, x) \ |
38 | | do \ |
39 | | { \ |
40 | | VSIFReadL(&(x), 2, 1, (f)); \ |
41 | | (x) = CPL_SWAP16((x)); \ |
42 | | } while (false); |
43 | | #else |
44 | | #define READ_WORD(f, x) \ |
45 | | do \ |
46 | | { \ |
47 | | VSIFReadL(&(x), 4, 1, (f)); \ |
48 | | } while (false); |
49 | | #define READ_SHORT(f, x) \ |
50 | | do \ |
51 | | { \ |
52 | | VSIFReadL(&(x), 2, 1, (f)); \ |
53 | | } while (false); |
54 | | #endif /* def CPL_LSB */ |
55 | | #define READ_BYTE(f, x) \ |
56 | 0 | do \ |
57 | 0 | { \ |
58 | 0 | VSIFReadL(&(x), 1, 1, (f)); \ |
59 | 0 | } while (false); |
60 | | |
61 | | /* read floating point value stored as ASCII */ |
62 | | #define READ_CHAR_FLOAT(n, l, f) \ |
63 | 0 | do \ |
64 | 0 | { \ |
65 | 0 | char psBuf[(l + 1)]; \ |
66 | 0 | psBuf[(l)] = '\0'; \ |
67 | 0 | VSIFReadL(&psBuf, (l), 1, (f)); \ |
68 | 0 | (n) = CPLAtof(psBuf); \ |
69 | 0 | } while (false); |
70 | | |
71 | | /* read numbers stored as ASCII */ |
72 | | #define READ_CHAR_VAL(x, n, f) \ |
73 | 0 | do \ |
74 | 0 | { \ |
75 | 0 | char psBuf[(n + 1)]; \ |
76 | 0 | psBuf[(n)] = '\0'; \ |
77 | 0 | VSIFReadL(&psBuf, (n), 1, (f)); \ |
78 | 0 | (x) = atoi(psBuf); \ |
79 | 0 | } while (false); |
80 | | |
81 | | /* read string fields |
82 | | * note: string must be size of field to be extracted + 1 |
83 | | */ |
84 | | #define READ_STRING(s, n, f) \ |
85 | 0 | do \ |
86 | 0 | { \ |
87 | 0 | VSIFReadL(&(s), 1, (n), (f)); \ |
88 | 0 | (s)[(n)] = '\0'; \ |
89 | 0 | } while (false); |
90 | | |
91 | | /*************************************************************************/ |
92 | | /* a few key offsets in the volume directory file */ |
93 | | #define VOL_DESC_RECORD_LENGTH 360 |
94 | | #define FILE_PTR_RECORD_LENGTH 360 |
95 | | #define NUM_RECORDS_OFFSET 160 |
96 | | |
97 | | /* a few key offsets and values within the File Pointer record */ |
98 | | #define REF_FILE_CLASS_CODE_OFFSET 66 |
99 | | #define REF_FILE_CLASS_CODE_LENGTH 4 |
100 | | #define FILE_NAME_OFFSET 310 |
101 | | |
102 | | /* some image option descriptor records */ |
103 | 0 | #define BITS_PER_SAMPLE_OFFSET 216 |
104 | | #define BITS_PER_SAMPLE_LENGTH 4 |
105 | | #define SAMPLES_PER_GROUP_OFFSET 220 |
106 | | #define SAMPLES_PER_GROUP_LENGTH 4 |
107 | 0 | #define NUMBER_LINES_OFFSET 236 |
108 | | #define NUMBER_LINES_LENGTH 8 |
109 | 0 | #define SAR_DATA_RECORD_LENGTH_OFFSET 186 |
110 | | #define SAR_DATA_RECORD_LENGTH_LENGTH 6 |
111 | | |
112 | 0 | #define IMAGE_OPT_DESC_LENGTH 720 |
113 | | |
114 | 0 | #define SIG_DAT_REC_OFFSET 412 |
115 | 0 | #define PROC_DAT_REC_OFFSET 192 |
116 | | |
117 | | /* metadata to be extracted from the leader file */ |
118 | 0 | #define LEADER_FILE_DESCRIPTOR_LENGTH 720 |
119 | 0 | #define DATA_SET_SUMMARY_LENGTH 4096 |
120 | | |
121 | | /* relative to end of leader file descriptor */ |
122 | 0 | #define EFFECTIVE_LOOKS_AZIMUTH_OFFSET 1174 /* floating point text */ |
123 | | #define EFFECTIVE_LOOKS_AZIMUTH_LENGTH 16 |
124 | | |
125 | | /* relative to leader file descriptor + dataset summary length */ |
126 | 0 | #define PIXEL_SPACING_OFFSET 92 |
127 | | #define LINE_SPACING_OFFSET 108 |
128 | 0 | #define ALPHANUMERIC_PROJECTION_NAME_OFFSET 412 |
129 | 0 | #define TOP_LEFT_LAT_OFFSET 1072 |
130 | | #define TOP_LEFT_LON_OFFSET 1088 |
131 | | #define TOP_RIGHT_LAT_OFFSET 1104 |
132 | | #define TOP_RIGHT_LON_OFFSET 1120 |
133 | | #define BOTTOM_RIGHT_LAT_OFFSET 1136 |
134 | | #define BOTTOM_RIGHT_LON_OFFSET 1152 |
135 | | #define BOTTOM_LEFT_LAT_OFFSET 1168 |
136 | | #define BOTTOM_LEFT_LON_OFFSET 1184 |
137 | | |
138 | | namespace gdal::PSALSARJaxa |
139 | | { |
140 | | /* a few useful enums */ |
141 | | enum eFileType |
142 | | { |
143 | | level_11 = 0, |
144 | | level_15, |
145 | | level_10, |
146 | | level_unknown = 999, |
147 | | }; |
148 | | |
149 | | enum ePolarization |
150 | | { |
151 | | hh = 0, |
152 | | hv, |
153 | | vh, |
154 | | vv |
155 | | }; |
156 | | } // namespace gdal::PSALSARJaxa |
157 | | |
158 | | using namespace gdal::PSALSARJaxa; |
159 | | |
160 | | /************************************************************************/ |
161 | | /* ==================================================================== */ |
162 | | /* PALSARJaxaDataset */ |
163 | | /* ==================================================================== */ |
164 | | /************************************************************************/ |
165 | | |
166 | | class PALSARJaxaRasterBand; |
167 | | |
168 | | class PALSARJaxaDataset final : public GDALPamDataset |
169 | | { |
170 | | friend class PALSARJaxaRasterBand; |
171 | | |
172 | | private: |
173 | | GDAL_GCP *pasGCPList; |
174 | | int nGCPCount; |
175 | | eFileType nFileType; |
176 | | |
177 | | public: |
178 | | PALSARJaxaDataset(); |
179 | | ~PALSARJaxaDataset() override; |
180 | | |
181 | | int GetGCPCount() override; |
182 | | const GDAL_GCP *GetGCPs() override; |
183 | | |
184 | | static GDALDataset *Open(GDALOpenInfo *poOpenInfo); |
185 | | static int Identify(GDALOpenInfo *poOpenInfo); |
186 | | static void ReadMetadata(PALSARJaxaDataset *poDS, VSILFILE *fp); |
187 | | }; |
188 | | |
189 | | PALSARJaxaDataset::PALSARJaxaDataset() |
190 | 0 | : pasGCPList(nullptr), nGCPCount(0), nFileType(level_unknown) |
191 | 0 | { |
192 | 0 | } |
193 | | |
194 | | PALSARJaxaDataset::~PALSARJaxaDataset() |
195 | 0 | { |
196 | 0 | if (nGCPCount > 0) |
197 | 0 | { |
198 | 0 | GDALDeinitGCPs(nGCPCount, pasGCPList); |
199 | 0 | CPLFree(pasGCPList); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | | /************************************************************************/ |
204 | | /* ==================================================================== */ |
205 | | /* PALSARJaxaRasterBand */ |
206 | | /* ==================================================================== */ |
207 | | /************************************************************************/ |
208 | | |
209 | | class PALSARJaxaRasterBand final : public GDALRasterBand |
210 | | { |
211 | | VSILFILE *fp; |
212 | | ePolarization nPolarization; |
213 | | eFileType nFileType; |
214 | | int nBitsPerSample; |
215 | | int nSamplesPerGroup; |
216 | | int nRecordSize; |
217 | | |
218 | | public: |
219 | | PALSARJaxaRasterBand(PALSARJaxaDataset *poDS, int nBand, VSILFILE *fp); |
220 | | ~PALSARJaxaRasterBand() override; |
221 | | |
222 | | CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) override; |
223 | | }; |
224 | | |
225 | | /************************************************************************/ |
226 | | /* PALSARJaxaRasterBand() */ |
227 | | /************************************************************************/ |
228 | | |
229 | | PALSARJaxaRasterBand::PALSARJaxaRasterBand(PALSARJaxaDataset *poDSIn, |
230 | | int nBandIn, VSILFILE *fpIn) |
231 | 0 | : fp(fpIn), nPolarization(hh), nBitsPerSample(0), nSamplesPerGroup(0), |
232 | 0 | nRecordSize(0) |
233 | 0 | { |
234 | 0 | poDS = poDSIn; |
235 | 0 | nBand = nBandIn; |
236 | | |
237 | | /* Read image options record to determine the type of data */ |
238 | 0 | VSIFSeekL(fp, BITS_PER_SAMPLE_OFFSET, SEEK_SET); |
239 | 0 | READ_CHAR_VAL(nBitsPerSample, BITS_PER_SAMPLE_LENGTH, fp); |
240 | 0 | READ_CHAR_VAL(nSamplesPerGroup, SAMPLES_PER_GROUP_LENGTH, fp); |
241 | |
|
242 | 0 | if (nBitsPerSample == 32 && nSamplesPerGroup == 2) |
243 | 0 | { |
244 | 0 | eDataType = GDT_CFloat32; |
245 | 0 | nFileType = level_11; |
246 | 0 | } |
247 | 0 | else if (nBitsPerSample == 8 && nSamplesPerGroup == 2) |
248 | 0 | { |
249 | 0 | eDataType = GDT_CInt16; /* should be 2 x signed byte */ |
250 | 0 | nFileType = level_10; |
251 | 0 | } |
252 | 0 | else |
253 | 0 | { |
254 | 0 | eDataType = GDT_UInt16; |
255 | 0 | nFileType = level_15; |
256 | 0 | } |
257 | |
|
258 | 0 | poDSIn->nFileType = nFileType; |
259 | | |
260 | | /* Read number of range/azimuth lines */ |
261 | 0 | VSIFSeekL(fp, NUMBER_LINES_OFFSET, SEEK_SET); |
262 | 0 | READ_CHAR_VAL(nRasterYSize, NUMBER_LINES_LENGTH, fp); |
263 | 0 | VSIFSeekL(fp, SAR_DATA_RECORD_LENGTH_OFFSET, SEEK_SET); |
264 | 0 | READ_CHAR_VAL(nRecordSize, SAR_DATA_RECORD_LENGTH_LENGTH, fp); |
265 | 0 | const int nDenom = ((nBitsPerSample / 8) * nSamplesPerGroup); |
266 | 0 | if (nDenom != 0) |
267 | 0 | nRasterXSize = |
268 | 0 | (nRecordSize - (nFileType != level_15 ? SIG_DAT_REC_OFFSET |
269 | 0 | : PROC_DAT_REC_OFFSET)) / |
270 | 0 | nDenom; |
271 | |
|
272 | 0 | poDSIn->nRasterXSize = nRasterXSize; |
273 | 0 | poDSIn->nRasterYSize = nRasterYSize; |
274 | | |
275 | | /* Polarization */ |
276 | 0 | switch (nBand) |
277 | 0 | { |
278 | 0 | case 0: |
279 | 0 | nPolarization = hh; |
280 | 0 | SetMetadataItem("POLARIMETRIC_INTERP", "HH"); |
281 | 0 | break; |
282 | 0 | case 1: |
283 | 0 | nPolarization = hv; |
284 | 0 | SetMetadataItem("POLARIMETRIC_INTERP", "HV"); |
285 | 0 | break; |
286 | 0 | case 2: |
287 | 0 | nPolarization = vh; |
288 | 0 | SetMetadataItem("POLARIMETRIC_INTERP", "VH"); |
289 | 0 | break; |
290 | 0 | case 3: |
291 | 0 | nPolarization = vv; |
292 | 0 | SetMetadataItem("POLARIMETRIC_INTERP", "VV"); |
293 | 0 | break; |
294 | | // TODO: What about the default? |
295 | 0 | } |
296 | | |
297 | | /* size of block we can read */ |
298 | 0 | nBlockXSize = nRasterXSize; |
299 | 0 | nBlockYSize = 1; |
300 | | |
301 | | /* set the file pointer to the first SAR data record */ |
302 | 0 | VSIFSeekL(fp, IMAGE_OPT_DESC_LENGTH, SEEK_SET); |
303 | 0 | } |
304 | | |
305 | | /************************************************************************/ |
306 | | /* ~PALSARJaxaRasterBand() */ |
307 | | /************************************************************************/ |
308 | | |
309 | | PALSARJaxaRasterBand::~PALSARJaxaRasterBand() |
310 | 0 | { |
311 | 0 | if (fp) |
312 | 0 | VSIFCloseL(fp); |
313 | 0 | } |
314 | | |
315 | | /************************************************************************/ |
316 | | /* IReadBlock() */ |
317 | | /************************************************************************/ |
318 | | |
319 | | CPLErr PALSARJaxaRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, |
320 | | int nBlockYOff, void *pImage) |
321 | 0 | { |
322 | 0 | int nNumBytes = 0; |
323 | 0 | if (nFileType == level_11) |
324 | 0 | { |
325 | 0 | nNumBytes = 8; |
326 | 0 | } |
327 | 0 | else |
328 | 0 | { |
329 | 0 | nNumBytes = 2; |
330 | 0 | } |
331 | |
|
332 | 0 | int nOffset = |
333 | 0 | IMAGE_OPT_DESC_LENGTH + ((nBlockYOff - 1) * nRecordSize) + |
334 | 0 | (nFileType == level_11 ? SIG_DAT_REC_OFFSET : PROC_DAT_REC_OFFSET); |
335 | |
|
336 | 0 | VSIFSeekL(fp, nOffset, SEEK_SET); |
337 | 0 | VSIFReadL(pImage, nNumBytes, nRasterXSize, fp); |
338 | |
|
339 | 0 | #ifdef CPL_LSB |
340 | 0 | if (nFileType == level_11) |
341 | 0 | GDALSwapWords(pImage, 4, nBlockXSize * 2, 4); |
342 | 0 | else |
343 | 0 | GDALSwapWords(pImage, 2, nBlockXSize, 2); |
344 | 0 | #endif |
345 | |
|
346 | 0 | return CE_None; |
347 | 0 | } |
348 | | |
349 | | /************************************************************************/ |
350 | | /* ==================================================================== */ |
351 | | /* PALSARJaxaDataset */ |
352 | | /* ==================================================================== */ |
353 | | /************************************************************************/ |
354 | | |
355 | | /************************************************************************/ |
356 | | /* ReadMetadata() */ |
357 | | /************************************************************************/ |
358 | | |
359 | | int PALSARJaxaDataset::GetGCPCount() |
360 | 0 | { |
361 | 0 | return nGCPCount; |
362 | 0 | } |
363 | | |
364 | | /************************************************************************/ |
365 | | /* GetGCPs() */ |
366 | | /************************************************************************/ |
367 | | |
368 | | const GDAL_GCP *PALSARJaxaDataset::GetGCPs() |
369 | 0 | { |
370 | 0 | return pasGCPList; |
371 | 0 | } |
372 | | |
373 | | /************************************************************************/ |
374 | | /* ReadMetadata() */ |
375 | | /************************************************************************/ |
376 | | |
377 | | void PALSARJaxaDataset::ReadMetadata(PALSARJaxaDataset *poDS, VSILFILE *fp) |
378 | 0 | { |
379 | | /* seek to the end of the leader file descriptor */ |
380 | 0 | VSIFSeekL(fp, LEADER_FILE_DESCRIPTOR_LENGTH, SEEK_SET); |
381 | 0 | if (poDS->nFileType == level_10) |
382 | 0 | { |
383 | 0 | poDS->SetMetadataItem("PRODUCT_LEVEL", "1.0"); |
384 | 0 | poDS->SetMetadataItem("AZIMUTH_LOOKS", "1.0"); |
385 | 0 | } |
386 | 0 | else if (poDS->nFileType == level_11) |
387 | 0 | { |
388 | 0 | poDS->SetMetadataItem("PRODUCT_LEVEL", "1.1"); |
389 | 0 | poDS->SetMetadataItem("AZIMUTH_LOOKS", "1.0"); |
390 | 0 | } |
391 | 0 | else |
392 | 0 | { |
393 | 0 | poDS->SetMetadataItem("PRODUCT_LEVEL", "1.5"); |
394 | | /* extract equivalent number of looks */ |
395 | 0 | VSIFSeekL( |
396 | 0 | fp, LEADER_FILE_DESCRIPTOR_LENGTH + EFFECTIVE_LOOKS_AZIMUTH_OFFSET, |
397 | 0 | SEEK_SET); |
398 | 0 | char szENL[17]; |
399 | 0 | double dfENL; |
400 | 0 | READ_CHAR_FLOAT(dfENL, 16, fp); |
401 | 0 | snprintf(szENL, sizeof(szENL), "%-16.1f", dfENL); |
402 | 0 | poDS->SetMetadataItem("AZIMUTH_LOOKS", szENL); |
403 | | |
404 | | /* extract pixel spacings */ |
405 | 0 | VSIFSeekL(fp, |
406 | 0 | LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH + |
407 | 0 | PIXEL_SPACING_OFFSET, |
408 | 0 | SEEK_SET); |
409 | 0 | double dfPixelSpacing; |
410 | 0 | double dfLineSpacing; |
411 | 0 | char szPixelSpacing[33]; |
412 | 0 | char szLineSpacing[33]; |
413 | 0 | READ_CHAR_FLOAT(dfPixelSpacing, 16, fp); |
414 | 0 | READ_CHAR_FLOAT(dfLineSpacing, 16, fp); |
415 | 0 | snprintf(szPixelSpacing, sizeof(szPixelSpacing), "%-32.1f", |
416 | 0 | dfPixelSpacing); |
417 | 0 | snprintf(szLineSpacing, sizeof(szLineSpacing), "%-32.1f", |
418 | 0 | dfLineSpacing); |
419 | 0 | poDS->SetMetadataItem("PIXEL_SPACING", szPixelSpacing); |
420 | 0 | poDS->SetMetadataItem("LINE_SPACING", szPixelSpacing); |
421 | | |
422 | | /* Alphanumeric projection name */ |
423 | 0 | VSIFSeekL(fp, |
424 | 0 | LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH + |
425 | 0 | ALPHANUMERIC_PROJECTION_NAME_OFFSET, |
426 | 0 | SEEK_SET); |
427 | 0 | char szProjName[33]; |
428 | 0 | READ_STRING(szProjName, 32, fp); |
429 | 0 | poDS->SetMetadataItem("PROJECTION_NAME", szProjName); |
430 | | |
431 | | /* Extract corner GCPs */ |
432 | 0 | poDS->nGCPCount = 4; |
433 | 0 | poDS->pasGCPList = |
434 | 0 | (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount); |
435 | 0 | GDALInitGCPs(poDS->nGCPCount, poDS->pasGCPList); |
436 | | |
437 | | /* setup the GCPs */ |
438 | 0 | int i; |
439 | 0 | for (i = 0; i < poDS->nGCPCount; i++) |
440 | 0 | { |
441 | 0 | char szID[30]; |
442 | 0 | snprintf(szID, sizeof(szID), "%d", i + 1); |
443 | 0 | CPLFree(poDS->pasGCPList[i].pszId); |
444 | 0 | poDS->pasGCPList[i].pszId = CPLStrdup(szID); |
445 | 0 | poDS->pasGCPList[i].dfGCPZ = 0.0; |
446 | 0 | } |
447 | |
|
448 | 0 | double dfTemp = 0.0; |
449 | | /* seek to start of GCPs */ |
450 | 0 | VSIFSeekL(fp, |
451 | 0 | LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH + |
452 | 0 | TOP_LEFT_LAT_OFFSET, |
453 | 0 | SEEK_SET); |
454 | | |
455 | | /* top-left GCP */ |
456 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
457 | 0 | poDS->pasGCPList[0].dfGCPY = dfTemp; |
458 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
459 | 0 | poDS->pasGCPList[0].dfGCPX = dfTemp; |
460 | 0 | poDS->pasGCPList[0].dfGCPLine = 0.5; |
461 | 0 | poDS->pasGCPList[0].dfGCPPixel = 0.5; |
462 | | |
463 | | /* top right GCP */ |
464 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
465 | 0 | poDS->pasGCPList[1].dfGCPY = dfTemp; |
466 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
467 | 0 | poDS->pasGCPList[1].dfGCPX = dfTemp; |
468 | 0 | poDS->pasGCPList[1].dfGCPLine = 0.5; |
469 | 0 | poDS->pasGCPList[1].dfGCPPixel = poDS->nRasterYSize - 0.5; |
470 | | |
471 | | /* bottom right GCP */ |
472 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
473 | 0 | poDS->pasGCPList[2].dfGCPY = dfTemp; |
474 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
475 | 0 | poDS->pasGCPList[2].dfGCPX = dfTemp; |
476 | 0 | poDS->pasGCPList[2].dfGCPLine = poDS->nRasterYSize - 0.5; |
477 | 0 | poDS->pasGCPList[2].dfGCPPixel = poDS->nRasterYSize - 0.5; |
478 | | |
479 | | /* bottom left GCP */ |
480 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
481 | 0 | poDS->pasGCPList[3].dfGCPY = dfTemp; |
482 | 0 | READ_CHAR_FLOAT(dfTemp, 16, fp); |
483 | 0 | poDS->pasGCPList[3].dfGCPX = dfTemp; |
484 | 0 | poDS->pasGCPList[3].dfGCPLine = poDS->nRasterYSize - 0.5; |
485 | 0 | poDS->pasGCPList[3].dfGCPPixel = 0.5; |
486 | 0 | } |
487 | | |
488 | | /* some generic metadata items */ |
489 | 0 | poDS->SetMetadataItem("SENSOR_BAND", "L"); /* PALSAR is L-band */ |
490 | 0 | poDS->SetMetadataItem("RANGE_LOOKS", "1.0"); |
491 | | |
492 | | /* Check if this is a PolSAR dataset */ |
493 | 0 | if (poDS->GetRasterCount() == 4) |
494 | 0 | { |
495 | | /* PALSAR data is only available from JAXA in Scattering Matrix form */ |
496 | 0 | poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING"); |
497 | 0 | } |
498 | 0 | } |
499 | | |
500 | | /************************************************************************/ |
501 | | /* Identify() */ |
502 | | /************************************************************************/ |
503 | | |
504 | | static void ReadWord(VSILFILE *fp, int *pVal) |
505 | 0 | { |
506 | 0 | READ_WORD(fp, *pVal); |
507 | 0 | } |
508 | | |
509 | | static void ReadByte(VSILFILE *fp, int *pVal) |
510 | 0 | { |
511 | 0 | READ_BYTE(fp, *pVal); |
512 | 0 | } |
513 | | |
514 | | int PALSARJaxaDataset::Identify(GDALOpenInfo *poOpenInfo) |
515 | 602k | { |
516 | 602k | if (poOpenInfo->nHeaderBytes < 360 || poOpenInfo->fpL == nullptr) |
517 | 538k | return 0; |
518 | | |
519 | | /* First, check that this is a PALSAR image indeed */ |
520 | 63.7k | if (!STARTS_WITH_CI((char *)(poOpenInfo->pabyHeader + 60), "AL")) |
521 | 63.6k | { |
522 | 63.6k | return 0; |
523 | 63.6k | } |
524 | 107 | const std::string osBasename = CPLGetBasenameSafe(poOpenInfo->pszFilename); |
525 | 107 | if (osBasename.size() < 9 || |
526 | 54 | !STARTS_WITH_CI(osBasename.c_str() + 4, "ALPSR")) |
527 | 107 | { |
528 | 107 | return 0; |
529 | 107 | } |
530 | | |
531 | | /* Check that this is a volume directory file */ |
532 | 0 | int nRecordSeq = 0; |
533 | 0 | int nRecordSubtype = 0; |
534 | 0 | int nRecordType = 0; |
535 | 0 | int nSecondSubtype = 0; |
536 | 0 | int nThirdSubtype = 0; |
537 | 0 | int nLengthRecord = 0; |
538 | |
|
539 | 0 | VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); |
540 | |
|
541 | 0 | ReadWord(poOpenInfo->fpL, &nRecordSeq); |
542 | 0 | ReadByte(poOpenInfo->fpL, &nRecordSubtype); |
543 | 0 | ReadByte(poOpenInfo->fpL, &nRecordType); |
544 | 0 | ReadByte(poOpenInfo->fpL, &nSecondSubtype); |
545 | 0 | ReadByte(poOpenInfo->fpL, &nThirdSubtype); |
546 | 0 | ReadWord(poOpenInfo->fpL, &nLengthRecord); |
547 | |
|
548 | 0 | VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); |
549 | | |
550 | | /* Check that we have the right record */ |
551 | 0 | if (nRecordSeq == 1 && nRecordSubtype == 192 && nRecordType == 192 && |
552 | 0 | nSecondSubtype == 18 && nThirdSubtype == 18 && nLengthRecord == 360) |
553 | 0 | { |
554 | 0 | return 1; |
555 | 0 | } |
556 | | |
557 | 0 | return 0; |
558 | 0 | } |
559 | | |
560 | | /************************************************************************/ |
561 | | /* Open() */ |
562 | | /************************************************************************/ |
563 | | GDALDataset *PALSARJaxaDataset::Open(GDALOpenInfo *poOpenInfo) |
564 | 0 | { |
565 | | /* Check that this actually is a JAXA PALSAR product */ |
566 | 0 | if (!PALSARJaxaDataset::Identify(poOpenInfo)) |
567 | 0 | return nullptr; |
568 | | |
569 | | /* -------------------------------------------------------------------- */ |
570 | | /* Confirm the requested access is supported. */ |
571 | | /* -------------------------------------------------------------------- */ |
572 | 0 | if (poOpenInfo->eAccess == GA_Update) |
573 | 0 | { |
574 | 0 | ReportUpdateNotSupportedByDriver("JAXAPALSAR"); |
575 | 0 | return nullptr; |
576 | 0 | } |
577 | | |
578 | 0 | PALSARJaxaDataset *poDS = new PALSARJaxaDataset(); |
579 | | |
580 | | /* Get the suffix of the filename, we'll need this */ |
581 | 0 | char *pszSuffix = |
582 | 0 | VSIStrdup((char *)(CPLGetFilename(poOpenInfo->pszFilename) + 3)); |
583 | | |
584 | | /* Try to read each of the polarizations */ |
585 | 0 | const size_t nImgFileLen = |
586 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).size() + strlen(pszSuffix) + |
587 | 0 | 8; |
588 | 0 | char *pszImgFile = (char *)CPLMalloc(nImgFileLen); |
589 | |
|
590 | 0 | int nBandNum = 1; |
591 | | |
592 | | /* HH */ |
593 | 0 | snprintf(pszImgFile, nImgFileLen, "%s%sIMG-HH%s", |
594 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING, |
595 | 0 | pszSuffix); |
596 | 0 | VSILFILE *fpHH = VSIFOpenL(pszImgFile, "rb"); |
597 | 0 | if (fpHH != nullptr) |
598 | 0 | { |
599 | 0 | poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 0, fpHH)); |
600 | 0 | nBandNum++; |
601 | 0 | } |
602 | | |
603 | | /* HV */ |
604 | 0 | snprintf(pszImgFile, nImgFileLen, "%s%sIMG-HV%s", |
605 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING, |
606 | 0 | pszSuffix); |
607 | 0 | VSILFILE *fpHV = VSIFOpenL(pszImgFile, "rb"); |
608 | 0 | if (fpHV != nullptr) |
609 | 0 | { |
610 | 0 | poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 1, fpHV)); |
611 | 0 | nBandNum++; |
612 | 0 | } |
613 | | |
614 | | /* VH */ |
615 | 0 | snprintf(pszImgFile, nImgFileLen, "%s%sIMG-VH%s", |
616 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING, |
617 | 0 | pszSuffix); |
618 | 0 | VSILFILE *fpVH = VSIFOpenL(pszImgFile, "rb"); |
619 | 0 | if (fpVH != nullptr) |
620 | 0 | { |
621 | 0 | poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 2, fpVH)); |
622 | 0 | nBandNum++; |
623 | 0 | } |
624 | | |
625 | | /* VV */ |
626 | 0 | snprintf(pszImgFile, nImgFileLen, "%s%sIMG-VV%s", |
627 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING, |
628 | 0 | pszSuffix); |
629 | 0 | VSILFILE *fpVV = VSIFOpenL(pszImgFile, "rb"); |
630 | 0 | if (fpVV != nullptr) |
631 | 0 | { |
632 | 0 | poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 3, fpVV)); |
633 | | /* nBandNum++; */ |
634 | 0 | } |
635 | |
|
636 | 0 | VSIFree(pszImgFile); |
637 | | |
638 | | /* did we get at least one band? */ |
639 | 0 | if (fpVV == nullptr && fpVH == nullptr && fpHV == nullptr && |
640 | 0 | fpHH == nullptr) |
641 | 0 | { |
642 | 0 | CPLError( |
643 | 0 | CE_Failure, CPLE_AppDefined, |
644 | 0 | "Unable to find any image data. Aborting opening as PALSAR image."); |
645 | 0 | delete poDS; |
646 | 0 | VSIFree(pszSuffix); |
647 | 0 | return nullptr; |
648 | 0 | } |
649 | | |
650 | | /* Level 1.0 products are not supported */ |
651 | 0 | if (poDS->nFileType == level_10) |
652 | 0 | { |
653 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
654 | 0 | "ALOS PALSAR Level 1.0 products are not supported. Aborting " |
655 | 0 | "opening as PALSAR image."); |
656 | 0 | delete poDS; |
657 | 0 | VSIFree(pszSuffix); |
658 | 0 | return nullptr; |
659 | 0 | } |
660 | | |
661 | | /* read metadata from Leader file. */ |
662 | 0 | const size_t nLeaderFilenameLen = |
663 | 0 | strlen(CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str()) + |
664 | 0 | strlen(pszSuffix) + 5; |
665 | 0 | char *pszLeaderFilename = (char *)CPLMalloc(nLeaderFilenameLen); |
666 | 0 | snprintf(pszLeaderFilename, nLeaderFilenameLen, "%s%sLED%s", |
667 | 0 | CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING, |
668 | 0 | pszSuffix); |
669 | |
|
670 | 0 | VSILFILE *fpLeader = VSIFOpenL(pszLeaderFilename, "rb"); |
671 | | /* check if the leader is actually present */ |
672 | 0 | if (fpLeader != nullptr) |
673 | 0 | { |
674 | 0 | ReadMetadata(poDS, fpLeader); |
675 | 0 | VSIFCloseL(fpLeader); |
676 | 0 | } |
677 | |
|
678 | 0 | VSIFree(pszLeaderFilename); |
679 | |
|
680 | 0 | VSIFree(pszSuffix); |
681 | | |
682 | | /* -------------------------------------------------------------------- */ |
683 | | /* Initialize any PAM information. */ |
684 | | /* -------------------------------------------------------------------- */ |
685 | 0 | poDS->SetDescription(poOpenInfo->pszFilename); |
686 | 0 | poDS->TryLoadXML(); |
687 | | |
688 | | /* -------------------------------------------------------------------- */ |
689 | | /* Check for overviews. */ |
690 | | /* -------------------------------------------------------------------- */ |
691 | 0 | poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename); |
692 | |
|
693 | 0 | return poDS; |
694 | 0 | } |
695 | | |
696 | | /************************************************************************/ |
697 | | /* GDALRegister_PALSARJaxa() */ |
698 | | /************************************************************************/ |
699 | | |
700 | | void GDALRegister_PALSARJaxa() |
701 | | |
702 | 22 | { |
703 | 22 | if (GDALGetDriverByName("JAXAPALSAR") != nullptr) |
704 | 0 | return; |
705 | | |
706 | 22 | GDALDriver *poDriver = new GDALDriver(); |
707 | | |
708 | 22 | poDriver->SetDescription("JAXAPALSAR"); |
709 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
710 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, |
711 | 22 | "JAXA PALSAR Product Reader (Level 1.1/1.5)"); |
712 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/palsar.html"); |
713 | | |
714 | 22 | poDriver->pfnOpen = PALSARJaxaDataset::Open; |
715 | 22 | poDriver->pfnIdentify = PALSARJaxaDataset::Identify; |
716 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
717 | | |
718 | 22 | GetGDALDriverManager()->RegisterDriver(poDriver); |
719 | 22 | } |