转自:http://schmidt.devlib.org/java/save-jpeg-thumbnail.html#source
Note: I wrote an article on potential problems when creating thumbnails with Java .
This programm loads an image via java.awt.Toolkit
, scales it down to a user-defined resolution and saves it as a JPEG file. The first part, the loading of the original image, is done the same way as in Viewer . So if you don't know yet how loading images with Toolkit
works you might want to study that program first.
Different from Viewer , this program (Thumbnail) works on the command line. So you won't get any windows or other graphical user interface components. The only visual feedback is the word Done.
after the program successfully terminated.
To use this program do the following:
- Save the program's source code as
Thumbnail.java
(regard case). - Open a shell (prompt), go to the directory where
Thumbnail.java
is and compile it:javac Thumbnail.java
You should now have a new class fileThumbnail.class
. - Run the program with five parameters for image file, thumbnail file, thumbnail width and thumbnail height and quality (a value from 0 to 100, 100 being the best and 0 the worst quality), e.g.:
java Thumbnail c:\image.jpg c:\thumbnail.jpg 120 80 75
The fileimage.jpg
must exist already,thumbnail.jpg
will be created (and any existing file of that name overwritten).
You will need Java 1.2 or higher to successfully run this program. The com.sun.image.codec.jpeg
package that will be used for saving the thumbnail is not available with all Java development kits, but as long as you are using a Sun JDK, it should be present.
With Java 1.4 a new way of writing JPEG files was introduced, the image I/O library in the package javax.imageio
. See the Screenshot.java example program . It saves as PNG, but all you have to do is change the second argument of ImageIO.write
from png
to jpg
. The advantage of ImageIO
: It is available with each 1.4+ JDK and JRE, not only those coming from Sun.
Explanation
Now let's see how this program works. First, it is checked that we have exactly five arguments. If this is not the case, an error message is printed to output and the program terminates.
Next, the input image is loaded via Toolkit
and MediaTracker
just as it was done in Viewer .
The third and fourth program argument contain the maximum size of the thumbnail to be created. The actual size of the thumbnail will be computed from that maximum size and the actual size of the image (all sizes are given as pixels). The code that does this is not really very readable, and also not essential to loading and saving image files. But it is necessary to create a thumbnail that is scaled correctly.
As an example, if the two arguments for the maximum thumbnail size are both 100
and the image that was loaded is 400
times 200
pixels large, we want the thumbnail to be 100
times 50
pixels large, not 100
times 100
, because the original image is twice as wide as it is high. A 100
times 100
pixel thumbnail would contain a very skewed version of the original image.
Now that we have determined the size of the thumbnail we create a BufferedImage
of that size, named thumbImage
. We ask for a Graphics2D
object for that new thumbnail image and call its drawImage
method to draw the original image on that new image. The call to drawImage
does the actual scaling. The rendering hints for bilinear interpolation can be left out (remove the line with graphics2D.setRenderingHint
) if high quality is not required and speed more important. Note that embedded color profiles can make scaling with bilinear interpolation very slow with certain versions of the JDK; this supposedly gets better with JDK 6. If you can't rule out that you are dealing with such JPEGs, make sure to not use the interpolation hint or thumbnail creation will take forever (well, two minutes on a modern system on a 6M image). For nicer results (at least in some cases) try RenderingHints.VALUE_INTERPOLATION_BICUBIC
instead of RenderingHints.VALUE_INTERPOLATION_BILINEAR
. Same warning as above.
In order to save the scaled-down image to a JPEG file, we create a buffered FileOutputStream
with the second argument as name and initialize the necessary objects from the com.sun.image.codec.jpeg
package. The quality argument from the command line is converted from the interval 0
to 100
to the interval 0.0f
to 1.0f
, because that's what the codec expects (I mostly use 0.75f
). The higher that quality number is, the better the resulting thumbnail image quality, but also the larger the resulting file.
The call to System.exit(0);
is unfortunately necessary for some Java runtime environments (because of a bug that keeps the AWT thread from terminating).
Source code of Thumbnail.java
import com.sun.image.codec.jpeg.*; import java.awt.*; import java.awt.image.*; import java.io.*; /** * Thumbnail.java (requires Java 1.2+) * Load an image, scale it down and save it as a JPEG file. * @author Marco Schmidt */ public class Thumbnail { public static void main(String[] args) throws Exception { if (args.length != 5) { System.err.println("Usage: java Thumbnail INFILE " + "OUTFILE WIDTH HEIGHT QUALITY"); System.exit(1); } // load image from INFILE Image image = Toolkit.getDefaultToolkit().getImage(args[0]); MediaTracker mediaTracker = new MediaTracker(new Container()); mediaTracker.addImage(image, 0); mediaTracker.waitForID(0); // determine thumbnail size from WIDTH and HEIGHT int thumbWidth = Integer.parseInt(args[2]); int thumbHeight = Integer.parseInt(args[3]); double thumbRatio = (double)thumbWidth / (double)thumbHeight; int imageWidth = image.getWidth(null); int imageHeight = image.getHeight(null); double imageRatio = (double)imageWidth / (double)imageHeight; if (thumbRatio < imageRatio) { thumbHeight = (int)(thumbWidth / imageRatio); } else { thumbWidth = (int)(thumbHeight * imageRatio); } // draw original image to thumbnail image object and // scale it to the new size on-the-fly BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = thumbImage.createGraphics(); graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null); // save thumbnail image to OUTFILE BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(args[1])); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder. getDefaultJPEGEncodeParam(thumbImage); int quality = Integer.parseInt(args[4]); quality = Math.max(0, Math.min(quality, 100)); param.setQuality((float)quality / 100.0f, false); encoder.setJPEGEncodeParam(param); encoder.encode(thumbImage); out.close(); System.out.println("Done."); System.exit(0); } }