micro_magick 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmJlNTMwZTY3OTVhNmIxZDQwNzE4OWRkZjU1Mzk3NTdmZmY2Nzk1Mw==
4
+ YmJkMmI2NzI4MTk4ZDBiZTZjNmFkZDc4ZTljNWZjYzkwZTMyYzdmOQ==
5
5
  data.tar.gz: !binary |-
6
- ZDdmODVlZjMzZjhjNjkzMWIwNmU3YWExMzQwMzJjMzM0YzFlNTBlNA==
7
- !binary "U0hBNTEy":
6
+ Yzk2YzEyNTk2OTEzYzkyOWI1MGE4NTc3MGNiNmY0ZWI3OThiZDI0NA==
7
+ SHA512:
8
8
  metadata.gz: !binary |-
9
- MjljYjdhNDk3MjVhYTlmMzFiNmE5ZDU2YmM5NTJmMDMwZTBmYjNkZDIyNmJi
10
- YTE5YWY0Y2NjZGFjYTA1ZDg2NzllMmMwNGQ1YjM3MzhmODAzOWU0M2VjOTgw
11
- MjZmNTFmMThkNzUwMmJiMjM1MWE0ZDlhYmFjN2I3N2U3YjFmZjY=
9
+ OTc4OGExNDUyOGRmMWFlZjIxODk3MGQ4Njg0ODRjMGUyODBlYzNjODQ5MjIy
10
+ YmJmZGI0ZTY1NTI3Y2U4NDdkN2M1YmY3YzdmMjUyNDgzN2YwYjcxMTE0OThj
11
+ MWJlNjFlZmUxYTIxMTgyZDQ4ZWVmOWQ3MGQ4YzI5YTg0ZWFkMmY=
12
12
  data.tar.gz: !binary |-
13
- Y2I5YTAyZGEyYTMzNmE1ZGExOTVkNjAxNDE2ZDBkMzljMzljMDcyMmYyZDNh
14
- ZjViOTUyZGZkOTJiMWExNjZkYjY0NTBlZDg1Y2VkNDY0OWE2OTZjNzZjOTAw
15
- ZmMzNGZiZWNjNGYyMGE0NzVjNTk3MGIzNGNhN2RiZTY1OWI4OWY=
13
+ NmI1ZmE4OTBlOTBlMGU4MjAxYzFmYjUzNTE2NGQ1OWE1NjEwMTRhYzAyNzUx
14
+ NmI3M2EwZDJmMzZmMjM1ZGMyODFkNjhlM2I0OTg1YjZmZjBmNTgxZTdjZDlm
15
+ NTI4ZWQzYWVhMGUwMjY0MzcyMTg2ZWJiOWViOTM0MjZmMTM2ZWI=
@@ -1,49 +1,62 @@
1
- require "micro_magick/version"
2
- require "micro_magick/convert"
3
- require "micro_magick/geometry"
4
- require "tempfile"
1
+ require 'micro_magick/version'
2
+ require 'micro_magick/identify_parser'
3
+ require 'micro_magick/image'
4
+ require 'open3'
5
5
 
6
6
  module MicroMagick
7
7
 
8
- InvalidArgument = Class.new(StandardError)
8
+ Error = Class.new(StandardError)
9
+ NoSuchFile = Class.new(Error)
10
+ MissingBinaries = Class.new(Error)
11
+ ArgumentError = Class.new(Error)
12
+ CorruptImageError = Class.new(Error)
9
13
 
10
- ENGINE2PREFIX = { :imagemagick => nil, :graphicsmagick => "gm" }
14
+ def self.use_imagemagick
15
+ @cmd_prefix = ''
16
+ end
11
17
 
12
- # @param engine must be :imagemagick, :graphicsmagick, or nil (which means reset to default behavior,
13
- # which means the next run will determine if GraphicsMagick or ImageMagick is installed)
14
- def self.use(engine)
15
- unless engine.nil? || ENGINE2PREFIX.keys.include?(engine)
16
- raise InvalidArgument, "Unknown graphics engine #{engine}"
17
- end
18
- @engine = engine
18
+ def self.use_graphicsmagick
19
+ @cmd_prefix = 'gm '
20
+ end
21
+
22
+ def self.reset!
23
+ @cmd_prefix = nil
19
24
  end
20
25
 
21
26
  def self.cmd_prefix
