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, 50 West Wilmot Street, Richmond Hill, Ont, 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/sysblockmap.h"
37 : #include "core/sysvirtualfile.h"
38 : #include "core/cpcidskfile.h"
39 : #include "core/pcidsk_utils.h"
40 : #include <cassert>
41 : #include <cstdlib>
42 : #include <cstring>
43 :
44 : using namespace PCIDSK;
45 :
46 : /************************************************************************/
47 : /* CTiledChannel() */
48 : /************************************************************************/
49 :
50 3 : CTiledChannel::CTiledChannel( PCIDSKBuffer &image_header,
51 : PCIDSKBuffer &file_header,
52 : int channelnum,
53 : CPCIDSKFile *file,
54 : eChanType pixel_type )
55 3 : : CPCIDSKChannel( image_header, file, pixel_type, channelnum )
56 :
57 : {
58 3 : tile_info_dirty = false;
59 :
60 : /* -------------------------------------------------------------------- */
61 : /* Establish the virtual file we will be accessing. */
62 : /* -------------------------------------------------------------------- */
63 3 : std::string filename;
64 :
65 3 : image_header.Get(64,64,filename);
66 :
67 3 : assert( strstr(filename.c_str(),"SIS=") != NULL );
68 :
69 3 : image = atoi(strstr(filename.c_str(),"SIS=") + 4);
70 :
71 3 : vfile = NULL;
72 :
73 : /* -------------------------------------------------------------------- */
74 : /* If this is an unassociated channel (ie. an overview), we */
75 : /* will set the size and blocksize values to someone */
76 : /* unreasonable and set them properly in EstablishAccess() */
77 : /* -------------------------------------------------------------------- */
78 3 : if( channelnum == -1 )
79 : {
80 3 : width = -1;
81 3 : height = -1;
82 3 : block_width = -1;
83 3 : block_height = -1;
84 3 : }
85 3 : }
86 :
87 : /************************************************************************/
88 : /* ~CTiledChannel() */
89 : /************************************************************************/
90 :
91 6 : CTiledChannel::~CTiledChannel()
92 :
93 : {
94 3 : Sync();
95 6 : }
96 :
97 : /************************************************************************/
98 : /* EstablishAccess() */
99 : /************************************************************************/
100 :
101 12 : void CTiledChannel::EstablishAccess()
102 :
103 : {
104 12 : if( vfile != NULL )
105 9 : return;
106 :
107 : /* -------------------------------------------------------------------- */
108 : /* Establish the virtual file to access this image. */
109 : /* -------------------------------------------------------------------- */
110 : SysBlockMap *bmap = dynamic_cast<SysBlockMap*>(
111 3 : file->GetSegment( SEG_SYS, "SysBMDir" ));
112 :
113 3 : if( bmap == NULL )
114 0 : ThrowPCIDSKException( "Unable to find SysBMDir segment." );
115 :
116 3 : vfile = bmap->GetVirtualFile( image );
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Parse the header. */
120 : /* -------------------------------------------------------------------- */
121 3 : PCIDSKBuffer theader(128);
122 3 : std::string data_type;
123 :
124 3 : vfile->ReadFromFile( theader.buffer, 0, 128 );
125 :
126 3 : width = theader.GetInt(0,8);
127 3 : height = theader.GetInt(8,8);
128 3 : block_width = theader.GetInt(16,8);
129 3 : block_height = theader.GetInt(24,8);
130 :
131 3 : theader.Get(32,4,data_type);
132 3 : theader.Get(54, 8, compression);
133 :
134 3 : if( data_type == "8U" )
135 3 : pixel_type = CHN_8U;
136 0 : else if( data_type == "16S" )
137 0 : pixel_type = CHN_16S;
138 0 : else if( data_type == "16U" )
139 0 : pixel_type = CHN_16U;
140 0 : else if( data_type == "32R" )
141 0 : pixel_type = CHN_32R;
142 : else
143 : {
144 : ThrowPCIDSKException( "Unknown channel type: %s",
145 0 : data_type.c_str() );
146 : }
147 :
148 : /* -------------------------------------------------------------------- */
149 : /* Extract the tile map */
150 : /* -------------------------------------------------------------------- */
151 3 : int tiles_per_row = (width + block_width - 1) / block_width;
152 3 : int tiles_per_col = (height + block_height - 1) / block_height;
153 3 : int tile_count = tiles_per_row * tiles_per_col;
154 : int i;
155 :
156 3 : tile_offsets.resize( tile_count );
157 3 : tile_sizes.resize( tile_count );
158 :
159 3 : PCIDSKBuffer tmap( tile_count * 20 );
160 :
161 3 : vfile->ReadFromFile( tmap.buffer, 128, tile_count*20 );
162 :
163 6 : for( i = 0; i < tile_count; i++ )
164 : {
165 3 : tile_offsets[i] = tmap.GetUInt64( i*12 + 0, 12 );
166 3 : tile_sizes[i] = tmap.GetInt( tile_count*12 + i*8, 8 );
167 : }
168 :
169 3 : tile_info_dirty = false;
170 :
171 : /* -------------------------------------------------------------------- */
172 : /* Establish byte swapping. Tiled data files are always big */
173 : /* endian, regardless of what the headers might imply. */
174 : /* -------------------------------------------------------------------- */
175 3 : unsigned short test_value = 1;
176 :
177 3 : if( ((uint8 *) &test_value)[0] == 1 )
178 3 : needs_swap = pixel_type != CHN_8U;
179 : else
180 0 : needs_swap = false;
181 : }
182 :
183 : /************************************************************************/
184 : /* Sync() */
185 : /* */
186 : /* Flush updated blockmap to disk if it is dirty. */
187 : /************************************************************************/
188 :
189 3 : void CTiledChannel::Sync()
190 :
191 : {
192 3 : if( !tile_info_dirty )
193 3 : return;
194 :
195 0 : int tiles_per_row = (width + block_width - 1) / block_width;
196 0 : int tiles_per_col = (height + block_height - 1) / block_height;
197 0 : int tile_count = tiles_per_row * tiles_per_col;
198 : int i;
199 :
200 0 : PCIDSKBuffer tmap( tile_count * 20 );
201 :
202 0 : for( i = 0; i < tile_count; i++ )
203 : {
204 0 : if( tile_offsets[i] == (uint64) -1 || tile_offsets[i] == 0 )
205 0 : tmap.Put( -1, i*12 + 0, 12 );
206 : else
207 0 : tmap.Put( tile_offsets[i], i*12 + 0, 12 );
208 0 : tmap.Put( tile_sizes[i], tile_count*12 + i*8, 8 );
209 : }
210 :
211 0 : vfile->WriteToFile( tmap.buffer, 128, tile_count*20 );
212 : }
213 :
214 : /************************************************************************/
215 : /* ReadBlock() */
216 : /************************************************************************/
217 :
218 1 : int CTiledChannel::ReadBlock( int block_index, void *buffer,
219 : int xoff, int yoff,
220 : int xsize, int ysize )
221 :
222 : {
223 1 : if( !vfile )
224 0 : EstablishAccess();
225 :
226 1 : int pixel_size = DataTypeSize(GetType());
227 :
228 : /* -------------------------------------------------------------------- */
229 : /* Default window if needed. */
230 : /* -------------------------------------------------------------------- */
231 1 : if( xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1 )
232 : {
233 1 : xoff = 0;
234 1 : yoff = 0;
235 1 : xsize = GetBlockWidth();
236 1 : ysize = GetBlockHeight();
237 : }
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Validate Window */
241 : /* -------------------------------------------------------------------- */
242 2 : if( xoff < 0 || xoff + xsize > GetBlockWidth()
243 1 : || yoff < 0 || yoff + ysize > GetBlockHeight() )
244 : {
245 : ThrowPCIDSKException(
246 : "Invalid window in ReadBloc(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
247 0 : xoff, yoff, xsize, ysize );
248 : }
249 :
250 1 : if( block_index < 0 || block_index >= (int) tile_offsets.size() )
251 : {
252 : ThrowPCIDSKException( "Requested non-existant block (%d)",
253 0 : block_index );
254 : }
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Does this tile exist? If not return a zeroed buffer. */
258 : /* -------------------------------------------------------------------- */
259 1 : if( tile_sizes[block_index] == 0 )
260 : {
261 0 : memset( buffer, 0, GetBlockWidth() * GetBlockHeight() * pixel_size );
262 0 : return 1;
263 : }
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* The simpliest case it an uncompressed direct and complete */
267 : /* tile read into the destination buffer. */
268 : /* -------------------------------------------------------------------- */
269 2 : if( xoff == 0 && xsize == GetBlockWidth()
270 1 : && yoff == 0 && ysize == GetBlockHeight()
271 : && tile_sizes[block_index] == xsize * ysize * pixel_size
272 : && compression == "NONE" )
273 : {
274 : vfile->ReadFromFile( buffer,
275 : tile_offsets[block_index],
276 1 : tile_sizes[block_index] );
277 : // Do byte swapping if needed.
278 1 : if( needs_swap )
279 0 : SwapData( buffer, pixel_size, xsize * ysize );
280 :
281 1 : return 1;
282 : }
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Load uncompressed data, one scanline at a time, into the */
286 : /* target buffer. */
287 : /* -------------------------------------------------------------------- */
288 0 : if( compression == "NONE" )
289 : {
290 : int iy;
291 :
292 0 : for( iy = 0; iy < ysize; iy++ )
293 : {
294 : vfile->ReadFromFile( ((uint8 *) buffer)
295 : + iy * xsize * pixel_size,
296 : tile_offsets[block_index]
297 : + ((iy+yoff)*block_width + xoff) * pixel_size,
298 0 : xsize * pixel_size );
299 : }
300 :
301 : // Do byte swapping if needed.
302 0 : if( needs_swap )
303 0 : SwapData( buffer, pixel_size, xsize * ysize );
304 :
305 0 : return 1;
306 : }
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Load the whole compressed data into a working buffer. */
310 : /* -------------------------------------------------------------------- */
311 0 : PCIDSKBuffer oCompressedData( tile_sizes[block_index] );
312 0 : PCIDSKBuffer oUncompressedData( pixel_size * block_width * block_height );
313 :
314 : vfile->ReadFromFile( oCompressedData.buffer,
315 : tile_offsets[block_index],
316 0 : tile_sizes[block_index] );
317 :
318 : /* -------------------------------------------------------------------- */
319 : /* Handle decompression. */
320 : /* -------------------------------------------------------------------- */
321 0 : if( compression == "RLE" )
322 : {
323 0 : RLEDecompressBlock( oCompressedData, oUncompressedData );
324 : }
325 0 : else if( strncmp(compression.c_str(),"JPEG",4) == 0 )
326 : {
327 0 : JPEGDecompressBlock( oCompressedData, oUncompressedData );
328 : }
329 : else
330 : {
331 : ThrowPCIDSKException(
332 : "Unable to read tile of unsupported compression type: %s",
333 0 : compression.c_str() );
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Swap if necessary. TODO: there is some reason to doubt that */
338 : /* the old implementation properly byte swapped compressed */
339 : /* data. Perhaps this should be conditional? */
340 : /* -------------------------------------------------------------------- */
341 0 : if( needs_swap )
342 : SwapData( oUncompressedData.buffer, pixel_size,
343 0 : GetBlockWidth() * GetBlockHeight() );
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Copy out the desired subwindow. */
347 : /* -------------------------------------------------------------------- */
348 : int iy;
349 :
350 0 : for( iy = 0; iy < ysize; iy++ )
351 : {
352 : memcpy( ((uint8 *) buffer) + iy * xsize * pixel_size,
353 : oUncompressedData.buffer
354 : + ((iy+yoff)*block_width + xoff) * pixel_size,
355 0 : xsize * pixel_size );
356 : }
357 :
358 0 : return 1;
359 : }
360 :
361 : /************************************************************************/
362 : /* WriteBlock() */
363 : /************************************************************************/
364 :
365 0 : int CTiledChannel::WriteBlock( int block_index, void *buffer )
366 :
367 : {
368 0 : if( !vfile )
369 0 : EstablishAccess();
370 :
371 0 : int pixel_size = DataTypeSize(GetType());
372 0 : int pixel_count = GetBlockWidth() * GetBlockHeight();
373 :
374 0 : if( block_index < 0 || block_index >= (int) tile_offsets.size() )
375 : {
376 : ThrowPCIDSKException( "Requested non-existant block (%d)",
377 0 : block_index );
378 : }
379 :
380 : /* -------------------------------------------------------------------- */
381 : /* The simpliest case it an uncompressed direct and complete */
382 : /* tile read into the destination buffer. */
383 : /* -------------------------------------------------------------------- */
384 0 : if( compression == "NONE"
385 : && tile_sizes[block_index] == pixel_count * pixel_size )
386 : {
387 : // Do byte swapping if needed.
388 0 : if( needs_swap )
389 0 : SwapData( buffer, pixel_size, pixel_count );
390 :
391 : vfile->WriteToFile( buffer,
392 : tile_offsets[block_index],
393 0 : tile_sizes[block_index] );
394 :
395 0 : if( needs_swap )
396 0 : SwapData( buffer, pixel_size, pixel_count );
397 :
398 0 : return 1;
399 : }
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Copy the uncompressed data into a PCIDSKBuffer, and byte */
403 : /* swap if needed. */
404 : /* -------------------------------------------------------------------- */
405 0 : PCIDSKBuffer oUncompressedData( pixel_size * block_width * block_height );
406 :
407 : memcpy( oUncompressedData.buffer, buffer,
408 0 : oUncompressedData.buffer_size );
409 :
410 0 : if( needs_swap )
411 0 : SwapData( oUncompressedData.buffer, pixel_size, pixel_count );
412 :
413 : /* -------------------------------------------------------------------- */
414 : /* Compress the imagery. */
415 : /* -------------------------------------------------------------------- */
416 0 : PCIDSKBuffer oCompressedData;
417 :
418 0 : if( compression == "NONE" )
419 : {
420 0 : oCompressedData = oUncompressedData;
421 : }
422 0 : else if( compression == "RLE" )
423 : {
424 0 : RLECompressBlock( oUncompressedData, oCompressedData );
425 : }
426 0 : else if( strncmp(compression.c_str(),"JPEG",4) == 0 )
427 : {
428 0 : JPEGCompressBlock( oUncompressedData, oCompressedData );
429 : }
430 : else
431 : {
432 : ThrowPCIDSKException(
433 : "Unable to write tile of unsupported compression type: %s",
434 0 : compression.c_str() );
435 : }
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* If this fits in the existing space, just write it directly. */
439 : /* -------------------------------------------------------------------- */
440 0 : if( oCompressedData.buffer_size <= tile_sizes[block_index] )
441 : {
442 : vfile->WriteToFile( oCompressedData.buffer,
443 : tile_offsets[block_index],
444 0 : oCompressedData.buffer_size );
445 0 : tile_sizes[block_index] = oCompressedData.buffer_size;
446 : }
447 :
448 : /* -------------------------------------------------------------------- */
449 : /* Otherwise we try and write it at the end of the virtual file. */
450 : /* -------------------------------------------------------------------- */
451 : else
452 : {
453 0 : uint64 new_offset = vfile->GetLength();
454 :
455 : vfile->WriteToFile( oCompressedData.buffer,
456 0 : new_offset, oCompressedData.buffer_size );
457 :
458 0 : tile_offsets[block_index] = new_offset;
459 0 : tile_sizes[block_index] = oCompressedData.buffer_size;
460 :
461 : }
462 :
463 0 : tile_info_dirty = true;
464 :
465 0 : return 1;
466 : }
467 :
468 : /************************************************************************/
469 : /* GetBlockWidth() */
470 : /************************************************************************/
471 :
472 6 : int CTiledChannel::GetBlockWidth()
473 :
474 : {
475 6 : EstablishAccess();
476 6 : return CPCIDSKChannel::GetBlockWidth();
477 : }
478 :
479 : /************************************************************************/
480 : /* GetBlockHeight() */
481 : /************************************************************************/
482 :
483 6 : int CTiledChannel::GetBlockHeight()
484 :
485 : {
486 6 : EstablishAccess();
487 6 : return CPCIDSKChannel::GetBlockHeight();
488 : }
489 :
490 : /************************************************************************/
491 : /* GetWidth() */
492 : /************************************************************************/
493 :
494 3 : int CTiledChannel::GetWidth()
495 :
496 : {
497 3 : if( width == -1 )
498 0 : EstablishAccess();
499 :
500 3 : return CPCIDSKChannel::GetWidth();
501 : }
502 :
503 : /************************************************************************/
504 : /* GetHeight() */
505 : /************************************************************************/
506 :
507 3 : int CTiledChannel::GetHeight()
508 :
509 : {
510 3 : if( height == -1 )
511 0 : EstablishAccess();
512 :
513 3 : return CPCIDSKChannel::GetHeight();
514 : }
515 :
516 : /************************************************************************/
517 : /* GetType() */
518 : /************************************************************************/
519 :
520 4 : eChanType CTiledChannel::GetType()
521 :
522 : {
523 4 : if( pixel_type == CHN_UNKNOWN )
524 0 : EstablishAccess();
525 :
526 4 : return CPCIDSKChannel::GetType();
527 : }
528 :
529 : /************************************************************************/
530 : /* RLEDecompressBlock() */
531 : /************************************************************************/
532 :
533 0 : void CTiledChannel::RLEDecompressBlock( PCIDSKBuffer &oCompressedData,
534 : PCIDSKBuffer &oDecompressedData )
535 :
536 :
537 : {
538 0 : int src_offset=0, dst_offset=0;
539 0 : uint8 *src = (uint8 *) oCompressedData.buffer;
540 0 : uint8 *dst = (uint8 *) oDecompressedData.buffer;
541 0 : int pixel_size = DataTypeSize(GetType());
542 :
543 : /* -------------------------------------------------------------------- */
544 : /* Process till we are out of source data, or our destination */
545 : /* buffer is full. These conditions should be satisified at */
546 : /* the same time! */
547 : /* -------------------------------------------------------------------- */
548 0 : while( src_offset + 1 + pixel_size <= oCompressedData.buffer_size
549 : && dst_offset < oDecompressedData.buffer_size )
550 : {
551 : /* -------------------------------------------------------------------- */
552 : /* Extract a repeat run */
553 : /* -------------------------------------------------------------------- */
554 0 : if( src[src_offset] > 127 )
555 : {
556 0 : int count = src[src_offset++] - 128;
557 : int i;
558 :
559 0 : if( dst_offset + count * pixel_size > oDecompressedData.buffer_size)
560 : {
561 0 : ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
562 : }
563 :
564 0 : while( count-- > 0 )
565 : {
566 0 : for( i = 0; i < pixel_size; i++ )
567 0 : dst[dst_offset++] = src[src_offset+i];
568 : }
569 0 : src_offset += pixel_size;
570 : }
571 :
572 : /* -------------------------------------------------------------------- */
573 : /* Extract a literal run. */
574 : /* -------------------------------------------------------------------- */
575 : else
576 : {
577 0 : int count = src[src_offset++];
578 :
579 0 : if( dst_offset + count*pixel_size > oDecompressedData.buffer_size
580 : || src_offset + count*pixel_size > oCompressedData.buffer_size)
581 : {
582 0 : ThrowPCIDSKException( "RLE compressed tile corrupt, overrun avoided." );
583 : }
584 :
585 : memcpy( dst + dst_offset, src + src_offset,
586 0 : pixel_size * count );
587 0 : src_offset += pixel_size * count;
588 0 : dst_offset += pixel_size * count;
589 : }
590 :
591 : }
592 :
593 : /* -------------------------------------------------------------------- */
594 : /* Final validation. */
595 : /* -------------------------------------------------------------------- */
596 0 : if( src_offset != oCompressedData.buffer_size
597 : || dst_offset != oDecompressedData.buffer_size )
598 : {
599 0 : ThrowPCIDSKException( "RLE compressed tile corrupt, result incomplete." );
600 : }
601 0 : }
602 :
603 : /************************************************************************/
604 : /* RLECompressBlock() */
605 : /* */
606 : /* TODO: There does not seem to be any byte order logic in here! */
607 : /************************************************************************/
608 :
609 0 : void CTiledChannel::RLECompressBlock( PCIDSKBuffer &oUncompressedData,
610 : PCIDSKBuffer &oCompressedData )
611 :
612 :
613 : {
614 0 : int src_bytes = oUncompressedData.buffer_size;
615 0 : int pixel_size = DataTypeSize(GetType());
616 0 : int src_offset = 0, dst_offset = 0;
617 : int i;
618 0 : uint8 *src = (uint8 *) oUncompressedData.buffer;
619 :
620 : /* -------------------------------------------------------------------- */
621 : /* Loop till input exausted. */
622 : /* -------------------------------------------------------------------- */
623 0 : while( src_offset < src_bytes )
624 : {
625 0 : bool bGotARun = false;
626 :
627 : /* -------------------------------------------------------------------- */
628 : /* Establish the run length, and emit if greater than 3. */
629 : /* -------------------------------------------------------------------- */
630 0 : if( src_offset + 3*pixel_size < src_bytes )
631 : {
632 0 : int count = 1;
633 :
634 0 : while( count < 127
635 : && src_offset + count*pixel_size < src_bytes )
636 : {
637 0 : bool bWordMatch = true;
638 :
639 0 : for( i = 0; i < pixel_size; i++ )
640 : {
641 0 : if( src[src_offset+i]
642 0 : != src[src_offset+i+count*pixel_size] )
643 0 : bWordMatch = false;
644 : }
645 :
646 0 : if( !bWordMatch )
647 0 : break;
648 :
649 0 : count++;
650 : }
651 :
652 0 : if( count >= 3 )
653 : {
654 0 : if( oCompressedData.buffer_size < dst_offset + pixel_size+1 )
655 0 : oCompressedData.SetSize( oCompressedData.buffer_size*2+100);
656 :
657 0 : oCompressedData.buffer[dst_offset++] = count+128;
658 :
659 0 : for( i = 0; i < pixel_size; i++ )
660 0 : oCompressedData.buffer[dst_offset++] = src[src_offset+i];
661 :
662 0 : src_offset += count * pixel_size;
663 :
664 0 : bGotARun = true;
665 : }
666 : else
667 0 : bGotARun = false;
668 : }
669 :
670 : /* -------------------------------------------------------------------- */
671 : /* Otherwise emit a literal till we encounter at least a three */
672 : /* word series. */
673 : /* -------------------------------------------------------------------- */
674 0 : if( !bGotARun )
675 : {
676 0 : int count = 1;
677 0 : int match_count = 0;
678 :
679 0 : while( count < 127
680 : && src_offset + count*pixel_size < src_bytes )
681 : {
682 0 : bool bWordMatch = true;
683 :
684 0 : for( i = 0; i < pixel_size; i++ )
685 : {
686 0 : if( src[src_offset+i]
687 0 : != src[src_offset+i+count*pixel_size] )
688 0 : bWordMatch = false;
689 : }
690 :
691 0 : if( bWordMatch )
692 0 : match_count++;
693 : else
694 0 : match_count = 0;
695 :
696 0 : if( match_count > 2 )
697 0 : break;
698 :
699 0 : count++;
700 : }
701 :
702 0 : assert( src_offset + count*pixel_size <= src_bytes );
703 :
704 0 : while( oCompressedData.buffer_size
705 : < dst_offset + count*pixel_size+1 )
706 0 : oCompressedData.SetSize( oCompressedData.buffer_size*2+100 );
707 :
708 0 : oCompressedData.buffer[dst_offset++] = count;
709 : memcpy( oCompressedData.buffer + dst_offset,
710 : src + src_offset,
711 0 : count * pixel_size );
712 0 : src_offset += count * pixel_size;
713 0 : dst_offset += count * pixel_size;
714 : }
715 : }
716 :
717 0 : oCompressedData.buffer_size = dst_offset;
718 0 : }
719 :
720 : /************************************************************************/
721 : /* JPEGDecompressBlock() */
722 : /************************************************************************/
723 :
724 0 : void CTiledChannel::JPEGDecompressBlock( PCIDSKBuffer &oCompressedData,
725 : PCIDSKBuffer &oDecompressedData )
726 :
727 :
728 : {
729 0 : if( file->GetInterfaces()->JPEGDecompressBlock == NULL )
730 0 : ThrowPCIDSKException( "JPEG decompression not enabled in the PCIDSKInterfaces of this build." );
731 :
732 0 : file->GetInterfaces()->JPEGDecompressBlock(
733 : (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
734 : (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
735 0 : GetBlockWidth(), GetBlockHeight(), GetType() );
736 0 : }
737 :
738 : /************************************************************************/
739 : /* JPEGCompressBlock() */
740 : /************************************************************************/
741 :
742 0 : void CTiledChannel::JPEGCompressBlock( PCIDSKBuffer &oDecompressedData,
743 : PCIDSKBuffer &oCompressedData )
744 :
745 :
746 :
747 : {
748 0 : if( file->GetInterfaces()->JPEGCompressBlock == NULL )
749 0 : ThrowPCIDSKException( "JPEG compression not enabled in the PCIDSKInterfaces of this build." );
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* What quality should we be using? */
753 : /* -------------------------------------------------------------------- */
754 0 : int quality = 75;
755 :
756 0 : if( compression.c_str()[4] >= '1'
757 0 : && compression.c_str()[4] <= '0' )
758 0 : quality = atoi(compression.c_str() + 4);
759 :
760 : /* -------------------------------------------------------------------- */
761 : /* Make the output buffer plent big to hold any conceivable */
762 : /* result. */
763 : /* -------------------------------------------------------------------- */
764 0 : oCompressedData.SetSize( oDecompressedData.buffer_size * 2 + 1000 );
765 :
766 : /* -------------------------------------------------------------------- */
767 : /* invoke. */
768 : /* -------------------------------------------------------------------- */
769 0 : file->GetInterfaces()->JPEGCompressBlock(
770 : (uint8 *) oDecompressedData.buffer, oDecompressedData.buffer_size,
771 : (uint8 *) oCompressedData.buffer, oCompressedData.buffer_size,
772 0 : GetBlockWidth(), GetBlockHeight(), GetType(), 75 );
773 0 : }
774 :
|