wax_iiif 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +25 -0
  4. data/.travis.yml +2 -2
  5. data/Gemfile +3 -2
  6. data/README.md +4 -4
  7. data/lib/wax_iiif.rb +34 -44
  8. data/lib/wax_iiif/base_properties.rb +90 -0
  9. data/lib/wax_iiif/builder.rb +252 -0
  10. data/lib/wax_iiif/collection.rb +58 -0
  11. data/lib/{iiif_s3 → wax_iiif}/config.rb +46 -60
  12. data/lib/{iiif_s3 → wax_iiif}/errors.rb +6 -12
  13. data/lib/{iiif_s3 → wax_iiif}/full_image.rb +3 -8
  14. data/lib/wax_iiif/image_info.rb +89 -0
  15. data/lib/{iiif_s3 → wax_iiif}/image_record.rb +48 -63
  16. data/lib/{iiif_s3 → wax_iiif}/image_tile.rb +8 -14
  17. data/lib/{iiif_s3 → wax_iiif}/image_variant.rb +20 -38
  18. data/lib/wax_iiif/manifest.rb +151 -0
  19. data/lib/{iiif_s3 → wax_iiif}/thumbnail.rb +5 -9
  20. data/lib/{iiif_s3 → wax_iiif}/utilities.rb +5 -5
  21. data/lib/{iiif_s3 → wax_iiif}/utilities/helpers.rb +18 -48
  22. data/lib/{iiif_s3 → wax_iiif}/utilities/pdf_splitter.rb +20 -23
  23. data/spec/base_properties_spec.rb +8 -12
  24. data/spec/shared_contexts.rb +28 -92
  25. data/spec/spec_helper.rb +3 -3
  26. data/spec/wax_iiif/builder_spec.rb +143 -0
  27. data/spec/wax_iiif/collection_spec.rb +53 -0
  28. data/spec/wax_iiif/config_spec.rb +15 -0
  29. data/spec/wax_iiif/image_info_spec.rb +57 -0
  30. data/spec/wax_iiif/image_record_spec.rb +82 -0
  31. data/spec/wax_iiif/image_variant_spec.rb +66 -0
  32. data/spec/wax_iiif/manifest_spec.rb +97 -0
  33. data/spec/wax_iiif/utilities/pdf_splitter_spec.rb +14 -0
  34. data/wax_iiif.gemspec +15 -19
  35. metadata +52 -97
  36. data/Guardfile +0 -10
  37. data/Rakefile +0 -24
  38. data/lib/iiif_s3/base_properties.rb +0 -95
  39. data/lib/iiif_s3/builder.rb +0 -241
  40. data/lib/iiif_s3/collection.rb +0 -61
  41. data/lib/iiif_s3/image_info.rb +0 -96
  42. data/lib/iiif_s3/manifest.rb +0 -151
  43. data/lib/iiif_s3/version.rb +0 -5
  44. data/spec/iiif_s3/builder_spec.rb +0 -152
  45. data/spec/iiif_s3/collection_spec.rb +0 -68
  46. data/spec/iiif_s3/config_spec.rb +0 -15
  47. data/spec/iiif_s3/image_info_spec.rb +0 -57
  48. data/spec/iiif_s3/image_record_spec.rb +0 -96
  49. data/spec/iiif_s3/image_variant_spec.rb +0 -68
  50. data/spec/iiif_s3/manifest_spec.rb +0 -97
  51. data/spec/iiif_s3/utilities/pdf_splitter_spec.rb +0 -17
  52. data/test.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31844c9c4c8aa58c1e5e940fd0bc447c073e0b4e1e5bf8f7dc77970eeaac95b5
4
- data.tar.gz: d17b64b8d0f9a6c69340128571128c74bb44c26fb119911aff496dd71a4abc5f
3
+ metadata.gz: b8e8bfe689315b674d1af11bb292df7b42c6da7dcdaa4fe277b746ab2fcacc5c
4
+ data.tar.gz: 787041b5e001e26094254a123bf1d42327e1a2ec1d4c7af729f4b1aabb432318
5
5
  SHA512:
