LCOV - code coverage report
Current view: top level - frmts/nitf - nitfwritejpeg.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 86 90 95.6 %
Date: 2024-11-21 22:18:42 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NITF Read/Write Translator
       4             :  * Purpose:  GDALDataset/GDALRasterBand implementation on top of "nitflib".
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12             :  * represented by the Minister of National Defence, 2006.
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************/
      16             : 
      17             : #ifdef JPEG_SUPPORTED
      18             : 
      19             : #include "cpl_port.h"
      20             : #include "gdal_pam.h"
      21             : 
      22             : CPL_C_START
      23             : #ifdef LIBJPEG_12_PATH
      24             : #include LIBJPEG_12_PATH
      25             : #else
      26             : #include "jpeglib.h"
      27             : #endif
      28             : CPL_C_END
      29             : 
      30             : #if defined(EXPECTED_JPEG_LIB_VERSION) && !defined(LIBJPEG_12_PATH)
      31             : #if EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
      32             : #error EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION
      33             : #endif
      34             : #endif
      35             : 
      36             : /*
      37             :  * Do we want to do special processing suitable for when JSAMPLE is a
      38             :  * 16bit value?
      39             :  */
      40             : 
      41             : /* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which
      42             :  * adds a dual-mode 8/12 bit API in the same library.
      43             :  */
      44             : 
      45             : #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12)
      46             : /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo
      47             :  * >= 2.2 Cf
      48             :  * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b
      49             :  */
      50             : #undef BITS_IN_JSAMPLE
      51             : /* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */
      52             : #if defined(NITFWriteJPEGBlock)
      53             : #define BITS_IN_JSAMPLE 12
      54             : #define GDAL_JSAMPLE J12SAMPLE
      55             : #else
      56             : #define BITS_IN_JSAMPLE 8
      57             : #define GDAL_JSAMPLE JSAMPLE
      58             : #endif
      59             : #else
      60             : #define GDAL_JSAMPLE JSAMPLE
      61             : #endif
      62             : 
      63             : #if defined(JPEG_LIB_MK1)
      64             : #define JPEG_LIB_MK1_OR_12BIT 1
      65             : #elif BITS_IN_JSAMPLE == 12
      66             : #define JPEG_LIB_MK1_OR_12BIT 1
      67             : #endif
      68             : 
      69             : #if defined(JPEG_DUAL_MODE_8_12) && !defined(NITFWriteJPEGBlock)
      70             : int NITFWriteJPEGBlock_12(GDALDataset *poSrcDS, VSILFILE *fp, int nBlockXOff,
      71             :                           int nBlockYOff, int nBlockXSize, int nBlockYSize,
      72             :                           int bProgressive, int nQuality, const GByte *pabyAPP6,
      73             :                           int nRestartInterval, GDALProgressFunc pfnProgress,
      74             :                           void *pProgressData);
      75             : #endif
      76             : 
      77             : int NITFWriteJPEGBlock(GDALDataset *poSrcDS, VSILFILE *fp, int nBlockXOff,
      78             :                        int nBlockYOff, int nBlockXSize, int nBlockYSize,
      79             :                        int bProgressive, int nQuality, const GByte *pabyAPP6,
      80             :                        int nRestartInterval, GDALProgressFunc pfnProgress,
      81             :                        void *pProgressData);
      82             : 
      83             : #ifdef NITFWriteJPEGBlock
      84             : #define jpeg_vsiio_src NITF_jpeg_vsiio_src12
      85             : #define jpeg_vsiio_dest NITF_jpeg_vsiio_dest12
      86             : #else
      87             : #define jpeg_vsiio_src NITF_jpeg_vsiio_src
      88             : #define jpeg_vsiio_dest NITF_jpeg_vsiio_dest
      89             : #endif
      90             : #include "../jpeg/vsidataio.h"
      91             : #include "../jpeg/vsidataio.cpp"
      92             : 
      93             : /************************************************************************/
      94             : /*                         NITFWriteJPEGBlock()                         */
      95             : /************************************************************************/
      96             : 
      97          96 : int NITFWriteJPEGBlock(GDALDataset *poSrcDS, VSILFILE *fp, int nBlockXOff,
      98             :                        int nBlockYOff, int nBlockXSize, int nBlockYSize,
      99             :                        int bProgressive, int nQuality, const GByte *pabyAPP6,
     100             :                        int nRestartInterval, GDALProgressFunc pfnProgress,
     101             :                        void *pProgressData)
     102             : {
     103          96 :     GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     104             : #if defined(JPEG_DUAL_MODE_8_12) && !defined(NITFWriteJPEGBlock)
     105          55 :     if (eDT == GDT_UInt16)
     106             :     {
     107          41 :         return NITFWriteJPEGBlock_12(poSrcDS, fp, nBlockXOff, nBlockYOff,
     108             :                                      nBlockXSize, nBlockYSize, bProgressive,
     109             :                                      nQuality, pabyAPP6, nRestartInterval,
     110          41 :                                      pfnProgress, pProgressData);
     111             :     }
     112             : #endif
     113             : 
     114          55 :     int anBandList[3] = {1, 2, 3};
     115             : 
     116             :     /* -------------------------------------------------------------------- */
     117             :     /*      Initialize JPG access to the file.                              */
     118             :     /* -------------------------------------------------------------------- */
     119             :     struct jpeg_compress_struct sCInfo;
     120             :     struct jpeg_error_mgr sJErr;
     121             : 
     122          55 :     memset(&sCInfo, 0, sizeof(sCInfo));
     123          55 :     sCInfo.err = jpeg_std_error(&sJErr);
     124          55 :     jpeg_create_compress(&sCInfo);
     125             : 
     126          55 :     jpeg_vsiio_dest(&sCInfo, fp);
     127             : 
     128          55 :     sCInfo.image_width = nBlockXSize;
     129          55 :     sCInfo.image_height = nBlockYSize;
     130             : 
     131          55 :     const int nBands = poSrcDS->GetRasterCount();
     132          55 :     sCInfo.input_components = nBands;
     133             : 
     134          55 :     if (nBands == 1)
     135             :     {
     136           4 :         sCInfo.in_color_space = JCS_GRAYSCALE;
     137             :     }
     138             :     else
     139             :     {
     140          51 :         sCInfo.in_color_space = JCS_RGB;
     141             :     }
     142             : 
     143          55 :     jpeg_set_defaults(&sCInfo);
     144             : 
     145             : #if defined(JPEG_LIB_MK1_OR_12BIT)
     146          41 :     if (eDT == GDT_UInt16)
     147             :     {
     148          41 :         sCInfo.data_precision = 12;
     149             :     }
     150             :     else
     151             :     {
     152           0 :         sCInfo.data_precision = 8;
     153             :     }
     154             : #endif
     155             : 
     156             :     GDALDataType eWorkDT;
     157             : #ifdef JPEG_LIB_MK1
     158             :     sCInfo.bits_in_jsample = sCInfo.data_precision;
     159             :     eWorkDT = GDT_UInt16; /* Always force to 16 bit for JPEG_LIB_MK1 */
     160             : #else
     161          55 :     eWorkDT = eDT;
     162             : #endif
     163             : 
     164          55 :     sCInfo.write_JFIF_header = FALSE;
     165             : 
     166             :     /* Set the restart interval */
     167          55 :     if (nRestartInterval < 0)
     168             :     {
     169             :         /* nRestartInterval < 0 means that we will guess the value */
     170             :         /* so we set it at the maximum allowed by MIL-STD-188-198 */
     171             :         /* that is to say the number of MCU per row-block */
     172          55 :         nRestartInterval = nBlockXSize / 8;
     173             :     }
     174             : 
     175          55 :     if (nRestartInterval > 0)
     176          55 :         sCInfo.restart_interval = nRestartInterval;
     177             : 
     178          55 :     jpeg_set_quality(&sCInfo, nQuality, TRUE);
     179             : 
     180          55 :     if (bProgressive)
     181           0 :         jpeg_simple_progression(&sCInfo);
     182             : 
     183          55 :     jpeg_start_compress(&sCInfo, TRUE);
     184             : 
     185             :     /* -------------------------------------------------------------------- */
     186             :     /*    Emits APP6 NITF application segment (required by MIL-STD-188-198) */
     187             :     /* -------------------------------------------------------------------- */
     188          55 :     if (pabyAPP6)
     189             :     {
     190             :         /* 0xe6 = APP6 marker */
     191          10 :         jpeg_write_marker(&sCInfo, 0xe6, (const JOCTET *)pabyAPP6, 23);
     192             :     }
     193             : 
     194             :     /* -------------------------------------------------------------------- */
     195             :     /*      Loop over image, copying image data.                            */
     196             :     /* -------------------------------------------------------------------- */
     197          55 :     const int nWorkDTSize = GDALGetDataTypeSizeBytes(eWorkDT);
     198             : 
     199             :     GByte *pabyScanline = reinterpret_cast<GByte *>(
     200          55 :         CPLMalloc(cpl::fits_on<int>(nBands * nBlockXSize * nWorkDTSize)));
     201             : 
     202          55 :     const int nXSize = poSrcDS->GetRasterXSize();
     203          55 :     const int nYSize = poSrcDS->GetRasterYSize();
     204             : 
     205          55 :     const double nTotalPixels = static_cast<double>(nXSize) * nYSize;
     206             : 
     207          55 :     int nBlockXSizeToRead = nBlockXSize;
     208          55 :     if (nBlockXSize * nBlockXOff + nBlockXSize > nXSize)
     209             :     {
     210           6 :         nBlockXSizeToRead = nXSize - nBlockXSize * nBlockXOff;
     211             :     }
     212          55 :     int nBlockYSizeToRead = nBlockYSize;
     213          55 :     if (nBlockYSize * nBlockYOff + nBlockYSize > nYSize)
     214             :     {
     215          45 :         nBlockYSizeToRead = nYSize - nBlockYSize * nBlockYOff;
     216             :     }
     217             : 
     218             : #if defined(JPEG_LIB_MK1_OR_12BIT)
     219          41 :     bool bClipWarn = false;
     220             : #endif
     221             : 
     222          55 :     CPLErr eErr = CE_None;
     223       10800 :     for (int iLine = 0; iLine < nBlockYSize && eErr == CE_None; iLine++)
     224             :     {
     225       10745 :         if (iLine < nBlockYSizeToRead)
     226             :         {
     227         950 :             eErr = poSrcDS->RasterIO(
     228             :                 GF_Read, nBlockXSize * nBlockXOff,
     229         475 :                 iLine + nBlockYSize * nBlockYOff, nBlockXSizeToRead, 1,
     230             :                 pabyScanline, nBlockXSizeToRead, 1, eWorkDT, nBands, anBandList,
     231         475 :                 static_cast<GSpacing>(nBands) * nWorkDTSize,
     232         475 :                 static_cast<GSpacing>(nBands) * nWorkDTSize * nBlockXSize,
     233             :                 nWorkDTSize, nullptr);
     234             : 
     235             :             /* Repeat the last pixel till the end of the line */
     236             :             /* to minimize discontinuity */
     237         475 :             if (nBlockXSizeToRead < nBlockXSize)
     238             :             {
     239         604 :                 for (int iBand = 0; iBand < nBands; iBand++)
     240             :                 {
     241             : #if defined(JPEG_LIB_MK1_OR_12BIT)
     242           3 :                     if (eWorkDT == GDT_UInt16)
     243             :                     {
     244           3 :                         GUInt16 *panScanline =
     245             :                             reinterpret_cast<GUInt16 *>(pabyScanline);
     246           3 :                         const GUInt16 nVal =
     247           3 :                             panScanline[nBands * (nBlockXSizeToRead - 1) +
     248           3 :                                         iBand];
     249         723 :                         for (int iX = nBlockXSizeToRead; iX < nBlockXSize; iX++)
     250             :                         {
     251         720 :                             panScanline[nBands * iX + iBand] = nVal;
     252             :                         }
     253             :                     }
     254             :                     else
     255             : #endif
     256             :                     {
     257         450 :                         GByte bVal =
     258         450 :                             pabyScanline[nBands * (nBlockXSizeToRead - 1) +
     259         450 :                                          iBand];
     260        6750 :                         for (int iX = nBlockXSizeToRead; iX < nBlockXSize; iX++)
     261             :                         {
     262        6300 :                             pabyScanline[nBands * iX + iBand] = bVal;
     263             :                         }
     264             :                     }
     265             :                 }
     266             :             }
     267             :         }
     268             : 
     269             : #if defined(JPEG_LIB_MK1_OR_12BIT)
     270             :         // clamp 16bit values to 12bit.
     271       10304 :         if (eDT == GDT_UInt16)
     272             :         {
     273       10304 :             GUInt16 *panScanline = reinterpret_cast<GUInt16 *>(pabyScanline);
     274             : 
     275     7878720 :             for (int iPixel = 0; iPixel < nBlockXSize * nBands; iPixel++)
     276             :             {
     277     7868420 :                 if (panScanline[iPixel] > 4095)
     278             :                 {
     279       20480 :                     panScanline[iPixel] = 4095;
     280       20480 :                     if (!bClipWarn)
     281             :                     {
     282          40 :                         bClipWarn = true;
     283          40 :                         CPLError(CE_Warning, CPLE_AppDefined,
     284             :                                  "One or more pixels clipped to fit 12bit "
     285             :                                  "domain for jpeg output.");
     286             :                     }
     287             :                 }
     288             :             }
     289             :         }
     290             : #endif
     291             : 
     292       10745 :         GDAL_JSAMPLE *ppSamples =
     293             :             reinterpret_cast<GDAL_JSAMPLE *>(pabyScanline);
     294             : 
     295       10745 :         if (eErr == CE_None)
     296             :         {
     297             : #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && BITS_IN_JSAMPLE == 12
     298             :             jpeg12_write_scanlines(&sCInfo, &ppSamples, 1);
     299             : #else
     300       10745 :             jpeg_write_scanlines(&sCInfo, &ppSamples, 1);
     301             : #endif
     302             :         }
     303             : 
     304       10745 :         double nCurPixels =
     305       10745 :             static_cast<double>(nBlockYOff) * nBlockYSize * nXSize +
     306       10745 :             static_cast<double>(nBlockXOff) * nBlockYSize * nBlockXSize +
     307       10745 :             (iLine + 1) * nBlockXSizeToRead;
     308       21490 :         if (eErr == CE_None &&
     309       10745 :             !pfnProgress(nCurPixels / nTotalPixels, nullptr, pProgressData))
     310             :         {
     311           0 :             eErr = CE_Failure;
     312           0 :             CPLError(CE_Failure, CPLE_UserInterrupt,
     313             :                      "User terminated CreateCopy()");
     314             :         }
     315             :     }
     316             : 
     317             :     /* -------------------------------------------------------------------- */
     318             :     /*      Cleanup and close.                                              */
     319             :     /* -------------------------------------------------------------------- */
     320          55 :     CPLFree(pabyScanline);
     321             : 
     322          55 :     if (eErr == CE_None)
     323          55 :         jpeg_finish_compress(&sCInfo);
     324          55 :     jpeg_destroy_compress(&sCInfo);
     325             : 
     326          55 :     return eErr == CE_None;
     327             : }
     328             : #endif /* def JPEG_SUPPORTED */

Generated by: LCOV version 1.14