image_voodoo 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/image_voodoo CHANGED
@@ -27,16 +27,30 @@ opts = OptionParser.new do |opts|
27
27
  opts.separator ""
28
28
  opts.separator "Actions:"
29
29
 
30
+ opts.on("-b", "--brightness SCALE,OFFSET", "Adjust brightness") do |args|
31
+ scale, offset = args.split(/\,/i).map {|v| v.to_f}
32
+ opts.usage "You need to specify proper scale and offset" unless scale && offset
33
+ actions << lambda {|img| img.adjust_brightness(scale, offset) }
34
+ end
35
+
30
36
  opts.on("-d", "--dimensions", "Print the image dimensions") do
31
37
  actions << lambda {|img| puts "#{img.width}x#{img.height}"; img }
32
38
  end
33
39
 
40
+ opts.on("-g", "--greyscale", "Convert image to greyscale") do
41
+ actions << lambda {|img| img.greyscale }
42
+ end
43
+
44
+ opts.on("-n", "--negative", "Make a negative out of the image") do
45
+ actions << lambda {|img| img.negative }
46
+ end
47
+
34
48
  opts.on("-s", "--save FILENAME", "Save the results to a new file") do |f|
35
49
  actions << lambda {|img| img.save(f); img }
36
50
  end
37
51
 
38
52
  opts.on("-t", "--thumbnail SIZE", Integer, "Create a thumbnail of the given size") do |size|
39
- actions << lambda {|img| result = nil; img.thumbnail(size) {|img2| result = img2 }; result }
53
+ actions << lambda {|img| img.thumbnail(size) }
40
54
  end
41
55
 