6
- metadata.gz: b8b751aaa0cc21122743f4a2a6f7d166cac8cc7bb36942c631cae2343d382973fe2400282dc1c9e884dc4b9b4902ef8b42fa50a214c69b315a0168c29390b334
7
- data.tar.gz: 7ee23f85b57d3ee86abe9002220b73a5138a950dc94406499d2fa59bd7824c56cab91682cd6dc94d8aa311a185e28e774ea2c09e139269c9866324eb5ae0cc15
6
+ metadata.gz: 3bed76dcd0835a29fcbf74eb01c38c4980d91af269eabde4d5f6535c058a2e81e4e7a2252a6b2d24c7c9029d142baf8600d6179ae3db2de95622682ea5a6acfe
7
+ data.tar.gz: 15683183c49c2968751abb425cc0d75a4b42d7d21ef7d11a0725b4cddc991079324bf3cf69d4ea9e330a81faf0b05303bd7c92ae827bd5a766eff7683b90d38d
data/.gitignore CHANGED
@@ -20,6 +20,7 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+ temp
23
24
 
24
25
  .env
25
26
 
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ Exclude: ['spec/**/*']
4
+ Metrics/LineLength:
5
+ IgnoredPatterns: ['raise', 'puts', '#', '@', 'spec']
6
+ Style/FrozenStringLiteralComment:
7
+ Enabled: false
8
+ Style/RedundantSelf:
9
+ Enabled: false
10
+ Metrics/MethodLength:
11
+ Enabled: false
12
+ Style/DoubleNegation:
13
+ Enabled: false
14
+ Metrics/AbcSize:
15
+ Enabled: false
16
+ Metrics/CyclomaticComplexity:
17
+ Enabled: false
18
+ Metrics/PerceivedComplexity:
19
+ Enabled: false
20
+ Metrics/ClassLength:
21
+ Enabled: false
22
+ Layout/EmptyLineAfterGuardClause:
23
+ Enabled: false
24
+ Lint/UriEscapeUnescape:
25
+ Enabled: false
@@ -1,11 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2
4
- - 2.3
5
3
  - 2.4
4
+ - 2.5
6
5
  addons:
7
6
  apt:
8
7
  packages:
9
8
  - ghostscript
10
9
  script:
10
+ - bundle exec rubocop
11
11
  - bundle exec rspec
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in wax_iiif.gemspec
4
2
  gemspec
