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