22
- @engine ||= begin
23
- if system("hash gm 2>&-")
24
- :graphicsmagick
25
- elsif system("hash convert 2>&-")
26
- :imagemagick
27
+ @cmd_prefix ||= begin
28
+ if system('hash gm 2>&-')
29
+ 'gm '
30
+ elsif system('hash convert 2>&-')
31
+ ''
27
32
  else
28
- raise InvalidArgument, "Please install either GraphicsMagick or ImageMagick"
33
+ raise MissingBinaries, 'Please install either GraphicsMagick or ImageMagick'
29
34
  end
30
35
  end
31
- ENGINE2PREFIX[@engine]
32
36
  end
33
37
 
34
- def self.exec(cmd)
35
- stderr_file = Tempfile.new('stderr')
36
- stderr_path = stderr_file.path
37
- stderr_file.close
38
- result = `#{cmd} 2>"#{stderr_path}"`
39
- stderr = File.read(stderr_path).strip
40
- stderr_file.delete
41
- if $?.exitstatus != 0 || !stderr.empty?
42
- raise InvalidArgument, "#{cmd} failed: #{stderr}"
38
+ def self.exec(cmds, return_stdout = false)
39
+ final_cmd = cmd_prefix + cmds.join(' ')
40
+ stdout = Open3.popen3(final_cmd) do |stdin, stdout, stderr|
41
+ err = stderr.read.strip
42
+ if err.size > 0
43
+ error = if err =~ /unrecognized option/i
44
+ ArgumentError
45
+ elsif err =~ /corrupt/i
46
+ CorruptImageError
47
+ elsif err =~ /no such file or directory|unable to open/i
48
+ NoSuchFile
49
+ else
50
+ Error
51
+ end
52
+ raise error, "#{final_cmd} failed: #{err}"
53
+ end
54
+ stdout.read.strip
43
55
  end
44
- result
56
+ return_stdout ? stdout : final_cmd
57
+ rescue Errno::ENOENT => e
58
+ raise NoSuchFile, e.message
45
59
  end
46
-
47
60
  end
48
61
 
49
62
 
