LCOV - code coverage report
Current view: top level - frmts/mrf - Tif_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 68 99 68.7 %
Date: 2025-10-15 23:46:56 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             : 
      53             : #include "gdal_driver.h"
      54             : #include "gdal_drivermanager.h"
      55             : 
      56             : NAMESPACE_MRF_START
      57             : 
      58             : // Returns a unique filename
      59          10 : static CPLString uniq_memfname(const char *prefix)
      60             : {
      61             :     // Define MRF_LOCAL_TMP to use local files instead of RAM
      62             :     // #define MRF_LOCAL_TMP
      63             : #if defined(MRF_LOCAL_TMP)
      64             :     return CPLGenerateTempFilenameSafe(prefix);
      65             : #else
      66          10 :     return VSIMemGenerateHiddenFilename(prefix);
      67             : #endif
      68             : }
      69             : 
      70             : //
      71             : // Uses GDAL to create a temporary TIF file, using the band create options
      72             : // copies the content to the destination buffer then erases the temp TIF
      73             : //
      74           5 : static CPLErr CompressTIF(buf_mgr &dst, const buf_mgr &src, const ILImage &img,
      75             :                           char **papszOptions)
      76             : {
      77             :     CPLErr ret;
      78           5 :     GDALDriver *poTiffDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
      79             :     VSIStatBufL statb;
      80          10 :     CPLString fname = uniq_memfname("mrf_tif_write");
      81             : 
      82             :     GDALDataset *poTiff =
      83           5 :         poTiffDriver->Create(fname, img.pagesize.x, img.pagesize.y,
      84           5 :                              img.pagesize.c, img.dt, papszOptions);
      85             : 
      86           5 :     if (nullptr == poTiff)
      87           0 :         return CE_Failure;
      88             : 
      89             :     // Write directly to avoid double caching in GDAL
      90             :     // Unfortunately not possible for multiple bands
      91           5 :     if (img.pagesize.c == 1)
      92           5 :         ret = poTiff->GetRasterBand(1)->WriteBlock(0, 0, src.buffer);
      93             :     else
      94             :         ret =
      95           0 :             poTiff->RasterIO(GF_Write, 0, 0, img.pagesize.x, img.pagesize.y,
      96           0 :                              src.buffer, img.pagesize.x, img.pagesize.y, img.dt,
      97           0 :                              img.pagesize.c, nullptr, 0, 0, 0, nullptr);
      98           5 :     if (CE_None != ret)
      99           0 :         return ret;
     100           5 :     GDALClose(poTiff);
     101             : 
     102             :     // Check that we can read the file
     103           5 :     if (VSIStatL(fname, &statb))
     104             :     {
     105           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: TIFF, can't stat %s",
     106             :                  fname.c_str());
     107           0 :         return CE_Failure;
     108             :     }
     109             : 
     110           5 :     if (static_cast<size_t>(statb.st_size) > dst.size)
     111             :     {
     112           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     113             :                  "MRF: TIFF, Tiff generated is too large");
     114           0 :         return CE_Failure;
     115             :     }
     116             : 
     117           5 :     VSILFILE *pf = VSIFOpenL(fname, "rb");
     118           5 :     if (pf == nullptr)
     119             :     {
     120           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: TIFF, can't open %s",
     121             :                  fname.c_str());
     122           0 :         return CE_Failure;
     123             :     }
     124             : 
     125           5 :     VSIFReadL(dst.buffer, static_cast<size_t>(statb.st_size), 1, pf);
     126           5 :     dst.size = static_cast<size_t>(statb.st_size);
     127           5 :     VSIFCloseL(pf);
     128           5 :     VSIUnlink(fname);
     129             : 
     130           5 :     return CE_None;
     131             : }
     132             : 
     133             : // Read from a RAM Tiff. This is rather generic
     134             : // cppcheck-suppress constParameterReference
     135           5 : static CPLErr DecompressTIF(buf_mgr &dst, const buf_mgr &src,
     136             :                             const ILImage &img)
     137             : {
     138          10 :     CPLString fname = uniq_memfname("mrf_tif_read");
     139             :     VSILFILE *fp =
     140           5 :         VSIFileFromMemBuffer(fname, (GByte *)(src.buffer), src.size, false);
     141             :     // Comes back opened, but we can't use it
     142           5 :     if (nullptr == fp)
     143             :     {
     144           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     145             :                  "MRF: TIFF, can't open %s as a temp file", fname.c_str());
     146           0 :         return CE_Failure;
     147             :     }
     148           5 :     VSIFCloseL(fp);
     149             : 
     150             :     static const char *const apszAllowedDrivers[] = {"GTiff", nullptr};
     151           5 :     GDALDataset *poTiff = GDALDataset::FromHandle(GDALOpenEx(
     152             :         fname, GDAL_OF_RASTER, apszAllowedDrivers, nullptr, nullptr));
     153             : 
     154           5 :     if (poTiff == nullptr || 0 == poTiff->GetRasterCount())
     155             :     {
     156           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     157             :                  "MRF: Can't open page as a raster Tiff");
     158           0 :         GDALClose(poTiff);  // safe to call on nullptr
     159           0 :         VSIUnlink(fname);
     160           0 :         return CE_Failure;
     161             :     }
     162             : 
     163           5 :     const GDALDataType eGTiffDT = poTiff->GetRasterBand(1)->GetRasterDataType();
     164           5 :     const int nDTSize = GDALGetDataTypeSizeBytes(eGTiffDT);
     165           5 :     if (poTiff->GetRasterXSize() != img.pagesize.x ||
     166           5 :         poTiff->GetRasterYSize() != img.pagesize.y ||
     167          15 :         poTiff->GetRasterCount() != img.pagesize.c || img.dt != eGTiffDT ||
     168           5 :         static_cast<size_t>(img.pagesize.x) * img.pagesize.y * nDTSize *
     169           5 :                 img.pagesize.c !=
     170           5 :             dst.size)
     171             :     {
     172           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     173             :                  "MRF: TIFF tile inconsistent with MRF parameters");
     174           0 :         GDALClose(poTiff);
     175           0 :         VSIUnlink(fname);
     176           0 :         return CE_Failure;
     177             :     }
     178             : 
     179             :     CPLErr ret;
     180             :     // Bypass the GDAL caching if single band and block size is right
     181           5 :     int nBlockXSize = 0, nBlockYSize = 0;
     182           5 :     poTiff->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
     183             : 
     184             :     // Allow for TIFF blocks to be larger than MRF page size, but not in
     185             :     // huge proportion, to avoid later attempts at allocating a lot of memory
     186           5 :     if ((nBlockXSize > 4096 && nBlockXSize > img.pagesize.x) ||
     187           5 :         (nBlockYSize > 4096 && nBlockYSize > img.pagesize.y))
     188             :     {
     189           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     190             :                  "MRF: TIFF block size inconsistent with MRF parameters");
     191           0 :         GDALClose(poTiff);
     192           0 :         VSIUnlink(fname);
     193           0 :         return CE_Failure;
     194             :     }
     195             : 
     196           5 :     if (img.pagesize.c == 1 && nBlockXSize == img.pagesize.x &&
     197           5 :         nBlockYSize == img.pagesize.y)
     198           5 :         ret = poTiff->GetRasterBand(1)->ReadBlock(0, 0, dst.buffer);
     199             :     else
     200           0 :         ret = poTiff->RasterIO(
     201           0 :             GF_Read, 0, 0, img.pagesize.x, img.pagesize.y, dst.buffer,
     202           0 :             img.pagesize.x, img.pagesize.y, img.dt, img.pagesize.c, nullptr,
     203           0 :             static_cast<GSpacing>(nDTSize) * img.pagesize.c,
     204           0 :             static_cast<GSpacing>(nDTSize) * img.pagesize.c * img.pagesize.x,
     205             :             nDTSize, nullptr);
     206             : 
     207           5 :     GDALClose(poTiff);
     208           5 :     VSIUnlink(fname);
     209           5 :     return ret;
     210             : }
     211             : 
     212           5 : CPLErr TIF_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     213             : {
     214           5 :     return DecompressTIF(dst, src, img);
     215             : }
     216             : 
     217           5 : CPLErr TIF_Band::Compress(buf_mgr &dst, buf_mgr &src)
     218             : {
     219           5 :     return CompressTIF(dst, src, img, papszOptions);
     220             : }
     221             : 
     222          15 : TIF_Band::TIF_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     223          15 :     : MRFRasterBand(pDS, image, b, int(level))
     224             : {
     225             :     // Increase the page buffer by 1K in case Tiff expands data
     226          15 :     pDS->SetPBufferSize(image.pageSizeBytes + 1024);
     227             : 
     228             :     // Static create options for TIFF tiles
     229          15 :     papszOptions = CSLAddNameValue(nullptr, "COMPRESS", "DEFLATE");
     230          15 :     papszOptions = CSLAddNameValue(papszOptions, "TILED", "Yes");
     231          15 :     papszOptions = CSLAddNameValue(papszOptions, "BLOCKXSIZE",
     232          30 :                                    CPLOPrintf("%d", img.pagesize.x));
     233          15 :     papszOptions = CSLAddNameValue(papszOptions, "BLOCKYSIZE",
     234          30 :                                    CPLOPrintf("%d", img.pagesize.y));
     235          15 :     int q = img.quality / 10;
     236             :     // Move down so the default 85 quality maps to ZLEVEL 6.  This makes the max
     237             :     // ZLEVEL 8, which is fine.
     238          15 :     if (q > 2)
     239          15 :         q -= 2;
     240          15 :     if (q == 0)  // TIF does not accept ZLEVEL of zero
     241           0 :         q = 6;
     242          15 :     papszOptions = CSLAddNameValue(papszOptions, "ZLEVEL", CPLOPrintf("%d", q));
     243          15 : }
     244             : 
     245          30 : TIF_Band::~TIF_Band()
     246             : {
     247          15 :     CSLDestroy(papszOptions);
     248          30 : }
     249             : 
     250             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14