1 : /******************************************************************************
2 : * $Id: gdaldefaultoverviews.cpp 19429 2010-04-17 00:41:48Z 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 19429 2010-04-17 00:41:48Z warmerdam $");
35 :
36 : /************************************************************************/
37 : /* GDALDefaultOverviews() */
38 : /************************************************************************/
39 :
40 13509 : GDALDefaultOverviews::GDALDefaultOverviews()
41 :
42 : {
43 13509 : poDS = NULL;
44 13509 : poODS = NULL;
45 13509 : bOvrIsAux = FALSE;
46 :
47 13509 : bCheckedForMask = FALSE;
48 13509 : bCheckedForOverviews = FALSE;
49 :
50 13509 : poMaskDS = NULL;
51 :
52 13509 : bOwnMaskDS = FALSE;
53 13509 : poBaseDS = NULL;
54 :
55 13509 : papszInitSiblingFiles = NULL;
56 13509 : pszInitName = NULL;
57 13509 : }
58 :
59 : /************************************************************************/
60 : /* ~GDALDefaultOverviews() */
61 : /************************************************************************/
62 :
63 13509 : GDALDefaultOverviews::~GDALDefaultOverviews()
64 :
65 : {
66 13509 : CPLFree( pszInitName );
67 13509 : CSLDestroy( papszInitSiblingFiles );
68 :
69 13509 : if( poODS != NULL )
70 : {
71 171 : poODS->FlushCache();
72 171 : GDALClose( poODS );
73 171 : poODS = NULL;
74 : }
75 :
76 13509 : if( poMaskDS != NULL )
77 : {
78 13 : if( bOwnMaskDS )
79 : {
80 10 : poMaskDS->FlushCache();
81 10 : GDALClose( poMaskDS );
82 : }
83 13 : poMaskDS = NULL;
84 : }
85 13509 : }
86 :
87 : /************************************************************************/
88 : /* IsInitialized() */
89 : /* */
90 : /* Returns TRUE if we are initialized. */
91 : /************************************************************************/
92 :
93 303197 : int GDALDefaultOverviews::IsInitialized()
94 :
95 : {
96 303197 : OverviewScan();
97 303197 : return poDS != NULL;
98 : }
99 :
100 : /************************************************************************/
101 : /* Initialize() */
102 : /************************************************************************/
103 :
104 : void GDALDefaultOverviews::Initialize( GDALDataset *poDSIn,
105 : const char * pszBasename,
106 : char **papszSiblingFiles,
107 6713 : int bNameIsOVR )
108 :
109 : {
110 6713 : poDS = poDSIn;
111 :
112 : /* -------------------------------------------------------------------- */
113 : /* If we were already initialized, destroy the old overview */
114 : /* file handle. */
115 : /* -------------------------------------------------------------------- */
116 6713 : 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 6713 : bCheckedForOverviews = FALSE;
129 :
130 6713 : CPLFree( pszInitName );
131 6713 : pszInitName = NULL;
132 6713 : if( pszBasename != NULL )
133 6713 : pszInitName = CPLStrdup(pszBasename);
134 6713 : bInitNameIsOVR = bNameIsOVR;
135 :
136 6713 : CSLDestroy( papszInitSiblingFiles );
137 6713 : papszInitSiblingFiles = NULL;
138 6713 : if( papszSiblingFiles != NULL )
139 47 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
140 6713 : }
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 303197 : void GDALDefaultOverviews::OverviewScan()
152 :
153 : {
154 303197 : if( bCheckedForOverviews || poDS == NULL )
155 301332 : return;
156 :
157 1865 : bCheckedForOverviews = true;
158 :
159 1865 : CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" );
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Open overview dataset if it exists. */
163 : /* -------------------------------------------------------------------- */
164 : int bExists;
165 :
166 1865 : if( pszInitName == NULL )
167 0 : pszInitName = CPLStrdup(poDS->GetDescription());
168 :
169 1865 : if( !EQUAL(pszInitName,":::VIRTUAL:::") )
170 : {
171 1752 : if( bInitNameIsOVR )
172 0 : osOvrFilename = pszInitName;
173 : else
174 1752 : osOvrFilename.Printf( "%s.ovr", pszInitName );
175 :
176 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
177 1752 : papszInitSiblingFiles );
178 :
179 : #if !defined(WIN32)
180 1752 : if( !bInitNameIsOVR && !bExists && !papszInitSiblingFiles )
181 : {
182 1642 : osOvrFilename.Printf( "%s.OVR", pszInitName );
183 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
184 1642 : papszInitSiblingFiles );
185 1642 : if( !bExists )
186 1642 : osOvrFilename.Printf( "%s.ovr", pszInitName );
187 : }
188 : #endif
189 :
190 1752 : if( bExists )
191 : {
192 96 : 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 1865 : if( !poODS && !EQUAL(pszInitName,":::VIRTUAL:::") )
205 : {
206 : poODS = GDALFindAssociatedAuxFile( pszInitName, poDS->GetAccess(),
207 1656 : poDS );
208 :
209 1656 : 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 1865 : if( poODS == NULL )
233 : {
234 : const char *pszProxyOvrFilename =
235 1767 : poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
236 :
237 1767 : if( pszProxyOvrFilename != NULL )
238 : {
239 6 : 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 6 : osOvrFilename = pszProxyOvrFilename;
248 :
249 6 : 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 1865 : if( poODS )
259 : {
260 104 : int nOverviewCount = GetOverviewCount(1);
261 : int iOver;
262 :
263 229 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
264 : {
265 125 : GDALRasterBand *poBand = GetOverview( 1, iOver );
266 125 : GDALDataset *poOverDS = NULL;
267 :
268 125 : if( poBand != NULL )
269 125 : poOverDS = poBand->GetDataset();
270 :
271 125 : if( poOverDS != NULL )
272 : {
273 123 : poOverDS->oOvManager.poBaseDS = poDS;
274 123 : poOverDS->oOvManager.poDS = poOverDS;
275 : }
276 : }
277 : }
278 : }
279 :
280 : /************************************************************************/
281 : /* GetOverviewCount() */
282 : /************************************************************************/
283 :
284 299852 : int GDALDefaultOverviews::GetOverviewCount( int nBand )
285 :
286 : {
287 : GDALRasterBand * poBand;
288 :
289 299852 : if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
290 299311 : return 0;
291 :
292 541 : poBand = poODS->GetRasterBand( nBand );
293 541 : if( poBand == NULL )
294 0 : return 0;
295 : else
296 : {
297 541 : if( bOvrIsAux )
298 8 : return poBand->GetOverviewCount();
299 : else
300 533 : return poBand->GetOverviewCount() + 1;
301 : }
302 : }
303 :
304 : /************************************************************************/
305 : /* GetOverview() */
306 : /************************************************************************/
307 :
308 : GDALRasterBand *
309 505 : GDALDefaultOverviews::GetOverview( int nBand, int iOverview )
310 :
311 : {
312 : GDALRasterBand * poBand;
313 :
314 505 : if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
315 0 : return NULL;
316 :
317 505 : poBand = poODS->GetRasterBand( nBand );
318 505 : if( poBand == NULL )
319 0 : return NULL;
320 :
321 505 : if( bOvrIsAux )
322 8 : return poBand->GetOverview( iOverview );
323 :
324 : else // TIFF case, base is overview 0.
325 : {
326 497 : if( iOverview == 0 )
327 365 : return poBand;
328 132 : else if( iOverview-1 >= poBand->GetOverviewCount() )
329 0 : return NULL;
330 : else
331 132 : 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 214 : int GDALOvLevelAdjust( int nOvLevel, int nXSize )
351 :
352 : {
353 214 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
354 :
355 214 : return (int) (0.5 + nXSize / (double) nOXSize);
356 : }
357 :
358 : /************************************************************************/
359 : /* CleanOverviews() */
360 : /* */
361 : /* Remove all existing overviews. */
362 : /************************************************************************/
363 :
364 5 : CPLErr GDALDefaultOverviews::CleanOverviews()
365 :
366 : {
367 : // Anything to do?
368 5 : if( poODS == NULL )
369 2 : 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 : GDALDefaultOverviews::BuildOverviewsSubDataset(
406 : const char * pszPhysicalFile,
407 : const char * pszResampling,
408 : int nOverviews, int * panOverviewList,
409 : int nBands, int * panBandList,
410 4 : GDALProgressFunc pfnProgress, void * pProgressData)
411 :
412 : {
413 4 : if( osOvrFilename.length() == 0 && nOverviews > 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 : GDALDefaultOverviews::BuildOverviews(
455 : const char * pszBasename,
456 : const char * pszResampling,
457 : int nOverviews, int * panOverviewList,
458 : int nBands, int * panBandList,
459 76 : GDALProgressFunc pfnProgress, void * pProgressData)
460 :
461 : {
462 : GDALRasterBand **pahBands;
463 : CPLErr eErr;
464 : int i;
465 :
466 76 : if( pfnProgress == NULL )
467 0 : pfnProgress = GDALDummyProgress;
468 :
469 76 : 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 72 : if( poODS == NULL )
477 : {
478 72 : bOvrIsAux = CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" ));
479 72 : 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 72 : 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 72 : if( pszBasename == NULL && osOvrFilename.length() == 0 )
519 0 : pszBasename = poDS->GetDescription();
520 :
521 72 : 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 72 : int nNewOverviews, *panNewOverviewList = NULL;
535 72 : GDALRasterBand *poBand = poDS->GetRasterBand( 1 );
536 :
537 72 : nNewOverviews = 0;
538 72 : panNewOverviewList = (int *) CPLCalloc(sizeof(int),nOverviews);
539 161 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
540 : {
541 : int j;
542 :
543 89 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
544 : {
545 : int nOvFactor;
546 0 : GDALRasterBand * poOverview = poBand->GetOverview( j );
547 0 : if (poOverview == NULL)
548 0 : continue;
549 :
550 : nOvFactor = (int)
551 0 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
552 :
553 0 : if( nOvFactor == panOverviewList[i]
554 : || nOvFactor == GDALOvLevelAdjust( panOverviewList[i],
555 : poBand->GetXSize() ) )
556 0 : panOverviewList[i] *= -1;
557 : }
558 :
559 89 : if( panOverviewList[i] > 0 )
560 89 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
561 : }
562 :
563 : /* -------------------------------------------------------------------- */
564 : /* Build band list. */
565 : /* -------------------------------------------------------------------- */
566 72 : pahBands = (GDALRasterBand **) CPLCalloc(sizeof(GDALRasterBand *),nBands);
567 175 : for( i = 0; i < nBands; i++ )
568 103 : pahBands[i] = poDS->GetRasterBand( panBandList[i] );
569 :
570 : /* -------------------------------------------------------------------- */
571 : /* Build new overviews - Imagine. Keep existing file open if */
572 : /* we have it. But mark all overviews as in need of */
573 : /* regeneration, since HFAAuxBuildOverviews() doesn't actually */
574 : /* produce the imagery. */
575 : /* -------------------------------------------------------------------- */
576 :
577 : #ifndef WIN32CE
578 :
579 72 : if( bOvrIsAux )
580 : {
581 : eErr = HFAAuxBuildOverviews( osOvrFilename, poDS, &poODS,
582 : nBands, panBandList,
583 : nNewOverviews, panNewOverviewList,
584 : pszResampling,
585 2 : pfnProgress, pProgressData );
586 :
587 : int j;
588 :
589 4 : for( j = 0; j < nOverviews; j++ )
590 : {
591 2 : if( panOverviewList[j] > 0 )
592 2 : panOverviewList[j] *= -1;
593 : }
594 : }
595 :
596 : /* -------------------------------------------------------------------- */
597 : /* Build new overviews - TIFF. Close TIFF files while we */
598 : /* operate on it. */
599 : /* -------------------------------------------------------------------- */
600 : else
601 : #endif /* WIN32CE */
602 : {
603 70 : if( poODS != NULL )
604 : {
605 0 : delete poODS;
606 0 : poODS = NULL;
607 : }
608 :
609 : eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
610 : nNewOverviews, panNewOverviewList,
611 70 : pszResampling, pfnProgress, pProgressData );
612 :
613 : // Probe for proxy overview filename.
614 70 : if( eErr == CE_Failure )
615 : {
616 : const char *pszProxyOvrFilename =
617 2 : poDS->GetMetadataItem("FILENAME","ProxyOverviewRequest");
618 :
619 2 : if( pszProxyOvrFilename != NULL )
620 : {
621 0 : osOvrFilename = pszProxyOvrFilename;
622 : eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
623 : nNewOverviews, panNewOverviewList,
624 : pszResampling,
625 0 : pfnProgress, pProgressData );
626 : }
627 : }
628 :
629 70 : if( eErr == CE_None )
630 : {
631 68 : poODS = (GDALDataset *) GDALOpen( osOvrFilename, GA_Update );
632 68 : if( poODS == NULL )
633 0 : eErr = CE_Failure;
634 : }
635 : }
636 :
637 : /* -------------------------------------------------------------------- */
638 : /* Refresh old overviews that were listed. */
639 : /* -------------------------------------------------------------------- */
640 : GDALRasterBand **papoOverviewBands;
641 :
642 : papoOverviewBands = (GDALRasterBand **)
643 72 : CPLCalloc(sizeof(void*),nOverviews);
644 :
645 173 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
646 : {
647 101 : poBand = poDS->GetRasterBand( panBandList[iBand] );
648 :
649 101 : nNewOverviews = 0;
650 240 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
651 : {
652 : int j;
653 :
654 340 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
655 : {
656 : int nOvFactor;
657 209 : GDALRasterBand * poOverview = poBand->GetOverview( j );
658 209 : if (poOverview == NULL)
659 0 : continue;
660 :
661 : int bHasNoData;
662 209 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
663 :
664 209 : if (bHasNoData)
665 7 : poOverview->SetNoDataValue(noDataValue);
666 :
667 : nOvFactor = (int)
668 209 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
669 :
670 209 : if( nOvFactor == - panOverviewList[i]
671 : || nOvFactor == GDALOvLevelAdjust( -panOverviewList[i],
672 : poBand->GetXSize() ) )
673 : {
674 8 : papoOverviewBands[nNewOverviews++] = poOverview;
675 8 : break;
676 : }
677 : }
678 : }
679 :
680 101 : if( nNewOverviews > 0 )
681 : {
682 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
683 : nNewOverviews,
684 : (GDALRasterBandH*)papoOverviewBands,
685 : pszResampling,
686 6 : pfnProgress, pProgressData );
687 : }
688 : }
689 :
690 : /* -------------------------------------------------------------------- */
691 : /* Cleanup */
692 : /* -------------------------------------------------------------------- */
693 72 : CPLFree( papoOverviewBands );
694 72 : CPLFree( panNewOverviewList );
695 72 : CPLFree( pahBands );
696 :
697 : /* -------------------------------------------------------------------- */
698 : /* If we have a mask file, we need to build it's overviews */
699 : /* too. */
700 : /* -------------------------------------------------------------------- */
701 72 : if( HaveMaskFile() && poMaskDS )
702 : {
703 : poMaskDS->BuildOverviews( pszResampling, nOverviews, panOverviewList,
704 1 : 0, NULL, pfnProgress, pProgressData );
705 1 : if( bOwnMaskDS )
706 1 : GDALClose( poMaskDS );
707 :
708 : // force next request to reread mask file.
709 1 : poMaskDS = NULL;
710 1 : bOwnMaskDS = FALSE;
711 1 : bCheckedForMask = FALSE;
712 : }
713 :
714 : /* -------------------------------------------------------------------- */
715 : /* If we have an overview dataset, then mark all the overviews */
716 : /* with the base dataset Used later for finding overviews */
717 : /* masks. Uggg. */
718 : /* -------------------------------------------------------------------- */
719 72 : if( poODS )
720 : {
721 70 : int nOverviewCount = GetOverviewCount(1);
722 : int iOver;
723 :
724 157 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
725 : {
726 87 : GDALRasterBand *poBand = GetOverview( 1, iOver );
727 87 : GDALDataset *poOverDS = NULL;
728 :
729 87 : if( poBand != NULL )
730 87 : poOverDS = poBand->GetDataset();
731 :
732 87 : if (poOverDS != NULL)
733 : {
734 85 : poOverDS->oOvManager.poBaseDS = poDS;
735 85 : poOverDS->oOvManager.poDS = poOverDS;
736 : }
737 : }
738 : }
739 :
740 72 : return eErr;
741 : }
742 :
743 : /************************************************************************/
744 : /* CreateMaskBand() */
745 : /************************************************************************/
746 :
747 3 : CPLErr GDALDefaultOverviews::CreateMaskBand( int nFlags, int nBand )
748 :
749 : {
750 3 : if( nBand < 1 )
751 3 : nFlags |= GMF_PER_DATASET;
752 :
753 : /* -------------------------------------------------------------------- */
754 : /* ensure existing file gets opened if there is one. */
755 : /* -------------------------------------------------------------------- */
756 3 : HaveMaskFile();
757 :
758 : /* -------------------------------------------------------------------- */
759 : /* Try creating the mask file. */
760 : /* -------------------------------------------------------------------- */
761 3 : if( poMaskDS == NULL )
762 : {
763 3 : CPLString osMskFilename;
764 3 : GDALDriver *poDr = (GDALDriver *) GDALGetDriverByName( "GTiff" );
765 3 : char **papszOpt = NULL;
766 : int nBX, nBY;
767 : int nBands;
768 :
769 3 : if( poDr == NULL )
770 0 : return CE_Failure;
771 :
772 3 : GDALRasterBand *poTBand = poDS->GetRasterBand(1);
773 3 : if( poTBand == NULL )
774 0 : return CE_Failure;
775 :
776 3 : if( nFlags & GMF_PER_DATASET )
777 3 : nBands = 1;
778 : else
779 0 : nBands = poDS->GetRasterCount();
780 :
781 :
782 3 : papszOpt = CSLSetNameValue( papszOpt, "COMPRESS", "DEFLATE" );
783 3 : papszOpt = CSLSetNameValue( papszOpt, "INTERLEAVE", "BAND" );
784 :
785 3 : poTBand->GetBlockSize( &nBX, &nBY );
786 :
787 : // try to create matching tile size if legal in TIFF.
788 3 : if( (nBX % 16) == 0 && (nBY % 16) == 0 )
789 : {
790 0 : papszOpt = CSLSetNameValue( papszOpt, "TILED", "YES" );
791 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKXSIZE",
792 0 : CPLString().Printf("%d",nBX) );
793 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKYSIZE",
794 0 : CPLString().Printf("%d",nBY) );
795 : }
796 :
797 3 : osMskFilename.Printf( "%s.msk", poDS->GetDescription() );
798 : poMaskDS = poDr->Create( osMskFilename,
799 : poDS->GetRasterXSize(),
800 : poDS->GetRasterYSize(),
801 3 : nBands, GDT_Byte, papszOpt );
802 3 : CSLDestroy( papszOpt );
803 :
804 3 : if( poMaskDS == NULL ) // presumably error already issued.
805 0 : return CE_Failure;
806 :
807 3 : bOwnMaskDS = TRUE;
808 : }
809 :
810 : /* -------------------------------------------------------------------- */
811 : /* Save the mask flags for this band. */
812 : /* -------------------------------------------------------------------- */
813 3 : if( nBand > poMaskDS->GetRasterCount() )
814 : {
815 : CPLError( CE_Failure, CPLE_AppDefined,
816 : "Attempt to create a mask band for band %d of %s,\n"
817 : "but the .msk file has a PER_DATASET mask.",
818 0 : nBand, poDS->GetDescription() );
819 0 : return CE_Failure;
820 : }
821 :
822 : int iBand;
823 :
824 16 : for( iBand = 0; iBand < poDS->GetRasterCount(); iBand++ )
825 : {
826 : // we write only the info for this band, unless we are
827 : // using PER_DATASET in which case we write for all.
828 : if( nBand != iBand + 1 && !(nFlags | GMF_PER_DATASET) )
829 : continue;
830 :
831 : poMaskDS->SetMetadataItem(
832 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand+1 ),
833 5 : CPLString().Printf("%d", nFlags ) );
834 : }
835 :
836 3 : return CE_None;
837 : }
838 :
839 : /************************************************************************/
840 : /* GetMaskBand() */
841 : /************************************************************************/
842 :
843 10 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand( int nBand )
844 :
845 : {
846 10 : int nFlags = GetMaskFlags( nBand );
847 :
848 10 : if( nFlags == 0x8000 ) // secret code meaning we don't handle this band.
849 0 : return NULL;
850 :
851 10 : if( nFlags & GMF_PER_DATASET )
852 10 : return poMaskDS->GetRasterBand(1);
853 :
854 0 : if( nBand > 0 )
855 0 : return poMaskDS->GetRasterBand( nBand );
856 : else
857 0 : return NULL;
858 : }
859 :
860 : /************************************************************************/
861 : /* GetMaskFlags() */
862 : /************************************************************************/
863 :
864 20 : int GDALDefaultOverviews::GetMaskFlags( int nBand )
865 :
866 : {
867 : /* -------------------------------------------------------------------- */
868 : /* Fetch this band's metadata entry. They are of the form: */
869 : /* INTERNAL_MASK_FLAGS_n: flags */
870 : /* -------------------------------------------------------------------- */
871 20 : if( !HaveMaskFile() )
872 0 : return 0;
873 :
874 : const char *pszValue =
875 : poMaskDS->GetMetadataItem(
876 20 : CPLString().Printf( "INTERNAL_MASK_FLAGS_%d", MAX(nBand,1)) );
877 :
878 20 : if( pszValue == NULL )
879 0 : return 0x8000;
880 : else
881 20 : return atoi(pszValue);
882 : }
883 :
884 : /************************************************************************/
885 : /* HaveMaskFile() */
886 : /* */
887 : /* Check for a mask file if we haven't already done so. */
888 : /* Returns TRUE if we have one, otherwise FALSE. */
889 : /************************************************************************/
890 :
891 : int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
892 2077 : const char *pszBasename )
893 :
894 : {
895 : /* -------------------------------------------------------------------- */
896 : /* Have we already checked for masks? */
897 : /* -------------------------------------------------------------------- */
898 2077 : if( bCheckedForMask )
899 279 : return poMaskDS != NULL;
900 :
901 1798 : if( papszSiblingFiles == NULL )
902 1798 : papszSiblingFiles = papszInitSiblingFiles;
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Are we an overview? If so we need to find the corresponding */
906 : /* overview in the base files mask file (if there is one). */
907 : /* -------------------------------------------------------------------- */
908 1798 : if( poBaseDS != NULL && poBaseDS->oOvManager.HaveMaskFile() )
909 : {
910 3 : int iOver, nOverviewCount = 0;
911 3 : GDALRasterBand *poBaseBand = poBaseDS->GetRasterBand(1);
912 3 : GDALRasterBand *poBaseMask = NULL;
913 :
914 3 : if( poBaseBand != NULL )
915 3 : poBaseMask = poBaseBand->GetMaskBand();
916 3 : if( poBaseMask )
917 3 : nOverviewCount = poBaseMask->GetOverviewCount();
918 :
919 5 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
920 : {
921 5 : GDALRasterBand *poOverBand = poBaseMask->GetOverview( iOver );
922 5 : if (poOverBand == NULL)
923 0 : continue;
924 :
925 5 : if( poOverBand->GetXSize() == poDS->GetRasterXSize()
926 : && poOverBand->GetYSize() == poDS->GetRasterYSize() )
927 : {
928 3 : poMaskDS = poOverBand->GetDataset();
929 3 : break;
930 : }
931 : }
932 :
933 3 : bCheckedForMask = TRUE;
934 3 : bOwnMaskDS = FALSE;
935 :
936 3 : CPLAssert( poMaskDS != poDS );
937 :
938 3 : return poMaskDS != NULL;
939 : }
940 :
941 : /* -------------------------------------------------------------------- */
942 : /* Are we even initialized? If not, we apparently don't want */
943 : /* to support overviews and masks. */
944 : /* -------------------------------------------------------------------- */
945 1795 : if( !IsInitialized() )
946 138 : return FALSE;
947 :
948 : /* -------------------------------------------------------------------- */
949 : /* Check for .msk file. */
950 : /* -------------------------------------------------------------------- */
951 1657 : CPLString osMskFilename;
952 1657 : bCheckedForMask = TRUE;
953 :
954 1657 : if( pszBasename == NULL )
955 1657 : pszBasename = poDS->GetDescription();
956 :
957 : // Don't bother checking for masks of masks.
958 1657 : if( EQUAL(CPLGetExtension(pszBasename),".msk") )
959 1657 : return FALSE;
960 :
961 1657 : osMskFilename.Printf( "%s.msk", pszBasename );
962 :
963 : int bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
964 1657 : papszSiblingFiles );
965 :
966 : #if !defined(WIN32)
967 1657 : if( !bExists && !papszSiblingFiles )
968 : {
969 1637 : osMskFilename.Printf( "%s.MSK", pszBasename );
970 : bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
971 1637 : papszSiblingFiles );
972 : }
973 : #endif
974 :
975 1657 : if( !bExists )
976 1649 : return FALSE;
977 :
978 : /* -------------------------------------------------------------------- */
979 : /* Open the file. */
980 : /* -------------------------------------------------------------------- */
981 8 : poMaskDS = (GDALDataset *) GDALOpen( osMskFilename, poDS->GetAccess() );
982 8 : CPLAssert( poMaskDS != poDS );
983 :
984 8 : if( poMaskDS == NULL )
985 0 : return FALSE;
986 :
987 8 : bOwnMaskDS = TRUE;
988 :
989 8 : return TRUE;
990 : }
|