rmagick-screwdrivers 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: f6996c1d9295fecc5d2593702cd00ccac473d47e
4
+ data.tar.gz: 1f900b09343ae483b734ade275a4e597be363f41
5
+ !binary "U0hBNTEy":
6
+ metadata.gz: f7ecfdf5c4f190b0e533a6f7ba78873006dd1577460d024db7d86dca6531a9b758e9e935628021935f7b0d8258f4ca1ef6a25c6123d961bede2fa2cd1187321e
7
+ data.tar.gz: 9fb72a166559f83c45f5c684c2111414031f54658fbfd114a3b36ff7006f43e2b88248a65cf03bf64bc69fc6f8eceb4dae63233f327067d85ffcc6d81d0c9d1d
@@ -0,0 +1,11 @@
1
+ # .document is used by rdoc and yard to know how to generate documentation
2
+ # for example, it can be used to control how rdoc gets built when you do `gem install foo`
3
+
4
+ README.rdoc
5
+ lib/**/*.rb
6
+ bin/*
7
+
8
+ # Files below this - are treated as 'extra files', and aren't parsed for ruby code
9
+ -
10
+ features/**/*.feature
11
+ LICENSE
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rmagick-screwdrivers.gemspec
4
+ gemspec
5
+
6
+ gem "rspec-core", :git => 'git://github.com/rspec/rspec-core.git'
7
+ gem "rspec-expectations", :path => '../rspec-expectations'
8
+ gem "rspec-mocks", :git => 'git://github.com/rspec/rspec-mocks.git'
9
+ gem "rspec-support", :git => 'git://github.com/rspec/rspec-support.git'
10
+ gem "rspec", :git => 'git://github.com/rspec/rspec.git'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Alexei Matyushkin
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # Rmagick::Screwdrivers
2
+
3
+ Simple set of classes and their binary wrappers to make routine operations
4
+ with RMagick pleasant:
5
+
6
+ * **scale** — to scale an image to a set of scaled images with optional
7
+ watermark (text and/or date) applied
8
+ * method: `Magick::Screwdrivers.scale`
9
+ * binary: `bin/rmagick_scale`
10
+
11
+ * **collage** — to produce a collage of a directory with images
12
+ * method: `Magick::Screwdrivers.collage`
13
+ * binary: `bin/rmagick_collage`
14
+
15
+ * **poster** — to produce a poster from an image (a.k.a demotivator)
16
+ * method: `Magick::Screwdrivers.poster`
17
+ * binary: `bin/rmagick_poster`
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ gem 'rmagick-screwdrivers'
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or simply install the gem for binary usage:
30
+
31
+ gem install rmagick-screwdrivers
32
+
33
+ and make heavy use of it:
34
+
35
+ $ magick_collage --help
36
+ $ magick_poster -v --font DejaVuSans --type classic ~/img/img1.jpg 'Hello,' 'I’m a poster'
37
+
38
+ ## Usage
39
+
40
+ $ magick_poster --help
41
+ $ magick_scale --help
42
+ $ magick_collage --help
43
+
44
+ ## Contributing
45
+
46
+ 1. Fork it
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. Create new Pull Request
51
+
@@ -0,0 +1,23 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'bueller'
4
+ Bueller::Tasks.new
5
+ Bueller::GemcutterTasks.new
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:examples) do |examples|
9
+ examples.rspec_opts = '-Ispec'
10
+ end
11
+
12
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
13
+ spec.rspec_opts = '-Ispec'
14
+ spec.rcov = true
15
+ end
16
+
17
+ require 'cucumber/rake/task'
18
+ Cucumber::Rake::Task.new(:features)
19
+
20
+ task :default => :examples
21
+
22
+ require 'yard'
23
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
6
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
7
+
8
+ require 'rmagick/screwdrivers'
9
+
10
+ # options = {
11
+ # :columns => 5,
12
+ # :scale_range => 0.1,
13
+ # :thumb_width => 120,
14
+ # :rotate_angle => 20,
15
+ # :background => 'white',
16
+ # :border => '#DDDDDD',
17
+ # :logger => nil
18
+ # }.merge(options)
19
+
20
+ options = {}
21
+ OptionParser.new do |opts|
22
+ opts.banner = "Usage: #{$0} [options] FILE|DIR [DIR]"
23
+
24
+ # Verbose?
25
+ opts.on("-v", "--verbose", "Run verbosely (default: false)") do |v|
26
+ if v
27
+ require 'logger'
28
+ options[:logger] = Logger.new STDOUT
29
+ end
30
+ end
31
+ # Quality
32
+ opts.on("-q", "--quality [1-100]", Integer, "Quality of resulting JPEG (default: 90)") do |quality|
33
+ options[:quality] = quality
34
+ end
35
+ # Columns
36
+ opts.on("-c", "--columns COLS", Integer, "Number of columns in collage (default: 5)") do |cols|
37
+ options[:columns] = cols
38
+ end
39
+ # Maximal ± of thumbnail size (random(-s,+s))
40
+ opts.on("-s", "--scale-range VAL", Float, "Maximal ± of standard thumbnail size (default: 0.1)") do |scale_range|
41
+ options[:scale_range] = scale_range
42
+ end
43
+ # Thumbnail standard width
44
+ opts.on("-t", "--thumbsize SIZE", "Thumbnail standard width (default: 120)") do |thumb_width|
45
+ options[:thumb_width] = thumb_width
46
+ end
47
+ # Maximal angle to rotate thumbnails
48
+ opts.on("-a", "--rotate-angle ANGLE", "Maximal angle to rotate thumbnails (default: 20°)") do |rotate_angle|
49
+ options[:rotate_angle] = rotate_angle
50
+ end
51
+ # Background color
52
+ opts.on("-b", "--background COLOR", "Background color (default: 'white')") do |background|
53
+ options[:background] = background
54
+ end
55
+ # Foreground color
56
+ opts.on("-f", "--foreground COLOR", "Border color (default: '#DDDDDD')") do |foreground|
57
+ options[:border] = foreground
58
+ end
59
+
60
+ # No argument, shows at tail. This will print an options summary.
61
+ opts.on_tail("-h", "--help", "Show this message") do
62
+ puts opts
63
+ exit
64
+ end
65
+
66
+ end.parse!
67
+
68
+ raise "Run `#{$0} --help` for execution examples. Exiting…" if ARGV.size.zero? || ARGV.size > 2
69
+
70
+ file = ARGV.first
71
+ dir = ARGV.size == 2 ? ARGV.last : File.dirname(file)
72
+ `mkdir -p #{dir}`
73
+
74
+ outfile = File.basename(file).sub(/$/, "-collage.jpg")
75
+ Magick::Screwdrivers::collage(file, options).write(File.join dir, outfile) {
76
+ self.quality = options[:quality] || 90
77
+ }
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
6
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
7
+
8
+ require 'rmagick/screwdrivers'
9
+
10
+ # options = {
11
+ # :color => '#FFFFFF',
12
+ # :stroke => nil,
13
+ # :width => 600,
14
+ # :type => :classic, # :classic for black square around
15
+ # :lineheight => 6,
16
+ # :background => '#000000',
17
+ # :font => '/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf',
18
+ # :logger => nil
19
+ # }.merge(options)
20
+
21
+ options = {}
22
+ FONT_PATH = "/usr/share/fonts/truetype/*/**"
23
+ OptionParser.new do |opts|
24
+ opts.banner = "Usage: #{$0} [options] FILE TEXT1 TEXT2 [DIR]"
25
+
26
+ # Verbose?
27
+ opts.on("-v", "--verbose", "Run verbosely (default: false)") do |v|
28
+ if v
29
+ require 'logger'
30
+ options[:logger] = Logger.new STDOUT
31
+ end
32
+ end
33
+ # Quality
34
+ opts.on("-q", "--quality [1-100]", Integer, "Quality of resulting JPEG (default: 90)") do |quality|
35
+ options[:quality] = quality
36
+ end
37
+ # Color
38
+ opts.on("-c", "--color CLR", "Color of title (default: '#FFFFFF')") do |color|
39
+ options[:color] = color
40
+ end
41
+ # Stroke
42
+ opts.on("-s", "--stroke CLR", "Stroke color (default: nil)") do |stroke|
43
+ options[:stroke] = stroke
44
+ end
45
+ # Width
46
+ opts.on("-w", "--width PIXELS", Integer, "Width to scale image to (default: 600)") do |width|
47
+ options[:width] = w
48
+ end
49
+
50
+ # Type of poster (with keyword completion).
51
+ opts.on("-t", "--type TYPE", [:standard, :classic, :negative],
52
+ "Poster type (standard, classic, negative), default: classic") do |type|
53
+ options[:type] = type
54
+ end
55
+
56
+ # Border width
57
+ opts.on("-r", "--border SIZE", Integer,
58
+ "Size of border around poster (default: 6)") do |border|
59
+ options[:lineheight] = border
60
+ end
61
+
62
+ # Background color
63
+ opts.on("-b", "--background CLR", "Background color (default: black)") do |background|
64
+ options[:background] = background
65
+ end
66
+
67
+ # Font
68
+ opts.on("-f", "--font FONT",
69
+ "Registered with ImageMagick font, or full path to font file (default: Ubuntu-B.ttf)") do |font|
70
+ options[:font] = font
71
+ end
72
+
73
+ # No argument, shows at tail. This will print an options summary.
74
+ opts.on_tail("-h", "--help", "Show this message") do
75
+ puts opts
76
+ exit
77
+ end
78
+
79
+ end.parse!
80
+
81
+ raise "Run `#{$0} --help` for execution examples. Exiting…" if ARGV.size < 3
82
+
83
+ if options[:font]
84
+ unless File.exist?(options[:font])
85
+ options[:font] = Dir.glob(FONT_PATH).each { |f|
86
+ break f if File.basename(f) =~ /#{options[:font]}/
87
+ }
88
+ end
89
+ end
90
+ unless options[:font]
91
+ ttfs = Dir.glob(FONT_PATH)
92
+ options[:font] = %w(Ubuntu-B.ttf FreeSans.ttf).each { |ff|
93
+ result = ttfs.select { |f| File.basename(f) =~ /#{ff}/ }
94
+ break result.first unless result.empty?
95
+ }
96
+ end
97
+
98
+ Magick::Screwdrivers.info options[:logger], "Font #{options[:font] || DEFAULT} was chosen"
99
+
100
+ file = ARGV.shift
101
+ text1 = ARGV.shift
102
+ text2 = ARGV.shift
103
+ dir = ARGV.size.zero? ? File.dirname(file) : ARGV.last
104
+ `mkdir -p #{dir}`
105
+
106
+ outfile = File.basename(file).sub(/(\.\w+)$/, "-poster\\1")
107
+ Magick::Screwdrivers::poster(file, text1, text2, options).write(File.join dir, outfile) {
108
+ self.quality = options[:quality] || 90
109
+ }
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
6
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
7
+
8
+ require 'rmagick/screwdrivers'
9
+
10
+ # options = {
11
+ # :widths => 600,
12
+ # :date_in_watermark => false,
13
+ # :watermark => nil,
14
+ # :logger => nil
15
+ # }.merge(options)
16
+
17
+ options = {}
18
+ OptionParser.new do |opts|
19
+ opts.banner = "Usage: #{$0} [options] FILE [DIR]"
20
+
21
+ # Verbose?
22
+ opts.on("-v", "--verbose", "Run verbosely (default: false)") do |v|
23
+ if v
24
+ require 'logger'
25
+ options[:logger] = Logger.new STDOUT
26
+ end
27
+ end
28
+ # Quality
29
+ opts.on("-q", "--quality [1-100]", Integer, "Quality of resulting JPEG (default: 90)") do |quality|
30
+ options[:quality] = quality
31
+ end
32
+ # Widths
33
+ opts.on("-w", "--widths X,Y,Z", Array, "Widths of scaled images (default: 600)") do |widths|
34
+ options[:widths] = widths.map(&:to_i) - [0]
35
+ end
36
+ # Puts date on watermark?
37
+ opts.on("-d", "--date_in_watermark", "Append date to watermark (default: false)") do |dow|
38
+ options[:date_in_watermark] = dow
39
+ end
40
+ # Watermark text
41
+ opts.on("-m", "--watermark TEXT", "Text to use as watermark (default: none)") do |w|
42
+ options[:watermark] = w
43
+ end
44
+
45
+ # No argument, shows at tail. This will print an options summary.
46
+ opts.on_tail("-h", "--help", "Show this message") do
47
+ puts opts
48
+ exit
49
+ end
50
+
51
+ end.parse!
52
+
53
+ raise "Run `#{$0} --help` for execution examples. Exiting…" if ARGV.size.zero? || ARGV.size > 2
54
+
55
+ file = ARGV.first
56
+ dir = ARGV.size == 2 ? ARGV.last : File.dirname(file)
57
+ `mkdir -p #{dir}`
58
+
59
+ Magick::Screwdrivers::scale(file, options).each { |img|
60
+ outfile = File.basename(file).sub(/(\.\w+)$/, "-#{img.rows}×#{img.columns}\\1")
61
+ img.write(File.join dir, outfile) {
62
+ self.quality = options[:quality] || 90
63
+ }
64
+ }
@@ -0,0 +1,47 @@
1
+ Feature: Handy utilities for processing images
2
+ In order to make RMagick kinda command-line utility
3
+ We want to provide some handy utility methods
4
+
5
+ Scenario: folder of images may be processed to make a collage
6
+ Given a folder "data/images" is given as the input
7
+ And an output folder "data/results" is created
8
+ When I call the collage method
9
+ And save file to "data/results/collage.jpg"
10
+ Then the result is created as "data/results/collage.jpg"
11
+
12
+ Scenario: image scaling with optional watermark
13
+ Given an image "data/images/DSCF1354.JPG" is given as the input
14
+ And an output folder "data/results" is created
15
+ And everything is logged
16
+ When I call the scale method with widths 800,600,150
17
+ And save files with origin "data/results/scaled"
18
+ Then the result is created as an array of size 3
19
+
20
+ Scenario: create standard demotivator from image
21
+ Given an image "data/images/DSCF1354.JPG" is given as the input
22
+ And "standard" is given as poster type option
23
+ And an output folder "data/results" is created
24
+ And everything is logged
25
+ When I call the poster method with texts "Hello, there" and "I’m a demotivator"
26
+ And save file to "data/results/demotivator-standard.jpg"
27
+ Then the result is created as "data/results/demotivator-standard.jpg"
28
+
29
+ Scenario: create classic demotivator from image
30
+ Given an image "data/images/DSCF1354.JPG" is given as the input
31
+ And "classic" is given as poster type option
32
+ And an output folder "data/results" is created
33
+ And everything is logged
34
+ When I call the poster method with texts "Hello, there" and "I’m a demotivator"
35
+ And save file to "data/results/demotivator-classic.jpg"
36
+ Then the result is created as "data/results/demotivator-classic.jpg"
37
+
38
+ Scenario: create negative demotivator from image
39
+ Given an image "data/images/DSCF1354.JPG" is given as the input
40
+ And "negative" is given as poster type option
41
+ And an output folder "data/results" is created
42
+ And everything is logged
43
+ When I call the poster method with texts "Hello, there" and "I’m a demotivator"
44
+ And save file to "data/results/demotivator-negative.jpg"
45
+ Then the result is created as "data/results/demotivator-negative.jpg"
46
+
47
+
@@ -0,0 +1,64 @@
1
+ Given(/^a folder "(.*?)" is given as the input$/) do |dir|
2
+ @input = dir
3
+ end
4
+
5
+ Given(/^an image "(.*?)" is given as the input$/) do |file|
6
+ @input = file
7
+ @options = {}
8
+ end
9
+
10
+ Given(/^an output folder "(.*?)" is created$/) do |dir|
11
+ Dir.mkdir dir rescue "Directory exists, continue…"
12
+ end
13
+
14
+ Given(/^everything is logged$/) do
15
+ require 'logger'
16
+ @logger = Logger.new STDOUT
17
+ end
18
+
19
+ Given(/^"(.*?)" is given as poster type option$/) do |type|
20
+ @options[:type] = type.to_sym
21
+ @options[:stroke] = '#000000' if @options[:type] == :standard
22
+ end
23
+
24
+ # ===================================================================================
25
+
26
+ When(/^I call the collage method$/) do
27
+ @output = Magick::Screwdrivers::collage @input, {:logger => @logger}
28
+ end
29
+
30
+ When(/^I call the scale method with widths (\d+),(\d+),(\d+)$/) do |arg1, arg2, arg3|
31
+ opts = {
32
+ :logger => @logger,
33
+ :widths => [arg1.to_i,arg2.to_i,arg3.to_i],
34
+ :date_in_watermark => true,
35
+ :watermark => 'rmagick-screwdrivers'
36
+ }
37
+ @output = Magick::Screwdrivers::scale @input, opts
38
+ end
39
+
40
+ When(/^save file to "(.*?)"$/) do |file|
41
+ @output.write File.join(file)
42
+ end
43
+
44
+ When(/^save files with origin "(.*?)"$/) do |orig|
45
+ @output.each { |img|
46
+ img.write("#{orig}-#{img.rows}.#{img.format.downcase}") { self.quality = 90 }
47
+ }
48
+ end
49
+
50
+ When(/^I call the poster method with texts "(.*?)" and "(.*?)"$/) do |text1, text2|
51
+ @options[:logger] = @logger
52
+ @output = Magick::Screwdrivers::poster @input, text1, text2, @options
53
+ end
54
+
55
+
56
+ # ===================================================================================
57
+
58
+ Then(/^the result is created as "(.*?)"$/) do |img|
59
+ expect(@output.inspect).to match(/#{img}/)
60
+ end
61
+
62
+ Then(/^the result is created as an array of size (\d+)$/) do |arg1|
63
+ expect(@output.size).to eql(3)
64
+ end
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'rmagick/screwdrivers'
4
+
5
+ require 'rspec/expectations'
@@ -0,0 +1,11 @@
1
+ require "rmagick/screwdrivers/version"
2
+ require "rmagick/screwdrivers/helpers"
3
+ require "rmagick/screwdrivers/poster"
4
+ require "rmagick/screwdrivers/collage"
5
+ require "rmagick/screwdrivers/scale"
6
+
7
+ module Magick
8
+ module Screwdrivers
9
+ # Your code goes here...
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'RMagick'
4
+
5
+ module Magick
6
+ module Screwdrivers
7
+ def self.collage files, options={}
8
+ options = {
9
+ :columns => 5,
10
+ :scale_range => 0.1,
11
+ :thumb_width => 120,
12
+ :rotate_angle => 20,
13
+ :background => 'white',
14
+ :border => '#DDDDDD',
15
+ :logger => nil
16
+ }.merge(options)
17
+ files = "#{files}/*" if File.directory?(files)
18
+ imgs = ImageList.new
19
+ imgnull = Image.new(options[:thumb_width],options[:thumb_width]) {
20
+ self.background_color = 'transparent'
21
+ }
22
+ (options[:columns]+2).times { imgs << imgnull.dup }
23
+ Dir.glob("#{files}") { |f|
24
+ begin
25
+ i = img_from_file(f)
26
+ rescue
27
+ warn(options[:logger], "Skipping invalid file #{f}…")
28
+ next
29
+ end
30
+ scale = (1.0 + options[:scale_range]*Random::rand(-1.0..1.0))*options[:thumb_width]/[i.columns, i.rows].max
31
+ imgs << imgnull.dup if (imgs.size % (options[:columns]+2)).zero?
32
+ imgs << i.auto_orient.thumbnail(scale).polaroid(
33
+ Random::rand(-options[:rotate_angle]..options[:rotate_angle])
34
+ )
35
+ imgs << imgnull.dup if (imgs.size % (options[:columns]+2)) == options[:columns]+1
36
+ }
37
+ (2*options[:columns]+4-(imgs.size % (options[:columns]+2))).times { imgs << imgnull.dup }
38
+ info options[:logger], "Montaging image [#{options[:columns]}×#{imgs.size/(options[:columns]+2)-2}]"
39
+ imgs.montage {
40
+ self.tile = Magick::Geometry.new(options[:columns]+2)
41
+ self.geometry = "-#{options[:thumb_width]/5}-#{options[:thumb_width]/4}"
42
+ self.background_color = options[:background]
43
+ }.trim(true).border(10,10,options[:background]).border(1,1,options[:border])
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'RMagick'
4
+
5
+ module Magick
6
+ module Screwdrivers
7
+
8
+ # ==============================================================
9
+ # == Image preparation =================================
10
+ # ==============================================================
11
+
12
+ def self.img_from_file file
13
+ img = Magick::Image::read(file).first
14
+
15
+ # case img.orientation
16
+ # when Magick::RightTopOrientation
17
+ # img.rotate!(90)
18
+ # when Magick::BottomRightOrientation
19
+ # img.rotate!(180)
20
+ # when Magick::LeftBottomOrientation
21
+ # img.rotate!(-90)
22
+ # end
23
+
24
+ img
25
+ end
26
+
27
+ # ==============================================================
28
+ # == Handy logging =====================================
29
+ # ==============================================================
30
+
31
+ def self.warn logger = nil, msg = nil
32
+ logger.warn(msg) if logger && logger.respond_to?(:warn)
33
+ end
34
+ def self.info logger = nil, msg = nil
35
+ logger.info(msg) if logger && logger.respond_to?(:info)
36
+ end
37
+ def self.debug logger = nil, msg = nil
38
+ logger.debug(msg) if logger && logger.respond_to?(:debug)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ require 'RMagick'
4
+
5
+ module Magick
6
+ module Screwdrivers
7
+ def self.poster file, text1, text2, options={}
8
+ options = {
9
+ :color => '#FFFFFF',
10
+ :stroke => nil,
11
+ :width => 600,
12
+ :type => :classic, # :classic for black square around
13
+ :lineheight => 6,
14
+ :background => '#000000',
15
+ :font => '/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf',
16
+ :max_font_size => 48,
17
+ :logger => nil
18
+ }.merge(options)
19
+
20
+ text1 ||= ''
21
+ text2 ||= ''
22
+ options[:lineheight] = 3 if options[:lineheight] < 3
23
+
24
+ img = img_from_file(file)
25
+ img.thumbnail!(options[:width].to_f/img.columns.to_f)
26
+
27
+ mark = Magick::Image.new(img.columns, img.rows) do
28
+ self.background_color = options[:type] == :classic ? options[:background] : 'transparent'
29
+ end
30
+
31
+ gc = Magick::Draw.new
32
+
33
+ pointsize = [img.columns, options[:max_font_size]].min
34
+ classic_margin = 0
35
+
36
+ loop do
37
+ gc.pointsize = pointsize -= 1 + pointsize / 33
38
+
39
+ m1 = gc.get_type_metrics(text1)
40
+ w1 = m1.width
41
+ h1 = (m1.bounds.y2 - m1.bounds.y1).round
42
+
43
+ m2 = gc.get_type_metrics(text2)
44
+ w2 = m2.width
45
+ h2 = (m2.bounds.y2 - m2.bounds.y1).round
46
+
47
+ if w1 < img.columns - 10*options[:lineheight] && w2 < img.columns - 10*options[:lineheight]
48
+ if options[:type] == :classic
49
+ classic_margin = h2
50
+ mark.resize! img.columns+options[:lineheight]*14/3, img.rows+options[:lineheight]*8+h1+h2
51
+ gc.stroke_width = options[:lineheight]/3
52
+ gc.stroke = '#FFFFFF'
53
+ gc.fill = options[:background]
54
+ gc.rectangle(options[:lineheight]*7/6, options[:lineheight]*7/6, \
55
+ img.columns+options[:lineheight]*21/6, img.rows+options[:lineheight]*21/6)
56
+ gc.composite(
57
+ 7*options[:lineheight]/3, 7*options[:lineheight]/3,
58
+ 0, 0,
59
+ img, Magick::OverCompositeOp
60
+ )
61
+ gc.draw mark
62
+ end
63
+ break
64
+ end
65
+ end
66
+
67
+ gc.fill = options[:color]
68
+ gc.stroke = options[:stroke] || 'none'
69
+ gc.stroke_width = 1
70
+ gc.font = options[:font]
71
+
72
+ case options[:type]
73
+ when :classic
74
+ gc.annotate(mark, 0, 0, 0, classic_margin+2*options[:lineheight], text1) do
75
+ self.gravity = Magick::SouthGravity
76
+ end
77
+ else
78
+ gc.annotate(mark, 0, 0, 0, 0, text1) do
79
+ self.gravity = Magick::NorthGravity
80
+ end
81
+ end
82
+
83
+ gc.annotate(mark, 0, 0, 0, 0, text2) do
84
+ self.gravity = Magick::SouthGravity
85
+ end
86
+
87
+ case options[:type]
88
+ when :classic
89
+ mark
90
+ when :negative
91
+ img.composite(mark, Magick::SouthEastGravity, Magick::SubtractCompositeOp)
92
+ when :standard
93
+ img.composite(mark, Magick::SouthEastGravity, Magick::OverCompositeOp)
94
+ else
95
+ warn options[:logger], "Invalid type: #{options[:type]}"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ require 'RMagick'
4
+ require 'date'
5
+
6
+ module Magick
7
+ module Screwdrivers
8
+ def self.scale file, options={}
9
+ options = {
10
+ :widths => 600,
11
+ :date_in_watermark => false,
12
+ :watermark => nil,
13
+ :logger => nil
14
+ }.merge(options)
15
+
16
+ img = img_from_file file
17
+
18
+ date = img.get_exif_by_number(36867)[36867]
19
+ date = Date.parse(date.gsub(/:/, '/')) if date
20
+ date ||= Date.parse(img.properties['exif:DateTime'].gsub(/:/, '/')) if img.properties['exif:DateTime']
21
+ date ||= Date.parse(img.properties['date:modify']) if img.properties['date:modify']
22
+ date ||= Date.parse(img.properties['date:create']) if img.properties['date:create']
23
+ date ||= Date.parse(img.properties['xap:CreateDate']) if img.properties['xap:CreateDate']
24
+
25
+ options[:watermark] = ([
26
+ options[:watermark], date.strftime('%y/%m/%d')] - [nil]
27
+ ).join(' :: ').strip if options[:date_in_watermark]
28
+
29
+ result = ImageList.new
30
+
31
+ [*options[:widths]].each { |sz|
32
+ unless Integer === sz && sz < img.columns && sz > 0
33
+ warn options[:logger], "Invalid width #{sz} (original is #{img.columns}), skipping…"
34
+ next
35
+ end
36
+
37
+ curr = img.resize_to_fit(sz)
38
+
39
+ if will_wm = (options[:watermark] && curr.rows >= 400)
40
+ mark = Magick::Image.new(curr.rows, curr.columns) do
41
+ self.background_color = 'transparent'
42
+ end
43
+ draw = Magick::Draw.new
44
+ draw.encoding = 'Unicode'
45
+ draw.annotate(mark, 0, 0, 5, 2, options[:watermark]) do
46
+ self.encoding = 'Unicode'
47
+ self.gravity = Magick::SouthEastGravity
48
+ self.fill 'rgba(60%, 60%, 60%, 0.40)'
49
+ self.stroke = 'none'
50
+ self.pointsize = 1 + 2 * Math.log(sz, 3).to_i
51
+ self.font_family = 'Comfortaa'
52
+ self.font_weight = Magick::NormalWeight
53
+ self.font_style = Magick::NormalStyle
54
+ end
55
+ curr = curr.composite(mark.rotate(-90), Magick::SouthEastGravity, Magick::SubtractCompositeOp)
56
+ end
57
+
58
+ info options[:logger], "Scaling to width #{curr.rows}×#{curr.columns}, watermark: “#{will_wm ? options[:watermark] : 'NONE'}”"
59
+
60
+ result << curr
61
+ }
62
+
63
+ result
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ module Magick
2
+ module Screwdrivers
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'rmagick/screwdrivers/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'rmagick-screwdrivers'
6
+ s.version = Magick::Screwdrivers::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.date = '2013-10-26'
9
+ s.authors = ['Alexei Matyushkin']
10
+ s.email = 'am@mudasobwa.ru'
11
+ s.homepage = 'http://github.com/mudasobwa/rmagick-screwdrivers'
12
+ s.summary = %Q{RMagick addons for utilizing some common tasks}
13
+ s.description = %Q{Creating collages, demotivators and other handy stuff with RMagick}
14
+ s.extra_rdoc_files = [
15
+ 'LICENSE',
16
+ 'README.md',
17
+ ]
18
+
19
+ s.required_rubygems_version = Gem::Requirement.new('>= 1.3.7')
20
+ s.rubygems_version = '1.3.7'
21
+ s.specification_version = 3
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+
28
+ s.add_development_dependency 'rspec'
29
+ s.add_development_dependency 'yard'
30
+ s.add_development_dependency 'cucumber'
31
+ s.add_development_dependency 'yard-cucumber'
32
+ s.add_development_dependency 'bueller'
33
+
34
+ s.add_dependency 'rmagick'
35
+ end
36
+
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe RmagickScrewdrivers do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'rmagick-screwdrivers'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
8
+
9
+ RSpec.configure do |config|
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmagick-screwdrivers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexei Matyushkin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cucumber
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard-cucumber
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bueller
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rmagick
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Creating collages, demotivators and other handy stuff with RMagick
98
+ email: am@mudasobwa.ru
99
+ executables:
100
+ - magick_collage
101
+ - magick_poster
102
+ - magick_scale
103
+ extensions: []
104
+ extra_rdoc_files:
105
+ - LICENSE
106
+ - README.md
107
+ files:
108
+ - .document
109
+ - .gitignore
110
+ - Gemfile
111
+ - LICENSE
112
+ - README.md
113
+ - Rakefile
114
+ - bin/magick_collage
115
+ - bin/magick_poster
116
+ - bin/magick_scale
117
+ - features/rmagick-screwdrivers.feature
118
+ - features/step_definitions/rmagick-screwdrivers_steps.rb
119
+ - features/support/env.rb
120
+ - lib/rmagick/screwdrivers.rb
121
+ - lib/rmagick/screwdrivers/collage.rb
122
+ - lib/rmagick/screwdrivers/helpers.rb
123
+ - lib/rmagick/screwdrivers/poster.rb
124
+ - lib/rmagick/screwdrivers/scale.rb
125
+ - lib/rmagick/screwdrivers/version.rb
126
+ - rmagick-screwdrivers.gemspec
127
+ - spec/rmagick-screwdrivers_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: http://github.com/mudasobwa/rmagick-screwdrivers
130
+ licenses: []
131
+ metadata: {}
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: 1.3.7
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.0.2
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: RMagick addons for utilizing some common tasks
152
+ test_files: []
153
+ has_rdoc: