LCOV - code coverage report
Current view: top level - gcore - gdalorienteddataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 121 142 85.2 %
Date: 2024-05-03 15:49:35 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Dataset that modifies the orientation of an underlying dataset
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2022, Even Rouault, <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "gdalorienteddataset.h"
      30             : 
      31             : #include "gdal_utils.h"
      32             : 
      33             : #include <algorithm>
      34             : 
      35             : //! @cond Doxygen_Suppress
      36             : 
      37             : /************************************************************************/
      38             : /*                      GDALOrientedRasterBand                          */
      39             : /************************************************************************/
      40             : 
      41             : class GDALOrientedRasterBand : public GDALRasterBand
      42             : {
      43             :     GDALRasterBand *m_poSrcBand;
      44             :     std::unique_ptr<GDALDataset> m_poCacheDS{};
      45             : 
      46             :     GDALOrientedRasterBand(const GDALOrientedRasterBand &) = delete;
      47             :     GDALOrientedRasterBand &operator=(const GDALOrientedRasterBand &) = delete;
      48             : 
      49             :   protected:
      50             :     CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) override;
      51             : 
      52             :   public:
      53             :     GDALOrientedRasterBand(GDALOrientedDataset *poDSIn, int nBandIn);
      54             : 
      55           7 :     GDALColorInterp GetColorInterpretation() override
      56             :     {
      57           7 :         return m_poSrcBand->GetColorInterpretation();
      58             :     }
      59             : };
      60             : 
      61             : /************************************************************************/
      62             : /*                      GDALOrientedRasterBand()                        */
      63             : /************************************************************************/
      64             : 
      65          14 : GDALOrientedRasterBand::GDALOrientedRasterBand(GDALOrientedDataset *poDSIn,
      66          14 :                                                int nBandIn)
      67          14 :     : m_poSrcBand(poDSIn->m_poSrcDS->GetRasterBand(nBandIn))
      68             : {
      69          14 :     poDS = poDSIn;
      70          14 :     eDataType = m_poSrcBand->GetRasterDataType();
      71          14 :     if (poDSIn->m_eOrigin == GDALOrientedDataset::Origin::TOP_LEFT)
      72             :     {
      73           0 :         m_poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
      74             :     }
      75             :     else
      76             :     {
      77          14 :         nBlockXSize = poDS->GetRasterXSize();
      78          14 :         nBlockYSize = 1;
      79             :     }
      80          14 : }
      81             : 
      82             : /************************************************************************/
      83             : /*                  FlipLineHorizontally()                              */
      84             : /************************************************************************/
      85             : 
      86          40 : static void FlipLineHorizontally(void *pLine, int nDTSize, int nBlockXSize)
      87             : {
      88          40 :     switch (nDTSize)
      89             :     {
      90          40 :         case 1:
      91             :         {
      92          40 :             GByte *pabyLine = static_cast<GByte *>(pLine);
      93          80 :             for (int iX = 0; iX < nBlockXSize / 2; ++iX)
      94             :             {
      95          40 :                 std::swap(pabyLine[iX], pabyLine[nBlockXSize - 1 - iX]);
      96             :             }
      97          40 :             break;
      98             :         }
      99             : 
     100           0 :         default:
     101             :         {
     102           0 :             GByte *pabyLine = static_cast<GByte *>(pLine);
     103           0 :             std::vector<GByte> abyTemp(nDTSize);
     104           0 :             for (int iX = 0; iX < nBlockXSize / 2; ++iX)
     105             :             {
     106           0 :                 memcpy(&abyTemp[0], pabyLine + iX * nDTSize, nDTSize);
     107           0 :                 memcpy(pabyLine + iX * nDTSize,
     108           0 :                        pabyLine + (nBlockXSize - 1 - iX) * nDTSize, nDTSize);
     109           0 :                 memcpy(pabyLine + (nBlockXSize - 1 - iX) * nDTSize, &abyTemp[0],
     110             :                        nDTSize);
     111             :             }
     112           0 :             break;
     113             :         }
     114             :     }
     115          40 : }
     116             : 
     117             : /************************************************************************/
     118             : /*                            IReadBlock()                              */
     119             : /************************************************************************/
     120             : 
     121          70 : CPLErr GDALOrientedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
     122             :                                           void *pImage)
     123             : {
     124          70 :     auto l_poDS = cpl::down_cast<GDALOrientedDataset *>(poDS);
     125             : 
     126          70 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     127          70 :     if (m_poCacheDS == nullptr &&
     128          92 :         l_poDS->m_eOrigin != GDALOrientedDataset::Origin::TOP_LEFT &&
     129          22 :         l_poDS->m_eOrigin != GDALOrientedDataset::Origin::TOP_RIGHT)
     130             :     {
     131          12 :         auto poGTiffDrv = GetGDALDriverManager()->GetDriverByName("GTiff");
     132          12 :         CPLStringList aosOptions;
     133          12 :         aosOptions.AddString("-f");
     134          12 :         aosOptions.AddString(poGTiffDrv ? "GTiff" : "MEM");
     135          12 :         aosOptions.AddString("-b");
     136          12 :         aosOptions.AddString(CPLSPrintf("%d", nBand));
     137          12 :         if (poGTiffDrv)
     138             :         {
     139          12 :             aosOptions.AddString("-co");
     140          12 :             aosOptions.AddString("TILED=YES");
     141             :         }
     142          12 :         std::string osTmpName;
     143          12 :         if (poGTiffDrv)
     144             :         {
     145          12 :             if (static_cast<GIntBig>(nRasterXSize) * nRasterYSize * nDTSize >
     146             :                 10 * 1024 * 1024)
     147             :             {
     148           0 :                 osTmpName = CPLGenerateTempFilename(nullptr);
     149             :             }
     150             :             else
     151             :             {
     152             :                 osTmpName =
     153          12 :                     CPLSPrintf("/vsimem/_gdalorienteddataset/%p.tif", this);
     154             :             }
     155             :         }
     156             :         GDALTranslateOptions *psOptions =
     157          12 :             GDALTranslateOptionsNew(aosOptions.List(), nullptr);
     158          12 :         if (psOptions == nullptr)
     159           0 :             return CE_Failure;
     160          12 :         GDALDatasetH hOutDS = GDALTranslate(
     161             :             osTmpName.c_str(), GDALDataset::ToHandle(l_poDS->m_poSrcDS),
     162             :             psOptions, nullptr);
     163          12 :         GDALTranslateOptionsFree(psOptions);
     164          12 :         if (hOutDS == nullptr)
     165           0 :             return CE_Failure;
     166          12 :         m_poCacheDS.reset(GDALDataset::FromHandle(hOutDS));
     167          12 :         m_poCacheDS->MarkSuppressOnClose();
     168             :     }
     169             : 
     170          70 :     CPLErr eErr = CE_None;
     171          70 :     switch (l_poDS->m_eOrigin)
     172             :     {
     173           0 :         case GDALOrientedDataset::Origin::TOP_LEFT:
     174             :         {
     175           0 :             eErr = m_poSrcBand->ReadBlock(nBlockXOff, nBlockYOff, pImage);
     176           0 :             break;
     177             :         }
     178             : 
     179          10 :         case GDALOrientedDataset::Origin::TOP_RIGHT:
     180             :         {
     181          10 :             CPLAssert(nBlockXSize == nRasterXSize);
     182          10 :             CPLAssert(nBlockYSize == 1);
     183          10 :             if (m_poSrcBand->RasterIO(GF_Read, 0, nBlockYOff, nRasterXSize, 1,
     184             :                                       pImage, nRasterXSize, 1, eDataType, 0, 0,
     185          10 :                                       nullptr) != CE_None)
     186             :             {
     187           0 :                 return CE_Failure;
     188             :             }
     189          10 :             FlipLineHorizontally(pImage, nDTSize, nBlockXSize);
     190          10 :             break;
     191             :         }
     192             : 
     193          20 :         case GDALOrientedDataset::Origin::BOT_RIGHT:
     194             :         case GDALOrientedDataset::Origin::BOT_LEFT:
     195             :         {
     196          20 :             CPLAssert(nBlockXSize == nRasterXSize);
     197          20 :             CPLAssert(nBlockYSize == 1);
     198          20 :             if (m_poCacheDS->GetRasterBand(1)->RasterIO(
     199          20 :                     GF_Read, 0, nRasterYSize - 1 - nBlockYOff, nRasterXSize, 1,
     200             :                     pImage, nRasterXSize, 1, eDataType, 0, 0,
     201          20 :                     nullptr) != CE_None)
     202             :             {
     203           0 :                 return CE_Failure;
     204             :             }
     205          20 :             if (l_poDS->m_eOrigin == GDALOrientedDataset::Origin::BOT_RIGHT)
     206          10 :                 FlipLineHorizontally(pImage, nDTSize, nBlockXSize);
     207          20 :             break;
     208             :         }
     209             : 
     210          20 :         case GDALOrientedDataset::Origin::LEFT_TOP:
     211             :         case GDALOrientedDataset::Origin::RIGHT_TOP:
     212             :         {
     213          20 :             CPLAssert(nBlockXSize == nRasterXSize);
     214          20 :             CPLAssert(nBlockYSize == 1);
     215          20 :             if (m_poCacheDS->GetRasterBand(1)->RasterIO(
     216             :                     GF_Read, nBlockYOff, 0, 1, nRasterXSize, pImage, 1,
     217          20 :                     nRasterXSize, eDataType, 0, 0, nullptr) != CE_None)
     218             :             {
     219           0 :                 return CE_Failure;
     220             :             }
     221          20 :             if (l_poDS->m_eOrigin == GDALOrientedDataset::Origin::RIGHT_TOP)
     222          10 :                 FlipLineHorizontally(pImage, nDTSize, nBlockXSize);
     223          20 :             break;
     224             :         }
     225             : 
     226          20 :         case GDALOrientedDataset::Origin::RIGHT_BOT:
     227             :         case GDALOrientedDataset::Origin::LEFT_BOT:
     228             :         {
     229          20 :             CPLAssert(nBlockXSize == nRasterXSize);
     230          20 :             CPLAssert(nBlockYSize == 1);
     231          20 :             if (m_poCacheDS->GetRasterBand(1)->RasterIO(
     232          20 :                     GF_Read, nRasterYSize - 1 - nBlockYOff, 0, 1, nRasterXSize,
     233             :                     pImage, 1, nRasterXSize, eDataType, 0, 0,
     234          20 :                     nullptr) != CE_None)
     235             :             {
     236           0 :                 return CE_Failure;
     237             :             }
     238          20 :             if (l_poDS->m_eOrigin == GDALOrientedDataset::Origin::RIGHT_BOT)
     239          10 :                 FlipLineHorizontally(pImage, nDTSize, nBlockXSize);
     240          20 :             break;
     241             :         }
     242             :     }
     243             : 
     244          70 :     return eErr;
     245             : }
     246             : 
     247             : /************************************************************************/
     248             : /*                         GDALOrientedDataset()                        */
     249             : /************************************************************************/
     250             : 
     251          14 : GDALOrientedDataset::GDALOrientedDataset(GDALDataset *poSrcDataset,
     252          14 :                                          Origin eOrigin)
     253          14 :     : m_poSrcDS(poSrcDataset), m_eOrigin(eOrigin)
     254             : {
     255          14 :     switch (eOrigin)
     256             :     {
     257           6 :         case GDALOrientedDataset::Origin::TOP_LEFT:
     258             :         case GDALOrientedDataset::Origin::TOP_RIGHT:
     259             :         case GDALOrientedDataset::Origin::BOT_RIGHT:
     260             :         case GDALOrientedDataset::Origin::BOT_LEFT:
     261             :         {
     262           6 :             nRasterXSize = poSrcDataset->GetRasterXSize();
     263           6 :             nRasterYSize = poSrcDataset->GetRasterYSize();
     264           6 :             break;
     265             :         }
     266             : 
     267           8 :         case GDALOrientedDataset::Origin::LEFT_TOP:
     268             :         case GDALOrientedDataset::Origin::RIGHT_TOP:
     269             :         case GDALOrientedDataset::Origin::RIGHT_BOT:
     270             :         case GDALOrientedDataset::Origin::LEFT_BOT:
     271             :         {
     272             :             // Permute (x, y)
     273           8 :             nRasterXSize = poSrcDataset->GetRasterYSize();
     274           8 :             nRasterYSize = poSrcDataset->GetRasterXSize();
     275           8 :             break;
     276             :         }
     277             :     }
     278             : 
     279          14 :     const int nSrcBands = poSrcDataset->GetRasterCount();
     280          28 :     for (int i = 1; i <= nSrcBands; ++i)
     281             :     {
     282          14 :         SetBand(i, new GDALOrientedRasterBand(this, i));
     283             :     }
     284          14 : }
     285             : 
     286             : /************************************************************************/
     287             : /*                         GDALOrientedDataset()                        */
     288             : /************************************************************************/
     289             : 
     290          14 : GDALOrientedDataset::GDALOrientedDataset(
     291          14 :     std::unique_ptr<GDALDataset> &&poSrcDataset, Origin eOrigin)
     292          14 :     : GDALOrientedDataset(poSrcDataset.get(), eOrigin)
     293             : {
     294             :     // cppcheck-suppress useInitializationList
     295          14 :     m_poSrcDSHolder = std::move(poSrcDataset);
     296          14 : }
     297             : 
     298             : /************************************************************************/
     299             : /*                           GetMetadata()                              */
     300             : /************************************************************************/
     301             : 
     302          28 : char **GDALOrientedDataset::GetMetadata(const char *pszDomain)
     303             : {
     304          28 :     if (pszDomain == nullptr || pszDomain[0] == '\0')
     305             :     {
     306          14 :         if (m_aosSrcMD.empty())
     307             :         {
     308           7 :             m_aosSrcMD.Assign(CSLDuplicate(m_poSrcDS->GetMetadata(pszDomain)));
     309             :             const char *pszOrientation =
     310           7 :                 m_aosSrcMD.FetchNameValue("EXIF_Orientation");
     311           7 :             if (pszOrientation)
     312             :             {
     313             :                 m_aosSrcMD.SetNameValue("original_EXIF_Orientation",
     314           7 :                                         pszOrientation);
     315           7 :                 m_aosSrcMD.SetNameValue("EXIF_Orientation", nullptr);
     316             :             }
     317             :         }
     318          14 :         return m_aosSrcMD.List();
     319             :     }
     320          14 :     if (EQUAL(pszDomain, "EXIF"))
     321             :     {
     322          14 :         if (m_aosSrcMD_EXIF.empty())
     323             :         {
     324             :             m_aosSrcMD_EXIF.Assign(
     325           7 :                 CSLDuplicate(m_poSrcDS->GetMetadata(pszDomain)));
     326             :             const char *pszOrientation =
     327           7 :                 m_aosSrcMD_EXIF.FetchNameValue("EXIF_Orientation");
     328           7 :             if (pszOrientation)
     329             :             {
     330             :                 m_aosSrcMD_EXIF.SetNameValue("original_EXIF_Orientation",
     331           7 :                                              pszOrientation);
     332           7 :                 m_aosSrcMD_EXIF.SetNameValue("EXIF_Orientation", nullptr);
     333             :             }
     334             :         }
     335          14 :         return m_aosSrcMD_EXIF.List();
     336             :     }
     337           0 :     return m_poSrcDS->GetMetadata(pszDomain);
     338             : }
     339             : 
     340             : /************************************************************************/
     341             : /*                       GetMetadataItem()                              */
     342             : /************************************************************************/
     343             : 
     344          28 : const char *GDALOrientedDataset::GetMetadataItem(const char *pszName,
     345             :                                                  const char *pszDomain)
     346             : {
     347          28 :     return CSLFetchNameValue(GetMetadata(pszDomain), pszName);
     348             : }
     349             : 
     350             : //! @endcond

Generated by: LCOV version 1.14