// $Id: ImageUtils.java,v 1.1 2006/05/20 17:02:09 Sasha Buzko Exp $ // // Copyright 2000-2004 The Regents of the University of California. // All Rights Reserved. // // Permission to use, copy, modify and distribute any part of this // Molecular Biology Toolkit (MBT) // for educational, research and non-profit purposes, without fee, and without // a written agreement is hereby granted, provided that the above copyright // notice, this paragraph and the following three paragraphs appear in all // copies. // // Those desiring to incorporate this MBT into commercial products // or use for commercial purposes should contact the Technology Transfer & // Intellectual Property Services, University of California, San Diego, 9500 // Gilman Drive, Mail Code 0910, La Jolla, CA 92093-0910, Ph: (858) 534-5815, // FAX: (858) 534-7345, E-MAIL:invent@ucsd.edu. // // IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING // LOST PROFITS, ARISING OUT OF THE USE OF THIS MBT, EVEN IF THE // UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.// // THE MBT PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND THE // UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE UNIVERSITY OF CALIFORNIA MAKES // NO REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER IMPLIED OR // EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE // MBT WILL NOT INFRINGE ANY PATENT, TRADEMARK OR OTHER RIGHTS. // // For further information, please see: http://mbt.sdsc.edu // // History: // $Log: ImageUtils.java,v $ // Revision 1.1 2006/05/20 17:02:09 Sasha Buzko // Updated version // // Revision 1.1 2006/04/30 20:14:06 Sasha Buzko // New version of the app // // Revision 1.1 2006/04/15 19:42:28 Sasha Buzko // Initial commit // // Revision 1.1 2006/03/07 19:15:17 Administrator // *** empty log message *** // // Revision 1.2 2005/03/29 20:58:39 moreland // Fixed a bug in the computation of the new image aspect ratio. // // Revision 1.1 2004/08/19 16:49:04 moreland // *** empty log message *** // // Revision 1.0 2004/08/19 16:26:35 moreland // package edu.sdsc.mbt.image; // Unit testing import java.io.*; import com.sun.image.codec.jpeg.*; // Core import java.awt.*; import java.awt.image.*; /** * Provides AWT-based (pure Java) image manipulation methods * for cropping, scaling, and padding images. *
* @author John L. Moreland */ public class ImageUtils { /** * Find the edges of the input image using the upper left corner pixel * color as the background color, automatically crop the image down * to eliminate the excess background border, then scale the image * (maintaining the correct aspect ratio of the input image) and * then center the image with appropriate background padding * of the specified output width and height. *
* @return The cropped and scaled image. */ public static BufferedImage autoCropAndScale( Image image, int outWidth, int outHeight ) { double outRatio = (double) outWidth / (double) outHeight; int inWidth = image.getWidth( null ); int inHeight = image.getHeight( null ); double inRatio = (double) inWidth / (double) inHeight; // // Find the edges of the image by finding the min/max x,y coordinate // where pixels are a different color than the upper left pixel. // int pixels[] = getPixels( image ); // Source rectangle int sx1 = 0; int sy1 = 0; int sx2 = inWidth - 1; int sy2 = inHeight - 1; // Desination rectangle int dx1 = 0; int dy1 = 0; int dx2 = outWidth - 1; int dy2 = outHeight - 1; // Source rectangle int edges[] = findEdges( pixels, inWidth, inHeight ); if ( edges != null ) { sx1 = edges[0]; // left sy1 = edges[1]; // top sx2 = edges[2]; // right sy2 = edges[3]; // bottom } // // Recompute the destination rectangle to ensure that we maintain // the cropped image aspect ratio, fill as much of the destination // as possible, and center the source image horizontally or vertically. // double newInRatio = (double) (sx2-sx1) / (double) (sy2-sy1); if ( outRatio < newInRatio ) { // Output is narrower aspect than input // ------- // | out | // |-----| // | | // | in | // | | // |-----| // | out | // ------- int newOutHeight = (int) (outWidth / newInRatio); int spareHeight = outHeight - newOutHeight; int halfSpareHeight = (int) ((double) spareHeight / 2.0); dy1 = halfSpareHeight; dy2 = dy1 + newOutHeight; } else { // Output is wider aspect than input // --------------- // | o | i | o | // | u | n | u | // | t | | t | // --------------- int newOutWidth = (int) (outHeight * newInRatio); int spareWidth = outWidth - newOutWidth; int halfSpareWidth = (int) ((double) spareWidth / 2.0); dx1 = halfSpareWidth; dx2 = dx1 + newOutWidth; } /* System.err.println( "ImageUtils.autoCropAndScale rectangles:\n" + " src = \n" + " ratio = " + newInRatio + "\n" + " left = " + sx1 + "\n" + " top = " + sy1 + "\n" + " right = " + sx2 + "\n" + " bottom = " + sy2 + "\n" + " dst = \n" + " ratio = " + outRatio + "\n" + " left = " + dx1 + "\n" + " top = " + dy1 + "\n" + " right = " + dx2 + "\n" + " bottom = " + dy2 + "\n" + "" ); */ // // Draw input image to output image object and // scale it to the new size on-the-fly. // // Create the destination/output image. BufferedImage outImage = new BufferedImage( outWidth, outHeight, BufferedImage.TYPE_INT_RGB ); Graphics2D graphics2D = outImage.createGraphics( ); graphics2D.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); // Fill the image with the background (ie: the corner pixel) color. int bgColor = getPixel( pixels, outWidth, 0, 0 ); graphics2D.setColor( new Color( bgColor, true ) ); graphics2D.fillRect( 0, 0, outWidth, outHeight ); // Draw/scale the image. graphics2D.drawImage( image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null ); return outImage; } /** * Return the pixels (as 4-byte, 24-bit, 8-bit-per-component, ARGB ints). * Note that the caller needs to track the dimensions (width,height) * for subsequent manipulation. */ public static int[] getPixels( Image image ) { int width = image.getWidth( null ); int height = image.getHeight( null ); int[] pixels = new int[ width * height ]; PixelGrabber pg = new PixelGrabber( image, 0, 0, width, height, pixels, 0, width ); try { pg.grabPixels( ); } catch ( InterruptedException e ) { return null; } if ( (pg.getStatus() & ImageObserver.ABORT) != 0 ) return null; return pixels; } /** * Return one pixel (as 4-byte, 24-bit, 8-bit-per-component, ARGB int) * given the raw pixel array returned by the getPixels method. */ public static int getPixel( int pixels[], int width, int x, int y ) { return pixels[ y * width + x ]; } /** * Find the edges of the image by finding the min/max x,y coordinate * where pixels are a different color than the upper left pixel. *
* @return int[4] (left,top,right,bottom)
*/
public static int[] findEdges( int pixels[], int width, int height )
{
int firstPixel = getPixel( pixels, width, 0, 0 );
boolean done;
int edges[] = new int[4];
// Find top
done = false;
for ( int y=0; y
* Example: java ImageUtils inFile.png outFile.jpg 512 512
*/
public static void main( String args[] )
{
//
// Load an image from an input file.
//
Image image = Toolkit.getDefaultToolkit().getImage( args[0] );
MediaTracker mediaTracker = new MediaTracker( new Container() );
mediaTracker.addImage( image, 0 );
try
{
mediaTracker.waitForID( 0 );
}
catch ( java.lang.InterruptedException e )
{
System.err.println( e );
}
//
// Determine the output image size from width and height parameters.
//
int outWidth = Integer.parseInt( args[2] );
int outHeight = Integer.parseInt( args[3] );
BufferedImage outImage =
ImageUtils.autoCropAndScale( image, outWidth, outHeight );
//
// Save the output image to an output file.
//
FileOutputStream fos = null;
try
{
fos = new FileOutputStream( args[1] );
}
catch ( java.io.FileNotFoundException e )
{
System.err.println( e );
}
BufferedOutputStream out = new BufferedOutputStream( fos );
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder( out );
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam( outImage );
int quality = 100; // Integer.parseInt( args[4] );
quality = Math.max( 0, Math.min( quality, 100 ) );
param.setQuality( (float) quality / 100.0f, false );
encoder.setJPEGEncodeParam( param );
try
{
encoder.encode( outImage );
out.close( );
}
catch( java.io.IOException e )
{
System.err.println( e );
}
}
}
* argv[1] = output JPEG image file name.
* argv[2] = output image width.
* argv[3] = output image height.
*