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 #include "cpl_port.h"
39
40 using namespace PCIDSK;
41
42 /************************************************************************/
43 /* CPCIDSKBitmap() */
44 /************************************************************************/
45
CPCIDSKBitmap(PCIDSKFile * file,int segment,const char * segment_pointer)46 CPCIDSKBitmap::CPCIDSKBitmap( PCIDSKFile *file, int segment,
47 const char *segment_pointer )
48 : CPCIDSKSegment( file, segment, segment_pointer )
49
50 {
51 loaded = false;
52 }
53
54 /************************************************************************/
55 /* ~CPCIDSKBitmap() */
56 /************************************************************************/
57
~CPCIDSKBitmap()58 CPCIDSKBitmap::~CPCIDSKBitmap()
59
60 {
61 }
62
63 /************************************************************************/
64 /* Initialize() */
65 /* */
66 /* Set up a newly created bitmap segment. We just need to */
67 /* write some stuff into the segment header. */
68 /************************************************************************/
69
Initialize()70 void CPCIDSKBitmap::Initialize()
71
72 {
73 loaded = false;
74
75 CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
76
77 PCIDSKBuffer &bheader = pThis->GetHeader();
78
79 bheader.Put( 0, 160 , 16 );
80 bheader.Put( 0, 160+16*1, 16 );
81 bheader.Put( file->GetWidth(), 160+16*2, 16 );
82 bheader.Put( file->GetHeight(), 160+16*3, 16 );
83 bheader.Put( -1, 160+16*4, 16 );
84
85 file->WriteToFile( bheader.buffer, data_offset, 1024 );
86 }
87
88 /************************************************************************/
89 /* Load() */
90 /************************************************************************/
91
Load() const92 void CPCIDSKBitmap::Load() const
93
94 {
95 if( loaded )
96 return;
97
98 // We don't really mean the internals are const, just a lie to
99 // keep the const interfaces happy.
100
101 CPCIDSKBitmap *pThis = (CPCIDSKBitmap *) this;
102
103 PCIDSKBuffer &bheader = pThis->GetHeader();
104
105 pThis->width = bheader.GetInt( 192, 16 );
106 pThis->height = bheader.GetInt( 192+16, 16 );
107
108 // Choosing 8 lines per block ensures that each block
109 // starts on a byte boundary.
110 pThis->block_width = pThis->width;
111 pThis->block_height = 8;
112
113 pThis->loaded = true;
114 }
115
116 /************************************************************************/
117 /* GetBlockWidth() */
118 /************************************************************************/
119
GetBlockWidth() const120 int CPCIDSKBitmap::GetBlockWidth() const
121
122 {
123 if( !loaded )
124 Load();
125
126 return block_width;
127 }
128
129 /************************************************************************/
130 /* GetBlockHeight() */
131 /************************************************************************/
132
GetBlockHeight() const133 int CPCIDSKBitmap::GetBlockHeight() const
134
135 {
136 if( !loaded )
137 Load();
138
139 return block_height;
140 }
141
142 /************************************************************************/
143 /* GetBlockCount() */
144 /************************************************************************/
145
GetBlockCount() const146 int CPCIDSKBitmap::GetBlockCount() const
147
148 {
149 if( !loaded )
150 Load();
151
152 return ((width + block_width - 1) / block_width)
153 * ((height + block_height - 1) / block_height);
154 }
155
156 /************************************************************************/
157 /* GetWidth() */
158 /************************************************************************/
159
GetWidth() const160 int CPCIDSKBitmap::GetWidth() const
161
162 {
163 if( !loaded )
164 Load();
165
166 return width;
167 }
168
169 /************************************************************************/
170 /* GetHeight() */
171 /************************************************************************/
172
GetHeight() const173 int CPCIDSKBitmap::GetHeight() const
174
175 {
176 if( !loaded )
177 Load();
178
179 return height;
180 }
181
182 /************************************************************************/
183 /* GetType() */
184 /************************************************************************/
185
GetType() const186 eChanType CPCIDSKBitmap::GetType() const
187
188 {
189 return CHN_BIT;
190 }
191
192 /************************************************************************/
193 /* PCIDSK_CopyBits() */
194 /* */
195 /* Copy bit strings - adapted from GDAL. */
196 /************************************************************************/
197
198 static void
PCIDSK_CopyBits(const uint8 * pabySrcData,int nSrcOffset,int nSrcStep,uint8 * pabyDstData,int nDstOffset,int nDstStep,int nBitCount,int nStepCount)199 PCIDSK_CopyBits( const uint8 *pabySrcData, int nSrcOffset, int nSrcStep,
200 uint8 *pabyDstData, int nDstOffset, int nDstStep,
201 int nBitCount, int nStepCount )
202
203 {
204 int iStep;
205 int iBit;
206
207 for( iStep = 0; iStep < nStepCount; iStep++ )
208 {
209 for( iBit = 0; iBit < nBitCount; iBit++ )
210 {
211 if( pabySrcData[nSrcOffset>>3]
212 & (0x80 >>(nSrcOffset & 7)) )
213 pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7));
214 else
215 pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7));
216
217
218 nSrcOffset++;
219 nDstOffset++;
220 }
221
222 nSrcOffset += (nSrcStep - nBitCount);
223 nDstOffset += (nDstStep - nBitCount);
224 }
225 }
226
227 /************************************************************************/
228 /* ReadBlock() */
229 /************************************************************************/
230
ReadBlock(int block_index,void * buffer,int win_xoff,int win_yoff,int win_xsize,int win_ysize)231 int CPCIDSKBitmap::ReadBlock( int block_index, void *buffer,
232 int win_xoff, int win_yoff,
233 int win_xsize, int win_ysize )
234
235 {
236 uint64 block_size = (block_width * block_height + 7) / 8;
237 uint8 *wrk_buffer = (uint8 *) buffer;
238
239 if( block_index < 0 || block_index >= GetBlockCount() )
240 {
241 ThrowPCIDSKException( "Requested non-existant block (%d)",
242 block_index );
243 }
244 /* -------------------------------------------------------------------- */
245 /* If we are doing subwindowing, we will need to create a */
246 /* temporary bitmap to load into. If we are concerned about */
247 /* high performance access to small windows in big bitmaps we */
248 /* will eventually want to reimplement this to avoid reading */
249 /* the whole block to subwindow from. */
250 /* -------------------------------------------------------------------- */
251 if( win_ysize != -1 )
252 {
253 if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
254 || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
255 {
256 ThrowPCIDSKException(
257 "Invalid window in CPCIDSKBitmap::ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
258 win_xoff, win_yoff, win_xsize, win_ysize );
259 }
260
261 wrk_buffer = (uint8 *) malloc((size_t) block_size);
262 if( wrk_buffer == NULL )
263 ThrowPCIDSKException( "Out of memory allocating %d bytes in CPCIDSKBitmap::ReadBlock()",
264 (int) block_size );
265 }
266
267 /* -------------------------------------------------------------------- */
268 /* Read the block, taking care in the case of partial blocks at */
269 /* the bottom of the image. */
270 /* -------------------------------------------------------------------- */
271 if( (block_index+1) * block_height <= height )
272 ReadFromFile( wrk_buffer, block_size * block_index, block_size );
273 else
274 {
275 uint64 short_block_size;
276
277 memset( buffer, 0, (size_t) block_size );
278
279 short_block_size =
280 ((height - block_index*block_height) * block_width + 7) / 8;
281
282 ReadFromFile( wrk_buffer, block_size * block_index, short_block_size );
283 }
284
285 /* -------------------------------------------------------------------- */
286 /* Perform subwindowing if needed. */
287 /* -------------------------------------------------------------------- */
288 if( win_ysize != -1 )
289 {
290 int y_out;
291
292 for( y_out = 0; y_out < win_ysize; y_out++ )
293 {
294 PCIDSK_CopyBits( wrk_buffer,
295 win_xoff + (y_out+win_yoff)*block_width, 0,
296 (uint8*) buffer, y_out * win_xsize, 0,
297 win_xsize, 1 );
298 }
299
300 free( wrk_buffer );
301 }
302
303 return 0;
304 }
305
306 /************************************************************************/
307 /* WriteBlock() */
308 /************************************************************************/
309
WriteBlock(int block_index,void * buffer)310 int CPCIDSKBitmap::WriteBlock( int block_index, void *buffer )
311
312 {
313 uint64 block_size = (block_width * block_height) / 8;
314
315 if( (block_index+1) * block_height <= height )
316 WriteToFile( buffer, block_size * block_index, block_size );
317 else
318 {
319 uint64 short_block_size;
320
321 short_block_size =
322 ((height - block_index*block_height) * block_width + 7) / 8;
323
324 WriteToFile( buffer, block_size * block_index, short_block_size );
325 }
326
327 return 1;
328 }
329
330 /************************************************************************/
331 /* GetOverviewCount() */
332 /************************************************************************/
333
GetOverviewCount()334 int CPCIDSKBitmap::GetOverviewCount()
335 {
336 return 0;
337 }
338
339 /************************************************************************/
340 /* GetOverview() */
341 /************************************************************************/
342
GetOverview(CPL_UNUSED int i)343 PCIDSKChannel *CPCIDSKBitmap::GetOverview( CPL_UNUSED int i )
344 {
345 // The %d is ignored in the exception.
346 ThrowPCIDSKException("Non-existant overview %d requested on bitmap segment.");
347 return NULL;
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 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 ThrowPCIDSKException( "Attempt to SetEChanInfo() on a bitmap." );
530 }
531