image_util 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/AGENTS.md +2 -6
- data/CHANGELOG.md +10 -6
- data/README.md +132 -85
- data/docs/samples/background.png +0 -0
- data/docs/samples/dither.png +0 -0
- data/docs/samples/draw.png +0 -0
- data/docs/samples/paste.png +0 -0
- data/docs/samples/resize.png +0 -0
- data/docs/samples/sixel.png +0 -0
- data/lib/image_util/codec/image_magick.rb +18 -9
- data/lib/image_util/codec/ruby_sixel.rb +1 -1
- data/lib/image_util/codec.rb +1 -1
- data/lib/image_util/color/css_colors.rb +156 -0
- data/lib/image_util/color.rb +6 -6
- data/lib/image_util/filter/draw.rb +23 -1
- data/lib/image_util/image.rb +5 -3
- data/lib/image_util/version.rb +1 -1
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92f9a0c088385d833ceee58b203a3ba52a4de3d2cbfdd16ed6dc8d0213e18753
|
4
|
+
data.tar.gz: 275a94eb28e30c8d1a59ba25723284e864e8ad9b8a1041826cba37d983ba01fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 523748193e1b51083729b1583cfec3ac19ec02a11e893cc3d858deb30388eebd013a01ade2770cd236c2f947bffc0cc2583783d3094552451d99b873d840311b
|
7
|
+
data.tar.gz: 228f82c3508d236822c4a6e27ad721381ffa42aaa31d1e3ab839eeaf9d60363ab2bcd7e6340fab00cdeac23320ad4681036187bd2eb5bb5680242ff9a8451464
|
data/AGENTS.md
CHANGED
@@ -6,11 +6,7 @@
|
|
6
6
|
- Prefer double-quoted strings except in specs and the gemspec.
|
7
7
|
- Use RSpec's `should` syntax instead of `expect`.
|
8
8
|
- For one-line methods, use the `def name = expression` style.
|
9
|
-
|
10
|
-
|
11
|
-
- Image data is stored in `Image::Buffer` backed by `IO::Buffer`.
|
12
|
-
- Use `Filter::Mixin#define_immutable_version` to add non-bang versions of mutating filters.
|
13
|
-
- Views such as `View::Interpolated` and `View::Rounded` are built with `Data.define`.
|
14
|
-
- Pure Ruby algorithms are provided with optional FFI wrappers for libpng, libturbojpeg and libsixel.
|
9
|
+
- After adding new features or modifying existing ones, change documentation accordingly (especially README and especially CHANGELOG).
|
10
|
+
- Don't discuss codec internals or bug fixes in README. Only list supported formats. Document bug fixes in the CHANGELOG, not in README.
|
15
11
|
- Specs target at least 80% coverage as enforced by SimpleCov.
|
16
12
|
- The library aims to remain lightweight and portable.
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
## [
|
2
|
-
|
1
|
+
## [0.2.0] - 2025-07-21
|
2
|
+
- Ruby Sixel encoder now sets pixel aspect ratio metadata to display correctly in Windows Terminal
|
3
|
+
- Support for all CSS color names
|
4
|
+
- Range assignments with images now resize the image before pasting
|
5
|
+
- Circle drawing filter
|
6
|
+
- ImageMagick codec can encode and decode `png`, `jpeg` and `sixel`
|
7
|
+
|
8
|
+
## [0.1.0] - 2025-07-21
|
9
|
+
|
10
|
+
- Initial release
|
3
11
|
- Drop support for Ruby 3.1
|
4
12
|
- Native SIXEL encoder
|
5
13
|
- Background filter
|
@@ -12,7 +20,3 @@
|
|
12
20
|
- Paste and Draw filters for compositing and drawing
|
13
21
|
- Rounded and interpolated pixel views
|
14
22
|
- `Image#view` helper for custom access
|
15
|
-
|
16
|
-
## [0.1.0] - 2025-07-19
|
17
|
-
|
18
|
-
- Initial release
|
data/README.md
CHANGED
@@ -1,144 +1,191 @@
|
|
1
1
|
# ImageUtil
|
2
2
|
|
3
|
-
ImageUtil
|
3
|
+
ImageUtil is a lightweight Ruby library focused on manipulating images directly in memory. Its primary goal is to help scripts visualize data right in the terminal by supporting SIXEL output alongside common image formats. The API is still evolving and should be considered unstable until version 1.0.
|
4
4
|
|
5
|
-
|
5
|
+
## Creating an Image
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
* A `Color` helper class capable of parsing numbers, arrays and HTML style strings.
|
10
|
-
* Conversion of an image to PAM or SIXEL for quick previews in compatible terminals.
|
11
|
-
* Built-in SIXEL encoder that works without ImageMagick.
|
12
|
-
* Convenience methods for iterating over pixel locations and setting values.
|
13
|
-
* Overlaying colors with the `+` operator which blends using the alpha channel.
|
14
|
-
* Automatic format detection when reading images from strings or files.
|
15
|
-
* Alternate pixel views for interpolated or rounded coordinates.
|
16
|
-
|
17
|
-
## Installation
|
18
|
-
|
19
|
-
ImageUtil is available on RubyGems:
|
7
|
+
```ruby
|
8
|
+
require 'image_util'
|
20
9
|
|
21
|
-
|
22
|
-
|
10
|
+
# 40×40 RGBA image
|
11
|
+
img = ImageUtil::Image.new(40, 40)
|
23
12
|
```
|
24
13
|
|
25
|
-
|
14
|
+
An optional block receives pixel coordinates and should return something that can be converted to a color. Dimensions of more than two axes are supported.
|
26
15
|
|
27
16
|
```ruby
|
28
|
-
|
17
|
+
img = ImageUtil::Image.new(4, 4) { |x, y| ImageUtil::Color[x * 64, y * 64, 0] }
|
29
18
|
```
|
30
19
|
|
31
|
-
|
20
|
+
## Loading and Saving
|
32
21
|
|
33
|
-
|
22
|
+
Instead of building an image from scratch you can load one with
|
23
|
+
`ImageUtil::Image.from_string` or `ImageUtil::Image.from_file`.
|
24
|
+
Both helpers understand the built in codecs for `png`, `jpeg` and `pam`
|
25
|
+
formats:
|
34
26
|
|
35
|
-
```
|
36
|
-
|
37
|
-
|
38
|
-
bundle exec rake install
|
27
|
+
```ruby
|
28
|
+
img = ImageUtil::Image.from_file("logo.png")
|
29
|
+
data = ImageUtil::Image.from_string(File.binread("logo.jpeg"))
|
39
30
|
```
|
40
31
|
|
41
|
-
|
32
|
+
The same formats can be written back using `to_string` or `to_file`.
|
42
33
|
|
43
34
|
```ruby
|
44
|
-
|
35
|
+
img.to_file("out.png", :png)
|
36
|
+
binary = img.to_string(:jpeg)
|
37
|
+
```
|
45
38
|
|
46
|
-
|
47
|
-
i = ImageUtil::Image.new(4, 4)
|
39
|
+
## SIXEL Output
|
48
40
|
|
49
|
-
|
50
|
-
i[0, 0] = ImageUtil::Color[255, 0, 0]
|
41
|
+
Images can be previewed in compatible terminals:
|
51
42
|
|
52
|
-
|
53
|
-
puts
|
43
|
+
```ruby
|
44
|
+
puts img.to_sixel
|
54
45
|
```
|
55
46
|
|
56
|
-
|
47
|
+
In `irb` or `pry` the `inspect` method shows the image automatically, so you can
|
48
|
+
just evaluate the object:
|
57
49
|
|
58
50
|
```ruby
|
59
|
-
|
60
|
-
|
51
|
+
img
|
52
|
+
```
|
61
53
|
|
62
|
-
|
63
|
-
i.each_pixel do |pixel|
|
64
|
-
# pixel is an ImageUtil::Color instance
|
65
|
-
end
|
54
|
+
Most notably, SIXEL works in Windows Terminal, Konsole (KDE), iTerm2 (macOS), XTerm (launch with: `xterm -ti vt340`). Here's how it looks in Konsole:
|
66
55
|
|
67
|
-
|
68
|
-
target = ImageUtil::Image.new(8, 8) { ImageUtil::Color[0] }
|
69
|
-
source = ImageUtil::Image.new(2, 2) { ImageUtil::Color[255, 0, 0, 128] }
|
70
|
-
target.paste!(source, 3, 3, respect_alpha: true)
|
56
|
+

|
71
57
|
|
72
|
-
# draw a diagonal line
|
73
|
-
i.draw_line!([0, 0], [3, 3], ImageUtil::Color['red'], view: ImageUtil::View::Rounded)
|
74
|
-
```
|
75
58
|
|
76
|
-
|
77
|
-
coordinates to the nearest pixel. These views are useful for drawing
|
78
|
-
operations like the example above.
|
59
|
+
This library supports generating Sixel with either `libsixel`, `ImageMagick` or using a pure-Ruby Sixel generator. For best performance, try to install one of the earlier system packages.
|
79
60
|
|
80
|
-
|
61
|
+
## Color Values
|
62
|
+
|
63
|
+
`ImageUtil::Color.from` (also known as `ImageUtil::Color.[]`) accepts several inputs:
|
64
|
+
|
65
|
+
- Another `Color` instance
|
66
|
+
- Arrays of numeric components (`[r, g, b]` or `[r, g, b, a]`)
|
67
|
+
- Numbers (used for all RGB channels)
|
68
|
+
- Symbols or strings containing CSS color names (`:rebeccapurple`, 'papayawhip')
|
69
|
+
- Hex strings like `'#abc'`, `'#aabbcc'` or `'#rrggbbaa'`
|
70
|
+
|
71
|
+
When numeric components are given, integers are first clamped to the `0..255`
|
72
|
+
range. Float values are treated as fractions of 255, so `0.5` becomes `127.5`
|
73
|
+
and `1.0` becomes `255`. After scaling, values are again clamped to this range.
|
74
|
+
If the alpha channel is omitted it defaults to `255`.
|
81
75
|
|
82
76
|
```ruby
|
83
|
-
#
|
84
|
-
|
77
|
+
ImageUtil::Color[0.5] # => #808080
|
78
|
+
ImageUtil::Color[:red] # => #ff0000
|
79
|
+
ImageUtil::Color["#fc0"] # => #ffcc00
|
80
|
+
```
|
81
|
+
|
82
|
+
Note that whenever the library expects a color, it may be given in any form accepted by this function.
|
85
83
|
|
86
|
-
|
87
|
-
img.to_file("out.jpg", :jpeg)
|
84
|
+
## Pixel Access
|
88
85
|
|
89
|
-
|
90
|
-
|
86
|
+
Pixels can be accessed with integer coordinates or ranges. When ranges are used
|
87
|
+
a new `Image` containing that region is returned and can be modified separately.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
img[0, 0] = '#ff0000'
|
91
|
+
patch = img[0..1, 0..1]
|
91
92
|
```
|
92
93
|
|
93
|
-
|
94
|
+
For instance, you can extract a region, edit it and paste it back:
|
94
95
|
|
95
96
|
```ruby
|
96
|
-
|
97
|
-
|
97
|
+
img = ImageUtil::Image.new(4, 4) { [0, 0, 0] }
|
98
|
+
corner = img[0..1, 0..1]
|
99
|
+
corner.all = :green
|
100
|
+
img[0..1, 0..1] = corner
|
101
|
+
img[2, 2] = :yellow
|
102
|
+
img.to_file("pixel_patch.png", :png)
|
103
|
+
```
|
98
104
|
|
99
|
-
|
100
|
-
result = base.paste(other, 10, 10)
|
105
|
+
Assigning an image to a range automatically resizes it to fit before pasting.
|
101
106
|
|
102
|
-
|
103
|
-
|
107
|
+
Iteration helpers operate on arbitrary ranges and share the same syntax used
|
108
|
+
when indexing images. `each_pixel` yields color objects, while
|
109
|
+
`each_pixel_location` yields coordinate arrays. `set_each_pixel_by_location`
|
110
|
+
assigns the value returned by the block to every location (unless `nil` is returned).
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# fill a checkerboard pattern
|
114
|
+
img = ImageUtil::Image.new(8, 8) { :white }
|
115
|
+
img.set_each_pixel_by_location do |x, y|
|
116
|
+
:black if (x + y).odd?
|
117
|
+
end
|
118
|
+
|
119
|
+
# count how many black pixels were set
|
120
|
+
black = img.each_pixel.count { |c| c == :black }
|
104
121
|
```
|
105
122
|
|
106
|
-
|
123
|
+
Note that instead of manually calling `set_each_pixel_by_location`, you can just pass a block to `ImageUtil::Image.new`.
|
124
|
+
|
125
|
+
## Filters
|
126
|
+
|
127
|
+
`ImageUtil::Image` ships with a few convenience filters. Each bang method
|
128
|
+
modifies the image in place while the non-bang version returns a copy.
|
129
|
+
|
130
|
+
### Background
|
131
|
+
|
132
|
+
Flatten an RGBA image on a solid color.
|
107
133
|
|
108
134
|
```ruby
|
109
|
-
|
110
|
-
|
111
|
-
|
135
|
+
img = ImageUtil::Image.new(128, 128) { |x, y| [255, 0, 0, x + y] }
|
136
|
+
img.background([0, 0, 255])
|
137
|
+
```
|
138
|
+
|
139
|
+

