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