magro 0.1.0 → 0.4.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 +5 -5
- data/.coveralls.yml +1 -0
- data/.gitignore +4 -0
- data/.travis.yml +8 -3
- data/CHANGELOG.md +21 -0
- data/Gemfile +7 -1
- data/LICENSE.txt +1 -1
- data/README.md +17 -12
- data/ext/magro/imgrw.c +411 -0
- data/ext/magro/imgrw.h +18 -0
- data/ext/magro/magro.c +1 -394
- data/ext/magro/magro.h +2 -9
- data/lib/magro.rb +2 -0
- data/lib/magro/filter.rb +118 -0
- data/lib/magro/io.rb +10 -4
- data/lib/magro/transform.rb +77 -0
- data/lib/magro/version.rb +1 -1
- data/magro.gemspec +12 -7
- metadata +22 -66
data/lib/magro/io.rb
CHANGED
@@ -9,11 +9,14 @@ module Magro
|
|
9
9
|
# @param filename [String] Path to image file to be loaded.
|
10
10
|
# Currently, the following file formats are support:
|
11
11
|
# Portbale Network Graphics (*.png) and JPEG files (*.jpeg, *.jpg, *jpe).
|
12
|
+
# @raise [ArgumentError] This error is raised when filename is not String.
|
13
|
+
# @raise [IOError] This error is raised when failed to read image file.
|
14
|
+
# @raise [NoMemoryError] If memory allocation of image data fails, this error is raised.
|
12
15
|
# @return [Numo::UInt8] (shape: [height, width, n_channels]) Loaded image.
|
13
16
|
def imread(filename)
|
14
17
|
raise ArgumentError, 'Expect class of filename to be String.' unless filename.is_a?(String)
|
15
|
-
return read_jpg(filename) if filename =~ /\.(jpeg|jpg|jpe)$/
|
16
|
-
return read_png(filename) if filename =~ /\.png$/
|
18
|
+
return read_jpg(filename) if filename.downcase =~ /\.(jpeg|jpg|jpe)$/
|
19
|
+
return read_png(filename) if filename.downcase =~ /\.png$/
|
17
20
|
end
|
18
21
|
|
19
22
|
# Saves an image to file.
|
@@ -22,12 +25,15 @@ module Magro
|
|
22
25
|
# Portbale Network Graphics (*.png) and JPEG files (*.jpeg, *.jpg, *jpe).
|
23
26
|
# @param image [Numo::UInt8] (shape: [height, width, n_channels]) Image data to be saved.
|
24
27
|
# @param quality [Integer] Quality parameter of jpeg image that takes a value between 0 to 100.
|
28
|
+
# @raise [ArgumentError] If filename is not String or image is not Numo::NArray, this error is raised.
|
29
|
+
# @raise [IOError] This error is raised when failed to read image file.
|
30
|
+
# @raise [NoMemoryError] If memory allocation of image data fails, this error is raised.
|
25
31
|
# @return [Boolean] true if file save is successful.
|
26
32
|
def imsave(filename, image, quality: nil)
|
27
33
|
raise ArgumentError, 'Expect class of filename to be String.' unless filename.is_a?(String)
|
28
34
|
raise ArgumentError, 'Expect class of image to be Numo::NArray.' unless image.is_a?(Numo::NArray)
|
29
35
|
|
30
|
-
if filename =~ /\.(jpeg|jpg|jpe)$/
|
36
|
+
if filename.downcase =~ /\.(jpeg|jpg|jpe)$/
|
31
37
|
unless quality.nil?
|
32
38
|
raise ArgumentError, 'Expect class of quality to be Numeric.' unless quality.is_a?(Numeric)
|
33
39
|
raise ArgumentError, 'Range of quality value between 0 to 100.' unless quality.between?(0, 100)
|
@@ -35,7 +41,7 @@ module Magro
|
|
35
41
|
return save_jpg(filename, image, quality)
|
36
42
|
end
|
37
43
|
|
38
|
-
return save_png(filename, image) if filename =~ /\.png$/
|
44
|
+
return save_png(filename, image) if filename.downcase =~ /\.png$/
|
39
45
|
|
40
46
|
false
|
41
47
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Magro
|
4
|
+
# Transform module provide functions of image transfom.
|
5
|
+
module Transform
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Resizes an image with bilinear interpolation method.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# require 'numo/narray'
|
12
|
+
# require 'magro'
|
13
|
+
#
|
14
|
+
# image = Numo::UInt8.new(16, 16).seq
|
15
|
+
# resized = Magro::Transform.resize(image, height: 64, width: 64)
|
16
|
+
#
|
17
|
+
# @param image [Numo::UInt8] (shape: [height, width, n_channels] or [height, width]) Image data to be saved.
|
18
|
+
# @param height [Integer] Requested height in pixels.
|
19
|
+
# @param width [Integer] Requested width in pixels.
|
20
|
+
# @return [Numo::UInt8] (shape: [height, width, n_channels] or [height, width]) Resized image data.
|
21
|
+
def resize(image, height:, width:)
|
22
|
+
n_channels = image.shape[2]
|
23
|
+
|
24
|
+
if n_channels.nil?
|
25
|
+
bilinear_resize(image, height, width)
|
26
|
+
else
|
27
|
+
resized = image.class.zeros(height, width, n_channels)
|
28
|
+
n_channels.times { |c| resized[true, true, c] = bilinear_resize(image[true, true, c], height, width) }
|
29
|
+
resized
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# private
|
34
|
+
|
35
|
+
def bilinear_resize(image, new_height, new_width)
|
36
|
+
height, width = image.shape
|
37
|
+
|
38
|
+
y_ratio = height.fdiv(new_height)
|
39
|
+
x_ratio = width.fdiv(new_width)
|
40
|
+
|
41
|
+
y, x = Numo::Int32.new(new_height * new_width).seq.divmod(new_width)
|
42
|
+
|
43
|
+
y_p = Numo::Int32.cast((y_ratio * (y + 0.5) - 0.5).floor).clip(0, height - 1)
|
44
|
+
x_p = Numo::Int32.cast((x_ratio * (x + 0.5) - 0.5).floor).clip(0, width - 1)
|
45
|
+
y_n = Numo::Int32.cast((y_ratio * (y + 0.5) - 0.5).ceil).clip(0, height - 1)
|
46
|
+
x_n = Numo::Int32.cast((x_ratio * (x + 0.5) - 0.5).ceil).clip(0, width - 1)
|
47
|
+
|
48
|
+
flt = image.flatten
|
49
|
+
a = flt[y_p * width + x_p]
|
50
|
+
b = flt[y_p * width + x_n]
|
51
|
+
c = flt[y_n * width + x_p]
|
52
|
+
d = flt[y_n * width + x_n]
|
53
|
+
|
54
|
+
y_d = y_ratio * (y + 0.5) - 0.5
|
55
|
+
x_d = x_ratio * (x + 0.5) - 0.5
|
56
|
+
y_d = y_d.class.maximum(0, y_d - y_d.floor)
|
57
|
+
x_d = x_d.class.maximum(0, x_d - x_d.floor)
|
58
|
+
|
59
|
+
resized = a * (1 - x_d) * (1 - y_d) + b * x_d * (1 - y_d) + c * (1 - x_d) * y_d + d * x_d * y_d
|
60
|
+
|
61
|
+
resized = resized.round.clip(image.class::MIN, image.class::MAX) if integer_narray?(image)
|
62
|
+
resized = image.class.cast(resized) unless resized.is_a?(image.class)
|
63
|
+
resized.reshape(new_height, new_width)
|
64
|
+
end
|
65
|
+
|
66
|
+
INTEGER_NARRAY = %w[Numo::Int8 Numo::Int16 Numo::Int32 Numo::Int64
|
67
|
+
Numo::UInt8 Numo::UInt16 Numo::UInt32 Numo::UInt64].freeze
|
68
|
+
|
69
|
+
private_constant :INTEGER_NARRAY
|
70
|
+
|
71
|
+
def integer_narray?(image)
|
72
|
+
INTEGER_NARRAY.include?(image.class.to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
private_class_method :bilinear_resize, :integer_narray?
|
76
|
+
end
|
77
|
+
end
|
data/lib/magro/version.rb
CHANGED
data/magro.gemspec
CHANGED
@@ -8,12 +8,22 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ['yoshoku']
|
9
9
|
spec.email = ['yoshoku@outlook.com']
|
10
10
|
|
11
|
-
spec.summary = 'Magro is
|
12
|
-
spec.description =
|
11
|
+
spec.summary = 'Magro is a minimal image processing library for Ruby.'
|
12
|
+
spec.description = <<~MSG
|
13
|
+
Magro is a minimal image processing library for Ruby.
|
14
|
+
Magro uses Numo::NArray arrays as image objects and provides basic image processing functions.
|
15
|
+
Current supporting features are reading and writing JPEG and PNG images,
|
16
|
+
image resizing with bilinear interpolation method, and image filtering.
|
17
|
+
MSG
|
13
18
|
|
14
19
|
spec.homepage = 'https://github.com/yoshoku/magro'
|
15
20
|
spec.license = 'BSD-3-Clause'
|
16
21
|
|
22
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
23
|
+
spec.metadata['source_code_uri'] = 'https://github.com/yoshoku/magro'
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/yoshoku/magro/blob/master/CHANGELOG.md'
|
25
|
+
spec.metadata['documentation_uri'] = 'https://yoshoku.github.io/magro/doc/'
|
26
|
+
|
17
27
|
# Specify which files should be added to the gem when it is released.
|
18
28
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
29
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
@@ -26,9 +36,4 @@ Gem::Specification.new do |spec|
|
|
26
36
|
spec.extensions = ['ext/magro/extconf.rb']
|
27
37
|
|
28
38
|
spec.add_runtime_dependency 'numo-narray', '~> 0.9.1'
|
29
|
-
|
30
|
-
spec.add_development_dependency 'bundler', '~> 2.0'
|
31
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
-
spec.add_development_dependency 'rake-compiler', '~> 1.0'
|
33
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yoshoku
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|
@@ -24,63 +24,11 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.9.1
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '2.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '2.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '10.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '10.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake-compiler
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rspec
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '3.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '3.0'
|
83
|
-
description: Magro is an image processing library for Ruby.
|
27
|
+
description: |
|
28
|
+
Magro is a minimal image processing library for Ruby.
|
29
|
+
Magro uses Numo::NArray arrays as image objects and provides basic image processing functions.
|
30
|
+
Current supporting features are reading and writing JPEG and PNG images,
|
31
|
+
image resizing with bilinear interpolation method, and image filtering.
|
84
32
|
email:
|
85
33
|
- yoshoku@outlook.com
|
86
34
|
executables: []
|
@@ -88,6 +36,7 @@ extensions:
|
|
88
36
|
- ext/magro/extconf.rb
|
89
37
|
extra_rdoc_files: []
|
90
38
|
files:
|
39
|
+
- ".coveralls.yml"
|
91
40
|
- ".gitignore"
|
92
41
|
- ".rspec"
|
93
42
|
- ".travis.yml"
|
@@ -100,17 +49,25 @@ files:
|
|
100
49
|
- bin/console
|
101
50
|
- bin/setup
|
102
51
|
- ext/magro/extconf.rb
|
52
|
+
- ext/magro/imgrw.c
|
53
|
+
- ext/magro/imgrw.h
|
103
54
|
- ext/magro/magro.c
|
104
55
|
- ext/magro/magro.h
|
105
56
|
- lib/magro.rb
|
57
|
+
- lib/magro/filter.rb
|
106
58
|
- lib/magro/io.rb
|
59
|
+
- lib/magro/transform.rb
|
107
60
|
- lib/magro/version.rb
|
108
61
|
- magro.gemspec
|
109
62
|
homepage: https://github.com/yoshoku/magro
|
110
63
|
licenses:
|
111
64
|
- BSD-3-Clause
|
112
|
-
metadata:
|
113
|
-
|
65
|
+
metadata:
|
66
|
+
homepage_uri: https://github.com/yoshoku/magro
|
67
|
+
source_code_uri: https://github.com/yoshoku/magro
|
68
|
+
changelog_uri: https://github.com/yoshoku/magro/blob/master/CHANGELOG.md
|
69
|
+
documentation_uri: https://yoshoku.github.io/magro/doc/
|
70
|
+
post_install_message:
|
114
71
|
rdoc_options: []
|
115
72
|
require_paths:
|
116
73
|
- lib
|
@@ -125,9 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
82
|
- !ruby/object:Gem::Version
|
126
83
|
version: '0'
|
127
84
|
requirements: []
|
128
|
-
|
129
|
-
|
130
|
-
signing_key:
|
85
|
+
rubygems_version: 3.1.2
|
86
|
+
signing_key:
|
131
87
|
specification_version: 4
|
132
|
-
summary: Magro is
|
88
|
+
summary: Magro is a minimal image processing library for Ruby.
|
133
89
|
test_files: []
|