mojo_magick 0.5.7 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mojo_magick.rb CHANGED
@@ -1,15 +1,12 @@
1
- cwd = File.dirname(__FILE__)
2
- require 'open3'
3
- initializers_dir = File.expand_path(File.join(cwd, 'initializers'))
4
- Dir.glob(File.join(initializers_dir, '*.rb')).each { |f| require f }
5
- require File.join(cwd, 'mojo_magick/util/parser')
6
- require File.join(cwd, 'mojo_magick/errors')
7
- require File.join(cwd, 'mojo_magick/command_status')
8
- require File.join(cwd, 'image_magick/resource_limits')
9
- require File.join(cwd, 'image_magick/fonts')
10
- require File.join(cwd, 'mojo_magick/opt_builder')
11
- require File.join(cwd, 'mojo_magick/font')
12
- require 'tempfile'
1
+ require "tempfile"
2
+ require "open3"
3
+ require_relative "./mojo_magick/util/font_parser"
4
+ require_relative "./mojo_magick/errors"
5
+ require_relative "./mojo_magick/command_status"
6
+ require_relative "./mojo_magick/commands"
7
+ require_relative "./image_magick/fonts"
8
+ require_relative "./mojo_magick/opt_builder"
9
+ require_relative "./mojo_magick/font"
13
10
 
14
11
  # MojoMagick is a stateless set of module methods which present a convient interface
15
12
  # for accessing common tasks for ImageMagick command line library.
@@ -35,7 +32,8 @@ require 'tempfile'
35
32
  #
36
33
  # Equivalent to:
37
34
  #
38
- # MojoMagick::raw_command('convert', 'source.jpg -crop 250x250+0+0 +repage -strip -set comment "my favorite file" dest.jpg')
35
+ # MojoMagick::Commands.raw_command('convert', 'source.jpg -crop 250x250+0+0\
36
+ # +repage -strip -set comment "my favorite file" dest.jpg')
39
37
  #
40
38
  # Example #mogrify usage:
41
39
  #
@@ -43,7 +41,7 @@ require 'tempfile'
43
41
  #
44
42
  # Equivalent to:
45
43
  #
46
- # MojoMagick::raw_command('mogrify', '-shave 10x10 image.jpg')
44
+ # MojoMagick::Commands.raw_command('mogrify', '-shave 10x10 image.jpg')
47
45
  #
48
46
  # Example showing some additional options:
49
47
  #
@@ -60,39 +58,40 @@ require 'tempfile'
60
58
  # bang (!) can be appended to command names to use the '+' versions
61
59
  # instead of '-' versions.
62
60
  #
63
- module MojoMagick
64
- # enable resource limiting functionality
65
- extend ImageMagick::ResourceLimits
66
- extend ImageMagick::Fonts
67
61
 
68
- def self.windows?
69
- !(RUBY_PLATFORM =~ /win32/).nil?
62
+ module MojoMagickDeprecations
63
+ # rubocop:disable Naming/AccessorMethodName
64
+ def get_fonts
65
+ warn "DEPRECATION WARNING: #{__method__} is deprecated and will be removed with the next minor version release."\
66
+ " Please use `available_fonts` instead"
67
+ MojoMagick.available_fonts
70
68
  end
71
69
 
72
- def self.execute(command, args, _options = {})
73
- # this suppress error messages to the console
74
- # err_pipe = windows? ? "2>nul" : "2>/dev/null"
70
+ # rubocop:enable Naming/AccessorMethodName
71
+ ### Moved to `Commands`
72
+ def execute!(*args)
73
+ warn "DEPRECATION WARNING: #{__method__} is deprecated and will be removed with the next minor version release."\
74
+ " Please use `MojoMagick::Commands.execute!` instead"
75
+ MojoMagick::Commands.send(:execute!, *args)
76
+ end
75
77
 
