Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of a dataset overview warping class
5 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "gdal_priv.h"
15 :
16 : #include <cassert>
17 : #include <cstring>
18 :
19 : #include "cpl_conv.h"
20 : #include "cpl_error.h"
21 : #include "cpl_progress.h"
22 : #include "cpl_string.h"
23 : #include "gdal.h"
24 : #include "gdal_mdreader.h"
25 : #include "gdal_proxy.h"
26 :
27 : /** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
28 : have no parent dataset. This can be inconvenient in certain contexts, where
29 : cross-band processing must be done, or when API expect a fully fledged
30 : dataset. Furthermore even if overview band has a container dataset, that
31 : one often fails to declare its projection, geotransform, etc... which make
32 : it somehow useless. GDALOverviewDataset remedies to those deficiencies.
33 : */
34 :
35 : class GDALOverviewBand;
36 :
37 : /* ******************************************************************** */
38 : /* GDALOverviewDataset */
39 : /* ******************************************************************** */
40 :
41 : class GDALOverviewDataset final : public GDALDataset
42 : {
43 : private:
44 : friend class GDALOverviewBand;
45 :
46 : GDALDataset *poMainDS = nullptr;
47 :
48 : GDALDataset *poOvrDS = nullptr; // Will be often NULL.
49 : int nOvrLevel = 0;
50 : bool bThisLevelOnly = false;
51 :
52 : int nGCPCount = 0;
53 : GDAL_GCP *pasGCPList = nullptr;
54 : char **papszMD_RPC = nullptr;
55 : char **papszMD_GEOLOCATION = nullptr;
56 : GDALOverviewBand *m_poMaskBand = nullptr;
57 :
58 : static void Rescale(char **&papszMD, const char *pszItem, double dfRatio,
59 : double dfDefaultVal, double dfPreShift = 0,
60 : double dfPostShift = 0);
61 :
62 : protected:
63 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
64 : GDALDataType, int, BANDMAP_TYPE, GSpacing, GSpacing,
65 : GSpacing, GDALRasterIOExtraArg *psExtraArg) override;
66 :
67 : public:
68 : GDALOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
69 : bool bThisLevelOnly);
70 : ~GDALOverviewDataset() override;
71 :
72 : const OGRSpatialReference *GetSpatialRef() const override;
73 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
74 :
75 : int GetGCPCount() override;
76 : const OGRSpatialReference *GetGCPSpatialRef() const override;
77 : const GDAL_GCP *GetGCPs() override;
78 :
79 : CSLConstList GetMetadata(const char *pszDomain = "") override;
80 : const char *GetMetadataItem(const char *pszName,
81 : const char *pszDomain = "") override;
82 :
83 : int CloseDependentDatasets() override;
84 :
85 : private:
86 : CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
87 : };
88 :
89 : /* ******************************************************************** */
90 : /* GDALOverviewBand */
91 : /* ******************************************************************** */
92 :
93 : class GDALOverviewBand final : public GDALProxyRasterBand
94 : {
95 : protected:
96 : friend class GDALOverviewDataset;
97 :
98 : GDALRasterBand *poUnderlyingBand = nullptr;
99 : GDALRasterBand *RefUnderlyingRasterBand(bool bForceOpen) const override;
100 :
101 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
102 : GDALDataType, GSpacing, GSpacing,
103 : GDALRasterIOExtraArg *psExtraArg) override;
104 :
105 : public:
106 : GDALOverviewBand(GDALOverviewDataset *poDS, int nBand);
107 : ~GDALOverviewBand() override;
108 :
109 : CPLErr FlushCache(bool bAtClosing) override;
110 :
111 : int GetOverviewCount() override;
112 : GDALRasterBand *GetOverview(int) override;
113 :
114 : int GetMaskFlags() override;
115 : GDALRasterBand *GetMaskBand() override;
116 :
117 : private:
118 : CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
119 : };
120 :
121 : /************************************************************************/
122 : /* GetOverviewEx() */
123 : /************************************************************************/
124 :
125 1365 : static GDALRasterBand *GetOverviewEx(GDALRasterBand *poBand, int nLevel)
126 : {
127 1365 : if (nLevel == -1)
128 64 : return poBand;
129 1301 : return poBand->GetOverview(nLevel);
130 : }
131 :
132 : /************************************************************************/
133 : /* GDALCreateOverviewDataset() */
134 : /************************************************************************/
135 :
136 : // Takes a reference on poMainDS in case of success.
137 : // nOvrLevel=-1 means the full resolution dataset (only useful if
138 : // bThisLevelOnly = false to expose a dataset without its overviews)
139 202 : GDALDataset *GDALCreateOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
140 : bool bThisLevelOnly)
141 : {
142 : // Sanity checks.
143 202 : const int nBands = poMainDS->GetRasterCount();
144 202 : if (nBands == 0)
145 0 : return nullptr;
146 :
147 202 : auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
148 516 : for (int i = 1; i <= nBands; ++i)
149 : {
150 320 : auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
151 320 : if (poBand == nullptr)
152 : {
153 6 : return nullptr;
154 : }
155 628 : if (poBand->GetXSize() != poFirstBand->GetXSize() ||
156 314 : poBand->GetYSize() != poFirstBand->GetYSize())
157 : {
158 0 : return nullptr;
159 : }
160 : }
161 :
162 196 : return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
163 : }
164 :
165 : /************************************************************************/
166 : /* GDALOverviewDataset() */
167 : /************************************************************************/
168 :
169 196 : GDALOverviewDataset::GDALOverviewDataset(GDALDataset *poMainDSIn,
170 196 : int nOvrLevelIn, bool bThisLevelOnlyIn)
171 : : poMainDS(poMainDSIn), nOvrLevel(nOvrLevelIn),
172 196 : bThisLevelOnly(bThisLevelOnlyIn)
173 : {
174 196 : poMainDSIn->Reference();
175 196 : eAccess = poMainDS->GetAccess();
176 196 : auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
177 196 : nRasterXSize = poFirstBand->GetXSize();
178 196 : nRasterYSize = poFirstBand->GetYSize();
179 196 : poOvrDS = poFirstBand->GetDataset();
180 196 : if (nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS)
181 : {
182 0 : CPLDebug("GDAL", "Dataset of overview is the same as the main band. "
183 : "This is not expected");
184 0 : poOvrDS = nullptr;
185 : }
186 196 : nBands = poMainDS->GetRasterCount();
187 510 : for (int i = 0; i < nBands; ++i)
188 : {
189 314 : if (poOvrDS)
190 : {
191 : // Check that all overview bands belong to the same dataset
192 : auto poOvrBand =
193 314 : GetOverviewEx(poMainDS->GetRasterBand(i + 1), nOvrLevel);
194 314 : if (poOvrBand->GetDataset() != poOvrDS)
195 0 : poOvrDS = nullptr;
196 : }
197 314 : SetBand(i + 1, new GDALOverviewBand(this, i + 1));
198 : }
199 :
200 196 : if (poFirstBand->GetMaskFlags() == GMF_PER_DATASET)
201 : {
202 19 : auto poOvrMaskBand = poFirstBand->GetMaskBand();
203 38 : if (poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
204 19 : poOvrMaskBand->GetYSize() == nRasterYSize)
205 : {
206 19 : m_poMaskBand = new GDALOverviewBand(this, 0);
207 : }
208 : }
209 :
210 : // We create a fake driver that has the same name as the original
211 : // one, but we cannot use the real driver object, so that code
212 : // doesn't try to cast the GDALOverviewDataset* as a native dataset
213 : // object.
214 196 : if (poMainDS->GetDriver() != nullptr)
215 : {
216 196 : poDriver = new GDALDriver();
217 196 : poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
218 196 : poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
219 : }
220 :
221 196 : SetDescription(poMainDS->GetDescription());
222 :
223 196 : CPLDebug("GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
224 196 : poMainDS->GetDescription(), this);
225 :
226 196 : papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
227 : // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
228 196 : papszOpenOptions = CSLSetNameValue(
229 : papszOpenOptions, "OVERVIEW_LEVEL",
230 196 : nOvrLevel == -1
231 : ? "NONE"
232 188 : : CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" : ""));
233 196 : }
234 :
235 : /************************************************************************/
236 : /* ~GDALOverviewDataset() */
237 : /************************************************************************/
238 :
239 392 : GDALOverviewDataset::~GDALOverviewDataset()
240 : {
241 196 : GDALOverviewDataset::FlushCache(true);
242 :
243 196 : GDALOverviewDataset::CloseDependentDatasets();
244 :
245 196 : if (nGCPCount > 0)
246 : {
247 1 : GDALDeinitGCPs(nGCPCount, pasGCPList);
248 1 : CPLFree(pasGCPList);
249 : }
250 196 : CSLDestroy(papszMD_RPC);
251 :
252 196 : CSLDestroy(papszMD_GEOLOCATION);
253 :
254 196 : delete poDriver;
255 392 : }
256 :
257 : /************************************************************************/
258 : /* CloseDependentDatasets() */
259 : /************************************************************************/
260 :
261 196 : int GDALOverviewDataset::CloseDependentDatasets()
262 : {
263 196 : bool bRet = false;
264 :
265 196 : if (poMainDS)
266 : {
267 510 : for (int i = 0; i < nBands; ++i)
268 : {
269 : GDALOverviewBand *const band =
270 314 : cpl::down_cast<GDALOverviewBand *>(papoBands[i]);
271 314 : band->poUnderlyingBand = nullptr;
272 : }
273 196 : if (poMainDS->ReleaseRef())
274 40 : bRet = true;
275 196 : poMainDS = nullptr;
276 : }
277 :
278 196 : if (m_poMaskBand)
279 : {
280 19 : m_poMaskBand->poUnderlyingBand = nullptr;
281 19 : delete m_poMaskBand;
282 19 : m_poMaskBand = nullptr;
283 : }
284 :
285 196 : return bRet;
286 : }
287 :
288 : /************************************************************************/
289 : /* IRasterIO() */
290 : /* */
291 : /* The default implementation of IRasterIO() is to pass the */
292 : /* request off to each band objects rasterio methods with */
293 : /* appropriate arguments. */
294 : /************************************************************************/
295 :
296 3657 : CPLErr GDALOverviewDataset::IRasterIO(
297 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
298 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
299 : int nBandCount, BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
300 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
301 :
302 : {
303 : // Try to pass the request to the most appropriate overview dataset.
304 3657 : if (nBufXSize < nXSize && nBufYSize < nYSize)
305 : {
306 6 : int bTried = FALSE;
307 6 : const CPLErr eErr = TryOverviewRasterIO(
308 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
309 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
310 : nBandSpace, psExtraArg, &bTried);
311 6 : if (bTried)
312 2 : return eErr;
313 : }
314 :
315 : // In case the overview bands are really linked to a dataset, then issue
316 : // the request to that dataset.
317 3655 : if (poOvrDS != nullptr)
318 : {
319 3655 : const bool bEnabledOverviews = poOvrDS->AreOverviewsEnabled();
320 3655 : poOvrDS->SetEnableOverviews(false);
321 3655 : CPLErr eErr = poOvrDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
322 : pData, nBufXSize, nBufYSize, eBufType,
323 : nBandCount, panBandMap, nPixelSpace,
324 : nLineSpace, nBandSpace, psExtraArg);
325 3655 : poOvrDS->SetEnableOverviews(bEnabledOverviews);
326 3655 : return eErr;
327 : }
328 :
329 0 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
330 0 : void *pProgressDataGlobal = psExtraArg->pProgressData;
331 0 : CPLErr eErr = CE_None;
332 :
333 0 : for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
334 : ++iBandIndex)
335 : {
336 0 : GDALOverviewBand *poBand = cpl::down_cast<GDALOverviewBand *>(
337 0 : GetRasterBand(panBandMap[iBandIndex]));
338 0 : GByte *pabyBandData =
339 0 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
340 :
341 0 : psExtraArg->pfnProgress = GDALScaledProgress;
342 0 : psExtraArg->pProgressData = GDALCreateScaledProgress(
343 0 : 1.0 * iBandIndex / nBandCount, 1.0 * (iBandIndex + 1) / nBandCount,
344 : pfnProgressGlobal, pProgressDataGlobal);
345 :
346 0 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
347 : pabyBandData, nBufXSize, nBufYSize, eBufType,
348 : nPixelSpace, nLineSpace, psExtraArg);
349 :
350 0 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
351 : }
352 :
353 0 : psExtraArg->pfnProgress = pfnProgressGlobal;
354 0 : psExtraArg->pProgressData = pProgressDataGlobal;
355 :
356 0 : return eErr;
357 : }
358 :
359 : /************************************************************************/
360 : /* GetSpatialRef() */
361 : /************************************************************************/
362 :
363 82 : const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
364 :
365 : {
366 82 : return poMainDS->GetSpatialRef();
367 : }
368 :
369 : /************************************************************************/
370 : /* GetGeoTransform() */
371 : /************************************************************************/
372 :
373 51 : CPLErr GDALOverviewDataset::GetGeoTransform(GDALGeoTransform >) const
374 :
375 : {
376 51 : if (poMainDS->GetGeoTransform(gt) != CE_None)
377 3 : return CE_Failure;
378 :
379 : const double dfOvrXRatio =
380 48 : static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
381 : const double dfOvrYRatio =
382 48 : static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
383 48 : gt.Rescale(dfOvrXRatio, dfOvrYRatio);
384 :
385 48 : return CE_None;
386 : }
387 :
388 : /************************************************************************/
389 : /* GetGCPCount() */
390 : /************************************************************************/
391 :
392 17 : int GDALOverviewDataset::GetGCPCount()
393 :
394 : {
395 17 : return poMainDS->GetGCPCount();
396 : }
397 :
398 : /************************************************************************/
399 : /* GetGCPSpatialRef() */
400 : /************************************************************************/
401 :
402 3 : const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
403 :
404 : {
405 3 : return poMainDS->GetGCPSpatialRef();
406 : }
407 :
408 : /************************************************************************/
409 : /* GetGCPs() */
410 : /************************************************************************/
411 :
412 4 : const GDAL_GCP *GDALOverviewDataset::GetGCPs()
413 :
414 : {
415 4 : if (pasGCPList != nullptr)
416 1 : return pasGCPList;
417 :
418 3 : const GDAL_GCP *pasGCPsMain = poMainDS->GetGCPs();
419 3 : if (pasGCPsMain == nullptr)
420 2 : return nullptr;
421 1 : nGCPCount = poMainDS->GetGCPCount();
422 :
423 1 : pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsMain);
424 4 : for (int i = 0; i < nGCPCount; ++i)
425 : {
426 3 : pasGCPList[i].dfGCPPixel *=
427 3 : static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
428 3 : pasGCPList[i].dfGCPLine *=
429 3 : static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
430 : }
431 1 : return pasGCPList;
432 : }
433 :
434 : /************************************************************************/
435 : /* Rescale() */
436 : /************************************************************************/
437 :
438 : /* static */
439 12 : void GDALOverviewDataset::Rescale(char **&papszMD, const char *pszItem,
440 : double dfRatio, double dfDefaultVal,
441 : double dfPreShift /*= 0*/,
442 : double dfPostShift /*= 0*/)
443 : {
444 12 : double dfVal = CPLAtofM(CSLFetchNameValueDef(
445 : papszMD, pszItem, CPLSPrintf("%.17g", dfDefaultVal)));
446 12 : dfVal += dfPreShift;
447 12 : dfVal *= dfRatio;
448 12 : dfVal += dfPostShift;
449 12 : papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.17g", dfVal));
450 12 : }
451 :
452 : /************************************************************************/
453 : /* GetMetadata() */
454 : /************************************************************************/
455 :
456 139 : CSLConstList GDALOverviewDataset::GetMetadata(const char *pszDomain)
457 : {
458 139 : if (poOvrDS != nullptr)
459 : {
460 139 : CSLConstList papszMD = poOvrDS->GetMetadata(pszDomain);
461 139 : if (papszMD != nullptr)
462 1 : return papszMD;
463 : }
464 :
465 138 : CSLConstList papszMD = poMainDS->GetMetadata(pszDomain);
466 :
467 : // We may need to rescale some values from the RPC metadata domain.
468 138 : if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
469 : papszMD != nullptr)
470 : {
471 19 : if (papszMD_RPC)
472 17 : return papszMD_RPC;
473 2 : papszMD_RPC = CSLDuplicate(papszMD);
474 :
475 : const double dfXRatio =
476 2 : static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
477 : const double dfYRatio =
478 2 : static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
479 :
480 : // For line offset and pixel offset, we need to convert from RPC
481 : // pixel center registration convention to GDAL pixel top-left corner
482 : // registration convention by adding an initial 0.5 shift, and un-apply
483 : // it after scaling.
484 :
485 2 : Rescale(papszMD_RPC, RPC_LINE_OFF, dfYRatio, 0.0, 0.5, -0.5);
486 2 : Rescale(papszMD_RPC, RPC_LINE_SCALE, dfYRatio, 1.0);
487 2 : Rescale(papszMD_RPC, RPC_SAMP_OFF, dfXRatio, 0.0, 0.5, -0.5);
488 2 : Rescale(papszMD_RPC, RPC_SAMP_SCALE, dfXRatio, 1.0);
489 :
490 2 : papszMD = papszMD_RPC;
491 : }
492 :
493 : // We may need to rescale some values from the GEOLOCATION metadata domain.
494 121 : if (pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
495 : papszMD != nullptr)
496 : {
497 13 : if (papszMD_GEOLOCATION)
498 12 : return papszMD_GEOLOCATION;
499 1 : papszMD_GEOLOCATION = CSLDuplicate(papszMD);
500 :
501 1 : Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
502 1 : static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize,
503 : 0.0);
504 1 : Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
505 1 : static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize,
506 : 0.0);
507 :
508 1 : Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
509 1 : static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
510 : 1.0);
511 1 : Rescale(papszMD_GEOLOCATION, "LINE_STEP",
512 1 : static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
513 : 1.0);
514 :
515 1 : papszMD = papszMD_GEOLOCATION;
516 : }
517 :
518 109 : return papszMD;
519 : }
520 :
521 : /************************************************************************/
522 : /* GetMetadataItem() */
523 : /************************************************************************/
524 :
525 84 : const char *GDALOverviewDataset::GetMetadataItem(const char *pszName,
526 : const char *pszDomain)
527 : {
528 84 : if (poOvrDS != nullptr)
529 : {
530 84 : const char *pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
531 84 : if (pszValue != nullptr)
532 23 : return pszValue;
533 : }
534 :
535 61 : if (pszDomain != nullptr &&
536 61 : (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "GEOLOCATION")))
537 : {
538 27 : CSLConstList papszMD = GetMetadata(pszDomain);
539 27 : return CSLFetchNameValue(papszMD, pszName);
540 : }
541 :
542 34 : return poMainDS->GetMetadataItem(pszName, pszDomain);
543 : }
544 :
545 : /************************************************************************/
546 : /* GDALOverviewBand() */
547 : /************************************************************************/
548 :
549 333 : GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset *poDSIn, int nBandIn)
550 : {
551 333 : poDS = poDSIn;
552 333 : nBand = nBandIn;
553 333 : nRasterXSize = poDSIn->nRasterXSize;
554 333 : nRasterYSize = poDSIn->nRasterYSize;
555 : #if defined(__GNUC__)
556 : #pragma GCC diagnostic push
557 : #pragma GCC diagnostic ignored "-Wnull-dereference"
558 : #endif
559 333 : if (nBandIn == 0)
560 : {
561 19 : poUnderlyingBand = GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1),
562 : poDSIn->nOvrLevel);
563 19 : assert(poUnderlyingBand);
564 19 : poUnderlyingBand = poUnderlyingBand->GetMaskBand();
565 : }
566 : else
567 : {
568 314 : poUnderlyingBand = GetOverviewEx(
569 314 : poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
570 : }
571 333 : assert(poUnderlyingBand);
572 333 : eDataType = poUnderlyingBand->GetRasterDataType();
573 333 : poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
574 : #if defined(__GNUC__)
575 : #pragma GCC diagnostic pop
576 : #endif
577 333 : }
578 :
579 : /************************************************************************/
580 : /* ~GDALOverviewBand() */
581 : /************************************************************************/
582 :
583 666 : GDALOverviewBand::~GDALOverviewBand()
584 : {
585 333 : GDALOverviewBand::FlushCache(true);
586 666 : }
587 :
588 : /************************************************************************/
589 : /* FlushCache() */
590 : /************************************************************************/
591 :
592 666 : CPLErr GDALOverviewBand::FlushCache(bool bAtClosing)
593 : {
594 666 : if (poUnderlyingBand)
595 333 : return poUnderlyingBand->FlushCache(bAtClosing);
596 333 : return CE_None;
597 : }
598 :
599 : /************************************************************************/
600 : /* RefUnderlyingRasterBand() */
601 : /************************************************************************/
602 :
603 : GDALRasterBand *
604 3131 : GDALOverviewBand::RefUnderlyingRasterBand(bool /*bForceOpen */) const
605 : {
606 3131 : return poUnderlyingBand;
607 : }
608 :
609 : /************************************************************************/
610 : /* GetOverviewCount() */
611 : /************************************************************************/
612 :
613 38 : int GDALOverviewBand::GetOverviewCount()
614 : {
615 : GDALOverviewDataset *const poOvrDS =
616 38 : cpl::down_cast<GDALOverviewDataset *>(poDS);
617 38 : if (poOvrDS->bThisLevelOnly)
618 8 : return 0;
619 30 : GDALDataset *const poMainDS = poOvrDS->poMainDS;
620 30 : GDALRasterBand *poMainBand = (nBand == 0)
621 30 : ? poMainDS->GetRasterBand(1)->GetMaskBand()
622 28 : : poMainDS->GetRasterBand(nBand);
623 30 : return poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
624 : ;
625 : }
626 :
627 : /************************************************************************/
628 : /* GetOverview() */
629 : /************************************************************************/
630 :
631 16 : GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
632 : {
633 16 : if (iOvr < 0 || iOvr >= GetOverviewCount())
634 0 : return nullptr;
635 : GDALOverviewDataset *const poOvrDS =
636 16 : cpl::down_cast<GDALOverviewDataset *>(poDS);
637 16 : GDALDataset *const poMainDS = poOvrDS->poMainDS;
638 16 : GDALRasterBand *poMainBand = (nBand == 0)
639 16 : ? poMainDS->GetRasterBand(1)->GetMaskBand()
640 15 : : poMainDS->GetRasterBand(nBand);
641 16 : return poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
642 : }
643 :
644 : /************************************************************************/
645 : /* GetMaskFlags() */
646 : /************************************************************************/
647 :
648 186 : int GDALOverviewBand::GetMaskFlags()
649 : {
650 : GDALOverviewDataset *const poOvrDS =
651 186 : cpl::down_cast<GDALOverviewDataset *>(poDS);
652 186 : if (nBand != 0 && poOvrDS->m_poMaskBand)
653 1 : return GMF_PER_DATASET;
654 185 : return GDALProxyRasterBand::GetMaskFlags();
655 : }
656 :
657 : /************************************************************************/
658 : /* GetMaskBand() */
659 : /************************************************************************/
660 :
661 5 : GDALRasterBand *GDALOverviewBand::GetMaskBand()
662 : {
663 : GDALOverviewDataset *const poOvrDS =
664 5 : cpl::down_cast<GDALOverviewDataset *>(poDS);
665 5 : if (nBand != 0 && poOvrDS->m_poMaskBand)
666 1 : return poOvrDS->m_poMaskBand;
667 4 : return GDALProxyRasterBand::GetMaskBand();
668 : }
669 :
670 : /************************************************************************/
671 : /* IRasterIO() */
672 : /************************************************************************/
673 :
674 2152 : CPLErr GDALOverviewBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
675 : int nXSize, int nYSize, void *pData,
676 : int nBufXSize, int nBufYSize,
677 : GDALDataType eBufType, GSpacing nPixelSpace,
678 : GSpacing nLineSpace,
679 : GDALRasterIOExtraArg *psExtraArg)
680 : {
681 : GDALOverviewDataset *const poOvrDS =
682 2152 : cpl::down_cast<GDALOverviewDataset *>(poDS);
683 2152 : if (poOvrDS->bThisLevelOnly && poOvrDS->poOvrDS)
684 : {
685 110 : const bool bEnabledOverviews = poOvrDS->poOvrDS->AreOverviewsEnabled();
686 110 : poOvrDS->poOvrDS->SetEnableOverviews(false);
687 110 : CPLErr eErr = GDALProxyRasterBand::IRasterIO(
688 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
689 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
690 110 : poOvrDS->poOvrDS->SetEnableOverviews(bEnabledOverviews);
691 110 : return eErr;
692 : }
693 :
694 : // Try to pass the request to the most appropriate overview.
695 2042 : if (nBufXSize < nXSize && nBufYSize < nYSize)
696 : {
697 2 : int bTried = FALSE;
698 2 : const CPLErr eErr = TryOverviewRasterIO(
699 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
700 : eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
701 2 : if (bTried)
702 2 : return eErr;
703 : }
704 :
705 2040 : return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
706 : pData, nBufXSize, nBufYSize, eBufType,
707 2040 : nPixelSpace, nLineSpace, psExtraArg);
708 : }
|