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