Cool stuff Ross, whats the overhead like in terms of memory etc? 

I might have a bit of time to put this into a module and stuff it on review 
board. 

Cheers, Tim

On 15 Jan 2010, at 15:03, Ross Mellgren wrote:

> According to Jon on the call, he said he was putting together just such a 
> lift module (for image stuff), so I figured I'd toss this over in case it was 
> of use to him in that module.
> 
> If anyone else wants to use it independently, consider it a contribution to 
> lift, and licensed the same way.
> 
> -Ross
> 
> On Jan 15, 2010, at 9:51 AM, Peter Robinett wrote:
> 
>> Ross, this looks nice. Imagine resizing code is something that I've
>> personally had to do many times and is always annoying, so perhaps
>> this would make a good Lift module? Anyway, this is probably best
>> discussed on the main list...
>> 
>> Peter
>> 
>> On Jan 14, 3:01 am, Ross Mellgren <dri...@gmail.com> wrote:
>>> Oh I nearly forgot I said on the conference call the other day that I'd 
>>> send the image resize code we built at work, in case it would be helpful. 
>>> Here it is:
>>> 
>>> import java.awt.{Graphics, RenderingHints, Transparency}
>>> import java.awt.geom.AffineTransform
>>> import java.awt.image.{AffineTransformOp, BufferedImage, ColorModel, 
>>> IndexColorModel}
>>> 
>>> /**
>>> * Helpers for manipulating images
>>> */
>>> object ImageHelpers
>>> {
>>> // Some code here omitted -- Ed.
>>> 
>>>    /** Rendering hints set up for the highest quality rendering */
>>>    val highQualityHints = {
>>>        val h = new RenderingHints(null)
>>>        h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, 
>>> RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)
>>>        h.put(RenderingHints.KEY_COLOR_RENDERING, 
>>> RenderingHints.VALUE_COLOR_RENDER_QUALITY)
>>>        h.put(RenderingHints.KEY_INTERPOLATION, 
>>> RenderingHints.VALUE_INTERPOLATION_BICUBIC)
>>>        h.put(RenderingHints.KEY_ANTIALIASING, 
>>> RenderingHints.VALUE_ANTIALIAS_ON)
>>>        h.put(RenderingHints.KEY_RENDERING, 
>>> RenderingHints.VALUE_RENDER_QUALITY)
>>>        h
>>>    }
>>> 
>>> // Some code here omitted -- Ed.
>>> 
>>>    /**
>>>     * Resize an image of the given source type by the given ratios, 
>>> properly handling GIF transparency, giving back the resized
>>>     * image and the new image format type that should be used.
>>>     *
>>>     * The image type might change if the input type is an indexed color 
>>> model, because it is a hard problem to choose an optimized
>>>     * palette, and currently we don't. This function will return "png" as 
>>> the new type in this case.
>>>     *
>>>     * If the input image is not using an indexed color model with 
>>> transparency, then the target format and color model will be
>>>     * identical to the source.
>>>     */
>>>    def resize(source: BufferedImage, inputFormat: String, dx: Double, dy: 
>>> Double): (BufferedImage, String) = {
>>>        var sourceColorModel = source.getColorModel
>>>        val targetColorModel = source.getColorModel
>>>        val standardColorModel = ColorModel.getRGBdefault
>>> 
>>>        val (targetWidth, targetHeight) = (((source.getWidth: Double) * 
>>> dx).asInstanceOf[Int], ((source.getHeight: Double) * dy).asInstanceOf[Int])
>>> 
>>>        def resize(src: BufferedImage, dst: BufferedImage) {
>>>            val g = dst.createGraphics
>>>            try {
>>>                g.setRenderingHints(highQualityHints)
>>>                g.drawImage(src, new 
>>> AffineTransformOp(AffineTransform.getScaleInstance(dx, dy), 
>>> AffineTransformOp.TYPE_BICUBIC), 0, 0)
>>>            } finally {
>>>                g.dispose
>>>            }
>>>        }
>>> 
>>>        // GIF support in Java is very ornery. For GIFs we have to manually 
>>> do the masking on input, and then just punt on outputting GIFs and instead 
>>> output PNGs.
>>>        if (sourceColorModel.isInstanceOf[IndexColorModel] &&
>>>            sourceColorModel.hasAlpha &&
>>>            sourceColorModel.getTransparency == Transparency.BITMASK &&
>>>            
>>> sourceColorModel.asInstanceOf[IndexColorModel].getTransparentPixel >= 0) {
>>> 
>>>            val indexColorModel = 
>>> sourceColorModel.asInstanceOf[IndexColorModel]
>>>            val transparent = 
>>> indexColorModel.getRGB(indexColorModel.getTransparentPixel)
>>> 
>>>            val masked = new BufferedImage(standardColorModel, 
>>> standardColorModel.createCompatibleWritableRaster(source.getWidth, 
>>> source.getHeight), standardColorModel.isAlphaPremultiplied, null)
>>>            var w = masked.getWidth
>>>            var h = masked.getHeight
>>> 
>>>            val buf  = new Array[Int](w)
>>> 
>>>            var y = 0
>>>            while (y < h) {
>>>                source.getRGB(0, y, w, 1, buf,  0, 1)
>>> 
>>>                var x = 0
>>>                while (x < w) {
>>>                    val c = buf(x)
>>>                    if (c == transparent) {
>>>                        buf(x) = 0
>>>                    }
>>>                    x += 1
>>>                }
>>> 
>>>                masked.setRGB(0, y, w, 1, buf, 0, 1)
>>>                y += 1
>>>            }
>>> 
>>>            val resized = new BufferedImage(standardColorModel, 
>>> standardColorModel.createCompatibleWritableRaster(targetWidth, 
>>> targetHeight), standardColorModel.isAlphaPremultiplied, null)
>>>            resize(masked, resized)
>>>            (resized, "png")
>>>        } else if (sourceColorModel.isInstanceOf[IndexColorModel]) {
>>>            // The input color model is indexed, and we know we won't be 
>>> able to generate a tolerable palette to make another indexed color model, 
>>> so use sRGB and upgrade to PNG.
>>>            val resized = new BufferedImage(standardColorModel, 
>>> standardColorModel.createCompatibleWritableRaster(targetWidth, 
>>> targetHeight), standardColorModel.isAlphaPremultiplied, null)
>>>            resize(source, resized)
>>>            (resized, "png")
>>>        } else {
>>>            val resized = new BufferedImage(targetColorModel, 
>>> targetColorModel.createCompatibleWritableRaster(targetWidth, targetHeight), 
>>> targetColorModel.isAlphaPremultiplied, null)
>>>            resize(source, resized)
>>>            (resized, inputFormat)
>>>        }
>>>    }
>>> 
>>> }
>>> 
>>> It isn't perhaps the ideal implementation, as mentioned in some of the 
>>> comments, but perhaps Jon or others might find it useful in whole or part.
>>> 
>>> -Ross
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Lift-committers" group.
>> To post to this group, send email to lift-committ...@googlegroups.com.
>> To unsubscribe from this group, send email to 
>> lift-committers+unsubscr...@googlegroups.com.
>> For more options, visit this group at 
>> http://groups.google.com/group/lift-committers?hl=en.
>> 
>> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Lift" group.
> To post to this group, send email to lift...@googlegroups.com.
> To unsubscribe from this group, send email to 
> liftweb+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/liftweb?hl=en.
> 
> 

-- 
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to