76
- execute = "#{command} #{get_limits_as_params} #{args}"
77
- out, outerr, status = Open3.capture3(execute)
78
- CommandStatus.new execute, out, outerr, status
79
- rescue Exception => e
80
- raise MojoError, "#{e.class}: #{e.message}"
78
+ def execute(*args)
79
+ warn "DEPRECATION WARNING: #{__method__} is deprecated and will be removed with the next minor version release."\
80
+ " Please use `MojoMagick::Commands.execute!` instead"
81
+ MojoMagick::Commands.send(:execute, *args)
81
82
  end
82
83
 
83
- def self.execute!(command, args, options = {})
84
- # this suppress error messages to the console
85
- # err_pipe = windows? ? "2>nul" : "2>/dev/null"
86
- status = execute(command, args, options)
87
- unless status.success?
88
- err_msg = options[:err_msg] || "MojoMagick command failed: #{command}."
89
- raise(MojoFailed, "#{err_msg} (Exit status: #{status.exit_code})\n Command: #{status.command}\n Error: #{status.error}")
90
- end
91
- status.return_value
84
+ def raw_command(*args)
85
+ warn "DEPRECATION WARNING: #{__method__} is deprecated and will be removed with the next minor version release."\
86
+ " Please use `MojoMagick::Commands.execute!` instead"
87
+ MojoMagick::Commands.raw_command(*args)
92
88
  end
89
+ end
93
90
 
94
- def self.raw_command(*args)
95
- execute!(*args)
91
+ module MojoMagick
92
+ extend MojoMagickDeprecations
93
+ def self.windows?
94
+ !RUBY_PLATFORM.include(win32)
96
95
  end
97
96
 
98
97
  def self.shrink(source_file, dest_file, options)
@@ -110,46 +109,56 @@ module MojoMagick
110
109
  # resizes an image and returns the filename written to
111
110
  # options:
112
111
  # :width / :height => scale to these dimensions
113
- # :scale => pass scale options such as ">" to force shrink scaling only or "!" to force absolute width/height scaling (do not preserve aspect ratio)
112
+ # :scale => pass scale options such as ">" to force shrink scaling only or
113
+ # "!" to force absolute width/height scaling (do not preserve aspect ratio)
114
114
  # :percent => scale image to this percentage (do not specify :width/:height in this case)
115
115
  def self.resize(source_file, dest_file, options)
116
- scale_options = []
117
- scale_options << '>' unless options[:shrink_only].nil?
118
- scale_options << '<' unless options[:expand_only].nil?
119
- scale_options << '!' unless options[:absolute_aspect].nil?
120
- scale_options << '^' unless options[:fill].nil?
121
- scale_options = scale_options.join
122
-
116
+ scale_options = extract_scale_options(options)
117
+ geometry = extract_geometry_options(options)
123
118
  extras = []
124
- if !options[:width].nil? && !options[:height].nil?
125
- geometry = "#{options[:width]}X#{options[:height]}"
126
- elsif !options[:percent].nil?
127
- geometry = "#{options[:percent]}%"
128
- else
129
- raise MojoMagickError, "Unknown options for method resize: #{options.inspect}"
130
- end
131
119
  if !options[:fill].nil? && !options[:crop].nil?
132
- extras << '-gravity Center'
133
- extras << "-extent #{geometry}"
120
+ extras << "-gravity"
121
+ extras << "Center"
122
+ extras << "-extent"
123
+ extras << geometry.to_s
134
124
  end
135
- raw_command('convert', "\"#{source_file}\" -resize \"#{geometry}#{scale_options}\" #{extras.join(' ')} \"#{dest_file}\"")
125
+ Commands.raw_command("convert",
126
+ source_file,
127
+ "-resize", "#{geometry}#{scale_options}",
128
+ *extras, dest_file)
136
129
  dest_file
137
130
  end
138
131
 
132
+ def self.convert(source = nil, dest = nil)
133
+ opts = OptBuilder.new
134
+ opts.file source if source
135
+ yield opts
136
+ opts.file dest if dest
137
+
138
+ Commands.raw_command("convert", *opts.to_a)
139
+ end
140
+
141
+ def self.mogrify(dest = nil)
142
+ opts = OptBuilder.new
143
+ yield opts
144
+ opts.file dest if dest
145
+ Commands.raw_command("mogrify", *opts.to_a)
146
+ end
147
+
139
148
  def self.available_fonts
