thumbkit 0.0.2
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.
- data/.gitignore +12 -0
- data/Gemfile +16 -0
- data/Guardfile +16 -0
- data/LICENSE +22 -0
- data/README.md +246 -0
- data/Rakefile +2 -0
- data/lib/thumbkit/options.rb +15 -0
- data/lib/thumbkit/processor/audio.rb +28 -0
- data/lib/thumbkit/processor/image.rb +47 -0
- data/lib/thumbkit/processor/text.rb +99 -0
- data/lib/thumbkit/processor.rb +45 -0
- data/lib/thumbkit/version.rb +3 -0
- data/lib/thumbkit.rb +42 -0
- data/spec/fixtures/16Hz-20kHz-Exp-1f-5sec.mp3 +0 -0
- data/spec/fixtures/arabic.txt +7 -0
- data/spec/fixtures/greek.txt +14 -0
- data/spec/fixtures/hebrew.txt +17 -0
- data/spec/fixtures/jpg_file.jpg +0 -0
- data/spec/fixtures/png_file.png +0 -0
- data/spec/fixtures/text_file.txt +15 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/thumbkit/options_spec.rb +40 -0
- data/spec/thumbkit/processor/audio_spec.rb +57 -0
- data/spec/thumbkit/processor/image_spec.rb +81 -0
- data/spec/thumbkit/processor/text_spec.rb +114 -0
- data/spec/thumbkit/processor_spec.rb +47 -0
- data/spec/thumbkit_spec.rb +34 -0
- data/thumbkit.gemspec +18 -0
- metadata +89 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in thumbkit.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
|
7
|
+
# Development tools
|
8
|
+
gem 'rspec'
|
9
|
+
|
10
|
+
gem 'guard'
|
11
|
+
gem 'guard-rspec'
|
12
|
+
gem 'guard-bundler'
|
13
|
+
|
14
|
+
gem 'mini_magick'
|
15
|
+
gem 'waveform', git: 'https://github.com/amiel/waveform', branch: 'thumbkit'
|
16
|
+
gem 'oily_png'
|
data/Guardfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
notification :off
|
5
|
+
|
6
|
+
guard 'bundler' do
|
7
|
+
watch('Gemfile')
|
8
|
+
watch(/^.+\.gemspec/)
|
9
|
+
end
|
10
|
+
|
11
|
+
guard 'rspec', version: 2, cli: '--color -f doc', keep_failed: false do
|
12
|
+
watch(%r{^spec/.+_spec\.rb$})
|
13
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{ m[1] }_spec.rb" }
|
14
|
+
watch('spec/spec_helper.rb') { "spec" }
|
15
|
+
end
|
16
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Amiel Martin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
# Thumbkit
|
2
|
+
|
3
|
+
> it's like quicklook for carrierwave :)
|
4
|
+
>
|
5
|
+
> -- <cite>[Emmanuel Gomez][1]</cite>
|
6
|
+
|
7
|
+
[1]:https://github.com/emmanuel
|
8
|
+
|
9
|
+
Thumbkit makes thumbnails from a variety of media types.
|
10
|
+
Thumbkit is designed to work with carrierwave but does not require it.
|
11
|
+
|
12
|
+
## Synopsis
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
Thumbkit.new('path/to/audio.mp3').write_thumbnail # => 'path/to/audio.png'
|
16
|
+
Thumbkit.new('path/to/text.txt').write_thumbnail # => 'path/to/text.png'
|
17
|
+
Thumbkit.new('path/to/image.jpg').write_thumbnail # => 'path/to/image.jpg'
|
18
|
+
```
|
19
|
+
|
20
|
+
See [Usage](#usage) below for more examples
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
Add this line to your application's Gemfile:
|
25
|
+
|
26
|
+
gem 'thumbkit'
|
27
|
+
gem 'mini_magick' # For text or image thumbnails
|
28
|
+
gem 'waveform' # For audio thumbnails
|
29
|
+
gem 'oily_png' # Optional, for presumably faster audio thumbnails
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
$ bundle
|
34
|
+
|
35
|
+
Please see [Requirements](#requirements) for more information about each
|
36
|
+
thumbnail type.
|
37
|
+
|
38
|
+
|
39
|
+
## Requirements
|
40
|
+
|
41
|
+
### Image thumbnails
|
42
|
+
|
43
|
+
Thumbkit uses [MiniMagick](https://github.com/probablycorey/mini_magick) to
|
44
|
+
resize and crop images.
|
45
|
+
|
46
|
+
On OS X:
|
47
|
+
|
48
|
+
$ brew install imagemagick
|
49
|
+
$ gem install mini_magick
|
50
|
+
|
51
|
+
### Text thumbnails
|
52
|
+
|
53
|
+
Thumbkit uses [MiniMagick](https://github.com/probablycorey/mini_magick) to
|
54
|
+
render text files.
|
55
|
+
|
56
|
+
On OS X:
|
57
|
+
|
58
|
+
$ brew install imagemagick
|
59
|
+
$ gem install mini_magick
|
60
|
+
|
61
|
+
### HTML thumbnails
|
62
|
+
|
63
|
+
HTML thumbnails are not yet supported, but the plan is to use phantomjs to
|
64
|
+
render html files.
|
65
|
+
|
66
|
+
### Audio thumbnails
|
67
|
+
|
68
|
+
Thumbkit uses the [waveform](https://github.com/benalavi/waveform) gem to render
|
69
|
+
audio files. [waveform](https://github.com/benalavi/waveform) depends on
|
70
|
+
libsndfile. **ffmpeg** is required in order to generate thumbnails from anything
|
71
|
+
other than .wav files.
|
72
|
+
|
73
|
+
See https://github.com/benalavi/waveform for more on requirements.
|
74
|
+
|
75
|
+
NOTE: As of 0.0.3 waveform fails on mono files (benalavi/waveform#4,
|
76
|
+
benalavi/waveform#5. I've forked and fixed (see benalavi/waveform#6). Until my
|
77
|
+
fix gets merged in you can use https://github.com/amiel/waveform/tree/thumbkit.
|
78
|
+
Like so:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
gem 'thumbkit'
|
82
|
+
gem 'waveform', git: 'https://github.com/amiel/waveform', branch: 'thumbkit'
|
83
|
+
gem 'oily_png' # Optional, for presumably faster audio thumbnails
|
84
|
+
```
|
85
|
+
|
86
|
+
## Usage
|
87
|
+
|
88
|
+
Thumbkit takes a path to a file, and saves a thumbnail for that file regardless
|
89
|
+
of type. Certain types require different gems, but none are dependencies so
|
90
|
+
you'll have to install them yourself.
|
91
|
+
|
92
|
+
All settings can be set globally. These are the defaults:
|
93
|
+
|
94
|
+
### Configuration
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
Thumbkit.defaults = {
|
98
|
+
width: 200, height: 200,
|
99
|
+
gravity: 'Center',
|
100
|
+
colors: { foreground: '#888888', background: '#eeeeee' },
|
101
|
+
font: {
|
102
|
+
family: 'Arial-Regular',
|
103
|
+
pointsize: '18',
|
104
|
+
direction: :auto,
|
105
|
+
},
|
106
|
+
}
|
107
|
+
```
|
108
|
+
|
109
|
+
Setting `Thumbkit.defaults=` will deep merge. So setting one option is possible
|
110
|
+
with:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
Thumbkit.defaults = { colors: { foreground: '#FF69B4' } } # HOT PINK
|
114
|
+
```
|
115
|
+
|
116
|
+
#### Font options
|
117
|
+
|
118
|
+
The list of fonts available to imagemagick can be found with
|
119
|
+
`identify -list Font`
|
120
|
+
|
121
|
+
#### Gravity Options
|
122
|
+
|
123
|
+
A list of gravity options can be found with `identify -list Gravity`
|
124
|
+
|
125
|
+
See http://www.imagemagick.org/script/command-line-options.php#gravity for more
|
126
|
+
information.
|
127
|
+
|
128
|
+
### Image thumbnails
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
Thumbkit.new('path/to/image.jpg').write_thumbnail # => 'path/to/image.jpg'
|
132
|
+
```
|
133
|
+
|
134
|
+
Will write a 60x60 cropped image to `path/to/image.jpg`.
|
135
|
+
|
136
|
+
The format of the output file will depend on the extension of the output path
|
137
|
+
and defaults to the same as the input file.
|
138
|
+
|
139
|
+
### Text thumbnails
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
text = Thumbkit.new('path/to/text_file.txt')
|
143
|
+
|
144
|
+
text.write_thumbnail(nil, {
|
145
|
+
width: 200, height: 200,
|
146
|
+
colors: { foreground: '#663854' },
|
147
|
+
font: { pointsize: '18' },
|
148
|
+
}) # => 'path/to/text_file.png'
|
149
|
+
```
|
150
|
+
|
151
|
+
Will write a 200x200 cropped image to `path/to/text_file.png`.
|
152
|
+
|
153
|
+
The format of output will depend on the extension of the output path provided
|
154
|
+
but defaults to .png.
|
155
|
+
|
156
|
+
#### RTL support
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
text = Thumbkit.new('path/to/text_file.txt')
|
160
|
+
text.write_thumbnail(nil, font: { direction: 'right-to-left' }) # Force RTL
|
161
|
+
```
|
162
|
+
|
163
|
+
`direction` options:
|
164
|
+
|
165
|
+
* `nil`: don't specify the option to imagemagick (OS default)
|
166
|
+
* `:auto`: try to detect. Currently, this switches to `'right-to-left'` if there
|
167
|
+
are *any* RTL characters in the input. This is the default.
|
168
|
+
* `'right-to-left'`, `'left-to-right'`: force LTR or RTL
|
169
|
+
|
170
|
+
### Audio thumbnails
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
audio = Thumbkit.new('path/to/audio.mp3')
|
174
|
+
audio.write_thumbnail('path/to/ouput.png', {
|
175
|
+
colors: { foreground: '#ffffff', background: '#000000' },
|
176
|
+
}) # => 'path/to/output.png'
|
177
|
+
```
|
178
|
+
|
179
|
+
Will write a 60x60 cropped image to `path/to/output.png`.
|
180
|
+
|
181
|
+
Note that while imagemagick supports most color specification formats, waveform
|
182
|
+
only takes 6 digit hex values. However, there is one special case for the symbol
|
183
|
+
:transparent.
|
184
|
+
|
185
|
+
Audio thumbnails only support PNG output. A png file will be created regardless
|
186
|
+
of the extension of the output file provided.
|
187
|
+
|
188
|
+
### Composite thumbnails
|
189
|
+
|
190
|
+
NOT YET IMPLEMENTED
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
composite = Thumbkit.new(['path/to/audio.mp3', 'path/to/text_file.txt'])
|
194
|
+
composite.write_thumbnail('path/to/collection.png')
|
195
|
+
```
|
196
|
+
|
197
|
+
### CarrierWave usage
|
198
|
+
|
199
|
+
NOT YET IMPLEMENTED
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
class MyUploader < CarrierWave::Uploader::Base
|
203
|
+
include CarrierWave::Thumbkit
|
204
|
+
|
205
|
+
version :thumbnail do
|
206
|
+
process :thumbkit => [200, 200, { colors: { foreground: '#cccccc' } }]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
## Other plans
|
212
|
+
|
213
|
+
* Accept a StringIO instead of a pathname
|
214
|
+
* Maybe use filemagic if available
|
215
|
+
* Processors:
|
216
|
+
* Composite
|
217
|
+
* HTML
|
218
|
+
* PDF
|
219
|
+
* Video
|
220
|
+
|
221
|
+
## Contributing
|
222
|
+
|
223
|
+
1. Fork it
|
224
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
225
|
+
3. Run the test suite to make sure all tests pass before you start (`guard`)
|
226
|
+
4. Make your changes
|
227
|
+
5. Run the test suite again to make sure you didn't break anything existing (`guard`)
|
228
|
+
6. Commit your changes (`git commit -am 'Added some feature'`)
|
229
|
+
7. Push to the branch (`git push origin my-new-feature`)
|
230
|
+
8. Create new Pull Request
|
231
|
+
|
232
|
+
## Testing
|
233
|
+
|
234
|
+
Tests run in guard. If you don't like guard, a pull request on `Rakefile` would
|
235
|
+
be welcome.
|
236
|
+
|
237
|
+
Output files are placed in `spec/tmp` which is created automatically before each
|
238
|
+
test run and deleted automatically afterward unless `spec/tmp/.keep` exists. If
|
239
|
+
you would like to inspect the generated output files, create a file at
|
240
|
+
`spec/tmp/.keep`:
|
241
|
+
|
242
|
+
$ mkdir spec/tmp; touch spec/tmp/.keep
|
243
|
+
|
244
|
+
Many of the tests just verify that an image was created of the right type and
|
245
|
+
size, but do not actually verify that they have the correct content so it is
|
246
|
+
good to inspect the generated files.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
class Thumbkit::Options < DelegateClass(Hash)
|
4
|
+
@@merge_proc = proc { |key, left, right|
|
5
|
+
Hash === left && Hash === right ? left.merge(right, &@@merge_proc) : right
|
6
|
+
}
|
7
|
+
|
8
|
+
def merge(other)
|
9
|
+
Thumbkit::Options::new(__getobj__.merge(other, &@@merge_proc))
|
10
|
+
end
|
11
|
+
|
12
|
+
def +(other)
|
13
|
+
merge(other)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'waveform'
|
2
|
+
|
3
|
+
class Thumbkit::Processor::Audio < Thumbkit::Processor
|
4
|
+
|
5
|
+
def determine_outfile
|
6
|
+
self.class.force_extension(path, 'png')
|
7
|
+
end
|
8
|
+
|
9
|
+
def write
|
10
|
+
Waveform.new(path).generate(outfile, build_options)
|
11
|
+
|
12
|
+
outfile
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def build_options
|
18
|
+
{
|
19
|
+
force: true,
|
20
|
+
method: :rms, # Hard-coded for now.
|
21
|
+
width: options[:width],
|
22
|
+
height: options[:height],
|
23
|
+
color: options[:colors][:foreground],
|
24
|
+
background_color: options[:colors][:background],
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
class Thumbkit::Processor::Image < Thumbkit::Processor
|
4
|
+
|
5
|
+
def determine_outfile
|
6
|
+
@path
|
7
|
+
end
|
8
|
+
|
9
|
+
def write
|
10
|
+
resize_to_fill
|
11
|
+
|
12
|
+
outfile
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def type
|
20
|
+
File.extname(outfile)[1..-1]
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Copied and adjusted from CarrierWave
|
25
|
+
def resize_to_fill
|
26
|
+
image = ::MiniMagick::Image.open(path)
|
27
|
+
|
28
|
+
cols, rows = image[:dimensions]
|
29
|
+
image.format type
|
30
|
+
image.combine_options do |cmd|
|
31
|
+
if options[:width] != cols || options[:height] != rows
|
32
|
+
scale = [options[:width]/cols.to_f, options[:height]/rows.to_f].max
|
33
|
+
cols = (scale * (cols + 0.5)).round
|
34
|
+
rows = (scale * (rows + 0.5)).round
|
35
|
+
cmd.resize "#{ cols }x#{ rows }"
|
36
|
+
end
|
37
|
+
cmd.gravity options[:gravity].to_s
|
38
|
+
cmd.background options[:colors][:background].to_s
|
39
|
+
|
40
|
+
if cols != options[:width] || rows != options[:height]
|
41
|
+
cmd.extent "#{ options[:width] }x#{ options[:height] }"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
image.write(outfile)
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
# NOTES: For now, use reverse markdown for html
|
4
|
+
# https://github.com/xijo/reverse_markdown
|
5
|
+
# https://github.com/cousine/downmark_it
|
6
|
+
class Thumbkit::Processor::Text < Thumbkit::Processor
|
7
|
+
|
8
|
+
def determine_outfile
|
9
|
+
self.class.force_extension(path, 'png')
|
10
|
+
end
|
11
|
+
|
12
|
+
def write
|
13
|
+
command = build_command
|
14
|
+
run(command)
|
15
|
+
|
16
|
+
outfile
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
|
22
|
+
def command_builder
|
23
|
+
MiniMagick::CommandBuilder.new('mogrify')
|
24
|
+
end
|
25
|
+
|
26
|
+
# Regexes copies from www.frequency-decoder.com/demo/detect-text-direction/
|
27
|
+
# and https://github.com/geeksoflondon/grid4rails/issues/120
|
28
|
+
#
|
29
|
+
# Currently, this detects the direction by checking if *any* character in the
|
30
|
+
# input is an RTL character.
|
31
|
+
# TODO: Maybe check for a percentage of RTL characters?
|
32
|
+
def direction
|
33
|
+
# For future reference
|
34
|
+
# Hebrew - U+05D0 to U+05EA, U+05F0 to U+05F2, U+05BE, U+05C0, U+05C3, U+05F3, U+05F4, U+05B0 to U+05C4, U+0591 to U+05AF.
|
35
|
+
# Arabic - U+0600 to U+06FF, U+0750 to U+077F, U+FB50 to U+FDFF, U+FE70 to U+FEFF, U+10E60 to U+10E7F.
|
36
|
+
# ltrChars = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF'+'\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF',
|
37
|
+
# rtlChars = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC',
|
38
|
+
|
39
|
+
dir = options[:font][:direction]
|
40
|
+
if dir == :auto
|
41
|
+
if /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.match(IO.read(path))
|
42
|
+
'right-to-left'
|
43
|
+
else
|
44
|
+
'left-to-right'
|
45
|
+
end
|
46
|
+
else
|
47
|
+
dir
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Example generated command
|
52
|
+
# mogrify -density "288" -background "#ccc" -fill "#333" -pointsize "18" -antialias -font "Helvetica" -format png -trim -resize "%25" +repage -crop "200x200+10+10" +repage -write test.png test.txt
|
53
|
+
def build_command
|
54
|
+
command_builder.tap do |mogrify|
|
55
|
+
mogrify.density((72 * 4).to_s)
|
56
|
+
mogrify.background options[:colors][:background].to_s
|
57
|
+
mogrify.fill options[:colors][:foreground].to_s
|
58
|
+
mogrify.pointsize options[:font][:size].to_s
|
59
|
+
mogrify.antialias
|
60
|
+
mogrify.font options[:font][:family]
|
61
|
+
mogrify.direction direction if direction
|
62
|
+
mogrify.gravity options[:gravity].to_s
|
63
|
+
# While we convert to png, imagemagick will still output the format given
|
64
|
+
# by the extension. This allows users to costumize the output with the
|
65
|
+
# outfile extension.
|
66
|
+
mogrify << '-format png'
|
67
|
+
mogrify.trim
|
68
|
+
mogrify.resize '25%'
|
69
|
+
mogrify << '+repage'
|
70
|
+
mogrify.crop "#{ options[:width] }x#{ options[:height] }+0+0"
|
71
|
+
mogrify.extent "#{ options[:width] }x#{ options[:height] }"
|
72
|
+
mogrify << '+repage'
|
73
|
+
mogrify.write outfile
|
74
|
+
mogrify << "label:@#{path}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Mostly copied from MiniMagick
|
79
|
+
def run(command_builder)
|
80
|
+
command = command_builder.command
|
81
|
+
|
82
|
+
sub = Subexec.run(command, timeout: MiniMagick.timeout)
|
83
|
+
|
84
|
+
if sub.exitstatus != 0
|
85
|
+
|
86
|
+
# Raise the appropriate error
|
87
|
+
if sub.output =~ /no decode delegate/i || sub.output =~ /did not return an image/i
|
88
|
+
raise MiniMagick::Invalid, sub.output
|
89
|
+
else
|
90
|
+
# TODO: should we do something different if the command times out ...?
|
91
|
+
# its definitely better for logging.. otherwise we dont really know
|
92
|
+
raise MiniMagick::Error, "Command (#{command.inspect.gsub("\\", "")}) failed: #{{:status_code => sub.exitstatus, :output => sub.output}.inspect}"
|
93
|
+
end
|
94
|
+
else
|
95
|
+
sub.output
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Thumbkit::Processor
|
2
|
+
autoload :Text, 'thumbkit/processor/text'
|
3
|
+
autoload :Audio, 'thumbkit/processor/audio'
|
4
|
+
autoload :Image, 'thumbkit/processor/image'
|
5
|
+
|
6
|
+
def self.processors
|
7
|
+
@processors ||= {
|
8
|
+
'png' => 'Image',
|
9
|
+
'jpg' => 'Image',
|
10
|
+
'txt' => 'Text',
|
11
|
+
'md' => 'Text',
|
12
|
+
'mp3' => 'Audio',
|
13
|
+
'wav' => 'Audio',
|
14
|
+
'm4a' => 'Audio',
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.processor_for(extension)
|
19
|
+
if (class_name = self.processors[extension])
|
20
|
+
self.const_get(class_name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.force_extension(filename, extension)
|
26
|
+
dir, fname = File.split(filename)
|
27
|
+
File.join(dir, "#{ File.basename(fname, '.*') }.#{ extension }")
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :path, :outfile, :options
|
31
|
+
def initialize(path, outfile, options)
|
32
|
+
@path = path
|
33
|
+
@outfile = outfile || determine_outfile
|
34
|
+
@options = Thumbkit.defaults + options
|
35
|
+
end
|
36
|
+
|
37
|
+
def determine_outfile
|
38
|
+
raise NotImplementedError, 'Cannot determine an output file'
|
39
|
+
end
|
40
|
+
|
41
|
+
def write
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/thumbkit.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "thumbkit/version"
|
2
|
+
|
3
|
+
class Thumbkit
|
4
|
+
autoload :Processor, 'thumbkit/processor'
|
5
|
+
autoload :Options, 'thumbkit/options'
|
6
|
+
|
7
|
+
attr_accessor :path, :filename, :type
|
8
|
+
|
9
|
+
def self.defaults
|
10
|
+
@defaults ||= Thumbkit::Options.new({
|
11
|
+
width: 200,
|
12
|
+
height: 200,
|
13
|
+
# Try `identify -list Gravity` for a list of available options
|
14
|
+
gravity: 'Center',
|
15
|
+
colors: {
|
16
|
+
# Colors must be 6-digit hex
|
17
|
+
background: '#eeeeee',
|
18
|
+
foreground: '#888888',
|
19
|
+
},
|
20
|
+
font: {
|
21
|
+
# Try `identify -list Font` for available font options
|
22
|
+
family: 'Arial-Regular',
|
23
|
+
size: '18', # In points
|
24
|
+
direction: :auto, # nil, :auto, 'right-to-left', or 'left-to-right'
|
25
|
+
},
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(path)
|
30
|
+
@path = File.expand_path(path)
|
31
|
+
@filename = File.basename(@path)
|
32
|
+
@type = File.extname(filename)[1..-1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def processor
|
36
|
+
@processor ||= Thumbkit::Processor.processor_for(type)
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_thumbnail(outfile = nil, options = {})
|
40
|
+
processor.new(path, outfile, options).write
|
41
|
+
end
|
42
|
+
end
|
Binary file
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Capital letters
|
2
|
+
Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω
|
3
|
+
Capital letters with tonos
|
4
|
+
Ά Έ Ή Ί Ό Ύ Ώ
|
5
|
+
Capital letters with dialytika
|
6
|
+
Ϊ Ϋ
|
7
|
+
Small letters
|
8
|
+
α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σς τ υ φ χ ψ ω
|
9
|
+
Small letters with tonos
|
10
|
+
ά έ ή ί ό ύ ώ
|
11
|
+
Small letters with dialytika
|
12
|
+
ϊ ϋ
|
13
|
+
Small letters with dialytika and tonos
|
14
|
+
ΐ ΰ
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Hebrew
|
2
|
+
|
3
|
+
Hebrew alphabet
|
4
|
+
’ b g d h w z H T y kk l mm nn s ‘ pp cc q r š ś t
|
5
|
+
א ב ג ד ה ו ז ח ט י כך ל מם נן ס ע פף צץ ק ר שׁ שׂ ת
|
6
|
+
Letters with dagesh or mapiq
|
7
|
+
’ b g d h w z T y kk l m n s pp c q r š ś t
|
8
|
+
אּ בּ גּ דּ הּ וּ זּ טּ יּ כּךּ לּ מּ נּ סּ פּףּ צּ קּ רּ שּׁ שּׂ תּ
|
9
|
+
Yiddish digraphs
|
10
|
+
ww wy yy
|
11
|
+
װ ױ ײ
|
12
|
+
Letters with rafeh
|
13
|
+
v x f
|
14
|
+
בֿ כֿ פֿ
|
15
|
+
Vowels with points
|
16
|
+
a å o u i ai
|
17
|
+
אַ אָ וֹ וּ יִ ײַ
|
Binary file
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
An Example Text File
|
2
|
+
|
3
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
4
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
5
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
6
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
7
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
8
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
9
|
+
|
10
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
11
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
12
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
13
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
14
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
15
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'thumbkit'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
def path_to_fixture(fixture_name)
|
7
|
+
Pathname.new("spec/fixtures").join(fixture_name).expand_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def tmp_path
|
11
|
+
Pathname.new("spec/tmp")
|
12
|
+
end
|
13
|
+
|
14
|
+
def path_for_output(outfile = '')
|
15
|
+
tmp_path.join(outfile).expand_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ImageMacros
|
20
|
+
def its_size_should_be(size)
|
21
|
+
it "its size should be #{ size }" do
|
22
|
+
r = `identify -ping -quiet -format "%wx%h" "#{subject}"`.chomp
|
23
|
+
r.should == size
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def its_mimetype_should_be(mime)
|
28
|
+
it "its mime type should be #{ mime }" do
|
29
|
+
m = `file --mime-type -n -N "#{ subject }"|cut -d' ' -f2`.chomp
|
30
|
+
m.should == mime
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
RSpec.configure do |config|
|
36
|
+
config.extend ImageMacros
|
37
|
+
config.include Helpers
|
38
|
+
|
39
|
+
def mkdir_safe(dir)
|
40
|
+
Dir.mkdir(dir)
|
41
|
+
rescue Errno::EEXIST
|
42
|
+
# Great, it's already there.
|
43
|
+
end
|
44
|
+
|
45
|
+
config.around(:each) do |example|
|
46
|
+
mkdir_safe tmp_path.to_s
|
47
|
+
example.run
|
48
|
+
FileUtils.rm_rf(tmp_path.to_s) unless File.exist?(tmp_path.join('.keep').to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit::Options do
|
4
|
+
describe '#merge' do
|
5
|
+
it "does a deep merge" do
|
6
|
+
h1 = { x: { y: [4, 5, 6], z: [7, 8, 9], a: 'abar' } }
|
7
|
+
h2 = { x: { y: [1, 2, 3], z: 'xyz', b: { c: 'd' } } }
|
8
|
+
defaults = Thumbkit::Options.new(h1)
|
9
|
+
defaults.merge(h2).should == {
|
10
|
+
x: {
|
11
|
+
y: [1, 2, 3],
|
12
|
+
z: 'xyz',
|
13
|
+
a: 'abar',
|
14
|
+
b: { c: 'd' },
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it "does an even deeper merge" do
|
20
|
+
# NOTE: These options resemble, but don't actually reflect the available
|
21
|
+
# options for Thumbkit.
|
22
|
+
h1 = { colors: { background: 'blue' }, font: { family: { name: 'Helvetica', weight: 'bold' } } }
|
23
|
+
h2 = { colors: { foreground: 'black' }, font: { family: { weight: 'light', transform: 'small-caps' } } }
|
24
|
+
defaults = Thumbkit::Options.new(h1)
|
25
|
+
defaults.merge(h2).should == {
|
26
|
+
colors: {
|
27
|
+
background: 'blue',
|
28
|
+
foreground: 'black',
|
29
|
+
},
|
30
|
+
font: {
|
31
|
+
family: {
|
32
|
+
name: 'Helvetica',
|
33
|
+
weight: 'light',
|
34
|
+
transform: 'small-caps',
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit::Processor::Audio do
|
4
|
+
|
5
|
+
let(:fixture) { '16Hz-20kHz-Exp-1f-5sec.mp3' }
|
6
|
+
let(:path) { File.expand_path(path_to_fixture(fixture)) }
|
7
|
+
let(:outfile) { nil }
|
8
|
+
let(:options) { {} }
|
9
|
+
let(:processor) { Thumbkit::Processor::Audio.new(path, outfile, options) }
|
10
|
+
subject { processor }
|
11
|
+
|
12
|
+
its(:path) { should == path }
|
13
|
+
|
14
|
+
describe '#auto_outflie' do
|
15
|
+
subject { processor.outfile }
|
16
|
+
context 'when nothing specified' do
|
17
|
+
it { should == File.expand_path(path_to_fixture('16Hz-20kHz-Exp-1f-5sec.png')) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# context 'with an extensionless outfile' do
|
21
|
+
# let(:outfile) { 'foo.' }
|
22
|
+
# it { should == 'foo.png' }
|
23
|
+
# end
|
24
|
+
|
25
|
+
# Not sure what to do in this case. Waveform just outputs a png file no
|
26
|
+
# matter what...
|
27
|
+
#
|
28
|
+
# context 'with a jpg specified' do
|
29
|
+
# let(:outfile) { path_for_output('audio-test.jpg').to_s }
|
30
|
+
# before { processor.write }
|
31
|
+
# it { should == path_for_output('audio_test.jpg').to_s }
|
32
|
+
# end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#write' do
|
36
|
+
let(:outfile) { path_for_output('audio-test.png').to_s }
|
37
|
+
subject { processor.write }
|
38
|
+
|
39
|
+
it 'returns the path of the outfile' do
|
40
|
+
subject.should == outfile
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'writes a file' do
|
44
|
+
File.should exist(subject)
|
45
|
+
end
|
46
|
+
|
47
|
+
its_size_should_be('200x200')
|
48
|
+
|
49
|
+
context 'with size settings' do
|
50
|
+
let(:outfile) { path_for_output('audio-test-300x250.png').to_s }
|
51
|
+
# Let's change a few settings for manual inspection
|
52
|
+
let(:options) { { width: 300, height: 250, colors: { background: :transparent, foreground: '#ffeecc' } } }
|
53
|
+
|
54
|
+
its_size_should_be('300x250')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit::Processor::Image do
|
4
|
+
|
5
|
+
let(:fixture) { 'png_file.png' }
|
6
|
+
let(:path) { File.expand_path(path_to_fixture(fixture)) }
|
7
|
+
let(:outfile) { nil }
|
8
|
+
let(:options) { {} }
|
9
|
+
let(:processor) { Thumbkit::Processor::Image.new(path, outfile, options) }
|
10
|
+
subject { processor }
|
11
|
+
|
12
|
+
its(:path) { should == path }
|
13
|
+
|
14
|
+
describe '#auto_outflie' do
|
15
|
+
subject { processor.outfile }
|
16
|
+
context 'when nothing specified' do
|
17
|
+
it { should == File.expand_path(path_to_fixture('png_file.png')) }
|
18
|
+
|
19
|
+
context 'when the fixture is a jpeg' do
|
20
|
+
let(:fixture) { 'jpg_file.jpg' }
|
21
|
+
it { should == File.expand_path(path_to_fixture('jpg_file.jpg')) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# context 'with an extensionless outfile' do
|
26
|
+
# let(:outfile) { 'foo.' }
|
27
|
+
# it { should == 'foo.png' }
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#write' do
|
32
|
+
let(:outfile) { path_for_output('png_file.png').to_s }
|
33
|
+
subject { processor.write }
|
34
|
+
|
35
|
+
it 'returns the path of the outfile' do
|
36
|
+
subject.should == outfile
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'writes a file' do
|
40
|
+
File.should exist(subject)
|
41
|
+
end
|
42
|
+
|
43
|
+
its_size_should_be('200x200')
|
44
|
+
its_mimetype_should_be('image/png')
|
45
|
+
|
46
|
+
context 'with size settings' do
|
47
|
+
let(:outfile) { path_for_output('resize_test_300x250.png').to_s }
|
48
|
+
# Let's change a few settings for manual inspection
|
49
|
+
let(:options) { { width: 300, height: 250 } }
|
50
|
+
|
51
|
+
its_size_should_be('300x250')
|
52
|
+
its_mimetype_should_be('image/png')
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with size and gravity settings' do
|
56
|
+
let(:outfile) { path_for_output('resize_test_southwest_300x100.png').to_s }
|
57
|
+
# Let's change a few settings for manual inspection
|
58
|
+
let(:options) { { width: 300, height: 100, gravity: 'SouthWest' } }
|
59
|
+
|
60
|
+
its_size_should_be('300x100')
|
61
|
+
its_mimetype_should_be('image/png')
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
context 'with size settings larger than the image' do
|
66
|
+
let(:outfile) { path_for_output('resize_test_600x600.png').to_s }
|
67
|
+
# Let's change a few settings for manual inspection
|
68
|
+
let(:options) { { width: 600, height: 600 } }
|
69
|
+
|
70
|
+
its_size_should_be('600x600')
|
71
|
+
its_mimetype_should_be('image/png')
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with a jpg file' do
|
75
|
+
let(:outfile) { path_for_output('jpg_file.jpg').to_s }
|
76
|
+
it { should == path_for_output('jpg_file.jpg').to_s }
|
77
|
+
its_size_should_be('200x200')
|
78
|
+
its_mimetype_should_be('image/jpeg')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit::Processor::Text do
|
4
|
+
|
5
|
+
let(:fixture) { 'text_file.txt' }
|
6
|
+
let(:path) { File.expand_path(path_to_fixture(fixture)) }
|
7
|
+
let(:outfile) { nil }
|
8
|
+
let(:options) { {} }
|
9
|
+
let(:processor) { Thumbkit::Processor::Text.new(path, outfile, options) }
|
10
|
+
subject { processor }
|
11
|
+
|
12
|
+
its(:path) { should == path }
|
13
|
+
|
14
|
+
|
15
|
+
describe '#auto_outflie' do
|
16
|
+
subject { processor.outfile }
|
17
|
+
context 'when nothing specified' do
|
18
|
+
it { should == File.expand_path(path_to_fixture('text_file.png')) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# context 'with an extensionless outfile' do
|
22
|
+
# let(:outfile) { 'foo.' }
|
23
|
+
# it { should == 'foo.png' }
|
24
|
+
# end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#write' do
|
28
|
+
let(:outfile) { path_for_output('text-test.png').to_s }
|
29
|
+
subject { processor.write }
|
30
|
+
|
31
|
+
it 'returns the path of the outfile' do
|
32
|
+
subject.should == outfile
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns the name of the outfile' do
|
36
|
+
File.basename(subject).should == 'text-test.png'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'writes a file' do
|
40
|
+
File.should exist(subject)
|
41
|
+
end
|
42
|
+
|
43
|
+
its_size_should_be('200x200')
|
44
|
+
its_mimetype_should_be('image/png')
|
45
|
+
|
46
|
+
context 'with size settings' do
|
47
|
+
let(:outfile) { path_for_output('text-test-300x250.png').to_s }
|
48
|
+
# Let's change a few settings for manual inspection
|
49
|
+
let(:options) { { width: 300, height: 250, colors: { background: :transparent, foreground: '#334455' } } }
|
50
|
+
|
51
|
+
its_size_should_be('300x250')
|
52
|
+
its_mimetype_should_be('image/png')
|
53
|
+
# Manually check the file to verify colors
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with gravity settings' do
|
57
|
+
let(:outfile) { path_for_output('text-test-northeast-150x250.png').to_s }
|
58
|
+
# Let's change a few settings for manual inspection
|
59
|
+
let(:options) { {
|
60
|
+
width: 150, height: 250, gravity: 'NorthEast',
|
61
|
+
colors: { background: :transparent, foreground: '#334455' }
|
62
|
+
} }
|
63
|
+
|
64
|
+
its_size_should_be('150x250')
|
65
|
+
its_mimetype_should_be('image/png')
|
66
|
+
# Manually check the file to verify colors and gravity
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'with some greek letters' do
|
70
|
+
let(:fixture) { 'greek.txt' }
|
71
|
+
let(:outfile) { path_for_output('greek.png').to_s }
|
72
|
+
it('writes a file') { File.should exist(subject) }
|
73
|
+
it('autodetects left-to-right') { processor.__send__(:direction).should == 'left-to-right' }
|
74
|
+
its_size_should_be('200x200')
|
75
|
+
its_mimetype_should_be('image/png')
|
76
|
+
# Manually check the file to verify unicode stuff worked
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with an arabic file' do
|
80
|
+
let(:options) { { font: { direction: :auto } } }
|
81
|
+
let(:fixture) { 'arabic.txt' }
|
82
|
+
let(:outfile) { path_for_output('arabic.png').to_s }
|
83
|
+
it('writes a file') { File.should exist(subject) }
|
84
|
+
it('autodetects right-to-left') { processor.__send__(:direction).should == 'right-to-left' }
|
85
|
+
its_size_should_be('200x200')
|
86
|
+
its_mimetype_should_be('image/png')
|
87
|
+
# Manually check the file to verify unicode stuff and right-to-left worked
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with an hebrew file' do
|
91
|
+
let(:options) { { font: { direction: 'right-to-left', size: '12' }, width: 400 } }
|
92
|
+
let(:fixture) { 'hebrew.txt' }
|
93
|
+
let(:outfile) { path_for_output('hebrew.png').to_s }
|
94
|
+
it('writes a file') { File.should exist(subject) }
|
95
|
+
it('is right-to-left') { processor.__send__(:direction).should == 'right-to-left' }
|
96
|
+
its_size_should_be('400x200')
|
97
|
+
its_mimetype_should_be('image/png')
|
98
|
+
# Manually check the file to verify unicode stuff and right-to-left worked
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
context 'with an arabic file to output to jpg' do
|
103
|
+
let(:options) { { width: 600, height: 400 } }
|
104
|
+
let(:fixture) { 'arabic.txt' }
|
105
|
+
let(:outfile) { path_for_output('arabic.jpg').to_s }
|
106
|
+
it('writes a file') { File.should exist(subject) }
|
107
|
+
it('autodetects right-to-left') { processor.__send__(:direction).should == 'right-to-left' }
|
108
|
+
its_size_should_be('600x400')
|
109
|
+
its_mimetype_should_be('image/jpeg')
|
110
|
+
# Manually check the file to verify unicode stuff and right-to-left worked
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit::Processor do
|
4
|
+
describe '.processor_for' do
|
5
|
+
subject { Thumbkit::Processor.processor_for(extension) }
|
6
|
+
context 'for a .txt' do
|
7
|
+
let(:extension) { 'txt' }
|
8
|
+
it { should == Thumbkit::Processor::Text }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'for a .mp3' do
|
12
|
+
let(:extension) { 'mp3' }
|
13
|
+
it { should == Thumbkit::Processor::Audio }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.force_extension' do
|
18
|
+
let(:extension) { 'png' }
|
19
|
+
subject { Thumbkit::Processor.force_extension path, extension }
|
20
|
+
context 'given an mp3 file' do
|
21
|
+
let(:path) { 'foo/bar/blah.mp3' }
|
22
|
+
it { should == 'foo/bar/blah.png' }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#initialize' do
|
27
|
+
let(:options) { {} }
|
28
|
+
subject { Thumbkit::Processor.new('infile.png', 'outfile.png', options) }
|
29
|
+
|
30
|
+
context 'with no options' do
|
31
|
+
its(:options) { should == Thumbkit.defaults }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with some overrides' do
|
35
|
+
let(:options) { { width: 250, height: 250 } }
|
36
|
+
|
37
|
+
it 'overrides the options' do
|
38
|
+
subject.options[:width].should == 250
|
39
|
+
subject.options[:height].should == 250
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'but leaves others' do
|
43
|
+
subject.options[:colors].should == Thumbkit.defaults[:colors]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Thumbkit do
|
4
|
+
context 'a .txt file' do
|
5
|
+
subject { Thumbkit.new path_to_fixture('text_file.txt') }
|
6
|
+
|
7
|
+
its(:filename) { should == 'text_file.txt' }
|
8
|
+
its(:path) { should == File.expand_path(path_to_fixture('text_file.txt')) }
|
9
|
+
its(:processor) { should == Thumbkit::Processor::Text }
|
10
|
+
its(:type) { should == 'txt' }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with a .mp3 file' do
|
14
|
+
subject { Thumbkit.new path_to_fixture('16Hz-20kHz-Exp-1f-5sec.mp3') }
|
15
|
+
|
16
|
+
its(:filename) { should == '16Hz-20kHz-Exp-1f-5sec.mp3' }
|
17
|
+
its(:path) { should == File.expand_path(path_to_fixture('16Hz-20kHz-Exp-1f-5sec.mp3')) }
|
18
|
+
its(:processor) { should == Thumbkit::Processor::Audio }
|
19
|
+
its(:type) { should == 'mp3' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
describe Thumbkit, '.defaults' do
|
25
|
+
subject { Thumbkit.defaults }
|
26
|
+
|
27
|
+
it 'returns defaults for colors' do
|
28
|
+
subject.should have_key(:colors)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns defaults for font' do
|
32
|
+
subject.should have_key(:font)
|
33
|
+
end
|
34
|
+
end
|
data/thumbkit.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/thumbkit/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Amiel Martin"]
|
6
|
+
gem.email = ["amiel@carnesmedia.com"]
|
7
|
+
gem.description = %q{Thumbkit makes thumbnails!}
|
8
|
+
gem.summary = %q{Thumbkit makes thumbnails from a variety of media types. Planned: Audio, Text, Image, and Video.}
|
9
|
+
gem.homepage = "http://github.com/carnesmedia/thumbkit"
|
10
|
+
|
11
|
+
# TODO: Remove dependency on git
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "thumbkit"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Thumbkit::VERSION
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thumbkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Amiel Martin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Thumbkit makes thumbnails!
|
15
|
+
email:
|
16
|
+
- amiel@carnesmedia.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- Guardfile
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- lib/thumbkit.rb
|
28
|
+
- lib/thumbkit/options.rb
|
29
|
+
- lib/thumbkit/processor.rb
|
30
|
+
- lib/thumbkit/processor/audio.rb
|
31
|
+
- lib/thumbkit/processor/image.rb
|
32
|
+
- lib/thumbkit/processor/text.rb
|
33
|
+
- lib/thumbkit/version.rb
|
34
|
+
- spec/fixtures/16Hz-20kHz-Exp-1f-5sec.mp3
|
35
|
+
- spec/fixtures/arabic.txt
|
36
|
+
- spec/fixtures/greek.txt
|
37
|
+
- spec/fixtures/hebrew.txt
|
38
|
+
- spec/fixtures/jpg_file.jpg
|
39
|
+
- spec/fixtures/png_file.png
|
40
|
+
- spec/fixtures/text_file.txt
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- spec/thumbkit/options_spec.rb
|
43
|
+
- spec/thumbkit/processor/audio_spec.rb
|
44
|
+
- spec/thumbkit/processor/image_spec.rb
|
45
|
+
- spec/thumbkit/processor/text_spec.rb
|
46
|
+
- spec/thumbkit/processor_spec.rb
|
47
|
+
- spec/thumbkit_spec.rb
|
48
|
+
- thumbkit.gemspec
|
49
|
+
homepage: http://github.com/carnesmedia/thumbkit
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.15
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: ! 'Thumbkit makes thumbnails from a variety of media types. Planned: Audio,
|
73
|
+
Text, Image, and Video.'
|
74
|
+
test_files:
|
75
|
+
- spec/fixtures/16Hz-20kHz-Exp-1f-5sec.mp3
|
76
|
+
- spec/fixtures/arabic.txt
|
77
|
+
- spec/fixtures/greek.txt
|
78
|
+
- spec/fixtures/hebrew.txt
|
79
|
+
- spec/fixtures/jpg_file.jpg
|
80
|
+
- spec/fixtures/png_file.png
|
81
|
+
- spec/fixtures/text_file.txt
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
- spec/thumbkit/options_spec.rb
|
84
|
+
- spec/thumbkit/processor/audio_spec.rb
|
85
|
+
- spec/thumbkit/processor/image_spec.rb
|
86
|
+
- spec/thumbkit/processor/text_spec.rb
|
87
|
+
- spec/thumbkit/processor_spec.rb
|
88
|
+
- spec/thumbkit_spec.rb
|
89
|
+
has_rdoc:
|