lib/image_voodoo.rb in image_voodoo-0.4 vs lib/image_voodoo.rb in image_voodoo-0.5

- old
+ new

@@ -28,23 +28,26 @@ include Java import java.awt.RenderingHints import java.awt.color.ColorSpace import java.awt.geom.AffineTransform + import java.awt.image.BufferedImage import java.awt.image.ByteLookupTable import java.awt.image.ColorConvertOp import java.awt.image.LookupOp import java.awt.image.RescaleOp - import java.awt.image.BufferedImage JFile = java.io.File import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import javax.imageio.ImageIO import javax.swing.JFrame NEGATIVE_OP = LookupOp.new(ByteLookupTable.new(0, (0...254).to_a.reverse.to_java(:byte)), nil) GREY_OP = ColorConvertOp.new(ColorSpace.getInstance(ColorSpace::CS_GRAY), nil) + ARGB = BufferedImage::TYPE_INT_ARGB + RGB = BufferedImage::TYPE_INT_RGB + SCALE_SMOOTH = java.awt.Image::SCALE_SMOOTH def initialize(src) @src = src end @@ -59,51 +62,47 @@ border_width = options[:width].to_i || 2 color = hex_to_color(options[:color]) || hex_to_color("000000") style = options[:style] style = nil if style.to_sym == :plain new_width, new_height = width + 2*border_width, height + 2*border_width - target = BufferedImage.new(new_width, new_height, color_type) - graphics = target.graphics - graphics.color = color - if style - raised = style.to_sym == :raised ? true : false - graphics.fill3DRect(0, 0, new_width, new_height, raised) - else - graphics.fill_rect(0, 0, new_width, new_height) + target = paint(BufferedImage.new(new_width, new_height, color_type)) do |g| + g.color = color + if style + raised = style.to_sym == :raised ? true : false + g.fill3DRect(0, 0, new_width, new_height, raised) + else + g.fill_rect(0, 0, new_width, new_height) + end + g.draw_image(@src, nil, border_width, border_width) end - graphics.draw_image(@src, nil, border_width, border_width) - graphics.dispose - target = ImageVoodoo.new target block_given? ? yield(target) : target end # # Adjusts the brightness of each pixel in image by the following formula: # new_pixel = pixel * scale + offset # def adjust_brightness(scale, offset) - image = ImageVoodoo.new internal_transform(RescaleOp.new(scale, offset, nil)) + image = internal_transform(RescaleOp.new(scale, offset, nil)) block_given? ? yield(image) : image end # # Converts rgb hex color value to an alpha value an yields/returns the new # image. # def alpha(rgb) color = hex_to_color(rgb) - target = BufferedImage.new(width, height, BufferedImage::TYPE_INT_ARGB) - graphics = target.graphics - graphics.set_composite(java.awt.AlphaComposite::Src) - graphics.draw_image(@src, nil, 0, 0) - graphics.dispose - 0.upto(height-1) do |i| - 0.upto(width-1) do |j| - target.setRGB(j, i, 0x8F1C1C) if target.getRGB(j, i) == color.getRGB + target = paint(BufferedImage.new(width, height, ARGB)) do |g| + g.set_composite(java.awt.AlphaComposite::Src) + g.draw_image(@src, nil, 0, 0) + 0.upto(height-1) do |i| + 0.upto(width-1) do |j| + target.setRGB(j, i, 0x8F1C1C) if target.getRGB(j, i) == color.getRGB + end end end - target = ImageVoodoo.new target block_given? ? yield(target) : target end # # Write current image out as a stream of bytes using provided format. @@ -129,63 +128,52 @@ # # Flips the image horizontally and yields/returns the new image. # def flip_horizontally - target = BufferedImage.new(width, height, color_type) - graphics = target.graphics - graphics.draw_image(@src, 0, 0, width, height, width, 0, 0, height, nil) - graphics.dispose - target = ImageVoodoo.new target + target = paint do |g| + g.draw_image @src, 0, 0, width, height, width, 0, 0, height, nil + end block_given? ? yield(target) : target end # # Flips the image vertically and yields/returns the new image. # def flip_vertically - target = BufferedImage.new(width, height, color_type) - graphics = target.graphics - graphics.draw_image(@src, 0, 0, width, height, 0, height, width, 0, nil) - graphics.dispose - target = ImageVoodoo.new target + target = paint do |g| + g.draw_image @src, 0, 0, width, height, 0, height, width, 0, nil + end block_given? ? yield(target) : target end # # Creates a grayscale version of image and yields/returns the new image. # def greyscale - image = ImageVoodoo.new internal_transform(GREY_OP) - block_given? ? yield(image) : image + target = internal_transform(GREY_OP) + block_given? ? yield(target) : target end alias_method :grayscale, :greyscale # # Creates a negative and yields/returns the new image. # def negative - image = ImageVoodoo.new internal_transform(NEGATIVE_OP) - block_given? ? yield(image) : image + target = internal_transform(NEGATIVE_OP) + block_given? ? yield(target) : target end # # Resizes the image to width and height using bicubic interpolation and # yields/returns the new image. # def resize(width, height) - target = BufferedImage.new(width, height, color_type) - graphics = target.graphics - graphics.set_rendering_hint(RenderingHints::KEY_INTERPOLATION, - RenderingHints::VALUE_INTERPOLATION_BICUBIC) - w_scale = width.to_f / @src.width - h_scale = height.to_f / @src.height - transform = AffineTransform.get_scale_instance w_scale, h_scale - graphics.draw_rendered_image @src, transform - graphics.dispose - - target = ImageVoodoo.new target + target = paint(BufferedImage.new(width, height, color_type)) do |g| + scaled_image = @src.get_scaled_instance width, height, SCALE_SMOOTH + g.draw_image scaled_image, 0, 0, nil + end block_given? ? yield(target) : target rescue NativeException => ne raise ArgumentError, ne.message end @@ -205,11 +193,10 @@ # Resize (scale) the current image by the provided ratio and yield/return # the new image. # def scale(ratio) new_width, new_height = (width * ratio).to_i, (height * ratio).to_i - target = resize(new_width, new_height) block_given? ? yield(target) : target end # @@ -247,11 +234,11 @@ def getPreferredSize java.awt.Dimension.new(@image.width, @image.height) end def paintComponent(graphics) - graphics.drawImage(@image.to_java, @x, @y, nil) + graphics.draw_image(@image.to_java, @x, @y, nil) end end # Internal class for closing preview window class WindowClosed @@ -282,15 +269,13 @@ url = java.net.URL.new(source) image = java.awt.Toolkit.default_toolkit.create_image(url) tracker = java.awt.MediaTracker.new(java.awt.Label.new("")) tracker.addImage(image, 0); tracker.waitForID(0) - target = BufferedImage.new(image.getWidth, image.getHeight, BufferedImage::TYPE_INT_RGB) - graphics = target.graphics - graphics.drawImage(image, 0, 0, nil) - graphics.dispose - target = ImageVoodoo.new target + target = paint(BufferedImage.new(image.width, image.height, RGB)) do |g| + g.draw_image image, 0, 0, nil + end block_given? ? yield(target) : target rescue java.io.IOException, java.net.MalformedURLException raise ArgumentError.new "Trouble retrieving image: #{$!.message}" end @@ -349,20 +334,34 @@ # # Determines the best colorspace for a new image based on whether the # existing image contains an alpha channel or not. # def color_type - return BufferedImage::TYPE_INT_ARGB if @src.color_model.has_alpha - BufferedImage::TYPE_INT_RGB + @src.color_model.has_alpha ? ARGB : RGB end # + # DRY up drawing setup+teardown + # + def paint(src=dup_src) + yield src.graphics + src.graphics.dispose + ImageVoodoo.new src + end + + # + # Make a duplicate of the underlying Java src image + # + def dup_src + BufferedImage.new width, height, color_type + end + + # # Do simple AWT operation transformation to target. # - def internal_transform(operation, target=BufferedImage.new(width, height, color_type)) - graphics = target.graphics - graphics.drawImage(@src, 0, 0, nil) - graphics.drawImage(operation.filter(target, nil), 0, 0, nil) - graphics.dispose - target + def internal_transform(operation, target=dup_src) + paint(target) do |g| + g.draw_image(@src, 0, 0, nil) + g.draw_image(operation.filter(target, nil), 0, 0, nil) + end end end