lib/image_voodoo/awt.rb in image_voodoo-0.8.2 vs lib/image_voodoo/awt.rb in image_voodoo-0.8.3

- old
+ new

@@ -1,6 +1,10 @@ +require 'image_voodoo/awt/shapes' + class ImageVoodoo + include ImageVoodoo::Shapes + java_import java.awt.RenderingHints java_import java.awt.color.ColorSpace java_import java.awt.geom.AffineTransform java_import java.awt.image.BufferedImage java_import java.awt.image.ShortLookupTable @@ -8,22 +12,20 @@ java_import java.awt.image.LookupOp java_import java.awt.image.RescaleOp java_import java.io.ByteArrayInputStream java_import java.io.ByteArrayOutputStream java_import javax.imageio.ImageIO + java_import javax.imageio.IIOImage + java_import javax.imageio.ImageWriteParam + java_import javax.imageio.stream.FileImageOutputStream java_import javax.swing.JFrame - NEGATIVE_OP = LookupOp.new(ShortLookupTable.new(0, (0...255).to_a.reverse.to_java(:short)), 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 - + # FIXME: Move and rewrite in terms of new shape + ## # - # AWT-only (experimental) - # Add a border to the image and yield/return a new image. The following - # options are supported: + # *AWT* (experimental) Add a border to the image and yield/return a new + # image. The following options are supported: # - width: How thick is the border (default: 3) # - color: Which color is the border (in rrggbb hex value) # - style: etched, raised, plain (default: plain) # def add_border(options = {}) @@ -43,69 +45,11 @@ g.draw_image(@src, nil, border_width, border_width) end block_given? ? yield(target) : target end - def adjust_brightness_impl(scale, offset) - transform(RescaleOp.new(scale, offset, nil)) - end - - # AWT-only - def alpha_impl(rgb) - color = hex_to_color(rgb) - 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 - end - - def bytes_impl(format) - out = ByteArrayOutputStream.new - ImageIO.write(@src, format, out) - out.to_byte_array - end - - def flip_horizontally_impl - paint {|g| g.draw_image @src, 0, 0, width, height, width, 0, 0, height, nil} - end - - def flip_vertically_impl - paint {|g| g.draw_image @src, 0, 0, width, height, 0, height, width, 0, nil} - end - - def greyscale_impl - transform(GREY_OP) - end - - def negative_impl - transform(NEGATIVE_OP) - end - - def resize_impl(width, height) - 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 - end - - # - # Save using the format string (jpg, gif, etc..) to the open Java File - # instance passed in. - # - def save_impl(format, file) - ImageIO.write(@src, format, file) - end - - def with_crop_impl(left, top, right, bottom) - ImageVoodoo.new @src.get_subimage(left, top, right-left, bottom-top) - end - + ## # # A simple swing wrapper around an image voodoo object. # class JImagePanel < javax.swing.JPanel def initialize(image, x=0, y=0) @@ -125,30 +69,43 @@ def paintComponent(graphics) graphics.draw_image(@image.to_java, @x, @y, nil) end end + ImageVoodoo::JImagePanel.__persistent__ = true + # Internal class for closing preview window class WindowClosed def initialize(block = nil) @block = block || proc { java.lang.System.exit(0) } end def method_missing(meth,*args); end def windowClosing(event); @block.call; end end + ## # - # Creates a viewable frame displaying current image within it. + # *AWT* Creates a viewable frame displaying current image within it. # def preview(&block) frame = JFrame.new("Preview") frame.add_window_listener WindowClosed.new(block) frame.set_bounds 0, 0, width + 20, height + 40 frame.add JImagePanel.new(self, 10, 10) frame.visible = true end + ## + # *AWT* paint/render to the source + # + def paint(src=dup_src) + yield src.graphics + src.graphics.dispose + ImageVoodoo.new src + end + + ## # # TODO: Figure out how to determine whether source has alpha or not # Experimental: Read an image from the url source and yield/return that # image. # @@ -164,26 +121,40 @@ block_given? ? yield(target) : target rescue java.io.IOException, java.net.MalformedURLException raise ArgumentError.new "Trouble retrieving image: #{$!.message}" end + ## + # *AWT* Create an image of width x height filled with a single color. + # + def self.canvas(width, height, rgb='000000') + image = ImageVoodoo.new(BufferedImage.new(width, height, ARGB)) + image.rect(0, 0, width, height, rgb) + end + + private + + NEGATIVE_OP = LookupOp.new(ShortLookupTable.new(0, (0...256).to_a.reverse.to_java(:short)), 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 self.with_image_impl(file) buffered_image = ImageIO.read(file) buffered_image ? ImageVoodoo.new(buffered_image) : nil end def self.with_bytes_impl(bytes) ImageVoodoo.new ImageIO.read(ByteArrayInputStream.new(bytes)) end - private - # # Converts a RGB hex value into a java.awt.Color object or dies trying # with an ArgumentError. # - def hex_to_color(rgb) + def self.hex_to_color(rgb) raise ArgumentError.new "hex rrggbb needed" if rgb !~ /[[:xdigit:]]{6,6}/ java.awt.Color.new(rgb[0,2].to_i(16), rgb[2,2].to_i(16), rgb[4,2].to_i(16)) end @@ -197,11 +168,11 @@ # # Make a duplicate of the underlying Java src image # def dup_src - BufferedImage.new width, height, color_type + BufferedImage.new to_java.color_model, to_java.raster, true, nil end # # Do simple AWT operation transformation to target. # @@ -210,14 +181,76 @@ g.draw_image(@src, 0, 0, nil) g.draw_image(operation.filter(target, nil), 0, 0, nil) end end + def adjust_brightness_impl(scale, offset) + transform(RescaleOp.new(scale, offset, nil)) + end + + def alpha_impl(rgb) + color = hex_to_color(rgb) + 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 + end + + def bytes_impl(format) + out = ByteArrayOutputStream.new + write_new_image format, out + out.to_byte_array + end + + def flip_horizontally_impl + paint {|g| g.draw_image @src, 0, 0, width, height, width, 0, 0, height, nil} + end + + def flip_vertically_impl + paint {|g| g.draw_image @src, 0, 0, width, height, 0, height, width, 0, nil} + end + + def greyscale_impl + transform(GREY_OP) + end + + def negative_impl + transform(NEGATIVE_OP) + end + + def resize_impl(width, height) + 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 + end + # - # DRY up drawing setup+teardown - # - def paint(src=dup_src) - yield src.graphics - src.graphics.dispose - ImageVoodoo.new src + # Save using the format string (jpg, gif, etc..) to the open Java File + # instance passed in. + # + def save_impl(format, file) + write_new_image format, FileImageOutputStream.new(file) + end + + def with_crop_impl(left, top, right, bottom) + ImageVoodoo.new @src.get_subimage(left, top, right-left, bottom-top) + end + + def write_new_image(format, stream) + writer = ImageIO.getImageWritersByFormatName(format).next + writer.output = stream + + param = writer.default_write_param + if param.can_write_compressed && @quality + param.compression_mode = ImageWriteParam::MODE_EXPLICIT + param.compression_quality = @quality + end + + writer.write nil, IIOImage.new(@src, nil, nil), param end end