@@ -0,0 +1,54 @@
1
+ module MicroMagick
2
+ class IdentifyParser
3
+
4
+ attr_reader :results
5
+
6
+ def initialize(stdout)
7
+ cleaned = stdout.encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
8
+ @lines = cleaned.split("\n").select { |ea| ea =~ /\S+:/ }
9
+ if @lines.empty?
10
+ @results = {}
11
+ else
12
+ @results = parse[:image] # < remove the "image" prefix.
13
+ if (m = /(\d+)x(\d+)/.match(@results[:geometry]))
14
+ @results[:width], @results[:height] = m[1].to_i, m[2].to_i
15
+ end
16
+ end
17
+ end
18
+
19
+ def [](key)
20
+ results[key_to_sym(key)]
21
+ end
22
+
23
+ def parse
24
+ result = {}
25
+ while true
26
+ line = @lines.shift
27
+ key, value = split(line)
28
+ if @lines.first && indent(line) < indent(@lines.first)
29
+ # The current line has a sub-section.
30
+ result[key] = parse()
31
+ else
32
+ result[key] = value
33
+ end
34
+
35
+ # Next line is indented less than the current line:
36
+ break if @lines.first.nil? || indent(line) > indent(@lines.first)
37
+ end
38
+ result
39
+ end
40
+
41
+ def indent(line)
42
+ /\S/.match(line).begin(0)
43
+ end
44
+
45
+ def split(line)
46
+ k, v = line.split(':', 2).map(&:strip)
47
+ [key_to_sym(k), v]
48
+ end
49
+
50
+ def key_to_sym(key)
51
+ key.is_a?(Symbol) ? key : key.strip.gsub(/[\b\W_-]+/, '_').downcase.to_sym
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,116 @@
1
+ require 'shellwords'
2
+ require 'yaml'
3
+
4
+ module MicroMagick
5
+ class Image
6
+ attr_reader :input_file
7
+
8
+ def initialize(input_file)
9
+ @input_file = input_file
10
+ @input_options = []
11
+ @output_options = []
12
+ end
13
+
14
+ def [](key)
15
+ identify[key]
16
+ end
17
+
18
+ def width
19
+ self[:width]
20
+ end
21
+
22
+ def height
23
+ self[:height]
24
+ end
25
+
26
+ def corrupt?
27
+ identify && @corrupt
28
+ end
29
+
30
+ # Strip the image of any profiles or comments.
31
+ # Note that this re-encodes the image, so it should only be used when downsampling
32
+ # (say, for a thumbnail)
33
+ # (ImageMagick has the -strip command, but GraphicsMagick doesn't.
34
+ # It turns out that ```+profile *``` does the same thing.)
35
+ def strip
36
+ add_output_option('+profile', '*')
37
+ end
38
+
39
+ # Crop to a square, using the specified gravity.
40
+ def square_crop(gravity = 'Center')
41
+ gravity(gravity) unless gravity.nil?
42
+ d = [width, height].min
43
+ crop("#{d}x#{d}+0+0!")
44
+ end
45
+
46
+ # For normal options, like -resize or -flip, you can call .resize("32x32") or .flip().
47
+ # If you need to add an output option that starts with a '+', you can use this method.
48
+ def add_output_option(option_name, *args)
49
+ (@output_options ||= []).push(option_name)
50
+ args.each { |ea| @output_options.push(Shellwords.escape(ea.to_s)) }
51
+
52
+ # if we're a resize call, let's give the -size render hint to gm, but only when it's safe:
53
+ # * we don't have input options yet,
54
+ # * we're not cropping (because the -size will prevent the crop from working),
55
+ # * and we have dimensions in the form of NNNxNNN
56
+ if %w{-geometry -resize -sample -scale}.include?(option_name) &&
57
+ @input_options.empty? &&
58
+ !@output_options.include?('-crop')
59
+ dimensions = args.first
60
+ if dimensions.to_s =~ /\A(\d+x\d+)\z/
61
+ @input_options.push('-size', dimensions)
62
+ end
63
+ end
64
+ # Support call chaining:
65
+ self
66
+ end
67
+
68
+ # Runs "convert"
69
+ # See http://www.imagemagick.org/script/convert.php
70
+ def write(output_file)
71
+ MicroMagick.exec(command('convert', output_file))
72
+ ensure
73
+ @input_options.clear
74
+ @output_options.clear
75
+ end
76
+
77
+ # Runs "mogrify"
78
+ # See http://www.imagemagick.org/script/mogrify.php
79
+ def overwrite
80
+ MicroMagick.exec(command('mogrify'))
81
+ ensure
82
+ @input_options.clear
83
+ @output_options.clear
84
+ end
85
+
86
+ private
87
+
88
+ def method_missing(method, *args, &block)
89
+ add_output_option("-#{method.to_s}", *args)
90
+ end
91
+
92
+ def command(command_name, output_file = nil)
93
+ cmd = [command_name]
94
+ cmd.push *@input_options
95
+ cmd.push Shellwords.escape(@input_file)
96
+ cmd.push *@output_options
97
+ cmd.push(Shellwords.escape(output_file)) if output_file
98
+ cmd
99
+ end
100
+
101
+ def identify
102
+ @identify || begin
103
+ cmd = ['identify', '-verbose', Shellwords.escape(input_file)]
104
+ @identify = IdentifyParser.new(MicroMagick.exec(cmd, true)).results
105
+ @corrupt = false
106
+ rescue CorruptImageError => e
107
+ @identify = {}
108
+ @corrupt = true
109
+ end
110
+ @identify
111
+ end
112
+ end
113
+
114
+ # Aliases to support < v0.0.6
115
+ Geometry = Convert = Image
116
+ end
@@ -1,3 +1,3 @@
1
1
  module MicroMagick
2
- VERSION = "0.0.6"
2
+ VERSION = '0.0.7'
3
3
  end
