image_voodoo 0.8.8 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10db8a256e32e37a28b94c9246049f7029484a49
4
- data.tar.gz: 27ec82a19aff0bc3171a2c0bff8338c1c7ef19e6
3
+ metadata.gz: 525eaa36345ce66a917c101be73299b04e2800cb
4
+ data.tar.gz: e851fe90c983c411388d7b1e37ef0c2e323f677b
5
5
  SHA512:
6
- metadata.gz: 9bf960b9cd108f06ea22ba69a5f01f7d5ee3ca10dec63fe7a79cf6d2fe986f9a6753ef1969c8eabfa95af8509e0b19211b6ea7c0718d6106c42d998e255e6e36
7
- data.tar.gz: 27e8b1a524c25f7a72b3b15c3a9e37e4bf983111410a8be64d78b45c55ce133ed185ec5cf47ab527b565828d106515fdf053ccc41ee0298b1b1b6df75fc923f3
6
+ metadata.gz: 02453c98b8e64606ecb01834cebd6d04ba96212377308ca3f4a36f2ab91ae79db59dee0ca1b8056d912b3e66eea71da20d120fb81935d98f6d3a1550e3e57b17
7
+ data.tar.gz: 204639d91890c6525a6bae30fd1db9fd61f999187576e5213ac064bc1b8b29e57d3b7412b4ae691e6c1caa9922bdf0659f5535c49a0ebfed9344af5721bdb4db
@@ -0,0 +1,115 @@
1
+ # Experiment to tweak source based on what rubocop wanted me to. I basically
2
+ # gave up and made the following exceptions. Personally, I find the tool did
3
+ # find many interesting/questionable code Qs in the project but it is soooo
4
+ # opinionated in pretty unimportant ways (like who cares how I write my
5
+ # comments, or why can't I use kind_of? or why give me a fail for a less
6
+ # readable but more performant pattern).
7
+ #
8
+ # I can obviously tweak rules (like below) but I keep hearing of people pulling
9
+ # their hair out over all the unimportant rules; I question why this project is
10
+ # "all-in" on it's rules versus leaving most of the style rules as some preset
11
+ # profiles people can opt in to.
12
+ #
13
+ # So I am committing this and I will try and run this every now and then to
14
+ # see what it thinks about what I wrote but you will not see this as a
15
+ # requirement for commits since I think by the time I configured it to my
16
+ # liking I could have finished implementing this library. Perhaps if I
17
+ # continue using this here and there I will end up with a profile I find
18
+ # acceptable? I did find value but all the piddly shit just made me angry.
19
+ # I will reflect on it some more...
20
+
21
+ # This is a Java AWT call. It is not what the tool thinks it is...which
22
+ # might be an issue for users interacting with Java from JRuby.
23
+ Lint/UselessSetterCall:
24
+ Exclude:
25
+ - 'lib/image_voodoo/awt.rb'
26
+
27
+ # This is just impossible for them to call properly. I am doing something
28
+ # like rotate_impl and it is a bunch of reasonably simple math. If you look
29
+ # for this transformation in a text book it will look like this code. Putting
30
+ # a bunch of math within different methods would get the score down but
31
+ # it would not help readability. (addendum: I did try and break it apart more
32
+ # and never reached 15 but got closer. I felt this rule is neat but the
33
+ # score really depends on what it is.
34
+ Metrics/AbcSize:
35
+ Max: 16.5
36
+
37
+ # This is triggered for correct_orientation_impl. I could put these transforms
38
+ # in a table and then execute lambdas for each orientation but this is much
39
+ # more clear.
40
+ Metrics/CyclomaticComplexity:
41
+ Max: 9
42
+
43
+ # A bunch of fields in a hash are basically generated data. Correcting them
44
+ # for column seems much too pedantic. I guess exclude is the right thing for
45
+ # an unusual file?
46
+ Metrics/LineLength:
47
+ Max: 132
48
+ Exclude:
49
+ - 'lib/image_voodoo/metadata.rb'
50
+
51
+ # Metadata classes have data in them. awt.rb is big and perhaps could be
52
+ # shrunk but it is not a hard file to navigate and the cleaving points are
53
+ # not super obvious. These sorts of rules feel very arbitrary and if I have
54
+ # n highly related things and they do not fit into a more restrictive
55
+ # taxonomy why would the file being longer matter? I do understand the
56
+ # motivation here but as a default rule this feels wrong to me.
57
+ Metrics/ClassLength:
58
+ Max: 250
59
+
60
+ # I do not find this very useful. There is no performance difference and
61
+ # sometimes I want to highlight this string does not involve interpolation.
62
+ # Other times it is not worth pointing out.
63
+ Style/StringLiterals:
64
+ Enabled: false
65
+
66
+ # require 'english' is a step too far for $! which is so baked into my
67
+ # head I do not want to change :)
68
+ Style/SpecialGlobalVars:
69
+ Enabled: false
70
+
71
+ # I am grouping math and using lack of whitespace for separation.
72
+ Style/SpaceAroundOperators:
73
+ Enabled: false
74
+
75
+ # I prefer tight assignment for opt args.
76
+ Style/SpaceAroundEqualsInParameterDefault:
77
+ Enabled: false
78
+
79
+ # Java methods which override or implement Java method names cannot be switched
80
+ # to snake case. Do we really need this as a rule anyways? I have never seen
81
+ # a Rubyist do this as a preferred style?
82
+ Style/MethodName:
83
+ Enabled: false
84
+
85
+ # bin/image_voodoo main options block.
86
+ Metrics/BlockLength:
87
+ Exclude:
88
+ - 'bin/image_voodoo'
89
+
90
+ # casecmp for this case seems like it is much less readable in a place where
91
+ # performance could never matter (a 3-4 char downcase before processing an
92
+ # image :) ). This could end up being important somewhere but as a default
93
+ # on it feels weird since I find it less readable.
94
+ Performance/Casecmp:
95
+ Exclude:
96
+ - 'lib/image_voodoo/awt.rb'
97
+
98
+ # Hash rocket looks much more natural in a rakefile for its deps.
99
+ Style/HashSyntax:
100
+ Exclude:
101
+ - 'Rakefile'
102
+
103
+ # Forget it. I do parallel assignment and you will have to peel it out of
104
+ # my cold dead hands.
105
+ Style/ParallelAssignment:
106
+ Enabled: false
107
+
108
+ # FIXME: consider keywords for shapes.
109
+ # I might switch these to keyword args if I ever revisit shapes support.
110
+ # In general lots of params do suck and are hard to remember. This library
111
+ # still is supposed to work in 1.8 but I can probably soon major rev this
112
+ # and switch over to keywords.
113
+ Metrics/ParameterLists:
114
+ Exclude:
115
+ - 'lib/image_voodoo/awt/shapes.rb'
@@ -1,2 +1,9 @@
1
+ language: ruby
2
+
3
+ sudo: false
4
+
1
5
  rvm:
