iiif-image-api 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8a37336c486475446d723312acff027b317dba79
4
+ data.tar.gz: 255166f9899b76d6906bdcedb11debfa3edbc968
5
+ SHA512:
6
+ metadata.gz: 86e7bf0d8bb3de17656616531ea9c379211a04dd75b01e9516ae78bef381f36abbab91368c932d6f6acca10a2a7a91074655303b351df33989c6fa042348c3b8
7
+ data.tar.gz: 2259209956d2ba02c041ed70dbf957d6fbe4486f626a4f4110aaba7ff6e74f862408406cc8433db1c2c569269379755e08b00955a6f74a620082941ffd72acd9
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
4
+ before_install: gem install bundler -v 1.10.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in iiif.gemspec
4
+ gemspec
@@ -0,0 +1,28 @@
1
+ # IIIF
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'iiif'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install iiif
18
+
19
+ ## Development
20
+
21
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
22
+
23
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
24
+
25
+ ## Contributing
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cbeer/iiif.
28
+
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "iiif"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'iiif/image/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'iiif-image-api'
8
+ spec.version = IIIF::Image::VERSION
9
+ spec.authors = ['Justin Coyne']
10
+ spec.email = ['jcoyne@justincoyne.com']
11
+
12
+ spec.summary = %(Ruby APIs for working with IIIF)
13
+ spec.description = %(Ruby APIs for working with IIIF)
14
+ spec.homepage = 'https://github.com/cbeer/iiif'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = 'exe'
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'activesupport', '~> 4.0'
22
+
23
+ spec.add_development_dependency 'bundler', "~> 1.10"
24
+ spec.add_development_dependency 'rake', "~> 10.0"
25
+ spec.add_development_dependency 'rspec'
26
+ end
@@ -0,0 +1,3 @@
1
+ require 'iiif/image'
2
+ module IIIF
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_support/all'
2
+ require 'iiif/image/version'
3
+
4
+ module IIIF
5
+ module Image
6
+ extend ActiveSupport::Autoload
7
+ autoload :Region
8
+ autoload :Size
9
+
10
+ autoload_under 'models' do
11
+ autoload :URI
12
+ autoload :Transformation
13
+ autoload :ImageRequestUri
14
+ autoload :Dimension
15
+ end
16
+
17
+ autoload_under 'services' do
18
+ autoload :OptionDecoder
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module IIIF::Image
2
+ # Represents the size of a rectangle
3
+ class Dimension
4
+ def initialize(height:, width:)
5
+ @height = height
6
+ @width = width
7
+ end
8
+
9
+ attr_reader :height, :width
10
+
11
+ # @param scale [Float] scale factor between 0 and 1
12
+ # @return [Dimension]
13
+ def scale(scale)
14
+ Dimension.new(height: height * scale, width: width * scale)
15
+ end
16
+
17
+ # Return true if both dimensions of other are greater
18
+ def enclosed_by?(other)
19
+ width <= other.width && height <= other.height
20
+ end
21
+
22
+ def ==(other)
23
+ width == other.width && height == other.height
24
+ end
25
+
26
+ def aspect
27
+ Rational(width, height)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ module IIIF::Image
2
+ # Class to represent IIIF Image Request URI
3
+ class ImageRequestUri < IIIF::Image::URI
4
+ # @param base_uri [String]
5
+ # @param identifier [String]
6
+ # @param transformation [Transformation]
7
+ def initialize(base_uri:, identifier:, transformation:)
8
+ @base_uri = base_uri
9
+ @identifier = identifier
10
+ @transformation = transformation
11
+ end
12
+
13
+ def to_s
14
+ "#{base_uri}#{identifier}/#{region}/#{size}/#{rotation}/#{quality}.#{format}"
15
+ end
16
+
17
+ delegate :valid?, to: :transformation
18
+
19
+ # I think this is unnecessary in later versions https://github.com/bbatsov/rubocop/pull/3883
20
+ # rubocop:disable Lint/UselessAccessModifier
21
+ private
22
+
23
+ delegate :region, :size, :rotation, :quality, :format, to: :transformation
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IIIF::Image
4
+ # A data object that describes the IIIF request
5
+ class Transformation
6
+ def initialize(region:, size:, rotation: '0', quality: 'default', format: 'jpg')
7
+ @region = region
8
+ @size = size
9
+ @rotation = rotation
10
+ @quality = quality
11
+ @format = format
12
+ end
13
+
14
+ attr_reader :region, :size, :rotation, :quality, :format
15
+
16
+ def to_params
17
+ { region: region,
18
+ size: size,
19
+ rotation: rotation,
20
+ quality: quality,
21
+ format: format }
22
+ end
23
+
24
+ def valid?
25
+ %w(color gray bitonal default).include? quality
26
+ end
27
+
28
+ def ==(other)
29
+ other.class == self.class &&
30
+ other.region == region &&
31
+ other.size == size &&
32
+ other.rotation == rotation &&
33
+ other.quality == quality &&
34
+ other.format == format
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module IIIF::Image
2
+ # Represents a URI to a IIIF image endpoint
3
+ class URI
4
+ # @param base_uri [String]
5
+ # @param identifier [String]
6
+ # @param transformation [Transformation]
7
+ def initialize(base_uri:, identifier:, transformation: nil)
8
+ @base_uri = base_uri
9
+ @identifier = identifier
10
+ @transformation = transformation
11
+ end
12
+
13
+ attr_reader :base_uri, :transformation, :identifier
14
+
15
+ def to_s
16
+ return to_image_request_uri.to_s if transformation
17
+ base_uri + identifier + '/info.json'
18
+ end
19
+
20
+ def valid?
21
+ return true unless transformation
22
+ to_image_request_uri.valid?
23
+ end
24
+
25
+ private
26
+
27
+ def to_image_request_uri
28
+ ImageRequestUri.new(base_uri: base_uri, identifier: identifier, transformation: transformation)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ module IIIF::Image
2
+ module Region
3
+ extend ActiveSupport::Autoload
4
+ autoload :Absolute
5
+ autoload :Full
6
+ autoload :Percent
7
+ autoload :Square
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ module IIIF::Image
2
+ module Region
3
+ # Represents an absolute specified region
4
+ class Absolute
5
+ # @param [Integer] x
6
+ # @param [Integer] y
7
+ # @param [Integer] width
8
+ # @param [Integer] height
9
+ def initialize(x, y, width, height)
10
+ @offset_x = x
11
+ @offset_y = y
12
+ @width = width
13
+ @height = height
14
+ end
15
+
16
+ attr_reader :offset_x, :offset_y, :width, :height
17
+
18
+ def dimensions
19
+ Dimension.new(width: width, height: height)
20
+ end
21
+
22
+ def to_s
23
+ "pct:#{offset_x},#{offset_y},#{width},#{height}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module IIIF::Image
2
+ module Region
3
+ # Represents the image or region requested at its full size.
4
+ # This is a nil crop operation.
5
+ class Full
6
+ def to_s
7
+ 'full'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module IIIF::Image
2
+ module Region
3
+ # represents request cooridnates specified as percentage
4
+ class Percent
5
+ # @param x [Float]
6
+ # @param y [Float]
7
+ # @param width [Float]
8
+ # @param height [Float]
9
+ def initialize(x, y, width, height)
10
+ @x_pct = x
11
+ @y_pct = y
12
+ @width_pct = width
13
+ @height_pct = height
14
+ end
15
+
16
+ attr_reader :x_pct, :y_pct, :width_pct, :height_pct
17
+
18
+ def to_s
19
+ "pct:#{x_pct},#{y_pct},#{width_pct},#{height_pct}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ module IIIF::Image
2
+ module Region
3
+ # Represents requested square cooridnates
4
+ class Square
5
+ def to_s
6
+ 'square'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IIIF::Image
4
+ # Decodes the URL parameters into a Transformation object
5
+ class OptionDecoder
6
+ OUTPUT_FORMATS = %w(jpg png).freeze
7
+
8
+ # a helper method for instantiating the OptionDecoder
9
+ # @param [ActiveSupport::HashWithIndifferentAccess] options
10
+ def self.decode(options)
11
+ new(options).decode
12
+ end
13
+
14
+ # @param [ActiveSupport::HashWithIndifferentAccess] options
15
+ def initialize(options)
16
+ @options = options
17
+ end
18
+
19
+ ##
20
+ # @return [Transformation]
21
+ def decode
22
+ IIIF::Image::Transformation.new(region: decode_region(@options.delete(:region)),
23
+ size: decode_size(@options.delete(:size)),
24
+ quality: decode_quality(@options[:quality]),
25
+ rotation: decode_rotation(@options[:rotation]),
26
+ format: decode_format(@options[:format]))
27
+ end
28
+
29
+ def decode_quality(quality)
30
+ return quality if %w(bitonal grey default color).include?(quality)
31
+ return 'default' if quality.nil?
32
+ raise InvalidAttributeError, "Unsupported quality: #{quality}"
33
+ end
34
+
35
+ def decode_rotation(rotation)
36
+ return 0 if rotation.nil? || rotation == '0'
37
+ begin
38
+ Float(rotation)
39
+ rescue ArgumentError
40
+ raise InvalidAttributeError, "Unsupported rotation: #{rotation}"
41
+ end
42
+ end
43
+
44
+ def decode_format(format)
45
+ format ||= 'jpg'
46
+ return format if OUTPUT_FORMATS.include?(format)
47
+ raise InvalidAttributeError, "Unsupported format: #{format}"
48
+ end
49
+
50
+ # rubocop:disable Metrics/AbcSize
51
+ def decode_region(region)
52
+ if region.nil? || region == 'full'
53
+ Region::Full.new
54
+ elsif md = /^pct:(\d+(?:.\d+)?),(\d+(?:.\d+)?),(\d+(?:.\d+)?),(\d+(?:.\d+)?)$/.match(region)
55
+ Region::Percentage
56
+ .new(md[1].to_f, md[2].to_f, md[3].to_f, md[4].to_f)
57
+ elsif md = /^(\d+),(\d+),(\d+),(\d+)$/.match(region)
58
+ Region::Absolute.new(md[1].to_i, md[2].to_i, md[3].to_i, md[4].to_i)
59
+ elsif region == 'square'
60
+ Region::Square.new
61
+ else
62
+ raise InvalidAttributeError, "Invalid region: #{region}"
63
+ end
64
+ end
65
+
66
+ def decode_size(size)
67
+ if size.nil? || size == 'max'
68
+ Size::Max.new
69
+ elsif size == 'full'
70
+ Size::Full.new # Deprecated
71
+ elsif md = /^,(\d+)$/.match(size)
72
+ Size::Height.new(md[1].to_i)
73
+ elsif md = /^(\d+),$/.match(size)
74
+ Size::Width.new(md[1].to_i)
75
+ elsif md = /^pct:(\d+(?:.\d+)?)$/.match(size)
76
+ Size::Percent.new(md[1].to_f)
77
+ elsif md = /^(\d+),(\d+)$/.match(size)
78
+ Size::Absolute.new(md[1].to_i, md[2].to_i)
79
+ elsif md = /^!(\d+),(\d+)$/.match(size)
80
+ Size::BestFit.new(md[1].to_i, md[2].to_i)
81
+ else
82
+ raise InvalidAttributeError, "Invalid size: #{size}"
83
+ end
84
+ end
85
+ # rubocop:enable Metrics/AbcSize
86
+ end
87
+ end
@@ -0,0 +1,12 @@
1
+ module IIIF::Image
2
+ module Size
3
+ extend ActiveSupport::Autoload
4
+ autoload :Absolute
5
+ autoload :BestFit
6
+ autoload :Full
7
+ autoload :Height
8
+ autoload :Max
9
+ autoload :Percent
10
+ autoload :Width
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # The width and height of the returned image are exactly w and h.
4
+ # The aspect ratio of the returned image may be different than the extracted
5
+ # region, resulting in a distorted image.
6
+ class Absolute
7
+ # @param [Integer] width
8
+ # @param [Integer] height
9
+ def initialize(width, height)
10
+ @width = width
11
+ @height = height
12
+ end
13
+
14
+ attr_reader :height, :width
15
+
16
+ def to_s
17
+ "#{width},#{height}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # The image content is scaled for the best fit such that the resulting width and
4
+ # height are less than or equal to the requested width and height.
5
+ class BestFit
6
+ # @param [Integer] width
7
+ # @param [Integer] height
8
+ def initialize(width, height)
9
+ @width = width
10
+ @height = height
11
+ end
12
+
13
+ attr_reader :height, :width
14
+
15
+ def to_s
16
+ "!#{width},#{height}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # represents requested full size. Full is deprecated in favor of Max in the IIIF spec
4
+ class Full
5
+ def to_s
6
+ "full"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # The image or region should be scaled so that its height is exactly equal
4
+ # to the provided parameter, and the width will be a calculated value that
5
+ # maintains the aspect ratio of the extracted region
6
+ class Height
7
+ # @param [Integer] height
8
+ def initialize(height)
9
+ @height = height
10
+ end
11
+
12
+ attr_reader :height
13
+
14
+ # @param ratio [Rational] the aspect ratio
15
+ def width_for_aspect_ratio(ratio)
16
+ (ratio * height).round
17
+ end
18
+
19
+ def to_s
20
+ ",#{height}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # represents requested max size
4
+ class Max
5
+ def to_s
6
+ "max"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # The width and height of the returned image is scaled to n% of the width and height
4
+ # of the extracted region. The aspect ratio of the returned image is the same as that
5
+ # of the extracted region.
6
+ class Percent
7
+ # @param percentage [Float]
8
+ def initialize(percentage)
9
+ @percentage = percentage
10
+ end
11
+
12
+ attr_reader :percentage
13
+
14
+ # @return [Float] scale factor between 0 and 1
15
+ def scale
16
+ percentage / 100
17
+ end
18
+
19
+ def to_s
20
+ "pct:#{percentage}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module IIIF::Image
2
+ module Size
3
+ # The image or region should be scaled so that its width is exactly equal
4
+ # to the provided parameter, and the height will be a calculated value that
5
+ # maintains the aspect ratio of the extracted region
6
+ class Width
7
+ # @param [Integer] width
8
+ def initialize(width)
9
+ @width = width
10
+ end
11
+
12
+ attr_reader :width
13
+
14
+ # @param ratio [Rational] the aspect ratio
15
+ def height_for_aspect_ratio(ratio)
16
+ (width / ratio).round
17
+ end
18
+
19
+ def to_s
20
+ "#{width},"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module IIIF
2
+ module Image
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iiif-image-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Justin Coyne
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
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: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Ruby APIs for working with IIIF
70
+ email:
71
+ - jcoyne@justincoyne.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - README.md
81
+ - Rakefile
82
+ - bin/console
83
+ - bin/setup
84
+ - iiif-image-api.gemspec
85
+ - lib/iiif.rb
86
+ - lib/iiif/image.rb
87
+ - lib/iiif/image/models/dimension.rb
88
+ - lib/iiif/image/models/image_request_uri.rb
89
+ - lib/iiif/image/models/transformation.rb
90
+ - lib/iiif/image/models/uri.rb
91
+ - lib/iiif/image/region.rb
92
+ - lib/iiif/image/region/absolute.rb
93
+ - lib/iiif/image/region/full.rb
94
+ - lib/iiif/image/region/percent.rb
95
+ - lib/iiif/image/region/square.rb
96
+ - lib/iiif/image/services/option_decoder.rb
97
+ - lib/iiif/image/size.rb
98
+ - lib/iiif/image/size/absolute.rb
99
+ - lib/iiif/image/size/best_fit.rb
100
+ - lib/iiif/image/size/full.rb
101
+ - lib/iiif/image/size/height.rb
102
+ - lib/iiif/image/size/max.rb
103
+ - lib/iiif/image/size/percent.rb
104
+ - lib/iiif/image/size/width.rb
105
+ - lib/iiif/image/version.rb
106
+ homepage: https://github.com/cbeer/iiif
107
+ licenses: []
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.6.13
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Ruby APIs for working with IIIF
129
+ test_files: []