Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: CALS driver
4 : * Purpose: CALS driver
5 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal_frmts.h"
14 : #include "gdal_pam.h"
15 : #include "gdal_priv.h"
16 :
17 : #include "tiff.h"
18 :
19 : /************************************************************************/
20 : /* ==================================================================== */
21 : /* CALSDataset */
22 : /* ==================================================================== */
23 : /************************************************************************/
24 :
25 : class CALSDataset final : public GDALPamDataset
26 : {
27 : friend class CALSRasterBand;
28 :
29 : CPLString osTIFFHeaderFilename;
30 : CPLString osSparseFilename;
31 : GDALDataset *poUnderlyingDS;
32 :
33 : static void WriteLEInt16(VSILFILE *fp, GInt16 nVal);
34 : static void WriteLEInt32(VSILFILE *fp, GInt32 nVal);
35 : static void WriteTIFFTAG(VSILFILE *fp, GInt16 nTagName, GInt16 nTagType,
36 : GInt32 nTagValue);
37 :
38 : public:
39 9 : CALSDataset() : poUnderlyingDS(nullptr)
40 : {
41 9 : }
42 :
43 : ~CALSDataset();
44 :
45 : static int Identify(GDALOpenInfo *poOpenInfo);
46 : static GDALDataset *Open(GDALOpenInfo *);
47 : static GDALDataset *CreateCopy(const char *pszFilename,
48 : GDALDataset *poSrcDS, int bStrict,
49 : char **papszOptions,
50 : GDALProgressFunc pfnProgress,
51 : void *pProgressData);
52 : };
53 :
54 : /************************************************************************/
55 : /* ==================================================================== */
56 : /* CALSRasterBand */
57 : /* ==================================================================== */
58 : /************************************************************************/
59 :
60 : class CALSRasterBand final : public GDALPamRasterBand
61 : {
62 : GDALRasterBand *poUnderlyingBand;
63 :
64 : public:
65 9 : explicit CALSRasterBand(CALSDataset *poDSIn)
66 9 : {
67 9 : poDS = poDSIn;
68 9 : poUnderlyingBand = poDSIn->poUnderlyingDS->GetRasterBand(1);
69 9 : poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
70 9 : nBand = 1;
71 9 : eDataType = GDT_Byte;
72 9 : }
73 :
74 : CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
75 :
76 6 : CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
77 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
78 : GDALDataType eBufType, GSpacing nPixelSpace,
79 : GSpacing nLineSpace,
80 : GDALRasterIOExtraArg *psExtraArg) override
81 : {
82 6 : return poUnderlyingBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
83 : pData, nBufXSize, nBufYSize, eBufType,
84 6 : nPixelSpace, nLineSpace, psExtraArg);
85 : }
86 :
87 1 : GDALColorTable *GetColorTable() override
88 : {
89 1 : return poUnderlyingBand->GetColorTable();
90 : }
91 :
92 1 : GDALColorInterp GetColorInterpretation() override
93 : {
94 1 : return GCI_PaletteIndex;
95 : }
96 :
97 0 : char **GetMetadata(const char *pszDomain) override
98 : {
99 0 : return poUnderlyingBand->GetMetadata(pszDomain);
100 : }
101 :
102 6 : const char *GetMetadataItem(const char *pszKey,
103 : const char *pszDomain) override
104 : {
105 6 : if (!m_bEnablePixelTypeSignedByteWarning)
106 4 : poUnderlyingBand->EnablePixelTypeSignedByteWarning(false);
107 : const char *pszRet =
108 6 : poUnderlyingBand->GetMetadataItem(pszKey, pszDomain);
109 6 : poUnderlyingBand->EnablePixelTypeSignedByteWarning(true);
110 6 : return pszRet;
111 : }
112 : };
113 :
114 4 : CPLErr CALSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pData)
115 : {
116 4 : return poUnderlyingBand->ReadBlock(nBlockXOff, nBlockYOff, pData);
117 : }
118 :
119 : /************************************************************************/
120 : /* ==================================================================== */
121 : /* CALSWrapperSrcBand */
122 : /* ==================================================================== */
123 : /************************************************************************/
124 :
125 : class CALSWrapperSrcBand final : public GDALPamRasterBand
126 : {
127 : GDALDataset *poSrcDS;
128 : bool bInvertValues;
129 :
130 : public:
131 7 : explicit CALSWrapperSrcBand(GDALDataset *poSrcDSIn)
132 7 : {
133 7 : poSrcDS = poSrcDSIn;
134 7 : SetMetadataItem("NBITS", "1", "IMAGE_STRUCTURE");
135 7 : poSrcDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
136 7 : eDataType = GDT_Byte;
137 7 : bInvertValues = true;
138 7 : GDALColorTable *poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
139 7 : if (poCT != nullptr && poCT->GetColorEntryCount() >= 2)
140 : {
141 3 : const GDALColorEntry *psEntry1 = poCT->GetColorEntry(0);
142 3 : const GDALColorEntry *psEntry2 = poCT->GetColorEntry(1);
143 3 : if (psEntry1->c1 == 255 && psEntry1->c2 == 255 &&
144 1 : psEntry1->c3 == 255 && psEntry2->c1 == 0 && psEntry2->c2 == 0 &&
145 1 : psEntry2->c3 == 0)
146 : {
147 1 : bInvertValues = false;
148 : }
149 : }
150 7 : }
151 :
152 0 : CPLErr IReadBlock(int /* nBlockXOff */, int /* nBlockYOff */,
153 : void * /* pData */) override
154 : {
155 : // Should not be called.
156 0 : return CE_Failure;
157 : }
158 :
159 : CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
160 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
161 : GDALDataType eBufType, GSpacing nPixelSpace,
162 : GSpacing nLineSpace,
163 : GDALRasterIOExtraArg *psExtraArg) override;
164 : };
165 :
166 5 : CPLErr CALSWrapperSrcBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
167 : int nXSize, int nYSize, void *pData,
168 : int nBufXSize, int nBufYSize,
169 : GDALDataType eBufType,
170 : GSpacing nPixelSpace, GSpacing nLineSpace,
171 : GDALRasterIOExtraArg *psExtraArg)
172 : {
173 5 : const CPLErr eErr = poSrcDS->GetRasterBand(1)->RasterIO(
174 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
175 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
176 5 : if (bInvertValues)
177 : {
178 503 : for (int j = 0; j < nBufYSize; j++)
179 : {
180 110102 : for (int i = 0; i < nBufXSize; i++)
181 109603 : ((GByte *)pData)[j * nLineSpace + i * nPixelSpace] =
182 109603 : 1 - ((GByte *)pData)[j * nLineSpace + i * nPixelSpace];
183 : }
184 : }
185 5 : return eErr;
186 : }
187 :
188 : /************************************************************************/
189 : /* ==================================================================== */
190 : /* CALSWrapperSrcDataset */
191 : /* ==================================================================== */
192 : /************************************************************************/
193 :
194 14 : class CALSWrapperSrcDataset final : public GDALPamDataset
195 : {
196 : public:
197 7 : CALSWrapperSrcDataset(GDALDataset *poSrcDS, const char *pszPadding)
198 7 : {
199 7 : nRasterXSize = poSrcDS->GetRasterXSize();
200 7 : nRasterYSize = poSrcDS->GetRasterYSize();
201 7 : SetBand(1, new CALSWrapperSrcBand(poSrcDS));
202 7 : SetMetadataItem("TIFFTAG_DOCUMENTNAME", pszPadding);
203 7 : }
204 :
205 : ~CALSWrapperSrcDataset() override;
206 : };
207 :
208 : CALSWrapperSrcDataset::~CALSWrapperSrcDataset() = default;
209 :
210 : /************************************************************************/
211 : /* ==================================================================== */
212 : /* CALSDataset */
213 : /* ==================================================================== */
214 : /************************************************************************/
215 :
216 : /************************************************************************/
217 : /* ~CALSDataset() */
218 : /************************************************************************/
219 :
220 18 : CALSDataset::~CALSDataset()
221 :
222 : {
223 9 : delete poUnderlyingDS;
224 9 : if (!osTIFFHeaderFilename.empty())
225 9 : VSIUnlink(osTIFFHeaderFilename);
226 9 : if (!osSparseFilename.empty())
227 9 : VSIUnlink(osSparseFilename);
228 18 : }
229 :
230 : /************************************************************************/
231 : /* Identify() */
232 : /************************************************************************/
233 :
234 58381 : int CALSDataset::Identify(GDALOpenInfo *poOpenInfo)
235 :
236 : {
237 : // If in the ingested bytes we found neither srcdocid: or rtype: 1, give up
238 58381 : if (poOpenInfo->nHeaderBytes == 0 ||
239 4254 : (strstr((const char *)poOpenInfo->pabyHeader, "srcdocid:") == nullptr &&
240 4241 : strstr((const char *)poOpenInfo->pabyHeader, "rtype: 1") == nullptr))
241 58368 : return FALSE;
242 :
243 : // If we found srcdocid: try to ingest up to 2048 bytes
244 26 : if (strstr((const char *)poOpenInfo->pabyHeader, "srcdocid:") &&
245 13 : !poOpenInfo->TryToIngest(2048))
246 0 : return FALSE;
247 :
248 13 : return strstr((const char *)poOpenInfo->pabyHeader, "rtype: 1") !=
249 13 : nullptr &&
250 13 : strstr((const char *)poOpenInfo->pabyHeader, "rorient:") !=
251 26 : nullptr &&
252 26 : strstr((const char *)poOpenInfo->pabyHeader, "rpelcnt:") != nullptr;
253 : }
254 :
255 : /************************************************************************/
256 : /* WriteLEInt16() */
257 : /************************************************************************/
258 :
259 207 : void CALSDataset::WriteLEInt16(VSILFILE *fp, GInt16 nVal)
260 : {
261 207 : CPL_LSBPTR16(&nVal);
262 207 : VSIFWriteL(&nVal, 1, 2, fp);
263 207 : }
264 :
265 : /************************************************************************/
266 : /* WriteLEInt32() */
267 : /************************************************************************/
268 :
269 198 : void CALSDataset::WriteLEInt32(VSILFILE *fp, GInt32 nVal)
270 : {
271 198 : CPL_LSBPTR32(&nVal);
272 198 : VSIFWriteL(&nVal, 1, 4, fp);
273 198 : }
274 :
275 : /************************************************************************/
276 : /* WriteTIFFTAG() */
277 : /************************************************************************/
278 :
279 90 : void CALSDataset::WriteTIFFTAG(VSILFILE *fp, GInt16 nTagName, GInt16 nTagType,
280 : GInt32 nTagValue)
281 : {
282 90 : WriteLEInt16(fp, nTagName);
283 90 : WriteLEInt16(fp, nTagType);
284 90 : WriteLEInt32(fp, 1);
285 90 : WriteLEInt32(fp, nTagValue);
286 90 : }
287 :
288 : /************************************************************************/
289 : /* Open() */
290 : /************************************************************************/
291 :
292 9 : GDALDataset *CALSDataset::Open(GDALOpenInfo *poOpenInfo)
293 :
294 : {
295 9 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
296 0 : return nullptr;
297 :
298 : const char *pszRPelCnt =
299 9 : strstr((const char *)poOpenInfo->pabyHeader, "rpelcnt:");
300 9 : int nXSize = 0;
301 9 : int nYSize = 0;
302 18 : if (sscanf(pszRPelCnt + strlen("rpelcnt:"), "%d,%d", &nXSize, &nYSize) !=
303 9 : 2 ||
304 9 : nXSize <= 0 || nYSize <= 0)
305 0 : return nullptr;
306 :
307 : const char *pszOrient =
308 9 : strstr((const char *)poOpenInfo->pabyHeader, "rorient:");
309 : int nAngle1, nAngle2;
310 9 : if (sscanf(pszOrient + strlen("rorient:"), "%d,%d", &nAngle1, &nAngle2) !=
311 : 2)
312 0 : return nullptr;
313 :
314 : const char *pszDensity =
315 9 : strstr((const char *)poOpenInfo->pabyHeader, "rdensty:");
316 9 : int nDensity = 0;
317 9 : if (pszDensity)
318 9 : sscanf(pszDensity + strlen("rdensty:"), "%d", &nDensity);
319 :
320 9 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_END);
321 9 : int nFAX4BlobSize = static_cast<int>(VSIFTellL(poOpenInfo->fpL)) - 2048;
322 9 : if (nFAX4BlobSize < 0)
323 0 : return nullptr;
324 :
325 9 : CALSDataset *poDS = new CALSDataset();
326 9 : poDS->nRasterXSize = nXSize;
327 9 : poDS->nRasterYSize = nYSize;
328 :
329 : // Create a TIFF header for a single-strip CCITTFAX4 file.
330 : poDS->osTIFFHeaderFilename =
331 9 : VSIMemGenerateHiddenFilename("cals_header.tiff");
332 9 : VSILFILE *fp = VSIFOpenL(poDS->osTIFFHeaderFilename, "wb");
333 9 : const int nTagCount = 10;
334 9 : const int nHeaderSize = 4 + 4 + 2 + nTagCount * 12 + 4;
335 9 : WriteLEInt16(fp, TIFF_LITTLEENDIAN); // TIFF little-endian signature.
336 9 : WriteLEInt16(fp, 42); // TIFF classic.
337 :
338 9 : WriteLEInt32(fp, 8); // Offset of IFD0.
339 :
340 9 : WriteLEInt16(fp, nTagCount); // Number of entries.
341 :
342 9 : WriteTIFFTAG(fp, TIFFTAG_IMAGEWIDTH, TIFF_LONG, nXSize);
343 9 : WriteTIFFTAG(fp, TIFFTAG_IMAGELENGTH, TIFF_LONG, nYSize);
344 9 : WriteTIFFTAG(fp, TIFFTAG_BITSPERSAMPLE, TIFF_SHORT, 1);
345 9 : WriteTIFFTAG(fp, TIFFTAG_COMPRESSION, TIFF_SHORT, COMPRESSION_CCITTFAX4);
346 9 : WriteTIFFTAG(fp, TIFFTAG_PHOTOMETRIC, TIFF_SHORT, PHOTOMETRIC_MINISWHITE);
347 9 : WriteTIFFTAG(fp, TIFFTAG_STRIPOFFSETS, TIFF_LONG, nHeaderSize);
348 9 : WriteTIFFTAG(fp, TIFFTAG_SAMPLESPERPIXEL, TIFF_SHORT, 1);
349 9 : WriteTIFFTAG(fp, TIFFTAG_ROWSPERSTRIP, TIFF_LONG, nYSize);
350 9 : WriteTIFFTAG(fp, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG, nFAX4BlobSize);
351 9 : WriteTIFFTAG(fp, TIFFTAG_PLANARCONFIG, TIFF_SHORT, PLANARCONFIG_CONTIG);
352 :
353 9 : WriteLEInt32(fp, 0); // Offset of next IFD.
354 :
355 9 : VSIFCloseL(fp);
356 :
357 : // Create a /vsisparse/ description file assembling the TIFF header
358 : // with the FAX4 codestream that starts at offset 2048 of the CALS file.
359 9 : poDS->osSparseFilename = VSIMemGenerateHiddenFilename("cals_sparse.xml");
360 9 : fp = VSIFOpenL(poDS->osSparseFilename, "wb");
361 9 : CPLAssert(fp);
362 9 : VSIFPrintfL(fp,
363 : "<VSISparseFile>"
364 : "<Length>%d</Length>"
365 : "<SubfileRegion>"
366 : "<Filename relative='0'>%s</Filename>"
367 : "<DestinationOffset>0</DestinationOffset>"
368 : "<SourceOffset>0</SourceOffset>"
369 : "<RegionLength>%d</RegionLength>"
370 : "</SubfileRegion>"
371 : "<SubfileRegion>"
372 : "<Filename relative='0'>%s</Filename>"
373 : "<DestinationOffset>%d</DestinationOffset>"
374 : "<SourceOffset>%d</SourceOffset>"
375 : "<RegionLength>%d</RegionLength>"
376 : "</SubfileRegion>"
377 : "</VSISparseFile>",
378 : nHeaderSize + nFAX4BlobSize, poDS->osTIFFHeaderFilename.c_str(),
379 : nHeaderSize, poOpenInfo->pszFilename, nHeaderSize, 2048,
380 : nFAX4BlobSize);
381 9 : VSIFCloseL(fp);
382 :
383 9 : poDS->poUnderlyingDS = (GDALDataset *)GDALOpenEx(
384 : CPLSPrintf("/vsisparse/%s", poDS->osSparseFilename.c_str()),
385 : GDAL_OF_RASTER | GDAL_OF_INTERNAL, nullptr, nullptr, nullptr);
386 9 : if (poDS->poUnderlyingDS == nullptr)
387 : {
388 0 : delete poDS;
389 0 : return nullptr;
390 : }
391 :
392 9 : if (nAngle1 != 0 || nAngle2 != 270)
393 : {
394 1 : poDS->SetMetadataItem("PIXEL_PATH", CPLSPrintf("%d", nAngle1));
395 1 : poDS->SetMetadataItem("LINE_PROGRESSION", CPLSPrintf("%d", nAngle2));
396 : }
397 :
398 9 : if (nDensity != 0)
399 : {
400 9 : poDS->SetMetadataItem("TIFFTAG_XRESOLUTION",
401 9 : CPLSPrintf("%d", nDensity));
402 9 : poDS->SetMetadataItem("TIFFTAG_YRESOLUTION",
403 9 : CPLSPrintf("%d", nDensity));
404 9 : poDS->SetMetadataItem("TIFFTAG_RESOLUTIONUNIT", "2 (pixels/inch)");
405 : }
406 :
407 9 : poDS->SetBand(1, new CALSRasterBand(poDS));
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Initialize any PAM information. */
411 : /* -------------------------------------------------------------------- */
412 9 : poDS->SetDescription(poOpenInfo->pszFilename);
413 9 : poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
414 :
415 : /* -------------------------------------------------------------------- */
416 : /* Open overviews. */
417 : /* -------------------------------------------------------------------- */
418 18 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
419 9 : poOpenInfo->GetSiblingFiles());
420 :
421 9 : return poDS;
422 : }
423 :
424 : /************************************************************************/
425 : /* CreateCopy() */
426 : /************************************************************************/
427 :
428 28 : GDALDataset *CALSDataset::CreateCopy(const char *pszFilename,
429 : GDALDataset *poSrcDS, int bStrict,
430 : char ** /* papszOptionsUnused */,
431 : GDALProgressFunc pfnProgress,
432 : void *pProgressData)
433 : {
434 51 : if (poSrcDS->GetRasterCount() == 0 ||
435 23 : (bStrict && poSrcDS->GetRasterCount() != 1))
436 : {
437 7 : CPLError(CE_Failure, CPLE_NotSupported,
438 : "CALS driver only supports single band raster.");
439 7 : return nullptr;
440 : }
441 21 : if (poSrcDS->GetRasterBand(1)->GetMetadataItem(
442 28 : "NBITS", "IMAGE_STRUCTURE") == nullptr ||
443 7 : !EQUAL(poSrcDS->GetRasterBand(1)->GetMetadataItem("NBITS",
444 : "IMAGE_STRUCTURE"),
445 : "1"))
446 : {
447 14 : CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_NotSupported,
448 : "CALS driver only supports 1-bit.");
449 14 : if (bStrict)
450 13 : return nullptr;
451 : }
452 :
453 15 : if (poSrcDS->GetRasterXSize() > 999999 ||
454 7 : poSrcDS->GetRasterYSize() > 999999)
455 : {
456 1 : CPLError(
457 : CE_Failure, CPLE_NotSupported,
458 : "CALS driver only supports datasets with dimension <= 999999.");
459 1 : return nullptr;
460 : }
461 :
462 : GDALDriver *poGTiffDrv =
463 7 : static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
464 7 : if (poGTiffDrv == nullptr)
465 : {
466 0 : CPLError(CE_Failure, CPLE_NotSupported,
467 : "CALS driver needs GTiff driver.");
468 0 : return nullptr;
469 : }
470 :
471 : // Write a in-memory TIFF with just the TIFF header to figure out
472 : // how large it will be.
473 : const CPLString osTmpFilename(
474 14 : VSIMemGenerateHiddenFilename("tmp_tif_header"));
475 7 : char **papszOptions = nullptr;
476 7 : papszOptions = CSLSetNameValue(papszOptions, "COMPRESS", "CCITTFAX4");
477 7 : papszOptions = CSLSetNameValue(papszOptions, "NBITS", "1");
478 7 : papszOptions = CSLSetNameValue(papszOptions, "BLOCKYSIZE",
479 : CPLSPrintf("%d", poSrcDS->GetRasterYSize()));
480 7 : papszOptions = CSLSetNameValue(papszOptions, "SPARSE_OK", "YES");
481 7 : GDALDataset *poDS = poGTiffDrv->Create(
482 : osTmpFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), 1,
483 : GDT_Byte, papszOptions);
484 7 : if (poDS == nullptr)
485 : {
486 : // Should not happen normally (except if CCITTFAX4 not available).
487 0 : CSLDestroy(papszOptions);
488 0 : return nullptr;
489 : }
490 7 : const char INITIAL_PADDING[] = "12345";
491 : // To adjust padding.
492 7 : poDS->SetMetadataItem("TIFFTAG_DOCUMENTNAME", INITIAL_PADDING);
493 7 : GDALClose(poDS);
494 : VSIStatBufL sStat;
495 7 : if (VSIStatL(osTmpFilename, &sStat) != 0)
496 : {
497 : // Shouldn't happen really. Just to make Coverity happy.
498 0 : CSLDestroy(papszOptions);
499 0 : return nullptr;
500 : }
501 7 : int nTIFFHeaderSize = static_cast<int>(sStat.st_size);
502 7 : VSIUnlink(osTmpFilename);
503 :
504 : // Redo the same thing, but this time write it to the output file
505 : // and use a variable TIFF tag (TIFFTAG_DOCUMENTNAME) to enlarge the
506 : // header + the variable TIFF tag so that they are 2048 bytes large.
507 7 : char szBuffer[2048 + 1] = {};
508 7 : memset(szBuffer, 'X', 2048 - nTIFFHeaderSize + strlen(INITIAL_PADDING));
509 7 : szBuffer[2048 - nTIFFHeaderSize + strlen(INITIAL_PADDING)] = 0;
510 7 : GDALDataset *poTmpDS = new CALSWrapperSrcDataset(poSrcDS, szBuffer);
511 7 : poDS = poGTiffDrv->CreateCopy(pszFilename, poTmpDS, FALSE, papszOptions,
512 : pfnProgress, pProgressData);
513 7 : delete poTmpDS;
514 7 : CSLDestroy(papszOptions);
515 7 : if (poDS == nullptr)
516 2 : return nullptr;
517 5 : delete poDS;
518 :
519 : // Now replace the TIFF header by the CALS header.
520 5 : VSILFILE *fp = VSIFOpenL(pszFilename, "rb+");
521 5 : if (fp == nullptr)
522 0 : return nullptr; // Shouldn't happen normally.
523 5 : memset(szBuffer, ' ', 2048);
524 10 : CPLString osField;
525 5 : osField = "srcdocid: NONE";
526 : // cppcheck-suppress redundantCopy
527 5 : memcpy(szBuffer, osField, osField.size());
528 :
529 5 : osField = "dstdocid: NONE";
530 5 : memcpy(szBuffer + 128, osField, osField.size());
531 :
532 5 : osField = "txtfilid: NONE";
533 5 : memcpy(szBuffer + 128 * 2, osField, osField.size());
534 :
535 5 : osField = "figid: NONE";
536 5 : memcpy(szBuffer + 128 * 3, osField, osField.size());
537 :
538 5 : osField = "srcgph: NONE";
539 5 : memcpy(szBuffer + 128 * 4, osField, osField.size());
540 :
541 5 : osField = "doccls: NONE";
542 5 : memcpy(szBuffer + 128 * 5, osField, osField.size());
543 :
544 5 : osField = "rtype: 1";
545 5 : memcpy(szBuffer + 128 * 6, osField, osField.size());
546 :
547 5 : int nAngle1 = 0;
548 5 : int nAngle2 = 270;
549 5 : const char *pszPixelPath = poSrcDS->GetMetadataItem("PIXEL_PATH");
550 : const char *pszLineProgression =
551 5 : poSrcDS->GetMetadataItem("LINE_PROGRESSION");
552 5 : if (pszPixelPath && pszLineProgression)
553 : {
554 1 : nAngle1 = atoi(pszPixelPath);
555 1 : nAngle2 = atoi(pszLineProgression);
556 : }
557 5 : osField = CPLSPrintf("rorient: %03d,%03d", nAngle1, nAngle2);
558 5 : memcpy(szBuffer + 128 * 7, osField, osField.size());
559 :
560 : osField = CPLSPrintf("rpelcnt: %06d,%06d", poSrcDS->GetRasterXSize(),
561 5 : poSrcDS->GetRasterYSize());
562 5 : memcpy(szBuffer + 128 * 8, osField, osField.size());
563 :
564 5 : int nDensity = 200;
565 5 : const char *pszXRes = poSrcDS->GetMetadataItem("TIFFTAG_XRESOLUTION");
566 5 : const char *pszYRes = poSrcDS->GetMetadataItem("TIFFTAG_YRESOLUTION");
567 5 : const char *pszResUnit = poSrcDS->GetMetadataItem("TIFFTAG_RESOLUTIONUNIT");
568 5 : if (pszXRes && pszYRes && pszResUnit && EQUAL(pszXRes, pszYRes) &&
569 1 : atoi(pszResUnit) == 2)
570 : {
571 1 : nDensity = atoi(pszXRes);
572 1 : if (nDensity < 1 || nDensity > 9999)
573 0 : nDensity = 200;
574 : }
575 5 : osField = CPLSPrintf("rdensty: %04d", nDensity);
576 5 : memcpy(szBuffer + 128 * 9, osField, osField.size());
577 :
578 5 : osField = "notes: NONE";
579 5 : memcpy(szBuffer + 128 * 10, osField, osField.size());
580 5 : VSIFWriteL(szBuffer, 1, 2048, fp);
581 5 : VSIFCloseL(fp);
582 :
583 10 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly, nullptr);
584 5 : return Open(&oOpenInfo);
585 : }
586 :
587 : /************************************************************************/
588 : /* GDALRegister_CALS() */
589 : /************************************************************************/
590 :
591 1928 : void GDALRegister_CALS()
592 :
593 : {
594 1928 : if (GDALGetDriverByName("CALS") != nullptr)
595 282 : return;
596 :
597 1646 : GDALDriver *poDriver = new GDALDriver();
598 :
599 1646 : poDriver->SetDescription("CALS");
600 1646 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
601 1646 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "CALS (Type 1)");
602 1646 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/cals.html");
603 1646 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
604 1646 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "cal ct1");
605 :
606 1646 : poDriver->pfnIdentify = CALSDataset::Identify;
607 1646 : poDriver->pfnOpen = CALSDataset::Open;
608 1646 : poDriver->pfnCreateCopy = CALSDataset::CreateCopy;
609 :
610 1646 : GetGDALDriverManager()->RegisterDriver(poDriver);
611 : }
|