2
6
  - jruby-19mode
7
+
8
+ before_script:
9
+ - git clone https://github.com/drewnoakes/metadata-extractor-images.git ../metadata-extractor-images
data/Rakefile CHANGED
@@ -4,10 +4,10 @@ Bundler::GemHelper.install_tasks
4
4
 
5
5
  task :default => :test
6
6
 
7
- desc "Run tests"
7
+ desc 'Run tests'
8
8
  task :test do
9
9
  Rake::TestTask.new do |t|
10
- t.libs << "lib:vendor"
10
+ t.libs << 'lib:vendor'
11
11
  t.test_files = FileList['test/test*.rb']
12
12
  end
13
13
  end
@@ -7,101 +7,91 @@ actions = []
7
7
  images = []
8
8
  original_image = nil
9
9
 
10
- opts = OptionParser.new do |opts|
11
- opts.banner = "Usage: image_voodoo [actions] image_file"
12
- opts.separator "Perform some actions on a source image."
13
-
14
- opts.separator ""
15
- opts.separator "Actions are meant to be chained. Examples:"
16
- opts.separator " # Print the dimensions"
17
- opts.separator " image_voodoo --dim small.jpg"
18
- opts.separator ""
19
- opts.separator " # Convert to a thumbnail, preview, and then save the result"
20
- opts.separator " image_voodoo --thumbnail 50 --preview --save thumb.png large.jpg"
21
- opts.separator ""
22
- opts.separator " # Convert source to 3 thumbnails, showing dimensions and"
23
- opts.separator " # previewing along the way"
24
- opts.separator " image_voodoo --dim --resize 50x50 --dim --preview --save t1.jpg"
25
- opts.separator " --pop --resize 40x40 --dim --preview --save t2.jpg"
26
- opts.separator " --pop --resize 30x30 --dim --preview --save t3.jpg image.jpg"
27
-
28
- opts.separator ""
29
- opts.separator "Actions:"
30
-
31
- opts.on("-a", "--alpha color_value", "Make color transparent in image") do |c|
32
- if c !~ /[[:xdigit:]]{6,6}/
33
- opts.usage "color_value is rrggbb in hexidecimal format"
34
- end
35
- actions << lambda {|img| img.alpha(c) }
36
- end
37
-
38
- opts.on("-b", "--brightness SCALE,OFFSET", "Adjust brightness") do |args|
39
- scale, offset = args.split(/,/).map {|v| v.to_f}
40
- opts.usage "You need to specify proper scale and offset" unless scale && offset
41
- actions << lambda {|img| img.adjust_brightness(scale, offset) }
42
- end
43
-
44
- opts.on("-B", "--border WIDTH,COLOR,STYLE", "Add a simple border") do |args|
10
+ opts = OptionParser.new do |o|
11
+ o.banner = 'Usage: image_voodoo [actions] image_file'
12
+ o.separator 'Perform actions/transformations on an image.'
13
+ o.separator ''
14
+ o.separator 'Examples:'
15
+ o.separator ' image_voodoo --dim small.jpg # Print the dimensions'
16
+ o.separator ''
17
+ o.separator ' # Make a thumbnail, preview it, and then save it.'
18
+ o.separator ' image_voodoo --thumbnail 50 --preview --save thumb.png large.jpg'
19
+ o.separator ''
20
+ o.separator ' # Make 2 thumbnails, showing dimensions and previewing them'
21
+ o.separator ' image_voodoo --dim --resize 50x50 --dim --preview --save t1.jpg'
22
+ o.separator ' --pop --resize 40x40 --dim --preview --save t2.jpg image.jpg'
23
+ o.separator ''
24
+ o.separator 'Actions:'
25
+
26
+ o.on('-a', '--alpha rrggbb', 'Make color transparent in image') do |c|
27
+ o.usage 'rrggbb is in hexidecimal format' if c !~ /[[:xdigit:]]{6,6}/
28
+ actions << ->(img) { img.alpha(c) }
29
+ end
30
+
31
+ o.on('-b', '--brightness SCALE,OFFSET', 'Adjust brightness') do |args|
32
+ scale, offset = args.split(/,/).map(&:to_f)
33
+ o.usage 'You need to specify proper scale and offset' unless scale && offset
34
+ actions << ->(img) { img.adjust_brightness(scale, offset) }
35
+ end
36
+
37
+ o.on('-B', '--border WIDTH,COLOR,STYLE', 'Add a simple border') do |args|
45
38
  width, color, style = args.split(/,/)
