micro_magick 0.0.6 → 0.0.7

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.
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
-