imogen 0.0.9 → 0.1.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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 09da39417c3f3659074517ded3cd333389d73294
4
- data.tar.gz: cf43db1635b701bf618aff5ea605b091aca53f01
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjdlYmVmMjIwZmFhMzNmYTdmMjNiOTFiYjM2ZjNmZTllMjYyZTRmMw==
5
+ data.tar.gz: !binary |-
6
+ YjU0NmU3NDdkZTE3YWI0NTdlMDUyMzhhYjk0OTI0ODI1YjIyYzAyYg==
5
7
  SHA512:
6
- metadata.gz: b792def58819afc01ba45716a2585ab967bbf622954167a1a46b39f1e899ad91b2ee1dfd257601db0fe5ffe1b5fe0b69014f6df5d9e8af099ed89600bdf1f9b4
7
- data.tar.gz: 9a7e6156211bf6fc74829bc0ab1f9fe040cce95a335d621eef3d39e39730aa90d4d4bc8897cdc37c86bf9bfc36df82c199c6ac22c06f38cdf5f7815086aace34
8
+ metadata.gz: !binary |-
9
+ MWQ1ODU2NTE3OWRlN2MwZTNlOWYzYjQ0NmI0ZDhmNTBjZmMzMDdmZWYwNmMy
10
+ NDAwNzU4Y2RhMTE0MjBlYWIxMzg3ZGQxZWU0Yjc2MjU3ZjBhYzY5NjE2NGY4
11
+ YTAxNjAzZTBkZGNlZTYwYzZiM2Y0NzFlOWIxNTliOTYzZmEzN2Y=
12
+ data.tar.gz: !binary |-
13
+ ZWE1ZjZiOGNjYzE3OWJlZjA5YWRlMWRlMDQzOWE2NTAxMzVmYjAzYmQ3M2Nm
14
+ NjVlZjY2NmY2YmE3NWU3MzE2NmQ2ZjhkNjYwMzY2ODA3MWQ3MzRkNTY5Mjg4
15
+ MDJjZDIxMzcyZjVmZTgwNDZiMTJiZjJhOTMzYjQ1MmU5YmRiNzY=
data/lib/imogen/dzi.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'imogen/zoomable'
2
+ require 'imogen/iiif'
3
+ module Imogen
4
+ module Dzi
5
+ def self.convert(img,dest_dir,format=:jpeg,opts={})
6
+ override = opts[:override]
7
+
8
+ end
9
+ def self.iiif_paths(img,tile_size=128,format=:jpeg)
10
+ width, height = img.width, img.height
11
+ max_levels = Imogen::Zoomable.max_levels_for(width, height)
12
+ results = {}
13
+ max_levels.downto(0) do |level|
14
+ c_ratio = 2**(max_levels-level)
15
+
16
+ tile_side = tile_size*c_ratio
17
+ x, col = 0, 0
18
+ while x < width
19
+ y, row = 0, 0
20
+ while y < height
21
+ results["#{level}/#{col_count}_#{row_count}"] = iiif_path_for_dzi(level,max_levels,col,row,tile_size,format)
22
+ y += tile_side
23
+ row += 1
24
+ end
25
+ x += tile_side
26
+ col += 1
27
+ end
28
+
29
+ end
30
+ end
31
+ def self.iiif_opts_for_dzi(level,max_levels,col,row,tile_size=128,format=:jpeg)
32
+ level = level.to_i
33
+ max_levels = max_levels.to_i
34
+ c_ratio = 2**(max_levels-level)
35
+
36
+ tile_side = tile_size*c_ratio
37
+ x = col * c_ratio
38
+ y = row * c_ratio
39
+ {
40
+ region: "#{x},#{y},#{tile_side},#{tile_side}",
41
+ size: "!#{tile_size},#{tile_size}",
42
+ format: format,
43
+ rotation: 0,
44
+ quality: :native
45
+ }
46
+ end
47
+ def self.iiif_path_for_dzi(level,max_levels,col,row,tile_size=512,format=:jpeg)
48
+ opts = iiif_opts_for_dzi(level, max_levels,col,row,tile_size,format)
49
+ "#{opts[:region]}/#{opts[:size]}/#{opts[:rotation]}/#{opts[:quality]}.#{Imogen::Iiif::FORMATS[format]}"
50
+ end
51
+ end
52
+ end
@@ -20,7 +20,7 @@ class Region < Transform
20
20
  ]
21
21
  elsif md = /^(\d+),(\d+),(\d+),(\d+)$/.match(region)