46
- options = {:width => width, :color => color, :style => style }
47
-
48
- actions << lambda {|img| img.add_border(options) }
39
+ options = { width: width, color: color, style: style }
40
+ actions << ->(img) { img.add_border(options) }
49
41
  end
50
42
 
51
- opts.on("-d", "--dimensions", "Print the image dimensions") do
52
- actions << lambda {|img| puts "#{img.width}x#{img.height}"; img }
43
+ o.on('-d', '--dimensions', 'Print the image dimensions') do
44
+ actions << ->(img) { img.tap { puts "#{img.width}x#{img.height}" } }
53
45
  end
54
46
 
55
- opts.on("-g", "--greyscale", "Convert image to greyscale") do
56
- actions << lambda {|img| img.greyscale }
47
+ o.on('-g', '--greyscale', 'Convert image to greyscale') do
48
+ actions << ->(img) { img.greyscale }
57
49
  end
58
50
 
59
- opts.on("-h", "--flip_horizontally") do
60
- actions << lambda {|img| img.flip_horizontally }
51
+ o.on('-h', '--flip_horizontally') do
52
+ actions << ->(img) { img.flip_horizontally }
61
53
  end
62
54
 
63
- opts.on("-m", "--metadata") do
64
- actions << lambda {|img| puts img.metadata }
55
+ o.on('-m', '--metadata') do
56
+ actions << ->(img) { img.tap { puts img.metadata } }
65
57
  end