Binary file
@@ -0,0 +1,185 @@
1
+ require 'test_helper'
2
+
3
+ describe MicroMagick::IdentifyParser do
4
+ describe 'simple parsing functions' do
5
+ let(:ip) { MicroMagick::IdentifyParser.new('') }
6
+ it 'converts keys to expected symbols' do
7
+ ip.key_to_sym('Image').must_equal :image
8
+ ip.key_to_sym('Channel Depths').must_equal :channel_depths
9
+ ip.key_to_sym('JPEG-Quality').must_equal :jpeg_quality
10
+ ip.key_to_sym('Y Cb Cr Positioning').must_equal :y_cb_cr_positioning
11
+ ip.key_to_sym('Profile-EXIF').must_equal :profile_exif
12
+ end
13
+
14
+ it 'determines line indent properly' do
15
+ ip.indent('Image: out.jpeg').must_equal 0
16
+ ip.indent(' Channel Depths:').must_equal 2
17
+ ip.indent(' Blue:').must_equal 4
18
+ end
19
+ end
20
+
21
+ describe 'with expected output' do
22
+ let(:ip) do
23
+ MicroMagick::IdentifyParser.new(<<-OUT)
24
+ Image: /tmp/input.jpg
25
+ Format: JPEG (Joint Photographic Experts Group JFIF format)
26
+ Mime type: image/jpeg
27
+ Class: DirectClass
28
+ Geometry: 1152x2048+0+0
29
+ Resolution: 72x72
30
+ Print size: 16x28.4444
31
+ Units: PixelsPerInch
32
+ Type: TrueColor
33
+ Endianess: Undefined
34
+ Colorspace: sRGB
35
+ Depth: 8-bit
36
+ Channel depth:
37
+ red: 8-bit
38
+ green: 8-bit
39
+ blue: 8-bit
40
+ Channel statistics:
41
+ Red:
42
+ min: 0 (0)
43
+ max: 255 (1)
44
+ mean: 133.986 (0.525437)
45
+ standard deviation: 54.1069 (0.212184)
46
+ kurtosis: -0.874804
47
+ skewness: -0.488666
48
+ Green:
49
+ min: 0 (0)
50
+ max: 255 (1)
51
+ mean: 119.681 (0.469337)
52
+ standard deviation: 64.5707 (0.253218)
53
+ kurtosis: -1.43104
54
+ skewness: -0.207503
55
+ Blue:
56
+ min: 0 (0)
57
+ max: 255 (1)
58
+ mean: 102.697 (0.402734)
59
+ standard deviation: 75.4283 (0.295797)
60
+ kurtosis: -1.69738
61
+ skewness: 0.0278036
62
+ Image statistics:
63
+ Overall:
64
+ min: 0 (0)
65
+ max: 255 (1)
66
+ mean: 118.788 (0.465836)
67
+ standard deviation: 65.2849 (0.256019)
68
+ kurtosis: -1.25648
69
+ skewness: -0.301872
70
+ Rendering intent: Perceptual
71
+ Gamma: 0.454545
72
+ Chromaticity:
73
+ red primary: (0.64,0.33)
74
+ green primary: (0.3,0.6)
75
+ blue primary: (0.15,0.06)
76
+ white point: (0.3127,0.329)
77
+ Background color: white
78
+ Border color: srgb(223,223,223)
79
+ Matte color: grey74
80
+ Transparent color: black
81
+ Interlace: None
82
+ Intensity: Undefined
83
+ Compose: Over
84
+ Page geometry: 1152x2048+0+0
85
+ Dispose: Undefined
86
+ Iterations: 0
87
+ Compression: JPEG
88
+ Quality: 94
89
+ Orientation: TopLeft
90
+ Properties:
91
+ date:create: 2014-02-09T08:59:26-08:00
92
+ date:modify: 2014-02-09T08:59:25-08:00
93
+ exif:ApertureValue: 228/100
94
+ exif:BrightnessValue: 105984/65536
95
+ exif:ColorSpace: 1
96
+ exif:ComponentsConfiguration: 1, 2, 3, 0
97
+ exif:Compression: 6
98
+ exif:DateTime: 2014:02:07 08:38:21
99
+ exif:DateTimeDigitized: 2014:02:07 08:38:21
100
+ exif:DateTimeOriginal: 2014:02:07 08:38:21
101
+ exif:ExifImageLength: 2048
102
+ exif:ExifImageWidth: 1152
103
+ exif:ExifOffset: 230
104
+ exif:ExifVersion: 48, 50, 50, 48
105
+ exif:ExposureBiasValue: 0/10
106
+ exif:ExposureMode: 0
107
+ exif:ExposureProgram: 2
108
+ exif:ExposureTime: 1/25
109
+ exif:Flash: 0
110
+ exif:FlashPixVersion: 48, 49, 48, 48
111
+ exif:FNumber: 220/100
112
+ exif:FocalLength: 420/100
113
+ exif:FocalLengthIn35mmFilm: 31
114
+ exif:GPSAltitude: 0/1000
115
+ exif:GPSAltitudeRef: 0
116
+ exif:GPSDateStamp: 2014:02:07
117
+ exif:GPSInfo: 722
118
+ exif:GPSLatitude: 37/1, 46/1, 341802/10000
119
+ exif:GPSLatitudeRef: N
120
+ exif:GPSLongitude: 122/1, 25/1, 6225/10000
121
+ exif:GPSLongitudeRef: W
122
+ exif:GPSProcessingMethod: ASCII
123
+ exif:GPSTimeStamp: 16/1, 38/1, 11/1
124
+ exif:GPSVersionID: 2, 2, 0, 0
125
+ exif:ImageLength: 1152
126
+ exif:ImageUniqueID: 9e6076155a3bd1ce0000000000000000
127
+ exif:ImageWidth: 2048
128
+ exif:InteroperabilityIndex: R98
129
+ exif:InteroperabilityOffset: 948
130
+ exif:InteroperabilityVersion: 48, 49, 48, 48
131
+ exif:ISOSpeedRatings: 125
132
+ exif:JPEGInterchangeFormat: 1072
133
+ exif:JPEGInterchangeFormatLength: 4729
134
+ exif:LightSource: 0
135
+ exif:Make: SAMSUNG
136
+ exif:MaxApertureValue: 228/100
137
+ exif:MeteringMode: 1
138
+ exif:Model: SCH-I545
139
+ exif:Orientation: 1
140
+ exif:ResolutionUnit: 2
141
+ exif:SceneCaptureType: 0
142
+ exif:SceneType: 1
143
+ exif:SensingMethod: 2
144
+ exif:ShutterSpeedValue: 304394/65536
145
+ exif:Software: Google
146
+ exif:thumbnail:ResolutionUnit: 2
147
+ exif:thumbnail:XResolution: 72/1
148
+ exif:thumbnail:YResolution: 72/1
149
+ exif:WhiteBalance: 0
150
+ exif:XResolution: 72/1
151
+ exif:YCbCrPositioning: 1
152
+ exif:YResolution: 72/1
153
+ jpeg:colorspace: 2
154
+ jpeg:sampling-factor: 2x2,1x1,1x1
155
+ signature: 2e969ff76481f84c85031e191ee902825bf6c2a12fb6083da57633326cde2bef
156
+ Profiles:
157
+ Profile-exif: 5808 bytes
158
+ Profile-xmp: 325 bytes
159
+ Artifacts:
160
+ filename: /Users/mrm/Downloads/20140207_083822.jpg
161
+ verbose: true
162
+ Tainted: False
163
+ Filesize: 227KB
164
+ Number pixels: 2.359M
165
+ Pixels per second: 29.49MB
166
+ User time: 0.070u
167
+ Elapsed time: 0:01.080
168
+ Version: ImageMagick 6.8.7-7 Q16 x86_64 2013-11-27 http://www.imagemagick.org
169
+ OUT
170
+ end
171
+
172
+ it 'extracts width and depth from geometry' do
173
+ ip[:width].must_equal 1152
174
+ ip[:height].must_equal 2048
175
+ end
176
+
177
+ it 'extracts sub-sections properly' do
178
+ ip[:channel_depth][:red].must_equal '8-bit'
179
+ ip[:channel_depth][:green].must_equal '8-bit'
180
+ ip[:channel_depth][:blue].must_equal '8-bit'
181
+ ip[:artifacts][:verbose].must_equal 'true'
182
+ end
183
+ end
184
+
185
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+ require 'tempfile'
3
+
4
+ module ImageTests
5
+ def self.included spec_class
6
+ spec_class.class_eval do
7
+
8
+ let(:img) { MicroMagick::Convert.new('test/480x270.jpg') }
9
+
10
+ let(:corrupt) { MicroMagick::Convert.new('test/corrupt.jpg') }
11
+
12
+ # By using the block format, the tempfile will be closed and deleted:
13
+ let(:outfile) { Tempfile.open(%w(out .jpg)) { |ea| ea.path } }
14
+
15
+ it 'extracts image geometry correctly' do
16
+ img.width.must_equal 270
17
+ img.height.must_equal 480
18
+ img.corrupt?.must_be_false
19
+ end
20
+
21
+ it 'detects corrupt images properly' do
22
+ corrupt.width.must_be_nil
23
+ corrupt.height.must_be_nil
24
+ corrupt.corrupt?.must_be_true
25
+ end
26
+
27
+ it 'resizes to cropped square' do
28
+ img.resize('64x64')
29
+ command = img.write(outfile)
30
+ command.must_equal "#{MicroMagick.cmd_prefix}convert -size 64x64 test/480x270.jpg -resize 64x64 " + Shellwords.escape(outfile)
31
+ File.exist?(outfile).must_be_true
32
+ g = MicroMagick::Geometry.new(outfile)
33
+ g.width.must_equal 64 * 270 / 480
34
+ g.height.must_equal 64
35
+ end
36
+
37
+ it 'removes exif headers from .strip' do
38
+ img.strip
39
+ command = img.write(outfile)
40
+ command.must_equal "#{MicroMagick.cmd_prefix}convert test/480x270.jpg +profile \\* " + Shellwords.escape(outfile)
41
+ i = MicroMagick::Image.new('test/480x270.jpg')
42
+ i['Profile-EXIF'].must_be_nil
43
+ end
44
+
45
+ it 'crops properly' do
46
+ command = img.quality(85).square_crop('North').resize('128x128').write(outfile)
47
+ command.must_equal "#{MicroMagick.cmd_prefix}convert test/480x270.jpg " +
48
+ "-quality 85 -gravity North -crop 270x270\\+0\\+0\\! -resize 128x128 " +
49
+ Shellwords.escape(outfile)
50
+ File.exist?(outfile).must_be_true
51
+ g = MicroMagick::Image.new(outfile)
52
+ g.width.must_equal 128
53
+ g.height.must_equal 128
54
+
55
+ # make sure calling previous arguments don't leak into new calls:
56
+ img.resize("64x64")
57
+ command = img.write(outfile)
58
+ command.must_equal "#{MicroMagick.cmd_prefix}convert -size 64x64 test/480x270.jpg -resize 64x64 " +
59
+ Shellwords.escape(outfile)
60
+ end
61
+
62
+ it 'raises errors from invalid parameters' do
63
+ img.boing
64
+ proc { img.write(outfile) }.must_raise MicroMagick::ArgumentError
65
+ end
66
+
67
+ let(:enoent) { MicroMagick::Image.new('nonexistant-file.jpg') }
68
+
69
+ it 'raises NoSuchFile when fetching attributes' do
70
+ proc { enoent.width }.must_raise MicroMagick::NoSuchFile
71
+ end
72
+
73
+ it 'raises NoSuchFile from write' do
74
+ proc { enoent.overwrite }.must_raise MicroMagick::NoSuchFile
75
+ end
76
+
77
+ it 'raises NoSuchFile from overwrite' do
78
+ proc { enoent.overwrite }.must_raise MicroMagick::NoSuchFile
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,11 +1,8 @@
1
- require "./test/micro_magick_test_base"
2
-
3
- class MicroGmagickTest < MicroMagickTestBase
4
-
5
- def setup
6
- MicroMagick.use(:graphicsmagick)
7
- super
8
- end
1
+ require 'test_helper'
2
+ require 'image_tests'
9
3
 
