1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSKBitmap class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2010
7 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "pcidsk_exception.h"
29 : #include "segment/cpcidskbitmap.h"
30 : #include "pcidsk_file.h"
31 : #include "core/pcidsk_utils.h"
32 : #include <cassert>
33 : #include <cstring>
34 : #include <cstdlib>
35 : #include <cstdio>
36 : #include <cctype>
37 :
38 : using namespace PCIDSK;
39 :
40 : /************************************************************************/
41 : /* CPCIDSKBitmap() */
42 : /************************************************************************/
43 :
44 16 : CPCIDSKBitmap::CPCIDSKBitmap( PCIDSKFile *file, int segment,
45 : const char *segment_pointer )
46 16 : : CPCIDSKSegment( file, segment, segment_pointer )
47 :
48 : {
49 16 : loaded = false;
50 16 : }
51 :
52 : /************************************************************************/
53 : /* ~CPCIDSKBitmap() */
54 : /************************************************************************/
55 :
56 16 : CPCIDSKBitmap::~CPCIDSKBitmap()
57 :
58 : {
59 16 : }
60 :
61 : /************************************************************************/
62 : /* Initialize() */
63 : /* */
64 : /* Set up a newly created bitmap segment. We just need to */
65 : /* write some stuff into the segment header. */
66 : /************************************************************************/
67 :
68 0 : void CPCIDSKBitmap::Initialize()
69 :
70 : {
71 0 : loaded = false;
72 :
73 0 : CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
74 :
75 0 : PCIDSKBuffer &bheader = pThis->GetHeader();
76 :
77 0 : bheader.Put( 0, 160 , 16 );
78 0 : bheader.Put( 0, 160+16*1, 16 );
79 0 : bheader.Put( file->GetWidth(), 160+16*2, 16 );
80 0 : bheader.Put( file->GetHeight(), 160+16*3, 16 );
81 0 : bheader.Put( -1, 160+16*4, 16 );
82 :
83 0 : file->WriteToFile( bheader.buffer, data_offset, 1024 );
84 0 : }
85 :
86 : /************************************************************************/
87 : /* Load() */
88 : /************************************************************************/
89 :
90 16 : void CPCIDSKBitmap::Load() const
91 :
92 : {
93 16 : if( loaded )
94 0 : return;
95 :
96 : // We don't really mean the internals are const, just a lie to
97 : // keep the const interfaces happy.
98 :
99 16 : CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
100 :
101 16 : PCIDSKBuffer &bheader = pThis->GetHeader();
102 :
103 16 : pThis->width = bheader.GetInt( 192, 16 );
104 16 : pThis->height = bheader.GetInt( 192+16, 16 );
105 :
106 : // Choosing 8 lines per block ensures that each block
107 : // starts on a byte boundary.
108 16 : pThis->block_width = pThis->width;
109 16 : pThis->block_height = 8;
110 :
111 16 : pThis->loaded = true;
112 : }
113 :
114 : /************************************************************************/
115 : /* GetBlockWidth() */
116 : /************************************************************************/
117 :
118 32 : int CPCIDSKBitmap::GetBlockWidth() const
119 :
120 : {
121 32 : if( !loaded )
122 16 : Load();
123 :
124 32 : return block_width;
125 : }
126 :
127 : /************************************************************************/
128 : /* GetBlockHeight() */
129 : /************************************************************************/
130 :
131 32 : int CPCIDSKBitmap::GetBlockHeight() const
132 :
133 : {
134 32 : if( !loaded )
135 0 : Load();
136 :
137 32 : return block_height;
138 : }
139 :
140 : /************************************************************************/
141 : /* GetBlockCount() */
142 : /************************************************************************/
143 :
144 128 : int CPCIDSKBitmap::GetBlockCount() const
145 :
146 : {
147 128 : if( !loaded )
148 0 : Load();
149 :
150 : return ((width + block_width - 1) / block_width)
151 128 : * ((height + block_height - 1) / block_height);
152 : }
153 :
154 : /************************************************************************/
155 : /* GetWidth() */
156 : /************************************************************************/
157 :
158 16 : int CPCIDSKBitmap::GetWidth() const
159 :
160 : {
161 16 : if( !loaded )
162 0 : Load();
163 :
164 16 : return width;
165 : }
166 :
167 : /************************************************************************/
168 : /* GetHeight() */
169 : /************************************************************************/
170 :
171 16 : int CPCIDSKBitmap::GetHeight() const
172 :
173 : {
174 16 : if( !loaded )
175 0 : Load();
176 :
177 16 : return height;
178 : }
179 :
180 : /************************************************************************/
181 : /* GetType() */
182 : /************************************************************************/
183 :
184 160 : eChanType CPCIDSKBitmap::GetType() const
185 :
186 : {
187 160 : return CHN_BIT;
188 : }
189 :
190 : /************************************************************************/
191 : /* PCIDSK_CopyBits() */
192 : /* */
193 : /* Copy bit strings - adapted from GDAL. */
194 : /************************************************************************/
195 :
196 : static void
197 0 : PCIDSK_CopyBits( const uint8 *pabySrcData, int nSrcOffset, int nSrcStep,
198 : uint8 *pabyDstData, int nDstOffset, int nDstStep,
199 : int nBitCount, int nStepCount )
200 :
201 : {
202 : int iStep;
203 : int iBit;
204 :
205 0 : for( iStep = 0; iStep < nStepCount; iStep++ )
206 : {
207 0 : for( iBit = 0; iBit < nBitCount; iBit++ )
208 : {
209 0 : if( pabySrcData[nSrcOffset>>3]
210 : & (0x80 >>(nSrcOffset & 7)) )
211 0 : pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7));
212 : else
213 0 : pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7));
214 :
215 :
216 0 : nSrcOffset++;
217 0 : nDstOffset++;
218 : }
219 :
220 0 : nSrcOffset += (nSrcStep - nBitCount);
221 0 : nDstOffset += (nDstStep - nBitCount);
222 : }
223 0 : }
224 :
225 : /************************************************************************/
226 : /* ReadBlock() */
227 : /************************************************************************/
228 :
229 128 : int CPCIDSKBitmap::ReadBlock( int block_index, void *buffer,
230 : int win_xoff, int win_yoff,
231 : int win_xsize, int win_ysize )
232 :
233 : {
234 128 : uint64 block_size = (block_width * block_height + 7) / 8;
235 128 : uint8 *wrk_buffer = (uint8 *) buffer;
236 :
237 128 : if( block_index < 0 || block_index >= GetBlockCount() )
238 : {
239 : ThrowPCIDSKException( "Requested non-existant block (%d)",
240 0 : block_index );
241 : }
242 : /* -------------------------------------------------------------------- */
243 : /* If we are doing subwindowing, we will need to create a */
244 : /* temporary bitmap to load into. If we are concerned about */
245 : /* high performance access to small windows in big bitmaps we */
246 : /* will eventually want to reimplement this to avoid reading */
247 : /* the whole block to subwindow from. */
248 : /* -------------------------------------------------------------------- */
249 128 : if( win_ysize != -1 )
250 : {
251 0 : if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
252 0 : || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
253 : {
254 : ThrowPCIDSKException(
255 : "Invalid window in CPCIDSKBitmap::ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
256 0 : win_xoff, win_yoff, win_xsize, win_ysize );
257 : }
258 :
259 0 : wrk_buffer = (uint8 *) malloc((size_t) block_size);
260 0 : if( wrk_buffer == NULL )
261 : ThrowPCIDSKException( "Out of memory allocating %d bytes in CPCIDSKBitmap::ReadBlock()",
262 0 : (int) block_size );
263 : }
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Read the block, taking care in the case of partial blocks at */
267 : /* the bottom of the image. */
268 : /* -------------------------------------------------------------------- */
269 128 : if( (block_index+1) * block_height <= height )
270 128 : ReadFromFile( wrk_buffer, block_size * block_index, block_size );
271 : else
272 : {
273 : uint64 short_block_size;
274 :
275 0 : memset( buffer, 0, (size_t) block_size );
276 :
277 : short_block_size =
278 0 : ((height - block_index*block_height) * block_width + 7) / 8;
279 :
280 0 : ReadFromFile( wrk_buffer, block_size * block_index, short_block_size );
281 : }
282 :
283 : /* -------------------------------------------------------------------- */
284 : /* Perform subwindowing if needed. */
285 : /* -------------------------------------------------------------------- */
286 128 : if( win_ysize != -1 )
287 : {
288 : int y_out;
289 :
290 0 : for( y_out = 0; y_out < win_ysize; y_out++ )
291 : {
292 : PCIDSK_CopyBits( wrk_buffer,
293 : win_xoff + (y_out+win_yoff)*block_width, 0,
294 : (uint8*) buffer, y_out * win_xsize, 0,
295 0 : win_xsize, 1 );
296 : }
297 :
298 0 : free( wrk_buffer );
299 : }
300 :
301 128 : return 0;
302 : }
303 :
304 : /************************************************************************/
305 : /* WriteBlock() */
306 : /************************************************************************/
307 :
308 0 : int CPCIDSKBitmap::WriteBlock( int block_index, void *buffer )
309 :
310 : {
311 0 : uint64 block_size = (block_width * block_height) / 8;
312 :
313 0 : if( (block_index+1) * block_height <= height )
314 0 : WriteToFile( buffer, block_size * block_index, block_size );
315 : else
316 : {
317 : uint64 short_block_size;
318 :
319 : short_block_size =
320 0 : ((height - block_index*block_height) * block_width + 7) / 8;
321 :
322 0 : WriteToFile( buffer, block_size * block_index, short_block_size );
323 : }
324 :
325 0 : return 1;
326 : }
327 :
328 : /************************************************************************/
329 : /* GetOverviewCount() */
330 : /************************************************************************/
331 :
332 0 : int CPCIDSKBitmap::GetOverviewCount()
333 :
334 : {
335 0 : return 0;
336 : }
337 :
338 : /************************************************************************/
339 : /* GetOverview() */
340 : /************************************************************************/
341 :
342 0 : PCIDSKChannel *CPCIDSKBitmap::GetOverview( int i )
343 :
344 : {
345 0 : ThrowPCIDSKException("Non-existant overview %d requested on bitmap segment.");
346 0 : return NULL;
347 : }
348 :
349 : /************************************************************************/
350 : /* IsOverviewValid() */
351 : /************************************************************************/
352 :
353 0 : bool CPCIDSKBitmap::IsOverviewValid( int i )
354 :
355 : {
356 0 : return false;
357 : }
358 :
359 : /************************************************************************/
360 : /* GetOverviewResampling() */
361 : /************************************************************************/
362 :
363 0 : std::string CPCIDSKBitmap::GetOverviewResampling( int i )
364 :
365 : {
366 0 : return "";
367 : }
368 :
369 : /************************************************************************/
370 : /* SetOverviewValidity() */
371 : /************************************************************************/
372 :
373 0 : void CPCIDSKBitmap::SetOverviewValidity( int i, bool validity )
374 :
375 : {
376 0 : }
377 :
378 : /************************************************************************/
379 : /* GetMetadataValue() */
380 : /************************************************************************/
381 :
382 0 : std::string CPCIDSKBitmap::GetMetadataValue( const std::string &key ) const
383 :
384 : {
385 0 : return CPCIDSKSegment::GetMetadataValue( key );
386 : }
387 :
388 : /************************************************************************/
389 : /* SetMetadataValue() */
390 : /************************************************************************/
391 :
392 0 : void CPCIDSKBitmap::SetMetadataValue( const std::string &key,
393 : const std::string &value )
394 :
395 : {
396 0 : CPCIDSKSegment::SetMetadataValue( key, value );
397 0 : }
398 :
399 : /************************************************************************/
400 : /* GetOverviewLevelMapping() */
401 : /************************************************************************/
402 0 : std::vector<int> CPCIDSKBitmap::GetOverviewLevelMapping() const
403 : {
404 0 : std::vector<int> ov;
405 :
406 : return ov;
407 : }
408 :
409 : /************************************************************************/
410 : /* GetMetadataKeys() */
411 : /************************************************************************/
412 :
413 0 : std::vector<std::string> CPCIDSKBitmap::GetMetadataKeys() const
414 :
415 : {
416 0 : return CPCIDSKSegment::GetMetadataKeys();
417 : }
418 :
419 : /************************************************************************/
420 : /* Synchronize() */
421 : /************************************************************************/
422 :
423 0 : void CPCIDSKBitmap::Synchronize()
424 :
425 : {
426 : // TODO
427 :
428 0 : CPCIDSKSegment::Synchronize();
429 0 : }
430 :
431 : /************************************************************************/
432 : /* GetDescription() */
433 : /************************************************************************/
434 :
435 32 : std::string CPCIDSKBitmap::GetDescription()
436 :
437 : {
438 32 : return CPCIDSKSegment::GetDescription();
439 : }
440 :
441 : /************************************************************************/
442 : /* SetDescription() */
443 : /************************************************************************/
444 :
445 0 : void CPCIDSKBitmap::SetDescription( const std::string &description )
446 :
447 : {
448 0 : CPCIDSKSegment::SetDescription( description );
449 0 : }
450 :
451 : /************************************************************************/
452 : /* GetHistoryEntries() */
453 : /************************************************************************/
454 :
455 0 : std::vector<std::string> CPCIDSKBitmap::GetHistoryEntries() const
456 :
457 : {
458 0 : return CPCIDSKSegment::GetHistoryEntries();
459 : }
460 :
461 : /************************************************************************/
462 : /* SetHistoryEntries() */
463 : /************************************************************************/
464 :
465 0 : void CPCIDSKBitmap::SetHistoryEntries( const std::vector<std::string> &entries )
466 :
467 : {
468 0 : CPCIDSKSegment::SetHistoryEntries( entries );
469 0 : }
470 :
471 : /************************************************************************/
472 : /* PushHistory() */
473 : /************************************************************************/
474 :
475 0 : void CPCIDSKBitmap::PushHistory( const std::string &app,
476 : const std::string &message )
477 :
478 : {
479 0 : CPCIDSKSegment::PushHistory( app, message );
480 0 : }
481 :
482 : /************************************************************************/
483 : /* GetChanInfo() */
484 : /************************************************************************/
485 0 : void CPCIDSKBitmap::GetChanInfo( std::string &filename, uint64 &image_offset,
486 : uint64 &pixel_offset, uint64 &line_offset,
487 : bool &little_endian ) const
488 :
489 : {
490 0 : image_offset = 0;
491 0 : pixel_offset = 0;
492 0 : line_offset = 0;
493 0 : little_endian = true;
494 0 : filename = "";
495 0 : }
496 :
497 : /************************************************************************/
498 : /* SetChanInfo() */
499 : /************************************************************************/
500 :
501 0 : void CPCIDSKBitmap::SetChanInfo( std::string filename, uint64 image_offset,
502 : uint64 pixel_offset, uint64 line_offset,
503 : bool little_endian )
504 :
505 : {
506 0 : ThrowPCIDSKException( "Attempt to SetChanInfo() on a bitmap." );
507 0 : }
508 :
509 : /************************************************************************/
510 : /* GetEChanInfo() */
511 : /************************************************************************/
512 0 : void CPCIDSKBitmap::GetEChanInfo( std::string &filename, int &echannel,
513 : int &exoff, int &eyoff,
514 : int &exsize, int &eysize ) const
515 :
516 : {
517 0 : echannel = 0;
518 0 : exoff = 0;
519 0 : eyoff = 0;
520 0 : exsize = 0;
521 0 : eysize = 0;
522 0 : filename = "";
523 0 : }
524 :
525 : /************************************************************************/
526 : /* SetEChanInfo() */
527 : /************************************************************************/
528 :
529 0 : void CPCIDSKBitmap::SetEChanInfo( std::string filename, int echannel,
530 : int exoff, int eyoff,
531 : int exsize, int eysize )
532 :
533 : {
534 0 : ThrowPCIDSKException( "Attempt to SetEChanInfo() on a bitmap." );
535 0 : }
|