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.