66
58
 
67
- opts.on("-n", "--negative", "Make a negative out of the image") do
68
- actions << lambda {|img| img.negative }
59
+ o.on('-n', '--negative', 'Make a negative out of the image') do
60
+ actions << ->(img) { img.negative }
69
61
  end
70
62
 
71
- opts.on("-o", "--orient", "Rotate image to orient it based on metadata") do
72
- actions << lambda {|img| img.correct_orientation }
63
+ o.on('-o', '--orient', 'Rotate image to orient it based on metadata') do
64
+ actions << ->(img) { img.correct_orientation }
73
65
  end
74
66
 
75
- opts.on("-q", "--quality 0..1", Float, "Set % of quality for lossy compression") do |quality|
76
- actions << lambda {|img| img.quality(quality) }
67
+ o.on('-q', '--quality 0..1', Float, 'Set % of quality for lossy compression') do |quality|
68
+ actions << ->(img) { img.quality(quality) }
77
69
  end
78
70
 
79
- opts.on("-R", "--rotate 0..360", Float, "Set angle to rotate image") do |angle|
80
- actions << lambda {|img| img.rotate(angle.to_f) }
71
+ o.on('-R', '--rotate 0..360', Float, 'Set angle to rotate image') do |angle|
72
+ actions << ->(img) { img.rotate(angle.to_f) }
81
73
  end
82
74
 
83
- opts.on("-r", "--resize WIDTHxHEIGHT", "Create a new image with the specified", "dimensions") do |dim|
84
- width, height = dim.split(/x/i).map {|v| v.to_i}
85
- opts.usage "You need to specify proper dimensions" unless width && width > 0 && height && height > 0
86
- actions << lambda {|img| img.resize(width,height) }
75
+ o.on('-r', '--resize WIDTHxHEIGHT', 'Make a new resized image') do |dim|
76
+ width, height = dim.split(/x/i).map(&:to_i)
77
+ o.usage 'You need to specify proper dimensions' unless width && width > 0 && height && height > 0
78
+ actions << ->(img) { img.resize(width, height) }
87
79
  end
88
80
 
89
-
90
- opts.on("-s", "--save FILENAME", "Save the results to a new file") do |f|
91
- actions << lambda {|img| img.save(f); img }
81
+ o.on('-s', '--save FILENAME', 'Save the results to a new file') do |f|
82
+ actions << ->(img) { img.tap { img.save(f) } }
92
83
  end
93
84
 
94
- opts.on("-t", "--thumbnail SIZE", Integer, "Create a thumbnail of the given size") do |size|
95
- actions << lambda {|img| img.thumbnail(size) }
85
+ o.on('-t', '--thumbnail SIZE', Integer, 'Create a thumbnail of the given size') do |size|
86
+ actions << ->(img) { img.thumbnail(size) }
96
87
  end
