image_voodoo 0.8.8 → 0.9.2
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 +5 -5
- data/.gitignore +4 -0
- data/.rubocop.yml +165 -0
- data/.travis.yml +16 -1
- data/Gemfile +5 -0
- data/Jars.lock +3 -0
- data/Rakefile +14 -4
- data/bin/image_voodoo +73 -84
- data/image_voodoo.gemspec +14 -7
- data/lib/image_science.rb +3 -1
- data/lib/image_voodoo/awt/core_ext/buffered_image.rb +15 -0
- data/lib/image_voodoo/awt/core_ext/graphics2d.rb +15 -0
- data/lib/image_voodoo/awt/shapes.rb +41 -3
- data/lib/image_voodoo/awt.rb +162 -152
- data/lib/image_voodoo/gae.rb +12 -6
- data/lib/image_voodoo/metadata.rb +138 -90
- data/lib/image_voodoo/needs_head.rb +3 -0
- data/lib/image_voodoo/version.rb +3 -1
- data/lib/image_voodoo.rb +47 -96
- data/samples/bench.rb +30 -36
- data/samples/file_greyscale.rb +2 -0
- data/samples/file_thumbnail.rb +2 -0
- data/samples/file_view.rb +4 -1
- data/samples/{in-memory.rb → in_memory.rb} +2 -0
- data/samples/lossy.rb +2 -0
- data/test/test_image_science.rb +34 -74
- data/test/test_image_voodoo.rb +84 -0
- data/test/test_metadata.rb +31 -16
- data/test/test_shapes.rb +23 -0
- data/tools/gen.rb +34 -27
- metadata +87 -10
- data/vendor/metadata-extractor-2.7.0.jar +0 -0
- data/vendor/xmpcore-5.1.2.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 432be5fdc3ce35d25ccec454aec40066f07f512fdf0d45891ecc49ff28e48368
|
4
|
+
data.tar.gz: cacc16a2c686344983bab91d9467ff8a80957f22db50ab037f54553bd1004823
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 421f317327a6d6ecb7c799cd1d4bee0a8a0193ce5f9395c55c2b642387d4fb8b6f62533255b565a5698d379c5ac91d19b0c0fc9fa7776116efee90c537ecf7dd
|
7
|
+
data.tar.gz: 2fe8bfed88aaa7645ed9eb240a652a0c47c095e72043f62dddfe5effcf415c3d833a2b5f6991ad852bb9a9bd06e4bd3363742807229c7efb0b227ab0b1d123af
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# Experiment to tweak source based on what rubocop wanted me to. I basically
|
2
|
+
# gave up and made the following exceptions. Personally, I find the tool did
|
3
|
+
# find many interesting/questionable code Qs in the project but it is soooo
|
4
|
+
# opinionated in pretty unimportant ways (like who cares how I write my
|
5
|
+
# comments, or why can't I use kind_of? or why give me a fail for a less
|
6
|
+
# readable but more performant pattern).
|
7
|
+
#
|
8
|
+
# I can obviously tweak rules (like below) but I keep hearing of people pulling
|
9
|
+
# their hair out over all the unimportant rules; I question why this project is
|
10
|
+
# "all-in" on it's rules versus leaving most of the style rules as some preset
|
11
|
+
# profiles people can opt in to.
|
12
|
+
#
|
13
|
+
# So I am committing this and I will try and run this every now and then to
|
14
|
+
# see what it thinks about what I wrote but you will not see this as a
|
15
|
+
# requirement for commits since I think by the time I configured it to my
|
16
|
+
# liking I could have finished implementing this library. Perhaps if I
|
17
|
+
# continue using this here and there I will end up with a profile I find
|
18
|
+
# acceptable? I did find value but all the piddly shit just made me angry.
|
19
|
+
# I will reflect on it some more...
|
20
|
+
|
21
|
+
# This is a Java AWT call. It is not what the tool thinks it is...which
|
22
|
+
# might be an issue for users interacting with Java from JRuby.
|
23
|
+
Lint/UselessSetterCall:
|
24
|
+
Exclude:
|
25
|
+
- 'lib/image_voodoo/awt.rb'
|
26
|
+
|
27
|
+
# This is just impossible for them to call properly. I am doing something
|
28
|
+
# like rotate_impl and it is a bunch of reasonably simple math. If you look
|
29
|
+
# for this transformation in a text book it will look like this code. Putting
|
30
|
+
# a bunch of math within different methods would get the score down but
|
31
|
+
# it would not help readability. (addendum: I did try and break it apart more
|
32
|
+
# and never reached 15 but got closer. I felt this rule is neat but the
|
33
|
+
# score really depends on what it is.
|
34
|
+
Metrics/AbcSize:
|
35
|
+
Max: 16.5
|
36
|
+
|
37
|
+
# This is triggered for correct_orientation_impl. I could put these transforms
|
38
|
+
# in a table and then execute lambdas for each orientation but this is much
|
39
|
+
# more clear.
|
40
|
+
Metrics/CyclomaticComplexity:
|
41
|
+
Max: 10
|
42
|
+
|
43
|
+
# A bunch of fields in a hash are basically generated data. Correcting them
|
44
|
+
# for column seems much too pedantic. I guess exclude is the right thing for
|
45
|
+
# an unusual file?
|
46
|
+
Layout/LineLength:
|
47
|
+
Max: 132
|
48
|
+
Exclude:
|
49
|
+
- 'lib/image_voodoo/metadata.rb'
|
50
|
+
|
51
|
+
# Metadata classes have data in them. awt.rb is big and perhaps could be
|
52
|
+
# shrunk but it is not a hard file to navigate and the cleaving points are
|
53
|
+
# not super obvious. These sorts of rules feel very arbitrary and if I have
|
54
|
+
# n highly related things and they do not fit into a more restrictive
|
55
|
+
# taxonomy why would the file being longer matter? I do understand the
|
56
|
+
# motivation here but as a default rule this feels wrong to me.
|
57
|
+
Metrics/ClassLength:
|
58
|
+
Max: 250
|
59
|
+
|
60
|
+
# I do not find this very useful. There is no performance difference and
|
61
|
+
# sometimes I want to highlight this string does not involve interpolation.
|
62
|
+
# Other times it is not worth pointing out.
|
63
|
+
Style/StringLiterals:
|
64
|
+
Enabled: false
|
65
|
+
|
66
|
+
# require 'english' is a step too far for $! which is so baked into my
|
67
|
+
# head I do not want to change :)
|
68
|
+
Style/SpecialGlobalVars:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
# I am grouping math and using lack of whitespace for separation.
|
72
|
+
Layout/SpaceAroundOperators:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
# I prefer tight assignment for opt args.
|
76
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
77
|
+
Enabled: false
|
78
|
+
|
79
|
+
# Java methods which override or implement Java method names cannot be switched
|
80
|
+
# to snake case. Do we really need this as a rule anyways? I have never seen
|
81
|
+
# a Rubyist do this as a preferred style?
|
82
|
+
Naming/MethodName:
|
83
|
+
Enabled: false
|
84
|
+
|
85
|
+
# bin/image_voodoo main options block.
|
86
|
+
Metrics/BlockLength:
|
87
|
+
Exclude:
|
88
|
+
- 'bin/image_voodoo'
|
89
|
+
|
90
|
+
# Hash rocket looks much more natural in a rakefile for its deps.
|
91
|
+
Style/HashSyntax:
|
92
|
+
Exclude:
|
93
|
+
- 'Rakefile'
|
94
|
+
|
95
|
+
# Forget it. I do parallel assignment and you will have to peel it out of
|
96
|
+
# my cold dead hands.
|
97
|
+
Style/ParallelAssignment:
|
98
|
+
Enabled: false
|
99
|
+
|
100
|
+
# FIXME: consider keywords for shapes.
|
101
|
+
# I might switch these to keyword args if I ever revisit shapes support.
|
102
|
+
# In general lots of params do suck and are hard to remember. This library
|
103
|
+
# still is supposed to work in 1.8 but I can probably soon major rev this
|
104
|
+
# and switch over to keywords.
|
105
|
+
Metrics/ParameterLists:
|
106
|
+
Exclude:
|
107
|
+
- 'lib/image_voodoo/awt/shapes.rb'
|
108
|
+
|
109
|
+
# This is complaining that 'x' and 'y' are bad names because they are less
|
110
|
+
# than 3 chars. Silly rule even if I appreciate what it is trying to
|
111
|
+
# accomplish. Interestingly, in image_voodoo I do use h for height and
|
112
|
+
# w for width. Those probably could be written out but they are so common
|
113
|
+
# I am basically opting for short-hand. This is something I rarely do except
|
114
|
+
# domain-driven code like this (x,y,h,w).
|
115
|
+
Naming/MethodParameterName:
|
116
|
+
Enabled: false
|
117
|
+
|
118
|
+
# This represents one of those frustrating dogmatic rules where if I followed
|
119
|
+
# this advice I would then violate the column length rule. I specifically
|
120
|
+
# use traditional if indented block in cases where if_mod doesn't fit.
|
121
|
+
# Gramatically, if_mod can be across two lines but I hate how that looks. The
|
122
|
+
# second solution of logical &&/|| change for a raise is alien to for all but
|
123
|
+
# assignment.
|
124
|
+
Style/IfUnlessModifier:
|
125
|
+
Enabled: false
|
126
|
+
|
127
|
+
# What the hell. Really telling people that encoding: utf-8 should not happen
|
128
|
+
# because there are no multi-byte utf-8 characters in it? Why add this noise?
|
129
|
+
Style/Encoding:
|
130
|
+
Enabled: false
|
131
|
+
|
132
|
+
# FIXME:
|
133
|
+
# This is an unknown error which I should figure out. It must be some
|
134
|
+
# StandardError (which is what nothing explicit means) but I should actually
|
135
|
+
# be more explicit here.
|
136
|
+
Style/RescueStandardError:
|
137
|
+
Exclude:
|
138
|
+
- 'lib/image_voodoo.rb'
|
139
|
+
|
140
|
+
|
141
|
+
# This was complaining metadata_impl should use @metadata_impl instead of
|
142
|
+
# @metadata. I disagree and am unsure why I need to follow this programs
|
143
|
+
# opinion on what a good name is? What is commentable is if I change the
|
144
|
+
# variable name to @gorgon it still tells me I need to use @metadata_impl.
|
145
|
+
# So if I conditionally add any state in any method it will tell me I am
|
146
|
+
# memoizing and have to use same ivar as the name of the method? Is it more
|
147
|
+
# sophisticated than that? Should I have spent 2-3 minutes trying to figure
|
148
|
+
# out how this rule was implemented? :)
|
149
|
+
Naming/MemoizedInstanceVariableName:
|
150
|
+
Enabled: false
|
151
|
+
|
152
|
+
# I have two modes of use for private. If it is a small number of individual
|
153
|
+
# methods I am explicit and inline the private. If it is a large number of
|
154
|
+
# methods especially when the name is fairly obvious that those will be private
|
155
|
+
# (like render_impl) then I use block private. Not sure telling me I can only
|
156
|
+
# use a single style is very useful.
|
157
|
+
Style/AccessModifierDeclarations:
|
158
|
+
Enabled: false
|
159
|
+
|
160
|
+
# I feel for the tiny amount of generation here a better name would not help
|
161
|
+
# me understand it better. This is one of those naming rules I feel is
|
162
|
+
# probably helpful a minority of the time. Also I have never been confused
|
163
|
+
# by what a heredoc text represents because of my heredoc terminator?
|
164
|
+
Naming/HeredocDelimiterNaming:
|
165
|
+
Enabled: false
|
data/.travis.yml
CHANGED
@@ -1,2 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
sudo: false
|
4
|
+
|
1
5
|
rvm:
|
2
|
-
- jruby-
|
6
|
+
- jruby-head
|
7
|
+
|
8
|
+
before_install:
|
9
|
+
- mkdir rvm_tmp
|
10
|
+
- cd rvm_tmp
|
11
|
+
|
12
|
+
before_script:
|
13
|
+
- cd ..
|
14
|
+
- git clone --depth 1 https://github.com/drewnoakes/metadata-extractor-images.git ../metadata-extractor-images
|
15
|
+
|
16
|
+
install: JRUBY_OPTS=--dev jruby --dev -S bundle install --jobs=3 --retry=3
|
17
|
+
|
data/Gemfile
ADDED
data/Jars.lock
ADDED
data/Rakefile
CHANGED
@@ -1,13 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler'
|
2
4
|
require 'rake/testtask'
|
5
|
+
require 'jars/installer'
|
3
6
|
Bundler::GemHelper.install_tasks
|
7
|
+
Bundler.setup
|
8
|
+
|
9
|
+
task :default => %i[vendor_jars test]
|
4
10
|
|
5
|
-
|
11
|
+
desc 'Vendor Jars'
|
12
|
+
task :vendor_jars do
|
13
|
+
test_file = File.expand_path File.join('lib', 'image_voodoo_jars.rb'), __dir__
|
14
|
+
Jars::Installer.vendor_jars! unless File.exist? test_file
|
15
|
+
end
|
6
16
|
|
7
|
-
desc
|
8
|
-
task :test do
|
17
|
+
desc 'Run tests'
|
18
|
+
task :test => :vendor_jars do
|
9
19
|
Rake::TestTask.new do |t|
|
10
|
-
t.libs <<
|
20
|
+
t.libs << 'lib:vendor'
|
11
21
|
t.test_files = FileList['test/test*.rb']
|
12
22
|
end
|
13
23
|
end
|
data/bin/image_voodoo
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
#!/usr/bin/env ruby
|
2
4
|
|
3
5
|
require 'optparse'
|
@@ -7,101 +9,91 @@ actions = []
|
|
7
9
|
images = []
|
8
10
|
original_image = nil
|
9
11
|
|
10
|
-
opts = OptionParser.new do |
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
opts.on("-b", "--brightness SCALE,OFFSET", "Adjust brightness") do |args|
|
39
|
-
scale, offset = args.split(/,/).map {|v| v.to_f}
|
40
|
-
opts.usage "You need to specify proper scale and offset" unless scale && offset
|
41
|
-
actions << lambda {|img| img.adjust_brightness(scale, offset) }
|
42
|
-
end
|
43
|
-
|
44
|
-
opts.on("-B", "--border WIDTH,COLOR,STYLE", "Add a simple border") do |args|
|
12
|
+
opts = OptionParser.new do |o|
|
13
|
+
o.banner = 'Usage: image_voodoo [actions] image_file'
|
14
|
+
o.separator 'Perform actions/transformations on an image.'
|
15
|
+
o.separator ''
|
16
|
+
o.separator 'Examples:'
|
17
|
+
o.separator ' image_voodoo --dim small.jpg # Print the dimensions'
|
18
|
+
o.separator ''
|
19
|
+
o.separator ' # Make a thumbnail, preview it, and then save it.'
|
20
|
+
o.separator ' image_voodoo --thumbnail 50 --preview --save thumb.png large.jpg'
|
21
|
+
o.separator ''
|
22
|
+
o.separator ' # Make 2 thumbnails, showing dimensions and previewing them'
|
23
|
+
o.separator ' image_voodoo --dim --resize 50x50 --dim --preview --save t1.jpg'
|
24
|
+
o.separator ' --pop --resize 40x40 --dim --preview --save t2.jpg image.jpg'
|
25
|
+
o.separator ''
|
26
|
+
o.separator 'Actions:'
|
27
|
+
|
28
|
+
o.on('-a', '--alpha rrggbb', 'Make color transparent in image') do |c|
|
29
|
+
o.usage 'rrggbb is in hexidecimal format' if c !~ /[[:xdigit:]]{6,6}/
|
30
|
+
actions << ->(img) { img.alpha(c) }
|
31
|
+
end
|
32
|
+
|
33
|
+
o.on('-b', '--brightness SCALE,OFFSET', 'Adjust brightness') do |args|
|
34
|
+
scale, offset = args.split(/,/).map(&:to_f)
|
35
|
+
o.usage 'You need to specify proper scale and offset' unless scale && offset
|
36
|
+
actions << ->(img) { img.adjust_brightness(scale, offset) }
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on('-B', '--border WIDTH,COLOR,STYLE', 'Add a simple border') do |args|
|
45
40
|
width, color, style = args.split(/,/)
|
46
|
-
options = {:
|
47
|
-
|
48
|
-
actions << lambda {|img| img.add_border(options) }
|
41
|
+
options = { width: width, color: color, style: style }
|
42
|
+
actions << ->(img) { img.add_border(options) }
|
49
43
|
end
|
50
44
|
|
51
|
-
|
52
|
-
actions <<
|
45
|
+
o.on('-d', '--dimensions', 'Print the image dimensions') do
|
46
|
+
actions << ->(img) { img.tap { puts "#{img.width}x#{img.height}" } }
|
53
47
|
end
|
54
48
|
|
55
|
-
|
56
|
-
actions <<
|
49
|
+
o.on('-g', '--greyscale', 'Convert image to greyscale') do
|
50
|
+
actions << ->(img) { img.greyscale }
|
57
51
|
end
|
58
52
|
|
59
|
-
|
60
|
-
actions <<
|
53
|
+
o.on('-h', '--flip_horizontally') do
|
54
|
+
actions << ->(img) { img.flip_horizontally }
|
61
55
|
end
|
62
56
|
|
63
|
-
|
64
|
-
actions <<
|
57
|
+
o.on('-m', '--metadata') do
|
58
|
+
actions << ->(img) { img.tap { puts img.metadata } }
|
65
59
|
end
|
66
60
|
|
67
|
-
|
68
|
-
actions <<
|
61
|
+
o.on('-n', '--negative', 'Make a negative out of the image') do
|
62
|
+
actions << ->(img) { img.negative }
|
69
63
|
end
|
70
64
|
|
71
|
-
|
72
|
-
actions <<
|
65
|
+
o.on('-o', '--orient', 'Rotate image to orient it based on metadata') do
|
66
|
+
actions << ->(img) { img.correct_orientation }
|
73
67
|
end
|
74
68
|
|
75
|
-
|
76
|
-
actions <<
|
69
|
+
o.on('-q', '--quality 0..1', Float, 'Set % of quality for lossy compression') do |quality|
|
70
|
+
actions << ->(img) { img.quality(quality) }
|
77
71
|
end
|
78
72
|
|
79
|
-
|
80
|
-
actions <<
|
73
|
+
o.on('-R', '--rotate 0..360', Float, 'Set angle to rotate image') do |angle|
|
74
|
+
actions << ->(img) { img.rotate(angle.to_f) }
|
81
75
|
end
|
82
76
|
|
83
|
-
|
84
|
-
width, height = dim.split(/x/i).map
|
85
|
-
|
86
|
-
actions <<
|
77
|
+
o.on('-r', '--resize WIDTHxHEIGHT', 'Make a new resized image') do |dim|
|
78
|
+
width, height = dim.split(/x/i).map(&:to_i)
|
79
|
+
o.usage 'You need to specify proper dimensions' unless width && width > 0 && height && height > 0
|
80
|
+
actions << ->(img) { img.resize(width, height) }
|
87
81
|
end
|
88
82
|
|
89
|
-
|
90
|
-
|
91
|
-
actions << lambda {|img| img.save(f); img }
|
83
|
+
o.on('-s', '--save FILENAME', 'Save the results to a new file') do |f|
|
84
|
+
actions << ->(img) { img.tap { img.save(f) } }
|
92
85
|
end
|
93
86
|
|
94
|
-
|
95
|
-
actions <<
|
87
|
+
o.on('-t', '--thumbnail SIZE', Integer, 'Create a thumbnail of the given size') do |size|
|
88
|
+
actions << ->(img) { img.thumbnail(size) }
|
96
89
|
end
|
97
90
|
|
98
|
-
|
99
|
-
actions << lambda {|img| img.flip_vertically }
|
100
|
-
end
|
101
|
-
|
102
|
-
opts.on("-p", "--preview", "Preview the image. Close the frame window",
|
103
|
-
"to continue, or quit the application to", "abort the action pipeline") do
|
91
|
+
o.on('-v', '--flip_vertically') { actions << ->(img) { img.flip_vertically } }
|
104
92
|
|
93
|
+
o.on('-p', '--preview',
|
94
|
+
'Preview the image. Close the frame window',
|
95
|
+
'to continue, or quit the application to',
|
96
|
+
'abort the action pipeline') do
|
105
97
|
headless = false
|
106
98
|
actions << lambda do |img|
|
107
99
|
done = false
|
@@ -111,36 +103,33 @@ opts = OptionParser.new do |opts|
|
|
111
103
|
end
|
112
104
|
end
|
113
105
|
|
114
|
-
|
115
|
-
actions <<
|
106
|
+
o.on('--push', 'Save the current image to be popped later') do
|
107
|
+
actions << ->(img) { img.tap { images << img } }
|
116
108
|
end
|
117
109
|
|
118
|
-
|
119
|
-
actions <<
|
110
|
+
o.on('--pop', 'Revert back to the previous image') do
|
111
|
+
actions << -> { images.pop || original_image }
|
120
112
|
end
|
121
113
|
|
122
|
-
|
123
|
-
actions <<
|
114
|
+
o.on('-f', '--format', 'Print the image format') do
|
115
|
+
actions << ->(img) { img.tap { img.format } }
|
124
116
|
end
|
125
117
|
|
126
|
-
|
127
|
-
puts opts
|
128
|
-
exit 0
|
129
|
-
end
|
118
|
+
o.on_tail('-h', '--help', 'Show this message') { o.usage }
|
130
119
|
|
131
|
-
def
|
132
|
-
puts msg
|
120
|
+
def o.usage(msg=nil)
|
121
|
+
puts msg if msg
|
133
122
|
puts self
|
134
123
|
exit 1
|
135
124
|
end
|
136
125
|
end
|
137
126
|
opts.parse!(ARGV)
|
138
|
-
opts.usage(
|
139
|
-
opts.usage(
|
127
|
+
opts.usage('You need to supply a source image filename.') unless ARGV.first
|
128
|
+
opts.usage('You need to supply one or more actions.') if actions.empty?
|
140
129
|
|
141
130
|
# For this binstub we only want to load non-headless if we are using
|
142
131
|
# the preview feature. top of See lib/image_voodoo.rb for more info...
|
143
|
-
|
132
|
+
require 'image_voodoo/needs_head' unless headless
|
144
133
|
|
145
134
|
require 'image_voodoo'
|
146
135
|
file_name = ARGV.first
|
data/image_voodoo.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
5
|
+
require 'image_voodoo/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |s|
|
6
8
|
s.name = 'image_voodoo'
|
@@ -12,11 +14,16 @@ Gem::Specification.new do |s|
|
|
12
14
|
s.summary = 'Image manipulation in JRuby with ImageScience compatible API'
|
13
15
|
s.description = 'Image manipulation in JRuby with ImageScience compatible API'
|
14
16
|
|
15
|
-
s.rubyforge_project = "image_voodoo"
|
16
|
-
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
-
s.require_paths = [
|
21
|
-
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
20
|
+
s.require_paths = %w[lib vendor]
|
21
|
+
|
22
|
+
s.add_development_dependency 'jar-dependencies'
|
23
|
+
s.add_development_dependency 'rake'
|
24
|
+
s.add_development_dependency 'rubocop'
|
25
|
+
s.add_development_dependency 'ruby-maven'
|
26
|
+
s.add_development_dependency 'test-unit'
|
27
|
+
|
28
|
+
s.requirements << 'jar com.drewnoakes, metadata-extractor, 2.11.0'
|
22
29
|
end
|
data/lib/image_science.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
|
5
|
+
# Hide in ImageVoodoo so awt.rb can see this and we will not polute global
|
6
|
+
class ImageVoodoo
|
7
|
+
java_import java.awt.image.BufferedImage
|
8
|
+
|
9
|
+
# Re-open to add convenience methods.
|
10
|
+
class BufferedImage
|
11
|
+
def each
|
12
|
+
height.times { |j| width.times { |i| yield i, j } }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
|
5
|
+
# Hide in ImageVoodoo so awt.rb can see this and we will not polute global
|
6
|
+
class ImageVoodoo
|
7
|
+
java_import java.awt.Graphics2D
|
8
|
+
|
9
|
+
# Re-open to add convenience methods.
|
10
|
+
class Graphics2D
|
11
|
+
def draw_this_image(image)
|
12
|
+
draw_image image, 0, 0, nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,5 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ImageVoodoo
|
4
|
+
# (Experimental) An attempt at some primitive drawing in images.
|
2
5
|
module Shapes
|
6
|
+
# FIXME: if image has alpha values the border shows through since it is
|
7
|
+
# a solid fill.
|
8
|
+
##
|
9
|
+
# *AWT* (experimental) Add a border to the image and yield/return a new
|
10
|
+
# image. The following options are supported:
|
11
|
+
# - width: How thick is the border (default: 3)
|
12
|
+
# - color: Which color is the border (in rrggbb hex value)
|
13
|
+
# - style: etched, raised, plain (default: plain)
|
14
|
+
#
|
15
|
+
def add_border(options = {})
|
16
|
+
border_width = options[:width].to_i || 2
|
17
|
+
new_width, new_height = width + 2*border_width, height + 2*border_width
|
18
|
+
target = paint(BufferedImage.new(new_width, new_height, color_type)) do |g|
|
19
|
+
paint_border(g, new_width, new_height, options)
|
20
|
+
g.draw_image(@src, nil, border_width, border_width)
|
21
|
+
end
|
22
|
+
block_given? ? yield(target) : target
|
23
|
+
end
|
24
|
+
|
25
|
+
def paint_border(g, new_width, new_height, options)
|
26
|
+
g.color = hex_to_color(options[:color])
|
27
|
+
fill_method, *args = border_style(options)
|
28
|
+
g.send fill_method, 0, 0, new_width, new_height, *args
|
29
|
+
end
|
30
|
+
|
31
|
+
def border_style(options)
|
32
|
+
case (options[:style] || "").to_s
|
33
|
+
when "raised" then
|
34
|
+
[:fill3DRect, true]
|
35
|
+
when "etched" then
|
36
|
+
[:fill3DRect, false]
|
37
|
+
else
|
38
|
+
[:fill_rect]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
3
42
|
##
|
4
43
|
# *AWT* Draw a square
|
5
44
|
#
|
@@ -18,14 +57,14 @@ class ImageVoodoo
|
|
18
57
|
# *AWT* Draw a rounded square
|
19
58
|
#
|
20
59
|
def square_rounded(x, y, dim, rgb, arc_width=0, fill=true)
|
21
|
-
rect_rounded(x,y, dim, dim, rgb, arc_width, arc_width, fill)
|
60
|
+
rect_rounded(x, y, dim, dim, rgb, arc_width, arc_width, fill)
|
22
61
|
end
|
23
62
|
|
24
63
|
##
|
25
64
|
# *AWT* Draw a rounded rectangle
|
26
65
|
#
|
27
66
|
def rect_rounded(x, y, width, height, rgb, arc_width=0, arc_height=0, fill=true)
|
28
|
-
as_color(
|
67
|
+
as_color(hex_to_color(rgb)) do |g|
|
29
68
|
if fill
|
30
69
|
g.fill_round_rect x, y, width, height, arc_width, arc_height
|
31
70
|
else
|
@@ -44,4 +83,3 @@ class ImageVoodoo
|
|
44
83
|
end
|
45
84
|
end
|
46
85
|
end
|
47
|
-
|