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