42
56
  opts.on("-p", "--preview", "Preview the image. Close the frame window",
@@ -60,7 +74,7 @@ opts = OptionParser.new do |opts|
60
74
  opts.on("-r", "--resize WIDTHxHEIGHT", "Create a new image with the specified", "dimensions") do |dim|
61
75
  width, height = dim.split(/x/i).map {|v| v.to_i}
62
76
  opts.usage "You need to specify proper dimensions" unless width && width > 0 && height && height > 0
63
- actions << lambda {|img| result = nil; img.resize(width,height) {|img2| result = img2}; result }
77
+ actions << lambda {|img| img.resize(width,height) }
64
78
  end
65
79
 
66
80
  opts.on_tail("-h", "--help", "Show this message") do
@@ -79,11 +93,11 @@ opts.usage("You need to supply a source image filename.") unless ARGV.first
79
93
  opts.usage("You need to supply one or more actions.") unless actions.size > 0
80
94
 
81
95
  require 'image_voodoo'
82
- ImageVoodoo.with_image(ARGV.first) do |img|
96
+ file_name = ARGV.first
97
+ method = file_name =~ /^http:/ ? :from_url : :with_image
98
+ ImageVoodoo.send(method, file_name) do |img|
83
99
  original_image = img
84
- actions.each do |act|
85
- img = act.call(img)
86
- end
100
+ actions.each { |act| img = act.call(img) }
87
101
  end
88
102
  # Be sure we exit out of swing
89
103
  java.lang.System.exit(0)
@@ -1,3 +1,3 @@
1
1
  class ImageVoodoo
2
- VERSION = "0.1"
3
- end
2
+ VERSION = "0.2"
3
+ end
data/lib/image_voodoo.rb CHANGED
@@ -12,30 +12,39 @@
12
12
  # end
13
13
  # end
14
14
  class ImageVoodoo
15
- VERSION = "0.1"
16
-
17
15
  include Java
18
16
 
19
17
  import java.awt.RenderingHints
18
+ import java.awt.color.ColorSpace
20
19
  import java.awt.geom.AffineTransform
20
+ import java.awt.image.ByteLookupTable
21
+ import java.awt.image.ColorConvertOp
22
+ import java.awt.image.LookupOp
23
+ import java.awt.image.RescaleOp
21
24
  import java.awt.image.BufferedImage
22
- import javax.imageio.ImageIO
23
- import javax.swing.JFrame
24
-
25
25
  JFile = java.io.File
26
26
  BAIS = java.io.ByteArrayInputStream
27
27
  BAOS = java.io.ByteArrayOutputStream
28
+ import javax.imageio.ImageIO
29
+ import javax.swing.JFrame
30
+
31
+ NEGATIVE_OP = LookupOp.new(ByteLookupTable.new(0, (0...254).to_a.reverse.to_java(:byte)), nil)
32
+ GREY_OP = ColorConvertOp.new(ColorSpace.getInstance(ColorSpace::CS_GRAY), nil)
28
33
 
29
34
  class JImagePanel < javax.swing.JPanel
30
- def initialize(image, x, y)
35
+ def initialize(image, x=0, y=0)
31
36
  super()
32
37
  @image, @x, @y = image, x, y
33
38
  end
39
+ def image=(image)
40
+ @image = image
41
+ invalidate
42
+ end
34
43
  def getPreferredSize
35
44
  java.awt.Dimension.new(@image.width, @image.height)
36
45
  end
37
46
  def paintComponent(graphics)
38
- graphics.drawImage(@image, @x, @y, nil)
47
+ graphics.drawImage(@image.to_java, @x, @y, nil)
39
48
  end
40
49
  end
41
50
 
@@ -43,13 +52,22 @@ class ImageVoodoo
43
52
  @src = src
44
53
  end
45
54
 
55
+ # Foreach pixel new_pixel = pixel * scale + offset
56
+ def adjust_brightness(scale, offset)
57
+ image = ImageVoodoo.new internal_transform(RescaleOp.new(scale, offset, nil))
58
+ block_given? ? yield(image) : image
59
+ end
60
+
46
61
  def cropped_thumbnail(size)
47
62
  l, t, r, b, half = 0, 0, width, height, (width - height).abs / 2
48
63
  l, r = half, half + height if width > height
49
64
  t, b = half, half + width if height > width
50
65
 
51
- with_crop(l, t, r, b) do |img|
52
- img.thumbnail(size) { |thumb| yield thumb }
66
+ with_crop(l, t, r, b) do |image|
67
+ image.thumbnail(size) do |thumb|
68
+ target = ImageVoodoo.new target
69
+ block_given? ? yield(target) : target
70
+ end
53
71
  end
54
72
  end
55
73
 
@@ -61,35 +79,35 @@ class ImageVoodoo
61
79
  @src.width
62
80
  end
63
81
 
82
+ def to_java
83
+ @src
84
+ end
85
+
86
+ def negative
87
+ image = ImageVoodoo.new internal_transform(NEGATIVE_OP)
88
+ block_given? ? yield(image) : image
89
+ end
90
+
64
91
  def resize(width, height)
65
- target = BufferedImage.new(width, height, BufferedImage::TYPE_INT_RGB)
92
+ target = BufferedImage.new(width, height, color_type)
66
93
  graphics = target.graphics
67
94
  graphics.set_rendering_hint(RenderingHints::KEY_INTERPOLATION,
68
95
  RenderingHints::VALUE_INTERPOLATION_BICUBIC)
69
-
70
96
  w_scale = width.to_f / @src.width
71
97
  h_scale = height.to_f / @src.height
72
-
73
98
  transform = AffineTransform.get_scale_instance w_scale, h_scale
74
-
75
99
  graphics.draw_rendered_image @src, transform
76
100
  graphics.dispose
77
101
 
78
- yield ImageVoodoo.new(target)
102
+ target = ImageVoodoo.new target
103
+ block_given? ? yield(target) : target
79
104
  rescue NativeException => ne
80
105
  raise ArgumentError, ne.message
81
106
  end
82
107
 
83
108
  def greyscale
84
- target = BufferedImage.new(width, height, BufferedImage::TYPE_USHORT_GRAY)
85
- graphics = target.graphics
86
- graphics.set_rendering_hint(RenderingHints::KEY_INTERPOLATION,
87
- RenderingHints::VALUE_INTERPOLATION_BICUBIC)
88
-
89
- graphics.draw_rendered_image @src, nil
90
- graphics.dispose
91
-
92
- yield ImageVoodoo.new(target)
109
+ image = ImageVoodoo.new internal_transform(GREY_OP)
110
+ block_given? ? yield(image) : image
93
111
  end
94
112
 
95
113
  def save(file)
@@ -112,7 +130,7 @@ class ImageVoodoo
112
130
  frame = JFrame.new("Preview")
113
131
  frame.add_window_listener WindowClosed.new(block)
114
132
  frame.set_bounds 0, 0, width + 20, height + 40
115
- frame.add JImagePanel.new(@src, 10, 10)
133
+ frame.add JImagePanel.new(self, 10, 10)
116
134
  frame.visible = true
117
135
  end
118
136
 
@@ -122,31 +140,67 @@ class ImageVoodoo
122
140
  String.from_java_bytes(out.to_byte_array)
123
141
  end
124
142
 
143
+ def scale(ratio)
144
+ new_width = (width * ratio).to_i
145
+ new_height = (height * ratio).to_i
146
+ resize(new_width, new_height) do |image|
147
+ target = ImageVoodoo.new image
148
+ block_given? ? yield(target) : target
149
+ end
150
+ end
151
+
125
152
  def thumbnail(size)
126
- scale = size.to_f / (width > height ? width : height)
127
- new_width = (width * scale).to_i
128
- new_height = (height * scale).to_i
129
- resize(new_width, new_height) {|image| yield image }
153
+ scale(size.to_f / (width > height ? width : height))
130
154
  end
131
155
 
132
156
  def with_crop(left, top, right, bottom)
133
- subimage = @src.get_subimage(left, top, right - left, bottom - top)
134
- yield ImageVoodoo.new(subimage)
157
+ image = ImageVoodoo.new(@src.get_subimage(left, top, right-left, bottom-top))
158
+ block_given? ? yield(image) : image
159
+ end
160
+
161
+ # TODO: Figure out how to determine whether source has alpha or not
162
+ def self.from_url(source)
163
+ url = java.net.URL.new(source)
164
+ image = java.awt.Toolkit.default_toolkit.create_image(url)
165
+ tracker = java.awt.MediaTracker.new(java.awt.Label.new(""))
166
+ tracker.addImage(image, 0);
167
+ tracker.waitForID(0)
168
+ target = BufferedImage.new(image.getWidth, image.getHeight, BufferedImage::TYPE_INT_RGB)
169
+ graphics = target.graphics
170
+ graphics.drawImage(image, 0, 0, nil)
171
+ graphics.dispose
172
+ target = ImageVoodoo.new target
173
+ block_given? ? yield(target) : target
174
+ rescue java.io.IOException, java.net.MalformedURLException
175
+ raise ArgumentError.new "Trouble retrieving image: #{$!.message}"
135
176
  end
136
177
 
137
178
  def self.with_image(file)
138
179
  readers = ImageIO.getImageReadersBySuffix(File.extname(file)[1..-1])
139
180
  raise TypeError, "unrecognized format for #{file}" unless readers.hasNext
140
- image = ImageIO.read(JFile.new(file))
141
- yield ImageVoodoo.new(image)
181
+ image = ImageVoodoo.new ImageIO.read(JFile.new(file))
182
+ block_given? ? yield(image) : image
142
183
  rescue NativeException => ne
143
184
  nil
144
185
  end
145
186
 
146
187
  def self.with_bytes(bytes)
147
188
  bytes = bytes.to_java_bytes if String === bytes
189
+ image = ImageVoodoo.new ImageIO.read(BAIS.new(bytes))
190
+ block_given? ? yield(image) : image
191
+ end
148
192
 
149
- image = ImageIO.read(BAIS.new(bytes))
150
- yield ImageVoodoo.new(image)
193
+ private
194
+ def color_type
195
+ return BufferedImage::TYPE_INT_ARGB if @src.color_model.has_alpha
196
+ BufferedImage::TYPE_INT_RGB
197
+ end
198
+
199
+ def internal_transform(operation, target=BufferedImage.new(width, height, color_type))
200
+ graphics = target.graphics
201
+ graphics.drawImage(@src, 0, 0, nil)
202
+ graphics.drawImage(operation.filter(target, nil), 0, 0, nil)
203
+ graphics.dispose
204
+ target
151
205
  end
152
206
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_voodoo
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ version: "0.2"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Enebo, Charles Nutter and JRuby contributors
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-03-27 00:00:00 -05:00
12
+ date: 2008-05-19 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15