image_voodoo 0.1 → 0.2

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