97
88
 
98
- opts.on("-v", "--flip_vertically") do
99
- actions << lambda {|img| img.flip_vertically }
100
- end
101
-
102
- opts.on("-p", "--preview", "Preview the image. Close the frame window",
103
- "to continue, or quit the application to", "abort the action pipeline") do
89
+ o.on('-v', '--flip_vertically') { actions << ->(img) { img.flip_vertically } }
104
90
 
91
+ o.on('-p', '--preview',
92
+ 'Preview the image. Close the frame window',
93
+ 'to continue, or quit the application to',
94
+ 'abort the action pipeline') do
105
95
  headless = false
106
96
  actions << lambda do |img|
107
97
  done = false
@@ -111,36 +101,33 @@ opts = OptionParser.new do |opts|
111
101
  end
112
102
  end
113
103
 
114
- opts.on("--push", "Save the current image to be popped later") do
115
- actions << lambda {|img| images << img; img }
104
+ o.on('--push', 'Save the current image to be popped later') do
105
+ actions << ->(img) { img.tap { images << img } }
116
106
  end
117
107
 
118
- opts.on("--pop", "Revert back to the previous saved image", "or the original source image") do
119
- actions << lambda {|img| images.pop || original_image }
108
+ o.on('--pop', 'Revert back to the previous image') do
109
+ actions << ->() { images.pop || original_image }
120
110
  end
121
111
 
122
- opts.on("-f", "--format", "Print the image format") do
123
- actions << lambda {|img| puts img.format; img }
112
+ o.on('-f', '--format', 'Print the image format') do
113
+ actions << ->(img) { img.tap { img.format } }
124
114
  end
125
115
 
126
- opts.on_tail("-h", "--help", "Show this message") do
127
- puts opts
128
- exit 0
129
- end
116
+ o.on_tail('-h', '--help', 'Show this message') { o.usage }
130
117
 
131
- def opts.usage(msg)
132
- puts msg
118
+ def o.usage(msg=nil)
119
+ puts msg if msg
133
120
  puts self
134
121
  exit 1
135
122
  end
136
123
  end
137
124
  opts.parse!(ARGV)
138
- opts.usage("You need to supply a source image filename.") unless ARGV.first
139
- opts.usage("You need to supply one or more actions.") unless actions.size > 0
125
+ opts.usage('You need to supply a source image filename.') unless ARGV.first
126
+ opts.usage('You need to supply one or more actions.') if actions.empty?
140
127
 
141
128
  # For this binstub we only want to load non-headless if we are using
142
129
  # the preview feature. top of See lib/image_voodoo.rb for more info...
143
- class ImageVoodoo; NEEDS_HEAD = true; end unless headless
130
+ require 'image_voodoo/needs_head' unless headless
144
131
 
145
132
  require 'image_voodoo'
146
133
  file_name = ARGV.first
@@ -1,6 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "image_voodoo/version"
2
+
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
+ require 'image_voodoo/version'
4
5
 
5
6
  Gem::Specification.new do |s|
6
7
  s.name = 'image_voodoo'
@@ -12,11 +13,11 @@ Gem::Specification.new do |s|
12
13
  s.summary = 'Image manipulation in JRuby with ImageScience compatible API'
13
14
  s.description = 'Image manipulation in JRuby with ImageScience compatible API'
14
15
 
15
- s.rubyforge_project = "image_voodoo"
16
+ s.rubyforge_project = 'image_voodoo'
16
17
 
17
18
  s.files = `git ls-files`.split("\n")
18
19
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
- s.require_paths = ["lib", "vendor"]
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
21
+ s.require_paths = %w[lib vendor]
21
22
  s.has_rdoc = true
22
23
  end
@@ -1,3 +1,3 @@
1
1
  require 'image_voodoo'
2
2
  # HA HA...let the pin-pricking begin
