ImageUtils.java
Upload User: gdxydsw
Upload Date: 2019-01-29
Package Size: 16721k
Code Size: 10k
Category:

Java Develop

Development Platform:

Java

  1. /*
  2.  * Copyright (c) JForum Team
  3.  * All rights reserved.
  4.  * Redistribution and use in source and binary forms, 
  5.  * with or without modification, are permitted provided 
  6.  * that the following conditions are met:
  7.  * 1) Redistributions of source code must retain the above 
  8.  * copyright notice, this list of conditions and the 
  9.  * following  disclaimer.
  10.  * 2)  Redistributions in binary form must reproduce the 
  11.  * above copyright notice, this list of conditions and 
  12.  * the following disclaimer in the documentation and/or 
  13.  * other materials provided with the distribution.
  14.  * 3) Neither the name of "Rafael Steil" nor 
  15.  * the names of its contributors may be used to endorse 
  16.  * or promote products derived from this software without 
  17.  * specific prior written permission.
  18.  * 
  19.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 
  20.  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
  21.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
  22.  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  24.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
  25.  * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  27.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
  28.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  29.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
  30.  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
  31.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
  32.  * IN CONTRACT, STRICT LIABILITY, OR TORT 
  33.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
  34.  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  35.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  36.  * 
  37.  * This file creation date: 21/04/2004 - 19:54:16
  38.  * The JForum Project
  39.  * http://www.jforum.net
  40.  */
  41. package net.jforum.util.image;
  42. import java.awt.Dimension;
  43. import java.awt.Image;
  44. import java.awt.image.BufferedImage;
  45. import java.awt.image.PixelGrabber;
  46. import java.io.File;
  47. import java.io.IOException;
  48. import java.util.Iterator;
  49. import java.util.Locale;
  50. import javax.imageio.IIOImage;
  51. import javax.imageio.ImageIO;
  52. import javax.imageio.ImageWriteParam;
  53. import javax.imageio.ImageWriter;
  54. import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
  55. import javax.imageio.stream.ImageOutputStream;
  56. import net.jforum.exceptions.ForumException;
  57. /**
  58.  * Utilities methods for image manipulation. It does not support writting of GIF images, but it can
  59.  * read from. GIF images will be saved as PNG.
  60.  * 
  61.  * @author Rafael Steil
  62.  * @version $Id: ImageUtils.java,v 1.23 2007/09/09 01:05:22 rafaelsteil Exp $
  63.  */
  64. public class ImageUtils
  65. {
  66. public static final int IMAGE_UNKNOWN = -1;
  67. public static final int IMAGE_JPEG = 0;
  68. public static final int IMAGE_PNG = 1;
  69. public static final int IMAGE_GIF = 2;
  70. /**
  71.  * Resizes an image
  72.  * 
  73.  * @param imgName The image name to resize. Must be the complet path to the file
  74.  * @param type int
  75.  * @param maxWidth The image's max width
  76.  * @param maxHeight The image's max height
  77.  * @return A resized <code>BufferedImage</code>
  78.  */
  79. public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight)
  80. {
  81. try {
  82. return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
  83. }
  84. catch (IOException e) {
  85. throw new ForumException(e);
  86. }
  87. }
  88. /**
  89.  * Resizes an image.
  90.  * 
  91.  * @param image
  92.  *            The image to resize
  93.  * @param maxWidth
  94.  *            The image's max width
  95.  * @param maxHeight
  96.  *            The image's max height
  97.  * @return A resized <code>BufferedImage</code>
  98.  * @param type
  99.  *            int
  100.  */
  101. public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight)
  102. {
  103. Dimension largestDimension = new Dimension(maxWidth, maxHeight);
  104. // Original size
  105. int imageWidth = image.getWidth(null);
  106. int imageHeight = image.getHeight(null);
  107. float aspectRatio = (float) imageWidth / imageHeight;
  108. if (imageWidth > maxWidth || imageHeight > maxHeight) {
  109. if ((float) largestDimension.width / largestDimension.height > aspectRatio) {
  110. largestDimension.width = (int) Math.ceil(largestDimension.height * aspectRatio);
  111. }
  112. else {
  113. largestDimension.height = (int) Math.ceil(largestDimension.width / aspectRatio);
  114. }
  115. imageWidth = largestDimension.width;
  116. imageHeight = largestDimension.height;
  117. }
  118. return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
  119. }
  120. /**
  121.  * Saves an image to the disk.
  122.  * 
  123.  * @param image  The image to save
  124.  * @param toFileName The filename to use
  125.  * @param type The image type. Use <code>ImageUtils.IMAGE_JPEG</code> to save as JPEG images,
  126.  *  or <code>ImageUtils.IMAGE_PNG</code> to save as PNG.
  127.  * @return <code>false</code> if no appropriate writer is found
  128.  */
  129. public static boolean saveImage(BufferedImage image, String toFileName, int type)
  130. {
  131. try {
  132. return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", new File(toFileName));
  133. }
  134. catch (IOException e) {
  135. throw new ForumException(e);
  136. }
  137. }
  138. /**
  139.  * Compress and save an image to the disk. Currently this method only supports JPEG images.
  140.  * 
  141.  * @param image The image to save
  142.  * @param toFileName The filename to use
  143.  * @param type The image type. Use <code>ImageUtils.IMAGE_JPEG</code> to save as JPEG images,
  144.  * or <code>ImageUtils.IMAGE_PNG</code> to save as PNG.
  145.  */
  146. public static void saveCompressedImage(BufferedImage image, String toFileName, int type)
  147. {
  148. try {
  149. if (type == IMAGE_PNG) {
  150. throw new UnsupportedOperationException("PNG compression not implemented");
  151. }
  152. Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
  153. ImageWriter writer;
  154. writer = (ImageWriter) iter.next();
  155. ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
  156. writer.setOutput(ios);
  157. ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
  158. iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  159. iwparam.setCompressionQuality(0.7F);
  160. writer.write(null, new IIOImage(image, null, null), iwparam);
  161. ios.flush();
  162. writer.dispose();
  163. ios.close();
  164. }
  165. catch (IOException e) {
  166. throw new ForumException(e);
  167. }
  168. }
  169. /**
  170.  * Creates a <code>BufferedImage</code> from an <code>Image</code>. This method can
  171.  * function on a completely headless system. This especially includes Linux and Unix systems
  172.  * that do not have the X11 libraries installed, which are required for the AWT subsystem to
  173.  * operate. This method uses nearest neighbor approximation, so it's quite fast. Unfortunately,
  174.  * the result is nowhere near as nice looking as the createHeadlessSmoothBufferedImage method.
  175.  * 
  176.  * @param image  The image to convert
  177.  * @param w The desired image width
  178.  * @param h The desired image height
  179.  * @return The converted image
  180.  * @param type int
  181.  */
  182. public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width, int height)
  183. {
  184. if (type == ImageUtils.IMAGE_PNG && hasAlpha(image)) {
  185. type = BufferedImage.TYPE_INT_ARGB;
  186. }
  187. else {
  188. type = BufferedImage.TYPE_INT_RGB;
  189. }
  190. BufferedImage bi = new BufferedImage(width, height, type);
  191. for (int y = 0; y < height; y++) {
  192. for (int x = 0; x < width; x++) {
  193. bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
  194. }
  195. }
  196. return bi;
  197. }
  198. /**
  199.  * Creates a <code>BufferedImage</code> from an <code>Image</code>. This method can
  200.  * function on a completely headless system. This especially includes Linux and Unix systems
  201.  * that do not have the X11 libraries installed, which are required for the AWT subsystem to
  202.  * operate. The resulting image will be smoothly scaled using bilinear filtering.
  203.  * 
  204.  * @param source The image to convert
  205.  * @param w The desired image width
  206.  * @param h The desired image height
  207.  * @return The converted image
  208.  * @param type  int
  209.  */
  210. public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type, int width, int height)
  211. {
  212. if (type == ImageUtils.IMAGE_PNG && hasAlpha(source)) {
  213. type = BufferedImage.TYPE_INT_ARGB;
  214. }
  215. else {
  216. type = BufferedImage.TYPE_INT_RGB;
  217. }
  218. BufferedImage dest = new BufferedImage(width, height, type);
  219. int sourcex;
  220. int sourcey;
  221. double scalex = (double) width / source.getWidth();
  222. double scaley = (double) height / source.getHeight();
  223. int x1;
  224. int y1;
  225. double xdiff;
  226. double ydiff;
  227. int rgb;
  228. int rgb1;
  229. int rgb2;
  230. for (int y = 0; y < height; y++) {
  231. sourcey = y * source.getHeight() / dest.getHeight();
  232. ydiff = scale(y, scaley) - sourcey;
  233. for (int x = 0; x < width; x++) {
  234. sourcex = x * source.getWidth() / dest.getWidth();
  235. xdiff = scale(x, scalex) - sourcex;
  236. x1 = Math.min(source.getWidth() - 1, sourcex + 1);
  237. y1 = Math.min(source.getHeight() - 1, sourcey + 1);
  238. rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey), xdiff);
  239. rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);
  240. rgb = getRGBInterpolation(rgb1, rgb2, ydiff);
  241. dest.setRGB(x, y, rgb);
  242. }
  243. }
  244. return dest;
  245. }
  246. private static double scale(int point, double scale)
  247. {
  248. return point / scale;
  249. }
  250. private static int getRGBInterpolation(int value1, int value2, double distance)
  251. {
  252. int alpha1 = (value1 & 0xFF000000) >>> 24;
  253. int red1 = (value1 & 0x00FF0000) >> 16;
  254. int green1 = (value1 & 0x0000FF00) >> 8;
  255. int blue1 = (value1 & 0x000000FF);
  256. int alpha2 = (value2 & 0xFF000000) >>> 24;
  257. int red2 = (value2 & 0x00FF0000) >> 16;
  258. int green2 = (value2 & 0x0000FF00) >> 8;
  259. int blue2 = (value2 & 0x000000FF);
  260. int rgb = ((int) (alpha1 * (1.0 - distance) + alpha2 * distance) << 24)
  261. | ((int) (red1 * (1.0 - distance) + red2 * distance) << 16)
  262. | ((int) (green1 * (1.0 - distance) + green2 * distance) << 8)
  263. | (int) (blue1 * (1.0 - distance) + blue2 * distance);
  264. return rgb;
  265. }
  266. /**
  267.  * Determines if the image has transparent pixels.
  268.  * 
  269.  * @param image The image to check for transparent pixel.s
  270.  * @return <code>true</code> of <code>false</code>, according to the result
  271.  */
  272. public static boolean hasAlpha(Image image)
  273. {
  274. try {
  275. PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
  276. pg.grabPixels();
  277. return pg.getColorModel().hasAlpha();
  278. }
  279. catch (InterruptedException e) {
  280. return false;
  281. }
  282. }
  283. }