mini_magick 3.8.1 → 4.9.4

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.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/lib/mini_gmagick.rb +1 -0
  3. data/lib/mini_magick/configuration.rb +198 -0
  4. data/lib/mini_magick/image/info.rb +192 -0
  5. data/lib/mini_magick/image.rb +456 -341
  6. data/lib/mini_magick/shell.rb +81 -0
  7. data/lib/mini_magick/tool/animate.rb +14 -0
  8. data/lib/mini_magick/tool/compare.rb +14 -0
  9. data/lib/mini_magick/tool/composite.rb +14 -0
  10. data/lib/mini_magick/tool/conjure.rb +14 -0
  11. data/lib/mini_magick/tool/convert.rb +14 -0
  12. data/lib/mini_magick/tool/display.rb +14 -0
  13. data/lib/mini_magick/tool/identify.rb +14 -0
  14. data/lib/mini_magick/tool/import.rb +14 -0
  15. data/lib/mini_magick/tool/magick.rb +14 -0
  16. data/lib/mini_magick/tool/mogrify.rb +14 -0
  17. data/lib/mini_magick/tool/mogrify_restricted.rb +15 -0
  18. data/lib/mini_magick/tool/montage.rb +14 -0
  19. data/lib/mini_magick/tool/stream.rb +14 -0
  20. data/lib/mini_magick/tool.rb +297 -0
  21. data/lib/mini_magick/utilities.rb +23 -50
  22. data/lib/mini_magick/version.rb +5 -5
  23. data/lib/mini_magick.rb +54 -65
  24. metadata +49 -51
  25. data/lib/mini_magick/command_builder.rb +0 -94
  26. data/lib/mini_magick/errors.rb +0 -4
  27. data/spec/files/actually_a_gif.jpg +0 -0
  28. data/spec/files/animation.gif +0 -0
  29. data/spec/files/composited.jpg +0 -0
  30. data/spec/files/erroneous.jpg +0 -0
  31. data/spec/files/layers.psd +0 -0
  32. data/spec/files/leaves (spaced).tiff +0 -0
  33. data/spec/files/not_an_image.php +0 -1
  34. data/spec/files/png.png +0 -0
  35. data/spec/files/simple-minus.gif +0 -0
  36. data/spec/files/simple.gif +0 -0
  37. data/spec/files/trogdor.jpg +0 -0
  38. data/spec/files/trogdor_capitalized.JPG +0 -0
  39. data/spec/lib/mini_magick/command_builder_spec.rb +0 -153
  40. data/spec/lib/mini_magick/image_spec.rb +0 -499
  41. data/spec/lib/mini_magick_spec.rb +0 -63
  42. data/spec/spec_helper.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4f4ae6b4f7d224af6275ad37b108c978f3fd8817
4
- data.tar.gz: 69d6e3f3b1289af2dd54a0309166e71fce1e2f45
2
+ SHA256:
3
+ metadata.gz: 3ab4ce03957b9a0f941f9bd2c34a5dcab63faffac5143eb6e7c90d7d860b57c5
4
+ data.tar.gz: 7bd78f0c862f1ca72b34e3c6fc4d14297adfa9dd6bc36218a35ef68c235320b5
5
5
  SHA512:
6
- metadata.gz: 248c08f2af654156c2a422bb3bb3e48a9b97087bab6dacace044bbc2175465c9a2e5de09eac05cb4110cc4efcc8a47f25424f03f6effa6df2cbb2fda85524557
7
- data.tar.gz: 3c000c0861b8e66312d875b8858cdc3fe0b32c842332b70c979675acbf9b4fc62fcb4732c5c49db96240e0bf400974a90ee01e90a34b1c3d817eaf60444030fb
6
+ metadata.gz: 16c4bfa3744a2bea117bff0118afcbf89fac2f3d9e92c5c8af2b095f6c1381c1d000bede5086ccffd72ecca8152845cde11a5ff762186bd90793ee5d83e03a77
7
+ data.tar.gz: fe593ad2a7bfd4b6f2d9892533fd5347046e7dfb6cfd8e3bc6049cb1ae7686f5af60c23f33254175bca4728a58bdeeab2b9bfb873ebd94c46f14e68e086f002f
data/lib/mini_gmagick.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require 'mini_magick'
2
+
2
3
  MiniMagick.processor = :gm
