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.