140
149
  # returns width, height of image if available, nil if not
141
150
  Font.all
142
151
  end
143
152
 
144
153
  def self.get_format(source_file, format_string)
145
- raw_command('identify', "-format \"#{format_string}\" \"#{source_file}\"")
154
+ Commands.raw_command("identify", "-format", format_string, source_file)
146
155
  end
147
156
 
148
157
  # returns an empty hash or a hash with :width and :height set (e.g. {:width => INT, :height => INT})
149
158
  # raises MojoFailed when results are indeterminate (width and height could not be determined)
150
159
  def self.get_image_size(source_file)
151
160
  # returns width, height of image if available, nil if not
152
- retval = get_format(source_file, 'w:%w h:%h')
161
+ retval = get_format(source_file, "w:%w h:%h")
153
162
  return {} unless retval
154
163
 
155
164
  width = retval.match(/w:([0-9]+) /)
@@ -161,30 +170,38 @@ module MojoMagick
161
170
  { width: width, height: height }
162
171
  end
163
172
 
164
- def self.convert(source = nil, dest = nil)
165
- opts = OptBuilder.new
166
- opts.file source if source
167
- yield opts
168
- opts.file dest if dest
169
- raw_command('convert', opts.to_s)
170
- end
171
-
172
- def self.mogrify(dest = nil)
173
- opts = OptBuilder.new
174
- yield opts
175
- opts.file dest if dest
176
- raw_command('mogrify', opts.to_s)
177
- end
178
-
179
173
  def self.tempfile(*opts)
180
174
  data = opts[0]
181
175
  rest = opts[1]
182
176
  ext = rest && rest[:format]
183
- file = Tempfile.new(['mojo', ext ? '.' + ext.to_s : ''])
177
+ file = Tempfile.new(["mojo", ext ? ".#{ext}" : ""])
184
178
  file.binmode
185
179
  file.write(data)
186
180
  file.path
187
181
  ensure
188
182
  file.close
189
183
  end
190
- end # MojoMagick
184
+
185
+ class << self
186
+ private
187
+
188
+ def extract_geometry_options(options)
189
+ if !options[:width].nil? && !options[:height].nil?
190
+ "#{options[:width]}X#{options[:height]}"
191
+ elsif !options[:percent].nil?
192
+ "#{options[:percent]}%"
193
+ else
194
+ raise MojoMagickError, "Resize requires width and height or percentage: #{options.inspect}"
195
+ end
196
+ end
197
+
198
+ def extract_scale_options(options)
199
+ [].tap { |scale_options|
200
+ scale_options << ">" unless options[:shrink_only].nil?
201
+ scale_options << "<" unless options[:expand_only].nil?
202
+ scale_options << "!" unless options[:absolute_aspect].nil?
203
+ scale_options << "^" unless options[:fill].nil?
204
+ }.join
205
+ end
206
+ end
207
+ end
@@ -5,7 +5,7 @@ module MojoMagick
5
5
  end
6
6
 
7
7
  def exit_code
8
- system_status.exitstatus || 'unknown'
8
+ system_status.exitstatus || "unknown"
9
9
  end
10
10
  end
11
11
  end
@@ -0,0 +1,32 @@
1
+ require_relative "opt_builder"
2
+
3
+ module MojoMagick
4
+ class Commands
5
+ def self.raw_command(*args)
6
+ execute!(*args)
7
+ end
8
+
9
+ class << self
10
+ private
11
+
12
+ def execute(command, *args)
13
+ execute = "#{command} #{args}"
14
+ out, outerr, status = Open3.capture3(command, *args.map(&:to_s))
15
+ CommandStatus.new execute, out, outerr, status
16
+ rescue StandardError => e
17
+ raise MojoError, "#{e.class}: #{e.message}"
18
+ end
19
+
20
+ def execute!(command, *args)
21
+ status = execute(command, *args)
22
+ unless status.success?
23
+ err_msg = "MojoMagick command failed: #{command}."
24
+ raise(MojoFailed, "#{err_msg} (Exit status: #{status.exit_code})\n" \
25
+ " Command: #{status.command}\n" \
26
+ " Error: #{status.error}")
27
+ end
28
+ status.return_value
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,7 @@
1
1
  module MojoMagick
