LCOV - code coverage report
Current view: top level - frmts/mrf - JPEG_band.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 225 332 67.8 %
Date: 2024-05-04 12:52:34 Functions: 23 32 71.9 %

          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.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are met:
       8             :  *   1. Redistributions of source code must retain the above copyright notice,
       9             :  * this list of conditions and the following disclaimer.
      10             :  *   2. Redistributions in binary form must reproduce the above copyright
      11             :  * notice, this list of conditions and the following disclaimer in the
      12             :  * documentation and/or other materials provided with the distribution.
      13             :  *   3. Neither the name of the California Institute of Technology (Caltech),
      14             :  * its operating division the Jet Propulsion Laboratory (JPL), the National
      15             :  * Aeronautics and Space Administration (NASA), nor the names of its
      16             :  * contributors may be used to endorse or promote products derived from this
      17             :  * software without specific prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      20             :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      21             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      22             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE
      23             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      24             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      25             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      26             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      27             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      28             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      29             :  * POSSIBILITY OF SUCH DAMAGE.
      30             :  *
      31             :  * Copyright 2014-2021 Esri
      32             :  *
      33             :  * Licensed under the Apache License, Version 2.0 (the "License");
      34             :  * you may not use this file except in compliance with the License.
      35             :  * You may obtain a copy of the License at
      36             :  *
      37             :  * http://www.apache.org/licenses/LICENSE-2.0
      38             :  *
      39             :  * Unless required by applicable law or agreed to in writing, software
      40             :  * distributed under the License is distributed on an "AS IS" BASIS,
      41             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      42             :  * See the License for the specific language governing permissions and
      43             :  * limitations under the License.
      44             :  *
      45             :  * Author: Lucian Plesea
      46             :  *
      47             :  *
      48             :  * JPEG band
      49             :  * JPEG page compression and decompression functions, file gets compiled twice
      50             :  * once directly and once through inclusion from JPEG12_band.cpp
      51             :  * JPEG12_SUPPORTED is defined if both 8 and 12 bit JPEG will be supported
      52             :  * JPEG12_ON    is defined only for the 12 bit versions
      53             :  *
      54             :  * The MRF JPEG codec implements the Zen (Zero ENhanced) JPEG extension
      55             :  * This extension, when supported by the decompressor, preserves the zero or
      56             :  * non-zero state of all pixels which allows zero pixels to be used as a
      57             :  * non-data mask Clients which don't support the Zen extension will read it as a
      58             :  * normal JPEG
      59             :  *
      60             :  * On page writes, a mask of all fully zero pixels is built
      61             :  * If the mask has some zero pixels, it is written in a JPEG APP3 "Zen" marker
      62             :  * If the mask has no zero pixels, a zero length APP3 marker is inserted
      63             :  *
      64             :  * On page reads, after the JPEG decompression, if a mask or a zero length APP3
      65             :  * marker is detected, the masked pixels with value of zero are set to 1 while
      66             :  * the non-masked ones are set to zero
      67             :  *
      68             :  */
      69             : 
      70             : #include "marfa.h"
      71             : #include <setjmp.h>
      72             : #include <vector>
      73             : 
      74             : CPL_C_START
      75             : #include "jpeglib.h"
      76             : #include "jerror.h"
      77             : CPL_C_END
      78             : 
      79             : #define PACKER
      80             : #include "BitMask2D.h"
      81             : #include "Packer_RLE.h"
      82             : 
      83             : #if defined(BRUNSLI)
      84             : #include <brunsli/encode.h>
      85             : #include <brunsli/decode.h>
      86             : #endif
      87             : 
      88             : #if defined(EXPECTED_JPEG_LIB_VERSION) && !defined(JPEG12_SUPPORTED)
      89             : #if EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
      90             : #error EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
      91             : #endif
      92             : #endif
      93             : 
      94             : /* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which
      95             :  * adds a dual-mode 8/12 bit API in the same library.
      96             :  */
      97             : 
      98             : #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12)
      99             : /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo
     100             :  * >= 2.2 Cf
     101             :  * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b
     102             :  */
     103             : #undef BITS_IN_JSAMPLE
     104             : /* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */
     105             : #if defined(JPEG12_ON)
     106             : #define BITS_IN_JSAMPLE 12
     107             : #define MRF_JSAMPLE J12SAMPLE
     108             : #define MRF_JSAMPARRAY J12SAMPARRAY
     109             : #define MRF_JSAMPIMAGE J12SAMPIMAGE
     110             : #define MRF_JSAMPROW J12SAMPROW
     111             : #else
     112             : #define BITS_IN_JSAMPLE 8
     113             : #define MRF_JSAMPLE JSAMPLE
     114             : #define MRF_JSAMPARRAY JSAMPARRAY
     115             : #define MRF_JSAMPIMAGE JSAMPIMAGE
     116             : #define MRF_JSAMPROW JSAMPROW
     117             : #endif
     118             : #else
     119             : #define MRF_JSAMPLE JSAMPLE
     120             : #define MRF_JSAMPARRAY JSAMPARRAY
     121             : #define MRF_JSAMPIMAGE JSAMPIMAGE
     122             : #define MRF_JSAMPROW JSAMPROW
     123             : #endif
     124             : 
     125             : NAMESPACE_MRF_START
     126             : 
     127             : typedef BitMap2D<> BitMask;
     128             : 
     129             : // Values for mask_state flag
     130             : 
     131             : enum
     132             : {
     133             :     NO_MASK = 0,
     134             :     MASK_LOADED,
     135             :     MASK_FULL
     136             : };
     137             : 
     138             : extern char CHUNK_NAME[];
     139             : extern size_t CHUNK_NAME_SIZE;
     140             : 
     141             : typedef struct MRFJPEGStruct
     142             : {
     143             :     jmp_buf setjmpBuffer;
     144             :     BitMask *mask;
     145             :     int mask_state;
     146             : 
     147          20 :     MRFJPEGStruct()
     148          20 :     {
     149          20 :         memset(&setjmpBuffer, 0, sizeof(setjmpBuffer));
     150          20 :         mask = nullptr;
     151          20 :         mask_state = NO_MASK;
     152          20 :     }
     153             : } MRFJPEGErrorStruct;
     154             : 
     155             : /**
     156             :  *\brief Called when jpeg wants to report a warning
     157             :  * msgLevel can be:
     158             :  * -1 Corrupt data
     159             :  * 0 always display
     160             :  * 1... Trace level
     161             :  */
     162             : 
     163         157 : static void emitMessage(j_common_ptr cinfo, int msgLevel)
     164             : {
     165         157 :     if (msgLevel > 0)
     166         157 :         return;  // No trace msgs
     167             :     // There can be many warnings, just print the first one
     168           0 :     if (cinfo->err->num_warnings++ > 1)
     169           0 :         return;
     170             :     char buffer[JMSG_LENGTH_MAX];
     171           0 :     cinfo->err->format_message(cinfo, buffer);
     172           0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer);
     173             : }
     174             : 
     175           0 : static void errorExit(j_common_ptr cinfo)
     176             : {
     177           0 :     MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data;
     178             :     // format the warning message
     179             :     char buffer[JMSG_LENGTH_MAX];
     180             : 
     181           0 :     cinfo->err->format_message(cinfo, buffer);
     182           0 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", buffer);
     183             :     // return control to the setjmp point
     184           0 :     longjmp(psJPEGStruct->setjmpBuffer, 1);
     185             : }
     186             : 
     187             : /**
     188             :  *\brief Do nothing stub function for JPEG library, called
     189             :  */
     190          16 : static void stub_source_dec(j_decompress_ptr /*cinfo*/)
     191             : {
     192          16 : }
     193             : 
     194             : /**
     195             :  *\brief: This function is supposed to do refilling of the input buffer,
     196             :  * but as we provided everything at the beginning, if it is called, then
     197             :  * we have an error.
     198             :  */
     199           0 : static boolean fill_input_buffer_dec(j_decompress_ptr cinfo)
     200             : {
     201           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Invalid JPEG stream");
     202           0 :     cinfo->err->msg_code = JERR_INPUT_EMPTY;
     203           0 :     cinfo->err->error_exit((j_common_ptr)(cinfo));
     204           0 :     return FALSE;
     205             : }
     206             : 
     207             : /**
     208             :  *\brief: Skips unknown chunks
     209             :  */
     210           0 : static void skip_input_data_dec(j_decompress_ptr cinfo, long l)
     211             : {
     212           0 :     struct jpeg_source_mgr *src = cinfo->src;
     213           0 :     if (l > 0)
     214             :     {
     215           0 :         if (static_cast<size_t>(l) > src->bytes_in_buffer)
     216           0 :             l = static_cast<long>(src->bytes_in_buffer);
     217           0 :         src->bytes_in_buffer -= l;
     218           0 :         src->next_input_byte += l;
     219             :     }
     220           0 : }
     221             : 
     222             : // Destination should be already set up
     223          24 : static void init_or_terminate_destination(j_compress_ptr /*cinfo*/)
     224             : {
     225          24 : }
     226             : 
     227             : // Called if the buffer provided is too small
     228           0 : static boolean empty_output_buffer(j_compress_ptr /*cinfo*/)
     229             : {
     230           0 :     std::cerr << "JPEG Output buffer empty called\n";
     231           0 :     return FALSE;
     232             : }
     233             : 
     234             : // Returns the number of zero pixels in the page, as well as clearing those bits
     235             : // in the mask
     236          12 : template <typename T> static int update_mask(BitMask &mask, T *src, int nc)
     237             : {
     238          12 :     int zeros = 0;
     239          12 :     int h = mask.getHeight();
     240          12 :     int w = mask.getWidth();
     241        6156 :     for (int y = 0; y < h; y++)
     242     3151876 :         for (int x = 0; x < w; x++)
     243             :         {
     244     3145724 :             bool is_zero = true;
     245     8388608 :             for (int c = 0; c < nc; c++)
     246     5242884 :                 if (*src++ != 0)
     247     1210910 :                     is_zero = false;
     248     3145724 :             if (is_zero)
     249             :             {
     250     2340864 :                 zeros++;
     251     2340864 :                 mask.clear(x, y);
     252             :             }
     253             :         }
     254          12 :     return zeros;
     255             : }
     256             : 
     257             : /*
     258             :  *\brief Compress a JPEG page in memory
     259             :  *
     260             :  * It handles byte or 12 bit data, grayscale, RGB, YUV, and multispectral
     261             :  *
     262             :  * Returns the compressed size in dest.size
     263             :  */
     264             : #if defined(JPEG12_ON)
     265           1 : CPLErr JPEG_Codec::CompressJPEG12(buf_mgr &dst, buf_mgr &src)
     266             : #else
     267          11 : CPLErr JPEG_Codec::CompressJPEG(buf_mgr &dst, buf_mgr &src)
     268             : #endif
     269             : 
     270             : {
     271             :     // The cinfo should stay open and reside in the DS, since it can be left
     272             :     // initialized It saves some time because it has the tables initialized
     273             :     struct jpeg_compress_struct cinfo;
     274          12 :     MRFJPEGStruct sJPEGStruct;
     275             :     struct jpeg_error_mgr sJErr;
     276          12 :     ILSize sz = img.pagesize;
     277             : 
     278             :     jpeg_destination_mgr jmgr;
     279          12 :     jmgr.next_output_byte = (JOCTET *)dst.buffer;
     280          12 :     jmgr.free_in_buffer = dst.size;
     281          12 :     jmgr.init_destination = init_or_terminate_destination;
     282          12 :     jmgr.empty_output_buffer = empty_output_buffer;
     283          12 :     jmgr.term_destination = init_or_terminate_destination;
     284             : 
     285          12 :     memset(&cinfo, 0, sizeof(cinfo));
     286             : 
     287             :     // Look at the source of this, some interesting tidbits
     288          12 :     cinfo.err = jpeg_std_error(&sJErr);
     289          12 :     sJErr.error_exit = errorExit;
     290          12 :     sJErr.emit_message = emitMessage;
     291          12 :     cinfo.client_data = (void *)&(sJPEGStruct);
     292          12 :     jpeg_create_compress(&cinfo);
     293          12 :     cinfo.dest = &jmgr;
     294             : 
     295             :     // The page specific info, size and color spaces
     296          12 :     cinfo.image_width = sz.x;
     297          12 :     cinfo.image_height = sz.y;
     298          12 :     cinfo.input_components = sz.c;
     299          12 :     switch (cinfo.input_components)
     300             :     {
     301           8 :         case 1:
     302           8 :             cinfo.in_color_space = JCS_GRAYSCALE;
     303           8 :             break;
     304           4 :         case 3:
     305           4 :             cinfo.in_color_space = JCS_RGB;
     306           4 :             break;  // Stored as YCbCr 4:2:0 by default
     307           0 :         default:
     308           0 :             cinfo.in_color_space = JCS_UNKNOWN;  // 2, 4-10 bands
     309             :     }
     310             : 
     311             : #if defined(JPEG12_ON)
     312           1 :     cinfo.data_precision = 12;
     313             : #else
     314          11 :     cinfo.data_precision = 8;
     315             : #endif
     316             : 
     317             :     // Set all required fields and overwrite the ones we want to change
     318          12 :     jpeg_set_defaults(&cinfo);
     319             : 
     320             :     // Override certain settings
     321          12 :     jpeg_set_quality(&cinfo, img.quality, TRUE);
     322          12 :     cinfo.dct_method = JDCT_FLOAT;  // Pretty fast and precise
     323          12 :     cinfo.optimize_coding =
     324          12 :         optimize;  // Set "OPTIMIZE=TRUE" in OPTIONS, default for 12bit
     325             : 
     326             :     // Do we explicitly turn off the YCC color and downsampling?
     327             : 
     328          12 :     if (cinfo.in_color_space == JCS_RGB)
     329             :     {
     330           4 :         if (rgb)
     331             :         {                                          // Stored as RGB
     332           1 :             jpeg_set_colorspace(&cinfo, JCS_RGB);  // Huge files
     333             :         }
     334           3 :         else if (sameres)
     335             :         {  // YCC, somewhat larger files with improved color spatial detail
     336           1 :             cinfo.comp_info[0].h_samp_factor = 1;
     337           1 :             cinfo.comp_info[0].v_samp_factor = 1;
     338             : 
     339             :             // Enabling these lines will make the color components use the same
     340             :             // tables as Y, even larger file with slightly better color depth
     341             :             // detail cinfo.comp_info[1].quant_tbl_no = 0;
     342             :             // cinfo.comp_info[2].quant_tbl_no = 0;
     343             : 
     344             :             // cinfo.comp_info[1].dc_tbl_no = 0;
     345             :             // cinfo.comp_info[2].dc_tbl_no = 0;
     346             : 
     347             :             // cinfo.comp_info[1].ac_tbl_no = 0;
     348             :             // cinfo.comp_info[2].ac_tbl_no = 0;
     349             :         }
     350             :     }
     351             : 
     352          24 :     int linesize = cinfo.image_width * cinfo.input_components *
     353          12 :                    ((cinfo.data_precision == 8) ? 1 : 2);
     354          12 :     MRF_JSAMPROW *rowp = (MRF_JSAMPROW *)CPLMalloc(sizeof(MRF_JSAMPROW) * sz.y);
     355          12 :     if (!rowp)
     356             :     {
     357           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG compression error");
     358           0 :         jpeg_destroy_compress(&cinfo);
     359           0 :         return CE_Failure;
     360             :     }
     361             : 
     362        6156 :     for (int i = 0; i < sz.y; i++)
     363             :     {
     364        6144 :         rowp[i] = (MRF_JSAMPROW)(src.buffer + i * linesize);
     365             : #if defined(JPEG12_ON)
     366      262656 :         for (int x = 0; x < sz.x; ++x)
     367             :         {
     368      262144 :             if (static_cast<unsigned short>(rowp[i][x]) > 4095)
     369             :             {
     370           0 :                 rowp[i][x] = (MRF_JSAMPLE)4095;
     371             :                 static bool bClipWarn = false;
     372           0 :                 if (!bClipWarn)
     373             :                 {
     374           0 :                     bClipWarn = true;
     375           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     376             :                              "One or more pixels clipped to fit 12bit domain "
     377             :                              "for jpeg output.");
     378             :                 }
     379             :             }
     380             :         }
     381             : #endif
     382             :     }
     383             : 
     384          12 :     if (setjmp(sJPEGStruct.setjmpBuffer))
     385             :     {
     386           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG compression error");
     387           0 :         jpeg_destroy_compress(&cinfo);
     388           0 :         CPLFree(rowp);
     389           0 :         return CE_Failure;
     390             :     }
     391             : 
     392             :     // Build a bitmaps of the black pixels
     393             :     // If there are any black pixels, write a compressed mask in APP3 "Zen"
     394             :     // chunk
     395             : 
     396             :     // Mask is initialized to all pixels valid
     397          24 :     BitMask mask(sz.x, sz.y);
     398          12 :     storage_manager mbuffer = {CHUNK_NAME, CHUNK_NAME_SIZE};
     399             : 
     400             :     int nzeros =
     401          12 :         (cinfo.data_precision == 8)
     402          12 :             ? update_mask(mask, reinterpret_cast<GByte *>(src.buffer), sz.c)
     403           1 :             : update_mask(mask, reinterpret_cast<GUInt16 *>(src.buffer), sz.c);
     404             : 
     405             :     // In case we need to build a Zen chunk
     406          12 :     char *buffer = nullptr;
     407             : 
     408          12 :     if (nzeros != 0)
     409             :     {  // build the Zen chunk
     410          12 :         mbuffer.size = 2 * mask.size() + CHUNK_NAME_SIZE;
     411          12 :         buffer = reinterpret_cast<char *>(CPLMalloc(mbuffer.size));
     412          12 :         if (!buffer)
     413             :         {
     414           0 :             jpeg_destroy_compress(&cinfo);
     415           0 :             CPLFree(rowp);
     416           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     417             :                      "MRF: JPEG Zen mask compression");
     418           0 :             return CE_Failure;
     419             :         }
     420             : 
     421          12 :         memcpy(buffer, CHUNK_NAME, CHUNK_NAME_SIZE);
     422          12 :         mbuffer.buffer = buffer + CHUNK_NAME_SIZE;
     423          12 :         mbuffer.size -= CHUNK_NAME_SIZE;
     424             : 
     425           0 :         RLEC3Packer c3;
     426          12 :         mask.set_packer(&c3);
     427          12 :         if (!mask.store(&mbuffer))
     428             :         {
     429           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     430             :                      "MRF: JPEG Zen mask compression");
     431           0 :             CPLFree(rowp);
     432           0 :             CPLFree(buffer);
     433           0 :             return CE_Failure;
     434             :         }
     435             : 
     436             :         // Change the buffer pointer to include the signature, on output the
     437             :         // size is the compressed size
     438          12 :         mbuffer.buffer = buffer;
     439          12 :         mbuffer.size += CHUNK_NAME_SIZE;
     440             : 
     441             :         // Check that the size fits in one JPEG chunk
     442          12 :         if (mbuffer.size + 2 + CHUNK_NAME_SIZE > 65535)
     443             :         {
     444             :             // Should split it in multiple chunks, for now mark this tile as all
     445             :             // data and emit a warning
     446           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     447             :                      "MRF: JPEG Zen mask too large");
     448           0 :             mbuffer.size = CHUNK_NAME_SIZE;  // Write just the signature
     449             :         }
     450             :     }
     451             : 
     452             :     // Everything is ready
     453          12 :     jpeg_start_compress(&cinfo, TRUE);
     454             : 
     455             :     // Always write the Zen app chunk, App3
     456          12 :     jpeg_write_marker(&cinfo, JPEG_APP0 + 3,
     457          12 :                       reinterpret_cast<JOCTET *>(mbuffer.buffer),
     458          12 :                       static_cast<unsigned int>(mbuffer.size));
     459             : 
     460             : #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && defined(JPEG12_ON)
     461             :     jpeg12_write_scanlines(&cinfo, rowp, sz.y);
     462             : #else
     463          12 :     jpeg_write_scanlines(&cinfo, rowp, sz.y);
     464             : #endif
     465          12 :     jpeg_finish_compress(&cinfo);
     466          12 :     jpeg_destroy_compress(&cinfo);
     467             : 
     468          12 :     CPLFree(rowp);
     469          12 :     CPLFree(buffer);  // Safe to call on null
     470             : 
     471             :     // Figure out the size of the JFIF
     472          12 :     dst.size -= jmgr.free_in_buffer;
     473          12 :     return CE_None;
     474             : }
     475             : 
     476             : /************************************************************************/
     477             : /*                          ProgressMonitor()                           */
     478             : /************************************************************************/
     479             : 
     480             : /* Avoid the risk of denial-of-service on crafted JPEGs with an insane */
     481             : /* number of scans. */
     482             : /* See
     483             :  * http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf
     484             :  */
     485        3584 : static void ProgressMonitor(j_common_ptr cinfo)
     486             : {
     487        3584 :     if (cinfo->is_decompressor)
     488             :     {
     489        3584 :         const int scan_no =
     490             :             reinterpret_cast<j_decompress_ptr>(cinfo)->input_scan_number;
     491        3584 :         const int MAX_SCANS = 100;
     492        3584 :         if (scan_no >= MAX_SCANS)
     493             :         {
     494           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     495             :                      "Scan number %d exceeds maximum scans (%d)", scan_no,
     496             :                      MAX_SCANS);
     497             : 
     498           0 :             MRFJPEGStruct *psJPEGStruct = (MRFJPEGStruct *)cinfo->client_data;
     499             : 
     500             :             // return control to the setjmp point
     501           0 :             longjmp(psJPEGStruct->setjmpBuffer, 1);
     502             :         }
     503             :     }
     504        3584 : }
     505             : 
     506             : // Returns the number of zero pixels, as well as clearing those bits int the
     507             : // mask
     508           8 : template <typename T> static void apply_mask(MRFJPEGStruct &sJ, T *s, int nc)
     509             : {
     510           8 :     if (NO_MASK == sJ.mask_state)
     511           0 :         return;
     512             : 
     513           8 :     BitMask *mask = sJ.mask;
     514           8 :     int w = mask->getWidth();
     515           8 :     int h = mask->getHeight();
     516             : 
     517           8 :     if (MASK_LOADED == sJ.mask_state)
     518             :     {  // Partial map
     519        4104 :         for (int y = 0; y < h; y++)
     520     2101246 :             for (int x = 0; x < w; x++)
     521             :             {
     522     2097154 :                 if (mask->isSet(x, y))
     523             :                 {  // Non zero pixel
     524     1218830 :                     for (int c = 0; c < nc; c++, s++)
     525             :                     {
     526      812929 :                         if (*s == 0)
     527       21654 :                             *s = 1;
     528             :                     }
     529             :                 }
     530             :                 else
     531             :                 {  // Zero pixel
     532     5072618 :                     for (int c = 0; c < nc; c++)
     533     3381374 :                         *s++ = 0;
     534             :                 }
     535             :             }
     536             :     }
     537           0 :     else if (MASK_FULL == sJ.mask_state)
     538             :     {  // All non-zero
     539           0 :         for (int y = 0; y < h; y++)
     540           0 :             for (int x = 0; x < w; x++)
     541             :             {
     542           0 :                 for (int c = 0; c < nc; c++, s++)
     543             :                 {
     544           0 :                     if (*s == 0)
     545           0 :                         *s = 1;
     546             :                 }
     547             :             }
     548             :     }
     549             : }
     550             : 
     551             : // JPEG marker processor, for the Zen app3 marker
     552             : // Can't return error, only works if the JPEG mask is all in the buffer
     553           8 : static boolean MaskProcessor(j_decompress_ptr pcinfo)
     554             : {
     555           8 :     struct jpeg_source_mgr *src = pcinfo->src;
     556           8 :     if (src->bytes_in_buffer < 2)
     557           0 :         ERREXIT(pcinfo, JERR_CANT_SUSPEND);
     558             :     // Big endian length, two bytes
     559           8 :     int len = (*src->next_input_byte++) << 8;
     560           8 :     len += *src->next_input_byte++;
     561             :     // The length includes the two bytes we just read
     562           8 :     src->bytes_in_buffer -= 2;
     563           8 :     len -= 2;
     564             :     // Check that it is safe to read the rest
     565           8 :     if (src->bytes_in_buffer < static_cast<size_t>(len))
     566           0 :         ERREXIT(pcinfo, JERR_CANT_SUSPEND);
     567           8 :     MRFJPEGStruct *psJPEG =
     568             :         reinterpret_cast<MRFJPEGStruct *>(pcinfo->client_data);
     569           8 :     BitMask *mask = psJPEG->mask;
     570             :     // caller doesn't want a mask or wrong chunk, skip the chunk and return
     571           8 :     if (!mask || static_cast<size_t>(len) < CHUNK_NAME_SIZE ||
     572           8 :         !EQUALN(reinterpret_cast<const char *>(src->next_input_byte),
     573             :                 CHUNK_NAME, CHUNK_NAME_SIZE))
     574             :     {
     575           0 :         src->bytes_in_buffer -= len;
     576           0 :         src->next_input_byte += len;
     577           0 :         return true;
     578             :     }
     579             : 
     580             :     // Skip the signature and load the mask
     581           8 :     src->bytes_in_buffer -= CHUNK_NAME_SIZE;
     582           8 :     src->next_input_byte += CHUNK_NAME_SIZE;
     583           8 :     len -= static_cast<int>(CHUNK_NAME_SIZE);
     584           8 :     if (len == 0)
     585             :     {  // No mask content means mask is all full, just return
     586           0 :         psJPEG->mask_state = MASK_FULL;
     587           0 :         return true;
     588             :     }
     589             : 
     590             :     // It is OK to use const cast, the mask doesn't touch the buffer
     591             :     storage_manager msrc = {const_cast<char *>(reinterpret_cast<const char *>(
     592           8 :                                 src->next_input_byte)),
     593           8 :                             static_cast<size_t>(len)};
     594             : 
     595           8 :     if (!mask->load(&msrc))
     596             :     {  // Fatal error return, mask is not valid
     597           0 :         ERREXIT(pcinfo, JERR_CANT_SUSPEND);
     598             :     }
     599             : 
     600           8 :     src->bytes_in_buffer -= len;
     601           8 :     src->next_input_byte += len;
     602           8 :     psJPEG->mask_state = MASK_LOADED;
     603           8 :     return true;
     604             : }
     605             : 
     606             : /**
     607             :  *\brief In memory decompression of JPEG file
     608             :  *
     609             :  * @param data pointer to output buffer
     610             :  * @param png pointer to PNG in memory
     611             :  * @param sz if non-zero, test that uncompressed data fits in the buffer.
     612             :  */
     613             : #if defined(JPEG12_ON)
     614           1 : CPLErr JPEG_Codec::DecompressJPEG12(buf_mgr &dst, const buf_mgr &isrc)
     615             : #else
     616           7 : CPLErr JPEG_Codec::DecompressJPEG(buf_mgr &dst, const buf_mgr &isrc)
     617             : #endif
     618             : 
     619             : {
     620           8 :     int nbands = img.pagesize.c;
     621             :     // Locals, clean up after themselves
     622             :     jpeg_decompress_struct cinfo;
     623           8 :     MRFJPEGStruct sJPEGStruct;
     624             :     struct jpeg_error_mgr sJErr;
     625          16 :     BitMask mask(img.pagesize.x, img.pagesize.y);
     626           8 :     RLEC3Packer packer;
     627           8 :     mask.set_packer(&packer);
     628             : 
     629           8 :     memset(&cinfo, 0, sizeof(cinfo));
     630             :     // Pass the mask address to the decompressor
     631           8 :     sJPEGStruct.mask = &mask;
     632             : 
     633             :     struct jpeg_source_mgr src;
     634             : 
     635           8 :     cinfo.err = jpeg_std_error(&sJErr);
     636           8 :     sJErr.error_exit = errorExit;
     637           8 :     sJErr.emit_message = emitMessage;
     638           8 :     cinfo.client_data = &sJPEGStruct;
     639             : 
     640           8 :     src.next_input_byte = reinterpret_cast<JOCTET *>(isrc.buffer);
     641           8 :     src.bytes_in_buffer = isrc.size;
     642           8 :     src.term_source = stub_source_dec;
     643           8 :     src.init_source = stub_source_dec;
     644           8 :     src.skip_input_data = skip_input_data_dec;
     645           8 :     src.fill_input_buffer = fill_input_buffer_dec;
     646           8 :     src.resync_to_restart = jpeg_resync_to_restart;
     647             : 
     648           8 :     jpeg_create_decompress(&cinfo);
     649             : 
     650           8 :     if (setjmp(sJPEGStruct.setjmpBuffer))
     651             :     {
     652           0 :         CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error reading JPEG page");
     653           0 :         jpeg_destroy_decompress(&cinfo);
     654           0 :         return CE_Failure;
     655             :     }
     656             : 
     657           8 :     cinfo.src = &src;
     658           8 :     jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 3, MaskProcessor);
     659           8 :     jpeg_read_header(&cinfo, TRUE);
     660             : 
     661             :     /* In some cases, libjpeg needs to allocate a lot of memory */
     662             :     /* http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf
     663             :      */
     664           8 :     if (jpeg_has_multiple_scans(&(cinfo)))
     665             :     {
     666             :         /* In this case libjpeg will need to allocate memory or backing */
     667             :         /* store for all coefficients */
     668             :         /* See call to jinit_d_coef_controller() from master_selection() */
     669             :         /* in libjpeg */
     670           0 :         vsi_l_offset nRequiredMemory =
     671           0 :             static_cast<vsi_l_offset>(cinfo.image_width) * cinfo.image_height *
     672           0 :             cinfo.num_components * ((cinfo.data_precision + 7) / 8);
     673             :         /* BLOCK_SMOOTHING_SUPPORTED is generally defined, so we need */
     674             :         /* to replicate the logic of jinit_d_coef_controller() */
     675           0 :         if (cinfo.progressive_mode)
     676           0 :             nRequiredMemory *= 3;
     677             : 
     678             : #ifndef GDAL_LIBJPEG_LARGEST_MEM_ALLOC
     679             : #define GDAL_LIBJPEG_LARGEST_MEM_ALLOC (100 * 1024 * 1024)
     680             : #endif
     681             : 
     682           0 :         if (nRequiredMemory > GDAL_LIBJPEG_LARGEST_MEM_ALLOC &&
     683           0 :             CPLGetConfigOption("GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC", nullptr) ==
     684             :                 nullptr)
     685             :         {
     686           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     687             :                      "Reading this image would require libjpeg to allocate "
     688             :                      "at least " CPL_FRMT_GUIB " bytes. "
     689             :                      "This is disabled since above the " CPL_FRMT_GUIB
     690             :                      " threshold. "
     691             :                      "You may override this restriction by defining the "
     692             :                      "GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, "
     693             :                      "or recompile GDAL by defining the "
     694             :                      "GDAL_LIBJPEG_LARGEST_MEM_ALLOC macro to a value greater "
     695             :                      "than " CPL_FRMT_GUIB,
     696             :                      static_cast<GUIntBig>(nRequiredMemory),
     697             :                      static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC),
     698             :                      static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC));
     699           0 :             jpeg_destroy_decompress(&cinfo);
     700           0 :             return CE_Failure;
     701             :         }
     702             :     }
     703             : 
     704             :     // Use float, it is actually faster than the ISLOW method by a tiny bit
     705           8 :     cinfo.dct_method = JDCT_FLOAT;
     706             : 
     707             :     //
     708             :     // Tolerate different input if we can do the conversion
     709             :     // Gray and RGB for example
     710             :     // This also means that a RGB MRF can be read as grayscale and vice versa
     711             :     // If libJPEG can't convert it will throw an error
     712             :     //
     713           8 :     if (nbands == 3 && cinfo.num_components != nbands)
     714           0 :         cinfo.out_color_space = JCS_RGB;
     715           8 :     if (nbands == 1 && cinfo.num_components != nbands)
     716           0 :         cinfo.out_color_space = JCS_GRAYSCALE;
     717             : 
     718           8 :     const int datasize = ((cinfo.data_precision == 8) ? 1 : 2);
     719           8 :     if (cinfo.image_width >
     720           8 :         static_cast<unsigned>(INT_MAX / (nbands * datasize)))
     721             :     {
     722           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     723             :                  "MRF: JPEG decompress buffer overflow");
     724           0 :         jpeg_destroy_decompress(&cinfo);
     725           0 :         return CE_Failure;
     726             :     }
     727           8 :     int linesize = cinfo.image_width * nbands * datasize;
     728             : 
     729             :     // We have a mismatch between the real and the declared data format
     730             :     // warn and fail if output buffer is too small
     731           8 :     if (linesize > static_cast<int>(INT_MAX / cinfo.image_height))
     732             :     {
     733           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     734             :                  "MRF: JPEG decompress buffer overflow");
     735           0 :         jpeg_destroy_decompress(&cinfo);
     736           0 :         return CE_Failure;
     737             :     }
     738           8 :     if (static_cast<size_t>(linesize) * cinfo.image_height != dst.size)
     739             :     {
     740           0 :         CPLError(CE_Warning, CPLE_AppDefined, "MRF: read JPEG size is wrong");
     741           0 :         if (static_cast<size_t>(linesize) * cinfo.image_height > dst.size)
     742             :         {
     743           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     744             :                      "MRF: JPEG decompress buffer overflow");
     745           0 :             jpeg_destroy_decompress(&cinfo);
     746           0 :             return CE_Failure;
     747             :         }
     748             :     }
     749             : 
     750             :     struct jpeg_progress_mgr sJProgress;
     751           8 :     sJProgress.progress_monitor = ProgressMonitor;
     752           8 :     cinfo.progress = &sJProgress;
     753             : 
     754           8 :     jpeg_start_decompress(&cinfo);
     755             : 
     756             :     // Decompress, two lines at a time is what libjpeg does
     757        3592 :     while (cinfo.output_scanline < cinfo.image_height)
     758             :     {
     759             :         char *rp[2];
     760        3584 :         rp[0] = (char *)dst.buffer + linesize * cinfo.output_scanline;
     761        3584 :         rp[1] = rp[0] + linesize;
     762             :         // if this fails, it calls the error handler
     763             :         // which will report an error
     764             : #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && defined(JPEG12_ON)
     765             :         if (jpeg12_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0)
     766             : #else
     767        3584 :         if (jpeg_read_scanlines(&cinfo, MRF_JSAMPARRAY(rp), 2) == 0)
     768             : #endif
     769             :         {
     770           0 :             jpeg_destroy_decompress(&cinfo);
     771           0 :             return CE_Failure;
     772             :         }
     773             :     }
     774           8 :     jpeg_finish_decompress(&cinfo);
     775           8 :     jpeg_destroy_decompress(&cinfo);
     776             : 
     777             :     // Apply the mask
     778           8 :     if (datasize == 1)
     779           7 :         apply_mask(sJPEGStruct, reinterpret_cast<char *>(dst.buffer),
     780           7 :                    img.pagesize.c);
     781             :     else
     782           1 :         apply_mask(sJPEGStruct, reinterpret_cast<GUInt16 *>(dst.buffer),
     783           1 :                    img.pagesize.c);
     784             : 
     785           8 :     return CE_None;
     786             : }
     787             : 
     788             : // From here to end it gets compiled only once
     789             : #if !defined(JPEG12_ON)
     790             : 
     791             : // The Zen chunk signature
     792             : char CHUNK_NAME[] = "Zen";
     793             : size_t CHUNK_NAME_SIZE = strlen(CHUNK_NAME) + 1;
     794             : 
     795             : const static GUInt32 JPEG_SIG = 0xe0ffd8ff;  // JPEG 4CC code
     796             : const static GUInt32 BRUN_SIG = 0xd242040a;  // Brunsli 4CC code, native
     797             : 
     798           7 : static bool isbrunsli(const buf_mgr &src)
     799             : {
     800             :     GUInt32 signature;
     801           7 :     memcpy(&signature, src.buffer, sizeof(signature));
     802           7 :     if (BRUN_SIG == CPL_LSBWORD32(signature))
     803           0 :         return true;
     804           7 :     return false;
     805             : }
     806             : 
     807           0 : bool JPEG_Codec::IsJPEG(const buf_mgr &src)
     808             : {
     809           0 :     if (isbrunsli(src))
     810           0 :         return true;
     811             :     GUInt32 signature;
     812           0 :     memcpy(&signature, src.buffer, sizeof(signature));
     813           0 :     if (JPEG_SIG == CPL_LSBWORD32(signature))
     814           0 :         return true;
     815           0 :     return false;
     816             : }
     817             : 
     818             : #if defined(BRUNSLI)
     819             : // Append to end of out vector
     820             : static size_t brunsli_fun_callback(void *out, const GByte *data, size_t size)
     821             : {
     822             :     auto outv = static_cast<std::vector<GByte> *>(out);
     823             :     outv->insert(outv->end(), data, data + size);
     824             :     return size;
     825             : }
     826             : #endif
     827             : 
     828             : // Type dependent dispachers
     829           8 : CPLErr JPEG_Band::Decompress(buf_mgr &dst, buf_mgr &src)
     830             : {
     831             : #if defined(JPEG12_SUPPORTED)
     832           8 :     if (GDT_Byte != img.dt)
     833           1 :         return codec.DecompressJPEG12(dst, src);
     834             : #endif
     835           7 :     if (!isbrunsli(src))
     836           7 :         return codec.DecompressJPEG(dst, src);
     837             : 
     838             :         // Need conversion to JFIF first
     839             : #if !defined(BRUNSLI)
     840           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     841             :              "MRF: JPEG-XL content, yet this GDAL was not compiled with "
     842             :              "BRUNSLI support");
     843           0 :     return CE_Failure;
     844             : #else
     845             :     std::vector<GByte> out;
     846             :     // Returns 0 on failure
     847             :     if (!DecodeBrunsli(src.size, reinterpret_cast<uint8_t *>(src.buffer), &out,
     848             :                        brunsli_fun_callback))
     849             :     {
     850             :         CPLError(CE_Failure, CPLE_AppDefined,
     851             :                  "MRF: JPEG-XL (brunsli) tile decode failed");
     852             :         return CE_Failure;
     853             :     }
     854             : 
     855             :     buf_mgr jfif_src;
     856             :     jfif_src.buffer = reinterpret_cast<char *>(out.data());
     857             :     jfif_src.size = out.size();
     858             :     return Decompress(dst, jfif_src);  // Call itself with JFIF JPEG source
     859             : #endif  // BRUNSLI
     860             : }
     861             : 
     862          12 : CPLErr JPEG_Band::Compress(buf_mgr &dst, buf_mgr &src)
     863             : {
     864             : #if defined(JPEG12_SUPPORTED)
     865          12 :     if (GDT_Byte != img.dt)
     866           1 :         return codec.CompressJPEG12(dst, src);
     867             : #endif
     868             : #if !defined(BRUNSLI)
     869          11 :     return codec.CompressJPEG(dst, src);
     870             : #else
     871             :     auto dst_size = dst.size;          // Save the original size
     872             :     auto err_code = codec.CompressJPEG(dst, src);
     873             :     if (codec.JFIF || err_code != CE_None)
     874             :         return err_code;
     875             : 
     876             :     // The JFIF is in dst buffer
     877             :     std::vector<GByte> out;
     878             :     if (!EncodeBrunsli(dst.size, reinterpret_cast<uint8_t *>(dst.buffer), &out,
     879             :                        brunsli_fun_callback))
     880             :     {
     881             :         CPLError(CE_Failure, CPLE_AppDefined,
     882             :                  "MRF: JPEG-XL (brunsli) tile encode failed");
     883             :         return CE_Failure;
     884             :     }
     885             :     // Copy the brunsli to the dst buffer
     886             :     if (out.size() > dst_size)
     887             :     {
     888             :         CPLError(CE_Failure, CPLE_AppDefined,
     889             :                  "MRF: JPEG-XL (brunsli) encoded tile too large");
     890             :         return CE_Failure;
     891             :     }
     892             :     memcpy(dst.buffer, out.data(), out.size());
     893             :     dst.size = out.size();
     894             :     return CE_None;
     895             : #endif  // BRUNSLI
     896             : }
     897             : 
     898             : // PHOTOMETRIC == MULTISPECTRAL turns off YCbCr conversion and downsampling
     899          49 : JPEG_Band::JPEG_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
     900          49 :     : MRFRasterBand(pDS, image, b, int(level)), codec(image)
     901             : {
     902          49 :     const int nbands = image.pagesize.c;
     903             :     // Check behavior on signed 16bit.  Does the libjpeg sign extend?
     904             : #if defined(JPEG12_SUPPORTED)
     905          49 :     if (GDT_Byte != image.dt && GDT_UInt16 != image.dt)
     906             : #else
     907             :     if (GDT_Byte != image.dt)
     908             : #endif
     909             :     {
     910           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     911             :                  "Data type not supported by MRF JPEG");
     912           0 :         return;
     913             :     }
     914             : 
     915          49 :     if (nbands == 3)
     916             :     {  // Only the 3 band JPEG has storage flavors
     917          30 :         CPLString const &pm = pDS->GetPhotometricInterpretation();
     918          30 :         if (pm == "RGB" || pm == "MULTISPECTRAL")
     919             :         {  // Explicit RGB or MS
     920           9 :             codec.rgb = TRUE;
     921           9 :             codec.sameres = TRUE;
     922             :         }
     923          30 :         if (pm == "YCC")
     924           6 :             codec.sameres = TRUE;
     925             :     }
     926             : 
     927          49 :     if (GDT_Byte == image.dt)
     928             :     {
     929          47 :         codec.optimize = GetOptlist().FetchBoolean("OPTIMIZE", FALSE) != FALSE;
     930          47 :         codec.JFIF = GetOptlist().FetchBoolean("JFIF", FALSE) != FALSE;
     931             :     }
     932             :     else
     933             :     {
     934           2 :         codec.optimize = true;  // Required for 12bit
     935             :     }
     936             : }
     937             : #endif
     938             : 
     939             : NAMESPACE_MRF_END

Generated by: LCOV version 1.14