1 /****************************************************************************** 2 * 3 * Project: Raster Matrix Format 4 * Purpose: Implementation of the JPEG decompression algorithm as used in 5 * GIS "Panorama" raster files. 6 * Author: Andrew Sudorgin (drons [a] list dot ru) 7 * 8 ****************************************************************************** 9 * Copyright (c) 2018, Andrew Sudorgin 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 * DEALINGS IN THE SOFTWARE. 28 ****************************************************************************/ 29 30 #ifdef HAVE_LIBJPEG 31 32 #include <algorithm> 33 #include "cpl_conv.h" 34 #include "rmfdataset.h" 35 #include "../mem/memdataset.h" 36 37 /************************************************************************/ 38 /* JPEGDecompress() */ 39 /************************************************************************/ 40 41 size_t RMFDataset::JPEGDecompress(const GByte* pabyIn, GUInt32 nSizeIn, 42 GByte* pabyOut, GUInt32 nSizeOut, 43 GUInt32 nRawXSize, GUInt32 nRawYSize) 44 { 45 if(pabyIn == nullptr || 46 pabyOut == nullptr || 47 nSizeOut < nSizeIn || 48 nSizeIn < 2) 49 return 0; 50 51 CPLString osTmpFilename; 52 VSILFILE* fp; 53 54 osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn); 55 56 fp = VSIFileFromMemBuffer(osTmpFilename, const_cast<GByte*>(pabyIn), 57 nSizeIn, FALSE); 58 59 if(fp == nullptr) 60 { 61 CPLError(CE_Failure, CPLE_AppDefined, 62 "RMF JPEG: Can't create %s file", osTmpFilename.c_str()); 63 return 0; 64 } 65 66 const char* apszAllowedDrivers[] = {"JPEG", nullptr}; 67 GDALDatasetH hTile; 68 69 70 CPLConfigOptionSetter oNoReadDir("GDAL_DISABLE_READDIR_ON_OPEN", 71 "EMPTY_DIR", false); 72 73 hTile = GDALOpenEx(osTmpFilename, GDAL_OF_RASTER | GDAL_OF_INTERNAL, 74 apszAllowedDrivers, nullptr, nullptr); 75 76 if(hTile == nullptr) 77 { 78 CPLError(CE_Failure, CPLE_AppDefined, 79 "RMF JPEG: Can't open %s file", osTmpFilename.c_str()); 80 VSIFCloseL(fp); 81 VSIUnlink(osTmpFilename); 82 return 0; 83 } 84 85 if(GDALGetRasterCount(hTile) != RMF_JPEG_BAND_COUNT) 86 { 87 CPLError(CE_Failure, CPLE_AppDefined, 88 "RMF JPEG: Invalid band count %d in tile, must be %d", 89 GDALGetRasterCount(hTile), (int)RMF_JPEG_BAND_COUNT); 90 GDALClose(hTile); 91 VSIFCloseL(fp); 92 VSIUnlink(osTmpFilename); 93 return 0; 94 } 95 96 int nBandCount = GDALGetRasterCount(hTile); 97 98 int nImageWidth = std::min(GDALGetRasterXSize(hTile), 99 static_cast<int>(nRawXSize)); 100 int nImageHeight = std::min(GDALGetRasterYSize(hTile), 101 static_cast<int>(nRawYSize)); 102 103 if( nRawXSize * nBandCount * nImageHeight > nSizeOut ) 104 { 105 CPLError(CE_Failure, CPLE_AppDefined, 106 "RMF JPEG: Too small output buffer"); 107 GDALClose(hTile); 108 VSIFCloseL(fp); 109 VSIUnlink(osTmpFilename); 110 return 0; 111 } 112 113 CPLErr eErr; 114 size_t nRet; 115 int aBandMap[RMF_JPEG_BAND_COUNT] = {3, 2, 1}; 116 eErr = GDALDatasetRasterIO(hTile, GF_Read, 0, 0, 117 nImageWidth, nImageHeight, pabyOut, 118 nImageWidth, nImageHeight, GDT_Byte, 119 nBandCount, aBandMap, 120 nBandCount, nRawXSize * nBandCount, 1); 121 if(CE_None != eErr) 122 { 123 CPLError(CE_Failure, CPLE_AppDefined, 124 "RMF JPEG: Error decompress JPEG tile"); 125 nRet = 0; 126 } 127 else 128 { 129 nRet = static_cast<size_t>(nRawXSize * nBandCount * nImageHeight); 130 } 131 132 GDALClose(hTile); 133 VSIFCloseL(fp); 134 VSIUnlink(osTmpFilename); 135 136 return nRet; 137 } 138 139 /************************************************************************/ 140 /* JPEGCompress() */ 141 /************************************************************************/ 142 143 size_t RMFDataset::JPEGCompress(const GByte* pabyIn, GUInt32 nSizeIn, 144 GByte* pabyOut, GUInt32 nSizeOut, 145 GUInt32 nRawXSize, GUInt32 nRawYSize, 146 const RMFDataset* poDS) 147 { 148 if(pabyIn == nullptr || 149 pabyOut == nullptr || 150 nSizeIn < 2) 151 return 0; 152 153 GDALDriverH hJpegDriver = GDALGetDriverByName("JPEG"); 154 155 if(hJpegDriver == nullptr) 156 { 157 CPLError(CE_Failure, CPLE_AppDefined, 158 "RMF: JPEG driver not found"); 159 return 0; 160 } 161 162 GDALDataType eType = GDT_Byte; 163 GDALDataset* poMemDS = MEMDataset::Create("", nRawXSize, nRawYSize, 0, 164 eType, nullptr); 165 166 for(int iBand = 0; iBand < RMF_JPEG_BAND_COUNT; ++iBand) 167 { 168 char szBuffer[32] = {}; 169 const GByte* pabyBand = pabyIn + (RMF_JPEG_BAND_COUNT - iBand - 1); 170 int nRet = CPLPrintPointer(szBuffer, (void*)(pabyBand), 171 sizeof(szBuffer)); 172 szBuffer[nRet] = 0; 173 174 char szBuffer0[64] = {}; 175 snprintf( szBuffer0, sizeof(szBuffer0), "DATAPOINTER=%s", szBuffer ); 176 177 char szBuffer1[64] = "PIXELOFFSET=3"; 178 char szBuffer2[64] = {}; 179 snprintf( szBuffer2, sizeof(szBuffer2), 180 "LINEOFFSET=%d", nRawXSize*RMF_JPEG_BAND_COUNT ); 181 182 char* apszOptions[4] = { szBuffer0, szBuffer1, szBuffer2, nullptr }; 183 184 poMemDS->AddBand(eType, apszOptions); 185 } 186 187 CPLString osTmpFilename; 188 osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn); 189 190 char szQuality[32] = {}; 191 if(poDS != nullptr && poDS->sHeader.iJpegQuality > 0) 192 { 193 snprintf(szQuality, sizeof(szQuality), 194 "QUALITY=%d", (int)poDS->sHeader.iJpegQuality); 195 } 196 else 197 { 198 snprintf(szQuality, sizeof(szQuality), "QUALITY=75"); 199 } 200 201 char* apszJpegOptions[2] = {szQuality, nullptr}; 202 203 GDALDatasetH hJpeg = GDALCreateCopy(hJpegDriver, osTmpFilename, poMemDS, 204 0, apszJpegOptions, nullptr, nullptr); 205 GDALClose(poMemDS); 206 207 if(hJpeg == nullptr) 208 { 209 CPLError(CE_Failure, CPLE_AppDefined, 210 "RMF JPEG: Error compress JPEG tile"); 211 VSIUnlink(osTmpFilename); 212 return 0; 213 } 214 215 GDALClose(hJpeg); 216 217 vsi_l_offset nDataLength = 0; 218 GByte* pabyBuffer = VSIGetMemFileBuffer(osTmpFilename, &nDataLength, TRUE); 219 220 if(nDataLength < nSizeOut) 221 { 222 memcpy(pabyOut, pabyBuffer, static_cast<size_t>(nDataLength)); 223 CPLFree(pabyBuffer); 224 return static_cast<size_t>(nDataLength); 225 } 226 227 CPLFree(pabyBuffer); 228 return 0; 229 } 230 #endif //HAVE_LIBJPEG 231