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