22
22
  p = [Integer(md[1]),Integer(md[2]),Integer(md[3]),Integer(md[4])]
23
- if p[0] == p[2] or p[1] == p[3]
23
+ if p[2] == 0 or p[3] == 0
24
24
  raise BadRequest.new("Invalid region: #{region}")
25
25
  end
26
26
  e = [
@@ -2,7 +2,7 @@ module Imogen
2
2
  module Iiif
3
3
  class Size < Transform
4
4
  def get(scale=nil)
5
- if scale.nil? or scale.eql? "0"
5
+ if scale.nil? or scale.eql? "full"
6
6
  return nil
7
7
  end
8
8
  if md = /^(\d+)?,(\d+)?$/.match(scale)
@@ -0,0 +1,38 @@
1
+ require 'imogen/zoomable'
2
+ module Imogen
3
+ module Iiif
4
+ module Tiles
5
+ def self.scale_factor_for(*dims)
6
+ Imogen::Zoomable.levels_for(*dims)**2
7
+ end
8
+ def self.for(img,dest_dir,format=:jpeg,tile_size=128,override=false)
9
+ width, height = img.width, img.height
10
+ max_level = Imogen::Zoomable.levels_for(width,height,tile_size)
11
+ max_level.downto(0) do |level|
12
+ scale = 0.5**level
13
+ level_width = (img.width*scale).ceil
14
+ level_width = (img.height*scale).ceil
15
+ region_size = (tile_size / scale).ceil
16
+ region_width = (scale * img.width).ceil
17
+ region_height = (scale * img.height).ceil
18
+ x, col = 0, 0
19
+ while x < width
20
+ y, row = 0, 0
21
+ while y < height
22
+ region = "#{x},#{y},#{[width-x,region_size].min},#{[height-y,region_size].min}"
23
+ size = "full"
24
+ dest_path = File.join(dest_dir,region,size,'0',"native.#{Imogen::Iiif::FORMATS[format]}")
25
+ unless File.exists? dest_path or override
26
+ yield(img,dest_path,format,Imogen::Iiif.path_to_opts(dest_path,dest_dir))
27
+ end
28
+ y += region_size
29
+ row += 1
30
+ end
31
+ x += region_size
32
+ col += 1
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/imogen/iiif.rb CHANGED
@@ -23,7 +23,7 @@ module Imogen
23
23
  module Quality
24
24
  VALUES = [:native, :color, :grey, :bitonal]
25
25
  def self.get(quality=:native)
26
- q = quality.to_sym
26
+ q = (quality || :native).to_sym
27
27
  raise BadRequest.new("bad quality #{quality}") unless VALUES.include? q
28
28
  return (q == :native or q == :color) ? nil : q
29
29
  end
@@ -41,15 +41,20 @@ module Imogen
41
41
  autoload :Region, 'imogen/iiif/region'
42
42
  autoload :Size, 'imogen/iiif/size'
43
43
  autoload :Rotation, 'imogen/iiif/rotation'
44
+ autoload :Tiles, 'imogen/iiif/tiles'
44
45
 
45
- FORMATS = [:jpeg, :png]
46
- def self.convert(img, dest_path, format=:jpeg, opts={})
46
+ FORMATS = {jpeg: 'jpg', jpg: 'jpg', png: 'png'}
47
+ EXTENSIONS = {'jpg' => :jpeg, 'png' => :png}
48
+ def self.convert(img, dest_path, format=nil, opts={})
49
+ format ||= opts.fetch(:format,:jpeg)
50
+ format = format.to_sym
47
51
  raise BadRequest.new("bad format #{format}") unless FORMATS.include? format
48
52
  Region.convert(img, opts[:region]) do |region|
49
53
  Size.convert(region, opts[:size]) do |size|
50
54
  Rotation.convert(size, opts[:rotation]) do |rotation|
51
55
  Quality.convert(rotation, opts[:quality]) do |quality|
52
56
  dst = FreeImage::File.new(dest_path)
57
+ format = :jpeg if format == :jpg
53
58
  if (img.color_type == :rgb)
54
59
  quality.convert_to_24bits {|result| dst.save(result, format)}
55
60
  else
@@ -60,5 +65,21 @@ module Imogen
60
65
  end
61
66
  end
62
67
  end
68
+ def self.path_to_opts(path,parent_dir)
69
+ if parent_dir and path.start_with? parent_dir
70
+ path = path.sub(parent_dir,'')
71
+ end
72
+ path = path[1..-1] if path =~ /^\//
73
+ parts = path.split('/')
74
+ quality = parts[-1].split('.')[0].to_sym
75
+ format = EXTENSIONS[parts[-1].split('.')[1]]
76
+ {
77
+ region: parts[0],
78
+ size: parts[1],
79
+ rotation: parts[2],
80
+ quality: quality,
81
+ format: format
82
+ }
83
+ end
63
84
  end
64
85
  end
@@ -1,10 +1,15 @@
1
1
  module Imogen
2
2
  module Zoomable
3
+ # levels for hypothetical 1x1 tiles
4
+ def self.max_levels_for(*dims)
5
+ return Math.log2(dims[0..1].max).ceil
6
+ end
7
+ # levels for width,height, tile_size=128
3
8
  def self.levels_for(*dims)
4
9
  max = dims[0..1].max || 0
5
- return 0 if max < 192
6
- max_tiles = (max.to_f / 96)
7
- Math.log2(max_tiles).floor
10
+ return 0 if max == 0
11
+ tile_size = dims[2] || 128
12
+ return Math.log2(dims[0..1].max.to_f / tile_size).ceil
8
13
  end
9
14
  def self.convert(img, dest_path)
10
15
  dst = FreeImage::File.new(dest_path)
data/lib/imogen.rb CHANGED
@@ -85,9 +85,7 @@ module Imogen
85
85
  result
86
86
  end
87
87
 
88
- def self.image(src_path)
89
-
90
- flags = 0
88
+ def self.image(src_path, flags=0)
91
89
 
92
90
  fif = format_from(src_path)
93
91
  if ((fif != :unknown) and FreeImage.FreeImage_FIFSupportsReading(fif))
@@ -97,9 +95,7 @@ module Imogen
97
95
  end
98
96
  return nil
99
97
  end
100
- def self.with_image(src_path, &block)
101
-
102
- flags = 0
98
+ def self.with_image(src_path, flags = 0, &block)
103
99
 
104
100
  fif = format_from(src_path)
105
101
  if ((fif != :unknown) and FreeImage.FreeImage_FIFSupportsReading(fif))
@@ -17,7 +17,8 @@ describe Imogen::Iiif::Region, type: :unit do
17
17
  expect(subject.get("80,15,60,75")).to eql([80,15,140,90])
18
18
  end
19
19
  it "should reject zero-dimension boxes" do
20
- expect{subject.get("101,15,10,15")}.to raise_error Imogen::Iiif::BadRequest
20
+ expect{subject.get("101,15,0,15")}.to raise_error Imogen::Iiif::BadRequest
21
+ expect{subject.get("101,15,10,0")}.to raise_error Imogen::Iiif::BadRequest
21
22
  end
22
23
  describe "that exceeds the bounds" do
23
24
  it "should calculate an overlapping region" do
@@ -13,17 +13,19 @@ describe Imogen::Iiif::Rotation, type: :unit do
13
13
  expect(subject.get("0")).to be_nil
14
14
  expect(subject.get(nil)).to be_nil
15
15
  end
16
+ # IIIF rotation is opposite FreeImage
16
17
  it "should calculate for positive values" do
17
- expect(subject.get("90")).to eql(90)
18
+ expect(subject.get("90")).to eql(270)
18
19
  expect(subject.get("180")).to eql(180)
19
- expect(subject.get("270")).to eql(270)
20
- expect(subject.get("450")).to eql(90)
20
+ expect(subject.get("270")).to eql(90)
21
+ expect(subject.get("450")).to eql(270)
21
22
  end
23
+ # IIIF rotation is opposite FreeImage
22
24
  it "should calculate for negative values" do
23
- expect(subject.get("-90")).to eql(270)
25
+ expect(subject.get("-90")).to eql(90)
24
26
  expect(subject.get("-180")).to eql(180)
25
- expect(subject.get("-270")).to eql(90)
26
- expect(subject.get("-450")).to eql(270)
27
+ expect(subject.get("-270")).to eql(270)
28
+ expect(subject.get("-450")).to eql(90)
27
29
  end
28
30
  end
29
31
  it "should reject arbitrary integer and float values" do
@@ -0,0 +1,78 @@
1
+ require 'imogen/iiif'
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ describe Imogen::Iiif::Tiles, type: :unit do
4
+ before(:all) do
5
+ @test_image = ImageStub.new(175,131)
6
+ end
7
+ let(:fullSize) { ["/0,0,175,131/full/0/native.jpg"]}
8
+ let(:tile128) {
9
+ [
10
+ "/0,0,128,128/full/0/native.jpg",
11
+ "/128,0,47,128/full/0/native.jpg",
12
+ "/0,128,128,3/full/0/native.jpg",
13
+ "/128,128,47,3/full/0/native.jpg"
14
+ ]
15
+ }
16
+ let(:tile64) {
17
+ [
18
+ "/0,0,64,64/full/0/native.jpg",
19
+ "/64,0,64,64/full/0/native.jpg",
20
+ "/128,0,47,64/full/0/native.jpg",
21
+ "/0,64,64,64/full/0/native.jpg",
22
+ "/64,64,64,64/full/0/native.jpg",
23
+ "/128,64,47,64/full/0/native.jpg",
24
+ "/0,128,64,3/full/0/native.jpg",
25
+ "/64,128,64,3/full/0/native.jpg",
26
+ "/128,128,47,3/full/0/native.jpg",
27
+ ]
28
+ }
29
+ describe '#scale_factor_for' do
30
+ it 'should calculate for different tile sizes' do
31
+ width, height = @test_image.width, @test_image.height
32
+ (0..8).each do |exp|
33
+ tile_size = 2**exp
34
+ expected = (8 - exp)**2
35
+ expect(subject.scale_factor_for(width, height, tile_size)).to eql(expected)
36
+ end
37
+ end
38
+ end
39
+ describe '#for' do
40
+ it 'should produce a single tile when contained' do
41
+ expected = fullSize
42
+ actual = []
43
+ subject.for(@test_image,'',:jpeg,256) do |img,dest_path,format,opts|
44
+ actual << dest_path
45
+ end
46
+ expect(actual).to eql(expected)
47
+ end
48
+ it 'should produce a tileset when half' do
49
+ expected = fullSize + tile128
50
+ expected.uniq!
51
+ actual = []
52
+ subject.for(@test_image,'',:jpeg,128) do |img,dest_path,format,opts|
53
+ actual << dest_path
54
+ end
55
+ actual.uniq!
56
+ expect(actual.sort).to eql(expected.sort)
57
+ end
58
+ it 'should produce a single tileset' do
59
+ expected = fullSize + tile128 + tile64
60
+ expected.uniq!
61
+ actual = []
62
+ subject.for(@test_image,'',:jpeg,64) do |img,dest_path,format,opts|
63
+ actual << dest_path
64
+ end
65
+ actual.uniq!
66
+ expect(actual.sort).to eql(expected.sort)
67
+ end
68
+ it 'should produce png when requested' do
69
+ expected = fullSize.collect {|x| x.sub(/jpg$/,'png')}
70
+ expected.uniq!
71
+ actual = []
72
+ subject.for(@test_image,'',:png,256) do |img,dest_path,format,opts|
73
+ actual << dest_path
74
+ end
75
+ expect(actual).to eql(expected)
76
+ end
77
+ end
78
+ end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imogen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Armintor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-19 00:00:00.000000000 Z
11
+ date: 2014-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-opencv
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - ! '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - ! '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - ! '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description:
@@ -48,15 +48,18 @@ files:
48
48
  - lib/imogen/auto_crop.rb
49
49
  - lib/imogen/auto_crop/box.rb
50
50
  - lib/imogen/auto_crop/edges.rb
51
+ - lib/imogen/dzi.rb
51
52
  - lib/imogen/iiif.rb
52
53
  - lib/imogen/iiif/region.rb
53
54
  - lib/imogen/iiif/rotation.rb
54
55
  - lib/imogen/iiif/size.rb
56
+ - lib/imogen/iiif/tiles.rb
55
57
  - lib/imogen/zoomable.rb
56
58
  - spec/spec_helper.rb
57
59
  - spec/unit/imogen_iiif_region_spec.rb
58
60
  - spec/unit/imogen_iiif_rotate_spec.rb
59
61
  - spec/unit/imogen_iiif_size_spec.rb
62
+ - spec/unit/imogen_iiif_tiles_spec.rb
60
63
  homepage: https://github.com/cul/imogen
61
64
  licenses: []
62
65
  metadata: {}
@@ -66,12 +69,12 @@ require_paths:
66
69
  - lib
67
70
  required_ruby_version: !ruby/object:Gem::Requirement
68
71
  requirements:
69
- - - ">="
72
+ - - ! '>='
70
73
  - !ruby/object:Gem::Version
71
74
  version: '0'
72
75
  required_rubygems_version: !ruby/object:Gem::Requirement
73
76
  requirements:
74
- - - ">="
77
+ - - ! '>='
75
78
  - !ruby/object:Gem::Version
76
79
  version: '0'
77
80
  requirements: []