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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTNlYjI5NTE1YzU0ZDIzNTQ2ODBkZGFlMGZiODhkYzQyZjg5ZDlmMg==
4
+ MTE0MzdjYjBkMjM2YTRlMTBlYjg1NzI2YzIyOTgxOGU5YjIxZmNlOA==
5
5
  data.tar.gz: !binary |-
6
- NDU2ZmNiZDc3YTkwZDQ5NTQ2ZDE4Zjc1MTQ0MjdlMTg3NmQyODYwZA==
6
+ MzkzOGYxMzcyM2EzNjI2ZWJhYmJlZTA4NjAxZjgyN2MzNWNkMjVkNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NmYwOGVhMDlhMzdkZGE0NjZkOWQzOGZjNThkZDI1ZTFjZTg5MTU0NGIwNzY4
10
- ZmRhMjgzMTQ2MjgyMTY0OTQxMGE3OTdmYjllYzRiOTk0ZDkwNmI0MTQzOWNk
11
- MWQ5YmNmZDAyZWUxMjc1OTAxNzY4NGY5OTgwYmM3MDA2ODk0NzI=
9
+ Y2VjZjBmZGMwMTZiNjQ2MWZkYjA2MjYyZTQ2NTUyNzUyNGNhNThhNmZiMDU3
10
+ MjNhMGZlMTQ0MWI4MmVkYTE3NTYyNzNmMmNkYWNjYmFiMWVmZDZiNzZkOGNk
11
+ NzZmMDFiNjM5NjJkMDIyOThlYzcxOGEyOTJlODkyZGJhYTE2MmI=
12
12
  data.tar.gz: !binary |-
13
- YmZhYTJlNDE2ZTQxNWY3YTNjMTY0NTJiNmM5ZGJlZDIyNWI0ZDU2NmQ1YzQ1
14
- YjBlMTAyMDQ5ZTRhZTg1YjBmNDUzOTQ3MzRkMDY3MGM0MzcyMTc2MmFhNWNi
15
- MjgwYWU4ZTM0MjVkNjZhMTkzMTY2ZDRjMGNkNzhhNTkyMWE3MmE=
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
@@ -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
@@ -0,0 +1,7 @@
1
+ class ImageStub
2
+ attr_reader :width, :height
3
+ def initialize(width,height)
4
+ @width = width
5
+ @height = height
6
+ end
7
+ end
@@ -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.7
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-09-16 00:00:00.000000000 Z
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: {}