java 图片压缩、缩放

对图像的缩放可以带来很多好处,比如在载入图像时可以有效减少各方面的压力。 
这里依靠thumbnailator、imgscalr这两个jar包分别实现。 
为了能够粗粒度的控制压缩,定义一个ScalrConfig来控制图像尺寸,图像类型(JPG、BMP。。。。)等。
   
   
   
   
  1. public class ScalrConfig {
  2. //图片质量
  3. private Float quality = 1F;
  4. //图片高度
  5. private int height = 600;
  6. //图片宽度
  7. private int width = 600;
  8. //使长或宽适应到某一个长度
  9. private Integer size ;
  10. //重写format
  11. private ImageExtensionEnum type = ImageExtensionEnum.JPG;
  12. //是否重写
  13. private boolean retype = true;
  14. //保持横纵比
  15. private boolean aspectRatio = true;
  16. //压缩过滤
  17. private ScalrFilter filter;
  18. public ScalrConfig(int size,int allowWidth,
  19. int allowHeight){
  20. this.size = size;
  21. this.filter = new DefautlScalrFiter(allowWidth,allowHeight);
  22. }
  23. public ScalrConfig(int width,int height,
  24. int allowWidth,int allowHeight){
  25. this.height = height;
  26. this.width = width;
  27. this.filter = new DefautlScalrFiter(allowWidth,allowHeight);
  28. }
  29. class DefautlScalrFiter implements ScalrFilter{
  30. private int allowWidth;
  31. private int allowHeight;
  32.  
  33. @Override
  34. public boolean doFilter(int _width, int _height) {
  35. return allowWidth < _width || allowHeight < _height;
  36. }
  37.  
  38. public DefautlScalrFiter(int allowWidth, int allowHeight) {
  39. this.allowWidth = allowWidth;
  40. this.allowHeight = allowHeight;
  41. }
  42. }
  43. //省略setter、getter

ImageExtensionEnum用来定义图片格式(GIF不支持。。。。)

   
   
   
   
  1. public enum ImageExtensionEnum {
  2. JPG,JPEG,PNG,BMP,GIF;
  3. public final static String [] getExtensions(){
  4. ImageExtensionEnum enums [] = ImageExtensionEnum.values();
  5. String [] extensions = new String [enums.length];
  6. for(int i=0;i<enums.length;i++)
  7. extensions[i] = enums[i].name();
  8. return extensions;
  9. }
  10. public static boolean isJPG(String extension){
  11. return JPEG.name().equalsIgnoreCase(extension) ||
  12. JPG.name().equalsIgnoreCase(extension);
  13. }
  14. public static boolean isSameType(String extension1,String extension2){
  15. if(extension1 == null || extension2 == null) return false;
  16. return (extension1.equalsIgnoreCase(extension2))||
  17. (isJPG(extension1)&&isJPG(extension2))?true : false;
  18. }
  19. }
ScalrFilter 用来控制图片是否需要被压缩,如果图片过小,此时缩放是不明智的。
   
   
   
   
  1. public interface ScalrFilter {
  2. public boolean doFilter(int _width,int _height);
  3.  
  4. }
下面是图片压缩:
   
   
   
   
  1. public interface Thumbnailer {
  2. /**
  3. *
  4. * @param is 图片文件流
  5. * @param size 图片大小
  6. * @param config 配置
  7. * @param extension 图片后缀
  8. * @return
  9. * @throws Exception
  10. */
  11. List<ThumbnailResult> createThumbnails(File file,
  12. ScalrConfig...configs) throws Exception;
  13.  
  14. }
thumnailResult 是一个接口,用来控制缩放成文件、写入输出流、返回缩放后的图片类型和大小:
   
   
   
   
  1. public interface ThumbnailResult {
  2. File writeToFile(File destFile) throws Exception;
  3. void writeToStream(OutputStream stream) throws Exception;
  4. int getWidth() throws Exception;
  5. int getHeight() throws Exception;
  6. String getExtension();
  7.  
  8. }
最后读取、判断文件:
   
   
   
   
  1. public abstract class AbstractThumbaniler implements Thumbnailer{
  2. @Override
  3. public List<ThumbnailResult> createThumbnails(File file,
  4. ScalrConfig... configs) throws Exception {
  5. if(configs == null || configs.length == 0)
  6. {
  7. throw new IllegalArgumentException("必须指定一个 ScalrConfig");
  8. }
  9. if (file == null)
  10. {
  11. throw new IllegalArgumentException("文件不能为空");
  12. }
  13. if (!file.exists())
  14. {
  15. throw new IllegalArgumentException(file.getAbsolutePath() + "不存在");
  16. }
  17. String oldExtension = MyStringUtils.getFilenameExtension(file.getName());
  18. if(!isSupportedOutputFormat(oldExtension))
  19. {
  20. throw new IllegalArgumentException("文件不符合格式");
  21. }
  22. BufferedImage image = ImageIO.read(file);
  23. if (image == null)
  24. {
  25. throw new IllegalArgumentException("文件不是一个真正的图片");
  26. }
  27. List<ThumbnailResult> results = new ArrayList<ThumbnailResult>();
  28. for(ScalrConfig config : configs)
  29. {
  30. ScalrFilter filter = config.getFilter();
  31. if(filter == null || (filter != null &&
  32. filter.doFilter(image.getWidth(), image.getHeight())))
  33. {
  34. results.add(createThumbnail(image, config,oldExtension));
  35. }
  36. }
  37. return results;
  38. }
  39. abstract ThumbnailResult createThumbnail(BufferedImage image,
  40. ScalrConfig config,String oldExtension) throws Exception;
  41. protected List<String> getSupportedOutputFormats(){
  42. String[] formats = ImageIO.getWriterFormatNames();
  43. if (formats == null)
  44. {
  45. return Collections.emptyList();
  46. }
  47. else
  48. {
  49. return Arrays.asList(formats);
  50. }
  51. }
  52. private boolean isSupportedOutputFormat(String format){
  53. for (String supportedFormat : getSupportedOutputFormats())
  54. {
  55. if (supportedFormat.equals(format))
  56. {
  57. return true;
  58. }
  59. }
  60. return false;
  61. }
  62.  
  63. }

首先是  thumbnailator ,它的使用非常简单! 
项目地址(请自觉): 
http://code.google.com/p/thumbnailator/  
它能够按照比例缩让、固定尺寸缩放、打水印、旋转和切割等各种的功能,牛逼的是完成这些功能只需要一行代码即可,例如:
   
   
   
   
  1. Thumbnails.of(new File("q:/user.bmp")).scale(0.25F).toFile(new File("q:/dest.bmmp"));
  2. Thumbnails.of(new File("q:/user.bmp")).size(300, 300).toFile(new File("q:/dest.bmmp"));
  3. Thumbnails.of(new File("q:/user.bmp")).size(300,300).
  4. keepAspectRatio(false).toFile(newFile("q:/dest.bmmp"));
下面是具体的使用:
   
   
   
   
  1. public class CoobirdThumbnailer extends AbstractThumbaniler {
  2.  
  3. @Override
  4. ThumbnailResult createThumbnail(BufferedImage image, ScalrConfig config,
  5. String oldExtension)throws Exception {
  6. int width = image.getWidth();
  7. int height = image.getHeight();
  8. this.calc(config, width, height);
  9. final Builder<BufferedImage> builder = Thumbnails.of(image);
  10. builder.size(config.getWidth(), config.getHeight())
  11. .keepAspectRatio(config.getAspectRatio());
  12. if (config.isRetype())
  13. {
  14. String newExtension = config.getType().name();
  15. if (!ImageExtensionEnum.isSameType(newExtension, oldExtension))
  16. oldExtension = newExtension;
  17. }
  18. builder.outputFormat(oldExtension);
  19. if (ImageExtensionEnum.isJPG(oldExtension)
  20. && config.getQuality() != null)
  21. {
  22. builder.outputQuality(config.getQuality());
  23. }
  24. return new CoobirdThumbnailResult(builder, oldExtension);
  25. }
  26.  
  27. private ScalrConfig calc(ScalrConfig config, int _width, int _height) {
  28. Integer size = config.getSize();
  29. if (size != null) {
  30. config.setAspectRatio(false);
  31. double sourceRatio = (double) _width / (double) _height;
  32. if (_width >= _height)
  33. {
  34. config.setWidth(size);
  35. config.setHeight((int) Math.round(size / sourceRatio));
  36. }
  37. if (_width < _height)
  38. {
  39. config.setHeight(size);
  40. config.setWidth((int) Math.round(size * sourceRatio));
  41. }
  42. }
  43. return config;
  44. }
  45.  
  46. private final class CoobirdThumbnailResult implements ThumbnailResult {
  47.  
  48. private Builder<BufferedImage> builder;
  49.  
  50. private String extension;
  51.  
  52. private CoobirdThumbnailResult(Builder<BufferedImage> builder,
  53. String extension) {
  54. super();
  55. this.builder = builder;
  56. this.extension = extension;
  57. }
  58.  
  59. @Override
  60. public File writeToFile(File destFile) throws Exception {
  61. String fileName = destFile.getName();
  62. String _extension = MyStringUtils.getFilenameExtension(fileName);
  63. if (!extension.equalsIgnoreCase(_extension))
  64. {
  65. destFile = new File(destFile.getParent(), fileName.concat(".")
  66. .concat(extension));
  67. }
  68. builder.toFile(destFile);
  69. return destFile;
  70. }
  71.  
  72. @Override
  73. public void writeToStream(OutputStream stream) throws Exception {
  74. builder.toOutputStream(stream);
  75. }
  76.  
  77. @Override
  78. public int getWidth() throws IOException {
  79. return builder.asBufferedImage().getWidth();
  80. }
  81.  
  82. @Override
  83. public int getHeight() throws IOException {
  84. return builder.asBufferedImage().getHeight();
  85. }
  86.  
  87. @Override
  88. public String getExtension() {
  89. return extension;
  90. }
  91. }
  92.  
  93. }

imgscalr,同样拥有图片压缩、裁剪等功能,使用同样非常简单。不过它好像没有输出到文件或者输出到流的功能(也许我没发现),它还支持多线程压缩?,感兴趣的可以看看  org.imgscalr.AsyncScalr  
项目地址: 
https://github.com/thebuzzmedia/imgscalr  或者  http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/  
官网上的例子:
   
   
   
   
  1. BufferedImage thumbnail =
  2. Scalr.resize(image, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH,
  3. 150, 100, Scalr.OP_ANTIALIAS);
具体使用:
   
   
   
   
  1. public class ImageScalrThumbnailer extends AbstractThumbaniler{
  2.  
  3. @Override
  4. ThumbnailResult createThumbnail(BufferedImage image, ScalrConfig config,
  5. String oldExtension) throws Exception {
  6. Integer size = config.getSize();
  7. if(size != null)
  8. {
  9. image = Scalr.resize(image, Method.QUALITY, size);
  10. }
  11. else
  12. {
  13. if(!config.getAspectRatio())
  14. {
  15. image = Scalr.resize(image, Method.QUALITY,
  16. Mode.FIT_EXACT,config.getWidth(),config.getHeight());
  17. }
  18. else
  19. {
  20. image = Scalr.resize(image, Method.QUALITY,
  21. config.getWidth(),config.getHeight());
  22. }
  23. }
  24. if (config.isRetype())
  25. {
  26. String newExtension = config.getType().name();
  27. if (!ImageExtensionEnum.isSameType(newExtension, oldExtension))
  28. oldExtension = newExtension;
  29. }
  30. return new ImgScalrThumbnailResult(oldExtension,
  31. config.getQuality(),image);
  32. }
  33. private final class ImgScalrThumbnailResult implements ThumbnailResult{
  34. private String extension ;
  35. private Float quality;
  36. private BufferedImage image;
  37.  
  38. @Override
  39. public File writeToFile(File destFile) throws Exception {
  40. String filename = destFile.getName();
  41. String targetExtension = MyStringUtils.getFilenameExtension(filename);
  42. if(!ImageExtensionEnum.isSameType(extension, targetExtension))
  43. {
  44. destFile = new File(destFile.getParent(),
  45. filename.concat(".").concat(extension));
  46. }
  47. ImageUtils.write(image, extension, quality, destFile);
  48. return destFile;
  49. }
  50.  
  51. @Override
  52. public void writeToStream(OutputStream stream) throws Exception {
  53. ImageUtils.write(image, extension, quality, stream);
  54. }
  55.  
  56. @Override
  57. public int getWidth() {
  58. return image.getWidth();
  59. }
  60.  
  61. @Override
  62. public int getHeight() {
  63. return image.getHeight();
  64. }
  65.  
  66. @Override
  67. public String getExtension(){
  68. return extension;
  69. }
  70.  
  71. private ImgScalrThumbnailResult(String extension, Float quality,
  72. BufferedImage image) {
  73. this.extension = extension;
  74. this.quality = quality;
  75. this.image = image;
  76. }
  77. }
  78.  
  79.  
  80. }
ImageUtils用来讲BufferedImage输出到文件或者流,具体如下(来源于Thumbanailator的util):
   
   
   
   
  1. public final class ImageUtils {
  2. public static void write(BufferedImage img , String formatName,
  3. Float quality,File destFile) throws IOException{
  4. Iterator<ImageWriter> writers =
  5. ImageIO.getImageWritersByFormatName(formatName);
  6. if (!writers.hasNext())
  7. {
  8. throw new UnsupportedFormatException(
  9. formatName,
  10. "No suitable ImageWriter found for " + formatName + "."
  11. );
  12. }
  13. ImageWriter writer = writers.next();
  14. ImageWriteParam writeParam = writer.getDefaultWriteParam();
  15. if (writeParam.canWriteCompressed())
  16. {
  17. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  18. List<String> supportedFormats =
  19. ThumbnailatorUtils.getSupportedOutputFormatTypes(formatName);
  20. if (!supportedFormats.isEmpty())
  21. {
  22. writeParam.setCompressionType(supportedFormats.get(0));
  23. }
  24. if(quality != null)
  25. {
  26. writeParam.setCompressionQuality(quality);
  27. }
  28. }
  29. ImageOutputStream ios;
  30. FileOutputStream fos;
  31. fos = new FileOutputStream(destFile);
  32. ios = ImageIO.createImageOutputStream(fos);
  33. if (ios == null || fos == null)
  34. {
  35. throw new IOException("Could not open output file.");
  36. }
  37. if (
  38. formatName.equalsIgnoreCase("jpg")
  39. || formatName.equalsIgnoreCase("jpeg")
  40. || formatName.equalsIgnoreCase("bmp")
  41. )
  42. {
  43. int width = img.getWidth();
  44. int height = img.getHeight();
  45. BufferedImage newImage = new BufferedImage(width, height,
  46. BufferedImage.TYPE_INT_RGB);
  47. Graphics g = newImage.createGraphics();
  48. g.drawImage(img, 0, 0, null);
  49. g.dispose();
  50. img = newImage;
  51. }
  52. writer.setOutput(ios);
  53. writer.write(null, new IIOImage(img, null, null), writeParam);
  54. writer.dispose();
  55. ios.close();
  56. fos.close();
  57. }
  58. public static void write(BufferedImage img,String formatName,
  59. Float quality,OutputStream os) throws IOException{
  60. Iterator<ImageWriter> writers =
  61. ImageIO.getImageWritersByFormatName(formatName);
  62. if (!writers.hasNext())
  63. {
  64. throw new UnsupportedFormatException(
  65. formatName,
  66. "No suitable ImageWriter found for " + formatName + "."
  67. );
  68. }
  69. ImageWriter writer = writers.next();
  70. ImageWriteParam writeParam = writer.getDefaultWriteParam();
  71. if (writeParam.canWriteCompressed())
  72. {
  73. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  74. List<String> supportedFormats =
  75. ThumbnailatorUtils.getSupportedOutputFormatTypes(formatName);
  76. if (!supportedFormats.isEmpty())
  77. {
  78. writeParam.setCompressionType(supportedFormats.get(0));
  79. }
  80. if (quality != null)
  81. {
  82. writeParam.setCompressionQuality(quality);
  83. }
  84. }
  85. ImageOutputStream ios = ImageIO.createImageOutputStream(os);
  86. if (ios == null)
  87. {
  88. throw new IOException("Could not open OutputStream.");
  89. }
  90. if (
  91. formatName.equalsIgnoreCase("jpg")
  92. || formatName.equalsIgnoreCase("jpeg")
  93. || formatName.equalsIgnoreCase("bmp")
  94. )
  95. {
  96. int width = img.getWidth();
  97. int height = img.getHeight();
  98. BufferedImage newImage = new BufferedImage(width, height,
  99. BufferedImage.TYPE_INT_RGB);
  100. Graphics g = newImage.createGraphics();
  101. g.drawImage(img, 0, 0, null);
  102. g.dispose();
  103. img = newImage;
  104. }
  105. writer.setOutput(ios);
  106. writer.write(null, new IIOImage(img, null, null), writeParam);
  107. writer.dispose();
  108. ios.close();
  109. }
  110.  
  111. }
MyStringUitls主要用来获取文件后缀名: 
 
   
   
   
   
  1. public class MyStringUtils {
  2. private static final char EXTENSION_SEPARATOR = '.';
  3. private static final String FOLDER_SEPARATOR = "/";
  4. public static String getFilenameExtension(String path) {
  5. if (path == null) {
  6. return null;
  7. }
  8. int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
  9. if (extIndex == -1) {
  10. return null;
  11. }
  12. int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
  13. if (folderIndex > extIndex) {
  14. return null;
  15. }
  16. return path.substring(extIndex + 1);
  17. }
  18.  
  19. }

测试:
 

   
   
   
   
  1. public class Test {
  2. public static void main(String [] args) throws Exception{
  3. Thumbnailer thumbnailer = ThumbnailerFactory.getThumbnailer();
  4. File toThumbnail = new File("q:/user.bmp");
  5. ScalrConfig config = new ScalrConfig(104,105, 160,160);
  6. config.setAspectRatio(true);
  7. config.setQuality(1F);
  8. config.setType(ImageExtensionEnum.BMP);
  9. List<ThumbnailResult> results = thumbnailer.
  10. createThumbnails(toThumbnail, config);
  11. if(!results.isEmpty())
  12. {
  13. File destFile = new File("q:/target22222.bmp");
  14. ThumbnailResult result = results.get(0);
  15. result.writeToFile(destFile);
  16. }
  17. }
  18. }

你可能感兴趣的:(java)