对图像的缩放可以带来很多好处,比如在载入图像时可以有效减少各方面的压力。
这里依靠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.
19. public ScalrConfig(int size,int allowWidth,
20. int allowHeight){
21. this.size = size;
22. this.filter = new DefautlScalrFiter(allowWidth,allowHeight);
23. }
24.
25. public ScalrConfig(int width,int height,
26. int allowWidth,int allowHeight){
27. this.height = height;
28. this.width = width;
29. this.filter = new DefautlScalrFiter(allowWidth,allowHeight);
30. }
31.
32. class DefautlScalrFiter implements ScalrFilter{
33.
34. private int allowWidth;
35.
36. private int allowHeight;
37.
38. @Override
39. public boolean doFilter(int _width, int _height) {
40. return allowWidth < _width || allowHeight < _height;
41. }
42.
43. public DefautlScalrFiter(int allowWidth, int allowHeight) {
44. this.allowWidth = allowWidth;
45. this.allowHeight = allowHeight;
46. }
47. }
48. //省略setter、getter
ImageExtensionEnum
用来定义图片格式(GIF不支持。。。。)
1. public enum ImageExtensionEnum {
2.
3. JPG,JPEG,PNG,BMP,GIF;
4.
5. public final static String [] getExtensions(){
6. ImageExtensionEnum enums [] = ImageExtensionEnum.values();
7. String [] extensions = new String [enums.length];
8. for(int i=0;i<enums.length;i++)
9. extensions[i] = enums[i].name();
10. return extensions;
11. }
12.
13. public static boolean isJPG(String extension){
14. return JPEG.name().equalsIgnoreCase(extension) ||
15. JPG.name().equalsIgnoreCase(extension);
16. }
17.
18. public static boolean isSameType(String extension1,String extension2){
19. if(extension1 == null || extension2 == null) return false;
20. return (extension1.equalsIgnoreCase(extension2))||
21. (isJPG(extension1)&&isJPG(extension2))?true : false;
22. }
23. }
ScalrFilter
用来控制图片是否需要被压缩,如果图片过小,此时缩放是不明智的。
1. public interface ScalrFilter {
2.
3. public boolean doFilter(int _width,int _height);
4.
5. }
下面是图片压缩:
1. public interface Thumbnailer {
2.
3. /**
4. *
5. * @param is 图片文件流
6. * @param size 图片大小
7. * @param config 配置
8. * @param extension 图片后缀
9. * @return
10. * @throws Exception
11. */
12. List<ThumbnailResult> createThumbnails(File file,
13. ScalrConfig...configs) throws Exception;
14.
15. }
thumnailResult
是一个接口,用来控制缩放成文件、写入输出流、返回缩放后的图片类型和大小:
1. public interface ThumbnailResult {
2.
3. File writeToFile(File destFile) throws Exception;
4.
5. void writeToStream(OutputStream stream) throws Exception;
6.
7. int getWidth() throws Exception;
8.
9. int getHeight() throws Exception;
10.
11. String getExtension();
12.
13.
14. }
最后读取、判断文件:
1. public abstract class AbstractThumbaniler implements Thumbnailer{
2.
3. @Override
4. public List<ThumbnailResult> createThumbnails(File file,
5. ScalrConfig... configs) throws Exception {
6. if(configs == null || configs.length == 0)
7. {
8. throw new IllegalArgumentException("必须指定一个 ScalrConfig");
9. }
10. if (file == null)
11. {
12. throw new IllegalArgumentException("文件不能为空");
13. }
14. if (!file.exists())
15. {
16. throw new IllegalArgumentException(file.getAbsolutePath() + "不存在");
17. }
18. String oldExtension = MyStringUtils.getFilenameExtension(file.getName());
19. if(!isSupportedOutputFormat(oldExtension))
20. {
21. throw new IllegalArgumentException("文件不符合格式");
22. }
23. BufferedImage image = ImageIO.read(file);
24. if (image == null)
25. {
26. throw new IllegalArgumentException("文件不是一个真正的图片");
27. }
28. List<ThumbnailResult> results = new ArrayList<ThumbnailResult>();
29. for(ScalrConfig config : configs)
30. {
31. ScalrFilter filter = config.getFilter();
32. if(filter == null || (filter != null &&
33. filter.doFilter(image.getWidth(), image.getHeight())))
34. {
35. results.add(createThumbnail(image, config,oldExtension));
36. }
37. }
38. return results;
39. }
40.
41. abstract ThumbnailResult createThumbnail(BufferedImage image,
42. ScalrConfig config,String oldExtension) throws Exception;
43.
44. protected List<String> getSupportedOutputFormats(){
45.
46. String[] formats = ImageIO.getWriterFormatNames();
47. if (formats == null)
48. {
49. return Collections.emptyList();
50. }
51. else
52. {
53. return Arrays.asList(formats);
54. }
55. }
56.
57. private boolean isSupportedOutputFormat(String format){
58. for (String supportedFormat : getSupportedOutputFormats())
59. {
60. if (supportedFormat.equals(format))
61. {
62. return true;
63. }
64. }
65.
66. return false;
67. }
68.
69. }
首先是
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
官网上的例子:
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.
34. private final class ImgScalrThumbnailResult implements ThumbnailResult{
35.
36. private String extension ;
37.
38. private Float quality;
39.
40. private BufferedImage image;
41.
42. @Override
43. public File writeToFile(File destFile) throws Exception {
44. String filename = destFile.getName();
45. String targetExtension = MyStringUtils.getFilenameExtension(filename);
46. if(!ImageExtensionEnum.isSameType(extension, targetExtension))
47. {
48. destFile = new File(destFile.getParent(),
49. filename.concat(".").concat(extension));
50. }
51. ImageUtils.write(image, extension, quality, destFile);
52. return destFile;
53. }
54.
55. @Override
56. public void writeToStream(OutputStream stream) throws Exception {
57. ImageUtils.write(image, extension, quality, stream);
58. }
59.
60. @Override
61. public int getWidth() {
62. return image.getWidth();
63. }
64.
65. @Override
66. public int getHeight() {
67. return image.getHeight();
68. }
69.
70. @Override
71. public String getExtension(){
72. return extension;
73. }
74.
75. private ImgScalrThumbnailResult(String extension, Float quality,
76. BufferedImage image) {
77. this.extension = extension;
78. this.quality = quality;
79. this.image = image;
80. }
81.
82. }
83.
84.
85. }
ImageUtils用来讲BufferedImage输出到文件或者流,具体如下(来源于Thumbanailator的util):
1. public final class ImageUtils {
2.
3. public static void write(BufferedImage img , String formatName,
4. Float quality,File destFile) throws IOException{
5. Iterator<ImageWriter> writers =
6. ImageIO.getImageWritersByFormatName(formatName);
7. if (!writers.hasNext())
8. {
9. throw new UnsupportedFormatException(
10. formatName,
11. "No suitable ImageWriter found for " + formatName + "."
12. );
13. }
14. ImageWriter writer = writers.next();
15. ImageWriteParam writeParam = writer.getDefaultWriteParam();
16. if (writeParam.canWriteCompressed())
17. {
18. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
19. List<String> supportedFormats =
20. ThumbnailatorUtils.getSupportedOutputFormatTypes(formatName);
21.
22. if (!supportedFormats.isEmpty())
23. {
24. writeParam.setCompressionType(supportedFormats.get(0));
25. }
26. if(quality != null)
27. {
28. writeParam.setCompressionQuality(quality);
29. }
30. }
31. ImageOutputStream ios;
32. FileOutputStream fos;
33. fos = new FileOutputStream(destFile);
34. ios = ImageIO.createImageOutputStream(fos);
35. if (ios == null || fos == null)
36. {
37. throw new IOException("Could not open output file.");
38. }
39. if (
40. formatName.equalsIgnoreCase("jpg")
41. || formatName.equalsIgnoreCase("jpeg")
42. || formatName.equalsIgnoreCase("bmp")
43. )
44. {
45. int width = img.getWidth();
46. int height = img.getHeight();
47. BufferedImage newImage = new BufferedImage(width, height,
48. BufferedImage.TYPE_INT_RGB);
49. Graphics g = newImage.createGraphics();
50. g.drawImage(img, 0, 0, null);
51. g.dispose();
52. img = newImage;
53. }
54. writer.setOutput(ios);
55. writer.write(null, new IIOImage(img, null, null), writeParam);
56. writer.dispose();
57. ios.close();
58. fos.close();
59. }
60.
61. public static void write(BufferedImage img,String formatName,
62. Float quality,OutputStream os) throws IOException{
63. Iterator<ImageWriter> writers =
64. ImageIO.getImageWritersByFormatName(formatName);
65. if (!writers.hasNext())
66. {
67. throw new UnsupportedFormatException(
68. formatName,
69. "No suitable ImageWriter found for " + formatName + "."
70. );
71. }
72. ImageWriter writer = writers.next();
73. ImageWriteParam writeParam = writer.getDefaultWriteParam();
74. if (writeParam.canWriteCompressed())
75. {
76. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
77. List<String> supportedFormats =
78. ThumbnailatorUtils.getSupportedOutputFormatTypes(formatName);
79.
80. if (!supportedFormats.isEmpty())
81. {
82. writeParam.setCompressionType(supportedFormats.get(0));
83. }
84. if (quality != null)
85. {
86. writeParam.setCompressionQuality(quality);
87. }
88. }
89. ImageOutputStream ios = ImageIO.createImageOutputStream(os);
90. if (ios == null)
91. {
92. throw new IOException("Could not open OutputStream.");
93. }
94. if (
95. formatName.equalsIgnoreCase("jpg")
96. || formatName.equalsIgnoreCase("jpeg")
97. || formatName.equalsIgnoreCase("bmp")
98. )
99. {
100. int width = img.getWidth();
101. int height = img.getHeight();
102. BufferedImage newImage = new BufferedImage(width, height,
103. BufferedImage.TYPE_INT_RGB);
104. Graphics g = newImage.createGraphics();
105. g.drawImage(img, 0, 0, null);
106. g.dispose();
107. img = newImage;
108. }
109. writer.setOutput(ios);
110. writer.write(null, new IIOImage(img, null, null), writeParam);
111. writer.dispose();
112. ios.close();
113. }
114.
115. }
MyStringUitls主要用来获取文件后缀名:
1. public class MyStringUtils {
2.
3. private static final char EXTENSION_SEPARATOR = '.';
4.
5. private static final String FOLDER_SEPARATOR = "/";
6.
7. public static String getFilenameExtension(String path) {
8. if (path == null) {
9. return null;
10. }
11. int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
12. if (extIndex == -1) {
13. return null;
14. }
15. int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
16. if (folderIndex > extIndex) {
17. return null;
18. }
19. return path.substring(extIndex + 1);
20. }
21.
22. }
测试:
1. public class Test {
2.
3. public static void main(String [] args) throws Exception{
4. Thumbnailer thumbnailer = ThumbnailerFactory.getThumbnailer();
5. File toThumbnail = new File("q:/user.bmp");
6. ScalrConfig config = new ScalrConfig(104,105, 160,160);
7. config.setAspectRatio(true);
8. config.setQuality(1F);
9. config.setType(ImageExtensionEnum.BMP);
10. List<ThumbnailResult> results = thumbnailer.
11. createThumbnails(toThumbnail, config);
12. if(!results.isEmpty())
13. {
14. File destFile = new File("q:/target22222.bmp");
15. ThumbnailResult result = results.get(0);
16. result.writeToFile(destFile);
17. }
18. }
19.
20.
21. }