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