4
+ describe 'Image tests under GraphicsMagick' do
5
+ before { MicroMagick.use_graphicsmagick }
6
+ include ImageTests
10
7
  end
11
8
 
@@ -1,11 +1,8 @@
1
- require "./test/micro_magick_test_base"
2
-
3
- class MicroImagickTest < MicroMagickTestBase
4
-
5
- def setup
6
- MicroMagick.use(:imagemagick)
7
- super
8
- end
1
+ require 'test_helper'
2
+ require 'image_tests'
9
3
 
4
+ describe 'Image tests under ImageMagick' do
5
+ before { MicroMagick.use_imagemagick }
6
+ include ImageTests
10
7
  end
11
8
 
@@ -1,34 +1,21 @@
1
- require "test/unit"
2
- require "micro_magick"
1
+ require 'test_helper'
3
2
 
4
- class MicroMagickTest < Test::Unit::TestCase
3
+ describe MicroMagick do
5
4
 
6
- def test_use_nil
7
- # This shouldn't throw:
8
- MicroMagick.use(nil)
9
-
10
- # eh, ok, now we should stub out system
11
- # and verify that the next call to cmd_prefix
12
- # calls `hash gm`?
13
-
14
- # Meh, let's just assume that the test running machine has gm in their PATH.
15
- assert_equal MicroMagick.cmd_prefix, "gm"
16
- end
17
-
18
- def test_use_invalid
19
- assert_raise MicroMagick::InvalidArgument do
20
- MicroMagick.use(:boink)
21
- end
5
+ it 'uses GraphicsMagick by default' do
6
+ # Assume that the machine that's running the test has gm in it's PATH
7
+ MicroMagick.reset!
8
+ MicroMagick.cmd_prefix.must_equal 'gm '
22
9
  end
