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