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