Java压缩图片
目的
压缩分为有损压缩和无损压缩。我做的是有损压缩。只是将图片比如5M大小压到100K以内甚至是50K。为了更加快速的展示图片。
要求
不要小看任何一个功能,可能看起来很简单,当做的的时候会遇到很多问题。
任务
(1)制作一个压缩的工具类。输入File file,输出File file 中间将图片缩小并按一定的规则命名并保存在同一级目录下。为了更加灵活还可以传入缩小后图片的宽高,还有不能将图片放大。传入文件是否是图片也要进行判断。
(2)将一服务器上所有图片都压缩一下,原图片保存,新图片以比如在原图片名称前面加thumbnail,就是thumbnail+file.getName.(实现方法可以在本地利用工具类写个main方法遍历某个文件夹下所有文件,是图片的就转一下。)
代码
工具类:ImgCompressUtil.java
public class ImgCompressUtil {
private static Image img;
private static int width;
private static int height;
public static void main(String[] args) throws Exception {
// File file = new File("E:\\c4f31814503ebfa49d3a5 - 副本 (1).PNG");
// File smallfile = ImgCompressUtil.imgComp(file, 0, 0);
//// file 原始图片文件 smallfile 压缩后的图片文件
// System.out.println(smallfile.getName());
}
/**
* <p>
* Title: isimg</p>
* <p>
* Description:// 通过ImageReader来解码这个file并返回一个BufferedImage对象 //
* 如果找不到合适的ImageReader则会返回null,我们可以认为这不是图片文件 // 或者在解析过程中报错,也返回false </p>
*
* @param file
* @return
* @author yuh
*/
public static boolean isimg(File file) {
try {
Image image = ImageIO.read(file);
img = ImageIO.read(file); // 构造Image对象
width = img.getWidth(null); // 得到源图宽
height = img.getHeight(null); // 得到源图长
return image != null;
} catch (Exception ex) {
return false;
}
}
/**
* 强制压缩/放大图片到固定的大小
*
* @param w int 新宽度
* @param h int 新高度
* @return
*/
@SuppressWarnings("restriction")
public static File resize(File file, int w, int h) throws IOException {
// SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
image.getGraphics().drawImage(img, 0, 0, w, h, null); // 绘制缩小后的图
File destFile = new File(file.getPath().substring(0, file.getPath().lastIndexOf(".")) + "_small"+file.getName().substring(file.getName().lastIndexOf(".")));
FileOutputStream out = new FileOutputStream(destFile); // 输出到文件流
// 可以正常实现bmp、png、gif转jpg
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image); // JPEG编码
out.close();
return destFile;
}
/**
*
* <p>
* Title: imgComp</p>
* <p>
* Description: 对图片进行压缩返回small图片,默认宽高可以传0,默认宽高为500</p>
*
* @param file File 原始图片
* @param w int 新宽度
* @param h int 新高度
* @return file File 缩略图 返回null,转换失败
* @author yuh
*/
public static File imgComp(File file, int w, int h) {
if (isimg(file)) {
if (w == 0) {
w = 300;
}
if (h == 0) {
h = 300;
}
System.out.println("开始:" + new Date().toString());
try {
if(width>=w && height>=h) {
if (width / height > w / h) {
h = (int) (height * w / width);
} else {
w = (int) (width * h / height);
}
}else {
w=width;
h=height;
}
System.out.println("结束:" + new Date().toString());
return resize(file, w, h);
} catch (Exception e) {
return null;
}
} else {
System.out.println("结束:文件格式有误");
return null;
}
}
}
中间遇到的问题
转换开始是没有问题的。我转过BMP、JPG、JPEG、PNG、GIF。
转换过程中遇到一个转不了的图片开始是PNG,后来改成上面任何格式图片都不行。转换是报错如下
Exception in thread "main" java.lang.IllegalArgumentException: Numbers of source Raster bands and source color space components do not match
at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:482)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.acceptPixels(JPEGImageReader.java:1268)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1236)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1039)
java - IllegalArgumentException:源栅格波段和源颜色空间组件的数量不匹配对于彩色图像异常
此图像阅读器试图对JPEG错误宽容,并且比标准Java JPEGImageReader稍微强大。但是,您的JPEG文件似乎有许多问题,因此无法100%读取:首先,图像中的ICC颜色配置文件有4个颜色组件,而图像数据只有3个颜色组件(这导致你见的例外)。根本原因可能是糟糕的转换软件。异常原因(没办法,这种图片用这转不了).
虽然不能转但还是要复制一份与原图一样但名字要匹配的,不能只转一部分。不然数据会很混乱。
将一个文件夹下所有图片都压缩一边代码
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.*;
/**
* <p>
* Title: ImgCompressUtil</p>
* <p>
* Description:图片压缩处理。 调用imgComp方法即可参数file,width,height。 width,height可默认为0。
* 例如File smallfile = ImgCompressUtil.imgComp(file, 0, 0);
* 如果原始宽高比比新宽高比大则以新宽等比缩放,否则以新高等比缩放。</p>
*
* @author yuh
* @date 2019年3月12日
*/
public class ImgCompressUtil {
private static Image img;
private static int width;
private static int height;
public static void main(String[] args) throws Exception {
getFileList("E:\\临时文件\\uploadimg");
// File fi = new File("E:\\临时文件\\bbb6d9.jpg");
// File file = new File("E:\\临时文件\\93f3bbb6d9.jpg");
// File smallfile = ImgCompressUtil.imgComp(file, 0, 0);
// file 原始图片文件 smallfile 压缩后的图片文件
// System.out.println(smallfile.getName());
}
/**
* <p>
* Title: isimg</p>
* <p>
* Description:// 通过ImageReader来解码这个file并返回一个BufferedImage对象 //
* 如果找不到合适的ImageReader则会返回null,我们可以认为这不是图片文件 // 或者在解析过程中报错,也返回false </p>
*
* @param file
* @return
* @author yuh
*/
public static boolean isimg(File file) {
try {
Image image = ImageIO.read(file);
img = ImageIO.read(file); // 构造Image对象
width = img.getWidth(null); // 得到源图宽
height = img.getHeight(null); // 得到源图长
return image != null;
} catch (IOException ex) {
return false;
}
}
/**
* 强制压缩/放大图片到固定的大小
*
* @param w int 新宽度
* @param h int 新高度
* @return
*/
@SuppressWarnings("restriction")
public static File resize(File file, int w, int h) throws IOException {
// SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
image.getGraphics().drawImage(img, 0, 0, w, h, null); // 绘制缩小后的图
File destFile = new File(file.getPath().substring(0, file.getPath().lastIndexOf(".")) + "_small"+file.getName().substring(file.getName().lastIndexOf(".")));
FileOutputStream out = new FileOutputStream(destFile); // 输出到文件流
// 可以正常实现bmp、png、gif转jpg
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image); // JPEG编码
out.close();
return destFile;
}
/**
*
* <p>
* Title: imgComp</p>
* <p>
* Description: 对图片进行压缩返回small图片,默认宽高可以传0,默认宽高为500</p>
*
* @param file File 原始图片
* @param w int 新宽度
* @param h int 新高度
* @return file File 缩略图
* @author yuh
*/
public static File imgComp(File file, int w, int h) {
if (isimg(file)) {
if (w == 0) {
w = 300;
}
if (h == 0) {
h = 300;
}
System.out.println("开始:" + new Date().toString());
try {
if(width>=w && height>=h) {
if (width / height > w / h) {
h = (int) (height * w / width);
} else {
w = (int) (width * h / height);
}
}else {
w=width;
h=height;
}
System.out.println("结束:" + new Date().toString());
return resize(file, w, h);
} catch (IOException e) {
e.printStackTrace();
return null;
}
} else {
System.out.println("结束:文件格式有误");
return null;
}
}
// BMP、JPG、JPEG、PNG、GIF
public static List<File> getFileList(String strPath) {
File dir = new File(strPath);
File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
// for (int i = 0; i < files.length; i++) {
// System.out.println(files[i].getPath());
// }
List<File> filelist = new ArrayList<File>();
if (files != null) {
boolean isEx = false;
for (int i = 0; i < files.length; i++) {
String fileName = files[i].getName();
if (files[i].isDirectory()) { // 判断是文件还是文件夹
getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
} else if (fileName.endsWith("BMP") || fileName.endsWith("JPG") || fileName.endsWith("JPEG")|| fileName.endsWith("PNG")|| fileName.endsWith("GIF") || fileName.endsWith("bmp") || fileName.endsWith("jpg") || fileName.endsWith("jpeg")|| fileName.endsWith("png")|| fileName.endsWith("gif")) { // 判断文件名是否以.avi结尾
try {
Image image = ImageIO.read(files[i]);
String strFileName = files[i].getAbsolutePath();
File smallfile = ImgCompressUtil.imgComp(files[i], 0, 0);
System.out.println("---" + strFileName);
filelist.add(files[i]);
} catch (Exception e) {
File destFile = new File(files[i].getPath().substring(0, files[i].getPath().lastIndexOf(".")) + "_small"+files[i].getName().substring(files[i].getName().lastIndexOf(".")));
try {
copyFile3( files[i].getPath(),destFile.getPath());
System.out.println("copysuccess");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
isEx = true;
continue;
}
} else {
continue;
}
}
}
return filelist;
}
/**
* 复制
* <p>Title: copyFile3</p>
* <p>Description: </p>
* @param srcPath
* @param destPath
* @throws IOException
* @author yuh
*/
public static void copyFile3(String srcPath, String destPath) throws IOException {
// 打开输入流
FileInputStream fis = new FileInputStream(srcPath);
// 打开输出流
FileOutputStream fos = new FileOutputStream(destPath);
// 读取和写入信息
int len = 0;
// 创建一个字节数组,当做缓冲区
byte[] b = new byte[1024];
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
// 关闭流 先开后关 后开先关
fos.close(); // 后开先关
fis.close(); // 先开后关
}
}
因为用到了com.sun.image.codec.jpeg.*;问题
编译可能会报缺少程序包com.sun.image.codec.jpeg缺少,
我当时使用命令编译的(复习一下)
XXX.java在某个目录中,Shift+Ctrl+鼠标右键,在此处打开命令窗口,
输入:javac XXX.java 进行编译。success就会生成class文件
输入:Java XXX.class 执行。
Java项目将
Maven项目
解决方法