Skip to content

Commit 94af1e2

Browse files
committed
C++ Bitmap Image Reader Writer Library http://partow.net/programming/bitmap/index.html
1 parent 7b671cb commit 94af1e2

File tree

3 files changed

+208
-22
lines changed

3 files changed

+208
-22
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: cpp
22

33
sudo: required
44

5-
dist: trusty
5+
dist: xenial
66

77
compiler:
88
- gcc

bitmap_image.hpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ class bitmap_image
4949
red_plane = 2
5050
};
5151

52+
struct rgb_t
53+
{
54+
unsigned char red;
55+
unsigned char green;
56+
unsigned char blue;
57+
};
58+
5259
bitmap_image()
5360
: file_name_(""),
5461
width_ (0),
@@ -164,10 +171,11 @@ class bitmap_image
164171
{
165172
const unsigned int y_offset = y * row_increment_;
166173
const unsigned int x_offset = x * bytes_per_pixel_;
174+
const unsigned int offset = y_offset + x_offset;
167175

168-
blue = data_[y_offset + x_offset + 0];
169-
green = data_[y_offset + x_offset + 1];
170-
red = data_[y_offset + x_offset + 2];
176+
blue = data_[offset + 0];
177+
green = data_[offset + 1];
178+
red = data_[offset + 2];
171179
}
172180

173181
template <typename RGB>
@@ -176,17 +184,25 @@ class bitmap_image
176184
get_pixel(x, y, colour.red, colour.green, colour.blue);
177185
}
178186

187+
inline rgb_t get_pixel(const unsigned int x, const unsigned int y) const
188+
{
189+
rgb_t colour;
190+
get_pixel(x, y, colour.red, colour.green, colour.blue);
191+
return colour;
192+
}
193+
179194
inline void set_pixel(const unsigned int x, const unsigned int y,
180195
const unsigned char red,
181196
const unsigned char green,
182197
const unsigned char blue)
183198
{
184199
const unsigned int y_offset = y * row_increment_;
185200
const unsigned int x_offset = x * bytes_per_pixel_;
201+
const unsigned int offset = y_offset + x_offset;
186202

187-
data_[y_offset + x_offset + 0] = blue;
188-
data_[y_offset + x_offset + 1] = green;
189-
data_[y_offset + x_offset + 2] = red;
203+
data_[offset + 0] = blue;
204+
data_[offset + 1] = green;
205+
data_[offset + 2] = red;
190206
}
191207

192208
template <typename RGB>
@@ -1606,12 +1622,7 @@ class bitmap_image
16061622
std::vector<unsigned char> data_;
16071623
};
16081624

1609-
struct rgb_t
1610-
{
1611-
unsigned char red;
1612-
unsigned char green;
1613-
unsigned char blue;
1614-
};
1625+
typedef bitmap_image::rgb_t rgb_t;
16151626