23
10
 
24
- def test_use_gm
25
- MicroMagick.use(:graphicsmagick)
26
- assert_equal "gm", MicroMagick.cmd_prefix
11
+ it 'uses GraphicsMagick when set explicitly' do
12
+ MicroMagick.use_graphicsmagick
13
+ MicroMagick.cmd_prefix.must_equal 'gm '
27
14
  end
28
15
 
29
- def test_use_im
30
- MicroMagick.use(:imagemagick)
31
- assert_equal nil, MicroMagick.cmd_prefix
16
+ it 'uses ImageMagick when set explicitly' do
17
+ MicroMagick.use_imagemagick
18
+ MicroMagick.cmd_prefix.must_equal ''
32
19
  end
33
20
 
34
21
  end
@@ -0,0 +1,3 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/great_expectations'
3
+ require 'micro_magick'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: micro_magick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew McEachen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-23 00:00:00.000000000 Z
11
+ date: 2014-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,6 +24,62 @@ dependencies:
24
24
  - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
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: minitest
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: minitest-great_expectations
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: minitest-reporters
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'
27
83
  description: ''
28
84
  email:
29
85
  - matthew-github@mceachen.org
@@ -32,15 +88,17 @@ extensions: []
32
88
  extra_rdoc_files: []
33
89
  files:
