Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: KRO format reader/writer
4 : * Purpose: Implementation of KOLOR Raw Format
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : * Financial Support: SITES (http://www.sites.fr)
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "gdal_frmts.h"
16 : #include "gdal_priv.h"
17 : #include "rawdataset.h"
18 :
19 : #include <algorithm>
20 :
21 : // http://www.autopano.net/wiki-en/Format_KRO
22 :
23 : /************************************************************************/
24 : /* ==================================================================== */
25 : /* KRODataset */
26 : /* ==================================================================== */
27 : /************************************************************************/
28 :
29 : class KRODataset final : public RawDataset
30 : {
31 : VSILFILE *fpImage = nullptr; // image data file.
32 :
33 : CPL_DISALLOW_COPY_ASSIGN(KRODataset)
34 :
35 : CPLErr Close() override;
36 :
37 : public:
38 37 : KRODataset() = default;
39 : ~KRODataset() override;
40 :
41 : static GDALDataset *Open(GDALOpenInfo *);
42 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
43 : int nBandsIn, GDALDataType eType,
44 : char **papszOptions);
45 : static int Identify(GDALOpenInfo *);
46 : };
47 :
48 : /************************************************************************/
49 : /* ==================================================================== */
50 : /* KRODataset */
51 : /* ==================================================================== */
52 : /************************************************************************/
53 :
54 : /************************************************************************/
55 : /* ~KRODataset() */
56 : /************************************************************************/
57 :
58 74 : KRODataset::~KRODataset()
59 :
60 : {
61 37 : KRODataset::Close();
62 74 : }
63 :
64 : /************************************************************************/
65 : /* Close() */
66 : /************************************************************************/
67 :
68 74 : CPLErr KRODataset::Close()
69 : {
70 74 : CPLErr eErr = CE_None;
71 74 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
72 : {
73 37 : if (KRODataset::FlushCache(true) != CE_None)
74 0 : eErr = CE_Failure;
75 :
76 37 : if (fpImage)
77 : {
78 37 : if (VSIFCloseL(fpImage) != 0)
79 : {
80 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
81 0 : eErr = CE_Failure;
82 : }
83 : }
84 :
85 37 : if (GDALPamDataset::Close() != CE_None)
86 0 : eErr = CE_Failure;
87 : }
88 74 : return eErr;
89 : }
90 :
91 : /************************************************************************/
92 : /* Identify() */
93 : /************************************************************************/
94 :
95 59028 : int KRODataset::Identify(GDALOpenInfo *poOpenInfo)
96 :
97 : {
98 59028 : if (poOpenInfo->nHeaderBytes < 20)
99 55242 : return FALSE;
100 :
101 3786 : if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
102 : "KRO\x01"))
103 3712 : return FALSE;
104 :
105 74 : return TRUE;
106 : }
107 :
108 : /************************************************************************/
109 : /* Open() */
110 : /************************************************************************/
111 :
112 37 : GDALDataset *KRODataset::Open(GDALOpenInfo *poOpenInfo)
113 :
114 : {
115 37 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
116 0 : return nullptr;
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Create a corresponding GDALDataset. */
120 : /* -------------------------------------------------------------------- */
121 74 : auto poDS = std::make_unique<KRODataset>();
122 37 : poDS->eAccess = poOpenInfo->eAccess;
123 37 : std::swap(poDS->fpImage, poOpenInfo->fpL);
124 :
125 : /* -------------------------------------------------------------------- */
126 : /* Read the file header. */
127 : /* -------------------------------------------------------------------- */
128 37 : char achHeader[20] = {'\0'};
129 37 : CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 20, poDS->fpImage));
130 :
131 : int nXSize;
132 37 : memcpy(&nXSize, achHeader + 4, 4);
133 37 : CPL_MSBPTR32(&nXSize);
134 :
135 37 : int nYSize = 0;
136 37 : memcpy(&nYSize, achHeader + 8, 4);
137 37 : CPL_MSBPTR32(&nYSize);
138 :
139 37 : int nDepth = 0;
140 37 : memcpy(&nDepth, achHeader + 12, 4);
141 37 : CPL_MSBPTR32(&nDepth);
142 :
143 37 : int nComp = 0;
144 37 : memcpy(&nComp, achHeader + 16, 4);
145 37 : CPL_MSBPTR32(&nComp);
146 :
147 74 : if (!GDALCheckDatasetDimensions(nXSize, nYSize) ||
148 37 : !GDALCheckBandCount(nComp, FALSE))
149 : {
150 0 : return nullptr;
151 : }
152 :
153 37 : poDS->nRasterXSize = nXSize;
154 37 : poDS->nRasterYSize = nYSize;
155 :
156 37 : GDALDataType eDT = GDT_Unknown;
157 37 : if (nDepth == 8)
158 : {
159 18 : eDT = GDT_Byte;
160 : }
161 19 : else if (nDepth == 16)
162 : {
163 11 : eDT = GDT_UInt16;
164 : }
165 8 : else if (nDepth == 32)
166 : {
167 8 : eDT = GDT_Float32;
168 : }
169 : else
170 : {
171 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unhandled depth : %d", nDepth);
172 0 : return nullptr;
173 : }
174 :
175 37 : const int nDataTypeSize = nDepth / 8;
176 :
177 74 : if (nComp == 0 || nDataTypeSize == 0 ||
178 37 : poDS->nRasterXSize > INT_MAX / (nComp * nDataTypeSize))
179 : {
180 0 : CPLError(CE_Failure, CPLE_AppDefined,
181 : "Too large width / number of bands");
182 0 : return nullptr;
183 : }
184 :
185 37 : vsi_l_offset nExpectedSize = static_cast<vsi_l_offset>(poDS->nRasterXSize) *
186 37 : poDS->nRasterYSize * nComp *
187 37 : nDataTypeSize +
188 37 : 20;
189 37 : VSIFSeekL(poDS->fpImage, 0, SEEK_END);
190 37 : if (VSIFTellL(poDS->fpImage) < nExpectedSize)
191 : {
192 0 : CPLError(CE_Failure, CPLE_FileIO, "File too short");
193 0 : return nullptr;
194 : }
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Create bands. */
198 : /* -------------------------------------------------------------------- */
199 112 : for (int iBand = 0; iBand < nComp; iBand++)
200 : {
201 : auto poBand = RawRasterBand::Create(
202 150 : poDS.get(), iBand + 1, poDS->fpImage, 20 + nDataTypeSize * iBand,
203 75 : nComp * nDataTypeSize, poDS->nRasterXSize * nComp * nDataTypeSize,
204 : eDT, RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
205 75 : RawRasterBand::OwnFP::NO);
206 75 : if (!poBand)
207 0 : return nullptr;
208 75 : if (nComp == 3 || nComp == 4)
209 : {
210 33 : poBand->SetColorInterpretation(
211 33 : static_cast<GDALColorInterp>(GCI_RedBand + iBand));
212 : }
213 75 : poDS->SetBand(iBand + 1, std::move(poBand));
214 : }
215 :
216 37 : if (nComp > 1)
217 16 : poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Initialize any PAM information. */
221 : /* -------------------------------------------------------------------- */
222 37 : poDS->SetDescription(poOpenInfo->pszFilename);
223 37 : poDS->TryLoadXML();
224 :
225 : /* -------------------------------------------------------------------- */
226 : /* Check for overviews. */
227 : /* -------------------------------------------------------------------- */
228 37 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
229 :
230 37 : return poDS.release();
231 : }
232 :
233 : /************************************************************************/
234 : /* Create() */
235 : /************************************************************************/
236 :
237 64 : GDALDataset *KRODataset::Create(const char *pszFilename, int nXSize, int nYSize,
238 : int nBandsIn, GDALDataType eType,
239 : char ** /* papszOptions */)
240 : {
241 64 : if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Float32)
242 : {
243 30 : CPLError(CE_Failure, CPLE_AppDefined,
244 : "Attempt to create KRO file with unsupported data type '%s'.",
245 : GDALGetDataTypeName(eType));
246 30 : return nullptr;
247 : }
248 34 : if (nXSize == 0 || nYSize == 0 || nBandsIn == 0)
249 : {
250 1 : return nullptr;
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Try to create file. */
255 : /* -------------------------------------------------------------------- */
256 33 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
257 33 : if (fp == nullptr)
258 : {
259 3 : CPLError(CE_Failure, CPLE_OpenFailed,
260 : "Attempt to create file `%s' failed.", pszFilename);
261 3 : return nullptr;
262 : }
263 :
264 30 : size_t nRet = VSIFWriteL("KRO\01", 4, 1, fp);
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Create a file level header. */
268 : /* -------------------------------------------------------------------- */
269 30 : int nTmp = nXSize;
270 30 : CPL_MSBPTR32(&nTmp);
271 30 : nRet += VSIFWriteL(&nTmp, 4, 1, fp);
272 :
273 30 : nTmp = nYSize;
274 30 : CPL_MSBPTR32(&nTmp);
275 30 : nRet += VSIFWriteL(&nTmp, 4, 1, fp);
276 :
277 30 : nTmp = GDALGetDataTypeSizeBits(eType);
278 30 : CPL_MSBPTR32(&nTmp);
279 30 : nRet += VSIFWriteL(&nTmp, 4, 1, fp);
280 :
281 30 : nTmp = nBandsIn;
282 30 : CPL_MSBPTR32(&nTmp);
283 30 : nRet += VSIFWriteL(&nTmp, 4, 1, fp);
284 :
285 : /* -------------------------------------------------------------------- */
286 : /* Zero out image data */
287 : /* -------------------------------------------------------------------- */
288 :
289 30 : CPL_IGNORE_RET_VAL(VSIFSeekL(fp,
290 60 : static_cast<vsi_l_offset>(nXSize) * nYSize *
291 30 : GDALGetDataTypeSizeBytes(eType) *
292 30 : nBandsIn -
293 : 1,
294 : SEEK_CUR));
295 30 : GByte byNul = 0;
296 30 : nRet += VSIFWriteL(&byNul, 1, 1, fp);
297 30 : if (VSIFCloseL(fp) != 0)
298 : {
299 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
300 0 : return nullptr;
301 : }
302 :
303 30 : if (nRet != 6)
304 10 : return nullptr;
305 :
306 20 : return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
307 : }
308 :
309 : /************************************************************************/
310 : /* GDALRegister_KRO() */
311 : /************************************************************************/
312 :
313 2033 : void GDALRegister_KRO()
314 :
315 : {
316 2033 : if (GDALGetDriverByName("KRO") != nullptr)
317 283 : return;
318 :
319 1750 : GDALDriver *poDriver = new GDALDriver();
320 :
321 1750 : poDriver->SetDescription("KRO");
322 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
323 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "KOLOR Raw");
324 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kro");
325 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
326 1750 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
327 1750 : "Byte UInt16 Float32");
328 :
329 1750 : poDriver->pfnIdentify = KRODataset::Identify;
330 1750 : poDriver->pfnOpen = KRODataset::Open;
331 1750 : poDriver->pfnCreate = KRODataset::Create;
332 :
333 1750 : GetGDALDriverManager()->RegisterDriver(poDriver);
334 : }
|