@@ -0,0 +1,198 @@
1
+ require 'mini_magick/utilities'
2
+ require 'logger'
3
+
4
+ module MiniMagick
5
+ module Configuration
6
+
7
+ ##
8
+ # Set whether you want to use [ImageMagick](http://www.imagemagick.org) or
9
+ # [GraphicsMagick](http://www.graphicsmagick.org).
10
+ #
11
+ # @return [Symbol] `:imagemagick`, `:imagemagick7`, or `:graphicsmagick`
12
+ #
13
+ attr_accessor :cli
14
+
15
+ ##
16
+ # If you don't have the CLI tools in your PATH, you can set the path to the
17
+ # executables.
18
+ #
19
+ attr_writer :cli_path
20
+ # @private (for backwards compatibility)
21
+ attr_accessor :processor_path
22
+
23
+ ##
24
+ # Adds a prefix to the CLI command.
25
+ # For example, you could use `firejail` to run all commands in a sandbox.
26
+ # Can be a string, or an array of strings.
27
+ # e.g. 'firejail', or ['firejail', '--force']
28
+ #
29
+ # @return [String]
30
+ # @return [Array<String>]
31
+ #
32
+ attr_accessor :cli_prefix
33
+
34
+ ##
35
+ # If you don't want commands to take too long, you can set a timeout (in
36
+ # seconds).
37
+ #
38
+ # @return [Integer]
39
+ #
40
+ attr_accessor :timeout
41
+ ##
42
+ # When get to `true`, it outputs each command to STDOUT in their shell
43
+ # version.
44
+ #
45
+ # @return [Boolean]
46
+ #
47
+ attr_reader :debug
48
+ ##
49
+ # Logger for {#debug}, default is `MiniMagick::Logger.new(STDOUT)`, but
50
+ # you can override it, for example if you want the logs to be written to
51
+ # a file.
52
+ #
53
+ # @return [Logger]
54
+ #
55
+ attr_accessor :logger
56
+
57
+ ##
58
+ # If set to `true`, it will `identify` every newly created image, and raise
59
+ # `MiniMagick::Invalid` if the image is not valid. Useful for validating
60
+ # user input, although it adds a bit of overhead. Defaults to `true`.
61
+ #
62
+ # @return [Boolean]
63
+ #
64
+ attr_accessor :validate_on_create
65
+ ##
66
+ # If set to `true`, it will `identify` every image that gets written (with
67
+ # {MiniMagick::Image#write}), and raise `MiniMagick::Invalid` if the image
68
+ # is not valid. Useful for validating that processing was sucessful,
69
+ # although it adds a bit of overhead. Defaults to `true`.
70
+ #
71
+ # @return [Boolean]
72
+ #
73
+ attr_accessor :validate_on_write
74
+
75
+ ##
76
+ # If set to `false`, it will not raise errors when ImageMagick returns
77
+ # status code different than 0. Defaults to `true`.
78
+ #
79
+ # @return [Boolean]
80
+ #
81
+ attr_accessor :whiny
82
+
83
+ ##
84
+ # Instructs MiniMagick how to execute the shell commands. Available
85
+ # APIs are "open3" (default) and "posix-spawn" (requires the "posix-spawn"
86
+ # gem).
87
+ #
88
+ # @return [String]
89
+ #
90
+ attr_accessor :shell_api
91
+
92
+ def self.extended(base)
93
+ base.validate_on_create = true
94
+ base.validate_on_write = true
95
+ base.whiny = true
96
+ base.shell_api = "open3"
97
+ base.logger = Logger.new($stdout).tap { |l| l.level = Logger::INFO }
98
+ end
99
+
100
+ ##
101
+ # @yield [self]
102
+ # @example
103
+ # MiniMagick.configure do |config|
104
+ # config.cli = :graphicsmagick
105
+ # config.timeout = 5
106
+ # end
107
+ #
108
+ def configure
109
+ yield self
110
+ end
111
+
112
+ CLI_DETECTION = {
113
+ imagemagick: "mogrify",
114
+ graphicsmagick: "gm",
115
+ imagemagick7: "magick",
116
+ }
117
+
118
+ # @private (for backwards compatibility)
119
+ def processor
120
+ @processor ||= CLI_DETECTION.values.detect do |processor|
121
+ MiniMagick::Utilities.which(processor)
122
+ end
123
+ end
124
+
125
+ # @private (for backwards compatibility)
126
+ def processor=(processor)
127
+ @processor = processor.to_s
128
+
129
+ unless CLI_DETECTION.value?(@processor)
130
+ raise ArgumentError,
131
+ "processor has to be set to either \"magick\", \"mogrify\" or \"gm\"" \
132
+ ", was set to #{@processor.inspect}"
133
+ end
134
+ end
135
+
136
+ ##
137
+ # Get [ImageMagick](http://www.imagemagick.org) or
138
+ # [GraphicsMagick](http://www.graphicsmagick.org).
139
+ #
140
+ # @return [Symbol] `:imagemagick` or `:graphicsmagick`
141
+ #
142
+ def cli
143
+ if instance_variable_defined?("@cli")
144
+ instance_variable_get("@cli")
145
+ else
146
+ cli = CLI_DETECTION.key(processor) or
147
+ fail MiniMagick::Error, "You must have ImageMagick or GraphicsMagick installed"
148
+
149
+ instance_variable_set("@cli", cli)
150
+ end
151
+ end
152
+
153
+ ##
154
+ # Set whether you want to use [ImageMagick](http://www.imagemagick.org) or
155
+ # [GraphicsMagick](http://www.graphicsmagick.org).
156
+ #
157
+ def cli=(value)
158
+ @cli = value
159
+
160
+ if not CLI_DETECTION.key?(@cli)
161
+ raise ArgumentError,
162
+ "CLI has to be set to either :imagemagick, :imagemagick7 or :graphicsmagick" \
163
+ ", was set to #{@cli.inspect}"
164
+ end
165
+ end
166
+
167
+ ##
168
+ # If you set the path of CLI tools, you can get the path of the
169
+ # executables.
170
+ #
171
+ # @return [String]
172
+ #
173
+ def cli_path
174
+ if instance_variable_defined?("@cli_path")
175
+ instance_variable_get("@cli_path")
176
+ else
177
+ processor_path = instance_variable_get("@processor_path") if instance_variable_defined?("@processor_path")
178
+
179
+ instance_variable_set("@cli_path", processor_path)
180
+ end
181
+ end
182
+
183
+ ##
184
+ # When set to `true`, it outputs each command to STDOUT in their shell
185
+ # version.
186
+ #
187
+ def debug=(value)
188
+ warn "MiniMagick.debug is deprecated and will be removed in MiniMagick 5. Use `MiniMagick.logger.level = Logger::DEBUG` instead."
189
+ logger.level = value ? Logger::DEBUG : Logger::INFO
190
+ end
191
+
192
+ # Backwards compatibility
193
+ def reload_tools
194
+ warn "MiniMagick.reload_tools is deprecated because it is no longer necessary"
195
+ end
196
+
197
+ end
198
+ end
@@ -0,0 +1,192 @@
1
+ require "json"
2
+
3
+ module MiniMagick
4
+ class Image
5
+ # @private
6
+ class Info
7
+ ASCII_ENCODED_EXIF_KEYS = %w[ExifVersion FlashPixVersion]
8
+
9
+ def initialize(path)
10
+ @path = path
11
+ @info = {}
12
+ end
13
+
14
+ def [](value, *args)
15
+ case value
16
+ when "format", "width", "height", "dimensions", "size", "human_size"
17
+ cheap_info(value)
18
+ when "colorspace"
19
+ colorspace
20
+ when "mime_type"
21
+ mime_type
22
+ when "resolution"
23
+ resolution(*args)
24
+ when "signature"
25
+ signature
26
+ when /^EXIF\:/i
27
+ raw_exif(value)
28
+ when "exif"
29
+ exif
30
+ when "details"
31
+ details
32
+ when "data"
33
+ data
34
+ else
35
+ raw(value)
36
+ end
37
+ end
38
+
39
+ def clear
40
+ @info.clear
41
+ end
42
+
43
+ def cheap_info(value)
44
+ @info.fetch(value) do
45
+ format, width, height, size = self["%m %w %h %b"].split(" ")
46
+
47
+ path = @path
48
+ path = path.match(/\[\d+\]$/).pre_match if path =~ /\[\d+\]$/
49
+
50
+ @info.update(
51
+ "format" => format,
52
+ "width" => Integer(width),
53
+ "height" => Integer(height),
54
+ "dimensions" => [Integer(width), Integer(height)],
55
+ "size" => File.size(path),
56
+ "human_size" => size,
57
+ )
58
+
59
+ @info.fetch(value)
60
+ end
61
+ rescue ArgumentError, TypeError
62
+ raise MiniMagick::Invalid, "image data can't be read"
63
+ end
64
+
65
+ def colorspace
66
+ @info["colorspace"] ||= self["%r"]
67
+ end
68
+
69
+ def mime_type
70
+ "image/#{self["format"].downcase}"
71
+ end
72
+
73
+ def resolution(unit = nil)
74
+ output = identify do |b|
75
+ b.units unit if unit
76
+ b.format "%x %y"
77
+ end
78
+ output.split(" ").map(&:to_i)
79
+ end
80
+
81
+ def raw_exif(value)
82
+ self["%[#{value}]"]
83
+ end
84
+
85
+ def exif
86
+ @info["exif"] ||= (
87
+ hash = {}
88
+ output = self["%[EXIF:*]"]
89
+
90
+ output.each_line do |line|
91
+ line = line.chomp("\n")
92
+
93
+ case MiniMagick.cli
94
+ when :imagemagick, :imagemagick7
95
+ if match = line.match(/^exif:/)
96
+ key, value = match.post_match.split("=", 2)
97
+ value = decode_comma_separated_ascii_characters(value) if ASCII_ENCODED_EXIF_KEYS.include?(key)
98
+ hash[key] = value
99
+ else
100
+ hash[hash.keys.last] << "\n#{line}"
101
+ end
102
+ when :graphicsmagick
103
+ next if line == "unknown"
104
+ key, value = line.split("=", 2)
105
+ value.gsub!("\\012", "\n") # convert "\012" characters to newlines
106
+ hash[key] = value
107
+ end
108
+ end
109
+
110
+ hash
111
+ )
112
+ end
113
+
114
+ def raw(value)
115
+ @info["raw:#{value}"] ||= identify { |b| b.format(value) }
116
+ end
117
+
118
+ def signature
119
+ @info["signature"] ||= self["%#"]
120
+ end
121
+
122
+ def details
123
+ warn "[MiniMagick] MiniMagick::Image#details has been deprecated, as it was causing too many parsing errors. You should use MiniMagick::Image#data instead, which differs in a way that the keys are in camelcase." if MiniMagick.imagemagick? || MiniMagick.imagemagick7?
124
+
125
+ @info["details"] ||= (
126
+ details_string = identify(&:verbose)
127
+ key_stack = []
128
+ details_string.lines.to_a[1..-1].each_with_object({}) do |line, details_hash|
129
+ next if !line.valid_encoding? || line.strip.length.zero?
130
+
131
+ level = line[/^\s*/].length / 2 - 1
132
+ if level >= 0
133
+ key_stack.pop until key_stack.size <= level
134
+ else
135
+ # Some metadata, such as SVG clipping paths, will be saved without
136
+ # indentation, resulting in a level of -1
137
+ last_key = details_hash.keys.last
138
+ details_hash[last_key] = '' if details_hash[last_key].empty?
139
+ details_hash[last_key] << line
140
+ next
141
+ end
142
+
143
+ key, _, value = line.partition(/:[\s]/).map(&:strip)
144
+ hash = key_stack.inject(details_hash) { |_hash, _key| _hash.fetch(_key) }
145
+ if value.empty?
146
+ hash[key] = {}
147
+ key_stack.push key
148
+ else
149
+ hash[key] = value
150
+ end
151
+ end
152
+ )
153
+ end
154
+
155
+ def data
156
+ raise Error, "MiniMagick::Image#data isn't supported on GraphicsMagick. Use MiniMagick::Image#details instead." if MiniMagick.graphicsmagick?
157
+
158
+ @info["data"] ||= (
159
+ json = MiniMagick::Tool::Convert.new do |convert|
160
+ convert << path
161
+ convert << "json:"
162
+ end
163
+
164
+ data = JSON.parse(json)
165
+ data = data.fetch(0) if data.is_a?(Array)
166
+ data.fetch("image")
167
+ )
168
+ end
169
+
170
+ def identify
171
+ MiniMagick::Tool::Identify.new do |builder|
172
+ yield builder if block_given?
173
+ builder << path
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def decode_comma_separated_ascii_characters(encoded_value)
180
+ return encoded_value unless encoded_value.include?(',')
181
+ encoded_value.scan(/\d+/).map(&:to_i).map(&:chr).join
182
+ end
183
+
184
+ def path
185
+ value = @path
186
+ value += "[0]" unless value =~ /\[\d+\]$/
187
+ value
188
+ end
189
+
190
+ end
191
+ end
192
+ end