34
90
  - lib/micro_magick.rb
35
- - lib/micro_magick/convert.rb
36
- - lib/micro_magick/geometry.rb
91
+ - lib/micro_magick/identify_parser.rb
92
+ - lib/micro_magick/image.rb
37
93
  - lib/micro_magick/version.rb
38
94
  - test/480x270.jpg
39
- - test/geometry_test.rb
95
+ - test/corrupt.jpg
96
+ - test/identify_parser_test.rb
97
+ - test/image_tests.rb
40
98
  - test/micro_gmagick_test.rb
41
99
  - test/micro_imagick_test.rb
42
100
  - test/micro_magick_test.rb
43
- - test/micro_magick_test_base.rb
101
+ - test/test_helper.rb
44
102
  homepage: https://github.com/mceachen/micro_magick
45
103
  licenses: []
46
104
  metadata: {}
@@ -60,14 +118,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
118
  version: '0'
61
119
  requirements: []
62
120
  rubyforge_project:
63
- rubygems_version: 2.0.3
121
+ rubygems_version: 2.2.0
64
122
  signing_key:
65
123
  specification_version: 4
66
- summary: The simplest and most correct ImageMagick/GraphicsMagick ruby wrapper
124
+ summary: Simple and efficient ImageMagick/GraphicsMagick ruby wrapper
67
125
  test_files:
68
126
  - test/480x270.jpg
69
- - test/geometry_test.rb
127
+ - test/corrupt.jpg
128
+ - test/identify_parser_test.rb
129
+ - test/image_tests.rb
70
130
  - test/micro_gmagick_test.rb
71
131
  - test/micro_imagick_test.rb
72
132
  - test/micro_magick_test.rb