3
- ImageScience = ImageVoodoo
3
+ ImageScience = ImageVoodoo
@@ -5,10 +5,7 @@
5
5
  unless defined? ImageVoodoo::NEEDS_HEAD
6
6
  java.lang.System.set_property 'java.awt.headless', 'true'
7
7
  end
8
-
9
8
 
10
- ##
11
- #
12
9
  # = ImageVoodoo
13
10
  # == Description
14
11
  #
@@ -33,7 +30,6 @@ end
33
30
  #
34
31
  # img = ImageVoodoo.with_image(ARGV[0])
35
32
  # negative_img = img.negative
36
- #
37
33
  class ImageVoodoo
38
34
  attr_accessor :quality
39
35
 
@@ -41,16 +37,15 @@ class ImageVoodoo
41
37
 
42
38
  JFile = java.io.File
43
39
 
44
- ##
45
40
  # FIXME: This has an issue when used in test/unit where the classcastexception
46
41
  # is throwing the stack trace to output. This does not happen when used
47
42
  # directly. Not sure....
48
43
  # gae and awt define the technology-specific methods and more importantly
49
44
  # all the *_impl methods which you will see referenced in this file.
50
45
  begin
51
- require 'image_voodoo/gae'
46
+ require 'image_voodoo/gae'
52
47
  rescue
53
- require 'image_voodoo/awt'
48
+ require 'image_voodoo/awt'
54
49
  end
55
50
 
56
51
  def initialize(io, src, format=nil)
@@ -58,127 +53,107 @@ class ImageVoodoo
58
53
  @quality = nil # nil means no specific quality ever specified
59
54
  end
60
55
 
61
- ##
62
- #
56
+ # Gets RGB value within the source image at [x, y]. If using AWT backend
57
+ # then consider using color_at as this is a Java signed int value of an
58
+ # unsigned value.
59
+ def pixel(x, y)
60
+ @src.getRGB(x, y)
61
+ end
62
+
63
63
  # Adjusts the brightness of each pixel in image by the following formula:
64
64
  # new_pixel = pixel * scale + offset
65
- #
66
65
  def adjust_brightness(scale, offset)
67
66
  image = guard { adjust_brightness_impl(scale, offset) }
68
67
  block_given? ? yield(image) : image
69
68
  end
70
69
 
71
- ##
72
- #
73
70
  # Converts rgb hex color value to an alpha value an yields/returns the new
74
71
  # image.
75
- #
76
72
  def alpha(rgb)
77
73
  target = guard { alpha_impl(rgb) }
78
74
  block_given? ? yield(target) : target
79
75
  end
80
76
 
81
- ##
82
- #
83
77
  # Get current image bytes as a String using provided format. Format parameter
84
78
  # is the informal name of an image type - for instance,
85
79
  # "bmp" or "jpg". If the backend is AWT the types available are listed in
86
80
  # javax.imageio.ImageIO.getWriterFormatNames()
87
- #
88
81
  def bytes(format)
89
82
  java_bytes = guard { bytes_impl(format) }
90
83
  String.from_java_bytes java_bytes
91
84
  end
92
85
 
93
- ##
94
86
  # If current image was taken by a phone it might save the orientation
95
87
  # in format it was physically taken and added IFD0 Orientation information
96
88
  # instead of rotating it. This method will perform that rotation based
97
89
  # on Orientation metadata.
98
- #
99
90
  def correct_orientation
100
91
  target = guard { correct_orientation_impl }
101
92
  block_given? ? yield(target) : target
102
93
  end
103
94
 
104
- ##
105
- #
106
95
  # Creates a square thumbnail of the image cropping the longest edge to
107
96
  # match the shortest edge, resizes to size, and yields/returns the new image.
108
- #
109
97
  def cropped_thumbnail(size)
110
- l, t, r, b, half = 0, 0, width, height, (width - height).abs / 2
111
- l, r = half, half + height if width > height
112
- t, b = half, half + width if height > width
113
-
98
+ l, t, r, b = calculate_thumbnail_dimentions
114
99
  target = with_crop(l, t, r, b).thumbnail(size)
