1 : /******************************************************************************
2 : * $Id: gdaldefaultoverviews.cpp 25358 2012-12-27 13:19:58Z 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 25358 2012-12-27 13:19:58Z rouault $");
35 :
36 : /************************************************************************/
37 : /* GDALDefaultOverviews() */
38 : /************************************************************************/
39 :
40 16714 : GDALDefaultOverviews::GDALDefaultOverviews()
41 :
42 : {
43 16714 : poDS = NULL;
44 16714 : poODS = NULL;
45 16714 : bOvrIsAux = FALSE;
46 :
47 16714 : bCheckedForMask = FALSE;
48 16714 : bCheckedForOverviews = FALSE;
49 :
50 16714 : poMaskDS = NULL;
51 :
52 16714 : bOwnMaskDS = FALSE;
53 16714 : poBaseDS = NULL;
54 :
55 16714 : papszInitSiblingFiles = NULL;
56 16714 : pszInitName = NULL;
57 16714 : }
58 :
59 : /************************************************************************/
60 : /* ~GDALDefaultOverviews() */
61 : /************************************************************************/
62 :
63 16714 : GDALDefaultOverviews::~GDALDefaultOverviews()
64 :
65 : {
66 16714 : CPLFree( pszInitName );
67 16714 : CSLDestroy( papszInitSiblingFiles );
68 :
69 16714 : CloseDependentDatasets();
70 16714 : }
71 :
72 : /************************************************************************/
73 : /* CloseDependentDatasets() */
74 : /************************************************************************/
75 :
76 17898 : int GDALDefaultOverviews::CloseDependentDatasets()
77 : {
78 17898 : int bHasDroppedRef = FALSE;
79 17898 : if( poODS != NULL )
80 : {
81 196 : bHasDroppedRef = TRUE;
82 196 : poODS->FlushCache();
83 196 : GDALClose( poODS );
84 196 : poODS = NULL;
85 : }
86 :
87 17898 : if( poMaskDS != NULL )
88 : {
89 23 : if( bOwnMaskDS )
90 : {
91 20 : bHasDroppedRef = TRUE;
92 20 : poMaskDS->FlushCache();
93 20 : GDALClose( poMaskDS );
94 : }
95 23 : poMaskDS = NULL;
96 : }
97 :
98 17898 : return bHasDroppedRef;
99 : }
100 :
101 : /************************************************************************/
102 : /* IsInitialized() */
103 : /* */
104 : /* Returns TRUE if we are initialized. */
105 : /************************************************************************/
106 :
107 309885 : int GDALDefaultOverviews::IsInitialized()
108 :
109 : {
110 309885 : OverviewScan();
111 309885 : return poDS != NULL;
112 : }
113 :
114 : /************************************************************************/
115 : /* Initialize() */
116 : /************************************************************************/
117 :
118 8920 : void GDALDefaultOverviews::Initialize( GDALDataset *poDSIn,
119 : const char * pszBasename,
120 : char **papszSiblingFiles,
121 : int bNameIsOVR )
122 :
123 : {
124 8920 : poDS = poDSIn;
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* If we were already initialized, destroy the old overview */
128 : /* file handle. */
129 : /* -------------------------------------------------------------------- */
130 8920 : 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 8920 : bCheckedForOverviews = FALSE;
143 :
144 8920 : CPLFree( pszInitName );
145 8920 : pszInitName = NULL;
146 8920 : if( pszBasename != NULL )
147 8920 : pszInitName = CPLStrdup(pszBasename);
148 8920 : bInitNameIsOVR = bNameIsOVR;
149 :
150 8920 : CSLDestroy( papszInitSiblingFiles );
151 8920 : papszInitSiblingFiles = NULL;
152 8920 : if( papszSiblingFiles != NULL )
153 4223 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
154 8920 : }
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 309885 : void GDALDefaultOverviews::OverviewScan()
166 :
167 : {
168 309885 : if( bCheckedForOverviews || poDS == NULL )
169 306679 : return;
170 :
171 3206 : bCheckedForOverviews = true;
172 :
173 3206 : CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" );
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Open overview dataset if it exists. */
177 : /* -------------------------------------------------------------------- */
178 : int bExists;
179 :
180 3206 : if( pszInitName == NULL )
181 0 : pszInitName = CPLStrdup(poDS->GetDescription());
182 :
183 3206 : if( !EQUAL(pszInitName,":::VIRTUAL:::") )
184 : {
185 3084 : if( bInitNameIsOVR )
186 0 : osOvrFilename = pszInitName;
187 : else
188 3084 : osOvrFilename.Printf( "%s.ovr", pszInitName );
189 :
190 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
191 3084 : papszInitSiblingFiles );
192 :
193 : #if !defined(WIN32)
194 3084 : if( !bInitNameIsOVR && !bExists && !papszInitSiblingFiles )
195 : {
196 1099 : osOvrFilename.Printf( "%s.OVR", pszInitName );
197 : bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
198 1099 : papszInitSiblingFiles );
199 1099 : if( !bExists )
200 1099 : osOvrFilename.Printf( "%s.ovr", pszInitName );
201 : }
202 : #endif
203 :
204 3084 : 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 3206 : if( !poODS && !EQUAL(pszInitName,":::VIRTUAL:::") )
221 : {
222 2980 : int bTryFindAssociatedAuxFile = TRUE;
223 2980 : if( papszInitSiblingFiles )
224 : {
225 1881 : CPLString osAuxFilename = CPLResetExtension( pszInitName, "aux");
226 : int iSibling = CSLFindString( papszInitSiblingFiles,
227 1881 : CPLGetFilename(osAuxFilename) );
228 1881 : if( iSibling < 0 )
229 : {
230 1877 : osAuxFilename = pszInitName;
231 1877 : osAuxFilename += ".aux";
232 : iSibling = CSLFindString( papszInitSiblingFiles,
233 1877 : CPLGetFilename(osAuxFilename) );
234 1877 : if( iSibling < 0 )
235 1877 : bTryFindAssociatedAuxFile = FALSE;
236 1881 : }
237 : }
238 :
239 2980 : if (bTryFindAssociatedAuxFile)
240 : {
241 : poODS = GDALFindAssociatedAuxFile( pszInitName, poDS->GetAccess(),
242 1103 : poDS );
243 : }
244 :
245 2980 : 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 3206 : if( poODS == NULL )
269 : {
270 : const char *pszProxyOvrFilename =
271 3095 : poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
272 :
273 3095 : 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 3206 : 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 303164 : int GDALDefaultOverviews::GetOverviewCount( int nBand )
323 :
324 : {
325 : GDALRasterBand * poBand;
326 :
327 303164 : if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
328 302432 : 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 : /* Some config option are not compatible with mask overviews */
751 : /* so unset them, and define more sensible values */
752 1 : int bJPEG = EQUAL(CPLGetConfigOption("COMPRESS_OVERVIEW", ""), "JPEG");
753 1 : int bPHOTOMETRIC_YCBCR = EQUAL(CPLGetConfigOption("PHOTOMETRIC_OVERVIEW", ""), "YCBCR");
754 1 : if( bJPEG )
755 0 : CPLSetThreadLocalConfigOption("COMPRESS_OVERVIEW", "DEFLATE");
756 1 : if( bPHOTOMETRIC_YCBCR )
757 0 : CPLSetThreadLocalConfigOption("PHOTOMETRIC_OVERVIEW", "");
758 :
759 : poMaskDS->BuildOverviews( pszResampling, nOverviews, panOverviewList,
760 1 : 0, NULL, pfnProgress, pProgressData );
761 :
762 : /* Restore config option */
763 1 : if( bJPEG )
764 0 : CPLSetThreadLocalConfigOption("COMPRESS_OVERVIEW", "JPEG");
765 1 : if( bPHOTOMETRIC_YCBCR )
766 0 : CPLSetThreadLocalConfigOption("PHOTOMETRIC_OVERVIEW", "YCBCR");
767 :
768 1 : if( bOwnMaskDS )
769 1 : GDALClose( poMaskDS );
770 :
771 : // force next request to reread mask file.
772 1 : poMaskDS = NULL;
773 1 : bOwnMaskDS = FALSE;
774 1 : bCheckedForMask = FALSE;
775 : }
776 :
777 : /* -------------------------------------------------------------------- */
778 : /* If we have an overview dataset, then mark all the overviews */
779 : /* with the base dataset Used later for finding overviews */
780 : /* masks. Uggg. */
781 : /* -------------------------------------------------------------------- */
782 85 : if( poODS )
783 : {
784 83 : int nOverviewCount = GetOverviewCount(1);
785 : int iOver;
786 :
787 193 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
788 : {
789 110 : GDALRasterBand *poBand = GetOverview( 1, iOver );
790 110 : GDALDataset *poOverDS = NULL;
791 :
792 110 : if( poBand != NULL )
793 110 : poOverDS = poBand->GetDataset();
794 :
795 110 : if (poOverDS != NULL)
796 : {
797 97 : poOverDS->oOvManager.poBaseDS = poDS;
798 97 : poOverDS->oOvManager.poDS = poOverDS;
799 : }
800 : }
801 : }
802 :
803 85 : return eErr;
804 : }
805 :
806 : /************************************************************************/
807 : /* CreateMaskBand() */
808 : /************************************************************************/
809 :
810 7 : CPLErr GDALDefaultOverviews::CreateMaskBand( int nFlags, int nBand )
811 :
812 : {
813 7 : if( nBand < 1 )
814 7 : nFlags |= GMF_PER_DATASET;
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* ensure existing file gets opened if there is one. */
818 : /* -------------------------------------------------------------------- */
819 7 : HaveMaskFile();
820 :
821 : /* -------------------------------------------------------------------- */
822 : /* Try creating the mask file. */
823 : /* -------------------------------------------------------------------- */
824 7 : if( poMaskDS == NULL )
825 : {
826 7 : CPLString osMskFilename;
827 7 : GDALDriver *poDr = (GDALDriver *) GDALGetDriverByName( "GTiff" );
828 7 : char **papszOpt = NULL;
829 : int nBX, nBY;
830 : int nBands;
831 :
832 7 : if( poDr == NULL )
833 0 : return CE_Failure;
834 :
835 7 : GDALRasterBand *poTBand = poDS->GetRasterBand(1);
836 7 : if( poTBand == NULL )
837 0 : return CE_Failure;
838 :
839 7 : if( nFlags & GMF_PER_DATASET )
840 7 : nBands = 1;
841 : else
842 0 : nBands = poDS->GetRasterCount();
843 :
844 :
845 7 : papszOpt = CSLSetNameValue( papszOpt, "COMPRESS", "DEFLATE" );
846 7 : papszOpt = CSLSetNameValue( papszOpt, "INTERLEAVE", "BAND" );
847 :
848 7 : poTBand->GetBlockSize( &nBX, &nBY );
849 :
850 : // try to create matching tile size if legal in TIFF.
851 7 : if( (nBX % 16) == 0 && (nBY % 16) == 0 )
852 : {
853 4 : papszOpt = CSLSetNameValue( papszOpt, "TILED", "YES" );
854 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKXSIZE",
855 4 : CPLString().Printf("%d",nBX) );
856 : papszOpt = CSLSetNameValue( papszOpt, "BLOCKYSIZE",
857 4 : CPLString().Printf("%d",nBY) );
858 : }
859 :
860 7 : osMskFilename.Printf( "%s.msk", poDS->GetDescription() );
861 : poMaskDS = poDr->Create( osMskFilename,
862 : poDS->GetRasterXSize(),
863 : poDS->GetRasterYSize(),
864 7 : nBands, GDT_Byte, papszOpt );
865 7 : CSLDestroy( papszOpt );
866 :
867 7 : if( poMaskDS == NULL ) // presumably error already issued.
868 0 : return CE_Failure;
869 :
870 7 : bOwnMaskDS = TRUE;
871 : }
872 :
873 : /* -------------------------------------------------------------------- */
874 : /* Save the mask flags for this band. */
875 : /* -------------------------------------------------------------------- */
876 7 : if( nBand > poMaskDS->GetRasterCount() )
877 : {
878 : CPLError( CE_Failure, CPLE_AppDefined,
879 : "Attempt to create a mask band for band %d of %s,\n"
880 : "but the .msk file has a PER_DATASET mask.",
881 0 : nBand, poDS->GetDescription() );
882 0 : return CE_Failure;
883 : }
884 :
885 : int iBand;
886 :
887 40 : for( iBand = 0; iBand < poDS->GetRasterCount(); iBand++ )
888 : {
889 : // we write only the info for this band, unless we are
890 : // using PER_DATASET in which case we write for all.
891 : if( nBand != iBand + 1 && !(nFlags | GMF_PER_DATASET) )
892 : continue;
893 :
894 : poMaskDS->SetMetadataItem(
895 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand+1 ),
896 13 : CPLString().Printf("%d", nFlags ) );
897 : }
898 :
899 7 : return CE_None;
900 : }
901 :
902 : /************************************************************************/
903 : /* GetMaskBand() */
904 : /************************************************************************/
905 :
906 17 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand( int nBand )
907 :
908 : {
909 17 : int nFlags = GetMaskFlags( nBand );
910 :
911 17 : if( nFlags == 0x8000 ) // secret code meaning we don't handle this band.
912 0 : return NULL;
913 :
914 17 : if( nFlags & GMF_PER_DATASET )
915 17 : return poMaskDS->GetRasterBand(1);
916 :
917 0 : if( nBand > 0 )
918 0 : return poMaskDS->GetRasterBand( nBand );
919 : else
920 0 : return NULL;
921 : }
922 :
923 : /************************************************************************/
924 : /* GetMaskFlags() */
925 : /************************************************************************/
926 :
927 34 : int GDALDefaultOverviews::GetMaskFlags( int nBand )
928 :
929 : {
930 : /* -------------------------------------------------------------------- */
931 : /* Fetch this band's metadata entry. They are of the form: */
932 : /* INTERNAL_MASK_FLAGS_n: flags */
933 : /* -------------------------------------------------------------------- */
934 34 : if( !HaveMaskFile() )
935 0 : return 0;
936 :
937 : const char *pszValue =
938 : poMaskDS->GetMetadataItem(
939 34 : CPLString().Printf( "INTERNAL_MASK_FLAGS_%d", MAX(nBand,1)) );
940 :
941 34 : if( pszValue == NULL )
942 0 : return 0x8000;
943 : else
944 34 : return atoi(pszValue);
945 : }
946 :
947 : /************************************************************************/
948 : /* HaveMaskFile() */
949 : /* */
950 : /* Check for a mask file if we haven't already done so. */
951 : /* Returns TRUE if we have one, otherwise FALSE. */
952 : /************************************************************************/
953 :
954 3159 : int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
955 : const char *pszBasename )
956 :
957 : {
958 : /* -------------------------------------------------------------------- */
959 : /* Have we already checked for masks? */
960 : /* -------------------------------------------------------------------- */
961 3159 : if( bCheckedForMask )
962 372 : return poMaskDS != NULL;
963 :
964 2787 : if( papszSiblingFiles == NULL )
965 2787 : papszSiblingFiles = papszInitSiblingFiles;
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Are we an overview? If so we need to find the corresponding */
969 : /* overview in the base files mask file (if there is one). */
970 : /* -------------------------------------------------------------------- */
971 2787 : if( poBaseDS != NULL && poBaseDS->oOvManager.HaveMaskFile() )
972 : {
973 3 : int iOver, nOverviewCount = 0;
974 3 : GDALRasterBand *poBaseBand = poBaseDS->GetRasterBand(1);
975 3 : GDALRasterBand *poBaseMask = NULL;
976 :
977 3 : if( poBaseBand != NULL )
978 3 : poBaseMask = poBaseBand->GetMaskBand();
979 3 : if( poBaseMask )
980 3 : nOverviewCount = poBaseMask->GetOverviewCount();
981 :
982 5 : for( iOver = 0; iOver < nOverviewCount; iOver++ )
983 : {
984 5 : GDALRasterBand *poOverBand = poBaseMask->GetOverview( iOver );
985 5 : if (poOverBand == NULL)
986 0 : continue;
987 :
988 5 : if( poOverBand->GetXSize() == poDS->GetRasterXSize()
989 : && poOverBand->GetYSize() == poDS->GetRasterYSize() )
990 : {
991 3 : poMaskDS = poOverBand->GetDataset();
992 3 : break;
993 : }
994 : }
995 :
996 3 : bCheckedForMask = TRUE;
997 3 : bOwnMaskDS = FALSE;
998 :
999 3 : CPLAssert( poMaskDS != poDS );
1000 :
1001 3 : return poMaskDS != NULL;
1002 : }
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Are we even initialized? If not, we apparently don't want */
1006 : /* to support overviews and masks. */
1007 : /* -------------------------------------------------------------------- */
1008 2784 : if( !IsInitialized() )
1009 247 : return FALSE;
1010 :
1011 : /* -------------------------------------------------------------------- */
1012 : /* Check for .msk file. */
1013 : /* -------------------------------------------------------------------- */
1014 2537 : CPLString osMskFilename;
1015 2537 : bCheckedForMask = TRUE;
1016 :
1017 2537 : if( pszBasename == NULL )
1018 2537 : pszBasename = poDS->GetDescription();
1019 :
1020 : // Don't bother checking for masks of masks.
1021 2537 : if( EQUAL(CPLGetExtension(pszBasename),"msk") )
1022 6 : return FALSE;
1023 :
1024 2531 : osMskFilename.Printf( "%s.msk", pszBasename );
1025 :
1026 : int bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
1027 2531 : papszSiblingFiles );
1028 :
1029 : #if !defined(WIN32)
1030 2531 : if( !bExists && !papszSiblingFiles )
1031 : {
1032 759 : osMskFilename.Printf( "%s.MSK", pszBasename );
1033 : bExists = CPLCheckForFile( (char *) osMskFilename.c_str(),
1034 759 : papszSiblingFiles );
1035 : }
1036 : #endif
1037 :
1038 2531 : if( !bExists )
1039 2517 : return FALSE;
1040 :
1041 : /* -------------------------------------------------------------------- */
1042 : /* Open the file. */
1043 : /* -------------------------------------------------------------------- */
1044 : GDALOpenInfo oOpenInfo(osMskFilename, poDS->GetAccess(),
1045 14 : papszInitSiblingFiles);
1046 14 : poMaskDS = (GDALDataset *) GDALOpenInternal( oOpenInfo, NULL );
1047 14 : CPLAssert( poMaskDS != poDS );
1048 :
1049 14 : if( poMaskDS == NULL )
1050 0 : return FALSE;
1051 :
1052 14 : bOwnMaskDS = TRUE;
1053 :
1054 14 : return TRUE;
1055 : }
|