bitmap-plus-plus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +40 -0
  3. data/LICENSE +25 -0
  4. data/README.md +75 -0
  5. data/examples/colormaps.rb +1857 -0
  6. data/examples/draw_primitives.rb +53 -0
  7. data/examples/julia.rb +68 -0
  8. data/examples/mandelbrot.rb +68 -0
  9. data/examples/random_colors.rb +37 -0
  10. data/examples/transformations.rb +84 -0
  11. data/ext/BitmapPlusPlus-rb.cpp +420 -0
  12. data/ext/BitmapPlusPlus-rb.hpp +11 -0
  13. data/ext/BitmapPlusPlus.hpp +659 -0
  14. data/ext/CMakeLists.txt +170 -0
  15. data/ext/CMakePresets.json +209 -0
  16. data/lib/bitmap-plus-plus/version.rb +3 -0
  17. data/lib/bitmap-plus-plus.rb +3 -0
  18. data/sig/Bmp/Bitmap.rbs +39 -0
  19. data/sig/Bmp/BitmapHeader.rbs +22 -0
  20. data/sig/Bmp/Exception.rbs +5 -0
  21. data/sig/Bmp/Pixel.rbs +16 -0
  22. data/sig/Rice/Arg.rbs +6 -0
  23. data/sig/Rice/Buffer/342/211/272Rice/352/236/211/352/236/211detail/352/236/211/352/236/211ParameterAbstract/342/210/227/342/211/273.rbs +15 -0
  24. data/sig/Rice/Buffer/342/211/272char/342/211/273.rbs +16 -0
  25. data/sig/Rice/ModuleRegistry.rbs +5 -0
  26. data/sig/Rice/Native.rbs +9 -0
  27. data/sig/Rice/NativeKind.rbs +20 -0
  28. data/sig/Rice/NativeRegistry.rbs +5 -0
  29. data/sig/Rice/Parameter.rbs +7 -0
  30. data/sig/Rice/Pointer/342/211/272Rice/352/236/211/352/236/211detail/352/236/211/352/236/211ParameterAbstract/342/210/227/342/211/273.rbs +5 -0
  31. data/sig/Rice/Pointer/342/211/272char/342/211/273.rbs +5 -0
  32. data/sig/Rice/Reference/342/211/272char/342/211/273.rbs +6 -0
  33. data/sig/Rice/Reference/342/211/272int/342/211/273.rbs +6 -0
  34. data/sig/Rice/Reference/342/211/272unsigned/302/240Int64/342/211/273.rbs +6 -0
  35. data/sig/Rice/Registries.rbs +8 -0
  36. data/sig/Rice/TypeRegistry.rbs +5 -0
  37. data/sig/Std/Exception.rbs +6 -0
  38. data/sig/Std/Filesystem/Path.rbs +6 -0
  39. data/sig/Std/RuntimeError.rbs +6 -0
  40. data/sig/Std/Vector/342/211/272Rice/352/236/211/352/236/211detail/352/236/211/352/236/211ParameterAbstract/302/240const/342/210/227/342/211/273.rbs +33 -0
  41. metadata +116 -0
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Drawing Primitives
5
+ #
6
+ # This example demonstrates the basic drawing capabilities of BitmapPlusPlus:
7
+ # - Lines
8
+ # - Rectangles (filled and outline)
9
+ # - Triangles (filled and outline)
10
+ # - Circles (filled and outline)
11
+
12
+ require "bitmap-plus-plus"
13
+
14
+ def draw_primitives
15
+ # Create a custom background color from hex value
16
+ background = Bmp::Pixel.new(0x25292e)
17
+
18
+ # Create a 512x240 bitmap
19
+ image = Bmp::Bitmap.new(512, 240)
20
+ image.clear(background)
21
+
22
+ # Draw a yellow line from position (250, 50) to position (500, 50)
23
+ image.draw_line(250, 50, 500, 50, Bmp::Yellow)
24
+
25
+ # Draw a red rectangle outline at position (10, 10) with size 100x100
26
+ image.draw_rect(10, 10, 100, 100, Bmp::Red)
27
+
28
+ # Draw a white filled rectangle at position (120, 10) with size 100x100
29
+ image.fill_rect(120, 10, 100, 100, Bmp::White)
30
+
31
+ # Draw a cyan triangle outline
32
+ image.draw_triangle(60, 120, 10, 220, 120, 220, Bmp::Cyan)
33
+
34
+ # Draw a magenta filled triangle
35
+ image.fill_triangle(180, 120, 130, 220, 245, 220, Bmp::Magenta)
36
+
37
+ # Draw a gray circle outline at center (300, 170) with radius 50
38
+ image.draw_circle(300, 170, 50, Bmp::Gray)
39
+
40
+ # Draw a lime filled circle at center (420, 170) with radius 50
41
+ image.fill_circle(420, 170, 50, Bmp::Lime)
42
+
43
+ # Save the bitmap
44
+ output_path = File.join(__dir__, "output", "primitives.bmp")
45
+ Dir.mkdir(File.dirname(output_path)) unless Dir.exist?(File.dirname(output_path))
46
+ std_path = Std::Filesystem::Path.new(output_path)
47
+ image.save(std_path)
48
+
49
+ puts "Saved: #{output_path}"
50
+ puts "Image size: #{image.width}x#{image.height}"
51
+ end
52
+
53
+ draw_primitives if __FILE__ == $PROGRAM_NAME
data/examples/julia.rb ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Julia Set Fractal
5
+ #
6
+ # This example generates a Julia set fractal image using BitmapPlusPlus.
7
+ # The Julia set is similar to the Mandelbrot set but uses a fixed complex
8
+ # constant instead of varying it per pixel.
9
+
10
+ require "bitmap-plus-plus"
11
+ require_relative "colormaps"
12
+
13
+ MAX_ITERATIONS = 300
14
+
15
+ # Julia set constant - try different values for different patterns!
16
+ # Some interesting values:
17
+ # -0.70, 0.27015 (classic)
18
+ # -0.8, 0.156 (dendrite)
19
+ # -0.4, 0.6 (rabbit)
20
+ # 0.285, 0.01 (siegel disk)
21
+ CR = -0.70000
22
+ CI = 0.27015
23
+
24
+ def julia
25
+ width = 640
26
+ height = 480
27
+ image = Bmp::Bitmap.new(width, height)
28
+
29
+ puts "Generating Julia set (#{width}x#{height})..."
30
+ puts "Constant: #{CR} + #{CI}i"
31
+
32
+ height.times do |y|
33
+ puts "Row: #{y}/#{height}" if (y % 50).zero?
34
+
35
+ width.times do |x|
36
+ # Map pixel coordinates to complex plane
37
+ nextr = 1.5 * (2.0 * x / width - 1.0)
38
+ nexti = (2.0 * y / height - 1.0)
39
+
40
+ MAX_ITERATIONS.times do |i|
41
+ prevr = nextr
42
+ previ = nexti
43
+
44
+ # z = z^2 + c (where c is fixed)
45
+ nextr = prevr * prevr - previ * previ + CR
46
+ nexti = 2 * prevr * previ + CI
47
+
48
+ # Check if escaped
49
+ if (nextr * nextr + nexti * nexti) > 4
50
+ index = ((1000.0 * i) / MAX_ITERATIONS).floor
51
+ pixel = HSV_COLORMAP[index.clamp(0, HSV_COLORMAP.length - 1)]
52
+ image.set(x, y, pixel)
53
+ break
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # Save the bitmap
60
+ output_path = File.join(__dir__, "output", "julia.bmp")
61
+ Dir.mkdir(File.dirname(output_path)) unless Dir.exist?(File.dirname(output_path))
62
+ std_path = Std::Filesystem::Path.new(output_path)
63
+ image.save(std_path)
64
+
65
+ puts "Saved: #{output_path}"
66
+ end
67
+
68
+ julia if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Mandelbrot Set Fractal
5
+ #
6
+ # This example generates a Mandelbrot set fractal image using BitmapPlusPlus.
7
+ # It demonstrates:
8
+ # - Creating bitmaps with specific dimensions
9
+ # - Setting individual pixels with calculated colors
10
+ # - Using color maps for smooth coloring
11
+
12
+ require "bitmap-plus-plus"
13
+ require_relative "colormaps"
14
+
15
+ MAX_ITERATIONS = 500
16
+
17
+ def mandelbrot
18
+ width = 640
19
+ height = 480
20
+ image = Bmp::Bitmap.new(width, height)
21
+
22
+ puts "Generating Mandelbrot set (#{width}x#{height})..."
23
+
24
+ height.times do |y|
25
+ puts "Row: #{y}/#{height}" if (y % 50).zero?
26
+
27
+ width.times do |x|
28
+ # Map pixel coordinates to complex plane
29
+ cr = 1.5 * (2.0 * x / width - 1.0) - 0.5
30
+ ci = (2.0 * y / height - 1.0)
31
+
32
+ nextr = nexti = 0.0
33
+
34
+ MAX_ITERATIONS.times do |i|
35
+ prevr = nextr
36
+ previ = nexti
37
+
38
+ # z = z^2 + c
39
+ nextr = prevr * prevr - previ * previ + cr
40
+ nexti = 2 * prevr * previ + ci
41
+
42
+ # Check if escaped (|z| > 2)
43
+ if (nextr * nextr + nexti * nexti) > 4
44
+ z = Math.sqrt(nextr * nextr + nexti * nexti)
45
+
46
+ # Smooth coloring using continuous iteration count
47
+ # https://en.wikipedia.org/wiki/Mandelbrot_set#Continuous_.28smooth.29_coloring
48
+ smooth_i = i + 1 - Math.log2(Math.log2(z))
49
+ index = (1000.0 * Math.log2(1.75 + smooth_i) / Math.log2(MAX_ITERATIONS)).to_i
50
+
51
+ pixel = JET_COLORMAP[index.clamp(0, JET_COLORMAP.length - 1)]
52
+ image.set(x, y, pixel)
53
+ break
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # Save the bitmap
60
+ output_path = File.join(__dir__, "output", "mandelbrot.bmp")
61
+ Dir.mkdir(File.dirname(output_path)) unless Dir.exist?(File.dirname(output_path))
62
+ std_path = Std::Filesystem::Path.new(output_path)
63
+ image.save(std_path)
64
+
65
+ puts "Saved: #{output_path}"
66
+ end
67
+
68
+ mandelbrot if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Random Colors
5
+ #
6
+ # This example demonstrates:
7
+ # - Using the each iterator to modify pixels
8
+ # - Creating pixels with random RGB values
9
+ # - The assign method for copying pixel values
10
+
11
+ require "bitmap-plus-plus"
12
+
13
+ def random_pixel
14
+ Bmp::Pixel.new(rand(256), rand(256), rand(256))
15
+ end
16
+
17
+ def random_colors
18
+ puts "Generating random color image..."
19
+
20
+ image = Bmp::Bitmap.new(512, 512)
21
+
22
+ # Use the each iterator to set each pixel to a random color
23
+ image.each do |pixel|
24
+ pixel.assign(random_pixel)
25
+ end
26
+
27
+ # Save the bitmap
28
+ output_path = File.join(__dir__, "output", "random_colors.bmp")
29
+ Dir.mkdir(File.dirname(output_path)) unless Dir.exist?(File.dirname(output_path))
30
+ std_path = Std::Filesystem::Path.new(output_path)
31
+ image.save(std_path)
32
+
33
+ puts "Saved: #{output_path}"
34
+ puts "Total pixels: #{image.size}"
35
+ end
36
+
37
+ random_colors if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Image Transformations
5
+ #
6
+ # This example demonstrates the transformation methods:
7
+ # - flip_v (vertical flip)
8
+ # - flip_h (horizontal flip)
9
+ # - rotate_90_left
10
+ # - rotate_90_right
11
+ #
12
+ # All transformations return a new Bitmap (they are immutable operations).
13
+
14
+ require "bitmap-plus-plus"
15
+
16
+ def create_test_image
17
+ # Create an asymmetric image to clearly show transformations
18
+ image = Bmp::Bitmap.new(200, 150)
19
+ image.clear(Bmp::White)
20
+
21
+ # Draw an "F" shape to make orientation obvious
22
+ image.fill_rect(20, 20, 20, 110, Bmp::Blue) # Vertical bar
23
+ image.fill_rect(40, 20, 80, 20, Bmp::Blue) # Top horizontal
24
+ image.fill_rect(40, 60, 50, 20, Bmp::Blue) # Middle horizontal
25
+
26
+ # Add a red circle in top-right corner
27
+ image.fill_circle(160, 40, 25, Bmp::Red)
28
+
29
+ image
30
+ end
31
+
32
+ def transformations
33
+ puts "Generating transformation examples..."
34
+
35
+ output_dir = File.join(__dir__, "output")
36
+ Dir.mkdir(output_dir) unless Dir.exist?(output_dir)
37
+
38
+ # Create original image
39
+ original = create_test_image
40
+ path = File.join(output_dir, "transform_original.bmp")
41
+ std_path = Std::Filesystem::Path.new(path)
42
+ original.save(std_path)
43
+
44
+ puts "Saved: transform_original.bmp (#{original.width}x#{original.height})"
45
+
46
+ # Vertical flip
47
+ flipped_v = original.flip_v
48
+ path = File.join(output_dir, "transform_flip_v.bmp")
49
+ std_path = Std::Filesystem::Path.new(path)
50
+ flipped_v.save(std_path)
51
+ puts "Saved: transform_flip_v.bmp"
52
+
53
+ # Horizontal flip
54
+ flipped_h = original.flip_h
55
+ path = File.join(output_dir, "transform_flip_h.bmp")
56
+ std_path = Std::Filesystem::Path.new(path)
57
+ flipped_h.save(std_path)
58
+ puts "Saved: transform_flip_h.bmp"
59
+
60
+ # Rotate 90 degrees left (counter-clockwise)
61
+ rotated_left = original.rotate_90_left
62
+ path = File.join(output_dir, "transform_rotate_left.bmp")
63
+ std_path = Std::Filesystem::Path.new(path)
64
+ rotated_left.save(std_path)
65
+ puts "Saved: transform_rotate_left.bmp (#{rotated_left.width}x#{rotated_left.height})"
66
+
67
+ # Rotate 90 degrees right (clockwise)
68
+ rotated_right = original.rotate_90_right
69
+ path = File.join(output_dir, "transform_rotate_right.bmp")
70
+ std_path = Std::Filesystem::Path.new(path)
71
+ rotated_right.save(std_path)
72
+ puts "Saved: transform_rotate_right.bmp (#{rotated_right.width}x#{rotated_right.height})"
73
+
74
+ # Chain transformations: flip both ways = 180 degree rotation
75
+ rotated_180 = original.flip_v.flip_h
76
+ path = File.join(output_dir, "transform_rotate_180.bmp")
77
+ std_path = Std::Filesystem::Path.new(path)
78
+ rotated_180.save(std_path)
79
+ puts "Saved: transform_rotate_180.bmp (flip_v + flip_h)"
80
+
81
+ puts "\nAll transformations complete!"
82
+ end
83
+
84
+ transformations if __FILE__ == $PROGRAM_NAME