washi 0.1.0 → 0.1.1
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 +4 -4
- data/lib/washi.rb +1 -10
- data/lib/washi/config.rb +15 -0
- data/lib/washi/mini_dzt/file_storage.rb +28 -0
- data/lib/washi/mini_dzt/s3_storage.rb +61 -0
- data/lib/washi/mini_dzt/tiler.rb +99 -0
- data/lib/washi/tiler.rb +12 -0
- data/lib/washi/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a438f0fc570d286f3aa0e810ef7a09f36effcd67
|
4
|
+
data.tar.gz: 7e1a88bcbbbd0ba9e9c9f8076a287a33773559ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a34e96479d6b6b75898d0bc968da6cefea0cb48a864bf023a28f8ed2632bdd13d9f67a7ff2c47876eb7b293df735e37dbd78af477582b062b4d1b2cb1d12096e
|
7
|
+
data.tar.gz: 69474be1aacde8a0111404c0744338aa8ab17a3df86aa87c2171e515c8990ba2e245d412efa572e3668a298077732053a9a85ab855a311105b3413470b8026f3
|
data/lib/washi.rb
CHANGED
@@ -1,10 +1 @@
|
|
1
|
-
|
2
|
-
class Tiler
|
3
|
-
def self.call(input_path, output_path, options={})
|
4
|
-
unless tile_size = options[:tile_size]
|
5
|
-
fail "Need pass :tile_size"
|
6
|
-
end
|
7
|
-
`vips dzsave #{input_path} #{output_path} --tile-size #{tile_size} --overlap 0 --vips-progress --vips-leak`
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
1
|
+
require 'washi/tiler'
|
data/lib/washi/config.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Washil
|
2
|
+
@@config = Class.new {
|
3
|
+
attr_accessor :overlap, :binapath, :options
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@overlap = 0
|
7
|
+
@binapath = 'vips dzsave'
|
8
|
+
@options = %w|--vips-progress --vips-leak|
|
9
|
+
end
|
10
|
+
}.new
|
11
|
+
|
12
|
+
def self.config
|
13
|
+
@@config
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module DZT
|
2
|
+
class FileStorage
|
3
|
+
#
|
4
|
+
# @param destination: Full directory in which to output tiles, defaults to 'tiles' in the current dir.
|
5
|
+
#
|
6
|
+
def initialize(options = {})
|
7
|
+
@store_path = options[:destination] || File.join(Dir.pwd, 'tiles')
|
8
|
+
end
|
9
|
+
|
10
|
+
def exists?
|
11
|
+
File.directory?(@store_path) && !Dir['@{@store_path}/*'].empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def storage_location(level)
|
15
|
+
File.join(@store_path, level.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def mkdir(path)
|
19
|
+
FileUtils.mkdir_p(path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(file, dest, options = {})
|
23
|
+
quality = options[:quality]
|
24
|
+
file.quality quality
|
25
|
+
file.write(dest)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module DZT
|
2
|
+
class S3Storage
|
3
|
+
DEFAULT_ACL = 'public-read'
|
4
|
+
DEFAULT_KEY = ''
|
5
|
+
#
|
6
|
+
# @param s3_acl: ACL to use for storing, defaults to 'public-read'.
|
7
|
+
# @param s3_bucket: Bucket to store tiles.
|
8
|
+
# @param s3_key: Key to prefix stored files.
|
9
|
+
# @param aws_id: AWS Id.
|
10
|
+
# @param aws_secret: AWS Secret.
|
11
|
+
#
|
12
|
+
def initialize(options = {})
|
13
|
+
@s3_acl = options[:s3_acl] || DEFAULT_ACL
|
14
|
+
@s3_bucket = options[:s3_bucket]
|
15
|
+
@s3_key = options[:s3_key] || DEFAULT_KEY
|
16
|
+
@s3_id = options[:aws_id]
|
17
|
+
@s3_secret = options[:aws_secret]
|
18
|
+
end
|
19
|
+
|
20
|
+
def s3
|
21
|
+
@s3 ||= begin
|
22
|
+
require_fog!
|
23
|
+
Fog::Storage.new(
|
24
|
+
provider: 'AWS',
|
25
|
+
aws_access_key_id: @s3_id,
|
26
|
+
aws_secret_access_key: @s3_secret
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Currently does not supporting checking S3 fo overwritten files
|
32
|
+
def exists?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def storage_location(level)
|
37
|
+
"#{@s3_key}/#{level}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# no-op
|
41
|
+
def mkdir(_path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def write(file, dest, options = {})
|
45
|
+
quality = options[:quality]
|
46
|
+
s3.put_object(@s3_bucket, dest, file.to_blob { @quality = quality if quality },
|
47
|
+
'Content-Type' => file.mime_type,
|
48
|
+
'x-amz-acl' => @s3_acl
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def require_fog!
|
55
|
+
require 'fog'
|
56
|
+
rescue LoadError => e
|
57
|
+
STDERR.puts 'Fog is required for storing data in S3, run `gem install fog`.'
|
58
|
+
raise e
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
module MiniDzt
|
4
|
+
class Tiler
|
5
|
+
# Defaults
|
6
|
+
DEFAULT_TILE_SIZE = 512
|
7
|
+
DEFAULT_TILE_OVERLAP = 0
|
8
|
+
DEFAULT_QUALITY = 75
|
9
|
+
DEFAULT_TILE_FORMAT = 'jpg'
|
10
|
+
DEFAULT_OVERWRITE_FLAG = false
|
11
|
+
|
12
|
+
# Generates the DZI-formatted tiles and sets necessary metadata on this object.
|
13
|
+
#
|
14
|
+
# @param [Hash] options
|
15
|
+
# @option source Magick::Image, or filename of image to be used for tiling
|
16
|
+
# @option quality Image compression quality (default: 75)
|
17
|
+
# @option format Format for output tiles (default: "jpg")
|
18
|
+
# @option size Size, in pixels, for tile squares (default: 512)
|
19
|
+
# @option overlap Size, in pixels, of the overlap between tiles (default: 2)
|
20
|
+
# @option overwrite Whether or not to overwrite if the destination exists (default: false)
|
21
|
+
def initialize(options)
|
22
|
+
fail 'Missing options[:source].' unless options[:source]
|
23
|
+
|
24
|
+
@tile_source = MiniMagick::Image.open(options[:source])
|
25
|
+
@tile_size = options[:size] || DEFAULT_TILE_SIZE
|
26
|
+
@tile_overlap = options[:overlap] || DEFAULT_TILE_OVERLAP
|
27
|
+
@tile_format = options[:format] || DEFAULT_TILE_FORMAT
|
28
|
+
@tile_quality = options[:quality] || DEFAULT_QUALITY
|
29
|
+
@overwrite = options[:overwrite] || DEFAULT_OVERWRITE_FLAG
|
30
|
+
|
31
|
+
@max_tiled_height = @tile_source.height
|
32
|
+
@max_tiled_width = @tile_source.width
|
33
|
+
end
|
34
|
+
|
35
|
+
def slice!(output_dir)
|
36
|
+
@tmp_working_dir = Pathname(@tile_source.path).dirname + "mini_dzt_#{SecureRandom.hex}"
|
37
|
+
FileUtils.mkdir_p @tmp_working_dir
|
38
|
+
|
39
|
+
orig_width = @tile_source.width
|
40
|
+
orig_height = @tile_source.height
|
41
|
+
|
42
|
+
max_level(orig_width, orig_height).downto(0) do |level|
|
43
|
+
puts "Level #{level}..."
|
44
|
+
current_level_storage_dir = "#{@tmp_working_dir}/#{level}"
|
45
|
+
FileUtils.mkdir_p current_level_storage_dir
|
46
|
+
|
47
|
+
width = @tile_source.width
|
48
|
+
height = @tile_source.height
|
49
|
+
|
50
|
+
manuscripts = get_manuscripts(width, height, current_level_storage_dir)
|
51
|
+
|
52
|
+
manuscripts.each do |dest_path, geometry_arg|
|
53
|
+
crope_image(@tile_source, dest_path, geometry_arg, @tile_quality)
|
54
|
+
end
|
55
|
+
|
56
|
+
@tile_source.resize("50%")
|
57
|
+
end
|
58
|
+
FileUtils.mv @tmp_working_dir, output_dir
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def tile_counts(length)
|
63
|
+
return 1 if length <= @tile_size
|
64
|
+
(length / @tile_size.to_f).ceil
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_manuscripts(width, height, current_level_storage_dir)
|
68
|
+
manuscripts = []
|
69
|
+
|
70
|
+
overlapping_tile_size = @tile_size + @tile_overlap
|
71
|
+
col_counts = tile_counts(width)
|
72
|
+
row_counts = tile_counts(height)
|
73
|
+
x, y = [0, 0]
|
74
|
+
|
75
|
+
row_counts.times do |row_count|
|
76
|
+
col_counts.times do |col_count|
|
77
|
+
manuscripts << [
|
78
|
+
File.join(current_level_storage_dir, "#{col_count}_#{row_count}.#{@tile_format}"),
|
79
|
+
"#{overlapping_tile_size}x#{overlapping_tile_size}+#{x}+#{y}"
|
80
|
+
]
|
81
|
+
x += @tile_size
|
82
|
+
end
|
83
|
+
x = 0
|
84
|
+
y += @tile_size
|
85
|
+
end
|
86
|
+
manuscripts
|
87
|
+
end
|
88
|
+
|
89
|
+
def max_level(width, height)
|
90
|
+
(Math.log([width, height].max) / Math.log(2)).ceil
|
91
|
+
end
|
92
|
+
|
93
|
+
def crope_image(image, dest_path, geometry_arg, quality = 75)
|
94
|
+
puts geometry_arg
|
95
|
+
cmd = "convert -crop #{geometry_arg} #{image.path} #{dest_path}"
|
96
|
+
system(cmd)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/washi/tiler.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'washi/config'
|
2
|
+
|
3
|
+
module Washi
|
4
|
+
class Tiler
|
5
|
+
def self.call(input_path, output_path, options={})
|
6
|
+
unless tile_size = options[:tile_size]
|
7
|
+
fail "Need pass :tile_size"
|
8
|
+
end
|
9
|
+
`#{Washil.config.binapath} #{input_path} #{output_path} --tile-size #{tile_size} --overlap #{Washil.config.overlap} #{Washil.config.options.join(" ")}`
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/washi/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: washi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gogotanaka
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,11 @@ files:
|
|
71
71
|
- bin/setup
|
72
72
|
- exe/washi
|
73
73
|
- lib/washi.rb
|
74
|
+
- lib/washi/config.rb
|
75
|
+
- lib/washi/mini_dzt/file_storage.rb
|
76
|
+
- lib/washi/mini_dzt/s3_storage.rb
|
77
|
+
- lib/washi/mini_dzt/tiler.rb
|
78
|
+
- lib/washi/tiler.rb
|
74
79
|
- lib/washi/version.rb
|
75
80
|
- test/fixtures/img1.jpg
|
76
81
|
- test/fixtures/img2.jpg
|