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
14namespace 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