/src/gdal/frmts/pcidsk/sdk/channel/ctiledchannel.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Purpose: Implementation of the CTiledChannel class. |
4 | | * |
5 | | * This class is used to implement band interleaved channels within a |
6 | | * PCIDSK file (which are always packed, and FILE interleaved data from |
7 | | * external raw files which may not be packed. |
8 | | * |
9 | | ****************************************************************************** |
10 | | * Copyright (c) 2009 |
11 | | * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada. |
12 | | * |
13 | | * SPDX-License-Identifier: MIT |
14 | | ****************************************************************************/ |
15 | | |
16 | | #include "pcidsk_config.h" |
17 | | #include "pcidsk_types.h" |
18 | | #include "pcidsk_exception.h" |
19 | | #include "channel/ctiledchannel.h" |
20 | | #include "segment/systiledir.h" |
21 | | #include "blockdir/blocktilelayer.h" |
22 | | #include "core/cpcidskfile.h" |
23 | | #include "core/cpcidskblockfile.h" |
24 | | #include "core/pcidsk_raster.h" |
25 | | #include "core/pcidsk_utils.h" |
26 | | #include <cassert> |
27 | | #include <cstdlib> |
28 | | #include <cstring> |
29 | | |
30 | | namespace PCIDSK |
31 | | { |
32 | | |
33 | | /************************************************************************/ |
34 | | /* CTiledChannel() */ |
35 | | /************************************************************************/ |
36 | | |
37 | | CTiledChannel::CTiledChannel( PCIDSKBuffer &image_headerIn, |
38 | | uint64 ih_offsetIn, |
39 | | CPL_UNUSED PCIDSKBuffer &file_headerIn, |
40 | | int channelnumIn, |
41 | | CPCIDSKFile *fileIn, |
42 | | eChanType pixel_typeIn ) |
43 | 139 | : CPCIDSKChannel( image_headerIn, ih_offsetIn, fileIn, pixel_typeIn, channelnumIn) |
44 | | |
45 | 139 | { |
46 | 139 | std::string filename; |
47 | | |
48 | 139 | image_headerIn.Get(64,64,filename); |
49 | | |
50 | 139 | assert( strstr(filename.c_str(),"SIS=") != nullptr ); |
51 | | |
52 | 139 | image = atoi(strstr(filename.c_str(),"SIS=") + 4); |
53 | | |
54 | 139 | mpoTileLayer = nullptr; |
55 | 139 | } |
56 | | |
57 | | /************************************************************************/ |
58 | | /* ~CTiledChannel() */ |
59 | | /************************************************************************/ |
60 | | CTiledChannel::~CTiledChannel() |
61 | 139 | { |
62 | 139 | try |
63 | 139 | { |
64 | 139 | Synchronize(); |
65 | 139 | } |
66 | 139 | catch( const PCIDSKException& e ) |
67 | 139 | { |
68 | 0 | fprintf(stderr, "Exception in ~CTiledChannel(): %s", e.what()); // ok |
69 | 0 | } |
70 | 139 | } |
71 | | |
72 | | /************************************************************************/ |
73 | | /* EstablishAccess() */ |
74 | | /************************************************************************/ |
75 | | void CTiledChannel::EstablishAccess() const |
76 | 884 | { |
77 | 884 | if (mpoTileLayer) |
78 | 745 | return; |
79 | | |
80 | 139 | CPCIDSKBlockFile oBlockFile(file); |
81 | | |
82 | 139 | SysTileDir * poTileDir = oBlockFile.GetTileDir(); |
83 | | |
84 | 139 | if (!poTileDir) |
85 | 5 | return ThrowPCIDSKException("Unable to find the tile directory segment."); |
86 | | |
87 | 134 | mpoTileLayer = poTileDir->GetTileLayer((uint32) image); |
88 | | |
89 | 134 | if (!mpoTileLayer) |
90 | 16 | return ThrowPCIDSKException("Unable to find the tiled channel: %d", image); |
91 | | |
92 | 118 | const char * pszDataType = mpoTileLayer->GetDataType(); |
93 | | |
94 | 118 | if (GetDataTypeFromName(pszDataType) == CHN_UNKNOWN) |
95 | 0 | return ThrowPCIDSKException("Unknown channel type: %s", pszDataType); |
96 | 118 | } |
97 | | |
98 | | /************************************************************************/ |
99 | | /* Synchronize() */ |
100 | | /* */ |
101 | | /* Flush updated blockmap to disk if it is dirty. */ |
102 | | /************************************************************************/ |
103 | | void CTiledChannel::Synchronize() |
104 | 139 | { |
105 | 139 | if (mpoTileLayer) |
106 | 77 | mpoTileLayer->Sync(); |
107 | 139 | } |
108 | | |
109 | | /************************************************************************/ |
110 | | /* ReadTile() */ |
111 | | /************************************************************************/ |
112 | | void CTiledChannel::ReadTile(void * buffer, uint32 nCol, uint32 nRow) |
113 | 476 | { |
114 | 476 | int nTileXSize = (int) mpoTileLayer->GetTileXSize(); |
115 | 476 | int nTileYSize = (int) mpoTileLayer->GetTileYSize(); |
116 | | |
117 | 476 | eChanType nDataType = GetType(); |
118 | | |
119 | | // Check if we can read an sparse tile. |
120 | 476 | if (mpoTileLayer->ReadSparseTile(buffer, nCol, nRow)) |
121 | 0 | { |
122 | | // Do byte swapping if needed. |
123 | 0 | if( needs_swap ) |
124 | 0 | { |
125 | 0 | SwapPixels( buffer, nDataType, static_cast<size_t>(nTileXSize) * nTileYSize ); |
126 | 0 | } |
127 | |
|
128 | 0 | return; |
129 | 0 | } |
130 | | |
131 | 476 | const char * compression = mpoTileLayer->GetCompressType(); |
132 | | |
133 | 476 | if (strcmp(compression, "NONE") == 0) |
134 | 472 | { |
135 | 472 | mpoTileLayer->ReadTile(buffer, nCol, nRow, mpoTileLayer->GetTileSize()); |
136 | | |
137 | | // Do byte swapping if needed. |
138 | 472 | if( needs_swap ) |
139 | 0 | { |
140 | 0 | SwapPixels( buffer, nDataType, static_cast<size_t>(nTileXSize) * nTileYSize ); |
141 | 0 | } |
142 | | |
143 | 472 | return; |
144 | 472 | } |
145 | | |
146 | 4 | uint32 nTileDataSize = mpoTileLayer->GetTileDataSize(nCol, nRow); |
147 | | |
148 | 4 | PCIDSKBuffer oCompressedData(nTileDataSize); |
149 | 4 | PCIDSKBuffer oUncompressedData(mpoTileLayer->GetTileSize()); |
150 | | |
151 | 4 | mpoTileLayer->ReadTile(oCompressedData.buffer, nCol, nRow, nTileDataSize); |
152 | | |
153 | 4 | if (strcmp(compression, "RLE") == 0) |
154 | 0 | { |
155 | 0 | RLEDecompressBlock( oCompressedData, oUncompressedData ); |
156 | 0 | } |
157 | 4 | else if (STARTS_WITH(compression, "JPEG")) |
158 | 0 | { |
159 | 0 | JPEGDecompressBlock( oCompressedData, oUncompressedData ); |
160 | 0 | } |
161 | 4 | else |
162 | 4 | { |
163 | 4 | return ThrowPCIDSKException( |
164 | 4 | "Unable to read tile of unsupported compression type: %s", |
165 | 4 | compression); |
166 | 4 | } |
167 | | |
168 | | /* -------------------------------------------------------------------- */ |
169 | | /* Swap if necessary. TODO: there is some reason to doubt that */ |
170 | | /* the old implementation properly byte swapped compressed */ |
171 | | /* data. Perhaps this should be conditional? */ |
172 | | /* -------------------------------------------------------------------- */ |
173 | 0 | if( needs_swap ) |
174 | 0 | SwapPixels( oUncompressedData.buffer, nDataType, |
175 | 0 | static_cast<size_t>(nTileXSize) * nTileYSize ); |
176 | |
|
177 | 0 | memcpy(buffer, oUncompressedData.buffer, oUncompressedData.buffer_size); |
178 | 0 | } |
179 | | |
180 | | /************************************************************************/ |
181 | | /* ReadBlock() */ |
182 | | /************************************************************************/ |
183 | | int CTiledChannel::ReadBlock( int iBlock, void *buffer, |
184 | | int xoff, int yoff, |
185 | | int xsize, int ysize ) |
186 | 476 | { |
187 | 476 | EstablishAccess(); |
188 | | |
189 | | // Validate the block index. |
190 | 476 | int nTileCount = (int) mpoTileLayer->GetTileCount(); |
191 | | |
192 | 476 | if( iBlock < 0 || iBlock >= nTileCount ) |
193 | 0 | { |
194 | 0 | return ThrowPCIDSKException(0, "Requested non-existent block (%d)", |
195 | 0 | iBlock ); |
196 | 0 | } |
197 | | |
198 | 476 | int nTileXSize = (int) mpoTileLayer->GetTileXSize(); |
199 | 476 | int nTileYSize = (int) mpoTileLayer->GetTileYSize(); |
200 | | |
201 | | // Default window. |
202 | 476 | if (xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1) |
203 | 476 | { |
204 | 476 | xoff = 0; |
205 | 476 | yoff = 0; |
206 | 476 | xsize = nTileXSize; |
207 | 476 | ysize = nTileYSize; |
208 | 476 | } |
209 | | |
210 | | // Validate the requested window. |
211 | 476 | if (xoff < 0 || xoff + xsize > nTileXSize || |
212 | 476 | yoff < 0 || yoff + ysize > nTileYSize) |
213 | 0 | { |
214 | 0 | return ThrowPCIDSKException(0, |
215 | 0 | "Invalid window in ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d", |
216 | 0 | xoff, yoff, xsize, ysize ); |
217 | 0 | } |
218 | | |
219 | 476 | uint32 nTilePerRow = mpoTileLayer->GetTilePerRow(); |
220 | | |
221 | 476 | if (nTilePerRow == 0) |
222 | 0 | return ThrowPCIDSKException(0, "Invalid number of tiles per row."); |
223 | | |
224 | 476 | uint32 nCol = iBlock % nTilePerRow; |
225 | 476 | uint32 nRow = iBlock / nTilePerRow; |
226 | | |
227 | | // Check if the entire tile was requested. |
228 | 476 | if (xoff == 0 && xsize == nTileXSize && |
229 | 476 | yoff == 0 && ysize == nTileYSize) |
230 | 476 | { |
231 | 476 | ReadTile(buffer, nCol, nRow); |
232 | | |
233 | 476 | return 1; |
234 | 476 | } |
235 | | |
236 | 0 | eChanType nDataType = GetType(); |
237 | 0 | int nPixelSize = DataTypeSize(nDataType); |
238 | 0 | int nPixelCount = xsize * ysize; |
239 | | |
240 | | // Check if we can read an sparse tile. |
241 | 0 | if (!mpoTileLayer->IsTileValid(nCol, nRow)) |
242 | 0 | { |
243 | 0 | if (xoff == 0 && xsize == nTileXSize) |
244 | 0 | { |
245 | 0 | mpoTileLayer->ReadPartialSparseTile |
246 | 0 | (buffer, nCol, nRow, |
247 | 0 | yoff * nTileXSize * nPixelSize, |
248 | 0 | nPixelCount * nPixelSize); |
249 | 0 | } |
250 | 0 | else |
251 | 0 | { |
252 | 0 | for (int iy = 0; iy < ysize; iy++) |
253 | 0 | { |
254 | 0 | mpoTileLayer->ReadPartialSparseTile |
255 | 0 | ((char*) buffer + iy * xsize * nPixelSize, nCol, nRow, |
256 | 0 | ((iy + yoff) * nTileXSize + xoff) * nPixelSize, |
257 | 0 | xsize * nPixelSize); |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | | // Do byte swapping if needed. |
262 | 0 | if( needs_swap ) |
263 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
264 | |
|
265 | 0 | return 1; |
266 | 0 | } |
267 | | |
268 | 0 | const char * compression = mpoTileLayer->GetCompressType(); |
269 | | |
270 | | // Read the requested window. |
271 | 0 | if (strcmp(compression, "NONE") == 0 && xoff == 0 && xsize == nTileXSize) |
272 | 0 | { |
273 | 0 | mpoTileLayer->ReadPartialTile(buffer, nCol, nRow, |
274 | 0 | yoff * nTileXSize * nPixelSize, |
275 | 0 | nPixelCount * nPixelSize); |
276 | | |
277 | | // Do byte swapping if needed. |
278 | 0 | if( needs_swap ) |
279 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
280 | 0 | } |
281 | | // Read the requested window line by line. |
282 | 0 | else if (strcmp(compression, "NONE") == 0) |
283 | 0 | { |
284 | 0 | for (int iy = 0; iy < ysize; iy++) |
285 | 0 | { |
286 | 0 | mpoTileLayer->ReadPartialTile |
287 | 0 | ((char*) buffer + iy * xsize * nPixelSize, nCol, nRow, |
288 | 0 | ((iy + yoff) * nTileXSize + xoff) * nPixelSize, |
289 | 0 | xsize * nPixelSize); |
290 | 0 | } |
291 | | |
292 | | // Do byte swapping if needed. |
293 | 0 | if( needs_swap ) |
294 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
295 | 0 | } |
296 | | // Read the entire tile and copy the requested window. |
297 | 0 | else |
298 | 0 | { |
299 | 0 | PCIDSKBuffer oTileData(mpoTileLayer->GetTileSize()); |
300 | |
|
301 | 0 | ReadTile(oTileData.buffer, nCol, nRow); |
302 | |
|
303 | 0 | for (int iy = 0; iy < ysize; iy++) |
304 | 0 | { |
305 | 0 | memcpy((char*) buffer + iy * xsize * nPixelSize, |
306 | 0 | oTileData.buffer + ((iy + yoff) * nTileXSize + xoff) * nPixelSize, |
307 | 0 | static_cast<size_t>(xsize) * nPixelSize); |
308 | 0 | } |
309 | 0 | } |
310 | |
|
311 | 0 | return 1; |
312 | 0 | } |
313 | | |
314 | | /************************************************************************/ |
315 | | /* WriteBlock() */ |
316 | | /************************************************************************/ |
317 | | int CTiledChannel::WriteBlock( int iBlock, void *buffer ) |
318 | 0 | { |
319 | 0 | if( !file->GetUpdatable() ) |
320 | 0 | return ThrowPCIDSKException(0, "File not open for update in WriteBlock()" ); |
321 | | |
322 | 0 | InvalidateOverviews(); |
323 | |
|
324 | 0 | EstablishAccess(); |
325 | | |
326 | | // Validate the block index. |
327 | 0 | int nTileCount = (int) mpoTileLayer->GetTileCount(); |
328 | |
|
329 | 0 | if( iBlock < 0 || iBlock >= nTileCount ) |
330 | 0 | { |
331 | 0 | return ThrowPCIDSKException(0, "Requested non-existent block (%d)", |
332 | 0 | iBlock ); |
333 | 0 | } |
334 | | |
335 | 0 | int nTileXSize = GetBlockWidth(); |
336 | 0 | int nTileYSize = GetBlockHeight(); |
337 | |
|
338 | 0 | eChanType nDataType = GetType(); |
339 | 0 | int nPixelCount = nTileXSize * nTileYSize; |
340 | |
|
341 | 0 | uint32 nTilePerRow = mpoTileLayer->GetTilePerRow(); |
342 | |
|
343 | 0 | if (nTilePerRow == 0) |
344 | 0 | return ThrowPCIDSKException(0, "Invalid number of tiles per row."); |
345 | | |
346 | 0 | uint32 nCol = iBlock % nTilePerRow; |
347 | 0 | uint32 nRow = iBlock / nTilePerRow; |
348 | | |
349 | | // Do byte swapping if needed. |
350 | 0 | if( needs_swap ) |
351 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
352 | | |
353 | | // Check if we can write an sparse tile. |
354 | 0 | if (mpoTileLayer->WriteSparseTile(buffer, nCol, nRow)) |
355 | 0 | { |
356 | 0 | if( needs_swap ) |
357 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
358 | |
|
359 | 0 | return 1; |
360 | 0 | } |
361 | | |
362 | 0 | const char * compression = mpoTileLayer->GetCompressType(); |
363 | | |
364 | | /* -------------------------------------------------------------------- */ |
365 | | /* The simplest case it an uncompressed direct and complete */ |
366 | | /* tile read into the destination buffer. */ |
367 | | /* -------------------------------------------------------------------- */ |
368 | 0 | if (strcmp(compression, "NONE") == 0) |
369 | 0 | { |
370 | 0 | mpoTileLayer->WriteTile(buffer, nCol, nRow); |
371 | |
|
372 | 0 | if( needs_swap ) |
373 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
374 | |
|
375 | 0 | return 1; |
376 | 0 | } |
377 | | |
378 | | /* -------------------------------------------------------------------- */ |
379 | | /* Copy the uncompressed data into a PCIDSKBuffer, and byte */ |
380 | | /* swap if needed. */ |
381 | | /* -------------------------------------------------------------------- */ |
382 | 0 | PCIDSKBuffer oUncompressedData(mpoTileLayer->GetTileSize()); |
383 | |
|
384 | 0 | memcpy(oUncompressedData.buffer, buffer, |
385 | 0 | oUncompressedData.buffer_size); |
386 | |
|
387 | 0 | if( needs_swap ) |
388 | 0 | SwapPixels( buffer, nDataType, nPixelCount ); |
389 | | |
390 | | /* -------------------------------------------------------------------- */ |
391 | | /* Compress the imagery. */ |
392 | | /* -------------------------------------------------------------------- */ |
393 | 0 | PCIDSKBuffer oCompressedData; |
394 | |
|
395 | 0 | if (strcmp(compression, "NONE") == 0) |
396 | 0 | { |
397 | 0 | oCompressedData = oUncompressedData; |
398 | 0 | } |
399 | 0 | else if (strcmp(compression, "RLE") == 0) |
400 | 0 | { |
401 | 0 | RLECompressBlock( oUncompressedData, oCompressedData ); |
402 | 0 | } |
403 | 0 | else if (STARTS_WITH(compression, "JPEG")) |
404 | 0 | { |
405 | 0 | JPEGCompressBlock( oUncompressedData, oCompressedData ); |
406 | 0 | } |
407 | 0 | else |
408 | 0 | { |
409 | 0 | return ThrowPCIDSKException(0, |
410 | 0 | "Unable to write tile of unsupported compression type: %s", |
411 | 0 | compression); |
412 | 0 | } |
413 | | |
414 | 0 | mpoTileLayer->WriteTile(oCompressedData.buffer, nCol, nRow, |
415 | 0 | oCompressedData.buffer_size); |
416 | |
|
417 | 0 | return 1; |
418 | 0 | } |
419 | | |
420 | | /************************************************************************/ |
421 | | /* GetBlockWidth() */ |
422 | | /************************************************************************/ |
423 | | int CTiledChannel::GetBlockWidth(void) const |
424 | 197 | { |
425 | 197 | EstablishAccess(); |
426 | | |
427 | 197 | return (int) mpoTileLayer->GetTileXSize(); |
428 | 197 | } |
429 | | |
430 | | /************************************************************************/ |
431 | | /* GetBlockHeight() */ |
432 | | /************************************************************************/ |
433 | | int CTiledChannel::GetBlockHeight(void) const |
434 | 135 | { |
435 | 135 | EstablishAccess(); |
436 | | |
437 | 135 | return (int) mpoTileLayer->GetTileYSize(); |
438 | 135 | } |
439 | | |
440 | | /************************************************************************/ |
441 | | /* GetWidth() */ |
442 | | /************************************************************************/ |
443 | | int CTiledChannel::GetWidth(void) const |
444 | 19 | { |
445 | 19 | EstablishAccess(); |
446 | | |
447 | 19 | return (int) mpoTileLayer->GetXSize(); |
448 | 19 | } |
449 | | |
450 | | /************************************************************************/ |
451 | | /* GetHeight() */ |
452 | | /************************************************************************/ |
453 | | int CTiledChannel::GetHeight(void) const |
454 | 19 | { |
455 | 19 | EstablishAccess(); |
456 | | |
457 | 19 | return (int) mpoTileLayer->GetYSize(); |
458 | 19 | } |
459 | | |
460 | | /************************************************************************/ |
461 | | /* GetType() */ |
462 | | /************************************************************************/ |
463 | | eChanType CTiledChannel::GetType(void) const |
464 | 1.10k | { |
465 | 1.10k | eChanType nDataType = CPCIDSKChannel::GetType(); |
466 | | |
467 | 1.10k | if (nDataType != CHN_UNKNOWN) |
468 | 1.06k | return nDataType; |
469 | | |
470 | 38 | EstablishAccess(); |
471 | | |
472 | 38 | return GetDataTypeFromName(mpoTileLayer->GetDataType()); |
473 | 1.10k | } |
474 | | |
475 | | /************************************************************************/ |
476 | | /* RLEDecompressBlock() */ |
477 | | /************************************************************************/ |
478 | | |
479 | | void CTiledChannel::RLEDecompressBlock( PCIDSKBuffer &oCompressedData, |
480 | | PCIDSKBuffer &oDecompressedData ) |
481 | | |
482 | | |
483 | 0 | { |
484 | 0 | int src_offset=0, dst_offset=0; |
485 | 0 | uint8 *src = (uint8 *) oCompressedData.buffer; |
486 | 0 | uint8 *dst = (uint8 *) oDecompressedData.buffer; |
487 | 0 | int nPixelSize = DataTypeSize(GetType()); |
488 | | |
489 | | /* -------------------------------------------------------------------- */ |
490 | | /* Process till we are out of source data, or our destination */ |
491 | | /* buffer is full. These conditions should be satisfied at */ |
492 | | /* the same time! */ |
493 | | /* -------------------------------------------------------------------- */ |
494 | 0 | while( src_offset + 1 + nPixelSize <= oCompressedData.buffer_size |
495 | 0 | && dst_offset < oDecompressedData.buffer_size ) |
496 | 0 | { |
497 | | /* -------------------------------------------------------------------- */ |
498 | | /* Extract a repeat run */ |
499 | | /* -------------------------------------------------------------------- */ |
500 | 0 | if( src[src_offset] > 127 ) |
501 | 0 | { |
502 | 0 | int count = src[src_offset++] - 128; |
503 | 0 | int i; |
504 | |
|
505 | 0 | if( dst_offset + count * nPixelSize > oDecompressedData.buffer_size) |
506 | 0 | { |
507 | 0 | return ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." ); |
508 | 0 | } |
509 | | |
510 | 0 | while( count-- > 0 ) |
511 | 0 | { |
512 | 0 | for( i = 0; i < nPixelSize; i++ ) |
513 | 0 | dst[dst_offset++] = src[src_offset+i]; |
514 | 0 | } |
515 | 0 | src_offset += nPixelSize; |
516 | 0 | } |
517 | | |
518 | | /* -------------------------------------------------------------------- */ |
519 | | /* Extract a literal run. */ |
520 | | /* -------------------------------------------------------------------- */ |
521 | 0 | else |
522 | 0 | { |
523 | 0 | int count = src[src_offset++]; |
524 | |
|
525 | 0 | if( dst_offset + count*nPixelSize > oDecompressedData.buffer_size |
526 | 0 | || src_offset + count*nPixelSize > oCompressedData.buffer_size) |
527 | 0 | { |
528 | 0 | return ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." ); |
529 | 0 | } |
530 | | |
531 | 0 | memcpy( dst + dst_offset, src + src_offset, |
532 | 0 | nPixelSize * count ); |
533 | 0 | src_offset += nPixelSize * count; |
534 | 0 | dst_offset += nPixelSize * count; |
535 | 0 | } |
536 | |
|
537 | 0 | } |
538 | | |
539 | | /* -------------------------------------------------------------------- */ |
540 | | /* Final validation. */ |
541 | | /* -------------------------------------------------------------------- */ |
542 | 0 | if( src_offset != oCompressedData.buffer_size |
543 | 0 | || dst_offset != oDecompressedData.buffer_size ) |
544 | 0 | { |
545 | 0 | return ThrowPCIDSKException( "RLE compressed tile corrupt, result incomplete." ); |
546 | 0 | } |
547 | 0 | } |
548 | | |
549 | | /************************************************************************/ |
550 | | /* RLECompressBlock() */ |
551 | | /* */ |
552 | | /* TODO: There does not seem to be any byte order logic in here! */ |
553 | | /************************************************************************/ |
554 | | |
555 | | void CTiledChannel::RLECompressBlock( PCIDSKBuffer &oUncompressedData, |
556 | | PCIDSKBuffer &oCompressedData ) |
557 | | |
558 | | |
559 | 0 | { |
560 | 0 | int src_bytes = oUncompressedData.buffer_size; |
561 | 0 | int nPixelSize = DataTypeSize(GetType()); |
562 | 0 | int src_offset = 0, dst_offset = 0; |
563 | 0 | int i; |
564 | 0 | uint8 *src = (uint8 *) oUncompressedData.buffer; |
565 | | |
566 | | /* -------------------------------------------------------------------- */ |
567 | | /* Loop till input exhausted. */ |
568 | | /* -------------------------------------------------------------------- */ |
569 | 0 | while( src_offset < src_bytes ) |
570 | 0 | { |
571 | 0 | bool bGotARun = false; |
572 | | |
573 | | /* -------------------------------------------------------------------- */ |
574 | | /* Establish the run length, and emit if greater than 3. */ |
575 | | /* -------------------------------------------------------------------- */ |
576 | 0 | if( src_offset + 3*nPixelSize < src_bytes ) |
577 | 0 | { |
578 | 0 | int count = 1; |
579 | |
|
580 | 0 | while( count < 127 |
581 | 0 | && src_offset + count*nPixelSize < src_bytes ) |
582 | 0 | { |
583 | 0 | bool bWordMatch = true; |
584 | |
|
585 | 0 | for( i = 0; i < nPixelSize; i++ ) |
586 | 0 | { |
587 | 0 | if( src[src_offset+i] |
588 | 0 | != src[src_offset+i+count*nPixelSize] ) |
589 | 0 | bWordMatch = false; |
590 | 0 | } |
591 | |
|
592 | 0 | if( !bWordMatch ) |
593 | 0 | break; |
594 | | |
595 | 0 | count++; |
596 | 0 | } |
597 | |
|
598 | 0 | if( count >= 3 ) |
599 | 0 | { |
600 | 0 | if( oCompressedData.buffer_size < dst_offset + nPixelSize+1 ) |
601 | 0 | oCompressedData.SetSize( oCompressedData.buffer_size*2+100); |
602 | |
|
603 | 0 | oCompressedData.buffer[dst_offset++] = (char) (count+128); |
604 | |
|
605 | 0 | for( i = 0; i < nPixelSize; i++ ) |
606 | 0 | oCompressedData.buffer[dst_offset++] = src[src_offset+i]; |
607 | |
|
608 | 0 | src_offset += count * nPixelSize; |
609 | |
|
610 | 0 | bGotARun = true; |
611 | 0 | } |
612 | 0 | else |
613 | 0 | bGotARun = false; |
614 | 0 | } |
615 | | |
616 | | /* -------------------------------------------------------------------- */ |
617 | | /* Otherwise emit a literal till we encounter at least a three */ |
618 | | /* word series. */ |
619 | | /* -------------------------------------------------------------------- */ |
620 | 0 | if( !bGotARun ) |
621 | 0 | { |
622 | 0 | int count = 1; |
623 | 0 | int match_count = 0; |
624 | |
|
625 | 0 | while( count < 127 |
626 | 0 | && src_offset + count*nPixelSize < src_bytes ) |
627 | 0 | { |
628 | 0 | bool bWordMatch = true; |
629 | |
|
630 | 0 | for( i = 0; i < nPixelSize; i++ ) |
631 | 0 | { |
632 | 0 | if( src[src_offset+i] |
633 | 0 | != src[src_offset+i+count*nPixelSize] ) |
634 | 0 | bWordMatch = false; |
635 | 0 | } |
636 | |
|
637 | 0 | if( bWordMatch ) |
638 | 0 | match_count++; |
639 | 0 | else |
640 | 0 | match_count = 0; |
641 | |
|
642 | 0 | if( match_count > 2 ) |
643 | 0 | break; |
644 | | |
645 | 0 | count++; |
646 | 0 | } |
647 | |
|
648 | 0 | assert( src_offset + count*nPixelSize <= src_bytes ); |
649 | | |
650 | 0 | while( oCompressedData.buffer_size |
651 | 0 | < dst_offset + count*nPixelSize+1 ) |
652 | 0 | oCompressedData.SetSize( oCompressedData.buffer_size*2+100 ); |
653 | |
|
654 | 0 | oCompressedData.buffer[dst_offset++] = (char) count; |
655 | 0 | memcpy( oCompressedData.buffer + dst_offset, |
656 | 0 | src + src_offset, |
657 | 0 | cpl::fits_on<int>(count * nPixelSize) ); |
658 | 0 | src_offset += count * nPixelSize; |
659 | 0 | dst_offset += count * nPixelSize; |
660 | 0 | } |
661 | 0 | } |
662 | | |
663 | 0 | oCompressedData.buffer_size = dst_offset; |
664 | 0 | } |
665 | | |
666 | | /************************************************************************/ |
667 | | /* JPEGDecompressBlock() */ |
668 | | /************************************************************************/ |
669 | | |
670 | | void CTiledChannel::JPEGDecompressBlock( PCIDSKBuffer &oCompressedData, |
671 | | PCIDSKBuffer &oDecompressedData ) |
672 | | |
673 | | |
674 | 0 | { |
675 | 0 | if( file->GetInterfaces()->JPEGDecompressBlock == nullptr ) |
676 | 0 | return ThrowPCIDSKException( "JPEG decompression not enabled in the PCIDSKInterfaces of this build." ); |
677 | | |
678 | 0 | file->GetInterfaces()->JPEGDecompressBlock( |
679 | 0 | (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size, |
680 | 0 | (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size, |
681 | 0 | GetBlockWidth(), GetBlockHeight(), GetType() ); |
682 | 0 | } |
683 | | |
684 | | /************************************************************************/ |
685 | | /* JPEGCompressBlock() */ |
686 | | /************************************************************************/ |
687 | | |
688 | | void CTiledChannel::JPEGCompressBlock( PCIDSKBuffer &oDecompressedData, |
689 | | PCIDSKBuffer &oCompressedData ) |
690 | | |
691 | | |
692 | | |
693 | 0 | { |
694 | 0 | if( file->GetInterfaces()->JPEGCompressBlock == nullptr ) |
695 | 0 | return ThrowPCIDSKException( "JPEG compression not enabled in the PCIDSKInterfaces of this build." ); |
696 | | |
697 | | /* -------------------------------------------------------------------- */ |
698 | | /* What quality should we be using? */ |
699 | | /* -------------------------------------------------------------------- */ |
700 | 0 | int quality = 75; |
701 | |
|
702 | 0 | const char * compression = mpoTileLayer->GetCompressType(); |
703 | |
|
704 | 0 | if (strlen(compression) > 4 && isdigit(static_cast<unsigned char>(compression[4]))) |
705 | 0 | quality = atoi(compression + 4); |
706 | | |
707 | | /* -------------------------------------------------------------------- */ |
708 | | /* Make the output buffer plenty big to hold any conceivable */ |
709 | | /* result. */ |
710 | | /* -------------------------------------------------------------------- */ |
711 | 0 | oCompressedData.SetSize( oDecompressedData.buffer_size * 2 + 1000 ); |
712 | | |
713 | | /* -------------------------------------------------------------------- */ |
714 | | /* invoke. */ |
715 | | /* -------------------------------------------------------------------- */ |
716 | 0 | file->GetInterfaces()->JPEGCompressBlock( |
717 | 0 | (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size, |
718 | 0 | (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size, |
719 | 0 | GetBlockWidth(), GetBlockHeight(), GetType(), quality ); |
720 | 0 | } |
721 | | |
722 | | } // namespace PCIDSK; |