115
100
  block_given? ? yield(target) : target
116
101
  end
117
102
 
118
- ##
119
- #
103
+ def calculate_thumbnail_dimensions
104
+ half = (width - height).abs / 2
105
+ if width > height
106
+ [half, 0, half + height, height]
107
+ else
108
+ [0, half, width, half + width]
109
+ end
110
+ end
111
+ private :calculate_thumbnail_dimensions
112
+
120
113
  # Flips the image horizontally and yields/returns the new image.
121
- #
122
114
  def flip_horizontally
123
115
  target = guard { flip_horizontally_impl }
124
116
  block_given? ? yield(target) : target
125
117
  end
126
118
 
127
- ##
128
- #
129
119
  # Flips the image vertically and yields/returns the new image.
130
- #
131
120
  def flip_vertically
132
121
  target = guard { flip_vertically_impl }
133
122
  block_given? ? yield(target) : target
134
123
  end
135
124
 
136
- ##
137
- #
138
125
  # Creates a grayscale version of image and yields/returns the new image.
139
- #
140
126
  def greyscale
141
127
  target = guard { greyscale_impl }
142
128
  block_given? ? yield(target) : target
143
129
  end
144
- alias_method :grayscale, :greyscale
130
+ alias grayscale greyscale
145
131
 
146
- ##
147
- #
148
132
  # Extracts metadata from an image.
149
- #
150
133
  def metadata
151
134
  guard { metadata_impl }
152
135
  end
153
136
 
154
- ##
155
- #
156
137
  # Creates a negative and yields/returns the new image.
157
- #
158
138
  def negative
159
139
  target = guard { negative_impl }
160
140
  block_given? ? yield(target) : target
161
141
  end
162
142
 
163
- ##
164
- #
165
143
  # Set quality you want resulting image to be once you save or extract
166
144
  # bytes for the image. Note: This will only work for lossy image
167
145
  # formats like PNG of JPEG. For others it will be ignored.
168
146
  def quality(amount)
169
147
  if amount < 0.0 || amount > 1.0
170
- raise ArgumentError.new "Quality must be between 0.0 and 1.0"
148
+ raise ArgumentError, 'Quality must be between 0.0 and 1.0'
171
149
  end
172
150
 
173
- target = self.dup
151
+ target = dup
174
152
  target.quality = amount
175
153
  block_given? ? yield(target) : target
176
154
  end
177
155
 
178
- ##
179
- #
180
156
  # Resizes the image to width and height and yields/returns the new image.
181
- #
182
157
  def resize(width, height)
183
158
  target = guard { resize_impl(width, height) }
184
159
  block_given? ? yield(target) : target
@@ -186,135 +161,108 @@ class ImageVoodoo
186
161
  raise ArgumentError, ne.message
187
162
  end
188
163
 
189
- ##
190
- #
191
164
  # Rotates the image by angle (specified in degrees).
192
- #
193
165
  def rotate(angle)
194
- target = guard { rotate_impl(angle) }
166
+ target = guard { rotate_impl(to_radians(angle)) }
195
167
  block_given? ? yield(target) : target
196
168
  end
197
169
 
198
- ##
199
- #
200
170
  # Saves the image out to path. Changing the file extension will convert
201
171
  # the file type to the appropriate format.
202
- #
203
172
  def save(file)
204
173
  format = File.extname(file)
205
- return false if format == ""
174
+ return false if format == ''
206
175
  format = format[1..-1].downcase
207
176
  guard { save_impl(format, JFile.new(file)) }
208
177
  true
209
178
  end
210
179
 
211
- ##
212
- #
213
180
  # Resize (scale) the current image by the provided ratio and yield/return
214
181
  # the new image.
215
- #
216
182
  def scale(ratio)
217
183
  new_width, new_height = (width * ratio).to_i, (height * ratio).to_i
