all get documented properly soon, need to update this for the new server... also changed all the E-mail addresses in the old java source to match present reality
194 lines
8.0 KiB
Java
194 lines
8.0 KiB
Java
/*
|
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
|
* (the "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
|
* language governing rights and limitations under the License.
|
|
*
|
|
* The Original Code is the Venice Web Communities System.
|
|
*
|
|
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@users.sf.net>,
|
|
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
|
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
package com.silverwrist.util.image;
|
|
|
|
import java.awt.Dimension;
|
|
import java.awt.image.*;
|
|
import java.awt.image.renderable.ParameterBlock;
|
|
import java.io.*;
|
|
import javax.media.jai.*;
|
|
import com.sun.media.jai.codec.*;
|
|
|
|
/**
|
|
* A class that performs "normalization" on an image to fit within a bounding box of a specified pixel
|
|
* size. "Normalized" images are scaled down proportionally to fit the bounding box, then centered over
|
|
* a black backdrop (so the image will be "letterboxed" if it has a larger H:V aspect ratio than the bounding
|
|
* box, or "pillarboxed" if it has a smaller H:V aspect ratio than the bounding box).
|
|
*
|
|
* @author Eric J. Bowersox <erbo@users.sf.net>
|
|
* @version X
|
|
*/
|
|
public class ImageNormalizer
|
|
{
|
|
/*--------------------------------------------------------------------------------
|
|
* External static operations
|
|
*--------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* "Normalizes" an image to fit within a bounding box of a specified pixel size. "Normalized" images are
|
|
* scaled down proportionally to fit the bounding box, then centered over a black backdrop (so the image
|
|
* will be "letterboxed" if it has a larger H:V aspect ratio than the bounding box, or "pillarboxed" if it
|
|
* has a smaller H:V aspect ratio than the bounding box).
|
|
*
|
|
* @param raw_data Raw image data from the input, in any JAI-recognized format.
|
|
* @param width The width of the bounding box to use to normalize the image.
|
|
* @param height The height of the bounding box to use to normalize the image.
|
|
* @param out_format The desired format for output (such as "JPEG").
|
|
* @return The normalized image data and its length, as an <CODE>ImageLengthPair</CODE>.
|
|
* @exception com.silverwrist.util.image.ImageNormalizerException An error occurred in the image data or
|
|
* the image transformation process.
|
|
* @see ImageLengthPair
|
|
* @see ImageNormalizerException
|
|
*/
|
|
public static ImageLengthPair normalizeImage(InputStream raw_data, int width, int height, String out_format)
|
|
throws ImageNormalizerException
|
|
{
|
|
PlanarImage img1; // the "initial" image we're loading
|
|
try
|
|
{ // Start by loading the image we're working with.
|
|
SeekableStream istm = new ForwardSeekableStream(raw_data);
|
|
RenderedOp rop1 = JAI.create("stream",istm);
|
|
img1 = rop1.getRendering();
|
|
|
|
} // end try
|
|
catch (RuntimeException re)
|
|
{ // unable to get the rendering here!
|
|
throw new ImageNormalizerException("Image data not a valid image format",re);
|
|
|
|
} // end catch
|
|
|
|
try
|
|
{ // Compute the scaling factors required to get the image down to the appropriate size, then choose
|
|
// the smaller of the two to use as the final scaling factor.
|
|
Float scale_width = null, scale_height = null;
|
|
if (img1.getWidth()>width)
|
|
scale_width = new Float((float)width / (float)(img1.getWidth()));
|
|
if (img1.getHeight()>height)
|
|
scale_height = new Float((float)height / (float)(img1.getHeight()));
|
|
Float scale = null;
|
|
if (scale_width!=null)
|
|
{ // we can scale by width, how about height?
|
|
if (scale_height!=null)
|
|
{ // yes, height too...pick the smaller of the two
|
|
if (scale_width.floatValue()<scale_height.floatValue())
|
|
scale = scale_width;
|
|
else
|
|
scale = scale_height;
|
|
|
|
} // end if
|
|
else // no, just width
|
|
scale = scale_width;
|
|
|
|
} // end if
|
|
else if (scale_height!=null) // can only scale by height
|
|
scale = scale_height;
|
|
|
|
// If we need to scale the image now, do so.
|
|
PlanarImage img2; // image post-scaling
|
|
if (scale!=null)
|
|
{ // scale the image down!
|
|
ParameterBlock pb1 = new ParameterBlock();
|
|
pb1.addSource(img1);
|
|
pb1.add(scale.floatValue());
|
|
pb1.add(scale.floatValue());
|
|
pb1.add(0.0F);
|
|
pb1.add(0.0F);
|
|
pb1.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
|
|
img2 = JAI.create("scale",pb1);
|
|
|
|
} // end if
|
|
else // just use this as the next image
|
|
img2 = img1;
|
|
|
|
// Figure out the offsets required to center the new image within the "frame."
|
|
int offset_x = (width - img2.getWidth()) / 2;
|
|
int offset_y = (height - img2.getHeight()) / 2;
|
|
|
|
// If we need to translate the image now, do so.
|
|
PlanarImage img3; // image after scaling and translation
|
|
if ((offset_x!=0) || (offset_y!=0))
|
|
{ // set up a translation to move the image to the right location
|
|
ParameterBlock pb2 = new ParameterBlock();
|
|
pb2.addSource(img2);
|
|
pb2.add((float)offset_x);
|
|
pb2.add((float)offset_y);
|
|
pb2.add(Interpolation.getInstance(Interpolation.INTERP_NEAREST));
|
|
img3 = JAI.create("translate",pb2);
|
|
|
|
} // end if
|
|
else // just take the image as it is
|
|
img3 = img2;
|
|
|
|
// To set up the backdrop, first we need to create an image of the right size but with the same
|
|
// sample model and color model as our transformed image.
|
|
TiledImage back1 = new TiledImage(0,0,width,height,0,0,img3.getSampleModel(),img3.getColorModel());
|
|
|
|
// Now we need to make that image black. The easiest way to do that is multiply all pixel
|
|
// values in the image by 0.
|
|
ParameterBlock pb = new ParameterBlock();
|
|
pb.addSource(back1);
|
|
double[] parms = new double[1];
|
|
parms[0] = 0.0;
|
|
pb.add(parms);
|
|
PlanarImage back2 = JAI.create("multiplyconst",pb);
|
|
|
|
// Now overlay the scaled/translated image on top of the background to get the final image.
|
|
PlanarImage final_img = JAI.create("overlay",back2,img3);
|
|
|
|
// With our final image in hand, we can now encode it in the desired output format and turn
|
|
// it into a streamful of data.
|
|
ByteArrayOutputStream ostm = new ByteArrayOutputStream(4096);
|
|
JAI.create("encode",final_img,ostm,out_format,null);
|
|
byte[] odata = ostm.toByteArray();
|
|
ostm.close();
|
|
return new ImageLengthPair(odata.length,new ByteArrayInputStream(odata));
|
|
|
|
} // end try
|
|
catch (Exception e)
|
|
{ // catchall exception
|
|
throw new ImageNormalizerException("unspecified error in scaling or translation",e);
|
|
|
|
} // end catch
|
|
|
|
} // end normalizeImage
|
|
|
|
/**
|
|
* "Normalizes" an image to fit within a bounding box of a specified pixel size. "Normalized" images are
|
|
* scaled down proportionally to fit the bounding box, then centered over a black backdrop (so the image
|
|
* will be "letterboxed" if it has a larger H:V aspect ratio than the bounding box, or "pillarboxed" if it
|
|
* has a smaller H:V aspect ratio than the bounding box).
|
|
*
|
|
* @param raw_data Raw image data from the input, in any JAI-recognized format.
|
|
* @param dim The dimensions of the bounding box to use to normalize the image.
|
|
* @param out_format The desired format for output (such as "JPEG").
|
|
* @return The normalized image data and its length, as an <CODE>ImageLengthPair</CODE>.
|
|
* @exception com.silverwrist.util.image.ImageNormalizerException An error occurred in the image data or
|
|
* the image transformation process.
|
|
* @see ImageLengthPair
|
|
* @see ImageNormalizerException
|
|
*/
|
|
public static ImageLengthPair normalizeImage(InputStream raw_data, Dimension dim, String out_format)
|
|
throws ImageNormalizerException
|
|
{
|
|
return normalizeImage(raw_data,dim.width,dim.height,out_format);
|
|
|
|
} // end normalizeImage
|
|
|
|
} // end class ImageNormalizer
|