|
140
|
+
|
141
|
+
### Paste
|
142
|
+
|
143
|
+
Place one image over another. When `respect_alpha` is true, the pasted pixels are
|
144
|
+
blended with the base image.
|
112
145
|
|
113
|
-
|
114
|
-
|
115
|
-
|
146
|
+
```ruby
|
147
|
+
base = ImageUtil::Image.new(128, 128) { |x, y| [x, y, 50] }
|
148
|
+
overlay = ImageUtil::Image.new(64, 64) { |x, y| [255, 0, 0, (x + y) * 2] }
|
149
|
+
base.paste!(overlay, 32, 32, respect_alpha: true)
|
116
150
|
```
|
117
151
|
|
118
|
-
|
152
|
+

|
153
|
+
|
154
|
+
### Draw
|
119
155
|
|
120
|
-
|
121
|
-
common formats such as PNG, JPEG and SIXEL. The library ships with pure Ruby
|
122
|
-
encoders and FFI wrappers around `libpng`, `libturbojpeg` and `libsixel` when
|
123
|
-
available.
|
156
|
+
Draw simple shapes directly on the image.
|
124
157
|
|
125
158
|
```ruby
|
126
|
-
|
127
|
-
|
159
|
+
img = ImageUtil::Image.new(128, 128) { [0, 0, 0] }
|
160
|
+
img.draw_line!([0, 0], [127, 127], :red)
|
161
|
+
img.draw_line!([0, 127], [127, 0], :lime)
|
162
|
+
img.draw_circle!([64, 64], 30, :blue)
|
163
|
+
```
|
128
164
|
|
129
|
-
|
130
|
-
|
131
|
-
|
165
|
+