16161627
inline bool operator==(const rgb_t& c0, const rgb_t& c1)
16171628
{

readme.md

Lines changed: 184 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,76 @@ int main()
415415

416416
----
417417

418-
#### Simple Example 7 - Maze Generation
418+
#### Simple Example 7 - Frosted Glass Effect
419+
The following example will render a baseline image using a
420+
combination of plasma and checkered pattern effects. Then
421+
proceed to apply a frosted glass diffusion effect upon the
422+
base image. Finally the frosted glass version of the image
423+
will be saved to 'glass_effect.bmp'.
424+
425+
```c++
426+
#include <algorithm>
427+
#include <cstdlib>
428+
#include "bitmap_image.hpp"
429+
430+
int main()
431+
{
432+
const int width = 600;
433+
const int height = 600;
434+
const int kernel_size = 10;
435+
436+
bitmap_image base(width,height);
437+
438+
base.clear();
439+
440+
{
441+
const double c1 = 0.8;
442+
const double c2 = 0.4;
443+
const double c3 = 0.2;
444+
const double c4 = 0.6;
445+
446+
::srand(0xA5AA57A5);
447+
448+
plasma(base, 0, 0, base.width(), base.height(), c1, c2, c3, c4, 3.0, jet_colormap);
449+
450+
checkered_pattern(30, 30, 230, bitmap_image:: red_plane, base);
451+
checkered_pattern(30, 30, 0, bitmap_image::green_plane, base);
452+
checkered_pattern(30, 30, 100, bitmap_image:: blue_plane, base);
453+
}
454+
455+
bitmap_image glass_image(base.width(),base.height());
456+
457+
glass_image = base;
458+
459+
for (int y = 0; y < height; ++y)
460+
{
461+
for (int x = 0; x < width; ++x)
462+
{
463+
const unsigned int min_x = std::max(0, x - kernel_size);
464+
const unsigned int min_y = std::max(0, y - kernel_size);
465+
const unsigned int max_x = std::min(x + kernel_size, width - 1);
466+
const unsigned int max_y = std::min(y + kernel_size, height - 1);
467+
const unsigned int dx = (max_x - min_x);
468+
const unsigned int dy = (max_y - min_y);
469+
const unsigned int N = rand() % (dx * dy);
470+
const unsigned int cx = (N % dx) + min_x;
471+
const unsigned int cy = (N / dx) + min_y;
472+
473+
glass_image.set_pixel(x, y, base.get_pixel(cx, cy));
474+
}
475+
}
476+
477+
glass_image.save_image("glass_effect.bmp");
478+
479+
return 0;
480+
}
481+
```
482+
483+
![ScreenShot](http://www.partow.net/programming/bitmap/images/glass_effect.png?raw=true "C++ Bitmap Library Frosted Glass Effect Example - By Arash Partow")
484+
485+
----
486+
487+
#### Simple Example 8 - Maze Generation
419488
The following example will render a maze generated using a simple
420489
recursive backtracking algorithm. The example demonstrates the use of
421490
the drawing and colouring functionalities. Once the maze has been
@@ -435,7 +504,7 @@ const move_t move[5] =
435504
{
436505
{ 0, 0, 0 },
437506
// North East South West
438-
{ 0,-1, S }, { 1, 0, W }, { 0, 1, N }, {-1, 0, E }
507+
{ 0, -1, S }, { 1, 0, W }, { 0, 1, N }, { -1, 0, E }
439508
};
440509

441510
const int movemap[] = {0, 1, 2, 0, 3, 0, 0, 0, 4};
@@ -463,9 +532,9 @@ void generate_maze(int cx, int cy, response_image<int>& maze)
463532

464533
if (
465534
(x < 0) || (y < 0) ||
466-
(untouched != maze(x,y)) ||
467535
(x >= (int)maze.width ()) ||
468-
(y >= (int)maze.height())
536+
(y >= (int)maze.height()) ||
537+
(untouched != maze(x,y))
469538
)
470539
continue;
471540

@@ -559,7 +628,7 @@ int main()
559628
560629
----
561630
562-
#### Simple Example 8 - Fireballs Along A Lissajous Curve
631+
#### Simple Example 9 - Fireballs Along A Lissajous Curve
563632
The following example is an old-school graphical effect of rendering
564633
fireballs that have been placed equidistant to their immediate
565634
neighbours following a Lissajous curve. The fireballs will then
@@ -728,7 +797,7 @@ int main()
728797

729798
----
730799

731-
#### Simple Example 9 - Sierpinski Triangle Via Monte-Carlo Method
800+
#### Simple Example 10 - Sierpinski Triangle Via Monte-Carlo Method
732801
The following example will render the Sierpinski triangle fractal
733802
using a linear difference equation based monte-carlo process, and then
734803
proceed to save the generated bitmap as *'sierpinski_triangle.bmp'*.
@@ -792,7 +861,7 @@ int main()
792861
793862
----
794863
795-
#### Simple Example 10 - Circles And Equilateral Triangles
864+
#### Simple Example 11 - Circles And Equilateral Triangles
796865
The following example randomly generate circles and proceed to
797866
inscribe multiple levels of inner equilateral triangles. The example
798867
demonstrates the use of the cartesian canvas, pen functions, various
@@ -883,7 +952,7 @@ int main()
883952

884953
----
885954

886-
#### Simple Example 11 - Archimedean Spirals
955+
#### Simple Example 12 - Archimedean Spirals
887956
The following example renders Archimedean spirals upon a gray-scale
888957
plasma background. The example demonstrates the use of the cartesian
889958
canvas, pen functions, and colour maps. Once complete the rendering
@@ -977,7 +1046,7 @@ int main()
9771046
9781047
----
9791048
980-
#### Simple Example 12 - Image Shuffle
1049+
#### Simple Example 13 - Image Shuffle
9811050
The following example will take as input *'tiger.bmp'*. Then proceed
9821051
to dissect the image into 9 cells of 3x3, then proceed to randomly
9831052
shuffle cells. The example demonstrates the copying to-and-from
@@ -1042,6 +1111,112 @@ int main()
10421111

10431112
----
10441113

1114+
#### Simple Example 14 - Phyllotaxis Spiral
1115+
The following example renders a Phyllotaxis spiral upon a copper
1116+
plasma background. The example demonstrates the use of the cartesian
1117+
canvas, circle fill function, and colour maps. Once complete the
1118+
rendering will be saved to disk with the name: *'phyllotaxis.bmp'*.
1119+
1120+
```c++
1121+
#include <cmath>
1122+
#include <cstdlib>
1123+
#include "bitmap_image.hpp"
1124+
1125+
int main()
1126+
{
1127+
const int canvas_width = 600;
1128+
const int canvas_height = 600;
1129+
1130+
const double pi = 3.1415926535897932384626433832795028841971;
1131+
const double phi = pi * (3.0 - std::sqrt(5.0));
1132+
const double radius = (std::min(canvas_width, canvas_height) / 2.0) - 5.0;
1133+
const double N = 1200.0;
1134+
const double spread = radius / std::sqrt(N);
1135+
const double p_radius = std::floor(spread / 2.0);
1136+
1137+
cartesian_canvas canvas(canvas_width,canvas_height);
1138+
1139+
{
1140+
// Render background using Plasma effect
1141+
const double c1 = 0.9;
1142+
const double c2 = 0.5;
1143+
const double c3 = 0.3;
1144+
const double c4 = 0.7;
1145+
1146+
bitmap_image& image = canvas.image();
1147+
1148+
::srand(0xA5AA5AA5);
1149+
1150+
plasma(image, 0, 0, image.width(), image.height(), c1, c2, c3, c4, 3.0, copper_colormap);
1151+
}
1152+
1153+
for (double i = 0.0; i < N; ++i)
1154+
{
1155+
const double theta = phi * i;
1156+
const double d = spread * std::sqrt(i);
1157+
const double x = d * std::cos(theta);
1158+
const double y = d * std::sin(theta);
1159+
1160+
canvas.pen_color(hsv_colormap[static_cast<std::size_t>(1000.0 * (i / N))]);
1161+
canvas.fill_circle(x, y, p_radius);
1162+
}
1163+
1164+
canvas.image().save_image("phyllotaxis.bmp");
1165+
1166+
return 0;
1167+
}
1168+
```
1169+
1170+
![ScreenShot](http://www.partow.net/programming/bitmap/images/phyllotaxis.png?raw=true "C++ Bitmap Library Phyllotaxis Spiral - By Arash Partow")
1171+
1172+
----
1173+
1174+
#### Simple Example 15 - Pointillism Effect
1175+
The following example will render an input image of a *Sunflower*
1176+
using an approximation of the Pointillism painting technique. Once
1177+
the rendering is complete the image will be saved to disk with the
1178+
name: *'pointillist.bmp'*.
1179+
1180+
```c++
1181+
#include <cstdlib>
1182+
#include "bitmap_image.hpp"
1183+
1184+
int main()
1185+
{
1186+
bitmap_image base("sunflower.bmp");
1187+
1188+
cartesian_canvas canvas(base.width(),base.height());
1189+
canvas.image() = base;
1190+
1191+
const int pixel_count = base.width() * base.height();
1192+
const int N = static_cast<int>(pixel_count * 0.03); // 3% of pixels
1193+
const double rnd_ratio = pixel_count / (1.0 + RAND_MAX);
1194+
1195+
::srand(0xA57A57A5);
1196+
1197+
for (int i = 0; i < N; ++i)
1198+
{
1199+
const int r = static_cast<int>(rand() * rnd_ratio);
1200+
const int x = (r % base.width());
1201+
const int y = (r / base.width());
1202+
const double cx = x - (base.width() / 2.0);
1203+
const double cy = (base.height() / 2.0) - y;
1204+
const double radius = 1.0 + (r % 7);
1205+
1206+
canvas.pen_color(base.get_pixel(x, y));
1207+
canvas.fill_circle(cx, cy, radius);
1208+
}
1209+
1210+
canvas.image().save_image("pointillist.bmp");
1211+
1212+
return 0;
1213+
}
1214+
```
1215+
1216+
![ScreenShot](http://www.partow.net/programming/bitmap/images/pointillist.png?raw=true "C++ Bitmap Library Pointillism Effect - By Arash Partow")
1217+
1218+
----
1219+
10451220
#### Final Note
10461221
The above examples are for exposition purposes, primarily intended to
10471222
demonstrate the functionality of the bitmap_image library using short,

0 commit comments

Comments
 (0)