1 | // Aseprite Document Library |
2 | // Copyright (C) 2019 Igara Studio S.A. |
3 | // Copyright (C) 2001-2014 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifndef DOC_IMAGE_BITS_H_INCLUDED |
9 | #define DOC_IMAGE_BITS_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #include <algorithm> |
13 | |
14 | namespace doc { |
15 | |
16 | class Image; |
17 | template<typename ImageTraits> class ImageIterator; |
18 | template<typename ImageTraits> class ImageConstIterator; |
19 | |
20 | template<typename ImageTraits> |
21 | class ImageBits { |
22 | public: |
23 | typedef typename ImageTraits::address_t address_t; |
24 | typedef ImageIterator<ImageTraits> iterator; |
25 | typedef ImageConstIterator<ImageTraits> const_iterator; |
26 | |
27 | ImageBits() : |
28 | m_image(NULL), |
29 | m_bounds(0, 0, 0, 0) { |
30 | } |
31 | |
32 | ImageBits(const ImageBits& other) : |
33 | m_image(other.m_image), |
34 | m_bounds(other.m_bounds) { |
35 | } |
36 | |
37 | ImageBits(Image* image, const gfx::Rect& bounds) : |
38 | m_image(image), |
39 | m_bounds(bounds) { |
40 | ASSERT(bounds.x >= 0 && bounds.x+bounds.w <= image->width() && |
41 | bounds.y >= 0 && bounds.y+bounds.h <= image->height()); |
42 | } |
43 | |
44 | ImageBits& operator=(const ImageBits& other) { |
45 | m_image = other.m_image; |
46 | m_bounds = other.m_bounds; |
47 | return *this; |
48 | } |
49 | |
50 | // Iterate over the full area. |
51 | iterator begin() { |
52 | return iterator(m_image, m_bounds, m_bounds.x, m_bounds.y); |
53 | } |
54 | iterator end() { |
55 | iterator it(m_image, m_bounds, m_bounds.x+m_bounds.w-1, m_bounds.y+m_bounds.h-1); |
56 | ++it; |
57 | return it; |
58 | } |
59 | |
60 | const_iterator begin() const { |
61 | return const_iterator(m_image, m_bounds, m_bounds.x, m_bounds.y); |
62 | } |
63 | const_iterator end() const { |
64 | const_iterator it(m_image, m_bounds, m_bounds.x+m_bounds.w-1, m_bounds.y+m_bounds.h-1); |
65 | ++it; |
66 | return it; |
67 | } |
68 | |
69 | // Iterate over a sub-area. |
70 | iterator begin_area(const gfx::Rect& area) { |
71 | ASSERT(m_bounds.contains(area)); |
72 | return iterator(m_image, area, area.x, area.y); |
73 | } |
74 | iterator end_area(const gfx::Rect& area) { |
75 | ASSERT(m_bounds.contains(area)); |
76 | iterator it(m_image, area, area.x+area.w-1, area.y+area.h-1); |
77 | ++it; |
78 | return it; |
79 | } |
80 | |
81 | const_iterator begin_area(const gfx::Rect& area) const { |
82 | ASSERT(m_bounds.contains(area)); |
83 | return const_iterator(m_image, area, area.x, area.y); |
84 | } |
85 | const_iterator end_area(const gfx::Rect& area) const { |
86 | ASSERT(m_bounds.contains(area)); |
87 | const_iterator it(m_image, area, area.x+area.w-1, area.y+area.h-1); |
88 | ++it; |
89 | return it; |
90 | } |
91 | |
92 | Image* image() const { return m_image; } |
93 | const gfx::Rect& bounds() { return m_bounds; } |
94 | |
95 | Image* image() { return m_image; } |
96 | |
97 | void unlock() { |
98 | if (m_image) { |
99 | m_image->unlockBits(*this); |
100 | m_image = NULL; |
101 | } |
102 | } |
103 | |
104 | private: |
105 | Image* m_image; |
106 | gfx::Rect m_bounds; |
107 | }; |
108 | |
109 | template<typename ImageTraits> |
110 | class LockImageBits { |
111 | public: |
112 | typedef ImageBits<ImageTraits> Bits; |
113 | typedef typename Bits::iterator iterator; |
114 | typedef typename Bits::const_iterator const_iterator; |
115 | |
116 | explicit LockImageBits(const Image* image) |
117 | : m_bits(image->lockBits<ImageTraits>(Image::ReadLock, image->bounds())) { |
118 | } |
119 | |
120 | LockImageBits(const Image* image, const gfx::Rect& bounds) |
121 | : m_bits(image->lockBits<ImageTraits>(Image::ReadLock, bounds)) { |
122 | } |
123 | |
124 | LockImageBits(Image* image, Image::LockType lockType) |
125 | : m_bits(image->lockBits<ImageTraits>(lockType, image->bounds())) { |
126 | } |
127 | |
128 | LockImageBits(Image* image, Image::LockType lockType, const gfx::Rect& bounds) |
129 | : m_bits(image->lockBits<ImageTraits>(lockType, bounds)) { |
130 | } |
131 | |
132 | ~LockImageBits() { |
133 | m_bits.image()->unlockBits(m_bits); |
134 | } |
135 | |
136 | // Iterators. |
137 | iterator begin() { return m_bits.begin(); } |
138 | iterator end() { return m_bits.end(); } |
139 | const_iterator begin() const { return m_bits.begin(); } |
140 | const_iterator end() const { return m_bits.end(); } |
141 | |
142 | iterator begin_area(const gfx::Rect& area) { return m_bits.begin_area(area); } |
143 | iterator end_area(const gfx::Rect& area) { return m_bits.end_area(area); } |
144 | const_iterator begin_area(const gfx::Rect& area) const { return m_bits.begin_area(area); } |
145 | const_iterator end_area(const gfx::Rect& area) const { return m_bits.end_area(area); } |
146 | |
147 | const Image* image() const { return m_bits.image(); } |
148 | const gfx::Rect& bounds() const { return m_bits.bounds(); } |
149 | |
150 | Image* image() { return m_bits.image(); } |
151 | |
152 | private: |
153 | Bits m_bits; |
154 | |
155 | LockImageBits(); // Undefined |
156 | }; |
157 | |
158 | template<class ImageTraits, |
159 | class UnaryFunction> |
160 | inline void for_each_pixel(const Image* image, UnaryFunction f) { |
161 | const LockImageBits<ImageTraits> bits(image); |
162 | std::for_each(bits.begin(), bits.end(), f); |
163 | } |
164 | |
165 | template<class ImageTraits, |
166 | class UnaryOperation> |
167 | inline void transform_image(Image* image, UnaryOperation f) { |
168 | LockImageBits<ImageTraits> bits(image); |
169 | std::transform(bits.begin(), bits.end(), bits.begin(), f); |
170 | } |
171 | |
172 | } // namespace doc |
173 | |
174 | #endif |
175 | |