1 : /******************************************************************************
2 : * $Id: gdaldefaultoverviews.cpp 22381 2011-05-16 21:14:22Z rouault $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Helper code to implement overview and mask support for many
6 : * drivers with no inherent format support.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2000, 2007, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdal_priv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: gdaldefaultoverviews.cpp 22381 2011-05-16 21:14:22Z rouault $");
35 :
36 : /************************************************************************/
37 : /* GDALDefaultOverviews() */
38 : /************************************************************************/
39 :
40 15163 : GDALDefaultOverviews::GDALDefaultOverviews()
41 :
42 : {
43 15163 : poDS = NULL;
44 15163 : poODS = NULL;
45 15163 : bOvrIsAux = FALSE;
46 :
47 15163 : bCheckedForMask = FALSE;
48 15163 : bCheckedForOverviews = FALSE;
49 :
50 15163 : poMaskDS = NULL;
51 :
52 15163 : bOwnMaskDS = FALSE;
53 15163 : poBaseDS = NULL;
54 :
55 15163 : papszInitSiblingFiles = NULL;
56 15163 : pszInitName = NULL;
57 15163 : }
58 :
59 : /************************************************************************/
60 : /* ~GDALDefaultOverviews() */
61 : /************************************************************************/
62 :
63 15163 : GDALDefaultOverviews::~GDALDefaultOverviews()
64 :
65 : {
66 15163 : CPLFree( pszInitName );
67 15163 : CSLDestroy( papszInitSiblingFiles );
68 :
69 15163 : CloseDependentDatasets();
70 15163 : }
71 :
72 : /************************************************************************/
73 : /* CloseDependentDatasets() */
74 : /************************************************************************/
75 :
76 16031 : int GDALDefaultOverviews::CloseDependentDatasets()
77 : {
78 16031 : int bHasDroppedRef = FALSE;
79 16031 : if( poODS != NULL )
80 : {
81 187 : bHasDroppedRef = TRUE;
82 187 : poODS->FlushCache();
83 187 : GDALClose( poODS );
84 187 : poODS = NULL;
85 : }
86 :
87 16031 : if( poMaskDS != NULL )
88 : {
89 19 : if( bOwnMaskDS )
90 : {
91 16 : bHasDroppedRef = TRUE;
92 16 : poMaskDS->FlushCache();
93 16 : GDALClose( poMaskDS );
94 : }
95 19 : poMaskDS = NULL;
96 : }
97 :
98 16031 : return bHasDroppedRef;
99 : }
100 :
101 : /************************************************************************/
102 : /* IsInitialized() */
103 : /* */
104 : /* Returns TRUE if we are initialized. */
105 : /************************************************************************/
106 :
107 304779 : int GDALDefaultOverviews::IsInitialized()
108 :
109 : {
110 304779 : OverviewScan();
111 304779 : return poDS != NULL;
112 : }
113 :
114 : /************************************************************************/
115 : /* Initialize() */
116 : /************************************************************************/
117 :
118 8241 : void GDALDefaultOverviews::Initialize( GDALDataset *poDSIn,
119 : const char * pszBasename,
120 : char **papszSiblingFiles,
121 : int bNameIsOVR )
122 :
123 : {
124 8241 : poDS = poDSIn;
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* If we were already initialized, destroy the old overview */
128 : /* file handle. */
129 : /* -------------------------------------------------------------------- */
130 8241 : if( poODS != NULL )
131 : {
132 0 : GDALClose( poODS );
133 0 : poODS = NULL;
134 :
135 0 : CPLDebug( "GDAL", "GDALDefaultOverviews::Initialize() called twice - this is odd and perhaps dangerous!" );
136 : }
137 :
138 : /* -------------------------------------------------------------------- */
139 : /* Store the initialization information for later use in */
140 : /* OverviewScan() */
141 : /* -------------------------------------------------------------------- */
142 8241 : bCheckedForOverviews = FALSE;
143 :
144 8241 : CPLFree( pszInitName );
145 8241 : pszInitName = NULL;
146 8241 : if( pszBasename != NULL )
147 8241 : pszInitName = CPLStrdup(pszBasename);
148 8241 : bInitNameIsOVR = bNameIsOVR;
149 :
150 8241 : CSLDestroy( papszInitSiblingFiles );
151 8241 : papszInitSiblingFiles = NULL;
152 8241 : if( papszSiblingFiles != NULL )
153 3982 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
154 8241 : }
155 :
156 : /************************************************************************/
157 : /* OverviewScan() */
158 : /* */
159 : /* This is called to scan for overview files when a first */
160 : /* request is made with regard to overviews. It uses the */
161 : /* pszInitName, bInitNameIsOVR and papszInitSiblingFiles */
162 : /* information that was stored at Initialization() time. */
163 : /************************************************************************/
164 :
165 304779 : void GDALDefaultOverviews::OverviewScan()
166 :
167 : {
168 304779 : if( bCheckedForOverviews || poDS == NULL )
169 302146 : return;
170 :
171 2633 : bCheckedForOverviews = true;
172 :
173 2633 : CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" );
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Open overview dataset if it exists. */
177 : /* -------------------------------------------------------------------- */
178 : int bExists;
179 :
180 2633 : if( pszInitName == NULL )
181 0 : pszInitName = CPLStrdup(poDS->GetDescription());
182 :
183 2633 : if( !EQUAL(pszInitName,":::VIRTUAL:::") )
184 : {
185 2520 : if( bInitNameIsOVR )
186 0 : osOvrFilename = pszInitName;
187 : else
188 2520 : osOvrFilename.Printf( "%s.ovr", pszInitName );
189 :
190 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
191 2520 : papszInitSiblingFiles );
192 :
193 : #if !defined(WIN32)
194 2520 : if( !bInitNameIsOVR && !bExists && !papszInitSiblingFiles )
195 : {
196 601 : osOvrFilename.Printf( "%s.OVR", pszInitName );
197 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
198 601 : papszInitSiblingFiles );
199 601 : if( !bExists )
200 601 : osOvrFilename.Printf( "%s.ovr", pszInitName );
201 : }
202 : #endif
203 :
204 2520 : if( bExists )
205 : {
206 : GDALOpenInfo oOpenInfo(osOvrFilename, poDS->GetAccess(),
207 103 : papszInitSiblingFiles);
208 103 : poODS = (GDALDataset*) GDALOpenInternal( oOpenInfo, NULL );
209 : }
210 : }
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* We didn't find that, so try and find a corresponding aux */
214 : /* file. Check that we are the dependent file of the aux */
215 : /* file. */
216 : /* */
217 : /* We only use the .aux file for overviews if they already have */
218 : /* overviews existing, or if USE_RRD is set true. */
219 : /* -------------------------------------------------------------------- */
220 2633 : if( !poODS && !EQUAL(pszInitName,":::VIRTUAL:::") )
221 : {
222 2417 : int bTryFindAssociatedAuxFile = TRUE;
223 2417 : if( papszInitSiblingFiles )
224 : {
225 1816 : CPLString osAuxFilename = CPLResetExtension( pszInitName, "aux");
226 : int iSibling = CSLFindString( papszInitSiblingFiles,
227 1816 : CPLGetFilename(osAuxFilename) );
228 1816 : if( iSibling < 0 )
229 : {
230 1812 : osAuxFilename = pszInitName;
231 1812 : osAuxFilename += ".aux";
232 : iSibling = CSLFindString( papszInitSiblingFiles,
233 1812 : CPLGetFilename(osAuxFilename) );
234 1812 : if( iSibling < 0 )
235 1812 : bTryFindAssociatedAuxFile = FALSE;
236 1816 : }
237 : }
238 :
239 2417 : if (bTryFindAssociatedAuxFile)
240 : {
241 : poODS = GDALFindAssociatedAuxFile( pszInitName, poDS->GetAccess(),
242 605 : poDS );
243 : }
244 :
245 2417 : if( poODS )
246 : {
247 2 : int bUseRRD = CSLTestBoolean(CPLGetConfigOption("USE_RRD","NO"));
248 :
249 2 : bOvrIsAux = TRUE;
250 2 : if( GetOverviewCount(1) == 0 && !bUseRRD )
251 : {
252 0 : bOvrIsAux = FALSE;
253 0 : GDALClose( poODS );
254 0 : poODS = NULL;
255 : }
256 : else
257 : {
258 2 : osOvrFilename = poODS->GetDescription();
259 : }
260 : }
261 : }
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* If we still don't have an overview, check to see if we have */
265 : /* overview metadata referencing a remote (ie. proxy) or local */
266 : /* subdataset overview dataset. */
267 : /* -------------------------------------------------------------------- */
268 2633 : if( poODS == NULL )
269 : {
270 : const char *pszProxyOvrFilename =
271 2528 : poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
272 :
273 2528 : if( pszProxyOvrFilename != NULL )
274 : {
275 8 : if( EQUALN(pszProxyOvrFilename,":::BASE:::",10) )
276 : {
277 0 : CPLString osPath = CPLGetPath(poDS->GetDescription());
278 :
279 : osOvrFilename =
280 0 : CPLFormFilename( osPath, pszProxyOvrFilename+10, NULL );
281 : }
282 : else
283 8 : osOvrFilename = pszProxyOvrFilename;
284 :
285 8 : poODS = (GDALDataset *) GDALOpen(osOvrFilename,poDS->GetAccess());
286 : }
287 : }
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* If we have an overview dataset, then mark all the overviews */
291 : /* with the base dataset Used later for finding overviews */
292 : /* masks. Uggg. */
293 : /* -------------------------------------------------------------------- */
294 2633 : if( poODS )
295 : {
296 113 : int nOverviewCount = GetOverviewCount(1);
297 : int iOver;
298 :
299 248 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
300 : {
301 135 : GDALRasterBand *poBand = GetOverview( 1, iOver );
302 135 : GDALDataset *poOverDS = NULL;
303 :
304 135 : if( poBand != NULL )
305 135 : poOverDS = poBand->GetDataset();
306 :
307 135 : if( poOverDS != NULL )
308 : {
309 133 : poOverDS->oOvManager.poBaseDS = poDS;
310 133 : poOverDS->oOvManager.poDS = poOverDS;
311 : }
312 : }
313 : }
314 : }
315 :
316 : /************************************************************************/
317 : /* GetOverviewCount() */
318 : /************************************************************************/
319 :
320 300287 : int GDALDefaultOverviews::GetOverviewCount( int nBand )
321 :
322 : {
323 : GDALRasterBand * poBand;
324 :
325 300287 : if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
326 299639 : return 0;
327 :
328 648 : poBand = poODS->GetRasterBand( nBand );
329 648 : if( poBand == NULL )
330 0 : return 0;
331 : else
332 : {
333 648 : if( bOvrIsAux )
334 8 : return poBand->GetOverviewCount();
335 : else
336 640 : return poBand->GetOverviewCount() + 1;
337 : }
338 : }
339 :
340 : /************************************************************************/
341 : /* GetOverview() */
342 : /************************************************************************/
343 :
344 : GDALRasterBand *
345 588 : GDALDefaultOverviews::GetOverview( int nBand, int iOverview )
346 :
347 : {
348 : GDALRasterBand * poBand;
349 :
350 588 : if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
351 0 : return NULL;
352 :
353 588 : poBand = poODS->GetRasterBand( nBand );
354 588 : if( poBand == NULL )
355 0 : return NULL;
356 :
357 588 : if( bOvrIsAux )
358 8 : return poBand->GetOverview( iOverview );
359 :
360 : else // TIFF case, base is overview 0.
361 : {
362 580 : if( iOverview == 0 )
363 422 : return poBand;
364 158 : else if( iOverview-1 >= poBand->GetOverviewCount() )
365 0 : return NULL;
366 : else
367 158 : return poBand->GetOverview( iOverview-1 );
368 : }
369 : }
370 :
371 : /************************************************************************/
372 : /* GDALOvLevelAdjust() */
373 : /* */
374 : /* Some overview levels cannot be achieved closely enough to be */
375 : /* recognised as the desired overview level. This function */
376 : /* will adjust an overview level to one that is achievable on */
377 : /* the given raster size. */
378 : /* */
379 : /* For instance a 1200x1200 image on which a 256 level overview */
380 : /* is request will end up generating a 5x5 overview. However, */
381 : /* this will appear to the system be a level 240 overview. */
382 : /* This function will adjust 256 to 240 based on knowledge of */
383 : /* the image size. */
384 : /************************************************************************/
385 :
386 8 : int GDALOvLevelAdjust( int nOvLevel, int nXSize )
387 :
388 : {
389 8 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
390 :
391 8 : return (int) (0.5 + nXSize / (double) nOXSize);
392 : }
393 :
394 : /************************************************************************/
395 : /* CleanOverviews() */
396 : /* */
397 : /* Remove all existing overviews. */
398 : /************************************************************************/
399 :
400 5 : CPLErr GDALDefaultOverviews::CleanOverviews()
401 :
402 : {
403 : // Anything to do?
404 5 : if( poODS == NULL )
405 2 : return CE_None;
406 :
407 : // Delete the overview file(s).
408 : GDALDriver *poOvrDriver;
409 :
410 3 : poOvrDriver = poODS->GetDriver();
411 3 : GDALClose( poODS );
412 3 : poODS = NULL;
413 :
414 : CPLErr eErr;
415 3 : if( poOvrDriver != NULL )
416 3 : eErr = poOvrDriver->Delete( osOvrFilename );
417 : else
418 0 : eErr = CE_None;
419 :
420 : // Reset the saved overview filename.
421 3 : if( !EQUAL(poDS->GetDescription(),":::VIRTUAL:::") )
422 : {
423 3 : int bUseRRD = CSLTestBoolean(CPLGetConfigOption("USE_RRD","NO"));
424 :
425 3 : if( bUseRRD )
426 0 : osOvrFilename = CPLResetExtension( poDS->GetDescription(), "aux" );
427 : else
428 3 : osOvrFilename.Printf( "%s.ovr", poDS->GetDescription() );
429 : }
430 : else
431 0 : osOvrFilename = "";
432 :
433 3 : return eErr;
434 : }
435 :
436 : /************************************************************************/
437 : /* BuildOverviewsSubDataset() */
438 : /************************************************************************/
439 :
440 : CPLErr
441 4 : GDALDefaultOverviews::BuildOverviewsSubDataset(
442 : const char * pszPhysicalFile,
443 : const char * pszResampling,
444 : int nOverviews, int * panOverviewList,
445 : int nBands, int * panBandList,
446 : GDALProgressFunc pfnProgress, void * pProgressData)
447 :
448 : {
449 4 : if( osOvrFilename.length() == 0 && nOverviews > 0 )
450 : {
451 4 : int iSequence = 0;
452 : VSIStatBufL sStatBuf;
453 :
454 4 : for( iSequence = 0; iSequence < 100; iSequence++ )
455 : {
456 4 : osOvrFilename.Printf( "%s_%d.ovr", pszPhysicalFile, iSequence );
457 4 : if( VSIStatExL( osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
458 : {
459 4 : CPLString osAdjustedOvrFilename;
460 :
461 4 : if( poDS->GetMOFlags() & GMO_PAM_CLASS )
462 : {
463 : osAdjustedOvrFilename.Printf( ":::BASE:::%s_%d.ovr",
464 : CPLGetFilename(pszPhysicalFile),
465 4 : iSequence );
466 : }
467 : else
468 0 : osAdjustedOvrFilename = osOvrFilename;
469 :
470 : poDS->SetMetadataItem( "OVERVIEW_FILE",
471 : osAdjustedOvrFilename,
472 4 : "OVERVIEWS" );
473 4 : break;
474 : }
475 : }
476 :
477 4 : if( iSequence == 100 )
478 0 : osOvrFilename = "";
479 : }
480 :
481 : return BuildOverviews( NULL, pszResampling, nOverviews, panOverviewList,
482 4 : nBands, panBandList, pfnProgress, pProgressData );
483 : }
484 :
485 : /************************************************************************/
486 : /* BuildOverviews() */
487 : /************************************************************************/
488 :
489 : CPLErr
490 83 : GDALDefaultOverviews::BuildOverviews(
491 : const char * pszBasename,
492 : const char * pszResampling,
493 : int nOverviews, int * panOverviewList,
494 : int nBands, int * panBandList,
495 : GDALProgressFunc pfnProgress, void * pProgressData)
496 :
497 : {
498 : GDALRasterBand **pahBands;
499 : CPLErr eErr;
500 : int i;
501 :
502 83 : if( pfnProgress == NULL )
503 0 : pfnProgress = GDALDummyProgress;
504 :
505 83 : if( nOverviews == 0 )
506 4 : return CleanOverviews();
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* If we don't already have an overview file, we need to decide */
510 : /* what format to use. */
511 : /* -------------------------------------------------------------------- */
512 79 : if( poODS == NULL )
513 : {
514 79 : bOvrIsAux = CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" ));
515 79 : if( bOvrIsAux )
516 : {
517 : VSIStatBufL sStatBuf;
518 :
519 2 : osOvrFilename = CPLResetExtension(poDS->GetDescription(),"aux");
520 :
521 2 : if( VSIStatExL( osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
522 0 : osOvrFilename.Printf( "%s.aux", poDS->GetDescription() );
523 : }
524 : }
525 : /* -------------------------------------------------------------------- */
526 : /* If we already have the overviews open, but they are */
527 : /* read-only, then try and reopen them read-write. */
528 : /* -------------------------------------------------------------------- */
529 0 : else if( poODS->GetAccess() == GA_ReadOnly )
530 : {
531 0 : GDALClose( poODS );
532 0 : poODS = (GDALDataset *) GDALOpen( osOvrFilename, GA_Update );
533 0 : if( poODS == NULL )
534 0 : return CE_Failure;
535 : }
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* Our TIFF overview support currently only works safely if all */
539 : /* bands are handled at the same time. */
540 : /* -------------------------------------------------------------------- */
541 79 : if( !bOvrIsAux && nBands != poDS->GetRasterCount() )
542 : {
543 : CPLError( CE_Failure, CPLE_NotSupported,
544 : "Generation of overviews in external TIFF currently only"
545 : " supported when operating on all bands.\n"
546 0 : "Operation failed.\n" );
547 0 : return CE_Failure;
548 : }
549 :
550 : /* -------------------------------------------------------------------- */
551 : /* If a basename is provided, use it to override the internal */
552 : /* overview filename. */
553 : /* -------------------------------------------------------------------- */
554 79 : if( pszBasename == NULL && osOvrFilename.length() == 0 )
555 0 : pszBasename = poDS->GetDescription();
556 :
557 79 : if( pszBasename != NULL )
558 : {
559 0 : if( bOvrIsAux )
560 0 : osOvrFilename.Printf( "%s.aux", pszBasename );
561 : else
562 0 : osOvrFilename.Printf( "%s.ovr", pszBasename );
563 : }
564 :
565 : /* -------------------------------------------------------------------- */
566 : /* Establish which of the overview levels we already have, and */
567 : /* which are new. We assume that band 1 of the file is */
568 : /* representative. */
569 : /* -------------------------------------------------------------------- */
570 79 : int nNewOverviews, *panNewOverviewList = NULL;
571 79 : GDALRasterBand *poBand = poDS->GetRasterBand( 1 );
572 :
573 79 : nNewOverviews = 0;
574 79 : panNewOverviewList = (int *) CPLCalloc(sizeof(int),nOverviews);
575 178 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
576 : {
577 : int j;
578 :
579 99 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
580 : {
581 : int nOvFactor;
582 0 : GDALRasterBand * poOverview = poBand->GetOverview( j );
583 0 : if (poOverview == NULL)
584 0 : continue;
585 :
586 : nOvFactor = (int)
587 0 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
588 :
589 0 : if( nOvFactor == panOverviewList[i]
590 : || nOvFactor == GDALOvLevelAdjust( panOverviewList[i],
591 : poBand->GetXSize() ) )
592 0 : panOverviewList[i] *= -1;
593 : }
594 :
595 99 : if( panOverviewList[i] > 0 )
596 99 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
597 : }
598 :
599 : /* -------------------------------------------------------------------- */
600 : /* Build band list. */
601 : /* -------------------------------------------------------------------- */
602 79 : pahBands = (GDALRasterBand **) CPLCalloc(sizeof(GDALRasterBand *),nBands);
603 202 : for( i = 0; i < nBands; i++ )
604 123 : pahBands[i] = poDS->GetRasterBand( panBandList[i] );
605 :
606 : /* -------------------------------------------------------------------- */
607 : /* Build new overviews - Imagine. Keep existing file open if */
608 : /* we have it. But mark all overviews as in need of */
609 : /* regeneration, since HFAAuxBuildOverviews() doesn't actually */
610 : /* produce the imagery. */
611 : /* -------------------------------------------------------------------- */
612 :
613 : #ifndef WIN32CE
614 :
615 79 : if( bOvrIsAux )
616 : {
617 : eErr = HFAAuxBuildOverviews( osOvrFilename, poDS, &poODS,
618 : nBands, panBandList,
619 : nNewOverviews, panNewOverviewList,
620 : pszResampling,
621 2 : pfnProgress, pProgressData );
622 :
623 : int j;
624 :
625 4 : for( j = 0; j < nOverviews; j++ )
626 : {
627 2 : if( panOverviewList[j] > 0 )
628 2 : panOverviewList[j] *= -1;
629 : }
630 : }
631 :
632 : /* -------------------------------------------------------------------- */
633 : /* Build new overviews - TIFF. Close TIFF files while we */
634 : /* operate on it. */
635 : /* -------------------------------------------------------------------- */
636 : else
637 : #endif /* WIN32CE */
638 : {
639 77 : if( poODS != NULL )
640 : {
641 0 : delete poODS;
642 0 : poODS = NULL;
643 : }
644 :
645 : eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
646 : nNewOverviews, panNewOverviewList,
647 77 : pszResampling, pfnProgress, pProgressData );
648 :
649 : // Probe for proxy overview filename.
650 77 : if( eErr == CE_Failure )
651 : {
652 : const char *pszProxyOvrFilename =
653 3 : poDS->GetMetadataItem("FILENAME","ProxyOverviewRequest");
654 :
655 3 : if( pszProxyOvrFilename != NULL )
656 : {
657 1 : osOvrFilename = pszProxyOvrFilename;
658 : eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
659 : nNewOverviews, panNewOverviewList,
660 : pszResampling,
661 1 : pfnProgress, pProgressData );
662 : }
663 : }
664 :
665 77 : if( eErr == CE_None )
666 : {
667 75 : poODS = (GDALDataset *) GDALOpen( osOvrFilename, GA_Update );
668 75 : if( poODS == NULL )
669 0 : eErr = CE_Failure;
670 : }
671 : }
672 :
673 : /* -------------------------------------------------------------------- */
674 : /* Refresh old overviews that were listed. */
675 : /* -------------------------------------------------------------------- */
676 : GDALRasterBand **papoOverviewBands;
677 :
678 : papoOverviewBands = (GDALRasterBand **)
679 79 : CPLCalloc(sizeof(void*),nOverviews);
680 :
681 200 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
682 : {
683 121 : poBand = poDS->GetRasterBand( panBandList[iBand] );
684 :
685 121 : nNewOverviews = 0;
686 289 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
687 : {
688 : int j;
689 :
690 426 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
691 : {
692 : int nOvFactor;
693 260 : GDALRasterBand * poOverview = poBand->GetOverview( j );
694 260 : if (poOverview == NULL)
695 0 : continue;
696 :
697 : int bHasNoData;
698 260 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
699 :
700 260 : if (bHasNoData)
701 7 : poOverview->SetNoDataValue(noDataValue);
702 :
703 : nOvFactor = (int)
704 260 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
705 :
706 518 : if( nOvFactor == - panOverviewList[i]
707 258 : || (panOverviewList[i] < 0 &&
708 0 : nOvFactor == GDALOvLevelAdjust( -panOverviewList[i],
709 : poBand->GetXSize() )) )
710 : {
711 2 : papoOverviewBands[nNewOverviews++] = poOverview;
712 2 : break;
713 : }
714 : }
715 : }
716 :
717 121 : if( nNewOverviews > 0 )
718 : {
719 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
720 : nNewOverviews,
721 : (GDALRasterBandH*)papoOverviewBands,
722 : pszResampling,
723 2 : pfnProgress, pProgressData );
724 : }
725 : }
726 :
727 : /* -------------------------------------------------------------------- */
728 : /* Cleanup */
729 : /* -------------------------------------------------------------------- */
730 79 : CPLFree( papoOverviewBands );
731 79 : CPLFree( panNewOverviewList );
732 79 : CPLFree( pahBands );
733 :
734 : /* -------------------------------------------------------------------- */
735 : /* If we have a mask file, we need to build it's overviews */
736 : /* too. */
737 : /* -------------------------------------------------------------------- */
738 79 : if( HaveMaskFile() && poMaskDS )
739 : {
740 : poMaskDS->BuildOverviews( pszResampling, nOverviews, panOverviewList,
741 1 : 0, NULL, pfnProgress, pProgressData );
742 1 : if( bOwnMaskDS )
743 1 : GDALClose( poMaskDS );
744 :
745 : // force next request to reread mask file.
746 1 : poMaskDS = NULL;
747 1 : bOwnMaskDS = FALSE;
748 1 : bCheckedForMask = FALSE;
749 : }
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* If we have an overview dataset, then mark all the overviews */
753 : /* with the base dataset Used later for finding overviews */
754 : /* masks. Uggg. */
755 : /* -------------------------------------------------------------------- */
756 79 : if( poODS )
757 : {
758 77 : int nOverviewCount = GetOverviewCount(1);
759 : int iOver;
760 :
761 174 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
762 : {
763 97 : GDALRasterBand *poBand = GetOverview( 1, iOver );
764 97 : GDALDataset *poOverDS = NULL;
765 :
766 97 : if( poBand != NULL )
767 97 : poOverDS = poBand->GetDataset();
768 :
769 97 : if (poOverDS != NULL)
770 : {
771 95 : poOverDS->oOvManager.poBaseDS = poDS;
772 95 : poOverDS->oOvManager.poDS = poOverDS;
773 : }
774 : }
775 : }
776 :
777 79 : return eErr;
778 : }
779 :
780 : /************************************************************************/
781 : /* CreateMaskBand() */
782 : /************************************************************************/
783 :
784 5 : CPLErr GDALDefaultOverviews::CreateMaskBand( int nFlags, int nBand )
785 :
786 : {
787 5 : if( nBand < 1 )
788 5 : nFlags |= GMF_PER_DATASET;
789 :
790 : /* -------------------------------------------------------------------- */
791 : /* ensure existing file gets opened if there is one. */
792 : /* -------------------------------------------------------------------- */
793 5 : HaveMaskFile();
794 :
795 : /* -------------------------------------------------------------------- */
796 : /* Try creating the mask file. */
797 : /* -------------------------------------------------------------------- */
798 5 : if( poMaskDS == NULL )
799 : {
800 5 : CPLString osMskFilename;
801 5 : GDALDriver *poDr = (GDALDriver *) GDALGetDriverByName( "GTiff" );
802 5 : char **papszOpt = NULL;
803 : int nBX, nBY;
804 : int nBands;
805 :
806 5 : if( poDr == NULL )
807 0 : return CE_Failure;
808 :
809 5 : GDALRasterBand *poTBand = poDS->GetRasterBand(1);
810 5 : if( poTBand == NULL )
811 0 : return CE_Failure;
812 :
813 5 : if( nFlags & GMF_PER_DATASET )
814 5 : nBands = 1;
815 : else
816 0 : nBands = poDS->GetRasterCount();
817 :
818 :
819 5 : papszOpt = CSLSetNameValue( papszOpt, "COMPRESS", "DEFLATE" );
820 5 : papszOpt = CSLSetNameValue( papszOpt, "INTERLEAVE", "BAND" );
821 :
822 5 : poTBand->GetBlockSize( &nBX, &nBY );
823 :
824 : // try to create matching tile size if legal in TIFF.
825 5 : if( (nBX % 16) == 0 && (nBY % 16) == 0 )
826 : {
827 2 : papszOpt = CSLSetNameValue( papszOpt, "TILED", "YES" );
828 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKXSIZE",
829 2 : CPLString().Printf("%d",nBX) );
830 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKYSIZE",
831 2 : CPLString().Printf("%d",nBY) );
832 : }
833 :
834 5 : osMskFilename.Printf( "%s.msk", poDS->GetDescription() );
835 : poMaskDS = poDr->Create( osMskFilename,
836 : poDS->GetRasterXSize(),
837 : poDS->GetRasterYSize(),
838 5 : nBands, GDT_Byte, papszOpt );
839 5 : CSLDestroy( papszOpt );
840 :
841 5 : if( poMaskDS == NULL ) // presumably error already issued.
842 0 : return CE_Failure;
843 :
844 5 : bOwnMaskDS = TRUE;
845 : }
846 :
847 : /* -------------------------------------------------------------------- */
848 : /* Save the mask flags for this band. */
849 : /* -------------------------------------------------------------------- */
850 5 : if( nBand > poMaskDS->GetRasterCount() )
851 : {
852 : CPLError( CE_Failure, CPLE_AppDefined,
853 : "Attempt to create a mask band for band %d of %s,\n"
854 : "but the .msk file has a PER_DATASET mask.",
855 0 : nBand, poDS->GetDescription() );
856 0 : return CE_Failure;
857 : }
858 :
859 : int iBand;
860 :
861 32 : for( iBand = 0; iBand < poDS->GetRasterCount(); iBand++ )
862 : {
863 : // we write only the info for this band, unless we are
864 : // using PER_DATASET in which case we write for all.
865 : if( nBand != iBand + 1 && !(nFlags | GMF_PER_DATASET) )
866 : continue;
867 :
868 : poMaskDS->SetMetadataItem(
869 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand+1 ),
870 11 : CPLString().Printf("%d", nFlags ) );
871 : }
872 :
873 5 : return CE_None;
874 : }
875 :
876 : /************************************************************************/
877 : /* GetMaskBand() */
878 : /************************************************************************/
879 :
880 15 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand( int nBand )
881 :
882 : {
883 15 : int nFlags = GetMaskFlags( nBand );
884 :
885 15 : if( nFlags == 0x8000 ) // secret code meaning we don't handle this band.
886 0 : return NULL;
887 :
888 15 : if( nFlags & GMF_PER_DATASET )
889 15 : return poMaskDS->GetRasterBand(1);
890 :
891 0 : if( nBand > 0 )
892 0 : return poMaskDS->GetRasterBand( nBand );
893 : else
894 0 : return NULL;
895 : }
896 :
897 : /************************************************************************/
898 : /* GetMaskFlags() */
899 : /************************************************************************/
900 :
901 30 : int GDALDefaultOverviews::GetMaskFlags( int nBand )
902 :
903 : {
904 : /* -------------------------------------------------------------------- */
905 : /* Fetch this band's metadata entry. They are of the form: */
906 : /* INTERNAL_MASK_FLAGS_n: flags */
907 : /* -------------------------------------------------------------------- */
908 30 : if( !HaveMaskFile() )
909 0 : return 0;
910 :
911 : const char *pszValue =
912 : poMaskDS->GetMetadataItem(
913 30 : CPLString().Printf( "INTERNAL_MASK_FLAGS_%d", MAX(nBand,1)) );
914 :
915 30 : if( pszValue == NULL )
916 0 : return 0x8000;
917 : else
918 30 : return atoi(pszValue);
919 : }
920 :
921 : /************************************************************************/
922 : /* HaveMaskFile() */
923 : /* */
924 : /* Check for a mask file if we haven't already done so. */
925 : /* Returns TRUE if we have one, otherwise FALSE. */
926 : /************************************************************************/
927 :
928 2924 : int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
929 : const char *pszBasename )
930 :
931 : {
932 : /* -------------------------------------------------------------------- */
933 : /* Have we already checked for masks? */
934 : /* -------------------------------------------------------------------- */
935 2924 : if( bCheckedForMask )
936 330 : return poMaskDS != NULL;
937 :
938 2594 : if( papszSiblingFiles == NULL )
939 2594 : papszSiblingFiles = papszInitSiblingFiles;
940 :
941 : /* -------------------------------------------------------------------- */
942 : /* Are we an overview? If so we need to find the corresponding */
943 : /* overview in the base files mask file (if there is one). */
944 : /* -------------------------------------------------------------------- */
945 2594 : if( poBaseDS != NULL && poBaseDS->oOvManager.HaveMaskFile() )
946 : {
947 3 : int iOver, nOverviewCount = 0;
948 3 : GDALRasterBand *poBaseBand = poBaseDS->GetRasterBand(1);
949 3 : GDALRasterBand *poBaseMask = NULL;
950 :
951 3 : if( poBaseBand != NULL )
952 3 : poBaseMask = poBaseBand->GetMaskBand();
953 3 : if( poBaseMask )
954 3 : nOverviewCount = poBaseMask->GetOverviewCount();
955 :
956 5 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
957 : {
958 5 : GDALRasterBand *poOverBand = poBaseMask->GetOverview( iOver );
959 5 : if (poOverBand == NULL)
960 0 : continue;
961 :
962 5 : if( poOverBand->GetXSize() == poDS->GetRasterXSize()
963 : && poOverBand->GetYSize() == poDS->GetRasterYSize() )
964 : {
965 3 : poMaskDS = poOverBand->GetDataset();
966 3 : break;
967 : }
968 : }
969 :
970 3 : bCheckedForMask = TRUE;
971 3 : bOwnMaskDS = FALSE;
972 :
973 3 : CPLAssert( poMaskDS != poDS );
974 :
975 3 : return poMaskDS != NULL;
976 : }
977 :
978 : /* -------------------------------------------------------------------- */
979 : /* Are we even initialized? If not, we apparently don't want */
980 : /* to support overviews and masks. */
981 : /* -------------------------------------------------------------------- */
982 2591 : if( !IsInitialized() )
983 187 : return FALSE;
984 :
985 : /* -------------------------------------------------------------------- */
986 : /* Check for .msk file. */
987 : /* -------------------------------------------------------------------- */
988 2404 : CPLString osMskFilename;
989 2404 : bCheckedForMask = TRUE;
990 :
991 2404 : if( pszBasename == NULL )
992 2404 : pszBasename = poDS->GetDescription();
993 :
994 : // Don't bother checking for masks of masks.
995 2404 : if( EQUAL(CPLGetExtension(pszBasename),"msk") )
996 4 : return FALSE;
997 :
998 2400 : osMskFilename.Printf( "%s.msk", pszBasename );
999 :
1000 : int bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
1001 2400 : papszSiblingFiles );
1002 :
1003 : #if !defined(WIN32)
1004 2400 : if( !bExists && !papszSiblingFiles )
1005 : {
1006 688 : osMskFilename.Printf( "%s.MSK", pszBasename );
1007 : bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
1008 688 : papszSiblingFiles );
1009 : }
1010 : #endif
1011 :
1012 2400 : if( !bExists )
1013 2388 : return FALSE;
1014 :
1015 : /* -------------------------------------------------------------------- */
1016 : /* Open the file. */
1017 : /* -------------------------------------------------------------------- */
1018 : GDALOpenInfo oOpenInfo(osMskFilename, poDS->GetAccess(),
1019 12 : papszInitSiblingFiles);
1020 12 : poMaskDS = (GDALDataset *) GDALOpenInternal( oOpenInfo, NULL );
1021 12 : CPLAssert( poMaskDS != poDS );
1022 :
1023 12 : if( poMaskDS == NULL )
1024 0 : return FALSE;
1025 :
1026 12 : bOwnMaskDS = TRUE;
1027 :
1028 12 : return TRUE;
1029 : }
|