Coverage Report

Created: 2025-06-09 07:43

/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