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