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