/src/gdal/frmts/pcidsk/sdk/segment/cpcidskbitmap.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | CPCIDSKBitmap::CPCIDSKBitmap( PCIDSKFile *fileIn, int segmentIn, |
29 | | const char *segment_pointer ) |
30 | 0 | : CPCIDSKSegment( fileIn, segmentIn, segment_pointer ) |
31 | | |
32 | 0 | { |
33 | 0 | loaded = false; |
34 | 0 | width = 0; |
35 | 0 | height = 0; |
36 | 0 | block_width = 0; |
37 | 0 | block_height = 0; |
38 | 0 | } Unexecuted instantiation: PCIDSK::CPCIDSKBitmap::CPCIDSKBitmap(PCIDSK::PCIDSKFile*, int, char const*) Unexecuted instantiation: PCIDSK::CPCIDSKBitmap::CPCIDSKBitmap(PCIDSK::PCIDSKFile*, int, char const*) |
39 | | |
40 | | /************************************************************************/ |
41 | | /* ~CPCIDSKBitmap() */ |
42 | | /************************************************************************/ |
43 | | |
44 | | CPCIDSKBitmap::~CPCIDSKBitmap() |
45 | | |
46 | 0 | { |
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 | | void CPCIDSKBitmap::Initialize() |
57 | | |
58 | 0 | { |
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 | | void CPCIDSKBitmap::Load() const |
79 | | |
80 | 0 | { |
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 | 0 | } |
101 | | |
102 | | /************************************************************************/ |
103 | | /* GetBlockWidth() */ |
104 | | /************************************************************************/ |
105 | | |
106 | | int CPCIDSKBitmap::GetBlockWidth() const |
107 | | |
108 | 0 | { |
109 | 0 | if( !loaded ) |
110 | 0 | Load(); |
111 | |
|
112 | 0 | return block_width; |
113 | 0 | } |
114 | | |
115 | | /************************************************************************/ |
116 | | /* GetBlockHeight() */ |
117 | | /************************************************************************/ |
118 | | |
119 | | int CPCIDSKBitmap::GetBlockHeight() const |
120 | | |
121 | 0 | { |
122 | 0 | if( !loaded ) |
123 | 0 | Load(); |
124 | |
|
125 | 0 | return block_height; |
126 | 0 | } |
127 | | |
128 | | /************************************************************************/ |
129 | | /* GetBlockCount() */ |
130 | | /************************************************************************/ |
131 | | |
132 | | int CPCIDSKBitmap::GetBlockCount() const |
133 | | |
134 | 0 | { |
135 | 0 | if( !loaded ) |
136 | 0 | Load(); |
137 | |
|
138 | 0 | return DIV_ROUND_UP(width, block_width) * DIV_ROUND_UP(height, block_height); |
139 | 0 | } |
140 | | |
141 | | /************************************************************************/ |
142 | | /* GetWidth() */ |
143 | | /************************************************************************/ |
144 | | |
145 | | int CPCIDSKBitmap::GetWidth() const |
146 | | |
147 | 0 | { |
148 | 0 | if( !loaded ) |
149 | 0 | Load(); |
150 | |
|
151 | 0 | return width; |
152 | 0 | } |
153 | | |
154 | | /************************************************************************/ |
155 | | /* GetHeight() */ |
156 | | /************************************************************************/ |
157 | | |
158 | | int CPCIDSKBitmap::GetHeight() const |
159 | | |
160 | 0 | { |
161 | 0 | if( !loaded ) |
162 | 0 | Load(); |
163 | |
|
164 | 0 | return height; |
165 | 0 | } |
166 | | |
167 | | /************************************************************************/ |
168 | | /* GetType() */ |
169 | | /************************************************************************/ |
170 | | |
171 | | eChanType CPCIDSKBitmap::GetType() const |
172 | | |
173 | 0 | { |
174 | 0 | return CHN_BIT; |
175 | 0 | } |
176 | | |
177 | | /************************************************************************/ |
178 | | /* PCIDSK_CopyBits() */ |
179 | | /* */ |
180 | | /* Copy bit strings - adapted from GDAL. */ |
181 | | /************************************************************************/ |
182 | | |
183 | | static void |
184 | | PCIDSK_CopyBits( const uint8 *pabySrcData, int nSrcOffset, int nSrcStep, |
185 | | uint8 *pabyDstData, int nDstOffset, int nDstStep, |
186 | | int nBitCount, int nStepCount ) |
187 | | |
188 | 0 | { |
189 | 0 | int iStep; |
190 | 0 | int iBit; |
191 | |
|
192 | 0 | for( iStep = 0; iStep < nStepCount; iStep++ ) |
193 | 0 | { |
194 | 0 | for( iBit = 0; iBit < nBitCount; iBit++ ) |
195 | 0 | { |
196 | 0 | if( pabySrcData[nSrcOffset>>3] |
197 | 0 | & (0x80 >>(nSrcOffset & 7)) ) |
198 | 0 | pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7)); |
199 | 0 | else |
200 | 0 | pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7)); |
201 | | |
202 | |
|
203 | 0 | nSrcOffset++; |
204 | 0 | nDstOffset++; |
205 | 0 | } |
206 | |
|
207 | 0 | nSrcOffset += (nSrcStep - nBitCount); |
208 | 0 | nDstOffset += (nDstStep - nBitCount); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | /************************************************************************/ |
213 | | /* ReadBlock() */ |
214 | | /************************************************************************/ |
215 | | |
216 | | int CPCIDSKBitmap::ReadBlock( int block_index, void *buffer, |
217 | | int win_xoff, int win_yoff, |
218 | | int win_xsize, int win_ysize ) |
219 | | |
220 | 0 | { |
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 | 0 | { |
226 | 0 | return ThrowPCIDSKException(0, "Requested non-existent block (%d)", |
227 | 0 | block_index ); |
228 | 0 | } |
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 | 0 | { |
238 | 0 | if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth() |
239 | 0 | || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() ) |
240 | 0 | { |
241 | 0 | return ThrowPCIDSKException( 0, |
242 | 0 | "Invalid window in CPCIDSKBitmap::ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d", |
243 | 0 | win_xoff, win_yoff, win_xsize, win_ysize ); |
244 | 0 | } |
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 | 0 | } |
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 | 0 | else |
259 | 0 | { |
260 | 0 | 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 | 0 | } |
269 | | |
270 | | /* -------------------------------------------------------------------- */ |
271 | | /* Perform subwindowing if needed. */ |
272 | | /* -------------------------------------------------------------------- */ |
273 | 0 | if( win_ysize != -1 ) |
274 | 0 | { |
275 | 0 | int y_out; |
276 | |
|
277 | 0 | for( y_out = 0; y_out < win_ysize; y_out++ ) |
278 | 0 | { |
279 | 0 | PCIDSK_CopyBits( wrk_buffer, |
280 | 0 | win_xoff + (y_out+win_yoff)*block_width, 0, |
281 | 0 | (uint8*) buffer, y_out * win_xsize, 0, |
282 | 0 | win_xsize, 1 ); |
283 | 0 | } |
284 | |
|
285 | 0 | free( wrk_buffer ); |
286 | 0 | } |
287 | |
|
288 | 0 | return 0; |
289 | 0 | } |
290 | | |
291 | | /************************************************************************/ |
292 | | /* WriteBlock() */ |
293 | | /************************************************************************/ |
294 | | |
295 | | int CPCIDSKBitmap::WriteBlock( int block_index, void *buffer ) |
296 | | |
297 | 0 | { |
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 | 0 | else |
303 | 0 | { |
304 | 0 | 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 | 0 | } |
311 | |
|
312 | 0 | return 1; |
313 | 0 | } |
314 | | |
315 | | /************************************************************************/ |
316 | | /* GetOverviewCount() */ |
317 | | /************************************************************************/ |
318 | | |
319 | | int CPCIDSKBitmap::GetOverviewCount() |
320 | 0 | { |
321 | 0 | return 0; |
322 | 0 | } |
323 | | |
324 | | /************************************************************************/ |
325 | | /* GetOverview() */ |
326 | | /************************************************************************/ |
327 | | |
328 | | PCIDSKChannel *CPCIDSKBitmap::GetOverview( int i ) |
329 | 0 | { |
330 | 0 | return (PCIDSKChannel*) ThrowPCIDSKExceptionPtr("Non-existent overview %d requested on bitmap segment.", i); |
331 | 0 | } |
332 | | |
333 | | /************************************************************************/ |
334 | | /* IsOverviewValid() */ |
335 | | /************************************************************************/ |
336 | | |
337 | | bool CPCIDSKBitmap::IsOverviewValid( CPL_UNUSED int i ) |
338 | 0 | { |
339 | 0 | return false; |
340 | 0 | } |
341 | | |
342 | | /************************************************************************/ |
343 | | /* GetOverviewResampling() */ |
344 | | /************************************************************************/ |
345 | | |
346 | | std::string CPCIDSKBitmap::GetOverviewResampling( CPL_UNUSED int i ) |
347 | 0 | { |
348 | 0 | return ""; |
349 | 0 | } |
350 | | |
351 | | /************************************************************************/ |
352 | | /* SetOverviewValidity() */ |
353 | | /************************************************************************/ |
354 | | |
355 | | void CPCIDSKBitmap::SetOverviewValidity( CPL_UNUSED int i, CPL_UNUSED bool validity ) |
356 | 0 | { |
357 | 0 | } |
358 | | |
359 | | /************************************************************************/ |
360 | | /* GetMetadataValue() */ |
361 | | /************************************************************************/ |
362 | | |
363 | | std::string CPCIDSKBitmap::GetMetadataValue( const std::string &key ) const |
364 | | |
365 | 0 | { |
366 | 0 | return CPCIDSKSegment::GetMetadataValue( key ); |
367 | 0 | } |
368 | | |
369 | | /************************************************************************/ |
370 | | /* SetMetadataValue() */ |
371 | | /************************************************************************/ |
372 | | |
373 | | void CPCIDSKBitmap::SetMetadataValue( const std::string &key, |
374 | | const std::string &value ) |
375 | | |
376 | 0 | { |
377 | 0 | CPCIDSKSegment::SetMetadataValue( key, value ); |
378 | 0 | } |
379 | | |
380 | | /************************************************************************/ |
381 | | /* GetOverviewLevelMapping() */ |
382 | | /************************************************************************/ |
383 | | std::vector<int> CPCIDSKBitmap::GetOverviewLevelMapping() const |
384 | 0 | { |
385 | 0 | std::vector<int> ov; |
386 | |
|
387 | 0 | return ov; |
388 | 0 | } |
389 | | |
390 | | /************************************************************************/ |
391 | | /* GetMetadataKeys() */ |
392 | | /************************************************************************/ |
393 | | |
394 | | std::vector<std::string> CPCIDSKBitmap::GetMetadataKeys() const |
395 | | |
396 | 0 | { |
397 | 0 | return CPCIDSKSegment::GetMetadataKeys(); |
398 | 0 | } |
399 | | |
400 | | /************************************************************************/ |
401 | | /* Synchronize() */ |
402 | | /************************************************************************/ |
403 | | |
404 | | void CPCIDSKBitmap::Synchronize() |
405 | | |
406 | 0 | { |
407 | | // TODO |
408 | |
|
409 | 0 | CPCIDSKSegment::Synchronize(); |
410 | 0 | } |
411 | | |
412 | | /************************************************************************/ |
413 | | /* GetDescription() */ |
414 | | /************************************************************************/ |
415 | | |
416 | | std::string CPCIDSKBitmap::GetDescription() |
417 | | |
418 | 0 | { |
419 | 0 | return CPCIDSKSegment::GetDescription(); |
420 | 0 | } |
421 | | |
422 | | /************************************************************************/ |
423 | | /* SetDescription() */ |
424 | | /************************************************************************/ |
425 | | |
426 | | void CPCIDSKBitmap::SetDescription( const std::string &description ) |
427 | | |
428 | 0 | { |
429 | 0 | CPCIDSKSegment::SetDescription( description ); |
430 | 0 | } |
431 | | |
432 | | /************************************************************************/ |
433 | | /* GetHistoryEntries() */ |
434 | | /************************************************************************/ |
435 | | |
436 | | std::vector<std::string> CPCIDSKBitmap::GetHistoryEntries() const |
437 | | |
438 | 0 | { |
439 | 0 | return CPCIDSKSegment::GetHistoryEntries(); |
440 | 0 | } |
441 | | |
442 | | /************************************************************************/ |
443 | | /* SetHistoryEntries() */ |
444 | | /************************************************************************/ |
445 | | |
446 | | void CPCIDSKBitmap::SetHistoryEntries( const std::vector<std::string> &entries ) |
447 | | |
448 | 0 | { |
449 | 0 | CPCIDSKSegment::SetHistoryEntries( entries ); |
450 | 0 | } |
451 | | |
452 | | /************************************************************************/ |
453 | | /* PushHistory() */ |
454 | | /************************************************************************/ |
455 | | |
456 | | void CPCIDSKBitmap::PushHistory( const std::string &app, |
457 | | const std::string &message ) |
458 | | |
459 | 0 | { |
460 | 0 | CPCIDSKSegment::PushHistory( app, message ); |
461 | 0 | } |
462 | | |
463 | | /************************************************************************/ |
464 | | /* GetChanInfo() */ |
465 | | /************************************************************************/ |
466 | | void CPCIDSKBitmap::GetChanInfo( std::string &filename, uint64 &image_offset, |
467 | | uint64 &pixel_offset, uint64 &line_offset, |
468 | | bool &little_endian ) const |
469 | | |
470 | 0 | { |
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 | | 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 | 0 | { |
486 | 0 | return ThrowPCIDSKException( "Attempt to SetChanInfo() on a bitmap." ); |
487 | 0 | } |
488 | | |
489 | | /************************************************************************/ |
490 | | /* GetEChanInfo() */ |
491 | | /************************************************************************/ |
492 | | void CPCIDSKBitmap::GetEChanInfo( std::string &filename, int &echannel, |
493 | | int &exoff, int &eyoff, |
494 | | int &exsize, int &eysize ) const |
495 | 0 | { |
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 | | 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 | 0 | { |
512 | 0 | return ThrowPCIDSKException( "Attempt to SetEChanInfo() on a bitmap." ); |
513 | 0 | } |