|
166
|
+
|
167
|
+
### Resize
|
168
|
+
|
169
|
+
Scale an image to new dimensions.
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
img = ImageUtil::Image.new(256, 256) { |x, y| [x, y, 30] }
|
173
|
+
img[70, 70] = img.resize(64, 64)
|
174
|
+
img
|
132
175
|
```
|
133
176
|
|
134
|
-
|
177
|
+

|
178
|
+
|
179
|
+
### Dither
|
180
|
+
|
181
|
+
Reduce the image to a limited palette.
|
135
182
|
|
136
183
|
```ruby
|
137
|
-
|
184
|
+
img = ImageUtil::Image.new(256, 64) { |x, y| [x, y * 4, 200] }
|
185
|
+
img.dither(8)
|
138
186
|
```
|
139
187
|
|
140
|
-
|
141
|
-
available. Unsupported formats raise `ImageUtil::Codec::UnsupportedFormatError`.
|
188
|
+

|
142
189
|
|
143
190
|
## Development
|
144
191
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ImageUtil
|
4
4
|
module Codec
|
5
5
|
module ImageMagick
|
6
|
-
SUPPORTED_FORMATS = [
|
6
|
+
SUPPORTED_FORMATS = %i[sixel jpeg png].freeze
|
7
7
|
|
8
8
|
extend Guard
|
9
9
|
|
@@ -26,10 +26,13 @@ module ImageUtil
|
|
26
26
|
def encode(format, image)
|
27
27
|
guard_supported_format!(format, SUPPORTED_FORMATS)
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
fmt = format.to_s.downcase
|
30
|
+
pam = Codec::Pam.encode(:pam, image, fill_to: fmt == "sixel" ? 6 : nil)
|
31
|
+
|
32
|
+
IO.popen(["magick", "pam:-", "#{fmt}:-"], "r+") do |proc_io|
|
33
|
+
proc_io << pam
|
34
|
+
proc_io.close_write
|
35
|
+
proc_io.read
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
@@ -37,12 +40,18 @@ module ImageUtil
|
|
37
40
|
io << encode(format, image)
|
38
41
|
end
|
39
42
|
|
40
|
-
def decode(
|
41
|
-
|
43
|
+
def decode(format, data)
|
44
|
+
guard_supported_format!(format, SUPPORTED_FORMATS)
|
45
|
+
|
46
|
+
IO.popen(["magick", "#{format}:-", "pam:-"], "r+") do |proc_io|
|
47
|
+
proc_io << data
|
48
|
+
proc_io.close_write
|
49
|
+
Pam.decode(:pam, proc_io.read)
|
50
|
+
end
|
42
51
|
end
|
43
52
|
|
44
|
-
def decode_io(
|
45
|
-
|
53
|
+
def decode_io(format, io)
|
54
|
+
decode(format, io.read)
|
46
55
|
end
|
47
56
|
end
|
48
57
|
end
|
data/lib/image_util/codec.rb
CHANGED
@@ -111,7 +111,7 @@ module ImageUtil
|
|
111
111
|
register_codec :Libpng, :png
|
112
112
|
register_codec :Libturbojpeg, :jpeg
|
113
113
|
register_encoder :Libsixel, :sixel
|
114
|
-
|
114
|
+
register_codec :ImageMagick, :png, :jpeg, :sixel
|
115
115
|
register_encoder :RubySixel, :sixel
|
116
116
|
end
|
117
117
|
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ImageUtil
|
4
|
+
class Color < Array
|
5
|
+
CSS_COLORS = {
|
6
|
+
"aliceblue" => [240, 248, 255],
|
7
|
+
"antiquewhite" => [250, 235, 215],
|
8
|
+
"aqua" => [0, 255, 255],
|
9
|
+
"aquamarine" => [127, 255, 212],
|
10
|
+
"azure" => [240, 255, 255],
|
11
|
+
"beige" => [245, 245, 220],
|
12
|
+
"bisque" => [255, 228, 196],
|
13
|
+
"black" => [0, 0, 0],
|
14
|
+
"blanchedalmond" => [255, 235, 205],
|
15
|
+
"blue" => [0, 0, 255],
|
16
|
+
"blueviolet" => [138, 43, 226],
|
17
|
+
"brown" => [165, 42, 42],
|
18
|
+
"burlywood" => [222, 184, 135],
|
19
|
+
"cadetblue" => [95, 158, 160],
|
20
|
+
"chartreuse" => [127, 255, 0],
|
21
|
+
"chocolate" => [210, 105, 30],
|
22
|
+
"coral" => [255, 127, 80],
|
23
|
+
"cornflowerblue" => [100, 149, 237],
|
24
|
+
"cornsilk" => [255, 248, 220],
|
25
|
+
"crimson" => [220, 20, 60],
|
26
|
+
"cyan" => [0, 255, 255],
|
27
|
+
"darkblue" => [0, 0, 139],
|
28
|
+
"darkcyan" => [0, 139, 139],
|
29
|
+
"darkgoldenrod" => [184, 134, 11],
|
30
|
+
"darkgray" => [169, 169, 169],
|
31
|
+
"darkgrey" => [169, 169, 169],
|
32
|
+
"darkgreen" => [0, 100, 0],
|
33
|
+
"darkkhaki" => [189, 183, 107],
|
34
|
+
"darkmagenta" => [139, 0, 139],
|
35
|
+
"darkolivegreen" => [85, 107, 47],
|
36
|
+
"darkorange" => [255, 140, 0],
|
37
|
+
"darkorchid" => [153, 50, 204],
|
38
|
+
"darkred" => [139, 0, 0],
|
39
|
+
"darksalmon" => [233, 150, 122],
|
40
|
+
"darkseagreen" => [143, 188, 143],
|
41
|
+
"darkslateblue" => [72, 61, 139],
|
42
|
+
"darkslategray" => [47, 79, 79],
|
43
|
+
"darkslategrey" => [47, 79, 79],
|
44
|
+
"darkturquoise" => [0, 206, 209],
|
45
|
+
"darkviolet" => [148, 0, 211],
|
46
|
+
"deeppink" => [255, 20, 147],
|
47
|
+
"deepskyblue" => [0, 191, 255],
|
48
|
+
"dimgray" => [105, 105, 105],
|
49
|
+
"dimgrey" => [105, 105, 105],
|
50
|
+
"dodgerblue" => [30, 144, 255],
|
51
|
+
"firebrick" => [178, 34, 34],
|
52
|
+
"floralwhite" => [255, 250, 240],
|
53
|
+
"forestgreen" => [34, 139, 34],
|
54
|
+
"fuchsia" => [255, 0, 255],
|
55
|
+
"gainsboro" => [220, 220, 220],
|
56
|
+
"ghostwhite" => [248, 248, 255],
|
57
|
+
"gold" => [255, 215, 0],
|
58
|
+
"goldenrod" => [218, 165, 32],
|
59
|
+
"gray" => [128, 128, 128],
|
60
|
+
"grey" => [128, 128, 128],
|
61
|
+
"green" => [0, 128, 0],
|
62
|
+
"greenyellow" => [173, 255, 47],
|
63
|
+
"honeydew" => [240, 255, 240],
|
64
|
+
"hotpink" => [255, 105, 180],
|
65
|
+
"indianred" => [205, 92, 92],
|
66
|
+
"indigo" => [75, 0, 130],
|
67
|
+
"ivory" => [255, 255, 240],
|
68
|
+
"khaki" => [240, 230, 140],
|
69
|
+
"lavender" => [230, 230, 250],
|
70
|
+
"lavenderblush" => [255, 240, 245],
|
71
|
+
"lawngreen" => [124, 252, 0],
|
72
|
+
"lemonchiffon" => [255, 250, 205],
|
73
|
+
"lightblue" => [173, 216, 230],
|
74
|
+
"lightcoral" => [240, 128, 128],
|
75
|
+
"lightcyan" => [224, 255, 255],
|
76
|
+
"lightgoldenrodyellow" => [250, 250, 210],
|
77
|
+
"lightgray" => [211, 211, 211],
|
78
|
+
"lightgrey" => [211, 211, 211],
|
79
|
+
"lightgreen" => [144, 238, 144],
|
80
|
+
"lightpink" => [255, 182, 193],
|
81
|
+
"lightsalmon" => [255, 160, 122],
|
82
|
+
"lightseagreen" => [32, 178, 170],
|
83
|
+
"lightskyblue" => [135, 206, 250],
|
84
|
+
"lightslategray" => [119, 136, 153],
|
85
|
+
"lightslategrey" => [119, 136, 153],
|
86
|
+
"lightsteelblue" => [176, 196, 222],
|
87
|
+
"lightyellow" => [255, 255, 224],
|
88
|
+
"lime" => [0, 255, 0],
|
89
|
+
"limegreen" => [50, 205, 50],
|
90
|
+
"linen" => [250, 240, 230],
|
91
|
+
"magenta" => [255, 0, 255],
|
92
|
+
"maroon" => [128, 0, 0],
|
93
|
+
"mediumaquamarine" => [102, 205, 170],
|
94
|
+
"mediumblue" => [0, 0, 205],
|
95
|
+
"mediumorchid" => [186, 85, 211],
|
96
|
+
"mediumpurple" => [147, 112, 219],
|
97
|
+
"mediumseagreen" => [60, 179, 113],
|
98
|
+
"mediumslateblue" => [123, 104, 238],
|
99
|
+
"mediumspringgreen" => [0, 250, 154],
|
100
|
+
"mediumturquoise" => [72, 209, 204],
|
101
|
+
"mediumvioletred" => [199, 21, 133],
|
102
|
+
"midnightblue" => [25, 25, 112],
|
103
|
+
"mintcream" => [245, 255, 250],
|
104
|
+
"mistyrose" => [255, 228, 225],
|
105
|
+
"moccasin" => [255, 228, 181],
|
106
|
+
"navajowhite" => [255, 222, 173],
|
107
|
+
"navy" => [0, 0, 128],
|
108
|
+
"oldlace" => [253, 245, 230],
|
109
|
+
"olive" => [128, 128, 0],
|
110
|
+
"olivedrab" => [107, 142, 35],
|
111
|
+
"orange" => [255, 165, 0],
|
112
|
+
"orangered" => [255, 69, 0],
|
113
|
+
"orchid" => [218, 112, 214],
|
114
|
+
"palegoldenrod" => [238, 232, 170],
|
115
|
+
"palegreen" => [152, 251, 152],
|
116
|
+
"paleturquoise" => [175, 238, 238],
|
117
|
+
"palevioletred" => [219, 112, 147],
|
118
|
+
"papayawhip" => [255, 239, 213],
|
119
|
+
"peachpuff" => [255, 218, 185],
|
120
|
+
"peru" => [205, 133, 63],
|
121
|
+
"pink" => [255, 192, 203],
|
122
|
+
"plum" => [221, 160, 221],
|
123
|
+
"powderblue" => [176, 224, 230],
|
124
|
+
"purple" => [128, 0, 128],
|
125
|
+
"red" => [255, 0, 0],
|
126
|
+
"rosybrown" => [188, 143, 143],
|
127
|
+
"royalblue" => [65, 105, 225],
|
128
|
+
"saddlebrown" => [139, 69, 19],
|
129
|
+
"salmon" => [250, 128, 114],
|
130
|
+
"sandybrown" => [244, 164, 96],
|
131
|
+
"seagreen" => [46, 139, 87],
|
132
|
+
"seashell" => [255, 245, 238],
|
133
|
+
"sienna" => [160, 82, 45],
|
134
|
+
"silver" => [192, 192, 192],
|
135
|
+
"skyblue" => [135, 206, 235],
|
136
|
+
"slateblue" => [106, 90, 205],
|
137
|
+
"slategray" => [112, 128, 144],
|
138
|
+
"slategrey" => [112, 128, 144],
|
139
|
+
"snow" => [255, 250, 250],
|
140
|
+
"springgreen" => [0, 255, 127],
|
141
|
+
"steelblue" => [70, 130, 180],
|
142
|
+
"tan" => [210, 180, 140],
|
143
|
+
"teal" => [0, 128, 128],
|
144
|
+
"thistle" => [216, 191, 216],
|
145
|
+
"tomato" => [255, 99, 71],
|
146
|
+
"turquoise" => [64, 224, 208],
|
147
|
+
"violet" => [238, 130, 238],
|
148
|
+
"wheat" => [245, 222, 179],
|
149
|
+
"white" => [255, 255, 255],
|
150
|
+
"whitesmoke" => [245, 245, 245],
|
151
|
+
"yellow" => [255, 255, 0],
|
152
|
+
"yellowgreen" => [154, 205, 50],
|
153
|
+
"rebeccapurple" => [102, 51, 153]
|
154
|
+
}.freeze
|
155
|
+
end
|
156
|
+
end
|
data/lib/image_util/color.rb
CHANGED
@@ -6,6 +6,7 @@ module ImageUtil
|
|
6
6
|
super(args)
|
7
7
|
end
|
8
8
|
|
9
|
+
autoload :CSS_COLORS, "image_util/color/css_colors"
|
9
10
|
def r = self[0]
|
10
11
|
def g = self[1]
|
11
12
|
def b = self[2]
|
@@ -69,13 +70,12 @@ module ImageUtil
|
|
69
70
|
new($1.to_i(16), $2.to_i(16), $3.to_i(16))
|
70
71
|
when /\A#(\h{2})(\h{2})(\h{2})(\h{2})\z/
|
71
72
|
new($1.to_i(16), $2.to_i(16), $3.to_i(16), $4.to_i(16))
|
72
|
-
when "black" then new(0, 0, 0)
|
73
|
-
when "white" then new(255, 255, 255)
|
74
|
-
when "red" then new(255, 0, 0)
|
75
|
-
when "lime" then new(0, 255, 0)
|
76
|
-
when "blue" then new(0, 0, 255)
|
77
73
|
else
|
78
|
-
|
74
|
+
if (rgb = CSS_COLORS[value.downcase])
|
75
|
+
new(*rgb)
|
76
|
+
else
|
77
|
+
raise ArgumentError, "wrong String passed as color (passed: #{value.inspect})"
|
78
|
+
end
|
79
79
|
end
|
80
80
|
when Symbol
|
81
81
|
from(value.to_s)
|
@@ -62,7 +62,29 @@ module ImageUtil
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
def draw_circle!(center, radius, color = Color[:black], view: View::Interpolated)
|
66
|
+
fp = self.view(view)
|
67
|
+
cx, cy = center
|
68
|
+
min_x = (cx - radius).ceil
|
69
|
+
max_x = (cx + radius).floor
|
70
|
+
min_x.upto(max_x) do |x|
|
71
|
+
dy = Math.sqrt(radius * radius - (x - cx)**2)
|
72
|
+
fp[x, cy + dy] = color
|
73
|
+
fp[x, cy - dy] = color
|
74
|
+
end
|
75
|
+
|
76
|
+
min_y = (cy - radius).ceil
|
77
|
+
max_y = (cy + radius).floor
|
78
|
+
min_y.upto(max_y) do |y|
|
79
|
+
dx = Math.sqrt(radius * radius - (y - cy)**2)
|
80
|
+
fp[cx + dx, y] = color
|
81
|
+
fp[cx - dx, y] = color
|
82
|
+
end
|
83
|
+
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
define_immutable_version :draw_function, :draw_line, :draw_circle
|
66
88
|
|
67
89
|
private
|
68
90
|
|
data/lib/image_util/image.rb
CHANGED
@@ -136,9 +136,11 @@ module ImageUtil
|
|
136
136
|
@buf.set(location, value)
|
137
137
|
end
|
138
138
|
else
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
sizes, locations = location_expand(location)
|
140
|
+
if value.is_a?(Image)
|
141
|
+
paste!(value.resize(*sizes), *locations.first)
|
142
|
+
else
|
143
|
+
locations.each { |loc| self[*loc] = value }
|
142
144
|
end
|
143
145
|
end
|
144
146
|
end
|
data/lib/image_util/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: image_util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hmdne
|
@@ -38,6 +38,12 @@ files:
|
|
38
38
|
- LICENSE.txt
|
39
39
|
- README.md
|
40
40
|
- Rakefile
|
41
|
+
- docs/samples/background.png
|
42
|
+
- docs/samples/dither.png
|
43
|
+
- docs/samples/draw.png
|
44
|
+
- docs/samples/paste.png
|
45
|
+
- docs/samples/resize.png
|
46
|
+
- docs/samples/sixel.png
|
41
47
|
- lib/image_util.rb
|
42
48
|
- lib/image_util/codec.rb
|
43
49
|
- lib/image_util/codec/_guard.rb
|
@@ -48,6 +54,7 @@ files:
|
|
48
54
|
- lib/image_util/codec/pam.rb
|
49
55
|
- lib/image_util/codec/ruby_sixel.rb
|
50
56
|
- lib/image_util/color.rb
|
57
|
+
- lib/image_util/color/css_colors.rb
|
51
58
|
- lib/image_util/filter.rb
|
52
59
|
- lib/image_util/filter/_mixin.rb
|
53
60
|
- lib/image_util/filter/background.rb
|