imogen 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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: {}
|