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