1 /******************************************************************************
2 *
3 * Purpose: Implementation of the CPCIDSKBitmap class.
4 *
5 ******************************************************************************
6 * Copyright (c) 2010
7 * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, 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
CPCIDSKBitmap(PCIDSKFile * fileIn,int segmentIn,const char * segment_pointer)44 CPCIDSKBitmap::CPCIDSKBitmap( PCIDSKFile *fileIn, int segmentIn,
45 const char *segment_pointer )
46 : CPCIDSKSegment( fileIn, segmentIn, segment_pointer )
47
48 {
49 loaded = false;
50 width = 0;
51 height = 0;
52 block_width = 0;
53 block_height = 0;
54 }
55
56 /************************************************************************/
57 /* ~CPCIDSKBitmap() */
58 /************************************************************************/
59
~CPCIDSKBitmap()60 CPCIDSKBitmap::~CPCIDSKBitmap()
61
62 {
63 }
64
65 /************************************************************************/
66 /* Initialize() */
67 /* */
68 /* Set up a newly created bitmap segment. We just need to */
69 /* write some stuff into the segment header. */
70 /************************************************************************/
71
Initialize()72 void CPCIDSKBitmap::Initialize()
73
74 {
75 loaded = false;
76
77 CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
78
79 PCIDSKBuffer &bheader = pThis->GetHeader();
80
81 bheader.Put( 0, 160 , 16 );
82 bheader.Put( 0, 160+16*1, 16 );
83 bheader.Put( file->GetWidth(), 160+16*2, 16 );
84 bheader.Put( file->GetHeight(), 160+16*3, 16 );
85 bheader.Put( -1, 160+16*4, 16 );
86
87 file->WriteToFile( bheader.buffer, data_offset, 1024 );
88 }
89
90 /************************************************************************/
91 /* Load() */
92 /************************************************************************/
93
Load() const94 void CPCIDSKBitmap::Load() const
95
96 {
97 if( loaded )
98 return;
99
100 // We don't really mean the internals are const, just a lie to
101 // keep the const interfaces happy.
102
103 CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
104
105 PCIDSKBuffer &bheader = pThis->GetHeader();
106
107 pThis->width = bheader.GetInt( 192, 16 );
108 pThis->height = bheader.GetInt( 192+16, 16 );
109
110 // Choosing 8 lines per block ensures that each block
111 // starts on a byte boundary.
112 pThis->block_width = pThis->width;
113 pThis->block_height = 8;
114
115 pThis->loaded = true;
116 }
117
118 /************************************************************************/
119 /* GetBlockWidth() */
120 /************************************************************************/
121
GetBlockWidth() const122 int CPCIDSKBitmap::GetBlockWidth() const
123
124 {
125 if( !loaded )
126 Load();
127
128 return block_width;
129 }
130
131 /************************************************************************/
132 /* GetBlockHeight() */
133 /************************************************************************/
134
GetBlockHeight() const135 int CPCIDSKBitmap::GetBlockHeight() const
136
137 {
138 if( !loaded )
139 Load();
140
141 return block_height;
142 }
143
144 /************************************************************************/
145 /* GetBlockCount() */
146 /************************************************************************/
147
GetBlockCount() const148 int CPCIDSKBitmap::GetBlockCount() const
149
150 {
151 if( !loaded )
152 Load();
153
154 return ((width + block_width - 1) / block_width)
155 * ((height + block_height - 1) / block_height);
156 }
157
158 /************************************************************************/
159 /* GetWidth() */
160 /************************************************************************/
161
GetWidth() const162 int CPCIDSKBitmap::GetWidth() const
163
164 {
165 if( !loaded )
166 Load();
167
168 return width;
169 }
170
171 /************************************************************************/
172 /* GetHeight() */
173 /************************************************************************/
174
GetHeight() const175 int CPCIDSKBitmap::GetHeight() const
176
177 {
178 if( !loaded )
179 Load();
180
181 return height;
182 }
183
184 /************************************************************************/
185 /* GetType() */
186 /************************************************************************/
187
GetType() const188 eChanType CPCIDSKBitmap::GetType() const
189
190 {
191 return CHN_BIT;
192 }
193
194 /************************************************************************/
195 /* PCIDSK_CopyBits() */
196 /* */
197 /* Copy bit strings - adapted from GDAL. */
198 /************************************************************************/
199
200 static void
PCIDSK_CopyBits(const uint8 * pabySrcData,int nSrcOffset,int nSrcStep,uint8 * pabyDstData,int nDstOffset,int nDstStep,int nBitCount,int nStepCount)201 PCIDSK_CopyBits( const uint8 *pabySrcData, int nSrcOffset, int nSrcStep,
202 uint8 *pabyDstData, int nDstOffset, int nDstStep,
203 int nBitCount, int nStepCount )
204
205 {
206 int iStep;
207 int iBit;
208
209 for( iStep = 0; iStep < nStepCount; iStep++ )
210 {
211 for( iBit = 0; iBit < nBitCount; iBit++ )
212 {
213 if( pabySrcData[nSrcOffset>>3]
214 & (0x80 >>(nSrcOffset & 7)) )
215 pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7));
216 else
217 pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7));
218
219
220 nSrcOffset++;
221 nDstOffset++;
222 }
223
224 nSrcOffset += (nSrcStep - nBitCount);
225 nDstOffset += (nDstStep - nBitCount);
226 }
227 }
228
229 /************************************************************************/
230 /* ReadBlock() */
231 /************************************************************************/
232
ReadBlock(int block_index,void * buffer,int win_xoff,int win_yoff,int win_xsize,int win_ysize)233 int CPCIDSKBitmap::ReadBlock( int block_index, void *buffer,
234 int win_xoff, int win_yoff,
235 int win_xsize, int win_ysize )
236
237 {
238 uint64 block_size = (static_cast<uint64>(block_width) * block_height + 7) / 8;
239 uint8 *wrk_buffer = (uint8 *) buffer;
240
241 if( block_index < 0 || block_index >= GetBlockCount() )
242 {
243 return ThrowPCIDSKException(0, "Requested non-existent block (%d)",
244 block_index );
245 }
246 /* -------------------------------------------------------------------- */
247 /* If we are doing subwindowing, we will need to create a */
248 /* temporary bitmap to load into. If we are concerned about */
249 /* high performance access to small windows in big bitmaps we */
250 /* will eventually want to reimplement this to avoid reading */
251 /* the whole block to subwindow from. */
252 /* -------------------------------------------------------------------- */
253 if( win_ysize != -1 )
254 {
255 if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
256 || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
257 {
258 return ThrowPCIDSKException( 0,
259 "Invalid window in CPCIDSKBitmap::ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
260 win_xoff, win_yoff, win_xsize, win_ysize );
261 }
262
263 wrk_buffer = (uint8 *) malloc((size_t) block_size);
264 if( wrk_buffer == nullptr )
265 return ThrowPCIDSKException(0, "Out of memory allocating %d bytes in CPCIDSKBitmap::ReadBlock()",
266 (int) block_size );
267 }
268
269 /* -------------------------------------------------------------------- */
270 /* Read the block, taking care in the case of partial blocks at */
271 /* the bottom of the image. */
272 /* -------------------------------------------------------------------- */
273 if( (block_index+1) * block_height <= height )
274 ReadFromFile( wrk_buffer, block_size * block_index, block_size );
275 else
276 {
277 uint64 short_block_size;
278
279 memset( buffer, 0, (size_t) block_size );
280
281 short_block_size =
282 (static_cast<uint64>(height - block_index*block_height) * block_width + 7) / 8;
283
284 ReadFromFile( wrk_buffer, block_size * block_index, short_block_size );
285 }
286
287 /* -------------------------------------------------------------------- */
288 /* Perform subwindowing if needed. */
289 /* -------------------------------------------------------------------- */
290 if( win_ysize != -1 )
291 {
292 int y_out;
293
294 for( y_out = 0; y_out < win_ysize; y_out++ )
295 {
296 PCIDSK_CopyBits( wrk_buffer,
297 win_xoff + (y_out+win_yoff)*block_width, 0,
298 (uint8*) buffer, y_out * win_xsize, 0,
299 win_xsize, 1 );
300 }
301
302 free( wrk_buffer );
303 }
304
305 return 0;
306 }
307
308 /************************************************************************/
309 /* WriteBlock() */
310 /************************************************************************/
311
WriteBlock(int block_index,void * buffer)312 int CPCIDSKBitmap::WriteBlock( int block_index, void *buffer )
313
314 {
315 uint64 block_size = (static_cast<uint64>(block_width) * block_height) / 8;
316
317 if( (block_index+1) * block_height <= height )
318 WriteToFile( buffer, block_size * block_index, block_size );
319 else
320 {
321 uint64 short_block_size;
322
323 short_block_size =
324 (static_cast<uint64>(height - block_index*block_height) * block_width + 7) / 8;
325
326 WriteToFile( buffer, block_size * block_index, short_block_size );
327 }
328
329 return 1;
330 }
331
332 /************************************************************************/
333 /* GetOverviewCount() */
334 /************************************************************************/
335
GetOverviewCount()336 int CPCIDSKBitmap::GetOverviewCount()
337 {
338 return 0;
339 }
340
341 /************************************************************************/
342 /* GetOverview() */
343 /************************************************************************/
344
GetOverview(int i)345 PCIDSKChannel *CPCIDSKBitmap::GetOverview( int i )
346 {
347 return (PCIDSKChannel*) ThrowPCIDSKExceptionPtr("Non-existent overview %d requested on bitmap segment.", i);
348 }
349
350 /************************************************************************/
351 /* IsOverviewValid() */
352 /************************************************************************/
353
IsOverviewValid(CPL_UNUSED int i)354 bool CPCIDSKBitmap::IsOverviewValid( CPL_UNUSED int i )
355 {
356 return false;
357 }
358
359 /************************************************************************/
360 /* GetOverviewResampling() */
361 /************************************************************************/
362
GetOverviewResampling(CPL_UNUSED int i)363 std::string CPCIDSKBitmap::GetOverviewResampling( CPL_UNUSED int i )
364 {
365 return "";
366 }
367
368 /************************************************************************/
369 /* SetOverviewValidity() */
370 /************************************************************************/
371
SetOverviewValidity(CPL_UNUSED int i,CPL_UNUSED bool validity)372 void CPCIDSKBitmap::SetOverviewValidity( CPL_UNUSED int i, CPL_UNUSED bool validity )
373 {
374 }
375
376 /************************************************************************/
377 /* GetMetadataValue() */
378 /************************************************************************/
379
GetMetadataValue(const std::string & key) const380 std::string CPCIDSKBitmap::GetMetadataValue( const std::string &key ) const
381
382 {
383 return CPCIDSKSegment::GetMetadataValue( key );
384 }
385
386 /************************************************************************/
387 /* SetMetadataValue() */
388 /************************************************************************/
389
SetMetadataValue(const std::string & key,const std::string & value)390 void CPCIDSKBitmap::SetMetadataValue( const std::string &key,
391 const std::string &value )
392
393 {
394 CPCIDSKSegment::SetMetadataValue( key, value );
395 }
396
397 /************************************************************************/
398 /* GetOverviewLevelMapping() */
399 /************************************************************************/
GetOverviewLevelMapping() const400 std::vector<int> CPCIDSKBitmap::GetOverviewLevelMapping() const
401 {
402 std::vector<int> ov;
403
404 return ov;
405 }
406
407 /************************************************************************/
408 /* GetMetadataKeys() */
409 /************************************************************************/
410
GetMetadataKeys() const411 std::vector<std::string> CPCIDSKBitmap::GetMetadataKeys() const
412
413 {
414 return CPCIDSKSegment::GetMetadataKeys();
415 }
416
417 /************************************************************************/
418 /* Synchronize() */
419 /************************************************************************/
420
Synchronize()421 void CPCIDSKBitmap::Synchronize()
422
423 {
424 // TODO
425
426 CPCIDSKSegment::Synchronize();
427 }
428
429 /************************************************************************/
430 /* GetDescription() */
431 /************************************************************************/
432
GetDescription()433 std::string CPCIDSKBitmap::GetDescription()
434
435 {
436 return CPCIDSKSegment::GetDescription();
437 }
438
439 /************************************************************************/
440 /* SetDescription() */
441 /************************************************************************/
442
SetDescription(const std::string & description)443 void CPCIDSKBitmap::SetDescription( const std::string &description )
444
445 {
446 CPCIDSKSegment::SetDescription( description );
447 }
448
449 /************************************************************************/
450 /* GetHistoryEntries() */
451 /************************************************************************/
452
GetHistoryEntries() const453 std::vector<std::string> CPCIDSKBitmap::GetHistoryEntries() const
454
455 {
456 return CPCIDSKSegment::GetHistoryEntries();
457 }
458
459 /************************************************************************/
460 /* SetHistoryEntries() */
461 /************************************************************************/
462
SetHistoryEntries(const std::vector<std::string> & entries)463 void CPCIDSKBitmap::SetHistoryEntries( const std::vector<std::string> &entries )
464
465 {
466 CPCIDSKSegment::SetHistoryEntries( entries );
467 }
468
469 /************************************************************************/
470 /* PushHistory() */
471 /************************************************************************/
472
PushHistory(const std::string & app,const std::string & message)473 void CPCIDSKBitmap::PushHistory( const std::string &app,
474 const std::string &message )
475
476 {
477 CPCIDSKSegment::PushHistory( app, message );
478 }
479
480 /************************************************************************/
481 /* GetChanInfo() */
482 /************************************************************************/
GetChanInfo(std::string & filename,uint64 & image_offset,uint64 & pixel_offset,uint64 & line_offset,bool & little_endian) const483 void CPCIDSKBitmap::GetChanInfo( std::string &filename, uint64 &image_offset,
484 uint64 &pixel_offset, uint64 &line_offset,
485 bool &little_endian ) const
486
487 {
488 image_offset = 0;
489 pixel_offset = 0;
490 line_offset = 0;
491 little_endian = true;
492 filename = "";
493 }
494
495 /************************************************************************/
496 /* SetChanInfo() */
497 /************************************************************************/
498
SetChanInfo(CPL_UNUSED std::string filename,CPL_UNUSED uint64 image_offset,CPL_UNUSED uint64 pixel_offset,CPL_UNUSED uint64 line_offset,CPL_UNUSED bool little_endian)499 void CPCIDSKBitmap::SetChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED uint64 image_offset,
500 CPL_UNUSED uint64 pixel_offset, CPL_UNUSED uint64 line_offset,
501 CPL_UNUSED bool little_endian )
502 {
503 return ThrowPCIDSKException( "Attempt to SetChanInfo() on a bitmap." );
504 }
505
506 /************************************************************************/
507 /* GetEChanInfo() */
508 /************************************************************************/
GetEChanInfo(std::string & filename,int & echannel,int & exoff,int & eyoff,int & exsize,int & eysize) const509 void CPCIDSKBitmap::GetEChanInfo( std::string &filename, int &echannel,
510 int &exoff, int &eyoff,
511 int &exsize, int &eysize ) const
512 {
513 echannel = 0;
514 exoff = 0;
515 eyoff = 0;
516 exsize = 0;
517 eysize = 0;
518 filename = "";
519 }
520
521 /************************************************************************/
522 /* SetEChanInfo() */
523 /************************************************************************/
524
SetEChanInfo(CPL_UNUSED std::string filename,CPL_UNUSED int echannel,CPL_UNUSED int exoff,CPL_UNUSED int eyoff,CPL_UNUSED int exsize,CPL_UNUSED int eysize)525 void CPCIDSKBitmap::SetEChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED int echannel,
526 CPL_UNUSED int exoff, CPL_UNUSED int eyoff,
527 CPL_UNUSED int exsize, CPL_UNUSED int eysize )
528 {
529 return ThrowPCIDSKException( "Attempt to SetEChanInfo() on a bitmap." );
530 }
531