Line data Source code
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 30 : size_t RMFDataset::JPEGDecompress(const GByte *pabyIn, GUInt32 nSizeIn,
42 : GByte *pabyOut, GUInt32 nSizeOut,
43 : GUInt32 nRawXSize, GUInt32 nRawYSize)
44 : {
45 30 : if (pabyIn == nullptr || pabyOut == nullptr || nSizeOut < nSizeIn ||
46 : nSizeIn < 2)
47 0 : return 0;
48 :
49 60 : CPLString osTmpFilename;
50 : VSILFILE *fp;
51 :
52 30 : osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn);
53 :
54 30 : fp = VSIFileFromMemBuffer(osTmpFilename, const_cast<GByte *>(pabyIn),
55 : nSizeIn, FALSE);
56 :
57 30 : if (fp == nullptr)
58 : {
59 0 : CPLError(CE_Failure, CPLE_AppDefined, "RMF JPEG: Can't create %s file",
60 : osTmpFilename.c_str());
61 0 : return 0;
62 : }
63 :
64 30 : const char *apszAllowedDrivers[] = {"JPEG", nullptr};
65 : GDALDatasetH hTile;
66 :
67 : CPLConfigOptionSetter oNoReadDir("GDAL_DISABLE_READDIR_ON_OPEN",
68 60 : "EMPTY_DIR", false);
69 :
70 30 : hTile = GDALOpenEx(osTmpFilename, GDAL_OF_RASTER | GDAL_OF_INTERNAL,
71 : apszAllowedDrivers, nullptr, nullptr);
72 :
73 30 : if (hTile == nullptr)
74 : {
75 0 : CPLError(CE_Failure, CPLE_AppDefined, "RMF JPEG: Can't open %s file",
76 : osTmpFilename.c_str());
77 0 : VSIFCloseL(fp);
78 0 : VSIUnlink(osTmpFilename);
79 0 : return 0;
80 : }
81 :
82 30 : if (GDALGetRasterCount(hTile) != RMF_JPEG_BAND_COUNT)
83 : {
84 0 : CPLError(CE_Failure, CPLE_AppDefined,
85 : "RMF JPEG: Invalid band count %d in tile, must be %d",
86 : GDALGetRasterCount(hTile), (int)RMF_JPEG_BAND_COUNT);
87 0 : GDALClose(hTile);
88 0 : VSIFCloseL(fp);
89 0 : VSIUnlink(osTmpFilename);
90 0 : return 0;
91 : }
92 :
93 30 : int nBandCount = GDALGetRasterCount(hTile);
94 :
95 : int nImageWidth =
96 30 : std::min(GDALGetRasterXSize(hTile), static_cast<int>(nRawXSize));
97 : int nImageHeight =
98 30 : std::min(GDALGetRasterYSize(hTile), static_cast<int>(nRawYSize));
99 :
100 30 : if (nRawXSize * nBandCount * nImageHeight > nSizeOut)
101 : {
102 0 : CPLError(CE_Failure, CPLE_AppDefined,
103 : "RMF JPEG: Too small output buffer");
104 0 : GDALClose(hTile);
105 0 : VSIFCloseL(fp);
106 0 : VSIUnlink(osTmpFilename);
107 0 : return 0;
108 : }
109 :
110 : CPLErr eErr;
111 : size_t nRet;
112 30 : int aBandMap[RMF_JPEG_BAND_COUNT] = {3, 2, 1};
113 60 : eErr = GDALDatasetRasterIO(hTile, GF_Read, 0, 0, nImageWidth, nImageHeight,
114 : pabyOut, nImageWidth, nImageHeight, GDT_Byte,
115 : nBandCount, aBandMap, nBandCount,
116 30 : nRawXSize * nBandCount, 1);
117 30 : if (CE_None != eErr)
118 : {
119 0 : CPLError(CE_Failure, CPLE_AppDefined,
120 : "RMF JPEG: Error decompress JPEG tile");
121 0 : nRet = 0;
122 : }
123 : else
124 : {
125 30 : nRet = static_cast<size_t>(nRawXSize * nBandCount * nImageHeight);
126 : }
127 :
128 30 : GDALClose(hTile);
129 30 : VSIFCloseL(fp);
130 30 : VSIUnlink(osTmpFilename);
131 :
132 30 : return nRet;
133 : }
134 :
135 : /************************************************************************/
136 : /* JPEGCompress() */
137 : /************************************************************************/
138 :
139 2 : size_t RMFDataset::JPEGCompress(const GByte *pabyIn, GUInt32 nSizeIn,
140 : GByte *pabyOut, GUInt32 nSizeOut,
141 : GUInt32 nRawXSize, GUInt32 nRawYSize,
142 : const RMFDataset *poDS)
143 : {
144 2 : if (pabyIn == nullptr || pabyOut == nullptr || nSizeIn < 2)
145 0 : return 0;
146 :
147 2 : GDALDriverH hJpegDriver = GDALGetDriverByName("JPEG");
148 :
149 2 : if (hJpegDriver == nullptr)
150 : {
151 0 : CPLError(CE_Failure, CPLE_AppDefined, "RMF: JPEG driver not found");
152 0 : return 0;
153 : }
154 :
155 2 : const GDALDataType eType = GDT_Byte;
156 : auto poMemDS = std::unique_ptr<MEMDataset>(
157 4 : MEMDataset::Create("", nRawXSize, nRawYSize, 0, eType, nullptr));
158 :
159 8 : for (int iBand = 0; iBand < RMF_JPEG_BAND_COUNT; ++iBand)
160 : {
161 6 : const GByte *pabyBand = pabyIn + (RMF_JPEG_BAND_COUNT - iBand - 1);
162 6 : auto hBand = MEMCreateRasterBandEx(
163 6 : poMemDS.get(), iBand + 1, const_cast<GByte *>(pabyBand), eType, 3,
164 6 : nRawXSize * RMF_JPEG_BAND_COUNT, false);
165 6 : poMemDS->AddMEMBand(hBand);
166 : }
167 :
168 4 : CPLString osTmpFilename;
169 2 : osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn);
170 :
171 2 : char szQuality[32] = {};
172 2 : if (poDS != nullptr && poDS->sHeader.iJpegQuality > 0)
173 : {
174 2 : snprintf(szQuality, sizeof(szQuality), "QUALITY=%d",
175 2 : (int)poDS->sHeader.iJpegQuality);
176 : }
177 : else
178 : {
179 0 : snprintf(szQuality, sizeof(szQuality), "QUALITY=75");
180 : }
181 :
182 2 : char *apszJpegOptions[2] = {szQuality, nullptr};
183 :
184 : GDALDatasetH hJpeg =
185 2 : GDALCreateCopy(hJpegDriver, osTmpFilename, poMemDS.get(), 0,
186 : apszJpegOptions, nullptr, nullptr);
187 2 : poMemDS.reset();
188 :
189 2 : if (hJpeg == nullptr)
190 : {
191 0 : CPLError(CE_Failure, CPLE_AppDefined,
192 : "RMF JPEG: Error compress JPEG tile");
193 0 : VSIUnlink(osTmpFilename);
194 0 : return 0;
195 : }
196 :
197 2 : GDALClose(hJpeg);
198 :
199 2 : vsi_l_offset nDataLength = 0;
200 2 : GByte *pabyBuffer = VSIGetMemFileBuffer(osTmpFilename, &nDataLength, TRUE);
201 :
202 2 : if (nDataLength < nSizeOut)
203 : {
204 2 : memcpy(pabyOut, pabyBuffer, static_cast<size_t>(nDataLength));
205 2 : CPLFree(pabyBuffer);
206 2 : return static_cast<size_t>(nDataLength);
207 : }
208 :
209 0 : CPLFree(pabyBuffer);
210 0 : return 0;
211 : }
212 : #endif // HAVE_LIBJPEG
|