218
184
  target = resize(new_width, new_height)
219
185
  block_given? ? yield(target) : target
220
186
  end
221
187
 
222
- ##
223
- #
224
188
  # Creates a proportional thumbnail of the image scaled so its longest
225
189
  # edge is resized to size and yields/returns the new image.
226
- #
227
190
  def thumbnail(size)
228
191
  target = scale(size.to_f / (width > height ? width : height))
229
192
  block_given? ? yield(target) : target
230
193
  end
231
194
 
232
- ##
233
- #
234
195
  # Crops an image to left, top, right, and bottom and then yields/returns the
235
196
  # new image.
236
- #
237
197
  def with_crop(left, top, right, bottom)
238
198
  image = guard { with_crop_impl(left, top, right, bottom) }
239
199
  block_given? ? yield(image) : image
240
200
  end
241
201
 
242
- ##
243
- #
202
+ # Creates a new (empty) image with a file name specified.
203
+ def self.new_image(width, height, file_name)
204
+ image = guard { new_image_impl(width, height, file_name) }
205
+ block_given? ? yield(image) : image
206
+ end
207
+
244
208
  # A top-level image loader opens path and then yields/returns the image.
245
- #
246
209
  def self.with_image(path)
247
210
  raise ArgumentError, "file does not exist: #{path}" unless File.file?(path)
248
211
  image = guard { with_image_impl(JFile.new(path)) }
249
212
  image && block_given? ? yield(image) : image
250
213
  end
251
214
 
252
- ##
253
- #
254
215
  # A top-level image loader reads bytes and then yields/returns the image.
255
- #
256
216
  def self.with_bytes(bytes)
257
- bytes = bytes.to_java_bytes if String === bytes
217
+ bytes = bytes.to_java_bytes if bytes.is_a? String
258
218
  image = guard { with_bytes_impl(bytes) }
259
219
  block_given? ? yield(image) : image
260
220
  end
261
221
 
262
222
  class << self
263
- alias_method :with_image_from_memory, :with_bytes
223
+ alias with_image_from_memory with_bytes
264
224
  end
265
225
 
266
- ##
267
- #
268
226
  # *_impl providers only need provide the implementation if it can
269
227
  # support it. Otherwise, this method will detect that the method is
270
228
  # missing.
271
- #
272
229
  def self.guard(&block)
273
- begin
274
- return block.call
275
- rescue NoMethodError => e
276
- "Unimplemented Feature: #{e}"
277
- end
230
+ return block.call
231
+ rescue NoMethodError => e
232
+ "Unimplemented Feature: #{e}"
278
233
  end
234
+
279
235
  def guard(&block)
280
236
  ImageVoodoo.guard(&block)
281
237
  end
282
238
 
283
- ##
284
- #
285
239
  # Returns the height of the image, in pixels.
286
- #
287
240
  def height
288
241
  @src.height
289
242
  end
290
243
 
291
- ##
292
- #
293
244
  # Returns the width of the image, in pixels.
294
- #
295
245
  def width
296
246
  @src.width
297
247
  end
298
248
 
299
- ##
300
- #
301
249
  # Returns the underlying Java class associated with this object. Note:
302
250
  # Depending on whether you are using AWT or GAE/J you will get a totally
303
251
  # different Java class. So caveat emptor!
304
- #
305
252
  def to_java
306
253
  @src
307
254
  end
308
255
 
309
- ##
310
- #
311
256
  # Returns detected image format from binary representation of input data
312
257
  # as upper case string. Eg. JPEG, BMP, PNG. For GWT image representation
313
258
  # compatibility method name is :format. It also accepts block and returns
314
259
  # format as first block argument. When format not detected or not set it
315
260
  # returns nil
316
- #
317
261
  def format
318
262
  @format && block_given? ? yield(@format) : @format
319
263
  end
264
+
265
+ def to_radians(degrees)
266
+ degrees * Math::PI / 180
267
+ end
320
268
  end