riiif 2.0.0.beta2 → 2.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +2 -11
- data/.rubocop_todo.yml +76 -33
- data/README.md +17 -2
- data/app/controllers/riiif/images_controller.rb +8 -2
- data/app/models/riiif/image.rb +15 -20
- data/app/models/riiif/image_information.rb +12 -24
- data/app/services/riiif/crop.rb +99 -30
- data/app/services/riiif/image_magick_info_extractor.rb +9 -2
- data/app/services/riiif/imagemagick_command_factory.rb +9 -4
- data/app/services/riiif/kakadu_command_factory.rb +2 -2
- data/app/services/riiif/resize.rb +72 -7
- data/app/transformers/riiif/kakadu_transformer.rb +25 -2
- data/docs/benchmark.md +75 -0
- data/lib/riiif/engine.rb +2 -1
- data/lib/riiif/routes.rb +3 -0
- data/lib/riiif/version.rb +1 -1
- data/riiif.gemspec +3 -3
- data/spec/controllers/riiif/images_controller_spec.rb +14 -3
- data/spec/models/riiif/image_information_spec.rb +2 -10
- data/spec/models/riiif/image_spec.rb +10 -16
- data/spec/services/riiif/imagemagick_command_factory_spec.rb +6 -6
- data/spec/services/riiif/kakadu_command_factory_spec.rb +15 -15
- data/spec/transformers/riiif/kakadu_transformer_spec.rb +22 -22
- metadata +24 -46
- data/app/models/riiif/transformation.rb +0 -35
- data/app/services/riiif/imagemagick_transformer.rb +0 -8
- data/app/services/riiif/option_decoder.rb +0 -88
- data/app/services/riiif/region/absolute.rb +0 -23
- data/app/services/riiif/region/full.rb +0 -23
- data/app/services/riiif/region/percentage.rb +0 -68
- data/app/services/riiif/region/square.rb +0 -45
- data/app/services/riiif/size/absolute.rb +0 -39
- data/app/services/riiif/size/best_fit.rb +0 -18
- data/app/services/riiif/size/full.rb +0 -17
- data/app/services/riiif/size/height.rb +0 -24
- data/app/services/riiif/size/percent.rb +0 -44
- data/app/services/riiif/size/width.rb +0 -24
- data/spec/models/riiif/transformation_spec.rb +0 -42
- data/spec/services/riiif/region/absolute_spec.rb +0 -17
- data/spec/services/riiif/size/absolute_spec.rb +0 -17
- data/spec/services/riiif/size/height_spec.rb +0 -13
- data/spec/services/riiif/size/width_spec.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b274258986b942fec11fa586bd52f13e9bf8a567725954f8ca6fd92282780207
|
4
|
+
data.tar.gz: d786222b5b9be2b1c6d514917adb239d498ed819f88f9de93d9a8f61852f1c5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4b7a1b45f2513f51abb150a0bc6678bc1578b4ab64da8487b7447af3a0cab2db922d8e7a49a5c737cfd9931e2abcd4f2bbeec37838862ecee49ffaeee6e9eb7
|
7
|
+
data.tar.gz: 4d06560bdbbf84747e7dba9f341fb6d5eff45dd6e1e573839aa8ec236b42dc242d7a31b8ff9c2bc4d6f31248839c9c3c0e39a76e884569904f7c36aa5aa5834b
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2018-02-23 11:28:05 -0600 using RuboCop version 0.52.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count:
|
9
|
+
# Offense count: 2
|
10
10
|
# Configuration parameters: AllowSafeAssignment.
|
11
11
|
Lint/AssignmentInCondition:
|
12
12
|
Exclude:
|
13
13
|
- 'app/models/riiif/file.rb'
|
14
|
-
- 'app/
|
14
|
+
- 'app/resolvers/riiif/http_file_resolver.rb'
|
15
|
+
|
16
|
+
# Offense count: 1
|
17
|
+
Lint/DuplicateMethods:
|
18
|
+
Exclude:
|
15
19
|
- 'app/resolvers/riiif/http_file_resolver.rb'
|
16
20
|
|
17
21
|
# Offense count: 1
|
@@ -24,50 +28,89 @@ Lint/UselessAssignment:
|
|
24
28
|
Exclude:
|
25
29
|
- 'app/models/riiif/file.rb'
|
26
30
|
|
27
|
-
# Offense count:
|
28
|
-
|
29
|
-
|
31
|
+
# Offense count: 21
|
32
|
+
# Configuration parameters: CountComments, ExcludedMethods.
|
33
|
+
Metrics/BlockLength:
|
34
|
+
Max: 233
|
30
35
|
|
31
36
|
# Offense count: 1
|
32
37
|
Metrics/CyclomaticComplexity:
|
33
|
-
Max:
|
38
|
+
Max: 7
|
34
39
|
|
35
|
-
# Offense count:
|
36
|
-
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
37
|
-
# URISchemes: http, https
|
38
|
-
Metrics/LineLength:
|
39
|
-
Max: 117
|
40
|
-
|
41
|
-
# Offense count: 6
|
40
|
+
# Offense count: 3
|
42
41
|
# Configuration parameters: CountComments.
|
43
42
|
Metrics/MethodLength:
|
44
43
|
Max: 18
|
45
44
|
|
45
|
+
# Offense count: 1
|
46
|
+
# Configuration parameters: CountKeywordArgs.
|
46
47
|
Metrics/ParameterLists:
|
48
|
+
Max: 6
|
49
|
+
|
50
|
+
# Offense count: 1
|
51
|
+
RSpec/DescribeClass:
|
52
|
+
Exclude:
|
53
|
+
- 'spec/routing/resize_routes_spec.rb'
|
54
|
+
|
55
|
+
# Offense count: 2
|
56
|
+
# Configuration parameters: SkipBlocks, EnforcedStyle.
|
57
|
+
# SupportedStyles: described_class, explicit
|
58
|
+
RSpec/DescribedClass:
|
47
59
|
Exclude:
|
48
|
-
- '
|
60
|
+
- 'spec/models/riiif/image_spec.rb'
|
61
|
+
|
62
|
+
# Offense count: 7
|
63
|
+
# Configuration parameters: Max.
|
64
|
+
RSpec/ExampleLength:
|
65
|
+
Exclude:
|
66
|
+
- 'spec/controllers/riiif/images_controller_spec.rb'
|
67
|
+
- 'spec/models/riiif/http_file_resolver_spec.rb'
|
68
|
+
- 'spec/transformers/riiif/kakadu_transformer_spec.rb'
|
49
69
|
|
50
70
|
# Offense count: 1
|
51
|
-
|
52
|
-
# SupportedStyles: nested, compact
|
53
|
-
Style/ClassAndModuleChildren:
|
71
|
+
RSpec/LeadingSubject:
|
54
72
|
Exclude:
|
55
|
-
- '
|
73
|
+
- 'spec/transformers/riiif/kakadu_transformer_spec.rb'
|
74
|
+
|
75
|
+
# Offense count: 43
|
76
|
+
# Configuration parameters: .
|
77
|
+
# SupportedStyles: have_received, receive
|
78
|
+
RSpec/MessageSpies:
|
79
|
+
EnforcedStyle: receive
|
56
80
|
|
57
|
-
# Offense count:
|
58
|
-
|
81
|
+
# Offense count: 23
|
82
|
+
RSpec/NamedSubject:
|
83
|
+
Exclude:
|
84
|
+
- 'spec/controllers/riiif/images_controller_spec.rb'
|
85
|
+
- 'spec/models/riiif/akubra_system_file_resolver_spec.rb'
|
86
|
+
- 'spec/models/riiif/file_system_file_resolver_spec.rb'
|
87
|
+
- 'spec/models/riiif/http_file_resolver_spec.rb'
|
88
|
+
- 'spec/models/riiif/image_spec.rb'
|
89
|
+
|
90
|
+
# Offense count: 2
|
91
|
+
RSpec/RepeatedExample:
|
92
|
+
Exclude:
|
93
|
+
- 'spec/controllers/riiif/images_controller_spec.rb'
|
94
|
+
|
95
|
+
# Offense count: 7
|
96
|
+
# Configuration parameters: IgnoreSymbolicNames.
|
97
|
+
RSpec/VerifiedDoubles:
|
98
|
+
Exclude:
|
99
|
+
- 'spec/controllers/riiif/images_controller_spec.rb'
|
100
|
+
- 'spec/services/riiif/imagemagick_command_factory_spec.rb'
|
101
|
+
- 'spec/services/riiif/kakadu_command_factory_spec.rb'
|
102
|
+
|
103
|
+
# Offense count: 1
|
104
|
+
Rails/FilePath:
|
105
|
+
Exclude:
|
106
|
+
- 'spec/models/riiif/akubra_system_file_resolver_spec.rb'
|
107
|
+
|
108
|
+
# Offense count: 4
|
109
|
+
# Cop supports --auto-correct.
|
110
|
+
# Configuration parameters: PreferredDelimiters.
|
111
|
+
Style/PercentLiteralDelimiters:
|
59
112
|
Exclude:
|
60
|
-
- 'spec/**/*'
|
61
|
-
- 'test/**/*'
|
62
|
-
- 'app/controllers/riiif/images_controller.rb'
|
63
|
-
- 'app/models/riiif/file.rb'
|
64
113
|
- 'app/models/riiif/image.rb'
|
65
|
-
- 'app/resolvers/riiif/abstract_file_system_resolver.rb'
|
66
|
-
- 'app/resolvers/riiif/akubra_system_file_resolver.rb'
|
67
114
|
- 'app/resolvers/riiif/file_system_file_resolver.rb'
|
68
|
-
- '
|
69
|
-
- '
|
70
|
-
- 'lib/riiif.rb'
|
71
|
-
- 'lib/riiif/engine.rb'
|
72
|
-
- 'lib/riiif/rails/routes.rb'
|
73
|
-
- 'lib/riiif/routes.rb'
|
115
|
+
- 'spec/controllers/riiif/images_controller_spec.rb'
|
116
|
+
- 'spec/models/riiif/http_file_resolver_spec.rb'
|
data/README.md
CHANGED
@@ -63,6 +63,14 @@ If you need to use HTTP basic authentication you can enable it like this:
|
|
63
63
|
This file resolver caches the network files, so you will want to clear out the old files or the cache will expand until you run out of disk space.
|
64
64
|
Using a script like this would be a good idea: https://github.com/pulibrary/loris/blob/607567b921404a15a2111fbd7123604f4fdec087/bin/loris-cache_clean.sh
|
65
65
|
By default the cache is located in `tmp/network_files`. You can set the cache path like this: `Riiif::Image.file_resolver.cache_path = '/var/cache'`
|
66
|
+
### Kakadu (for faster jp2 decoding)
|
67
|
+
To configure Riiif to use Kakadu set:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Riiif::Engine.config.kakadu_enabled = true
|
71
|
+
```
|
72
|
+
|
73
|
+
See [benchmark](docs/benchmark.md) for details
|
66
74
|
|
67
75
|
### GraphicsMagick
|
68
76
|
|
@@ -167,7 +175,14 @@ Riiif::Image.info_service = lambda do |id, file|
|
|
167
175
|
resp = ActiveFedora::SolrService.get("id:#{fs_id}")
|
168
176
|
doc = resp['response']['docs'].first
|
169
177
|
raise "Unable to find solr document with id:#{fs_id}" unless doc
|
170
|
-
|
178
|
+
|
179
|
+
# You’ll want default values if you make thumbnails of PDFs or other
|
180
|
+
# file types that `identify` won’t return dimensions for
|
181
|
+
{
|
182
|
+
height: doc["height_is"] || 100,
|
183
|
+
width: doc["width_is"] || 100,
|
184
|
+
format: doc["mime_type_ssi"],
|
185
|
+
}
|
171
186
|
end
|
172
187
|
|
173
188
|
def logger
|
@@ -179,7 +194,7 @@ end
|
|
179
194
|
# Rails.cache. Some cache stores may not automatically purge expired content,
|
180
195
|
# such as the default FileStore.
|
181
196
|
# http://guides.rubyonrails.org/caching_with_rails.html#cache-stores
|
182
|
-
Riiif::Engine.config.
|
197
|
+
Riiif::Engine.config.cache_duration = 30.days
|
183
198
|
```
|
184
199
|
#### Special note for Passenger and Apache users
|
185
200
|
If you are running riiif in Passenger under Apache, you must set the following in your virtual host definition:
|
@@ -2,7 +2,7 @@ module Riiif
|
|
2
2
|
class ImagesController < ::ApplicationController
|
3
3
|
before_action :link_header, only: [:show, :info]
|
4
4
|
|
5
|
-
rescue_from
|
5
|
+
rescue_from IIIF::Image::InvalidAttributeError do
|
6
6
|
head 400
|
7
7
|
end
|
8
8
|
|
@@ -44,6 +44,12 @@ module Riiif
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
# See https://fetch.spec.whatwg.org/#http-access-control-allow-headers
|
48
|
+
def info_options
|
49
|
+
response.headers['Access-Control-Allow-Headers'] = 'Authorization'
|
50
|
+
self.response_body = ''
|
51
|
+
end
|
52
|
+
|
47
53
|
# this is a workaround for https://github.com/rails/rails/issues/25087
|
48
54
|
def redirect
|
49
55
|
# This was attempted with just info_path, but it gave a NoMethodError
|
@@ -120,7 +126,7 @@ module Riiif
|
|
120
126
|
CONTEXT => CONTEXT_URI,
|
121
127
|
ID => request.original_url.sub('/info.json', ''),
|
122
128
|
PROTOCOL => PROTOCOL_URI,
|
123
|
-
PROFILE => [LEVEL1, 'formats' => OptionDecoder::OUTPUT_FORMATS]
|
129
|
+
PROFILE => [LEVEL1, 'formats' => IIIF::Image::OptionDecoder::OUTPUT_FORMATS]
|
124
130
|
}
|
125
131
|
end
|
126
132
|
end
|
data/app/models/riiif/image.rb
CHANGED
@@ -1,27 +1,11 @@
|
|
1
1
|
require 'digest/md5'
|
2
2
|
|
3
|
-
##
|
4
|
-
# These explict requires are needed because in some contexts the Rails
|
5
|
-
# autoloader can either: unload already loaded classes, or cause a lock while
|
6
|
-
# trying to load a needed class.
|
7
|
-
require_dependency 'riiif/region/absolute'
|
8
|
-
require_dependency 'riiif/region/full'
|
9
|
-
require_dependency 'riiif/region/percentage'
|
10
|
-
require_dependency 'riiif/region/square'
|
11
|
-
|
12
|
-
require_dependency 'riiif/size/absolute'
|
13
|
-
require_dependency 'riiif/size/best_fit'
|
14
|
-
require_dependency 'riiif/size/full'
|
15
|
-
require_dependency 'riiif/size/height'
|
16
|
-
require_dependency 'riiif/size/percent'
|
17
|
-
require_dependency 'riiif/size/width'
|
18
|
-
|
19
3
|
module Riiif
|
20
4
|
class Image
|
21
5
|
extend Deprecation
|
22
6
|
|
23
7
|
class_attribute :file_resolver, :info_service, :authorization_service, :cache
|
24
|
-
self.file_resolver = FileSystemFileResolver.new(base_path: File.join(Rails.root, 'tmp'))
|
8
|
+
self.file_resolver = FileSystemFileResolver.new(base_path: ::File.join(Rails.root, 'tmp'))
|
25
9
|
self.authorization_service = NilAuthorizationService
|
26
10
|
self.cache = Rails.cache
|
27
11
|
|
@@ -60,20 +44,31 @@ module Riiif
|
|
60
44
|
key = Image.cache_key(id, cache_opts)
|
61
45
|
|
62
46
|
cache.fetch(key, compress: true, expires_in: Image.expires_in) do
|
63
|
-
file.extract(OptionDecoder.decode(args
|
47
|
+
file.extract(IIIF::Image::OptionDecoder.decode(args), info)
|
64
48
|
end
|
65
49
|
end
|
66
50
|
|
67
51
|
def info
|
68
52
|
@info ||= begin
|
69
53
|
result = info_service.call(id, file)
|
70
|
-
ImageInformation.new(
|
54
|
+
ImageInformation.new(
|
55
|
+
width: result[:width],
|
56
|
+
height: result[:height],
|
57
|
+
format: result[:format]
|
58
|
+
)
|
71
59
|
end
|
72
60
|
end
|
73
61
|
|
74
62
|
class << self
|
75
63
|
def expires_in
|
76
|
-
Riiif::Engine.config.cache_duration_in_days
|
64
|
+
if Riiif::Engine.config.respond_to?(:cache_duration_in_days)
|
65
|
+
Deprecation.warn(self,
|
66
|
+
'Riiif::Engine.config.cache_duration_in_days is deprecated; '\
|
67
|
+
'use #cache_duration instead and pass a fully-qualified date (e.g., `3.days`)')
|
68
|
+
Riiif::Engine.config.cache_duration_in_days.days
|
69
|
+
else
|
70
|
+
Riiif::Engine.config.cache_duration
|
71
|
+
end
|
77
72
|
end
|
78
73
|
|
79
74
|
def cache_key(id, options)
|
@@ -1,41 +1,29 @@
|
|
1
1
|
module Riiif
|
2
2
|
# This is the result of calling the Riiif.image_info service. It stores the height & width
|
3
|
-
class ImageInformation
|
3
|
+
class ImageInformation < IIIF::Image::Dimension
|
4
4
|
extend Deprecation
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(*args)
|
7
|
+
if args.size == 2
|
8
|
+
Deprecation.warn(self, 'calling initialize without kwargs is deprecated. Use named parameters.')
|
9
|
+
super(width: args.first, height: args.second)
|
10
|
+
else
|
11
|
+
@width = args.first[:width]
|
12
|
+
@height = args.first[:height]
|
13
|
+
@format = args.first[:format]
|
14
|
+
end
|
9
15
|
end
|
10
|
-
|
11
|
-
attr_reader :width, :height
|
16
|
+
attr_reader :format, :height, :width
|
12
17
|
|
13
18
|
def to_h
|
14
|
-
{ width: width, height: height }
|
15
|
-
end
|
16
|
-
|
17
|
-
def aspect_ratio
|
18
|
-
width.to_f / height
|
19
|
+
{ width: width, height: height, format: format }
|
19
20
|
end
|
20
21
|
|
21
|
-
def [](key)
|
22
|
-
to_h[key]
|
23
|
-
end
|
24
|
-
deprecation_deprecate :[] => 'Riiif::ImageInformation#[] has been deprecated ' \
|
25
|
-
'and will be removed in version 2.0. Use Riiif::ImageInformation#to_h and ' \
|
26
|
-
'call #[] on that result OR consider using #height and #width directly.'
|
27
|
-
|
28
22
|
# Image information is only valid if height and width are present.
|
29
23
|
# If an image info service doesn't have the value yet (not characterized perhaps?)
|
30
24
|
# then we wouldn't want to cache this value.
|
31
25
|
def valid?
|
32
26
|
width.present? && height.present?
|
33
27
|
end
|
34
|
-
|
35
|
-
def ==(other)
|
36
|
-
other.class == self.class &&
|
37
|
-
other.width == width &&
|
38
|
-
other.height == height
|
39
|
-
end
|
40
28
|
end
|
41
29
|
end
|
data/app/services/riiif/crop.rb
CHANGED
@@ -1,54 +1,123 @@
|
|
1
1
|
module Riiif
|
2
2
|
# Represents a cropping operation
|
3
3
|
class Crop
|
4
|
-
|
4
|
+
# @param transformation [IIIF::Image::Region] the result the user requested
|
5
|
+
# @param image_info []
|
6
|
+
def initialize(region, image_info)
|
7
|
+
@region = region
|
8
|
+
@image_info = image_info
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :image_info, :region
|
5
12
|
|
6
13
|
# @return [String] a region for imagemagick to decode
|
7
14
|
# (appropriate for passing to the -crop parameter)
|
8
15
|
def to_imagemagick
|
9
|
-
|
16
|
+
case region
|
17
|
+
when IIIF::Image::Region::Full
|
18
|
+
nil
|
19
|
+
when IIIF::Image::Region::Absolute
|
20
|
+
"#{region.width}x#{region.height}+#{region.offset_x}+#{region.offset_y}"
|
21
|
+
when IIIF::Image::Region::Square
|
22
|
+
imagemagick_square
|
23
|
+
when IIIF::Image::Region::Percent
|
24
|
+
imagemagick_percent
|
25
|
+
else
|
26
|
+
raise "Unknown region #{region.class}"
|
27
|
+
end
|
10
28
|
end
|
11
29
|
|
12
30
|
# @return [String] a region for kakadu to decode
|
13
31
|
# (appropriate for passing to the -region parameter)
|
14
32
|
def to_kakadu
|
15
|
-
|
33
|
+
case region
|
34
|
+
when IIIF::Image::Region::Full
|
35
|
+
nil
|
36
|
+
when IIIF::Image::Region::Absolute
|
37
|
+
"\{#{decimal_offset_y(region.offset_y)},#{decimal_offset_x(region.offset_x)}\}," \
|
38
|
+
"\{#{decimal_height(region.height)},#{decimal_width(region.width)}\}"
|
39
|
+
when IIIF::Image::Region::Square
|
40
|
+
kakadu_square
|
41
|
+
when IIIF::Image::Region::Percent
|
42
|
+
kakadu_percent
|
43
|
+
else
|
44
|
+
raise "Unknown region #{region.class}"
|
45
|
+
end
|
16
46
|
end
|
17
47
|
|
18
|
-
|
48
|
+
private
|
19
49
|
|
20
|
-
|
50
|
+
def imagemagick_percent
|
51
|
+
offset_x = (image_info.width * percentage_to_fraction(region.x_pct)).round
|
52
|
+
offset_y = (image_info.height * percentage_to_fraction(region.y_pct)).round
|
53
|
+
"#{region.width_pct}%x#{region.height_pct}+#{offset_x}+#{offset_y}"
|
54
|
+
end
|
21
55
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
56
|
+
def kakadu_percent
|
57
|
+
offset_x = (image_info.width * percentage_to_fraction(region.x_pct)).round
|
58
|
+
offset_y = (image_info.height * percentage_to_fraction(region.y_pct)).round
|
59
|
+
"\{#{decimal_offset_y(offset_y)},#{decimal_offset_x(offset_x)}\}," \
|
60
|
+
"\{#{percentage_to_fraction(region.height_pct)},#{percentage_to_fraction(region.width_pct)}\}"
|
61
|
+
end
|
26
62
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
63
|
+
def kakadu_square
|
64
|
+
min, max = [image_info.width, image_info.height].minmax
|
65
|
+
offset = (max - min) / 2
|
66
|
+
if image_info.height >= image_info.width
|
67
|
+
# Portrait
|
68
|
+
"\{#{decimal_height(offset)},0\}," \
|
69
|
+
"\{#{decimal_height(image_info.height)},#{decimal_width(image_info.height)}\}"
|
70
|
+
else
|
71
|
+
# Landscape
|
72
|
+
"\{0,#{decimal_width(offset)}\}," \
|
73
|
+
"\{#{decimal_height(image_info.width)},#{decimal_width(image_info.width)}\}"
|
74
|
+
end
|
75
|
+
end
|
31
76
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
77
|
+
def imagemagick_square
|
78
|
+
min, max = [image_info.width, image_info.height].minmax
|
79
|
+
offset = (max - min) / 2
|
80
|
+
if image_info.height >= image_info.width
|
81
|
+
"#{min}x#{min}+0+#{offset}"
|
82
|
+
else
|
83
|
+
"#{min}x#{min}+#{offset}+0"
|
84
|
+
end
|
85
|
+
end
|
36
86
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
87
|
+
# @return [Integer] the height in pixels
|
88
|
+
def height
|
89
|
+
image_info.height
|
90
|
+
end
|
41
91
|
|
42
|
-
|
43
|
-
|
44
|
-
|
92
|
+
# @return [Integer] the width in pixels
|
93
|
+
def width
|
94
|
+
image_info.width
|
95
|
+
end
|
45
96
|
|
46
|
-
|
47
|
-
|
48
|
-
|
97
|
+
# @return [Float] the fractional height with respect to the original size
|
98
|
+
def decimal_height(n = height)
|
99
|
+
n.to_f / image_info.height
|
100
|
+
end
|
49
101
|
|
50
|
-
|
51
|
-
|
52
|
-
|
102
|
+
# @return [Float] the fractional width with respect to the original size
|
103
|
+
def decimal_width(n = width)
|
104
|
+
n.to_f / image_info.width
|
105
|
+
end
|
106
|
+
|
107
|
+
def decimal_offset_x(offset_x)
|
108
|
+
offset_x.to_f / image_info.width
|
109
|
+
end
|
110
|
+
|
111
|
+
def decimal_offset_y(offset_y)
|
112
|
+
offset_y.to_f / image_info.height
|
113
|
+
end
|
114
|
+
|
115
|
+
def maintain_aspect_ratio?
|
116
|
+
(height / width) == (image_info.height / image_info.width)
|
117
|
+
end
|
118
|
+
|
119
|
+
def percentage_to_fraction(n)
|
120
|
+
n / 100.0
|
121
|
+
end
|
53
122
|
end
|
54
123
|
end
|