From 964f4cde7f7760d4c244206fdd51807db48da8ff Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Sat, 24 Mar 2018 14:38:43 +1100 Subject: [PATCH 01/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/readme.md b/readme.md index 76de6fa..139720d 100644 --- a/readme.md +++ b/readme.md @@ -1042,6 +1042,67 @@ int main() ---- +#### Simple Example 13 - Phyllotaxis Spiral +The following example renders a Phyllotaxis spiral upon a copper +plasma background. The example demonstrates the use of the cartesian +canvas, circle fill function, and colour maps. Once complete the +rendering will be saved to disk with the name: *'phyllotaxis.bmp'*. + + +```c++ +#include +#include +#include "bitmap_image.hpp" + +int main() +{ + const int canvas_width = 600; + const int canvas_height = 600; + + const double pi = 3.1415926535897932384626433832795028841971; + const double phi = pi * (3.0 - std::sqrt(5.0)); + const double radius = (std::min(canvas_width, canvas_height) / 2.0) - 10.0; + const double p_radius = 4.0; + const double N = 1000.0; + const double spread = radius / std::sqrt(N); + + cartesian_canvas canvas(canvas_width,canvas_height); + + { + // Render background using Plasma effect + const double c1 = 0.9; + const double c2 = 0.5; + const double c3 = 0.3; + const double c4 = 0.7; + + bitmap_image& image = canvas.image(); + + ::srand(0xA5AA5AA5); + + plasma(image, 0, 0, image.width(), image.height(), c1, c2, c3, c4, 3.0, copper_colormap); + } + + for (double i = 0.0; i < N; ++i) + { + const double theta = phi * i; + const double d = spread * std::sqrt(i); + const double x = d * std::cos(theta); + const double y = d * std::sin(theta); + + canvas.pen_color(hsv_colormap[((int)i) % 1000]); + canvas.fill_circle(x, y, p_radius); + } + + canvas.image().save_image("phyllotaxis.bmp"); + + return 0; +} +``` + +![ScreenShot](http://www.partow.net/programming/bitmap/images/phyllotaxis.png?raw=true "C++ Bitmap Library Phyllotaxis Spiral - By Arash Partow") + +---- + #### Final Note The above examples are for exposition purposes, primarily intended to demonstrate the functionality of the bitmap_image library using short, From d9bc59a7bbd080ec53a913c0ddf5f207b8d6ca8c Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Sat, 24 Mar 2018 16:02:00 +1100 Subject: [PATCH 02/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 139720d..c6668f1 100644 --- a/readme.md +++ b/readme.md @@ -1061,10 +1061,10 @@ int main() const double pi = 3.1415926535897932384626433832795028841971; const double phi = pi * (3.0 - std::sqrt(5.0)); - const double radius = (std::min(canvas_width, canvas_height) / 2.0) - 10.0; - const double p_radius = 4.0; - const double N = 1000.0; + const double radius = (std::min(canvas_width, canvas_height) / 2.0) - 5.0; + const double N = 1200.0; const double spread = radius / std::sqrt(N); + const double p_radius = std::floor(spread / 2.0); cartesian_canvas canvas(canvas_width,canvas_height); @@ -1089,7 +1089,7 @@ int main() const double x = d * std::cos(theta); const double y = d * std::sin(theta); - canvas.pen_color(hsv_colormap[((int)i) % 1000]); + canvas.pen_color(hsv_colormap[static_cast(1000.0 * (i / N))]); canvas.fill_circle(x, y, p_radius); } From 2dbb8e2476409d70c915d08717a5060c96f6b5e5 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Tue, 27 Mar 2018 18:33:41 +1100 Subject: [PATCH 03/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- bitmap_image.hpp | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/bitmap_image.hpp b/bitmap_image.hpp index 33e114d..e7c7220 100644 --- a/bitmap_image.hpp +++ b/bitmap_image.hpp @@ -49,6 +49,13 @@ class bitmap_image red_plane = 2 }; + struct rgb_t + { + unsigned char red; + unsigned char green; + unsigned char blue; + }; + bitmap_image() : file_name_(""), width_ (0), @@ -164,10 +171,11 @@ class bitmap_image { const unsigned int y_offset = y * row_increment_; const unsigned int x_offset = x * bytes_per_pixel_; + const unsigned int offset = y_offset + x_offset; - blue = data_[y_offset + x_offset + 0]; - green = data_[y_offset + x_offset + 1]; - red = data_[y_offset + x_offset + 2]; + blue = data_[offset + 0]; + green = data_[offset + 1]; + red = data_[offset + 2]; } template @@ -176,6 +184,13 @@ class bitmap_image get_pixel(x, y, colour.red, colour.green, colour.blue); } + inline rgb_t get_pixel(const unsigned int x, const unsigned int y) const + { + rgb_t colour; + get_pixel(x, y, colour.red, colour.green, colour.blue); + return colour; + } + inline void set_pixel(const unsigned int x, const unsigned int y, const unsigned char red, const unsigned char green, @@ -183,10 +198,11 @@ class bitmap_image { const unsigned int y_offset = y * row_increment_; const unsigned int x_offset = x * bytes_per_pixel_; + const unsigned int offset = y_offset + x_offset; - data_[y_offset + x_offset + 0] = blue; - data_[y_offset + x_offset + 1] = green; - data_[y_offset + x_offset + 2] = red; + data_[offset + 0] = blue; + data_[offset + 1] = green; + data_[offset + 2] = red; } template @@ -1606,12 +1622,7 @@ class bitmap_image std::vector data_; }; -struct rgb_t -{ - unsigned char red; - unsigned char green; - unsigned char blue; -}; +typedef bitmap_image::rgb_t rgb_t; inline bool operator==(const rgb_t& c0, const rgb_t& c1) { From aecf15abc81a1bc9471ca27f0158ca147f355ab8 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Tue, 27 Mar 2018 18:41:33 +1100 Subject: [PATCH 04/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index c6668f1..8f142b1 100644 --- a/readme.md +++ b/readme.md @@ -415,7 +415,76 @@ int main() ---- -#### Simple Example 7 - Maze Generation +#### Simple Example 7 - Frosted Glass Effect +The following example will render a baseline image using a +combination of plasma and checkered pattern effects. Then +proceed to apply a frosted glass diffusion effect upon the +base image. Finally the frosted glass version of the image +will be saved to 'glass_effect.bmp'. + +```c++ +#include +#include +#include "bitmap_image.hpp" + +int main() +{ + const int width = 600; + const int height = 600; + const int kernel_size = 10; + + bitmap_image base(width,height); + + base.clear(); + + { + const double c1 = 0.8; + const double c2 = 0.4; + const double c3 = 0.2; + const double c4 = 0.6; + + ::srand(0xA5AA57A5); + + plasma(base, 0, 0, base.width(), base.height(), c1, c2, c3, c4, 3.0, jet_colormap); + + checkered_pattern(30, 30, 230, bitmap_image:: red_plane, base); + checkered_pattern(30, 30, 0, bitmap_image::green_plane, base); + checkered_pattern(30, 30, 100, bitmap_image:: blue_plane, base); + } + + bitmap_image glass_image(base.width(),base.height()); + + glass_image = base; + + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + const unsigned int min_x = std::max(0, x - kernel_size); + const unsigned int min_y = std::max(0, y - kernel_size); + const unsigned int max_x = std::min(x + kernel_size, width - 1); + const unsigned int max_y = std::min(y + kernel_size, height - 1); + const unsigned int dx = (max_x - min_x); + const unsigned int dy = (max_y - min_y); + const unsigned int N = rand() % (dx * dy); + const unsigned int cx = (N % dx) + min_x; + const unsigned int cy = (N / dx) + min_y; + + glass_image.set_pixel(x, y, base.get_pixel(cx, cy)); + } + } + + glass_image.save_image("glass_effect.bmp"); + + return 0; +} +``` + +![ScreenShot](http://www.partow.net/programming/bitmap/images/glass_effect.png?raw=true "C++ Bitmap Library Frosted Glass Effect Example - By Arash Partow") + +---- + +#### Simple Example 8 - Maze Generation The following example will render a maze generated using a simple recursive backtracking algorithm. The example demonstrates the use of the drawing and colouring functionalities. Once the maze has been @@ -559,7 +628,7 @@ int main() ---- -#### Simple Example 8 - Fireballs Along A Lissajous Curve +#### Simple Example 9 - Fireballs Along A Lissajous Curve The following example is an old-school graphical effect of rendering fireballs that have been placed equidistant to their immediate neighbours following a Lissajous curve. The fireballs will then @@ -728,7 +797,7 @@ int main() ---- -#### Simple Example 9 - Sierpinski Triangle Via Monte-Carlo Method +#### Simple Example 10 - Sierpinski Triangle Via Monte-Carlo Method The following example will render the Sierpinski triangle fractal using a linear difference equation based monte-carlo process, and then proceed to save the generated bitmap as *'sierpinski_triangle.bmp'*. @@ -792,7 +861,7 @@ int main() ---- -#### Simple Example 10 - Circles And Equilateral Triangles +#### Simple Example 11 - Circles And Equilateral Triangles The following example randomly generate circles and proceed to inscribe multiple levels of inner equilateral triangles. The example demonstrates the use of the cartesian canvas, pen functions, various @@ -883,7 +952,7 @@ int main() ---- -#### Simple Example 11 - Archimedean Spirals +#### Simple Example 12 - Archimedean Spirals The following example renders Archimedean spirals upon a gray-scale plasma background. The example demonstrates the use of the cartesian canvas, pen functions, and colour maps. Once complete the rendering @@ -977,7 +1046,7 @@ int main() ---- -#### Simple Example 12 - Image Shuffle +#### Simple Example 13 - Image Shuffle The following example will take as input *'tiger.bmp'*. Then proceed to dissect the image into 9 cells of 3x3, then proceed to randomly shuffle cells. The example demonstrates the copying to-and-from @@ -1042,7 +1111,7 @@ int main() ---- -#### Simple Example 13 - Phyllotaxis Spiral +#### Simple Example 14 - Phyllotaxis Spiral The following example renders a Phyllotaxis spiral upon a copper plasma background. The example demonstrates the use of the cartesian canvas, circle fill function, and colour maps. Once complete the From ab5f32eddd0a250927a562086ed38f474c00d0ce Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Wed, 28 Mar 2018 15:41:38 +1100 Subject: [PATCH 05/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8f142b1..80dcc53 100644 --- a/readme.md +++ b/readme.md @@ -1117,7 +1117,6 @@ plasma background. The example demonstrates the use of the cartesian canvas, circle fill function, and colour maps. Once complete the rendering will be saved to disk with the name: *'phyllotaxis.bmp'*. - ```c++ #include #include @@ -1172,6 +1171,53 @@ int main() ---- +#### Simple Example 15 - Pointillist Effect +The following example will render an input image of a *Sunflower* +using an approximation of the Pointillist painting technique. Once +the rendering is complete the image will be saved to disk with the +name: *'pointillist.bmp'*. + +```c++ +#include +#include +#include "bitmap_image.hpp" + +int main() +{ + bitmap_image base("sunflower.bmp"); + + cartesian_canvas canvas(base.width(),base.height()); + canvas.image() = base; + + const int pixel_count = base.width() * base.height(); + const int N = static_cast(pixel_count * 0.03); // 3% of pixels + const double rnd_ratio = pixel_count / (1.0 + RAND_MAX); + + ::srand(0xA57A57A5); + + for (int i = 0; i < N; ++i) + { + const int r = static_cast(rand() * rnd_ratio); + const int x = (r % base.width()); + const int y = (r / base.width()); + const double cx = x - (base.width() / 2.0); + const double cy = (base.height() / 2.0) - y; + const double radius = 5.0 + (r % 5); + + canvas.pen_color(base.get_pixel(x, y)); + canvas.fill_circle(cx, cy, radius); + } + + canvas.image().save_image("pointillist.bmp"); + + return 0; +} +``` + +![ScreenShot](http://www.partow.net/programming/bitmap/images/pointillist.png?raw=true "C++ Bitmap Library Pointillist Effect - By Arash Partow") + +---- + #### Final Note The above examples are for exposition purposes, primarily intended to demonstrate the functionality of the bitmap_image library using short, From 4e1d5f6cd0d0b40541ec31c5655df4e90298428f Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Wed, 28 Mar 2018 15:43:59 +1100 Subject: [PATCH 06/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.md b/readme.md index 80dcc53..306c1c6 100644 --- a/readme.md +++ b/readme.md @@ -1178,7 +1178,6 @@ the rendering is complete the image will be saved to disk with the name: *'pointillist.bmp'*. ```c++ -#include #include #include "bitmap_image.hpp" From 11f00d149b64f43e5ed14935efff42ef2fef3dd3 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Wed, 28 Mar 2018 17:28:21 +1100 Subject: [PATCH 07/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 306c1c6..e078dc0 100644 --- a/readme.md +++ b/readme.md @@ -1171,9 +1171,9 @@ int main() ---- -#### Simple Example 15 - Pointillist Effect +#### Simple Example 15 - Pointillism Effect The following example will render an input image of a *Sunflower* -using an approximation of the Pointillist painting technique. Once +using an approximation of the Pointillism painting technique. Once the rendering is complete the image will be saved to disk with the name: *'pointillist.bmp'*. @@ -1201,7 +1201,7 @@ int main() const int y = (r / base.width()); const double cx = x - (base.width() / 2.0); const double cy = (base.height() / 2.0) - y; - const double radius = 5.0 + (r % 5); + const double radius = 1.0 + (r % 7); canvas.pen_color(base.get_pixel(x, y)); canvas.fill_circle(cx, cy, radius); @@ -1213,7 +1213,7 @@ int main() } ``` -![ScreenShot](http://www.partow.net/programming/bitmap/images/pointillist.png?raw=true "C++ Bitmap Library Pointillist Effect - By Arash Partow") +![ScreenShot](http://www.partow.net/programming/bitmap/images/pointillist.png?raw=true "C++ Bitmap Library Pointillism Effect - By Arash Partow") ---- From 9c76ab9c719b03ff904f54283743ebe7bef55f26 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Sun, 22 Apr 2018 18:08:00 +1000 Subject: [PATCH 08/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index e078dc0..c10dcb7 100644 --- a/readme.md +++ b/readme.md @@ -504,7 +504,7 @@ const move_t move[5] = { { 0, 0, 0 }, // North East South West - { 0,-1, S }, { 1, 0, W }, { 0, 1, N }, {-1, 0, E } + { 0, -1, S }, { 1, 0, W }, { 0, 1, N }, { -1, 0, E } }; const int movemap[] = {0, 1, 2, 0, 3, 0, 0, 0, 4}; @@ -532,9 +532,9 @@ void generate_maze(int cx, int cy, response_image& maze) if ( (x < 0) || (y < 0) || - (untouched != maze(x,y)) || (x >= (int)maze.width ()) || - (y >= (int)maze.height()) + (y >= (int)maze.height()) || + (untouched != maze(x,y)) ) continue; From b02297f41ce58e1380837c77ae3d09dd871758f2 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Sun, 23 Dec 2018 06:07:48 +1100 Subject: [PATCH 09/10] C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d88c773..c4e7b2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: cpp sudo: required -dist: trusty +dist: xenial compiler: - gcc From db80ca605a952e6a8ccd42eba3fcc5b40fba5640 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 30 May 2019 00:31:14 -0700 Subject: [PATCH 10/10] Implement write_image()/read_image() functions to write/read bmp images to/from STL streams for flexibility --- bitmap_image.hpp | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/bitmap_image.hpp b/bitmap_image.hpp index e7c7220..5a71c25 100644 --- a/bitmap_image.hpp +++ b/bitmap_image.hpp @@ -438,6 +438,13 @@ class bitmap_image return; } + write_image(stream); + + stream.close(); + } + + void write_image(std::ostream& stream) const + { bitmap_information_header bih; bih.width = width_; @@ -473,8 +480,6 @@ class bitmap_image stream.write(reinterpret_cast(data_ptr), sizeof(unsigned char) * bytes_per_pixel_ * width_); stream.write(padding_data,padding); } - - stream.close(); } inline void set_all_ith_bits_low(const unsigned int bitr_index) @@ -1380,18 +1385,18 @@ class bitmap_image } template - inline void read_from_stream(std::ifstream& stream,T& t) + inline void read_from_stream(std::istream& stream,T& t) { stream.read(reinterpret_cast(&t),sizeof(T)); } template - inline void write_to_stream(std::ofstream& stream,const T& t) const + inline void write_to_stream(std::ostream& stream,const T& t) const { stream.write(reinterpret_cast(&t),sizeof(T)); } - inline void read_bfh(std::ifstream& stream, bitmap_file_header& bfh) + inline void read_bfh(std::istream& stream, bitmap_file_header& bfh) { read_from_stream(stream,bfh.type ); read_from_stream(stream,bfh.size ); @@ -1409,7 +1414,7 @@ class bitmap_image } } - inline void write_bfh(std::ofstream& stream, const bitmap_file_header& bfh) const + inline void write_bfh(std::ostream& stream, const bitmap_file_header& bfh) const { if (big_endian()) { @@ -1429,7 +1434,7 @@ class bitmap_image } } - inline void read_bih(std::ifstream& stream,bitmap_information_header& bih) + inline void read_bih(std::istream& stream,bitmap_information_header& bih) { read_from_stream(stream,bih.size ); read_from_stream(stream,bih.width ); @@ -1459,7 +1464,7 @@ class bitmap_image } } - inline void write_bih(std::ofstream& stream, const bitmap_information_header& bih) const + inline void write_bih(std::ostream& stream, const bitmap_information_header& bih) const { if (big_endian()) { @@ -1515,6 +1520,13 @@ class bitmap_image return; } + read_bitmap(stream); + + stream.close(); + } + + bool read_bitmap(std::istream& stream) + { width_ = 0; height_ = 0; @@ -1532,10 +1544,8 @@ class bitmap_image bfh.clear(); bih.clear(); - stream.close(); - std::cerr << "bitmap_image::load_bitmap() ERROR: bitmap_image - Invalid type value " << bfh.type << " expected 19778." << std::endl; - return; + return false; } if (bih.bit_count != 24) @@ -1543,11 +1553,9 @@ class bitmap_image bfh.clear(); bih.clear(); - stream.close(); - std::cerr << "bitmap_image::load_bitmap() ERROR: bitmap_image - Invalid bit depth " << bih.bit_count << " expected 24." << std::endl; - return; + return false; } if (bih.size != bih.struct_size()) @@ -1555,11 +1563,9 @@ class bitmap_image bfh.clear(); bih.clear(); - stream.close(); - std::cerr << "bitmap_image::load_bitmap() ERROR: bitmap_image - Invalid BIH size " << bih.size << " expected " << bih.struct_size() << std::endl; - return; + return false; } width_ = bih.width; @@ -1582,13 +1588,11 @@ class bitmap_image bfh.clear(); bih.clear(); - stream.close(); - std::cerr << "bitmap_image::load_bitmap() ERROR: bitmap_image - Mismatch between logical and physical sizes of bitmap. " << "Logical: " << bitmap_logical_size << " " << "Physical: " << bitmap_file_size << std::endl; - return; + return false; } create_bitmap(); @@ -1600,6 +1604,8 @@ class bitmap_image stream.read(reinterpret_cast(data_ptr), sizeof(char) * bytes_per_pixel_ * width_); stream.read(padding_data,padding); } + + return true; } template