Skip to content

Commit 570e09a

Browse files
add BitmapImage
1 parent a8fba6b commit 570e09a

File tree

3 files changed

+315
-17
lines changed

3 files changed

+315
-17
lines changed

src/Image.cc

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,9 @@ Image::Image(const std::string& filename, ssize_t width, ssize_t height,
559559
bool has_alpha, uint8_t channel_width, uint64_t max_value) : Image(filename.c_str(), width, height, has_alpha, channel_width, max_value) {}
560560

561561
Image::~Image() {
562-
free(this->data.raw);
562+
if (this->data.raw) {
563+
free(this->data.raw);
564+
}
563565
}
564566

565567
bool Image::operator==(const Image& other) const {
@@ -1718,4 +1720,140 @@ void Image::resize_blit(const Image& source, ssize_t x, ssize_t y, ssize_t w,
17181720
}
17191721
}
17201722

1723+
static inline constexpr size_t byte_count_for_bit_count(size_t bit_count) {
1724+
return (bit_count + 7) & (~7);
1725+
}
1726+
1727+
BitmapImage::BitmapImage() : width(0), height(0), row_bytes(0), data(nullptr) {}
1728+
1729+
BitmapImage::BitmapImage(size_t w, size_t h)
1730+
: width(w),
1731+
height(h),
1732+
row_bytes(byte_count_for_bit_count(this->height)),
1733+
data(new uint8_t[this->get_data_size()]) {
1734+
memset(this->data, 0, this->get_data_size());
1735+
}
1736+
1737+
BitmapImage::BitmapImage(const BitmapImage& im)
1738+
: width(im.width),
1739+
height(im.height),
1740+
row_bytes(byte_count_for_bit_count(this->height)),
1741+
data(new uint8_t[this->get_data_size()]) {
1742+
memcpy(this->data, im.data, this->get_data_size());
1743+
}
1744+
1745+
const BitmapImage& BitmapImage::operator=(const BitmapImage& im) {
1746+
this->width = im.width;
1747+
this->height = im.height;
1748+
this->row_bytes = im.row_bytes;
1749+
size_t num_bytes = this->get_data_size();
1750+
if (this->data) {
1751+
delete[] this->data;
1752+
}
1753+
this->data = new uint8_t[num_bytes];
1754+
memcpy(this->data, im.data, num_bytes);
1755+
return *this;
1756+
}
1757+
1758+
BitmapImage::BitmapImage(BitmapImage&& im) {
1759+
this->width = im.width;
1760+
this->height = im.height;
1761+
this->row_bytes = im.row_bytes;
1762+
this->data = im.data;
1763+
im.width = 0;
1764+
im.height = 0;
1765+
im.row_bytes = 0;
1766+
im.data = nullptr;
1767+
}
1768+
1769+
BitmapImage& BitmapImage::operator=(BitmapImage&& im) {
1770+
this->width = im.width;
1771+
this->height = im.height;
1772+
this->row_bytes = im.row_bytes;
1773+
if (this->data) {
1774+
delete[] this->data;
1775+
}
1776+
this->data = im.data;
1777+
im.width = 0;
1778+
im.height = 0;
1779+
im.row_bytes = 0;
1780+
im.data = nullptr;
1781+
return *this;
1782+
}
1783+
1784+
BitmapImage::BitmapImage(FILE* f, size_t width, size_t height)
1785+
: BitmapImage(width, height) {
1786+
freadx(f, this->data, this->get_data_size());
1787+
}
1788+
1789+
BitmapImage::BitmapImage(const char* filename, size_t width, size_t height)
1790+
: BitmapImage(width, height) {
1791+
auto f = fopen_unique(filename, "rb");
1792+
freadx(f.get(), this->data, this->get_data_size());
1793+
}
1794+
1795+
BitmapImage::BitmapImage(const std::string& filename, size_t width, size_t height)
1796+
: BitmapImage(filename.c_str(), width, height) {}
1797+
1798+
BitmapImage::~BitmapImage() {
1799+
if (this->data) {
1800+
delete[] this->data;
1801+
}
1802+
}
1803+
1804+
bool BitmapImage::operator==(const BitmapImage& other) const {
1805+
if ((this->width != other.width) || (this->height != other.height) || (this->row_bytes != other.row_bytes)) {
1806+
return false;
1807+
}
1808+
return !memcmp(this->data, other.data, this->get_data_size());
1809+
}
1810+
1811+
bool BitmapImage::operator!=(const BitmapImage& other) const {
1812+
return !this->operator==(other);
1813+
}
1814+
1815+
void BitmapImage::clear(bool v) {
1816+
memset(this->data, v ? 0xFF : 0x00, this->get_data_size());
1817+
}
1818+
1819+
bool BitmapImage::read_pixel(size_t x, size_t y) const {
1820+
if (x >= this->width || y >= this->height) {
1821+
throw runtime_error("out of bounds");
1822+
}
1823+
return !!(this->data[y * byte_count_for_bit_count(this->width) + (x >> 3)] & (0x80 >> (x & 7)));
1824+
}
1825+
1826+
void BitmapImage::write_pixel(size_t x, size_t y, bool v) {
1827+
if (x >= this->width || y >= this->height) {
1828+
throw runtime_error("out of bounds");
1829+
}
1830+
if (v) {
1831+
this->data[y * byte_count_for_bit_count(this->width) + (x >> 3)] |= (0x80 >> (x & 7));
1832+
} else {
1833+
this->data[y * byte_count_for_bit_count(this->width) + (x >> 3)] &= (0x7F7F >> (x & 7));
1834+
}
1835+
}
1836+
1837+
void BitmapImage::invert() {
1838+
size_t num_bytes = this->get_data_size();
1839+
for (size_t z = 0; z < num_bytes; z++) {
1840+
this->data[z] = ~this->data[z];
1841+
}
1842+
}
1843+
1844+
Image BitmapImage::to_color(uint32_t false_color, uint32_t true_color, bool add_alpha) const {
1845+
Image ret(this->width, this->height, add_alpha);
1846+
uint8_t pending_bits = 0;
1847+
for (size_t y = 0; y < this->height; y++) {
1848+
for (size_t x = 0; x < this->width; x++) {
1849+
if (!(x & 7)) {
1850+
pending_bits = this->data[(y * this->row_bytes) + (x >> 3)];
1851+
}
1852+
ret.write_pixel(x, y, (pending_bits & 0x80) ? true_color : false_color);
1853+
pending_bits <<= 1;
1854+
}
1855+
}
1856+
return ret;
1857+
}
1858+
17211859
} // namespace phosg

