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 ADDED
@@ -0,0 +1,12 @@
1
+ .DS_Store
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ Gemfile.lock
7
+ coverage
8
+ doc/
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ tmp
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,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,3 @@
1
+ class Thumbkit
2
+ VERSION = "0.0.2"
3
+ 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
@@ -0,0 +1,7 @@
1
+ أَبْجَدِيَّة عَرَبِيَّة‎
2
+
3
+ ا ب ت ث ج ح
4
+ خ د ذ ر ز س
5
+ ش ص ض ط ظ ع
6
+ غ ف ق ك ل
7
+ م ن ه و ي
@@ -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.
@@ -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: