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