src/Image.hh

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace phosg {
1313

14-
// an Image represents a drawing canvas. this class is fairly simple; it
14+
// An Image represents a drawing canvas. This class is fairly simple; it
1515
// supports reading/writing individual pixels, drawing lines, and saving the
1616
// image as a PPM or Windows BMP file.
1717
class Image {
@@ -24,6 +24,8 @@ public:
2424
// copy/move from another image
2525
Image(const Image&);
2626
Image(Image&&);
27+
const Image& operator=(const Image& other);
28+
Image& operator=(Image&& other);
2729

2830
// load a file (autodetect format)
2931
explicit Image(FILE* f);
@@ -42,9 +44,6 @@ public:
4244

4345
~Image();
4446

45-
const Image& operator=(const Image& other);
46-
Image& operator=(Image&& other);
47-
4847
bool operator==(const Image& other) const;
4948
bool operator!=(const Image& other) const;
5049

@@ -196,4 +195,56 @@ private:
196195
void save_helper(Format format, Writer&& writer) const;
197196
};
198197

198+
// A BitmapImage represents a monochrome (black and white) drawing canvas
199+
class BitmapImage {
200+
public:
201+
BitmapImage();
202+
BitmapImage(size_t w, size_t h);
203+
204+
BitmapImage(FILE* f, size_t width, size_t height);
205+
BitmapImage(const char* filename, size_t width, size_t height);
206+
BitmapImage(const std::string& filename, size_t width, size_t height);
207+
208+
BitmapImage(const BitmapImage&);
209+
BitmapImage(BitmapImage&&);
210+
const BitmapImage& operator=(const BitmapImage& other);
211+
BitmapImage& operator=(BitmapImage&& other);
212+
213+
~BitmapImage();
214+
215+
bool operator==(const BitmapImage& other) const;
216+
bool operator!=(const BitmapImage& other) const;
217+
218+
inline size_t get_width() const {
219+
return this->width;
220+
}
221+
inline size_t get_height() const {
222+
return this->height;
223+
}
224+
inline const void* get_data() const {
225+
return this->data;
226+
}
227+
inline size_t get_data_size() const {
228+
return this->height * this->row_bytes;
229+
}
230+
231+
inline bool empty() const {
232+
return (this->data == nullptr);
233+
}
234+
235+
void clear(bool v);
236+
bool read_pixel(size_t x, size_t y) const;
237+
void write_pixel(size_t x, size_t y, bool v);
238+
239+
void invert();
240+
241+
Image to_color(uint32_t false_color, uint32_t true_color, bool add_alpha) const;
242+
243+
private:
244+
size_t width;
245+
size_t height;
246+
size_t row_bytes;
247+
uint8_t* data;
248+
};
249+
199250
} // namespace phosg

0 commit comments

Comments
 (0)