2
2
  class MojoMagickException < StandardError; end
3
+
3
4
  class MojoError < MojoMagickException; end
5
+
4
6
  class MojoFailed < MojoMagickException; end
5
7
  end
@@ -7,7 +7,6 @@ module MojoMagick
7
7
  end
8
8
 
9
9
  def initialize(property_hash = {})
10
- property_hash.symbolize_keys!
11
10
  %i[name family style stretch weight glyphs].each do |f|
12
11
  setter = "#{f}="
13
12
  send(setter, property_hash[f])
@@ -15,7 +14,7 @@ module MojoMagick
15
14
  end
16
15
 
17
16
  def self.all
18
- ImageMagick::Font.all.map { |font_info| Font.new(font_info) }
17
+ ImageMagick::Fonts.all
19
18
  end
20
19
  end
21
20
  end
@@ -17,9 +17,7 @@ module MojoMagick
17
17
 
18
18
  # Add files to command line, formatted if necessary
19
19
  def file(*args)
20
- args.each do |arg|
21
- add_formatted arg
22
- end
20
+ @opts << args
23
21
  self
24
22
  end
25
23
  alias files file
@@ -29,21 +27,17 @@ module MojoMagick
29
27
  end
30
28
 
31
29
  # annotate takes non-standard args
32
- def annotate(*args)
33
- @opts << '-annotate'
34
- arguments = args.join.split
35
- arguments.unshift '0' if arguments.length == 1
36
- arguments.each do |arg|
37
- add_formatted arg
38
- end
30
+ def annotate(*args, geometry: 0)
31
+ @opts << "-annotate"
32
+ arguments = [args.join]
33
+ arguments.unshift geometry.to_s
34
+ @opts << arguments
39
35
  end
40
36
 
41
37
  # Create a temporary file for the given image and add to command line
42
38
  def format(*args)
43
- @opts << '-format'
44
- args.each do |arg|
45
- add_formatted arg
46
- end
39
+ @opts << "-format"
40
+ @opts << args
47
41
  end
48
42
 
49
43
  def blob(*args)
@@ -64,33 +58,28 @@ module MojoMagick
64
58
  end
65
59
 
66
60
  # Generic commands. Arguments will be formatted if necessary
61
+ # rubocop:disable Style/MissingRespondToMissing
67
62
  def method_missing(command, *args)
68
- @opts << if command.to_s[-1, 1] == '!'
63
+ @opts << if command.to_s[-1, 1] == "!"
69
64
  "+#{command.to_s.chop}"
70
65
  else
71
66
  "-#{command}"
72
67
  end
73
- args.each do |arg|
74
- add_formatted arg
75
- end
68
+ @opts << args
76
69
  self
77
70
  end
78
71
 
79
- def to_s
80
- @opts.join ' '
72
+ # rubocop:enable Style/MissingRespondToMissing
73
+ def to_a
74
+ @opts.flatten
81
75
  end
82
76
 
83
77
  protected
84
78
 
85
- def add_formatted(arg)
86
- # Quote anything that would cause problems on *nix or windows
87
- @opts << quoted_arg(arg)
88
- end
89
-
90
79
  def quoted_arg(arg)
