LCOV - code coverage report
Current view: top level - frmts/mrf - Tif_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 70 101 69.3 %
Date: 2024-05-04 12:52:34 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2002-2012, California Institute of Technology.
       3             :  * All rights reserved.  Based on Government Sponsored Research under contracts
       4             :  * NAS7-1407 and/or NAS7-03001. Redistribution and use in source and binary
       5             :  * forms, with or without modification, are permitted provided that the
       6             :  * following conditions are met:
       7             :  *   1. Redistributions of source code must retain the above copyright notice,
       8             :  * this list of conditions and the following disclaimer.
       9             :  *   2. Redistributions in binary form must reproduce the above copyright
      10             :  * notice, this list of conditions and the following disclaimer in the
      11             :  * documentation and/or other materials provided with the distribution.
      12             :  *   3. Neither the name of the California Institute of Technology (Caltech),
      13             :  * its operating division the Jet Propulsion Laboratory (JPL), the National
      14             :  * Aeronautics and Space Administration (NASA), nor the names of its
      15             :  * contributors may be used to endorse or promote products derived from this
      16             :  * software without specific prior written permission.
      17             :  *
      18             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      19             :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      20             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      21             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE
      22             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      23             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      24             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      25             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      26             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      27             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      28             :  * POSSIBILITY OF SUCH DAMAGE.
      29             :  *
      30             :  * Copyright 2014-2021 Esri
      31             :  *
      32             :  * Licensed under the Apache License, Version 2.0 (the "License");
      33             :  * you may not use this file except in compliance with the License.
      34             :  * You may obtain a copy of the License at
      35             :  *
      36             :  * http://www.apache.org/licenses/LICENSE-2.0
      37             :  *
      38             :  * Unless required by applicable law or agreed to in writing, software
      39             :  * distributed under the License is distributed on an "AS IS" BASIS,
      40             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      41             :  * See the License for the specific language governing permissions and
      42             :  * limitations under the License.
      43             :  *
      44             :  * TIFF band
      45             :  * TIFF page compression and decompression functions
      46             :  *
      47             :  * Author:  Lucian Plesea, lplesea esri.com
      48             :  *
      49             :  */
      50             : 
      51             : #include "marfa.h"
      52             : NAMESPACE_MRF_START
      53             : 
      54             : // Returns a string in /vsimem/ + prefix + count that doesn't exist when this
      55             : // function gets called It is not thread safe, open the result as soon as
      56             : // possible
      57           8 : static CPLString uniq_memfname(const char *prefix)
      58             : {
      59             :     // Define MRF_LOCAL_TMP to use local files instead of RAM
      60             :     // #define MRF_LOCAL_TMP
      61             : #if defined(MRF_LOCAL_TMP)
      62             :     return CPLGenerateTempFilename(prefix);
      63             : #else
      64           8 :     CPLString fname;
      65             :     VSIStatBufL statb;
      66             :     static unsigned int cnt = 0;
      67           0 :     do
      68             :     {
      69           8 :         fname.Printf("/vsimem/%s_%08x", prefix, cnt++);
      70           8 :     } while (!VSIStatL(fname, &statb));
      71          16 :     return fname;
      72             : #endif
      73             : }
      74             : 
      75             : //
      76             : // Uses GDAL to create a temporary TIF file, using the band create options
      77             : // copies the content to the destination buffer then erases the temp TIF
      78             : //
      79           4 : static CPLErr CompressTIF(buf_mgr &dst, const buf_mgr &src, const ILImage &img,
      80             :                           char **papszOptions)
      81             : {
      82             :     CPLErr ret;
      83           4 :     GDALDriver *poTiffDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
      84             :     VSIStatBufL statb;
      85           8 :     CPLString fname = uniq_memfname("mrf_tif_write");
      86             : 
      87             :     GDALDataset *poTiff =
      88           4 :         poTiffDriver->Create(fname, img.pagesize.x, img.pagesize.y,
      89           4 :                              img.pagesize.c, img.dt, papszOptions);
      90             : 
      91           4 :     if (nullptr == poTiff)
      92           0 :         return CE_Failure;
      93             : 
      94             :     // Write directly to avoid double caching in GDAL
      95             :     // Unfortunately not possible for multiple bands
      96           4 :     if (img.pagesize.c == 1)
      97           4 :         ret = poTiff->GetRasterBand(1)->WriteBlock(0, 0, src.buffer);
      98             :     else
      99             :         ret =
     100           0 :             poTiff->RasterIO(GF_Write, 0, 0, img.pagesize.x, img.pagesize.y,
     101           0 :                              src.buffer, img.pagesize.x, img.pagesize.y, img.dt,
     102           0 :                              img.pagesize.c, nullptr, 0, 0, 0, nullptr);
     103           4 :     if (CE_None != ret)
     104           0 :         return ret;
     105           4 :     GDALClose(poTiff);
     106             : 
     107             :     // Check that we can read the file
     108           4 :     if (VSIStatL(fname, &statb))
     109             :     {
     110           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: TIFF, can't stat %s",
     111             :                  fname.c_str());
     112           0 :         return CE_Failure;
     113             :     }
     114             : 
     115           4 :     if (static_cast<size_t>(statb.st_size) > dst.size)
     116             :     {
     117           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     118             :                  "MRF: TIFF, Tiff generated is too large");
     119           0 :         return CE_Failure;
     120             :     }
     121             : 
     122           4 :     VSILFILE *pf = VSIFOpenL(fname, "rb");
     123           4 :     if (pf == nullptr)
     124             :     {
     125           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: TIFF, can't open %s",
     126             :                  fname.c_str());
     127           0 :         return CE_Failure;
     128             :     }
     129             : 
     130           4 :     VSIFReadL(dst.buffer, static_cast<size_t>(statb.st_size), 1, pf);
     131           4 :     dst.size = static_cast<size_t>(statb.st_size);
     132           4 :     VSIFCloseL(pf);
     133           4 :     VSIUnlink(fname);
     134             : 
     135           4 :     return CE_None;
     136             : }
     137             : 
     138             : // Read from a RAM Tiff. This is rather generic
     139             : // cppcheck-suppress constParameterReference
     140           4 : static CPLErr DecompressTIF(buf_mgr &dst, const buf_mgr &src,
     141             :                             const ILImage &img)
     142             : {
     143           8 :     CPLString fname = uniq_memfname("mrf_tif_read");
     144             :     VSILFILE *fp =
     145           4 :         VSIFileFromMemBuffer(fname, (GByte *)(src.buffer), src.size, false);
     146             :     // Comes back opened, but we can't use it
     147           4 :     if (nullptr == fp)
     148             :     {
     149           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     150             :                  "MRF: TIFF, can't open %s as a temp file", fname.c_str());
     151           0 :         return CE_Failure;
     152             :     }
     153           4 :     VSIFCloseL(fp);
     154             : 
     155             :     static const char *const apszAllowedDrivers[] = {"GTiff", nullptr};
     156           4 :     GDALDataset *poTiff = GDALDataset::FromHandle(GDALOpenEx(
     157             :         fname, GDAL_OF_RASTER, apszAllowedDrivers, nullptr, nullptr));
     158             : 
     159           4 :     if (poTiff == nullptr || 0 == poTiff->GetRasterCount())
     160             :     {
     161           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     162             :                  "MRF: Can't open page as a raster Tiff");
     163           0 :         GDALClose(poTiff);  // safe to call on nullptr
     164           0 :         VSIUnlink(fname);
     165           0 :         return CE_Failure;
     166             :     }
     167             : 
     168           4 :     const GDALDataType eGTiffDT = poTiff->GetRasterBand(1)->GetRasterDataType();
     169           4 :     const int nDTSize = GDALGetDataTypeSizeBytes(eGTiffDT);
     170           4 :     if (poTiff->GetRasterXSize() != img.pagesize.x ||
     171           4 :         poTiff->GetRasterYSize() != img.pagesize.y ||
     172          12 :         poTiff->GetRasterCount() != img.pagesize.c || img.dt != eGTiffDT ||
     173           4 :         static_cast<size_t>(img.pagesize.x) * img.pagesize.y * nDTSize *
     174           4 :                 img.pagesize.c !=
     175           4 :             dst.size)
     176             :     {
     177           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     178             :                  "MRF: TIFF tile inconsistent with MRF parameters");
     179           0 :         GDALClose(poTiff);
     180           0 :         VSIUnlink(fname);
     181           0 :         return CE_Failure;
     182             :     }
     183             : 
     184             :     CPLErr ret;
     185             :     // Bypass the GDAL caching if single band and block size is right
     186           4 :     int nBlockXSize = 0, nBlockYSize = 0;
     187           4 :     poTiff->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
     188             : 
     189             :     // Allow for TIFF blocks to be larger than MRF page size, but not in
     190             :     // huge proportion, to avoid later attempts at allocating a lot of memory
     191           4 :     if ((nBlockXSize > 4096 && nBlockXSize > img.pagesize.x) ||
     192           4 :         (nBlockYSize > 4096 && nBlockYSize > img.pagesize.y))
     193             :     {
     194           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     195             :                  "MRF: TIFF block size inconsistent with MRF parameters");
     196           0 :         GDALClose(poTiff);
     197           0 :         VSIUnlink(fname);
     198           0 :         return CE_Failure;
     199             :     }
     200             : 
     201           4 :     if (img.pagesize.c == 1 && nBlockXSize == img.pagesize.x &&
     202           4 :         nBlockYSize == img.pagesize.y)
     203           4 :         ret = poTiff->GetRasterBand(1)->ReadBlock(0, 0, dst.buffer);
     204             :     else
     205           0 :         ret = poTiff->RasterIO(
     206           0 :             GF_Read, 0, 0, img.pagesize.x, img.pagesize.y, dst.buffer,
     207           0 :             img.pagesize.x, img.pagesize.y, img.dt, img.pagesize.c, nullptr,
     208           0 :             static_cast<GSpacing>(nDTSize) * img.pagesize.c,
     209           0 :             static_cast<GSpacing>(nDTSize) * img.pagesize.c * img.pagesize.x,
     210             :             nDTSize, nullptr);
     211             : 
     212           4 :     GDALClose(poTiff);
     213           4 :     VSIUnlink(fname);
     214           4 :     return ret;
     215             : }
     216             : 
     217           4 : CPLErr TIF_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     218             : {
     219           4 :     return DecompressTIF(dst, src, img);
     220             : }
     221             : 
     222           4 : CPLErr TIF_Band::Compress(buf_mgr &dst, buf_mgr &src)
     223             : {
     224           4 :     return CompressTIF(dst, src, img, papszOptions);
     225             : }
     226             : 
     227          12 : TIF_Band::TIF_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     228          12 :     : MRFRasterBand(pDS, image, b, int(level))
     229             : {
     230             :     // Increase the page buffer by 1K in case Tiff expands data
     231          12 :     pDS->SetPBufferSize(image.pageSizeBytes + 1024);
     232             : 
     233             :     // Static create options for TIFF tiles
     234          12 :     papszOptions = CSLAddNameValue(nullptr, "COMPRESS", "DEFLATE");
     235          12 :     papszOptions = CSLAddNameValue(papszOptions, "TILED", "Yes");
     236          12 :     papszOptions = CSLAddNameValue(papszOptions, "BLOCKXSIZE",
     237          24 :                                    CPLOPrintf("%d", img.pagesize.x));
     238          12 :     papszOptions = CSLAddNameValue(papszOptions, "BLOCKYSIZE",
     239          24 :                                    CPLOPrintf("%d", img.pagesize.y));
     240          12 :     int q = img.quality / 10;
     241             :     // Move down so the default 85 quality maps to ZLEVEL 6.  This makes the max
     242             :     // ZLEVEL 8, which is fine.
     243          12 :     if (q > 2)
     244          12 :         q -= 2;
     245          12 :     papszOptions = CSLAddNameValue(papszOptions, "ZLEVEL", CPLOPrintf("%d", q));
     246          12 : }
     247             : 
     248          24 : TIF_Band::~TIF_Band()
     249             : {
     250          12 :     CSLDestroy(papszOptions);
     251          24 : }
     252             : 
     253             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14