image_voodoo 0.8.7 → 0.9.1
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 +17 -0
- data/Gemfile +5 -0
- data/Jars.lock +3 -0
- data/LICENSE-2.0.txt +202 -0
- data/README.exif +18 -0
- data/README.md +1 -0
- data/Rakefile +21 -0
- data/bin/image_voodoo +81 -72
- 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 +177 -124
- data/lib/image_voodoo/gae.rb +12 -6
- data/lib/image_voodoo/metadata.rb +1689 -0
- data/lib/image_voodoo/needs_head.rb +3 -0
- data/lib/image_voodoo/version.rb +3 -1
- data/lib/image_voodoo.rb +77 -90
- 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 +65 -0
- data/test/test_shapes.rb +23 -0
- data/tools/gen.rb +68 -0
- metadata +94 -7
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test/unit/testcase'
|
4
|
+
require 'test/unit' if $PROGRAM_NAME == __FILE__
|
5
|
+
require 'image_voodoo'
|
6
|
+
|
7
|
+
# Depends on a small portion of awt/shapes working properly
|
8
|
+
class TestImageVoodoo < Test::Unit::TestCase
|
9
|
+
# 04
|
10
|
+
# b8
|
11
|
+
def make_square
|
12
|
+
image = ImageVoodoo.new_image 20, 20, "test.gif"
|
13
|
+
image.square(*upper_left, 10, '000000')
|
14
|
+
image.square(10, 0, 10, '444444')
|
15
|
+
image.square(0, 10, 10, '888888')
|
16
|
+
image.square(*lower_right, 10, 'bb0000')
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_color(color, red, green, blue, alpha=nil)
|
20
|
+
assert_equal(red, color.red)
|
21
|
+
assert_equal(green, color.green)
|
22
|
+
assert_equal(blue, color.blue)
|
23
|
+
assert_equal(alpha, color.alpha) if alpha
|
24
|
+
end
|
25
|
+
|
26
|
+
def lower_right
|
27
|
+
[10, 10]
|
28
|
+
end
|
29
|
+
|
30
|
+
def upper_left
|
31
|
+
[0, 0]
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO: Don't fully know how to predict pixel values for adjust_brightness.
|
35
|
+
|
36
|
+
def test_alpha
|
37
|
+
image = make_square.alpha('000000')
|
38
|
+
assert_equal(0xff, image.color_at(*upper_left).alpha)
|
39
|
+
end
|
40
|
+
|
41
|
+
# 04 -> 40
|
42
|
+
# 8b b8
|
43
|
+
def test_flip_horizontally
|
44
|
+
image = make_square.flip_horizontally
|
45
|
+
assert_color(image.color_at(*upper_left), 0x44, 0x44, 0x44)
|
46
|
+
end
|
47
|
+
|
48
|
+
# 04 -> 8b
|
49
|
+
# 8b 04
|
50
|
+
def test_flip_vertically
|
51
|
+
image = make_square.flip_vertically
|
52
|
+
assert_color(image.color_at(*upper_left), 0x88, 0x88, 0x88)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_greyscale
|
56
|
+
image = make_square.greyscale
|
57
|
+
assert_color(image.color_at(*lower_right), 0x5d, 0x5d, 0x5d)
|
58
|
+
end
|
59
|
+
|
60
|
+
# 04 -0-> 04 -90-> 80 -180-> 4b -270-> b8
|
61
|
+
# 8b 8b b4 08 40
|
62
|
+
def test_rotate
|
63
|
+
image = make_square
|
64
|
+
assert_color(image.color_at(*upper_left), 0x00, 0x00, 0x00)
|
65
|
+
image = image.rotate(90)
|
66
|
+
assert_color(image.color_at(*upper_left), 0x88, 0x88, 0x88)
|
67
|
+
image = image.rotate(180)
|
68
|
+
assert_color(image.color_at(*upper_left), 0x44, 0x44, 0x44)
|
69
|
+
image = image.rotate(270)
|
70
|
+
assert_color(image.color_at(*upper_left), 0xbb, 0x00, 0x00)
|
71
|
+
end
|
72
|
+
|
73
|
+
# 04 -(-90)-> 4b -(-180)-> 80 -(-270)-> b8
|
74
|
+
# 8b 08 b4 40
|
75
|
+
def test_rotate_negative
|
76
|
+
image = make_square
|
77
|
+
image = image.rotate(-90)
|
78
|
+
assert_color(image.color_at(*upper_left), 0x44, 0x44, 0x44)
|
79
|
+
image = image.rotate(-180)
|
80
|
+
assert_color(image.color_at(*upper_left), 0x88, 0x88, 0x88)
|
81
|
+
image = image.rotate(-270)
|
82
|
+
assert_color(image.color_at(*upper_left), 0xbb, 0x00, 0x00)
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test/unit/testcase'
|
4
|
+
require 'test/unit' if $PROGRAM_NAME == __FILE__
|
5
|
+
require 'image_voodoo'
|
6
|
+
|
7
|
+
IMAGE_DIR = File.join File.dirname(__FILE__), '..', '..', 'metadata-extractor-images'
|
8
|
+
|
9
|
+
# FIXME: If we end up running on travis or other tool this should be ignored
|
10
|
+
# subdir to this project and probably clone repo into that subdir
|
11
|
+
if !File.exist? IMAGE_DIR
|
12
|
+
puts 'To run this test you must clone:'
|
13
|
+
puts 'https://github.com/drewnoakes/metadata-extractor-images.git'
|
14
|
+
puts 'into a sibling directory to image_voodoo'
|
15
|
+
else
|
16
|
+
class TestImageVoodooMetadata < Test::Unit::TestCase
|
17
|
+
def setup
|
18
|
+
@path = File.join IMAGE_DIR, 'jpg', 'Apple iPhone 4S.jpg'
|
19
|
+
@path_gps = File.join IMAGE_DIR, 'jpg', 'Apple iPhone 4.jpg'
|
20
|
+
@path_no_exif = File.join File.dirname(__FILE__), 'pix.png'
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_orientation(expected, metadata)
|
24
|
+
assert_equal expected, metadata[:IFD0][:Orientation]
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_metadata_from_file
|
28
|
+
ImageVoodoo.with_image @path do |img|
|
29
|
+
metadata = img.metadata
|
30
|
+
assert_orientation 6, metadata
|
31
|
+
assert_equal 6, metadata.orientation
|
32
|
+
assert_equal 3264, metadata.width
|
33
|
+
assert_equal 2448, metadata.height
|
34
|
+
assert_equal 'Apple', metadata.make
|
35
|
+
assert_equal 'iPhone 4S', metadata.model
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_metadata_from_inputstream
|
40
|
+
ImageVoodoo.with_bytes File.read(@path) do |img|
|
41
|
+
assert_orientation 6, img.metadata
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_metadata_no_ifd0
|
46
|
+
ImageVoodoo.with_image @path_no_exif do |img|
|
47
|
+
assert !img.metadata[:IFD0].exists?
|
48
|
+
assert_orientation nil, img.metadata
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_metadata_gps
|
53
|
+
ImageVoodoo.with_image @path_gps do |img|
|
54
|
+
assert img.metadata[:Gps].exists?
|
55
|
+
assert_equal('N', img.metadata[:Gps]['Latitude Ref'])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_metadata_to_s
|
60
|
+
ImageVoodoo.with_image @path do |img|
|
61
|
+
assert img.metadata.to_s =~ /Make = Apple/
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/test_shapes.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test/unit/testcase'
|
4
|
+
require 'test/unit' if $PROGRAM_NAME == __FILE__
|
5
|
+
require 'image_voodoo'
|
6
|
+
|
7
|
+
class TestShapes < Test::Unit::TestCase
|
8
|
+
def test_new_image
|
9
|
+
image = ImageVoodoo.new_image 10, 20, "test.gif"
|
10
|
+
assert_equal 10, image.width
|
11
|
+
assert_equal 20, image.height
|
12
|
+
assert_equal "gif", image.format
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_square
|
16
|
+
image = ImageVoodoo.new_image 10, 10, "test.gif"
|
17
|
+
image.square 0, 0, 10, 'ff9900'
|
18
|
+
color = image.color_at(0, 0)
|
19
|
+
assert_equal(0xff, color.red)
|
20
|
+
assert_equal(0x99, color.green)
|
21
|
+
assert_equal(0x00, color.blue)
|
22
|
+
end
|
23
|
+
end
|
data/tools/gen.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Used to generate part of metadata.rb. Unfortunately, I am unable to fill
|
4
|
+
# in appropriate access methods so I generate with get_string and then manually
|
5
|
+
# update. In future versions I will just run this twice with old and new src
|
6
|
+
# and manually splice in new data (or fixes).
|
7
|
+
#
|
8
|
+
# % find ../metadata-extractor/Source/ -name '*Directory.java' | xargs grep TAG_ | grep 'public static final' | ruby tools/gen.rb
|
9
|
+
|
10
|
+
# FIXME: I made style tweaks and removed redundant data manually in generated
|
11
|
+
# source. I should update this tool to do all that.
|
12
|
+
# FIXME: I should add a generated comment in metadata generated file.
|
13
|
+
|
14
|
+
def normalize_directory_name(path)
|
15
|
+
path.tr('/', '.')
|
16
|
+
end
|
17
|
+
|
18
|
+
def normalize_tag_name(capname)
|
19
|
+
name = capname.split('_').map(&:capitalize).join(' ')
|
20
|
+
[name, "TAG_#{capname}"]
|
21
|
+
end
|
22
|
+
|
23
|
+
# 'ExifSubIFDDirectory' => 'Exif Sub IFD0'
|
24
|
+
def humanize_directory_name(s)
|
25
|
+
s = s.gsub('Directory', '')
|
26
|
+
s.split(/([A-Z]+[a-z]+)/).map { |a| a == '' ? nil : a }.compact.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
io = $stdin
|
30
|
+
directories = {}
|
31
|
+
|
32
|
+
io.readlines.each do |line|
|
33
|
+
# .../IptcDirectory.java: public static final int TAG_BY_LINE = 80;
|
34
|
+
next if %r{Source/[/]?(?<dir_name>.*).java:.*TAG_(?<tag_name>[\S]+)} !~ line
|
35
|
+
|
36
|
+
directory_name = normalize_directory_name dir_name
|
37
|
+
directories[directory_name] ||= []
|
38
|
+
directories[directory_name] << normalize_tag_name(tag_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
directories.each do |directory, tag_names|
|
42
|
+
class_name = directory.split('.')[-1]
|
43
|
+
puts <<"EOS"
|
44
|
+
# GENERATED
|
45
|
+
class #{class_name} < Directory
|
46
|
+
java_import #{directory}
|
47
|
+
|
48
|
+
def self.directory_class
|
49
|
+
#{directory}
|
50
|
+
end"
|
51
|
+
|
52
|
+
TAGS = {
|
53
|
+
EOS
|
54
|
+
tag_names.each do |name, original_name|
|
55
|
+
puts "'#{name}' => ['#{original_name}', :get_string],"
|
56
|
+
end
|
57
|
+
puts <<EOS
|
58
|
+
}.freeze
|
59
|
+
end
|
60
|
+
EOS
|
61
|
+
end
|
62
|
+
|
63
|
+
puts 'DIRECTORY_MAP = {'
|
64
|
+
directories.each do |directory, _|
|
65
|
+
class_name = directory.split('.')[-1]
|
66
|
+
puts "'#{humanize_directory_name(class_name)}' => #{class_name},"
|
67
|
+
end
|
68
|
+
puts '}.freeze'
|
metadata
CHANGED
@@ -1,15 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: image_voodoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas E. Enebo, Charles Nutter, Nick Sieger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2021-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
name: jar-dependencies
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
name: rubocop
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
name: ruby-maven
|
62
|
+
prerelease: false
|
63
|
+
type: :development
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
name: test-unit
|
76
|
+
prerelease: false
|
77
|
+
type: :development
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
13
83
|
description: Image manipulation in JRuby with ImageScience compatible API
|
14
84
|
email: tom.enebo@gmail.com
|
15
85
|
executables:
|
@@ -20,9 +90,15 @@ files:
|
|
20
90
|
- ".gitignore"
|
21
91
|
- ".hgignore"
|
22
92
|
- ".hgtags"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- ".travis.yml"
|
95
|
+
- Gemfile
|
23
96
|
- History.txt
|
97
|
+
- Jars.lock
|
98
|
+
- LICENSE-2.0.txt
|
24
99
|
- LICENSE.txt
|
25
100
|
- Manifest.txt
|
101
|
+
- README.exif
|
26
102
|
- README.md
|
27
103
|
- Rakefile
|
28
104
|
- bin/image_voodoo
|
@@ -30,19 +106,27 @@ files:
|
|
30
106
|
- lib/image_science.rb
|
31
107
|
- lib/image_voodoo.rb
|
32
108
|
- lib/image_voodoo/awt.rb
|
109
|
+
- lib/image_voodoo/awt/core_ext/buffered_image.rb
|
110
|
+
- lib/image_voodoo/awt/core_ext/graphics2d.rb
|
33
111
|
- lib/image_voodoo/awt/shapes.rb
|
34
112
|
- lib/image_voodoo/gae.rb
|
113
|
+
- lib/image_voodoo/metadata.rb
|
114
|
+
- lib/image_voodoo/needs_head.rb
|
35
115
|
- lib/image_voodoo/version.rb
|
36
116
|
- samples/bench.rb
|
37
117
|
- samples/checkerboard.jpg
|
38
118
|
- samples/file_greyscale.rb
|
39
119
|
- samples/file_thumbnail.rb
|
40
120
|
- samples/file_view.rb
|
41
|
-
- samples/
|
121
|
+
- samples/in_memory.rb
|
42
122
|
- samples/lossy.rb
|
43
123
|
- test/pix.png
|
44
124
|
- test/pix_cmyk.jpg
|
45
125
|
- test/test_image_science.rb
|
126
|
+
- test/test_image_voodoo.rb
|
127
|
+
- test/test_metadata.rb
|
128
|
+
- test/test_shapes.rb
|
129
|
+
- tools/gen.rb
|
46
130
|
- vendor/CMYKDemo.jar
|
47
131
|
homepage: http://github.com/jruby/image_voodoo
|
48
132
|
licenses: []
|
@@ -62,9 +146,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
146
|
- - ">="
|
63
147
|
- !ruby/object:Gem::Version
|
64
148
|
version: '0'
|
65
|
-
requirements:
|
66
|
-
|
67
|
-
rubygems_version:
|
149
|
+
requirements:
|
150
|
+
- jar com.drewnoakes, metadata-extractor, 2.11.0
|
151
|
+
rubygems_version: 3.2.14
|
68
152
|
signing_key:
|
69
153
|
specification_version: 4
|
70
154
|
summary: Image manipulation in JRuby with ImageScience compatible API
|
@@ -72,3 +156,6 @@ test_files:
|
|
72
156
|
- test/pix.png
|
73
157
|
- test/pix_cmyk.jpg
|
74
158
|
- test/test_image_science.rb
|
159
|
+
- test/test_image_voodoo.rb
|
160
|
+
- test/test_metadata.rb
|
161
|
+
- test/test_shapes.rb
|