1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #ifndef INCLUDED_BASEBMP_PACKEDPIXELITERATOR_HXX
25 #define INCLUDED_BASEBMP_PACKEDPIXELITERATOR_HXX
26
27 #include <basebmp/metafunctions.hxx>
28 #include <basebmp/stridedarrayiterator.hxx>
29 #include <basebmp/nonstandarditerator.hxx>
30 #include <basebmp/accessortraits.hxx>
31
32 #include <boost/static_assert.hpp>
33 #include <vigra/metaprogramming.hxx>
34 #include <vigra/diff2d.hxx>
35
36 namespace basebmp
37 {
38
39 /// Get bitmask for data at given intra-word position, for given bit depth
40 template< typename value_type,
41 int bits_per_pixel,
42 bool MsbFirst,
43 typename difference_type >
get_mask(difference_type d)44 inline value_type get_mask( difference_type d )
45 {
46 BOOST_STATIC_ASSERT(bits_per_pixel > 0);
47 BOOST_STATIC_ASSERT(sizeof(value_type)*8 % bits_per_pixel == 0);
48 BOOST_STATIC_ASSERT(sizeof(value_type)*8 / bits_per_pixel > 1);
49 BOOST_STATIC_ASSERT(vigra::TypeTraits<value_type>::isPOD::asBool);
50
51 const unsigned int nIntraWordPositions( sizeof(value_type)*8 / bits_per_pixel );
52
53 // create bits_per_pixel 1s shift to intra-word position
54 return ((~(~0u << bits_per_pixel)) << bits_per_pixel*(MsbFirst ?
55 (nIntraWordPositions-1 - (d % nIntraWordPositions)) :
56 (d % nIntraWordPositions)));
57 }
58
get_shift(difference_type remainder)59 template< int num_intraword_positions, int bits_per_pixel, bool MsbFirst, typename difference_type > inline difference_type get_shift( difference_type remainder )
60 {
61 return bits_per_pixel*(MsbFirst ?
62 (num_intraword_positions - 1 - remainder) :
63 remainder);
64 }
65
66 template< typename Valuetype,
67 int bits_per_pixel,
68 bool MsbFirst > class PackedPixelColumnIterator : public NonStandardIterator
69 {
70 public:
71 // no reference, no index_reference type here
72 typedef Valuetype value_type;
73 typedef int difference_type;
74 typedef image_traverser_tag iterator_category;
75
76 typedef typename remove_const<value_type>::type mask_type;
77 typedef value_type* pointer;
78 typedef StridedArrayIterator< value_type > MoveY;
79
80 enum {
81 /** The number of pixel within a single value_type value
82 */
83 num_intraword_positions=sizeof(value_type)*8/bits_per_pixel,
84 /** Bit mask for one pixel (least significant bits)
85 */
86 bit_mask=~(~0u << bits_per_pixel)
87 };
88
89 private:
90 MoveY y;
91 mask_type mask_;
92 difference_type shift_;
93
inc()94 void inc()
95 {
96 ++y;
97 }
98
dec()99 void dec()
100 {
101 --y;
102 }
103
equal(PackedPixelColumnIterator const & rhs) const104 bool equal( PackedPixelColumnIterator const & rhs ) const
105 {
106 return rhs.y == y;
107 }
108
less(PackedPixelColumnIterator const & rhs) const109 bool less( PackedPixelColumnIterator const & rhs ) const
110 {
111 return y < rhs.y;
112 }
113
114 public:
PackedPixelColumnIterator()115 PackedPixelColumnIterator() :
116 y(0),
117 mask_( get_mask<value_type, bits_per_pixel, MsbFirst, difference_type>(0) ),
118 shift_( get_shift<num_intraword_positions, bits_per_pixel, MsbFirst, difference_type>(0) )
119 {}
120
PackedPixelColumnIterator(const MoveY & base,difference_type remainder)121 PackedPixelColumnIterator( const MoveY& base, difference_type remainder ) :
122 y(base),
123 mask_( get_mask<value_type, bits_per_pixel, MsbFirst>(remainder) ),
124 shift_( get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder) )
125 {}
126
operator +=(difference_type d)127 PackedPixelColumnIterator& operator+=( difference_type d )
128 {
129 y += d;
130 return *this;
131 }
132
operator -=(difference_type d)133 PackedPixelColumnIterator& operator-=( difference_type d )
134 {
135 y -= d;
136 return *this;
137 }
138
operator +(difference_type d)139 PackedPixelColumnIterator operator+( difference_type d )
140 {
141 PackedPixelColumnIterator res(*this);
142 res += d;
143 return res;
144 }
145
operator -(difference_type d)146 PackedPixelColumnIterator operator-( difference_type d )
147 {
148 PackedPixelColumnIterator res(*this);
149 res -= d;
150 return res;
151 }
152
operator ++()153 PackedPixelColumnIterator& operator++()
154 {
155 inc();
156 return *this;
157 }
158
operator --()159 PackedPixelColumnIterator& operator--()
160 {
161 dec();
162 return *this;
163 }
164
operator ++(int)165 PackedPixelColumnIterator operator++(int)
166 {
167 PackedPixelColumnIterator res(*this);
168 inc();
169 return res;
170 }
171
operator --(int)172 PackedPixelColumnIterator operator--(int)
173 {
174 PackedPixelColumnIterator res(*this);
175 dec();
176 return res;
177 }
178
operator ==(PackedPixelColumnIterator const & rhs) const179 bool operator==(PackedPixelColumnIterator const & rhs) const
180 {
181 return equal( rhs );
182 }
183
operator !=(PackedPixelColumnIterator const & rhs) const184 bool operator!=(PackedPixelColumnIterator const & rhs) const
185 {
186 return !equal( rhs );
187 }
188
operator <(PackedPixelColumnIterator const & rhs) const189 bool operator<(PackedPixelColumnIterator const & rhs) const
190 {
191 return less(rhs);
192 }
193
operator <=(PackedPixelColumnIterator const & rhs) const194 bool operator<=(PackedPixelColumnIterator const & rhs) const
195 {
196 return !rhs.less(*this);
197 }
198
operator >(PackedPixelColumnIterator const & rhs) const199 bool operator>(PackedPixelColumnIterator const & rhs) const
200 {
201 return rhs.less(*this);
202 }
203
operator >=(PackedPixelColumnIterator const & rhs) const204 bool operator>=(PackedPixelColumnIterator const & rhs) const
205 {
206 return !less(rhs);
207 }
208
operator -(PackedPixelColumnIterator const & rhs) const209 difference_type operator-(PackedPixelColumnIterator const & rhs) const
210 {
211 return y - rhs.y;
212 }
213
get() const214 value_type get() const
215 {
216 return unsigned_cast<value_type>(*y() & mask_) >> shift_;
217 }
218
get(difference_type d) const219 value_type get(difference_type d) const
220 {
221 return unsigned_cast<value_type>(*y(d) & mask_) >> shift_;
222 }
223
set(value_type v) const224 void set( value_type v ) const
225 {
226 const value_type pixel_value( (v << shift_) & mask_ );
227 *y() = (*y() & ~mask_) | pixel_value;
228 }
229
set(value_type v,difference_type d) const230 void set( value_type v, difference_type d ) const
231 {
232 const value_type pixel_value( (v << shift_) & mask_ );
233 *y(d) = (*y(d) & ~mask_) | pixel_value;
234 }
235 };
236
237 template< typename Valuetype,
238 int bits_per_pixel,
239 bool MsbFirst > class PackedPixelRowIterator : public NonStandardIterator
240 {
241 public:
242 // no reference, no index_reference type here
243 typedef Valuetype value_type;
244 typedef int difference_type;
245 typedef image_traverser_tag iterator_category;
246
247 typedef typename remove_const<value_type>::type mask_type;
248 typedef value_type* pointer;
249
250 enum {
251 /** The number of pixel within a single value_type value
252 */
253 num_intraword_positions=sizeof(value_type)*8/bits_per_pixel,
254 /** Bit mask for one pixel (least significant bits)
255 */
256 bit_mask=~(~0u << bits_per_pixel)
257 };
258
259 private:
260 pointer data_;
261 mask_type mask_;
262 difference_type remainder_;
263
update_mask()264 void update_mask()
265 {
266 mask_ = get_mask<value_type, bits_per_pixel, MsbFirst>(remainder_);
267 }
268
inc()269 void inc()
270 {
271 const difference_type newValue( remainder_ + 1 );
272 const difference_type data_offset( newValue / num_intraword_positions );
273
274 data_ += data_offset;
275 remainder_ = newValue % num_intraword_positions;
276
277 const mask_type shifted_mask(
278 MsbFirst ?
279 unsigned_cast<mask_type>(mask_) >> bits_per_pixel :
280 mask_ << bits_per_pixel );
281
282 // data_offset is 0 for shifted mask, and 1 for wrapped-around mask
283 mask_ = (1-data_offset)*shifted_mask + data_offset*(MsbFirst ?
284 bit_mask << bits_per_pixel*(num_intraword_positions-1) :
285 bit_mask);
286 }
287
dec()288 void dec()
289 {
290 const difference_type newValue( remainder_ - 1 );
291 const bool isNegative( is_negative(newValue) );
292 const difference_type newRemainder( newValue % num_intraword_positions );
293
294 // calc data_ += newValue / num_intraword_positions;
295 // remainder_ = newRemainder;
296 // for newValue >= 0, and
297 // data_ += newValue / num_intraword_positions - 1;
298 // remainder_ = num_intraword_positions - newRemainder;
299 // (to force remainder_ to be positive).
300 // This is branch-free, if is_negative() is branch-free
301 const difference_type data_offset( newValue / num_intraword_positions - isNegative );
302 data_ += data_offset;
303 remainder_ = newRemainder + isNegative*num_intraword_positions;
304
305 const mask_type shifted_mask(
306 MsbFirst ?
307 mask_ << bits_per_pixel :
308 unsigned_cast<mask_type>(mask_) >> bits_per_pixel );
309
310 // data_offset is 0 for shifted mask, and 1 for wrapped-around mask
311 mask_ = (1-data_offset)*shifted_mask + data_offset*(MsbFirst ?
312 bit_mask :
313 bit_mask << bits_per_pixel*(num_intraword_positions-1));
314 }
315
equal(PackedPixelRowIterator const & rhs) const316 bool equal( PackedPixelRowIterator const & rhs ) const
317 {
318 return rhs.data_ == data_ && rhs.remainder_ == remainder_;
319 }
320
less(PackedPixelRowIterator const & rhs) const321 bool less( PackedPixelRowIterator const & rhs ) const
322 {
323 return data_ == rhs.data_ ?
324 (remainder_ < rhs.remainder_) :
325 (data_ < rhs.data_);
326 }
327
328 public:
PackedPixelRowIterator()329 PackedPixelRowIterator() :
330 data_(0),
331 mask_( get_mask<value_type, bits_per_pixel, MsbFirst, difference_type>(0) ),
332 remainder_(0)
333 {}
334
PackedPixelRowIterator(pointer base,int x)335 explicit PackedPixelRowIterator( pointer base, int x ) :
336 data_(base),
337 mask_(0),
338 remainder_(x % num_intraword_positions)
339 {
340 update_mask();
341 }
342
operator +=(difference_type d)343 PackedPixelRowIterator& operator+=( difference_type d )
344 {
345 const difference_type newValue( remainder_ + d );
346 const bool isNegative( is_negative(newValue) );
347 const difference_type newRemainder( newValue % num_intraword_positions );
348
349 // calc data_ += newValue / num_intraword_positions;
350 // remainder_ = newRemainder;
351 // for newValue >= 0, and
352 // data_ += newValue / num_intraword_positions - 1;
353 // remainder_ = newRemainder + num_intraword_positions;
354 // (to force remainder_ to be positive).
355 // This is branch-free, if is_negative() is branch-free
356 data_ += newValue / num_intraword_positions - isNegative;
357 remainder_ = newRemainder + isNegative*num_intraword_positions;
358 update_mask();
359
360 return *this;
361 }
362
operator -=(difference_type d)363 PackedPixelRowIterator& operator-=( difference_type d )
364 {
365 // forward to operator+= - which has to cope with negative
366 // values, anyway.
367 return *this += -d;
368 }
369
operator +(difference_type d)370 PackedPixelRowIterator operator+( difference_type d )
371 {
372 PackedPixelRowIterator res(*this);
373 res += d;
374 return res;
375 }
376
operator -(difference_type d)377 PackedPixelRowIterator operator-( difference_type d )
378 {
379 PackedPixelRowIterator res(*this);
380 res -= d;
381 return res;
382 }
383
operator ++()384 PackedPixelRowIterator& operator++()
385 {
386 inc();
387 return *this;
388 }
389
operator --()390 PackedPixelRowIterator& operator--()
391 {
392 dec();
393 return *this;
394 }
395
operator ++(int)396 PackedPixelRowIterator operator++(int)
397 {
398 PackedPixelRowIterator res(*this);
399 inc();
400 return res;
401 }
402
operator --(int)403 PackedPixelRowIterator operator--(int)
404 {
405 PackedPixelRowIterator res(*this);
406 dec();
407 return res;
408 }
409
operator ==(PackedPixelRowIterator const & rhs) const410 bool operator==(PackedPixelRowIterator const & rhs) const
411 {
412 return equal( rhs );
413 }
414
operator !=(PackedPixelRowIterator const & rhs) const415 bool operator!=(PackedPixelRowIterator const & rhs) const
416 {
417 return !equal( rhs );
418 }
419
operator <(PackedPixelRowIterator const & rhs) const420 bool operator<(PackedPixelRowIterator const & rhs) const
421 {
422 return less(rhs);
423 }
424
operator <=(PackedPixelRowIterator const & rhs) const425 bool operator<=(PackedPixelRowIterator const & rhs) const
426 {
427 return !rhs.less(*this);
428 }
429
operator >(PackedPixelRowIterator const & rhs) const430 bool operator>(PackedPixelRowIterator const & rhs) const
431 {
432 return rhs.less(*this);
433 }
434
operator >=(PackedPixelRowIterator const & rhs) const435 bool operator>=(PackedPixelRowIterator const & rhs) const
436 {
437 return !less(rhs);
438 }
439
operator -(PackedPixelRowIterator const & rhs) const440 difference_type operator-(PackedPixelRowIterator const & rhs) const
441 {
442 return (data_ - rhs.data_)*num_intraword_positions + (remainder_ - rhs.remainder_);
443 }
444
get() const445 value_type get() const
446 {
447 return unsigned_cast<value_type>(*data_ & mask_) >>
448 get_shift<num_intraword_positions,
449 bits_per_pixel,
450 MsbFirst>(remainder_);
451 }
452
get(difference_type d) const453 value_type get(difference_type d) const
454 {
455 PackedPixelRowIterator tmp(*this);
456 tmp += d;
457 return tmp.get();
458 }
459
set(value_type v) const460 void set( value_type v ) const
461 {
462 const value_type pixel_value(
463 (v <<
464 get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder_))
465 & mask_ );
466 *data_ = (*data_ & ~mask_) | pixel_value;
467 }
468
set(value_type v,difference_type d) const469 void set( value_type v, difference_type d ) const
470 {
471 PackedPixelRowIterator tmp(*this);
472 tmp += d;
473 tmp.set(v);
474 }
475 };
476
477 /** 2D image iterator for packed pixel formats
478
479 This iterator can be used for image formats that pack more than
480 one pixel into an machine data type (like one bit per pixel, eight
481 of which packed into one char)
482 */
483 template< typename Valuetype,
484 int bits_per_pixel,
485 bool MsbFirst > class PackedPixelIterator : public NonStandardIterator
486 {
487 public:
488 // no reference, no index_reference type here
489 typedef Valuetype value_type;
490 typedef vigra::Diff2D difference_type;
491 typedef image_traverser_tag iterator_category;
492 typedef PackedPixelRowIterator<value_type,
493 bits_per_pixel,
494 MsbFirst> row_iterator;
495 typedef PackedPixelColumnIterator<value_type,
496 bits_per_pixel,
497 MsbFirst> column_iterator;
498
499 typedef value_type* pointer;
500 typedef int MoveX;
501 typedef StridedArrayIterator< value_type > MoveY;
502
503 enum {
504 /** The number of pixel within a single value_type value
505 */
506 num_intraword_positions=sizeof(value_type)*8/bits_per_pixel,
507 /** Bit mask for one pixel (least significant bits)
508 */
509 bit_mask=~(~0u << bits_per_pixel)
510 };
511
512 // TODO(F2): direction of iteration (ImageIterator can be made to
513 // run backwards)
514
515 private:
current() const516 pointer current() const
517 {
518 return y() + (x / num_intraword_positions);
519 }
520
current(int dx,int dy) const521 pointer current(int dx, int dy) const
522 {
523 return y(dy) + ((x+dx)/num_intraword_positions);
524 }
525
equal(PackedPixelIterator const & rhs) const526 bool equal(PackedPixelIterator const & rhs) const
527 {
528 return (x == rhs.x) && (y == rhs.y);
529 }
530
531 public:
PackedPixelIterator()532 PackedPixelIterator() :
533 x(0),
534 y(0)
535 {}
536
PackedPixelIterator(pointer base,int ystride)537 PackedPixelIterator(pointer base, int ystride) :
538 x(0),
539 y(ystride,base)
540 {}
541
operator ==(PackedPixelIterator const & rhs) const542 bool operator==(PackedPixelIterator const & rhs) const
543 {
544 return equal(rhs);
545 }
546
operator !=(PackedPixelIterator const & rhs) const547 bool operator!=(PackedPixelIterator const & rhs) const
548 {
549 return !equal(rhs);
550 }
551
operator -(PackedPixelIterator const & rhs) const552 difference_type operator-(PackedPixelIterator const & rhs) const
553 {
554 return difference_type(x - rhs.x, y - rhs.y);
555 }
556
557 MoveX x;
558 MoveY y;
559
operator +=(difference_type const & s)560 PackedPixelIterator & operator+=(difference_type const & s)
561 {
562 x += s.x;
563 y += s.y;
564 return *this;
565 }
566
operator -=(difference_type const & s)567 PackedPixelIterator & operator-=(difference_type const & s)
568 {
569 x -= s.x;
570 y -= s.y;
571 return *this;
572 }
573
operator +(difference_type const & s) const574 PackedPixelIterator operator+(difference_type const & s) const
575 {
576 PackedPixelIterator ret(*this);
577 ret += s;
578 return ret;
579 }
580
operator -(difference_type const & s) const581 PackedPixelIterator operator-(difference_type const & s) const
582 {
583 PackedPixelIterator ret(*this);
584 ret -= s;
585 return ret;
586 }
587
rowIterator() const588 row_iterator rowIterator() const
589 {
590 return row_iterator(current(),x);
591 }
592
columnIterator() const593 column_iterator columnIterator() const
594 {
595 return column_iterator(MoveY(y,
596 x / num_intraword_positions),
597 x % num_intraword_positions);
598 }
599
get() const600 value_type get() const
601 {
602 const int remainder( x % num_intraword_positions );
603
604 return (unsigned_cast<value_type>(*current() &
605 get_mask<value_type, bits_per_pixel, MsbFirst>(remainder))
606 >> get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder));
607 }
608
609 /***** XXX - This appears to be unused and fails to compile with gcc9
610 value_type get(difference_type const & d) const
611 {
612 // XXX - should x(d.x) be (x + d.x)?
613 const int remainder( x(d.x) % num_intraword_positions );
614
615 return (unsigned_cast<value_type>(*current(d.x,d.y) &
616 get_mask<value_type, bits_per_pixel, MsbFirst>(remainder))
617 >> get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder));
618 }
619 ******/
620
set(value_type v) const621 void set( value_type v ) const
622 {
623 const int remainder( x % num_intraword_positions );
624 const int mask( get_mask<value_type, bits_per_pixel, MsbFirst>(remainder) );
625 const value_type pixel_value(
626 (v <<
627 get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder))
628 & mask );
629 pointer p = current();
630 *p = (*p & ~mask) | pixel_value;
631 }
632
set(value_type v,difference_type const & d) const633 void set( value_type v, difference_type const & d ) const
634 {
635 const int remainder( (x + d.x) % num_intraword_positions );
636 const int mask( get_mask<value_type, bits_per_pixel, MsbFirst>(remainder) );
637 const value_type pixel_value(
638 (v <<
639 get_shift<num_intraword_positions, bits_per_pixel, MsbFirst>(remainder))
640 & mask );
641 pointer p = current(d.x,d.y);
642 *p = (*p & ~mask) | pixel_value;
643 }
644 };
645
646 //-----------------------------------------------------------------------------
647
648 // partial specialization for the accessor traits masked_accessor
649 // selector metafunction - can employ fast mask functor for the 1bpp
650 // case.
651 template< class Accessor,
652 class MaskAccessor,
653 class Iterator,
654 bool polarity,
655 bool MsbFirst > struct maskedAccessorSelector< Accessor,
656 MaskAccessor,
657 Iterator,
658 PackedPixelIterator< typename MaskAccessor::value_type,
659 1,
660 MsbFirst >,
661 polarity >
662 {
663 typedef TernarySetterFunctionAccessorAdapter<
664 Accessor,
665 MaskAccessor,
666 typename outputMaskFunctorSelector<
667 typename Accessor::value_type,
668 typename MaskAccessor::value_type,
669 polarity,
670 FastMask>::type >
671 type;
672 };
673
674 } // namespace basebmp
675
676 #endif /* INCLUDED_BASEBMP_PACKEDPIXELITERATOR_HXX */
677