91
- return arg unless arg =~ /[#'<>^|&();` ]/
80
+ return arg unless /[#'<>^|&();` ]/.match?(arg)
92
81
 
93
- ['"', arg.gsub('"', '\"').gsub("'", "\'"), '"'].join
82
+ ['"', arg.gsub('"', '\"').tr("'", "\'"), '"'].join
94
83
  end
95
84
  end
96
85
  end
@@ -0,0 +1,43 @@
1
+ # rubocop:disable Lint/AssignmentInCondition
2
+ module MojoMagick
3
+ module Util
4
+ class FontParser
5
+ attr_reader :raw_fonts
6
+
7
+ def initialize(raw_fonts)
8
+ @raw_fonts = raw_fonts
9
+ end
10
+
11
+ def parse
12
+ fonts = {}
13
+ enumerator = raw_fonts.split("\n").each
14
+ name = nil
15
+ while begin; line = enumerator.next; rescue StopIteration; line = nil; end
16
+ line.chomp!
17
+ line = enumerator.next if line_is_empty(line)
18
+ m = /^\s*Font:\s+(.*)$/.match(line)
19
+ if m
20
+ name = m[1].strip
21
+ fonts[name] = { name: name }
22
+ else
23
+ k, v = extract_key_value(line)
24
+ fonts[name][k] = v if k && name
25
+ end
26
+ end
27
+ fonts.values.map { |f| MojoMagick::Font.new f }
28
+ end
29
+
30
+ private
31
+
32
+ def extract_key_value(line)
33
+ key_val = line.split(":").map(&:strip)
34
+ [key_val[0].downcase.to_sym, key_val[1]]
35
+ end
36
+
37
+ def line_is_empty(line)
38
+ line.nil? || line.empty? || (/^\s+$/ =~ line)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ # rubocop:enable Lint/AssignmentInCondition
@@ -1,65 +1,20 @@
1
+ require_relative "./font_parser"
1
2
  module MojoMagick
2
3
  module Util
3
4
  class Parser
4
- # handle parsing outputs from ImageMagick commands
5
+ attr_reader :raw_fonts
5
6
 
6
- def parse_fonts(raw_fonts)
7
- fonts = {}
8
- enumerator = raw_fonts.split(/\n/).each
9
- name = nil
10
- while begin; line = enumerator.next; rescue StopIteration; line = nil; end
11
- line.chomp!
12
- line = enumerator.next if line.nil? || line.empty? || (/^\s+$/ =~ line)
13
- if m = /^\s*Font:\s+(.*)$/.match(line)
14
- name = m[1].strip
15
- fonts[name] = {name: name}
16
- else
17
- key_val = line.split(/:/).map(&:strip)
18
- k = key_val[0].downcase.to_sym
19
- v = key_val[1]
20
- fonts[name][k] = v if k && name
21
- end
22
- end
23
- fonts.values.map { |f| MojoMagick::Font.new f}
7
+ def initialize
8
+ warn "DEPRECATION WARNING: This class has been deprecated and will be removed with"\
9
+ " the next minor version release."\
10
+ " Please use `MojoMagick::Util::FontParser` instead"
24
11
  end
25
12
 
26
- def parse_limits(raw_limits)
27
- row_limits = raw_limits.split("\n")
28
- header = row_limits[0].chomp
29
- data = row_limits[2].chomp
30
- resources = header.strip.split
31
- limits = data.strip.split
32
-
33
- actual_values = {}
34
- readable_values = {}
35
-
36
- resources.each_index do |i|
37
- resource = resources[i].downcase.to_sym
38
- scale = limits[i].match(/[a-z]+$/) || []
39
- value = limits[i].match(/^[0-9]+/)
40
- unscaled_value = value ? value[0].to_i : -1
41
- scaled_value = case scale[0]
42
- when 'eb'
43
- unscaled_value * (2**60)
44
- when 'pb'
45
- unscaled_value * (2**50)
46
- when 'tb'
47
- unscaled_value * (2**40)
48
- when 'gb'
49
- unscaled_value * (2**30)
50
- when 'mb'
51
- unscaled_value * (2**20)
52
- when 'kb'
53
- unscaled_value * (2**10)
54
- when 'b'
55
- unscaled_value
56
- else
57
- unscaled_value
58
- end
59
- actual_values[resource] = scaled_value
60
- readable_values[resource] = limits[i]
61
- end
62
- [actual_values, readable_values]
13
+ def parse_fonts(fonts)
14
+ warn "DEPRECATION WARNING: #{__method__} has been deprecated and will be removed with"\
15
+ " the next minor version release."\
16
+ " Please use `MojoMagick::Util::FontParser#parse` instead"
17
+ FontParser.new(fonts).parse
63
18
  end
64
19
  end
65
20
  end