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