3
+
4
+ gem 'rubocop', '0.59.0', require: false
5
+ gem 'yard', require: false
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # wax_iiif
2
- [![Build Status](https://travis-ci.org/mnyrop/wax_iiif.svg?branch=master)](https://travis-ci.org/mnyrop/wax_iiif) [![Dependency Status](https://gemnasium.com/badges/github.com/mnyrop/wax_iiif.svg)](https://gemnasium.com/github.com/mnyrop/wax_iiif) [![Maintainability](https://api.codeclimate.com/v1/badges/3eb2fcf5ae47e7b6d686/maintainability)](https://codeclimate.com/github/mnyrop/wax_iiif/maintainability)
2
+ [![Gem Version](https://badge.fury.io/rb/wax_iiif.svg)](https://badge.fury.io/rb/wax_iiif) [![Build Status](https://travis-ci.org/mnyrop/wax_iiif.svg?branch=master)](https://travis-ci.org/mnyrop/wax_iiif) [![Maintainability](https://api.codeclimate.com/v1/badges/3eb2fcf5ae47e7b6d686/maintainability)](https://codeclimate.com/github/mnyrop/wax_iiif/maintainability)
3
3
 
4
- This fork is TRULY just a copy of the [iiif_s3 gem](https://github.com/cmoa/iiif_s3) with all the s3 dependencies and functionality removed!
4
+ ![License](https://img.shields.io/badge/license-MIT-green.svg) [![docs](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](https://www.rubydoc.info/github/minicomp/wax_iiif/)
5
5
 
6
- It enables the static creation of IIIF derivatives (level 0) for static exhibtion sites with [wax](https://minicomp.github.io/wax/).
6
+ This fork is *mostly* a copy of the [iiif_s3 gem](https://github.com/cmoa/iiif_s3) with all the s3 dependencies and functionality removed. It creates level 0 IIIF derivatives for static exhibition sites with [Minicomp/Wax](https://minicomp.github.io/wax/) via [Wax_Tasks](https://minicomp.github.io/wax_tasks/).
7
7
 
8
- For credit and documentation, head over to [iiif_s3](https://github.com/cmoa/iiif_s3).
8
+ Documentation for using `wax_iiif` without `wax_tasks` is forthcoming. In the meantime, check out [rubydoc](https://www.rubydoc.info/gems/wax_iiif).
@@ -1,83 +1,73 @@
1
1
  require 'csv'
2
2
  require 'json'
3
3
 
4
- require "iiif_s3/version"
5
- require "iiif_s3/errors"
6
- require "iiif_s3/base_properties"
7
- require "iiif_s3/image_record"
8
- require "iiif_s3/builder"
9
- require "iiif_s3/manifest"
10
- require "iiif_s3/config"
11
- require "iiif_s3/collection"
12
- require "iiif_s3/image_variant"
13
- require "iiif_s3/thumbnail"
14
- require "iiif_s3/image_tile"
15
- require "iiif_s3/full_image"
16
- require "iiif_s3/image_info"
17
- require "iiif_s3/utilities"
4
+ require_relative 'wax_iiif/errors'
5
+ require_relative 'wax_iiif/base_properties'
6
+ require_relative 'wax_iiif/image_record'
7
+ require_relative 'wax_iiif/builder'
8
+ require_relative 'wax_iiif/manifest'
9
+ require_relative 'wax_iiif/config'
10
+ require_relative 'wax_iiif/collection'
11
+ require_relative 'wax_iiif/image_variant'
12
+ require_relative 'wax_iiif/thumbnail'
13
+ require_relative 'wax_iiif/image_tile'
14
+ require_relative 'wax_iiif/full_image'
15
+ require_relative 'wax_iiif/image_info'
16
+ require_relative 'wax_iiif/utilities'
18
17
 
19
- # Module IiifS3 is a tool for generating IIIF resources from a set of files.
18
+ # Module WaxIiif is a tool for generating IIIF resources from a set of files.
20
19
  # It's designed to support the IIIF level 0 profile, and generates entirely static files.
21
20
  #
22
21
  # @author David Newbury <david.newbury@gmail.com>
23
22
  #
24
- module IiifS3
25
-
26
-
23
+ module WaxIiif
27
24
  #--------------------------------------------------------------------------
28
25
  # CONSTANTS
29
26
  #--------------------------------------------------------------------------
30
27
 
31
-
32
28
  # @return [String] The URI of the presentation context for the IIIF V.2
33
- PRESENTATION_CONTEXT = "http://iiif.io/api/presentation/2/context.json"
29
+ PRESENTATION_CONTEXT = 'http://iiif.io/api/presentation/2/context.json'.freeze
34
30
  # @return [String] The URI of the image context for the IIIF V.2
35
- IMAGE_CONTEXT = "http://iiif.io/api/image/2/context.json"
31
+ IMAGE_CONTEXT = 'http://iiif.io/api/image/2/context.json'.freeze
36
32
  # @return [String] The URI of the image protocol for IIIF
37
- IMAGE_PROTOCOL = "http://iiif.io/api/image"
33
+ IMAGE_PROTOCOL = 'http://iiif.io/api/image'.freeze
38
34
  # @return [String] The URI of the Level 0 profile for the IIIF V.2
39
- LEVEL_0 = "http://iiif.io/api/image/2/level0.json"
35
+ LEVEL_0 = 'http://iiif.io/api/image/2/level0.json'.freeze
40
36
  # @return [String] The IIIF default type for a sequence.
41
- SEQUENCE_TYPE = "sc:Sequence"
37
+ SEQUENCE_TYPE = 'sc:Sequence'.freeze
42
38
  # @return [String] The IIIF default type for a canvas
43
- CANVAS_TYPE = "sc:Canvas"
39
+ CANVAS_TYPE = 'sc:Canvas'.freeze
44
40
  # @return [String] The IIIF default type for a annotation.
45
- ANNOTATION_TYPE = "oa:Annotation"
41
+ ANNOTATION_TYPE = 'oa:Annotation'.freeze
46
42
  # @return [String] The IIIF default type for an image.
47
- IMAGE_TYPE = "dcterms:Image"
43
+ IMAGE_TYPE = 'dcterms:Image'.freeze
48
44
  # @return [String] The default label for a canvas without a specified name.
49
- MOTIVATION = "sc:painting"
45
+ MOTIVATION = 'sc:painting'.freeze
50
46
  # @return [String] The default label for a canvas without a specified name.
51
- DEFAULT_CANVAS_LABEL = "front"
47
+ DEFAULT_CANVAS_LABEL = 'front'.freeze
52
48
  # @return [String] The default name for a sequence without a specified name.
53
- DEFAULT_SEQUENCE_NAME = "default"
49
+ DEFAULT_SEQUENCE_NAME = 'default'.freeze
54
50
  # @return [String] The default reading direction for this manifest.
55
- DEFAULT_VIEWING_DIRECTION = "left-to-right"
51
+ DEFAULT_VIEWING_DIRECTION = 'left-to-right'.freeze
56
52
  # @return [Number] The size in pixels below which the canvas will be doubled.
57
53
  MIN_CANVAS_SIZE = 1200
58
54
 
59
-
60
- #--------------------------------------------------------------------------
61
- # HELPERS
62
- #--------------------------------------------------------------------------
63
-
64
-
55
+ #--------------------------------------------------------------------------
56
+ # HELPERS
57
+ #--------------------------------------------------------------------------
65
58
 
66
59
  # Validates a viewing direction string against the IIIF V.2.0 spec.
67
60
  #
68
61
  # According to v2 of the IIIF standards, there are only four valid viewing directions:
69
- # "left-to-right", "top-to-bottom”, "bottom-to-top" , and "right-to-left". This
62
+ # 'left-to-right', 'top-to-bottom', 'bottom-to-top' , and 'right-to-left'. This
70
63
  # returns true if the provided direction is one of these, and falst for anything else.
71
64
  #
72
65
  # @param [String] direction A viewing direction string
73
66
  #
74
67
  # @return [boolean] Is the provided string a valid viewing direction?
75
68
  #
76
- def self.is_valid_viewing_direction(direction)
77
- direction == "left-to-right" ||
78
- direction == "top-to-bottom" ||
79
- direction == "bottom-to-top" ||
80
- direction == "right-to-left"
69
+ def self.valid_viewing_direction?(direction)
70
+ valid = %w[left-to-right top-to-bottom bottom-to-top right-to-left]
71
+ valid.include? direction
81
72
  end
82
-
83
73
  end
@@ -0,0 +1,90 @@
1
+ require_relative 'utilities'
2
+ module WaxIiif
3
+ # Module BaseProperties provides the set of properties that are
4
+ # shared across all IIIF types.
5
+ #
6
+ # It is not a comprehensive list (yet), but it does handle
7
+ # most of the shared types. It does not include any types
8
+ # that have class-based restrictions.
9
+ #
10
+ # It also performs some basic sanity checking on (some of) the
11
+ # fields, and provides utility classes that are applicable across
12
+ # the fields.
13
+ #
14
+ # @todo Add within, service, seeAlso, viewingHint fields
15
+ # @author David Newbury <david.newbury@gmail.com>
16
+ #
17
+ module BaseProperties
18
+ include Utilities::Helpers
19
+
20
+ # @!attribute [rw] label
21
+ # @return [String] The human-readable label for this record
22
+ attr_accessor :label
23
+ # @!attribute [r] id
24
+ # @return [String] The URI for this record
25
+ attr_reader :id
26
+ # @!attribute [rw] description
27
+ # @return [String] The long-form description of this record
28
+ attr_accessor :description
29
+ # @!attribute [rw] metadata
30
+ # @return [Hash] A set of key/value pairs describing additional metadata for the object.
31
+ attr_accessor :metadata
32
+ # @!attribute [rw] attribution
33
+ # @return [String] a human-readable label, typically used for attribution or credit.
34
+ attr_accessor :attribution
35
+ # @!attribute [rw] logo
36
+ # @return [String] The URI to an image for the logo of the institution associated with this record.
37
+ attr_accessor :logo
38
+ # @!attribute [rw] license
39
+ # @return [String] The URI to a resource that describes the license or rights statement associated.
40
+ attr_accessor :license
41
+ # @!attribute [rw] related
42
+ # @return [String, Array<String>] The URI to related resources. Can be both a string or an array
43
+ attr_accessor :related
44
+
45
+ # The type of resource provided by this record.
46
+ #
47
+ # @return [String] The type of record
48
+ def type
49
+ self.class::TYPE
50
+ end
51
+
52
+ # Set the unique id for this record.
53
+ # This will automatically append the defined prefixes and suffixes.
54
+ #
55
+ # @param [String] _id The unique portion of this ID
56
+ # @return [string] The URI for this record
57
+ def id=(the_id)
58
+ @id = generate_id(the_id)
59
+ end
60
+
61
+ # Return the base data structure for this record as a Hash
62
+ # This will be in IIIF format, and should convert to JSON as JSON-LD nicely.
63
+ #
64
+ # @return [Hash] The base properties of this record
65
+ def base_properties
66
+ obj = {
67
+ '@context' => PRESENTATION_CONTEXT,
68
+ '@id' => self.id,
69
+ '@type' => self.type,
70
+ 'label' => self.label
71
+ }
72
+ obj['attribution'] = self.attribution if self.attribution
73
+ obj['logo'] = self.logo if self.logo
74
+ obj['description'] = self.description if self.description
75
+ obj['attribution'] = self.attribution if self.attribution
76
+ obj['license'] = self.license if self.license
77
+ obj['related'] = self.related if self.related
78
+ obj['metadata'] = self.metadata if self.metadata
79
+
80
+ obj
81
+ end
82
+
83
+ # Save the JSON representation of this record to disk
84
+ #
85
+ # @return [Void]
86
+ def save
87
+ save_to_disk(JSON.parse(self.to_json))
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,252 @@
1
+ require_relative 'utilities'
2
+ require 'pathname'
3
+
4
+ module WaxIiif
5
+ # Builder class
6
+ class Builder
7
+ include Utilities::Helpers
8
+
9
+ HEADER_VAL = 'filename'.freeze
10
+
11
+ #
12
+ # @!attribute [r] data
13
+ # @return [Array<Hash>] The raw data computed for the given set of images
14
+ attr_reader :data
15
+
16
+ #
17
+ # @!attribute [r] manifests
18
+ # @return [Array<Hash>] The manifest hashes for this configuration
19
+ attr_accessor :manifests
20
+
21
+ # @!attribute [r] config
22
+ # @return [WaxIiif::Config] The configuration object
23
+ attr_reader :config
24
+
25
+ # Initialize the builder.
26
+ #
27
+ # @param [Hash] config an optional configuration object.
28
+ # @see WaxIiif::Config
29
+ # @return [Void]
30
+ #
31
+ def initialize(config = {})
32
+ @manifests = []
33
+ @config = WaxIiif::Config.new(config)
34
+ end
35
+
36
+ #
37
+ # Load data into the IIIF builder.
38
+ #
39
+ # This will load the data, perform some basic verifications on it, and sort
40
+ # it into proper order.
41
+ #
42
+ # @param [Array<ImageRecord>, ImageRecord] data
43
+ # Either a single ImageRecord or an Array of ImageRecords.
44
+ # @raise [WaxIiif::Error::InvalidImageData] if any of the data does
45
+ # not pass the validation checks
46
+ #
47
+ # @return [Void]
48
+ #
49
+ def load(data)
50
+ @data = [data].flatten # handle hashes and arrays of hashes
51
+ # validate
52
+ @data.each do |image_record|
53
+ raise WaxIiif::Error::InvalidImageData, "Image record #{image_record.inspect} is not an ImageRecord" unless image_record.is_a? ImageRecord
54
+ raise WaxIiif::Error::InvalidImageData, "Image record #{image_record.inspect} does not have an ID" if image_record.id.nil?
55
+ end
56
+ end
57
+
58
+ #
59
+ # Take the loaded data and generate all the files.
60
+ #
61
+ # @param [Boolean] force_image_generation Generate images even if they already exist
62
+ #
63
+ # @return [Void]
64
+ #
65
+ def process_data(force_image_generation = false)
66
+ return nil if @data.nil? # do nothing without data.
67
+
68
+ @manifests = []
69
+ @data.group_by(&:manifest_id).each do |key, value|
70
+ resources = {}
71
+ manifest_id = key
72
+ image_records = value
73
+
74
+ # genrate the images
75
+ image_records.each do |image_record|
76
+ # It attempts to load the info files and skip generation - not currently working.
77
+ info_file = image_info_file_name(image_record)
78
+ if File.exist?(info_file) && !force_image_generation
79
+ puts "skipping #{info_file}" if @config.verbose?
80
+ image_record.variants = load_variants(info_file)
81
+ else
82
+ image_record.variants = generate_variants(image_record, @config)
83
+ generate_tiles(image_record, @config)
84
+ generate_image_json(image_record, @config)
85
+ end
86
+ # Save the image info for the manifest
87
+ resources[image_record.id] ||= []
88
+ resources[image_record.id].push image_record
89
+ end
90
+
91
+ # Generate the manifest
92
+ if manifest_id.to_s.empty?
93
+ resources.each do |_key, val|
94
+ manifests.push generate_manifest(val, @config)
95
+ end
96
+ else
97
+ manifests.push generate_manifest(image_records, @config)
98
+ end
99
+ end
100
+
101
+ generate_collection
102
+ end
103
+
104
+ def generate_collection
105
+ collection = Collection.new(@config)
106
+ manifests.each { |m| collection.add_manifest(m) }
107
+ collection.save
108
+ end
109
+
110
+ # Creates the required directories for exporting to the file system.
111
+ #
112
+ # @return [Void]
113
+ def create_build_directories
114
+ root_dir = generate_build_location('')
115
+ Dir.mkdir root_dir unless Dir.exist?(root_dir)
116
+ img_dir = generate_image_location('').split('/')[0...-1].join('/')
117
+ Dir.mkdir img_dir unless Dir.exist?(img_dir)
118
+ end
119
+
120
+ # Load data into the IIIF server from a CSV
121
+ #
122
+ # @param [String] csv_path Path to the CSV file containing the image data
123
+ #
124
+ # @return [Void]
125
+ # @todo Fix this to use the correct data format!
126
+ #
127
+ def load_csv(csv_path)
128
+ raise Error::InvalidCSV unless File.exist? csv_path
129
+ begin
130
+ vals = CSV.read(csv_path)
131
+ rescue CSV::MalformedCSVError
132
+ raise Error::InvalidCSV
133
+ end
134
+
135
+ raise Error::BlankCSV if vals.length.zero?
136
+ raise Error::InvalidCSV if vals[0].length != 3
137
+
138
+ # remove optional header
139
+ vals.shift if vals[0][0] == HEADER_VAL
140
+
141
+ @data = vals.collect do |data|
142
+ {
143
+ 'image_path' => data[0],
144
+ 'id' => data[1],
145
+ 'label' => data[2]
146
+ }
147
+ end
148
+ end
149
+
150
+ protected
151
+
152
+ #----------------------------------------------------------------
153
+ def load_variants(path)
154
+ data = JSON.parse escape_yaml(File.read(path))
155
+ id = data['@id']
156
+ w = data['width']
157
+ h = data['height']
158
+
159
+ thumb_size = data['sizes'].find do |a|
160
+ same_width = a['width'] == config.thumbnail_size
161
+ same_height = a['height'] == config.thumbnail_size
162
+ same_width || same_height
163
+ end
164
+
165
+ thumb_w = thumb_size['width']
166
+ thumb_h = thumb_size['height']
167
+ full_url = "#{id}/full/full/0/default.jpg"
168
+ thumb_url = "#{id}/full/#{thumb_w},/0/default.jpg"
169
+ full = FakeImageVariant.new(id,
170
+ w,
171
+ h,
172
+ full_url,
173
+ 'image/jpeg')
174
+ thumbnail = FakeImageVariant.new(id,
175
+ thumb_w,
176
+ thumb_h,
177
+ thumb_url,
178
+ 'image/jpeg')
179
+
180
+ { 'full' => full, 'thumbnail' => thumbnail }
181
+ end
182
+
183
+ def generate_tiles(data, config)
184
+ width = data.variants['full'].width
185
+ tile_width = config.tile_width
186
+ height = data.variants['full'].height
187
+ tiles = []
188
+ config.tile_scale_factors.each do |s|
189
+ (0..(height * 1.0 / (tile_width * s)).floor).each do |tile_y|
190
+ (0..(width * 1.0 / (tile_width * s)).floor).each do |tile_x|
191
+ tile = {
192
+ scale_factor: s,
193
+ xpos: tile_x,
194
+ ypos: tile_y,
195
+ x: tile_x * tile_width * s,
196
+ y: tile_y * tile_width * s,
197
+ width: tile_width * s,
198
+ height: tile_width * s,
199
+ xSize: tile_width,
200
+ ySize: tile_width
201
+ }
202
+ if tile[:x] + tile[:width] > width
203
+ tile[:width] = width - tile[:x]
204
+ tile[:xSize] = (tile[:width] / (s * 1.0)).ceil
205
+ end
206
+ if tile[:y] + tile[:height] > height
207
+ tile[:height] = height - tile[:y]
208
+ tile[:ySize] = (tile[:height] / (s * 1.0)).ceil
209
+ end
210
+ tiles.push(tile)
211
+ end
212
+ end
213
+ end
214
+ tiles.each do |tile|
215
+ ImageTile.new(data, @config, tile)
216
+ end
217
+ end
218
+
219
+ def image_info_file_name(data)
220
+ "#{generate_image_location(data.id)}/info.json"
221
+ end
222
+
223
+ def generate_image_json(data, config)
224
+ filename = image_info_file_name(data)
225
+ info = ImageInfo.new(data.variants['full'].id,
226
+ data.variants,
227
+ config.tile_width,
228
+ config.tile_scale_factors)
229
+ puts "writing #{filename}" if config.verbose?
230
+ Pathname.new(Pathname.new(filename).dirname).mkpath
231
+ File.open(filename, 'w') { |file| file.puts info.to_json }
232
+ info
233
+ end
234
+
235
+ def generate_manifest(data, config)
236
+ m = Manifest.new(data, config)
237
+ m.save_all_files_to_disk
238
+ m
239
+ end
240
+
241
+ def generate_variants(data, config)
242
+ obj = {
243
+ 'full' => FullImage.new(data, config),
244
+ 'thumbnail' => Thumbnail.new(data, config)
245
+ }
246
+ config.variants.each do |key, image_size|
247
+ obj[key] = ImageVariant.new(data, config, image_size)
248
+ end
249
+ obj
250
+ end
251
+ end
252
+ end