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 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: {}