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 ((width + block_width - 1) / block_width)
139 0 : * ((height + block_height - 1) / block_height);
140 : }
141 :
142 : /************************************************************************/
143 : /* GetWidth() */
144 : /************************************************************************/
145 :
146 0 : int CPCIDSKBitmap::GetWidth() const
147 :
148 : {
149 0 : if( !loaded )
150 0 : Load();
151 :
152 0 : return width;
153 : }
154 :
155 : /************************************************************************/
156 : /* GetHeight() */
157 : /************************************************************************/
158 :
159 0 : int CPCIDSKBitmap::GetHeight() const
160 :
161 : {
162 0 : if( !loaded )
163 0 : Load();
164 :
165 0 : return height;
166 : }
167 :
168 : /************************************************************************/
169 : /* GetType() */
170 : /************************************************************************/
171 :
172 0 : eChanType CPCIDSKBitmap::GetType() const
173 :
174 : {
175 0 : return CHN_BIT;
176 : }
177 :
178 : /************************************************************************/
179 : /* PCIDSK_CopyBits() */
180 : /* */
181 : /* Copy bit strings - adapted from GDAL. */
182 : /************************************************************************/
183 :
184 : static void
185 0 : PCIDSK_CopyBits( const uint8 *pabySrcData, int nSrcOffset, int nSrcStep,
186 : uint8 *pabyDstData, int nDstOffset, int nDstStep,
187 : int nBitCount, int nStepCount )
188 :
189 : {
190 : int iStep;
191 : int iBit;
192 :
193 0 : for( iStep = 0; iStep < nStepCount; iStep++ )
194 : {
195 0 : for( iBit = 0; iBit < nBitCount; iBit++ )
196 : {
197 0 : if( pabySrcData[nSrcOffset>>3]
198 0 : & (0x80 >>(nSrcOffset & 7)) )
199 0 : pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7));
200 : else
201 0 : pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7));
202 :
203 :
204 0 : nSrcOffset++;
205 0 : nDstOffset++;
206 : }
207 :
208 0 : nSrcOffset += (nSrcStep - nBitCount);
209 0 : nDstOffset += (nDstStep - nBitCount);
210 : }
211 0 : }
212 :
213 : /************************************************************************/
214 : /* ReadBlock() */
215 : /************************************************************************/
216 :
217 0 : int CPCIDSKBitmap::ReadBlock( int block_index, void *buffer,
218 : int win_xoff, int win_yoff,
219 : int win_xsize, int win_ysize )
220 :
221 : {
222 0 : uint64 block_size = (static_cast<uint64>(block_width) * block_height + 7) / 8;
223 0 : uint8 *wrk_buffer = (uint8 *) buffer;
224 :
225 0 : if( block_index < 0 || block_index >= GetBlockCount() )
226 : {
227 0 : return ThrowPCIDSKException(0, "Requested non-existent block (%d)",
228 0 : block_index );
229 : }
230 : /* -------------------------------------------------------------------- */
231 : /* If we are doing subwindowing, we will need to create a */
232 : /* temporary bitmap to load into. If we are concerned about */
233 : /* high performance access to small windows in big bitmaps we */
234 : /* will eventually want to reimplement this to avoid reading */
235 : /* the whole block to subwindow from. */
236 : /* -------------------------------------------------------------------- */
237 0 : if( win_ysize != -1 )
238 : {
239 0 : if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
240 0 : || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
241 : {
242 0 : return ThrowPCIDSKException( 0,
243 : "Invalid window in CPCIDSKBitmap::ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
244 0 : win_xoff, win_yoff, win_xsize, win_ysize );
245 : }
246 :
247 0 : wrk_buffer = (uint8 *) malloc((size_t) block_size);
248 0 : if( wrk_buffer == nullptr )
249 0 : return ThrowPCIDSKException(0, "Out of memory allocating %d bytes in CPCIDSKBitmap::ReadBlock()",
250 0 : (int) block_size );
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Read the block, taking care in the case of partial blocks at */
255 : /* the bottom of the image. */
256 : /* -------------------------------------------------------------------- */
257 0 : if( (block_index+1) * block_height <= height )
258 0 : ReadFromFile( wrk_buffer, block_size * block_index, block_size );
259 : else
260 : {
261 : uint64 short_block_size;
262 :
263 0 : memset( buffer, 0, (size_t) block_size );
264 :
265 0 : short_block_size =
266 0 : (static_cast<uint64>(height - block_index*block_height) * block_width + 7) / 8;
267 :
268 0 : ReadFromFile( wrk_buffer, block_size * block_index, short_block_size );
269 : }
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Perform subwindowing if needed. */
273 : /* -------------------------------------------------------------------- */
274 0 : if( win_ysize != -1 )
275 : {
276 : int y_out;
277 :
278 0 : for( y_out = 0; y_out < win_ysize; y_out++ )
279 : {
280 0 : PCIDSK_CopyBits( wrk_buffer,
281 0 : win_xoff + (y_out+win_yoff)*block_width, 0,
282 : (uint8*) buffer, y_out * win_xsize, 0,
283 : win_xsize, 1 );
284 : }
285 :
286 0 : free( wrk_buffer );
287 : }
288 :
289 0 : return 0;
290 : }
291 :
292 : /************************************************************************/
293 : /* WriteBlock() */
294 : /************************************************************************/
295 :
296 0 : int CPCIDSKBitmap::WriteBlock( int block_index, void *buffer )
297 :
298 : {
299 0 : uint64 block_size = (static_cast<uint64>(block_width) * block_height) / 8;
300 :
301 0 : if( (block_index+1) * block_height <= height )
302 0 : WriteToFile( buffer, block_size * block_index, block_size );
303 : else
304 : {
305 : uint64 short_block_size;
306 :
307 0 : short_block_size =
308 0 : (static_cast<uint64>(height - block_index*block_height) * block_width + 7) / 8;
309 :
310 0 : WriteToFile( buffer, block_size * block_index, short_block_size );
311 : }
312 :
313 0 : return 1;
314 : }
315 :
316 : /************************************************************************/
317 : /* GetOverviewCount() */
318 : /************************************************************************/
319 :
320 0 : int CPCIDSKBitmap::GetOverviewCount()
321 : {
322 0 : return 0;
323 : }
324 :
325 : /************************************************************************/
326 : /* GetOverview() */
327 : /************************************************************************/
328 :
329 0 : PCIDSKChannel *CPCIDSKBitmap::GetOverview( int i )
330 : {
331 0 : return (PCIDSKChannel*) ThrowPCIDSKExceptionPtr("Non-existent overview %d requested on bitmap segment.", i);
332 : }
333 :
334 : /************************************************************************/
335 : /* IsOverviewValid() */
336 : /************************************************************************/
337 :
338 0 : bool CPCIDSKBitmap::IsOverviewValid( CPL_UNUSED int i )
339 : {
340 0 : return false;
341 : }
342 :
343 : /************************************************************************/
344 : /* GetOverviewResampling() */
345 : /************************************************************************/
346 :
347 0 : std::string CPCIDSKBitmap::GetOverviewResampling( CPL_UNUSED int i )
348 : {
349 0 : return "";
350 : }
351 :
352 : /************************************************************************/
353 : /* SetOverviewValidity() */
354 : /************************************************************************/
355 :
356 0 : void CPCIDSKBitmap::SetOverviewValidity( CPL_UNUSED int i, CPL_UNUSED bool validity )
357 : {
358 0 : }
359 :
360 : /************************************************************************/
361 : /* GetMetadataValue() */
362 : /************************************************************************/
363 :
364 0 : std::string CPCIDSKBitmap::GetMetadataValue( const std::string &key ) const
365 :
366 : {
367 0 : return CPCIDSKSegment::GetMetadataValue( key );
368 : }
369 :
370 : /************************************************************************/
371 : /* SetMetadataValue() */
372 : /************************************************************************/
373 :
374 0 : void CPCIDSKBitmap::SetMetadataValue( const std::string &key,
375 : const std::string &value )
376 :
377 : {
378 0 : CPCIDSKSegment::SetMetadataValue( key, value );
379 0 : }
380 :
381 : /************************************************************************/
382 : /* GetOverviewLevelMapping() */
383 : /************************************************************************/
384 0 : std::vector<int> CPCIDSKBitmap::GetOverviewLevelMapping() const
385 : {
386 0 : std::vector<int> ov;
387 :
388 0 : return ov;
389 : }
390 :
391 : /************************************************************************/
392 : /* GetMetadataKeys() */
393 : /************************************************************************/
394 :
395 0 : std::vector<std::string> CPCIDSKBitmap::GetMetadataKeys() const
396 :
397 : {
398 0 : return CPCIDSKSegment::GetMetadataKeys();
399 : }
400 :
401 : /************************************************************************/
402 : /* Synchronize() */
403 : /************************************************************************/
404 :
405 0 : void CPCIDSKBitmap::Synchronize()
406 :
407 : {
408 : // TODO
409 :
410 0 : CPCIDSKSegment::Synchronize();
411 0 : }
412 :
413 : /************************************************************************/
414 : /* GetDescription() */
415 : /************************************************************************/
416 :
417 0 : std::string CPCIDSKBitmap::GetDescription()
418 :
419 : {
420 0 : return CPCIDSKSegment::GetDescription();
421 : }
422 :
423 : /************************************************************************/
424 : /* SetDescription() */
425 : /************************************************************************/
426 :
427 0 : void CPCIDSKBitmap::SetDescription( const std::string &description )
428 :
429 : {
430 0 : CPCIDSKSegment::SetDescription( description );
431 0 : }
432 :
433 : /************************************************************************/
434 : /* GetHistoryEntries() */
435 : /************************************************************************/
436 :
437 0 : std::vector<std::string> CPCIDSKBitmap::GetHistoryEntries() const
438 :
439 : {
440 0 : return CPCIDSKSegment::GetHistoryEntries();
441 : }
442 :
443 : /************************************************************************/
444 : /* SetHistoryEntries() */
445 : /************************************************************************/
446 :
447 0 : void CPCIDSKBitmap::SetHistoryEntries( const std::vector<std::string> &entries )
448 :
449 : {
450 0 : CPCIDSKSegment::SetHistoryEntries( entries );
451 0 : }
452 :
453 : /************************************************************************/
454 : /* PushHistory() */
455 : /************************************************************************/
456 :
457 0 : void CPCIDSKBitmap::PushHistory( const std::string &app,
458 : const std::string &message )
459 :
460 : {
461 0 : CPCIDSKSegment::PushHistory( app, message );
462 0 : }
463 :
464 : /************************************************************************/
465 : /* GetChanInfo() */
466 : /************************************************************************/
467 0 : void CPCIDSKBitmap::GetChanInfo( std::string &filename, uint64 &image_offset,
468 : uint64 &pixel_offset, uint64 &line_offset,
469 : bool &little_endian ) const
470 :
471 : {
472 0 : image_offset = 0;
473 0 : pixel_offset = 0;
474 0 : line_offset = 0;
475 0 : little_endian = true;
476 0 : filename = "";
477 0 : }
478 :
479 : /************************************************************************/
480 : /* SetChanInfo() */
481 : /************************************************************************/
482 :
483 0 : void CPCIDSKBitmap::SetChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED uint64 image_offset,
484 : CPL_UNUSED uint64 pixel_offset, CPL_UNUSED uint64 line_offset,
485 : CPL_UNUSED bool little_endian )
486 : {
487 0 : return ThrowPCIDSKException( "Attempt to SetChanInfo() on a bitmap." );
488 : }
489 :
490 : /************************************************************************/
491 : /* GetEChanInfo() */
492 : /************************************************************************/
493 0 : void CPCIDSKBitmap::GetEChanInfo( std::string &filename, int &echannel,
494 : int &exoff, int &eyoff,
495 : int &exsize, int &eysize ) const
496 : {
497 0 : echannel = 0;
498 0 : exoff = 0;
499 0 : eyoff = 0;
500 0 : exsize = 0;
501 0 : eysize = 0;
502 0 : filename = "";
503 0 : }
504 :
505 : /************************************************************************/
506 : /* SetEChanInfo() */
507 : /************************************************************************/
508 :
509 0 : void CPCIDSKBitmap::SetEChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED int echannel,
510 : CPL_UNUSED int exoff, CPL_UNUSED int eyoff,
511 : CPL_UNUSED int exsize, CPL_UNUSED int eysize )
512 : {
513 0 : return ThrowPCIDSKException( "Attempt to SetEChanInfo() on a bitmap." );
514 : }
|