I'm not sure, it might depend on a variety of factors. I know Java ImageIO can 
use disk-backed caching, but that's just for manufacturing the BufferedImage 
and so I don't know if it's disk-backed-ness carries over into the 
BufferedImage it produces.

I don't handle DPI -- I create a BufferedImage of mostly the same properties 
and do a pixel-pixel rescale. I suspect the DPI would only come into play when 
you need to write it to disk with an image format that supports DPI, however I 
surely don't know.

-Ross


On Jan 19, 2010, at 4:09 PM, Naftoli Gugenheim wrote:

> Does JAI need everything in RAM?
> Also, how do you deal with DPI?
> 
> -------------------------------------
> Ross Mellgren<dri...@gmail.com> wrote:
> 
> Well, it has to keep the whole source (packed) in memory and the target 
> (unpacked / 32 bit RGBA) in memory, so I would assume that as long as 
> AffineTransformOp is not doing something untoward it's probably around (src 
> width * src height * src bytes/pixel) + (dest width * dest height * 4 bytes) 
> plus a little bit extra.
> 
> I'm not a Java2D guru or anything, so I'm not sure how that could be improved 
> offhand.
> 
> If you want to wrap it up and put it in, that'd be awesome!
> 
> -Ross
> 
> On Jan 15, 2010, at 10:17 AM, Timothy Perrett wrote:
> 
>> 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.
>> 
>> 
> 
> -- 
> 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.
> 
> 

-- 
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