imogen 0.0.7 → 0.0.8
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 +8 -8
- data/lib/imogen/iiif/region.rb +53 -0
- data/lib/imogen/iiif/rotation.rb +25 -0
- data/lib/imogen/iiif/size.rb +36 -0
- data/lib/imogen/iiif.rb +64 -0
- data/lib/imogen.rb +5 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/unit/imogen_iiif_region_spec.rb +53 -0
- data/spec/unit/imogen_iiif_rotate_spec.rb +37 -0
- data/spec/unit/imogen_iiif_size_spec.rb +61 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTE0MzdjYjBkMjM2YTRlMTBlYjg1NzI2YzIyOTgxOGU5YjIxZmNlOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzkzOGYxMzcyM2EzNjI2ZWJhYmJlZTA4NjAxZjgyN2MzNWNkMjVkNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2VjZjBmZGMwMTZiNjQ2MWZkYjA2MjYyZTQ2NTUyNzUyNGNhNThhNmZiMDU3
|
10
|
+
MjNhMGZlMTQ0MWI4MmVkYTE3NTYyNzNmMmNkYWNjYmFiMWVmZDZiNzZkOGNk
|
11
|
+
NzZmMDFiNjM5NjJkMDIyOThlYzcxOGEyOTJlODkyZGJhYTE2MmI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MjRmZWJkNGI0YmQwNTY4MzM4YjVjODI4ZmNiMjlkNDk1OTE2YWNlMGM0MjM1
|
14
|
+
Nzk3NTZiOTlkZDU0MDJjYjJhZDJiYjM3ZDljMDJhMmY4NDZiOTkxYjgyODM0
|
15
|
+
OTIyZDkyZDA1M2QyZTY5M2IzZjQ0MmM2NWE5OGNlYzU3NmIxMjM=
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
module Imogen
|
4
|
+
module Iiif
|
5
|
+
class Region < Transform
|
6
|
+
# returns leftX, topY, rightX, bottomY
|
7
|
+
def get(region=nil)
|
8
|
+
if region.nil? || region == 'full'
|
9
|
+
return nil
|
10
|
+
elsif md = /^pct:(\d+(\.\d+)?),(\d+(\.\d+)?),(\d+(\.\d+)?),(\d+(\.\d+)?)$/.match(region)
|
11
|
+
p = [Float(md[1]),Float(md[3]),Float(md[5]),Float(md[7])]
|
12
|
+
if p[0] == p[2] or p[1] == p[3]
|
13
|
+
raise BadRequest.new("Invalid region: #{region}")
|
14
|
+
end
|
15
|
+
e = [
|
16
|
+
max(0,(@width * p[0] / 100).round),
|
17
|
+
max(0,(@height * p[1] / 100).round),
|
18
|
+
min(@width,(@width * (p[0] + p[2]) / 100).round),
|
19
|
+
min(@height,(@height * (p[1] + p[3]) / 100).round)
|
20
|
+
]
|
21
|
+
elsif md = /^(\d+),(\d+),(\d+),(\d+)$/.match(region)
|
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]
|
24
|
+
raise BadRequest.new("Invalid region: #{region}")
|
25
|
+
end
|
26
|
+
e = [
|
27
|
+
max(0,p[0]),
|
28
|
+
max(0,p[1]),
|
29
|
+
min(@width,(p[0] + p[2])),
|
30
|
+
min(@height,(p[1] + p[3]))
|
31
|
+
]
|
32
|
+
else
|
33
|
+
raise BadRequest.new("Invalid region: #{region}")
|
34
|
+
end
|
35
|
+
if e[0] > e[2] or e[1] > e[3]
|
36
|
+
raise BadRequest.new("Invalid region: #{region}")
|
37
|
+
end
|
38
|
+
if (e[2] - e[0]) * (e[3] - e[1]) < 100
|
39
|
+
raise BadRequest.new("Region too small: #{region}")
|
40
|
+
end
|
41
|
+
return e
|
42
|
+
end
|
43
|
+
def self.convert(img, region)
|
44
|
+
edges = Region.new(img).get(region)
|
45
|
+
if edges
|
46
|
+
img.copy(*edges) {|crop| yield crop}
|
47
|
+
else
|
48
|
+
yield img
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Imogen
|
2
|
+
module Iiif
|
3
|
+
class Rotation < Transform
|
4
|
+
RIGHT_ANGLES = [0,90,180,270]
|
5
|
+
def get(rotate)
|
6
|
+
if rotate.nil? or rotate.eql? '0'
|
7
|
+
return nil
|
8
|
+
end
|
9
|
+
raise BadRequest.new("bad rotate #{rotate}") unless rotate =~ /^-?\d+$/
|
10
|
+
r = rotate.to_i % 360
|
11
|
+
r = r + 360 if r < 0
|
12
|
+
raise BadRequest.new("bad rotate #{rotate}") unless RIGHT_ANGLES.include? r
|
13
|
+
return r > 0 ? r : nil
|
14
|
+
end
|
15
|
+
def self.convert(img, rotate)
|
16
|
+
rotation = Rotation.new(img).get(rotate)
|
17
|
+
if rotation
|
18
|
+
img.rotate(rotation) {|crop| yield crop}
|
19
|
+
else
|
20
|
+
yield img
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Imogen
|
2
|
+
module Iiif
|
3
|
+
class Size < Transform
|
4
|
+
def get(scale=nil)
|
5
|
+
if scale.nil? or scale.eql? "0"
|
6
|
+
return nil
|
7
|
+
end
|
8
|
+
if md = /^(\d+)?,(\d+)?$/.match(scale)
|
9
|
+
w = md[1] ? min(Integer(md[1]), @width) : nil
|
10
|
+
h = md[2] ? min(Integer(md[2]), @height) : nil
|
11
|
+
raise BadRequest.new("bad scale #{scale}") unless w or h
|
12
|
+
w ||= (@width * (h.to_f / @height)).round
|
13
|
+
h ||= (@height * (w.to_f / @width)).round
|
14
|
+
e = [w,h]
|
15
|
+
elsif md = /^pct:(\d+(\.\d+)?)/.match(scale)
|
16
|
+
p = Float(md[1])
|
17
|
+
p = min(100,p).to_f
|
18
|
+
raise BadRequest.new("bad size #{scale}") if p <= 0
|
19
|
+
e = [(@width * p / 100).round, (@height * p / 100).round]
|
20
|
+
else
|
21
|
+
raise BadRequest.new("bad size #{scale}")
|
22
|
+
end
|
23
|
+
raise BadRequest.new("bad size #{scale}") if e[0] <= 0 or e[1] <= 0
|
24
|
+
return e
|
25
|
+
end
|
26
|
+
def self.convert(img, size)
|
27
|
+
dims = Size.new(img).get(size)
|
28
|
+
if dims
|
29
|
+
img.rescale(*dims) {|crop| yield crop}
|
30
|
+
else
|
31
|
+
yield img
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/imogen/iiif.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Imogen
|
2
|
+
module Iiif
|
3
|
+
class BadRequest < Exception; end
|
4
|
+
class Transform
|
5
|
+
def initialize(src)
|
6
|
+
@width = 0
|
7
|
+
@height = 0
|
8
|
+
if src.respond_to? :width and src.respond_to? :height
|
9
|
+
img = src
|
10
|
+
@width = src.width
|
11
|
+
@height = src.height
|
12
|
+
else
|
13
|
+
raise "#{src.class.name} does not report width and height"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def max(x,y)
|
17
|
+
(x > y) ? x : y
|
18
|
+
end
|
19
|
+
def min(x,y)
|
20
|
+
(x < y) ? x : y
|
21
|
+
end
|
22
|
+
end
|
23
|
+
module Quality
|
24
|
+
VALUES = [:native, :color, :grey, :bitonal]
|
25
|
+
def self.get(quality=:native)
|
26
|
+
q = quality.to_sym
|
27
|
+
raise BadRequest.new("bad quality #{quality}") unless VALUES.include? q
|
28
|
+
return (q == :native or q == :color) ? nil : q
|
29
|
+
end
|
30
|
+
def self.convert(img, quality)
|
31
|
+
q = get(quality)
|
32
|
+
if q == :grey
|
33
|
+
img.convert_to_greyscale {|c| yield c}
|
34
|
+
elsif q == :bitonal
|
35
|
+
img.threshold(128) {|c| yield c}
|
36
|
+
else
|
37
|
+
yield img
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
autoload :Region, 'imogen/iiif/region'
|
42
|
+
autoload :Size, 'imogen/iiif/size'
|
43
|
+
autoload :Rotation, 'imogen/iiif/rotation'
|
44
|
+
|
45
|
+
FORMATS = [:jpeg, :png]
|
46
|
+
def self.convert(img, dest_path, format=:jpeg, opts={})
|
47
|
+
raise BadRequest.new("bad format #{format}") unless FORMATS.include? format
|
48
|
+
Region.convert(img, opts[:region]) do |region|
|
49
|
+
Size.convert(region, opts[:size]) do |size|
|
50
|
+
Rotation.convert(size, opts[:rotation]) do |rotation|
|
51
|
+
Quality.convert(rotation, opts[:quality]) do |quality|
|
52
|
+
dst = FreeImage::File.new(dest_path)
|
53
|
+
if (img.color_type == :rgb)
|
54
|
+
quality.convert_to_24bits {|result| dst.save(result, format)}
|
55
|
+
else
|
56
|
+
quality.convert_to_8bits {|result| dst.save(result, format)}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/imogen.rb
CHANGED
@@ -22,8 +22,13 @@ module Imogen
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
|
+
module Cropped
|
26
|
+
def self.convert(img, dest_path, edges, scale=nil, format=:jpeg)
|
27
|
+
end
|
28
|
+
end
|
25
29
|
require 'imogen/auto_crop'
|
26
30
|
require 'imogen/zoomable'
|
31
|
+
require 'imogen/iiif'
|
27
32
|
|
28
33
|
def self.search_paths
|
29
34
|
@search_paths ||= begin
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'imogen/iiif'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
describe Imogen::Iiif::Region, type: :unit do
|
4
|
+
before(:all) do
|
5
|
+
@test_image = ImageStub.new(175,131)
|
6
|
+
end
|
7
|
+
subject {Imogen::Iiif::Region.new(@test_image)}
|
8
|
+
describe "#get" do
|
9
|
+
describe "with default or full region" do
|
10
|
+
it "should return nil" do
|
11
|
+
expect(subject.get(nil)).to be_nil
|
12
|
+
expect(subject.get("full")).to be_nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
describe "with an absolute region" do
|
16
|
+
it "should calculate a contained region" do
|
17
|
+
expect(subject.get("80,15,60,75")).to eql([80,15,140,90])
|
18
|
+
end
|
19
|
+
it "should reject zero-dimension boxes" do
|
20
|
+
expect{subject.get("101,15,10,15")}.to raise_error Imogen::Iiif::BadRequest
|
21
|
+
end
|
22
|
+
describe "that exceeds the bounds" do
|
23
|
+
it "should calculate an overlapping region" do
|
24
|
+
expect(subject.get("80,15,100,175")).to eql([80,15,175,131])
|
25
|
+
end
|
26
|
+
it "should reject a disjoint region" do
|
27
|
+
expect{subject.get("176,15,1,75")}.to raise_error Imogen::Iiif::BadRequest
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
describe "with a percentage region" do
|
32
|
+
it "should calculate a contained region" do
|
33
|
+
expect(subject.get("pct:80,15,10,75")).to eql([140,20,158,118])
|
34
|
+
end
|
35
|
+
it "should reject zero-dimension boxes" do
|
36
|
+
expect{subject.get("pct:10.2,15,10.21,15")}.to raise_error Imogen::Iiif::BadRequest
|
37
|
+
end
|
38
|
+
describe "that exceeds the bounds" do
|
39
|
+
it "should calculate an overlapping region" do
|
40
|
+
expect(subject.get("pct:80,15,100,175")).to eql([140,20,175,131])
|
41
|
+
end
|
42
|
+
it "should reject a disjoint region" do
|
43
|
+
expect{subject.get("pct:101,15,100,15")}.to raise_error Imogen::Iiif::BadRequest
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
it "should reject non-conforming regions" do
|
48
|
+
expect{subject.get("px:1,2,3,4")}.to raise_error Imogen::Iiif::BadRequest
|
49
|
+
expect{subject.get("-1,2,3,4")}.to raise_error Imogen::Iiif::BadRequest
|
50
|
+
expect{subject.get("pct:-1,2,3,4")}.to raise_error Imogen::Iiif::BadRequest
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'imogen/iiif'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
describe Imogen::Iiif::Rotation, type: :unit do
|
4
|
+
before(:all) do
|
5
|
+
@test_image = ImageStub.new(175,131)
|
6
|
+
end
|
7
|
+
subject {Imogen::Iiif::Rotation.new(@test_image)}
|
8
|
+
describe "#get" do
|
9
|
+
describe "with values mod 360 in 90 degree rotations" do
|
10
|
+
it "should nil for 0 or nil" do
|
11
|
+
expect(subject.get("360")).to be_nil
|
12
|
+
expect(subject.get("-360")).to be_nil
|
13
|
+
expect(subject.get("0")).to be_nil
|
14
|
+
expect(subject.get(nil)).to be_nil
|
15
|
+
end
|
16
|
+
it "should calculate for positive values" do
|
17
|
+
expect(subject.get("90")).to eql(90)
|
18
|
+
expect(subject.get("180")).to eql(180)
|
19
|
+
expect(subject.get("270")).to eql(270)
|
20
|
+
expect(subject.get("450")).to eql(90)
|
21
|
+
end
|
22
|
+
it "should calculate for negative values" do
|
23
|
+
expect(subject.get("-90")).to eql(270)
|
24
|
+
expect(subject.get("-180")).to eql(180)
|
25
|
+
expect(subject.get("-270")).to eql(90)
|
26
|
+
expect(subject.get("-450")).to eql(270)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
it "should reject arbitrary integer and float values" do
|
30
|
+
expect{subject.get("2")}.to raise_error Imogen::Iiif::BadRequest
|
31
|
+
expect{subject.get("90.0")}.to raise_error Imogen::Iiif::BadRequest
|
32
|
+
end
|
33
|
+
it "should reject bad values" do
|
34
|
+
expect{subject.get("-2,")}.to raise_error Imogen::Iiif::BadRequest
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'imogen/iiif'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
describe Imogen::Iiif::Size, type: :unit do
|
4
|
+
before(:all) do
|
5
|
+
@test_image = ImageStub.new(175,131)
|
6
|
+
end
|
7
|
+
subject {Imogen::Iiif::Size.new(@test_image)}
|
8
|
+
describe "#get" do
|
9
|
+
describe "with scaling width" do
|
10
|
+
it "should calculate for a good value" do
|
11
|
+
expect(subject.get("105,")).to eql([105, 79])
|
12
|
+
end
|
13
|
+
it "should not upscale" do
|
14
|
+
expect(subject.get("350,")).to eql([175, 131])
|
15
|
+
end
|
16
|
+
it "should reject bad values" do
|
17
|
+
expect{subject.get("0,")}.to raise_error Imogen::Iiif::BadRequest
|
18
|
+
expect{subject.get("-2,")}.to raise_error Imogen::Iiif::BadRequest
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe "with scaling height" do
|
22
|
+
it "should calculate for a good value" do
|
23
|
+
# partial pixels get rounded up
|
24
|
+
expect(subject.get(",79")).to eql([106,79])
|
25
|
+
end
|
26
|
+
it "should not upscale" do
|
27
|
+
expect(subject.get(",262")).to eql([175, 131])
|
28
|
+
end
|
29
|
+
it "should reject bad values" do
|
30
|
+
expect{subject.get(",0")}.to raise_error Imogen::Iiif::BadRequest
|
31
|
+
expect{subject.get(",-2")}.to raise_error Imogen::Iiif::BadRequest
|
32
|
+
end
|
33
|
+
end
|
34
|
+
describe "with scaling width and height" do
|
35
|
+
it "should calculate for a good value" do
|
36
|
+
expect(subject.get("105,79")).to eql([105, 79])
|
37
|
+
end
|
38
|
+
it "should not upscale" do
|
39
|
+
expect(subject.get("350,262")).to eql([175, 131])
|
40
|
+
end
|
41
|
+
it "should reject bad values" do
|
42
|
+
expect{subject.get("350,0")}.to raise_error Imogen::Iiif::BadRequest
|
43
|
+
expect{subject.get("350,-2")}.to raise_error Imogen::Iiif::BadRequest
|
44
|
+
expect{subject.get("0,262")}.to raise_error Imogen::Iiif::BadRequest
|
45
|
+
expect{subject.get("0,262")}.to raise_error Imogen::Iiif::BadRequest
|
46
|
+
end
|
47
|
+
end
|
48
|
+
describe "with a percentage scale" do
|
49
|
+
it "should calculate for a good value" do
|
50
|
+
expect(subject.get("pct:60.0")).to eql([105, 79])
|
51
|
+
end
|
52
|
+
it "should not upscale" do
|
53
|
+
expect(subject.get("pct:105")).to eql([175, 131])
|
54
|
+
end
|
55
|
+
it "should reject bad values" do
|
56
|
+
expect{subject.get("pct:-20")}.to raise_error Imogen::Iiif::BadRequest
|
57
|
+
expect{subject.get("pct:0")}.to raise_error Imogen::Iiif::BadRequest
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imogen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
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-
|
11
|
+
date: 2014-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-opencv
|
@@ -48,7 +48,15 @@ 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/iiif.rb
|
52
|
+
- lib/imogen/iiif/region.rb
|
53
|
+
- lib/imogen/iiif/rotation.rb
|
54
|
+
- lib/imogen/iiif/size.rb
|
51
55
|
- lib/imogen/zoomable.rb
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- spec/unit/imogen_iiif_region_spec.rb
|
58
|
+
- spec/unit/imogen_iiif_rotate_spec.rb
|
59
|
+
- spec/unit/imogen_iiif_size_spec.rb
|
52
60
|
homepage: https://github.com/cul/imogen
|
53
61
|
licenses: []
|
54
62
|
metadata: {}
|