imaginizer 0.0.2 → 0.0.3
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/README.md +1 -1
- data/bin/imaginizer +2 -2
- data/lib/imaginizer.rb +9 -122
- data/lib/imaginizer/image.rb +196 -0
- data/lib/imaginizer/parser.rb +35 -35
- data/lib/imaginizer/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82ba111cb40bc4ffde4bb54212a371ce849b7876
|
4
|
+
data.tar.gz: ec933dd1678bf6ee211d9989fb5fac39e4c8ad16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 286af7a8402b9a6b55737b36bc39be6ddf5b371bb02741f65660bdc10f371e85af9e44921b5d5dc5dfa40abec54ecd0f660733f8bacde92414aa9ab93e25295e
|
7
|
+
data.tar.gz: 378ccaf62c45a887f1f1cf7d8ab9c8855d46dd546caf6fce19429ee42ed0275044827a4f70d2b3ca4bd82715dd778d68bbb9f626700d63550a561c68624a863e
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ You need [Imagemagick](http://www.imagemagick.org) with [Freetype](http://freety
|
|
11
11
|
|
12
12
|
To check if you have it installed, run this command:
|
13
13
|
|
14
|
-
check=`
|
14
|
+
check=`convert -list CONFIGURE 2> /dev/null|grep DELEGATES|grep freetype|wc -l`; if [ $check -eq 1 ]; then echo "Imagemagick/Freetype IS installed"; else echo "Imagemagick/Freetype IS NOT installed"; fi
|
15
15
|
|
16
16
|
To install:
|
17
17
|
|
data/bin/imaginizer
CHANGED
@@ -9,9 +9,9 @@ end
|
|
9
9
|
|
10
10
|
require 'imaginizer/parser'
|
11
11
|
|
12
|
-
options =
|
12
|
+
options = Imaginizer::Parser.parse ARGV
|
13
13
|
output = options.delete :output
|
14
14
|
puts "Creating images with #{options}:"
|
15
15
|
images = Imaginizer.create_images options
|
16
16
|
puts "Images created at #{images.map &:image_path}"
|
17
|
-
|
17
|
+
Imaginizer::Parser.output images, output
|
data/lib/imaginizer.rb
CHANGED
@@ -1,137 +1,24 @@
|
|
1
|
-
require '
|
1
|
+
require 'imaginizer/image'
|
2
2
|
|
3
3
|
module Imaginizer
|
4
4
|
def self.create_images(options = {})
|
5
5
|
sizes = options.delete(:sizes) { [] }
|
6
|
-
sizes.map
|
7
|
-
width, height = size.split 'x'
|
8
|
-
create_image options.merge(width: width, height: height)
|
9
|
-
end
|
6
|
+
sizes.map {|size| create_image size, options}
|
10
7
|
end
|
11
8
|
|
12
|
-
def self.create_image(options = {})
|
13
|
-
Image.create image_path(
|
9
|
+
def self.create_image(size, options = {})
|
10
|
+
Image.create size, image_path(size) do |image|
|
14
11
|
image.make_jpeg
|
15
|
-
image.resize
|
16
|
-
image.set_background options[:
|
17
|
-
image.
|
12
|
+
image.resize
|
13
|
+
image.set_background options[:background] if options[:background]
|
14
|
+
image.set_foreground options[:foreground] if options[:foreground]
|
18
15
|
image.set_title options[:title] if options[:title]
|
19
16
|
image.set_subtitle options[:subtitle] if options[:subtitle]
|
20
17
|
image.set_footer options[:footer] if options[:footer]
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
def self.image_path(
|
25
|
-
|
26
|
-
"/tmp/#{basename}.jpg"
|
27
|
-
end
|
28
|
-
|
29
|
-
class Image
|
30
|
-
attr_accessor :image_data, :image_path
|
31
|
-
|
32
|
-
def initialize(source_path = nil)
|
33
|
-
@image_data = MiniMagick::Image.open source_path || empty_image_path
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.create(image_path)
|
37
|
-
new.tap do |image|
|
38
|
-
image.image_path = image_path
|
39
|
-
yield image
|
40
|
-
image.image_data.write image_path
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
[:height, :width, :format].each do |method|
|
45
|
-
define_method method do
|
46
|
-
image_data[method]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def size
|
51
|
-
"#{width}x#{height}"
|
52
|
-
end
|
53
|
-
|
54
|
-
def make_jpeg
|
55
|
-
@image_data.format 'jpg'
|
56
|
-
end
|
57
|
-
|
58
|
-
def resize(w, h)
|
59
|
-
@image_data.resize "#{w}x#{h}!" if w and h
|
60
|
-
end
|
61
|
-
|
62
|
-
def crop(options = {})
|
63
|
-
return if options.none?
|
64
|
-
w = options[:width] || width
|
65
|
-
h = options[:height] || height
|
66
|
-
x_offset = (width - w)/2
|
67
|
-
y_offset = (height- h)/2
|
68
|
-
@image_data.crop "#{w}x#{h}+#{x_offset}+#{y_offset}"
|
69
|
-
end
|
70
|
-
|
71
|
-
def blur(radius_x_sigma)
|
72
|
-
@image_data.combine_options {|c| c.blur radius_x_sigma} if radius_x_sigma
|
73
|
-
end
|
74
|
-
|
75
|
-
def set_background(options = {})
|
76
|
-
overlay_image options.merge(blur: '0x15', fill: true)
|
77
|
-
end
|
78
|
-
|
79
|
-
def set_title(options = {})
|
80
|
-
overlay_text options.merge(uppercase: true)
|
81
|
-
end
|
82
|
-
|
83
|
-
def set_subtitle(options = {})
|
84
|
-
overlay_text options.merge(style: 'italic')
|
85
|
-
end
|
86
|
-
|
87
|
-
def set_footer(options = {})
|
88
|
-
overlay_box options.fetch(:box, {height: options[:size]})
|
89
|
-
overlay_text options.merge(style: 'bold', uppercase: true, gravity: 'south')
|
90
|
-
end
|
91
|
-
|
92
|
-
def overlay_text(options = {})
|
93
|
-
return unless text = options[:text]
|
94
|
-
text.upcase! if options[:uppercase]
|
95
|
-
@image_data.combine_options do |c|
|
96
|
-
c.fill 'white'
|
97
|
-
c.font font_path(options[:style])
|
98
|
-
c.gravity options.fetch(:gravity, 'center')
|
99
|
-
c.pointsize options[:size] if options[:size]
|
100
|
-
c.draw "text 0,0 '#{options[:text]}'"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def overlay_box(options = {})
|
105
|
-
return if options.none?
|
106
|
-
x2 = width
|
107
|
-
y2 = height
|
108
|
-
x1 = x2 - (options[:width] || x2)
|
109
|
-
y1 = y2 - (options[:height] || y2)
|
110
|
-
@image_data.combine_options do |c|
|
111
|
-
c.fill 'graya(0%, 0.5)'
|
112
|
-
c.draw "rectangle #{x1}, #{y1}, #{x2}, #{y2}"
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def overlay_image(options = {})
|
117
|
-
return unless options[:img]
|
118
|
-
image = Image.new options[:img]
|
119
|
-
image.blur options[:blur]
|
120
|
-
image.crop height: options[:height]
|
121
|
-
image.resize width, height if options[:fill]
|
122
|
-
@image_data = @image_data.composite image.image_data
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def empty_image_path
|
128
|
-
File.expand_path '../assets/1x1.jpg', __FILE__
|
129
|
-
end
|
130
|
-
|
131
|
-
def font_path(style)
|
132
|
-
style ||= 'regular'
|
133
|
-
font_file = "../assets/RobotoCondensed-#{style.capitalize}.ttf"
|
134
|
-
File.expand_path font_file, __FILE__
|
135
|
-
end
|
21
|
+
def self.image_path(size)
|
22
|
+
"/tmp/#{size}.jpg"
|
136
23
|
end
|
137
24
|
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
class Imaginizer::Image
|
4
|
+
attr_accessor :image_data, :image_path, :image_size
|
5
|
+
|
6
|
+
def initialize(source_path = nil)
|
7
|
+
@image_data = MiniMagick::Image.open source_path || empty_image_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.create(size, image_path)
|
11
|
+
new.tap do |image|
|
12
|
+
image.image_size = size
|
13
|
+
image.image_path = image_path
|
14
|
+
yield image
|
15
|
+
image.image_data.write image_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_jpeg
|
20
|
+
@image_data.format 'jpg'
|
21
|
+
end
|
22
|
+
|
23
|
+
def resize
|
24
|
+
@image_data.resize "#{image_width}x#{image_height}!"
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_background(options = {})
|
28
|
+
v = values_for :background
|
29
|
+
overlay_image options.merge(blur: '0x15', fill: true, x: v[:x],
|
30
|
+
y: v[:y], h: v[:h])
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_foreground(options = {})
|
34
|
+
v = values_for :foreground
|
35
|
+
overlay_image options.merge(h: v[:h], w: v[:w]) unless v[:skip]
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_title(options = {})
|
39
|
+
set_text :title, options do |v|
|
40
|
+
{style: 'bold', uppercase: true, x: v[:x], y: v[:y], size: v[:size]}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_subtitle(options = {})
|
45
|
+
set_text :subtitle, options do |v|
|
46
|
+
{style: 'italic', size: 14, x: v[:x], y: v[:y]}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_footer(options = {})
|
51
|
+
overlay_box values_for(:footer)
|
52
|
+
set_text :footer, options do |v|
|
53
|
+
{style: 'bold', uppercase: true, x: v[:x], y: v[:y], size: v[:size]}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def blur(radius_x_sigma)
|
60
|
+
@image_data.combine_options {|c| c.blur radius_x_sigma} if radius_x_sigma
|
61
|
+
end
|
62
|
+
|
63
|
+
def crop(options = {})
|
64
|
+
return if options.none?
|
65
|
+
w = options[:w] || width
|
66
|
+
h = options[:h] || height
|
67
|
+
x_offset = (width - w)/2
|
68
|
+
y_offset = (height- h)/2
|
69
|
+
@image_data.crop "#{w}x#{h}+#{x_offset}+#{y_offset}"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def values_for(property)
|
75
|
+
{medium_rectangle: {
|
76
|
+
width: 300,
|
77
|
+
height: 250,
|
78
|
+
background: {y: 125, h: 125},
|
79
|
+
foreground: {h: 125},
|
80
|
+
title: {y: 23, second_line_y: 57, size: 40},
|
81
|
+
subtitle: {y: 84},
|
82
|
+
footer: {h: 30, size: 25, y: 111}
|
83
|
+
},
|
84
|
+
rectangle: {
|
85
|
+
width: 180,
|
86
|
+
height: 150,
|
87
|
+
foreground: {skip: true},
|
88
|
+
title: {y: -39, second_line_y: -12, size: 34},
|
89
|
+
subtitle: {y: 13},
|
90
|
+
footer: {h: 28, size: 16, y: 63}
|
91
|
+
},
|
92
|
+
wide_skyscraper: {
|
93
|
+
width: 160,
|
94
|
+
height: 600,
|
95
|
+
background: {y: 250, h: 125},
|
96
|
+
foreground: {h: 250},
|
97
|
+
title: {y: -23, second_line_y: 0, size: 30},
|
98
|
+
subtitle: {y: 33},
|
99
|
+
footer: {h: 94, size: 26, y: 242, second_line_y: 263}
|
100
|
+
},
|
101
|
+
leaderboard: {
|
102
|
+
width: 728,
|
103
|
+
height: 90,
|
104
|
+
background: {x: 228},
|
105
|
+
foreground: {w: 228},
|
106
|
+
title: {x: 120, y: -24, size: 42},
|
107
|
+
subtitle: {x: 120, y: 5},
|
108
|
+
footer: {w: 500, h: 29, size: 26, x: 120, y: 30}
|
109
|
+
}
|
110
|
+
}[@image_size].fetch property, {}
|
111
|
+
end
|
112
|
+
|
113
|
+
[:height, :width, :format].each do |method|
|
114
|
+
define_method method do
|
115
|
+
image_data[method]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def size
|
120
|
+
"#{width}x#{height}"
|
121
|
+
end
|
122
|
+
|
123
|
+
def image_width
|
124
|
+
values_for :width
|
125
|
+
end
|
126
|
+
|
127
|
+
def image_height
|
128
|
+
values_for :height
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_text(size, options = {})
|
132
|
+
values = values_for size
|
133
|
+
size_options = options.merge yield(values)
|
134
|
+
if values[:second_line_y]
|
135
|
+
line1, line2 = word_wrap options[:text]
|
136
|
+
overlay_text size_options.merge(text: line1)
|
137
|
+
overlay_text size_options.merge(text: line2, y: values[:second_line_y])
|
138
|
+
else
|
139
|
+
overlay_text size_options
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def word_wrap(text)
|
144
|
+
text.delete("\n").sub(/(.{1,9})(\s+|$)/, "\\1\n").strip.split("\n")
|
145
|
+
end
|
146
|
+
|
147
|
+
def overlay_text(options = {})
|
148
|
+
return unless text = options[:text]
|
149
|
+
text.upcase! if options[:uppercase]
|
150
|
+
@image_data.combine_options do |c|
|
151
|
+
c.fill 'white'
|
152
|
+
c.font font_path(options[:style])
|
153
|
+
c.gravity 'center'
|
154
|
+
c.pointsize options[:size] if options[:size]
|
155
|
+
c.draw "text #{options[:x] || 0},#{options[:y] || 0} '#{options[:text]}'"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def overlay_box(options = {})
|
160
|
+
return if options.none?
|
161
|
+
x2 = width
|
162
|
+
y2 = height
|
163
|
+
x1 = x2 - (options[:w] || x2)
|
164
|
+
y1 = y2 - (options[:h] || y2)
|
165
|
+
@image_data.combine_options do |c|
|
166
|
+
c.fill 'graya(0%, 0.5)'
|
167
|
+
c.draw "rectangle #{x1}, #{y1}, #{x2}, #{y2}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def overlay_image(options = {})
|
172
|
+
return unless options[:img]
|
173
|
+
image = self.class.new options[:img]
|
174
|
+
image.blur options[:blur]
|
175
|
+
|
176
|
+
image.crop options
|
177
|
+
image.resize image_size if options[:fill]
|
178
|
+
overlay_x = options[:x] || 0
|
179
|
+
overlay_y = options[:y] || 0
|
180
|
+
@image_data = @image_data.composite image.image_data do |c|
|
181
|
+
c.geometry "#{image.width}x#{image.height}+#{overlay_x}+#{overlay_y}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
def empty_image_path
|
188
|
+
File.expand_path '../../assets/1x1.jpg', __FILE__
|
189
|
+
end
|
190
|
+
|
191
|
+
def font_path(style)
|
192
|
+
style ||= 'regular'
|
193
|
+
font_file = "../../assets/RobotoCondensed-#{style.capitalize}.ttf"
|
194
|
+
File.expand_path font_file, __FILE__
|
195
|
+
end
|
196
|
+
end
|
data/lib/imaginizer/parser.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'optparse'
|
2
|
-
|
3
|
+
|
4
|
+
class Imaginizer::Parser
|
5
|
+
def self.valid_sizes
|
6
|
+
[:medium_rectangle, :rectangle, :wide_skyscraper, :leaderboard]
|
7
|
+
end
|
8
|
+
|
3
9
|
def self.parse(args)
|
4
10
|
options = default_values
|
5
11
|
|
@@ -9,49 +15,38 @@ class ImaginizerParser
|
|
9
15
|
opts.separator ''
|
10
16
|
opts.separator 'Specific options:'
|
11
17
|
|
12
|
-
opts.on('-d', '--dimension
|
18
|
+
opts.on('-d', '--dimension [IAB_SIZE]', valid_sizes,
|
19
|
+
%Q(Sizes to create #{valid_sizes} – multiple values accepted)) do |d|
|
13
20
|
options[:sizes] << d
|
14
21
|
end
|
15
|
-
default_sizes = options.delete(:default_sizes)
|
16
|
-
options[:sizes] = default_sizes if options[:sizes].empty?
|
17
22
|
|
18
|
-
opts.on('-b', '--background path', String,
|
19
|
-
|
23
|
+
opts.on('-b', '--background path', String,
|
24
|
+
%q(Background image – either a local path or a URL)) do |path|
|
25
|
+
options[:background][:img] = path
|
20
26
|
end
|
21
27
|
|
22
|
-
opts.on('-f', '--foreground path', String,
|
23
|
-
|
28
|
+
opts.on('-f', '--foreground path', String,
|
29
|
+
%q(Foreground image – either a local path or a URL)) do |path|
|
30
|
+
options[:foreground][:img] = path
|
24
31
|
end
|
25
32
|
|
26
|
-
opts.on('
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
opts.on('-t', '--title text', String, 'Overlay title') do |text|
|
33
|
+
opts.on('-t', '--title text', String,
|
34
|
+
%q(Title to overlay – maximum 15 characters)) do |text|
|
31
35
|
options[:title][:text] = text
|
32
36
|
end
|
33
37
|
|
34
|
-
opts.on('
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
opts.on('-s', '--subtitle text', String, 'Overlay subtitle') do |text|
|
38
|
+
opts.on('-s', '--subtitle text', String,
|
39
|
+
%q(Subtitle to overlay – maximum 15 characters)) do |text|
|
39
40
|
options[:subtitle][:text] = text
|
40
41
|
end
|
41
42
|
|
42
|
-
opts.on('
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
opts.on('-r', '--footer text', String, 'Overlay footer') do |text|
|
43
|
+
opts.on('-r', '--footer text', String,
|
44
|
+
%q(Footer to overlay – maximum 20 characters)) do |text|
|
47
45
|
options[:footer][:text] = text
|
48
46
|
end
|
49
47
|
|
50
|
-
opts.on('
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
opts.on('-o', '--output [OUTPUT]', [:image, :html], 'What to show') do |o|
|
48
|
+
opts.on('-o', '--output [OUTPUT]', [:image, :html],
|
49
|
+
%q(Output type – either an image or an HTML page)) do |o|
|
55
50
|
options[:output] = o
|
56
51
|
end
|
57
52
|
|
@@ -70,6 +65,8 @@ class ImaginizerParser
|
|
70
65
|
end
|
71
66
|
|
72
67
|
opt_parser.parse!(args)
|
68
|
+
|
69
|
+
options[:sizes] = self.valid_sizes if options[:sizes].empty?
|
73
70
|
options
|
74
71
|
end
|
75
72
|
|
@@ -77,12 +74,11 @@ class ImaginizerParser
|
|
77
74
|
{}.tap do |opts|
|
78
75
|
opts[:output] = :html
|
79
76
|
opts[:sizes] = []
|
80
|
-
opts[:
|
81
|
-
opts[:
|
82
|
-
opts[:
|
83
|
-
opts[:
|
84
|
-
opts[:
|
85
|
-
opts[:fg] = {img: 'http://lorempixel.com/300/300/people', height: 100}
|
77
|
+
opts[:title] = {text: 'Title max 18 chars'}
|
78
|
+
opts[:subtitle] = {text: 'This subtitle is 30 characters'}
|
79
|
+
opts[:footer] = {text: 'A footer w/ 20 chars'}
|
80
|
+
opts[:background] = {img: 'http://lorempixel.com/300/300/abstract'}
|
81
|
+
opts[:foreground] = {img: 'http://lorempixel.com/300/300/people'}
|
86
82
|
end
|
87
83
|
end
|
88
84
|
|
@@ -98,13 +94,17 @@ class ImaginizerParser
|
|
98
94
|
<html>
|
99
95
|
<head>
|
100
96
|
<meta charset="UTF-8" />
|
97
|
+
<style>
|
98
|
+
body {background-color: #ccc}
|
99
|
+
figure {float: left}
|
100
|
+
</style>
|
101
101
|
<title>Imaginizer output</title>
|
102
102
|
</head>
|
103
103
|
<body>
|
104
104
|
#{images.map do |image|
|
105
105
|
'<figure>' +
|
106
106
|
'<img src="' + image.image_path + '" />' +
|
107
|
-
'<figcaption>Size: ' + image.
|
107
|
+
'<figcaption>Size: ' + image.image_size.to_s + '</figcaption>' +
|
108
108
|
'</figure>'
|
109
109
|
end.join}
|
110
110
|
</body>
|
data/lib/imaginizer/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imaginizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mini_magick
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- lib/assets/RobotoCondensed-Bold.ttf
|
124
124
|
- lib/assets/RobotoCondensed-Italic.ttf
|
125
125
|
- lib/assets/RobotoCondensed-Regular.ttf
|
126
|
+
- lib/imaginizer/image.rb
|
126
127
|
- lib/imaginizer/parser.rb
|
127
128
|
- lib/imaginizer/version.rb
|
128
129
|
- lib/imaginizer.rb
|