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

Generated by: LCOV version 1.14