riiif 2.0.0.beta2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|