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