73
- - test/micro_magick_test_base.rb
133
+ - test/test_helper.rb
134
+ has_rdoc:
@@ -1,84 +0,0 @@
1
- require 'shellwords'
2
-
3
- module MicroMagick
4
- class Convert
5
- def initialize(input_file)
6
- @input_file = input_file
7
- @input_options = []
8
- @output_options = []
9
- end
10
-
11
- def width
12
- geometry.width
13
- end
14
-
15
- def height
16
- geometry.height
17
- end
18
-
19
- def geometry
20
- @geometry ||= MicroMagick::Geometry.new(@input_file)
21
- end
22
-
23
- # strip the image of any profiles or comments
24
- # (ImageMagick has the -strip command, but GraphicsMagick doesn't.
25
- # It turns out that ```+profile *``` does the same thing.)
26
- def strip
27
- add_output_option("+profile", "*")
28
- end
29
-
30
- # Crop to a square, using the specified gravity.
31
- def square_crop(gravity = "Center")
32
- gravity(gravity) unless gravity.nil?
33
- d = [width, height].min
34
- crop("#{d}x#{d}+0+0!")
35
- end
36
-
37
- # For normal options, like -resize or -flip, you can call .resize("32x32") or .flip().
38
- # If you need to add an output option that starts with a '+', you can use this method.
39
- def add_output_option(option_name, *args)
40
- (@output_options ||= []) << option_name
41
- @output_options += args.collect { |ea| Shellwords.escape(ea.to_s) }
42
-
43
- # if we're a resize call, let's give the -size render hint to gm, but only when it's safe:
44
- # * we don't have input options yet,
45
- # * we're not cropping (because the -size will prevent the crop from working),
46
- # * and we have dimensions in the form of NNNxNNN
47
- if %w{-geometry -resize -sample -scale}.include?(option_name) &&
48
- @input_options.empty? &&
49
- !@output_options.include?("-crop")
50
- if (dimensions = args.first)
51
- if dimensions =~ /^(\d+x\d+)$/
52
- @input_options << "-size #{dimensions}"
53
- end
54
- end
55
- end
56
- end
57
-
58
-
59
- # Executes `convert`, writing to output_file, and clearing all previously set input and output options.
60
- # @return the command given to system()
61
- def write(output_file)
62
- @output_file = output_file
63
- cmd = command()
64
- MicroMagick.exec(cmd)
65
- @input_options.clear
66
- @output_options.clear
67
- cmd
68
- end
69
-
70
- protected
71
-
72
- def method_missing(method, *args, &block)
73
- add_output_option("-#{method.to_s}", *args)
74
- end
75
-
76
- def command
77
- ([MicroMagick.cmd_prefix, "convert"] +
78
- @input_options +
79
- [Shellwords.escape(@input_file)] +
80
- @output_options +
81
- [Shellwords.escape(@output_file)]).compact.join(" ")
82
- end
83
- end
84
- end
@@ -1,22 +0,0 @@
1
- require 'shellwords'
2
-
3
- module MicroMagick
4
- class Geometry
5
- attr_reader :width, :height
6
-
7
- def initialize(input_file)
8
- cmd = [MicroMagick.cmd_prefix,
9
- "identify",
10
- "-format",
11
- "%w:%h",
12
- Shellwords.escape(input_file)
13
- ]
14
- geometry = MicroMagick.exec(cmd.join(" "))
15
- @width, @height = geometry.split(':').collect { |ea| ea.to_i }
16
- end
17
-
18
- def to_s
19
- "#{width} x #{height}"
20
- end
21
- end
22
- end
@@ -1,10 +0,0 @@
1
- require "test/unit"
2
- require "micro_magick"
3
-
4
- class GeometryTest < Test::Unit::TestCase
5
- def test_geometry
6
- img = MicroMagick::Convert.new("test/480x270.jpg")
7
- assert_equal 270, img.width
8
- assert_equal 480, img.height
9
- end
10
- end
@@ -1,66 +0,0 @@
1
- require "test/unit"
2
- require "shellwords"
3
- require "micro_magick"
4
-
5
- class MicroMagickTestBase < Test::Unit::TestCase
6
-
7
- def setup
8
- @img = MicroMagick::Convert.new("test/480x270.jpg")
9
- tmp = Tempfile.new('out.jpg')
10
- @outfile = tmp.path
11
- tmp.close
12
- tmp.delete
13
- assert !File.exist?(@outfile)
14
- end
15
-
16
- def cmd_prefix
17
- s = MicroMagick.cmd_prefix
18
- s.nil? ? "" : s + " "
19
- end
20
-
21
- def test_resize
22
- @img.resize("64x64")
23
- command = @img.write(@outfile)
24
- assert_equal "#{cmd_prefix}convert -size 64x64 test/480x270.jpg -resize 64x64 " + Shellwords.escape(@outfile), command
25
- assert File.exist?(@outfile)
26
- g = MicroMagick::Geometry.new(@outfile)
27
- assert_equal (64 * (270.0/480.0)).to_i, g.width
28
- assert_equal 64, g.height
29
- end
30
-
31
- def test_strip
32
- @img.strip
33
- command = @img.write(@outfile)
34
- assert_equal "#{cmd_prefix}convert test/480x270.jpg +profile \\* " + Shellwords.escape(@outfile), command
35
- end
36
-
37
- def test_convert_with_crop
38
- @img.quality(85)
39
- @img.square_crop("North")
40
- @img.resize("128x128")
41
- command = @img.write(@outfile)
42
- assert_equal "#{cmd_prefix}convert test/480x270.jpg " +
43
- "-quality 85 -gravity North -crop 270x270\\+0\\+0\\! -resize 128x128 " +
44
- Shellwords.escape(@outfile),
45
- command
46
- assert File.exist?(@outfile)
47
- g = MicroMagick::Geometry.new(@outfile)
48
- assert_equal 128, g.width
49
- assert_equal 128, g.height
50
-
51
- # make sure calling previous arguments don't leak into new calls:
52
- @img.resize("64x64")
53
- command = @img.write(@outfile)
54
- assert_equal "#{cmd_prefix}convert -size 64x64 test/480x270.jpg -resize 64x64 " +
55
- Shellwords.escape(@outfile),
56
- command
57
- end
58
-
59
- def test_bad_args
60
- @img.boing
61
- assert_raise MicroMagick::InvalidArgument do
62
- @img.write(@outfile)
63
- end
64
- end
65
- end
66
-