LCOV - code coverage report
Current view: top level - frmts/mrf - JPNG_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 104 0.0 %
Date: 2024-11-21 22:18:42 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016-2021 Esri
       3             :  *
       4             :  * Author: Lucian Plesea
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  * http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : /*
      20             :  * JPNG band, uses JPEG or PNG encoding, depending on the input data
      21             :  */
      22             : 
      23             : #include "marfa.h"
      24             : 
      25             : CPL_C_START
      26             : #include <jpeglib.h>
      27             : #include <png.h>
      28             : CPL_C_END
      29             : 
      30             : NAMESPACE_MRF_START
      31             : 
      32             : // Test that all alpha values are equal to N
      33           0 : template <int N> static bool AllAlpha(const buf_mgr &src, const ILImage &img)
      34             : {
      35           0 :     int stride = img.pagesize.c;
      36           0 :     char *s = src.buffer + img.pagesize.c - 1;
      37           0 :     char *stop = src.buffer + img.pageSizeBytes;
      38           0 :     while (s < stop && N == static_cast<unsigned char>(*s))
      39           0 :         s += stride;
      40           0 :     return s >= stop;
      41             : }
      42             : 
      43             : // Strip the alpha from an RGBA buffer, safe to use in place
      44           0 : static void RGBA2RGB(const char *start, const char *stop, char *target)
      45             : {
      46           0 :     while (start < stop)
      47             :     {
      48           0 :         *target++ = *start++;
      49           0 :         *target++ = *start++;
      50           0 :         *target++ = *start++;
      51           0 :         start++;  // Skip the alpha
      52             :     }
      53           0 : }
      54             : 
      55             : // Add opaque alpha to an RGB buffer, safe to use in place
      56             : // works from stop to start, the last parameter is the end of the source region
      57           0 : static void RGB2RGBA(const char *start, char *stop, const char *source_end)
      58             : {
      59           0 :     while (start < stop)
      60             :     {
      61           0 :         *--stop = ~static_cast<char>(0);
      62           0 :         *--stop = *--source_end;
      63           0 :         *--stop = *--source_end;
      64           0 :         *--stop = *--source_end;
      65             :     }
      66           0 : }
      67             : 
      68             : // Strip the alpha from an Luma Alpha buffer, safe to use in place
      69           0 : static void LA2L(const char *start, const char *stop, char *target)
      70             : {
      71           0 :     while (start < stop)
      72             :     {
      73           0 :         *target++ = *start++;
      74           0 :         start++;  // Skip the alpha
      75             :     }
      76           0 : }
      77             : 
      78             : // Add opaque alpha to a Luma buffer, safe to use in place
      79             : // works from stop to start, the last parameter is the end of the source region
      80           0 : static void L2LA(const char *start, char *stop, const char *source_end)
      81             : {
      82           0 :     while (start < stop)
      83             :     {
      84           0 :         *--stop = ~static_cast<char>(0);
      85           0 :         *--stop = *--source_end;
      86             :     }
      87           0 : }
      88             : 
      89           0 : static CPLErr initBuffer(buf_mgr &b)
      90             : {
      91           0 :     b.buffer = (char *)(CPLMalloc(b.size));
      92           0 :     if (b.buffer != nullptr)
      93           0 :         return CE_None;
      94           0 :     CPLError(CE_Failure, CPLE_OutOfMemory, "Allocating temporary JPNG buffer");
      95           0 :     return CE_Failure;
      96             : }
      97             : 
      98           0 : CPLErr JPNG_Band::Decompress(buf_mgr &dst, buf_mgr &src)
      99             : {
     100             :     const static GUInt32 PNG_SIG = 0x474e5089;  // PNG 4CC code
     101             : 
     102           0 :     CPLErr retval = CE_None;
     103           0 :     ILImage image(img);
     104             :     GUInt32 signature;
     105           0 :     memcpy(&signature, src.buffer, sizeof(signature));
     106             : 
     107             :     // test against an LSB signature
     108           0 :     if (JPEG_Codec::IsJPEG(src))
     109             :     {
     110           0 :         image.pagesize.c -= 1;
     111           0 :         JPEG_Codec codec(image);
     112             : 
     113             :         // JPEG decoder expects the destination size to be accurate
     114           0 :         buf_mgr temp = dst;  // dst still owns the storage
     115           0 :         temp.size = (image.pagesize.c == 3) ? dst.size / 4 * 3 : dst.size / 2;
     116             : 
     117           0 :         retval = codec.DecompressJPEG(temp, src);
     118           0 :         if (CE_None == retval)
     119             :         {  // add opaque alpha, in place
     120           0 :             if (image.pagesize.c == 3)
     121           0 :                 RGB2RGBA(dst.buffer, dst.buffer + dst.size,
     122           0 :                          temp.buffer + temp.size);
     123             :             else
     124           0 :                 L2LA(dst.buffer, dst.buffer + dst.size,
     125           0 :                      temp.buffer + temp.size);
     126             :         }
     127             :     }
     128           0 :     else if (PNG_SIG == CPL_LSBWORD32(signature))
     129             :     {  // Should be PNG, it reads as 4 bands
     130           0 :         PNG_Codec codec(image);
     131           0 :         return codec.DecompressPNG(dst, src);
     132             :     }
     133             :     else
     134             :     {
     135           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Not a JPEG or PNG tile");
     136           0 :         retval = CE_Failure;
     137             :     }
     138             : 
     139           0 :     return retval;
     140             : }
     141             : 
     142             : // The PNG internal palette is set on first band write
     143           0 : CPLErr JPNG_Band::Compress(buf_mgr &dst, buf_mgr &src)
     144             : {
     145           0 :     ILImage image(img);
     146           0 :     buf_mgr temp = {nullptr, static_cast<size_t>(img.pageSizeBytes)};
     147           0 :     CPLErr retval = initBuffer(temp);
     148           0 :     if (retval != CE_None)
     149           0 :         return retval;
     150             : 
     151           0 :     if (AllAlpha<255>(src, image))
     152             :     {  // If all pixels are opaque, compress as JPEG
     153           0 :         if (image.pagesize.c == 4)
     154           0 :             RGBA2RGB(src.buffer, src.buffer + src.size, temp.buffer);
     155             :         else
     156           0 :             LA2L(src.buffer, src.buffer + src.size, temp.buffer);
     157             : 
     158           0 :         image.pagesize.c -= 1;  // RGB or Grayscale only for JPEG
     159           0 :         JPEG_Codec codec(image);
     160           0 :         codec.rgb = rgb;
     161           0 :         codec.optimize = optimize;
     162           0 :         codec.sameres = sameres;
     163           0 :         codec.JFIF = JFIF;
     164           0 :         retval = codec.CompressJPEG(dst, temp);
     165             :     }
     166           0 :     else if (!AllAlpha<0>(src, image))
     167             :     {
     168           0 :         PNG_Codec codec(image);
     169           0 :         codec.deflate_flags = deflate_flags;
     170           0 :         retval = codec.CompressPNG(dst, src);
     171             :     }
     172             :     else
     173           0 :         dst.size = 0;  // Don't store fully transparent pages
     174             : 
     175           0 :     CPLFree(temp.buffer);
     176           0 :     return retval;
     177             : }
     178             : 
     179             : /**
     180             :  * \brief For PPNG, builds the data structures needed to write the palette
     181             :  * The presence of the PNGColors and PNGAlpha is used as a flag for PPNG only
     182             :  */
     183             : 
     184           0 : JPNG_Band::JPNG_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     185             :     : MRFRasterBand(pDS, image, b, level), rgb(FALSE), sameres(FALSE),
     186           0 :       optimize(false), JFIF(false)
     187             : {  // Check error conditions
     188           0 :     if (image.dt != GDT_Byte)
     189             :     {
     190           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     191             :                  "Data type not supported by MRF JPNG");
     192           0 :         return;
     193             :     }
     194           0 :     if (image.order != IL_Interleaved ||
     195           0 :         (image.pagesize.c != 4 && image.pagesize.c != 2))
     196             :     {
     197           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     198             :                  "MRF JPNG can only handle 2 or 4 interleaved bands");
     199           0 :         return;
     200             :     }
     201             : 
     202           0 :     if (img.pagesize.c == 4)
     203             :     {  // RGBA can have storage flavors
     204           0 :         CPLString const &pm = pDS->GetPhotometricInterpretation();
     205           0 :         if (pm == "RGB" || pm == "MULTISPECTRAL")
     206             :         {  // Explicit RGB or MS
     207           0 :             rgb = TRUE;
     208           0 :             sameres = TRUE;
     209             :         }
     210           0 :         if (pm == "YCC")
     211           0 :             sameres = TRUE;
     212             :     }
     213             : 
     214           0 :     optimize = GetOptlist().FetchBoolean("OPTIMIZE", FALSE) != FALSE;
     215           0 :     JFIF = GetOptlist().FetchBoolean("JFIF", FALSE) != FALSE;
     216             : 
     217             :     // PNGs and JPGs can be larger than the source, especially for
     218             :     // small page size.
     219           0 :     poMRFDS->SetPBufferSize(image.pageSizeBytes + 100);
     220             : }
     221             : 
     222           0 : JPNG_Band::~JPNG_Band()
     223             : {
     224           0 : }
     225             : 
     226             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14