image_voodoo 0.5 → 0.6
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/Manifest.txt +2 -0
- data/lib/image_voodoo.rb +43 -185
- data/lib/image_voodoo/awt.rb +223 -0
- data/lib/image_voodoo/gae.rb +53 -0
- data/lib/image_voodoo/version.rb +1 -1
- metadata +4 -2
data/Manifest.txt
CHANGED
data/lib/image_voodoo.rb
CHANGED
@@ -27,62 +27,29 @@
|
|
27
27
|
class ImageVoodoo
|
28
28
|
include Java
|
29
29
|
|
30
|
-
import java.awt.RenderingHints
|
31
|
-
import java.awt.color.ColorSpace
|
32
|
-
import java.awt.geom.AffineTransform
|
33
|
-
import java.awt.image.BufferedImage
|
34
|
-
import java.awt.image.ByteLookupTable
|
35
|
-
import java.awt.image.ColorConvertOp
|
36
|
-
import java.awt.image.LookupOp
|
37
|
-
import java.awt.image.RescaleOp
|
38
30
|
JFile = java.io.File
|
39
|
-
import java.io.ByteArrayInputStream
|
40
|
-
import java.io.ByteArrayOutputStream
|
41
|
-
import javax.imageio.ImageIO
|
42
|
-
import javax.swing.JFrame
|
43
31
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
32
|
+
# FIXME: This has an issue when used in test/unit where the classcastexception
|
33
|
+
# is throwing the stack trace to output. This does not happen when used
|
34
|
+
# directly. Not sure....
|
35
|
+
# gae and awt define the technology-specific methods and more importantly
|
36
|
+
# all the *_impl methods which you will see referenced in this file.
|
37
|
+
begin
|
38
|
+
require 'image_voodoo/gae'
|
39
|
+
rescue
|
40
|
+
require 'image_voodoo/awt'
|
41
|
+
end
|
49
42
|
|
50
43
|
def initialize(src)
|
51
44
|
@src = src
|
52
45
|
end
|
53
46
|
|
54
|
-
#
|
55
|
-
# Add a border to the image and yield/return a new image. The following
|
56
|
-
# options are supported:
|
57
|
-
# - width: How thick is the border (default: 3)
|
58
|
-
# - color: Which color is the border (in rrggbb hex value)
|
59
|
-
# - style: etched, raised, plain (default: plain)
|
60
|
-
#
|
61
|
-
def add_border(options = {})
|
62
|
-
border_width = options[:width].to_i || 2
|
63
|
-
color = hex_to_color(options[:color]) || hex_to_color("000000")
|
64
|
-
style = options[:style]
|
65
|
-
style = nil if style.to_sym == :plain
|
66
|
-
new_width, new_height = width + 2*border_width, height + 2*border_width
|
67
|
-
target = paint(BufferedImage.new(new_width, new_height, color_type)) do |g|
|
68
|
-
g.color = color
|
69
|
-
if style
|
70
|
-
raised = style.to_sym == :raised ? true : false
|
71
|
-
g.fill3DRect(0, 0, new_width, new_height, raised)
|
72
|
-
else
|
73
|
-
g.fill_rect(0, 0, new_width, new_height)
|
74
|
-
end
|
75
|
-
g.draw_image(@src, nil, border_width, border_width)
|
76
|
-
end
|
77
|
-
block_given? ? yield(target) : target
|
78
|
-
end
|
79
|
-
|
80
47
|
#
|
81
48
|
# Adjusts the brightness of each pixel in image by the following formula:
|
82
49
|
# new_pixel = pixel * scale + offset
|
83
50
|
#
|
84
51
|
def adjust_brightness(scale, offset)
|
85
|
-
image =
|
52
|
+
image = guard { adjust_brightness_impl(scale, offset) }
|
86
53
|
block_given? ? yield(image) : image
|
87
54
|
end
|
88
55
|
|
@@ -91,16 +58,7 @@ class ImageVoodoo
|
|
91
58
|
# image.
|
92
59
|
#
|
93
60
|
def alpha(rgb)
|
94
|
-
|
95
|
-
target = paint(BufferedImage.new(width, height, ARGB)) do |g|
|
96
|
-
g.set_composite(java.awt.AlphaComposite::Src)
|
97
|
-
g.draw_image(@src, nil, 0, 0)
|
98
|
-
0.upto(height-1) do |i|
|
99
|
-
0.upto(width-1) do |j|
|
100
|
-
target.setRGB(j, i, 0x8F1C1C) if target.getRGB(j, i) == color.getRGB
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
61
|
+
target = guard { alpha_impl(rgb) }
|
104
62
|
block_given? ? yield(target) : target
|
105
63
|
end
|
106
64
|
|
@@ -108,9 +66,8 @@ class ImageVoodoo
|
|
108
66
|
# Write current image out as a stream of bytes using provided format.
|
109
67
|
#
|
110
68
|
def bytes(format)
|
111
|
-
|
112
|
-
|
113
|
-
String.from_java_bytes(out.to_byte_array)
|
69
|
+
java_bytes = guard { bytes_impl(format) }
|
70
|
+
String.from_java_bytes java_bytes
|
114
71
|
end
|
115
72
|
|
116
73
|
#
|
@@ -130,9 +87,7 @@ class ImageVoodoo
|
|
130
87
|
# Flips the image horizontally and yields/returns the new image.
|
131
88
|
#
|
132
89
|
def flip_horizontally
|
133
|
-
target =
|
134
|
-
g.draw_image @src, 0, 0, width, height, width, 0, 0, height, nil
|
135
|
-
end
|
90
|
+
target = guard { flip_horizontally_impl }
|
136
91
|
block_given? ? yield(target) : target
|
137
92
|
end
|
138
93
|
|
@@ -140,9 +95,7 @@ class ImageVoodoo
|
|
140
95
|
# Flips the image vertically and yields/returns the new image.
|
141
96
|
#
|
142
97
|
def flip_vertically
|
143
|
-
target =
|
144
|
-
g.draw_image @src, 0, 0, width, height, 0, height, width, 0, nil
|
145
|
-
end
|
98
|
+
target = guard { flip_vertically_impl }
|
146
99
|
block_given? ? yield(target) : target
|
147
100
|
end
|
148
101
|
|
@@ -150,7 +103,7 @@ class ImageVoodoo
|
|
150
103
|
# Creates a grayscale version of image and yields/returns the new image.
|
151
104
|
#
|
152
105
|
def greyscale
|
153
|
-
target =
|
106
|
+
target = guard { greyscale_impl }
|
154
107
|
block_given? ? yield(target) : target
|
155
108
|
end
|
156
109
|
alias_method :grayscale, :greyscale
|
@@ -159,19 +112,15 @@ class ImageVoodoo
|
|
159
112
|
# Creates a negative and yields/returns the new image.
|
160
113
|
#
|
161
114
|
def negative
|
162
|
-
target =
|
115
|
+
target = guard { negative_impl }
|
163
116
|
block_given? ? yield(target) : target
|
164
117
|
end
|
165
118
|
|
166
119
|
#
|
167
|
-
# Resizes the image to width and height
|
168
|
-
# yields/returns the new image.
|
120
|
+
# Resizes the image to width and height and yields/returns the new image.
|
169
121
|
#
|
170
122
|
def resize(width, height)
|
171
|
-
target =
|
172
|
-
scaled_image = @src.get_scaled_instance width, height, SCALE_SMOOTH
|
173
|
-
g.draw_image scaled_image, 0, 0, nil
|
174
|
-
end
|
123
|
+
target = guard { resize_impl(width, height) }
|
175
124
|
block_given? ? yield(target) : target
|
176
125
|
rescue NativeException => ne
|
177
126
|
raise ArgumentError, ne.message
|
@@ -185,7 +134,7 @@ class ImageVoodoo
|
|
185
134
|
format = File.extname(file)
|
186
135
|
return false if format == ""
|
187
136
|
format = format[1..-1].downcase
|
188
|
-
|
137
|
+
guard { save_impl(format, JFile.new(file)) }
|
189
138
|
true
|
190
139
|
end
|
191
140
|
|
@@ -213,79 +162,16 @@ class ImageVoodoo
|
|
213
162
|
# new image.
|
214
163
|
#
|
215
164
|
def with_crop(left, top, right, bottom)
|
216
|
-
image =
|
165
|
+
image = guard { with_crop_impl(left, top, right, bottom) }
|
217
166
|
block_given? ? yield(image) : image
|
218
167
|
end
|
219
168
|
|
220
|
-
#
|
221
|
-
# A simple swing wrapper around an image voodoo object.
|
222
|
-
#
|
223
|
-
class JImagePanel < javax.swing.JPanel
|
224
|
-
def initialize(image, x=0, y=0)
|
225
|
-
super()
|
226
|
-
@image, @x, @y = image, x, y
|
227
|
-
end
|
228
|
-
|
229
|
-
def image=(image)
|
230
|
-
@image = image
|
231
|
-
invalidate
|
232
|
-
end
|
233
|
-
|
234
|
-
def getPreferredSize
|
235
|
-
java.awt.Dimension.new(@image.width, @image.height)
|
236
|
-
end
|
237
|
-
|
238
|
-
def paintComponent(graphics)
|
239
|
-
graphics.draw_image(@image.to_java, @x, @y, nil)
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# Internal class for closing preview window
|
244
|
-
class WindowClosed
|
245
|
-
def initialize(block = nil)
|
246
|
-
@block = block || proc { java.lang.System.exit(0) }
|
247
|
-
end
|
248
|
-
def method_missing(meth,*args); end
|
249
|
-
def windowClosing(event); @block.call; end
|
250
|
-
end
|
251
|
-
|
252
|
-
#
|
253
|
-
# Creates a viewable frame displaying current image within it.
|
254
|
-
#
|
255
|
-
def preview(&block)
|
256
|
-
frame = JFrame.new("Preview")
|
257
|
-
frame.add_window_listener WindowClosed.new(block)
|
258
|
-
frame.set_bounds 0, 0, width + 20, height + 40
|
259
|
-
frame.add JImagePanel.new(self, 10, 10)
|
260
|
-
frame.visible = true
|
261
|
-
end
|
262
|
-
|
263
|
-
#
|
264
|
-
# TODO: Figure out how to determine whether source has alpha or not
|
265
|
-
# Experimental: Read an image from the url source and yield/return that
|
266
|
-
# image.
|
267
|
-
#
|
268
|
-
def self.from_url(source)
|
269
|
-
url = java.net.URL.new(source)
|
270
|
-
image = java.awt.Toolkit.default_toolkit.create_image(url)
|
271
|
-
tracker = java.awt.MediaTracker.new(java.awt.Label.new(""))
|
272
|
-
tracker.addImage(image, 0);
|
273
|
-
tracker.waitForID(0)
|
274
|
-
target = paint(BufferedImage.new(image.width, image.height, RGB)) do |g|
|
275
|
-
g.draw_image image, 0, 0, nil
|
276
|
-
end
|
277
|
-
block_given? ? yield(target) : target
|
278
|
-
rescue java.io.IOException, java.net.MalformedURLException
|
279
|
-
raise ArgumentError.new "Trouble retrieving image: #{$!.message}"
|
280
|
-
end
|
281
|
-
|
282
169
|
#
|
283
170
|
# A top-level image loader opens path and then yields/returns the image.
|
284
171
|
#
|
285
172
|
def self.with_image(file)
|
286
173
|
raise ArgumentError, "file does not exist" unless File.file?(file)
|
287
|
-
|
288
|
-
image = ImageVoodoo.new(buffered_image) if buffered_image
|
174
|
+
image = guard { with_image_impl(JFile.new(file)) }
|
289
175
|
image && block_given? ? yield(image) : image
|
290
176
|
end
|
291
177
|
|
@@ -294,10 +180,26 @@ class ImageVoodoo
|
|
294
180
|
#
|
295
181
|
def self.with_bytes(bytes)
|
296
182
|
bytes = bytes.to_java_bytes if String === bytes
|
297
|
-
image =
|
183
|
+
image = guard { with_bytes_impl(bytes) }
|
298
184
|
block_given? ? yield(image) : image
|
299
185
|
end
|
300
186
|
|
187
|
+
#
|
188
|
+
# *_impl providers only need provide the implementation if it can
|
189
|
+
# support it. Otherwise, this method will detect that the method is
|
190
|
+
# missing.
|
191
|
+
#
|
192
|
+
def self.guard(&block)
|
193
|
+
begin
|
194
|
+
return block.call
|
195
|
+
rescue NoMethodError => e
|
196
|
+
"Unimplemented Feature: #{e}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
def guard(&block)
|
200
|
+
ImageVoodoo.guard(&block)
|
201
|
+
end
|
202
|
+
|
301
203
|
#
|
302
204
|
# Returns the height of the image, in pixels.
|
303
205
|
#
|
@@ -313,55 +215,11 @@ class ImageVoodoo
|
|
313
215
|
end
|
314
216
|
|
315
217
|
#
|
316
|
-
# Returns the underlying Java
|
218
|
+
# Returns the underlying Java class associated with this object. Note:
|
219
|
+
# Depending on whether you are using AWT or GAE/J you will get a totally
|
220
|
+
# different Java class. So caveat emptor!
|
317
221
|
#
|
318
222
|
def to_java
|
319
223
|
@src
|
320
224
|
end
|
321
|
-
|
322
|
-
private
|
323
|
-
|
324
|
-
#
|
325
|
-
# Converts a RGB hex value into a java.awt.Color object or dies trying
|
326
|
-
# with an ArgumentError.
|
327
|
-
#
|
328
|
-
def hex_to_color(rgb)
|
329
|
-
raise ArgumentError.new "hex rrggbb needed" if rgb !~ /[[:xdigit:]]{6,6}/
|
330
|
-
|
331
|
-
java.awt.Color.new(rgb[0,2].to_i(16), rgb[2,2].to_i(16), rgb[4,2].to_i(16))
|
332
|
-
end
|
333
|
-
|
334
|
-
#
|
335
|
-
# Determines the best colorspace for a new image based on whether the
|
336
|
-
# existing image contains an alpha channel or not.
|
337
|
-
#
|
338
|
-
def color_type
|
339
|
-
@src.color_model.has_alpha ? ARGB : RGB
|
340
|
-
end
|
341
|
-
|
342
|
-
#
|
343
|
-
# DRY up drawing setup+teardown
|
344
|
-
#
|
345
|
-
def paint(src=dup_src)
|
346
|
-
yield src.graphics
|
347
|
-
src.graphics.dispose
|
348
|
-
ImageVoodoo.new src
|
349
|
-
end
|
350
|
-
|
351
|
-
#
|
352
|
-
# Make a duplicate of the underlying Java src image
|
353
|
-
#
|
354
|
-
def dup_src
|
355
|
-
BufferedImage.new width, height, color_type
|
356
|
-
end
|
357
|
-
|
358
|
-
#
|
359
|
-
# Do simple AWT operation transformation to target.
|
360
|
-
#
|
361
|
-
def internal_transform(operation, target=dup_src)
|
362
|
-
paint(target) do |g|
|
363
|
-
g.draw_image(@src, 0, 0, nil)
|
364
|
-
g.draw_image(operation.filter(target, nil), 0, 0, nil)
|
365
|
-
end
|
366
|
-
end
|
367
225
|
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
class ImageVoodoo
|
2
|
+
java_import java.awt.RenderingHints
|
3
|
+
java_import java.awt.color.ColorSpace
|
4
|
+
java_import java.awt.geom.AffineTransform
|
5
|
+
java_import java.awt.image.BufferedImage
|
6
|
+
java_import java.awt.image.ByteLookupTable
|
7
|
+
java_import java.awt.image.ColorConvertOp
|
8
|
+
java_import java.awt.image.LookupOp
|
9
|
+
java_import java.awt.image.RescaleOp
|
10
|
+
java_import java.io.ByteArrayInputStream
|
11
|
+
java_import java.io.ByteArrayOutputStream
|
12
|
+
java_import javax.imageio.ImageIO
|
13
|
+
java_import javax.swing.JFrame
|
14
|
+
|
15
|
+
NEGATIVE_OP = LookupOp.new(ByteLookupTable.new(0, (0...254).to_a.reverse.to_java(:byte)), nil)
|
16
|
+
GREY_OP = ColorConvertOp.new(ColorSpace.getInstance(ColorSpace::CS_GRAY), nil)
|
17
|
+
ARGB = BufferedImage::TYPE_INT_ARGB
|
18
|
+
RGB = BufferedImage::TYPE_INT_RGB
|
19
|
+
SCALE_SMOOTH = java.awt.Image::SCALE_SMOOTH
|
20
|
+
|
21
|
+
#
|
22
|
+
# AWT-only (experimental)
|
23
|
+
# Add a border to the image and yield/return a new image. The following
|
24
|
+
# options are supported:
|
25
|
+
# - width: How thick is the border (default: 3)
|
26
|
+
# - color: Which color is the border (in rrggbb hex value)
|
27
|
+
# - style: etched, raised, plain (default: plain)
|
28
|
+
#
|
29
|
+
def add_border(options = {})
|
30
|
+
border_width = options[:width].to_i || 2
|
31
|
+
color = hex_to_color(options[:color]) || hex_to_color("000000")
|
32
|
+
style = options[:style]
|
33
|
+
style = nil if style.to_sym == :plain
|
34
|
+
new_width, new_height = width + 2*border_width, height + 2*border_width
|
35
|
+
target = paint(BufferedImage.new(new_width, new_height, color_type)) do |g|
|
36
|
+
g.color = color
|
37
|
+
if style
|
38
|
+
raised = style.to_sym == :raised ? true : false
|
39
|
+
g.fill3DRect(0, 0, new_width, new_height, raised)
|
40
|
+
else
|
41
|
+
g.fill_rect(0, 0, new_width, new_height)
|
42
|
+
end
|
43
|
+
g.draw_image(@src, nil, border_width, border_width)
|
44
|
+
end
|
45
|
+
block_given? ? yield(target) : target
|
46
|
+
end
|
47
|
+
|
48
|
+
def adjust_brightness_impl(scale, offset)
|
49
|
+
transform(RescaleOp.new(scale, offset, nil))
|
50
|
+
end
|
51
|
+
|
52
|
+
# AWT-only
|
53
|
+
def alpha_impl(rgb)
|
54
|
+
color = hex_to_color(rgb)
|
55
|
+
target = paint(BufferedImage.new(width, height, ARGB)) do |g|
|
56
|
+
g.set_composite(java.awt.AlphaComposite::Src)
|
57
|
+
g.draw_image(@src, nil, 0, 0)
|
58
|
+
0.upto(height-1) do |i|
|
59
|
+
0.upto(width-1) do |j|
|
60
|
+
target.setRGB(j, i, 0x8F1C1C) if target.getRGB(j, i) == color.getRGB
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def bytes_impl(format)
|
67
|
+
out = ByteArrayOutputStream.new
|
68
|
+
ImageIO.write(@src, format, out)
|
69
|
+
out.to_byte_array
|
70
|
+
end
|
71
|
+
|
72
|
+
def flip_horizontally_impl
|
73
|
+
paint {|g| g.draw_image @src, 0, 0, width, height, width, 0, 0, height, nil}
|
74
|
+
end
|
75
|
+
|
76
|
+
def flip_vertically_impl
|
77
|
+
paint {|g| g.draw_image @src, 0, 0, width, height, 0, height, width, 0, nil}
|
78
|
+
end
|
79
|
+
|
80
|
+
def greyscale_impl
|
81
|
+
transform(GREY_OP)
|
82
|
+
end
|
83
|
+
|
84
|
+
def negative_impl
|
85
|
+
transform(NEGATIVE_OP)
|
86
|
+
end
|
87
|
+
|
88
|
+
def resize_impl(width, height)
|
89
|
+
paint(BufferedImage.new(width, height, color_type)) do |g|
|
90
|
+
scaled_image = @src.get_scaled_instance width, height, SCALE_SMOOTH
|
91
|
+
g.draw_image scaled_image, 0, 0, nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Save using the format string (jpg, gif, etc..) to the open Java File
|
97
|
+
# instance passed in.
|
98
|
+
#
|
99
|
+
def save_impl(format, file)
|
100
|
+
ImageIO.write(@src, format, file)
|
101
|
+
end
|
102
|
+
|
103
|
+
def with_crop_impl(left, top, right, bottom)
|
104
|
+
ImageVoodoo.new @src.get_subimage(left, top, right-left, bottom-top)
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# A simple swing wrapper around an image voodoo object.
|
109
|
+
#
|
110
|
+
class JImagePanel < javax.swing.JPanel
|
111
|
+
def initialize(image, x=0, y=0)
|
112
|
+
super()
|
113
|
+
@image, @x, @y = image, x, y
|
114
|
+
end
|
115
|
+
|
116
|
+
def image=(image)
|
117
|
+
@image = image
|
118
|
+
invalidate
|
119
|
+
end
|
120
|
+
|
121
|
+
def getPreferredSize
|
122
|
+
java.awt.Dimension.new(@image.width, @image.height)
|
123
|
+
end
|
124
|
+
|
125
|
+
def paintComponent(graphics)
|
126
|
+
graphics.draw_image(@image.to_java, @x, @y, nil)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Internal class for closing preview window
|
131
|
+
class WindowClosed
|
132
|
+
def initialize(block = nil)
|
133
|
+
@block = block || proc { java.lang.System.exit(0) }
|
134
|
+
end
|
135
|
+
def method_missing(meth,*args); end
|
136
|
+
def windowClosing(event); @block.call; end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Creates a viewable frame displaying current image within it.
|
141
|
+
#
|
142
|
+
def preview(&block)
|
143
|
+
frame = JFrame.new("Preview")
|
144
|
+
frame.add_window_listener WindowClosed.new(block)
|
145
|
+
frame.set_bounds 0, 0, width + 20, height + 40
|
146
|
+
frame.add JImagePanel.new(self, 10, 10)
|
147
|
+
frame.visible = true
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# TODO: Figure out how to determine whether source has alpha or not
|
152
|
+
# Experimental: Read an image from the url source and yield/return that
|
153
|
+
# image.
|
154
|
+
#
|
155
|
+
def self.from_url(source)
|
156
|
+
url = java.net.URL.new(source)
|
157
|
+
image = java.awt.Toolkit.default_toolkit.create_image(url)
|
158
|
+
tracker = java.awt.MediaTracker.new(java.awt.Label.new(""))
|
159
|
+
tracker.addImage(image, 0);
|
160
|
+
tracker.waitForID(0)
|
161
|
+
target = paint(BufferedImage.new(image.width, image.height, RGB)) do |g|
|
162
|
+
g.draw_image image, 0, 0, nil
|
163
|
+
end
|
164
|
+
block_given? ? yield(target) : target
|
165
|
+
rescue java.io.IOException, java.net.MalformedURLException
|
166
|
+
raise ArgumentError.new "Trouble retrieving image: #{$!.message}"
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.with_image_impl(file)
|
170
|
+
buffered_image = ImageIO.read(file)
|
171
|
+
buffered_image ? ImageVoodoo.new(buffered_image) : nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.with_bytes_impl(bytes)
|
175
|
+
ImageVoodoo.new ImageIO.read(ByteArrayInputStream.new(bytes))
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
#
|
181
|
+
# Converts a RGB hex value into a java.awt.Color object or dies trying
|
182
|
+
# with an ArgumentError.
|
183
|
+
#
|
184
|
+
def hex_to_color(rgb)
|
185
|
+
raise ArgumentError.new "hex rrggbb needed" if rgb !~ /[[:xdigit:]]{6,6}/
|
186
|
+
|
187
|
+
java.awt.Color.new(rgb[0,2].to_i(16), rgb[2,2].to_i(16), rgb[4,2].to_i(16))
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Determines the best colorspace for a new image based on whether the
|
192
|
+
# existing image contains an alpha channel or not.
|
193
|
+
#
|
194
|
+
def color_type
|
195
|
+
@src.color_model.has_alpha ? ARGB : RGB
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Make a duplicate of the underlying Java src image
|
200
|
+
#
|
201
|
+
def dup_src
|
202
|
+
BufferedImage.new width, height, color_type
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# Do simple AWT operation transformation to target.
|
207
|
+
#
|
208
|
+
def transform(operation, target=dup_src)
|
209
|
+
paint(target) do |g|
|
210
|
+
g.draw_image(@src, 0, 0, nil)
|
211
|
+
g.draw_image(operation.filter(target, nil), 0, 0, nil)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
#
|
216
|
+
# DRY up drawing setup+teardown
|
217
|
+
#
|
218
|
+
def paint(src=dup_src)
|
219
|
+
yield src.graphics
|
220
|
+
src.graphics.dispose
|
221
|
+
ImageVoodoo.new src
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class ImageVoodoo
|
2
|
+
java_import com.google.appengine.api.images.Image
|
3
|
+
java_import com.google.appengine.api.images.ImagesService
|
4
|
+
java_import com.google.appengine.api.images.ImagesServiceFactory
|
5
|
+
java_import com.google.appengine.api.images.Transform
|
6
|
+
|
7
|
+
ImageService = ImagesServiceFactory.images_service
|
8
|
+
|
9
|
+
# Value Add methods for this backend
|
10
|
+
|
11
|
+
def i_am_feeling_lucky
|
12
|
+
transform(ImagesServiceFactory.make_im_feeling_lucky)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Implementations of standard features
|
16
|
+
|
17
|
+
def flip_horizontally_impl
|
18
|
+
transform(ImagesServiceFactory.make_horizontal_flip)
|
19
|
+
end
|
20
|
+
|
21
|
+
def flip_vertically_impl
|
22
|
+
transform(ImagesServiceFactory.make_vertical_flip)
|
23
|
+
end
|
24
|
+
|
25
|
+
def resize_impl(width, height)
|
26
|
+
transform(ImagesServiceFactory.make_resize(width, height))
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_crop_impl(left, top, right, bottom)
|
30
|
+
transform(ImagesServiceFactory.make_crop(left, top, right, bottom))
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.with_bytes_impl(bytes)
|
34
|
+
ImageVoodoo.new ImageServicesFactory.make_image(bytes)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def from_java_bytes
|
40
|
+
String.from_java_bytes @src.image_data
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Make a duplicate of the underlying src image
|
45
|
+
#
|
46
|
+
def dup_src
|
47
|
+
ImageServicesFactory.make_image(from_java_bytes)
|
48
|
+
end
|
49
|
+
|
50
|
+
def transform(transform, target=dup_src)
|
51
|
+
ImageService.apply_transform(transform, target)
|
52
|
+
end
|
53
|
+
end
|
data/lib/image_voodoo/version.rb
CHANGED
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.
|
4
|
+
version: "0.6"
|
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: 2009-
|
12
|
+
date: 2009-06-17 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -31,6 +31,8 @@ files:
|
|
31
31
|
- LICENSE.txt
|
32
32
|
- lib/image_science.rb
|
33
33
|
- lib/image_voodoo
|
34
|
+
- lib/image_voodoo/awt.rb
|
35
|
+
- lib/image_voodoo/gae.rb
|
34
36
|
- lib/image_voodoo/version.rb
|
35
37
|
- lib/image_voodoo.rb
|
36
38
|
- samples/bench.rb
|