图片压缩(等比压缩、按高压缩、按宽压缩)和加水印(图片水印、文字水印)
每天学习一点,就进步一点,多积累一点,成长就快一点。
今天突然想起了做Java的图片压缩和加水印,以后可能会用的着,所以就研究了,当然也百度一下,有很多,所以我总结一下吧!废话不多说了,直接上代码:
package com.cwm.test.model;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* 压缩图片并加水印
* @author chenwangming
*
*/
public class ImageHelper {
private String srcFile;//源图片地址
private String destFile;//目标图片地址
private int width;//图片宽度
private int height;//图片高度
private Image img;//图片
public String getSrcFile() {
return srcFile;
}
public void setSrcFile(String srcFile) {
this.srcFile = srcFile;
}
public String getDestFile() {
return destFile;
}
public void setDestFile(String destFile) {
this.destFile = destFile;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public Image getImg() {
return img;
}
public void setImg(Image img) {
this.img = img;
}
/**
* 构造函数
* @param srcFile
* @param destFile
* @throws IOException
*/
public ImageHelper(String srcFile,String destFile) throws IOException
{
this.srcFile=srcFile;
this.destFile=destFile;
img = ImageIO.read(new File(srcFile));
width=img.getWidth(null);
height=img.getHeight(null);
}
/**
* 压缩/放大图片到固定的大小
* @param newWidth
* @param newHeight
* @throws ImageFormatException
* @throws IOException
*/
public void resize(int newWidth,int newHeight) throws ImageFormatException, IOException
{
Image img=Toolkit.getDefaultToolkit().getImage(srcFile);
BufferedImage bfi=toBufferedImage(img,newWidth,newHeight);
//第一种通过文件流和JPEGImageEncoder近JPEg编码输出
FileOutputStream newImageOPS = new FileOutputStream(destFile);//输出文件流
/*
* JPEGImageEncoder 将图像缓冲数据编码为 JPEG 数据流。该接口的用户应在 Raster
* 或 BufferedImage 中提供图像数据,在 JPEGEncodeParams 对象中设置必要的参数,
* 并成功地打开 OutputStream(编码 JPEG 流的目的流)。JPEGImageEncoder 接口可
* 将图像数据编码为互换的缩略 JPEG 数据流,该数据流将写入提供给编码器的 OutputStream 中。
注意:com.sun.image.codec.jpeg 包中的类并不属于核心 Java API。它们属于 Sun 发布的
JDK 和 JRE 产品的组成部分。虽然其它获得许可方可能选择发布这些类,但开发人员不能寄
希望于从非 Sun 实现的软件中得到它们。我们期望相同的功能最终可以在核心 API 或标准扩
展中得到。
*/
com.sun.image.codec.jpeg.JPEGImageEncoder encoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(newImageOPS);
encoder.encode(bfi);//近JPEG编码
newImageOPS.close();
//第二种通过图片流写入
//ImageIO.write(bfi, "JPEG", new File(destFile));
}
/**
* 生成图片缓存区
* @param image
* @param width
* @param height
* @return
*/
public static BufferedImage toBufferedImage(Image image,int width,int height) {
if (image instanceof BufferedImage) {
return (BufferedImage)image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent Pixels
//boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
/* if (hasAlpha) {
transparency = Transparency.BITMASK;
}*/
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(width, height, transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
//int type = BufferedImage.TYPE_3BYTE_BGR;//by wang
/*if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}*/
bimage = new BufferedImage(width, height, type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0,width,height, null);绘制缩小的图
g.dispose();
return bimage;
}
/**
* 按照固定的比例缩放图片
* @param t
* @throws IOException
*/
public void resize(double t) throws IOException{
int w = (int)(width*t);
int h = (int)(height*t);
resize(w,h);
}
/**
* 已宽度为基准,等比例缩放图片
* @param newWidth
* @throws IOException
*/
public void resizeByWidth(int newWidth) throws IOException{
int h = (int)(height*(new Double(newWidth)/width));
resize(newWidth,h);
}
/**
* 以高度为基准,等比例缩放图片
* @param newHeight
* @throws IOException
*/
public void resizeByHeight(int newHeight) throws IOException{
int w = (int)(width*(new Double(newHeight)/height));
resize(w,newHeight);
}
/**
* 生成规格
* @throws IOException
*/
public void resizeFix(int newWidth,int newHeight) throws IOException{
if(width>height || (width/height>newWidth/newHeight)){
resizeByWidth(newWidth);
}else{
resizeByHeight(newHeight);
}
}
/**
* 添加图片水印
* @param targetImg 目标图片路径,如:D:/eclipsetest/old/1.jpg
* @param waterImg 水印图片路径,如:D:/eclipsetest/old/水印图片.png
* @param x 水印图片距离目标图片左侧的偏移量,如果x<0, 则在正中间
* @param y 水印图片距离目标图片上侧的偏移量,如果y<0, 则在正中间
* @param alpha 透明度(0.0 -- 1.0, 0.0为完全透明,1.0为完全不透明)
* @throws Exception
*/
public static void pressImage(String targetImg,String waterImg,int x,int y,float alpha) throws Exception{
try {
File file = new File(targetImg);
Image image = ImageIO.read(file);
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(image, 0, 0, null);
Image waterImage = ImageIO.read(new File(waterImg));//水印文件
int width_wi=waterImage.getWidth(null);
int height_wi=waterImage.getHeight(null);
if(width<=width_wi || height<=height_wi){
throw new Exception("原图的宽、高必须大于水印图的宽、高");
}
AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha);
int widthDiff = width-width_wi;
int heightDiff = height-height_wi;
if(x<0){
x = widthDiff/2;
}else if(x>widthDiff){
x = widthDiff;
}
if(y<0){
y = heightDiff/2;
}else if(y>heightDiff){
y = heightDiff;
}
g.drawImage(waterImage, x, y, width_wi,height_wi,null);//水印文件结束
g.dispose();
ImageIO.write(bufferedImage, "JPEG", file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 添加文字水印
* @param targetImg 目标图片路径,如:D:/eclipsetest/old/1.jpg
* @param pressText 水印文字, 如:中国证券网
* @param fontName 字体名称, 如:宋体
* @param fontStyle 字体样式,如:粗体和斜体(Font.BOLD|Font.ITALIC)
* @param fontSize 字体大小,单位为像素
* @param color 字体颜色
* @param x 水印文字距离目标图片左侧的偏移量,如果x<0, 则在正中间
* @param y 水印文字距离目标图片上侧的偏移量,如果y<0, 则在正中间
* @param alpha 透明度(0.0 -- 1.0, 0.0为完全透明,1.0为完全不透明)
*/
public static void pressText(String targetImg,String pressText,String fontName,int fontStyle,int fontSize,Color color,int x,int y,float alpha){
try {
File file = new File(targetImg);
Image image = ImageIO.read(file);
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(image,0,0, width, height, null);
g.setFont(new Font(fontName, fontStyle, fontSize));
g.setColor(color);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
int width_wi = fontSize*getTextLength(pressText);
int height_wi = fontSize;
int widthDiff = width-width_wi;
int heightDiff = height-height_wi;
if(x<0){
x = widthDiff/2;
}else if(x>widthDiff){
x=widthDiff;
}
if(y<0){
y = heightDiff/2;
}else if(y>heightDiff){
y = heightDiff;
}
g.drawString(pressText, x, y+height_wi);//水印文件
g.dispose();
ImageIO.write(bufferedImage, "JPEG", file);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 计算文字像素长度
* @param text
* @return
*/
private static int getTextLength(String text){
int textLength = text.length();
int length = textLength;
for (int i = 0; i < textLength; i++) {
int wordLength = String.valueOf(text.charAt(i)).getBytes().length;
if(wordLength > 1){
length+=(wordLength-1);
}
}
return length%2==0 ? length/2:length/2+1;
}
/**
* 旋转任意度数的方法
* @param targetImg
* @param degree
* @param bgcolor
* @throws IOException
*/
public static void rotateImage(String targetImg, int degree, Color bgcolor) throws IOException {
File file = new File(targetImg);
BufferedImage sourceImage = ImageIO.read(file);
int iw = sourceImage.getWidth();//原始图象的宽度
int ih = sourceImage.getHeight();//原始图象的高度
int w = 0;
int h = 0;
int x = 0;
int y = 0;
degree = degree % 360;
if (degree < 0)
degree = 360 + degree;//将角度转换到0-360度之间
double ang = Math.toRadians(degree);//将角度转为弧度
/**
*确定旋转后的图象的高度和宽度
*/
if (degree == 180 || degree == 0 || degree == 360) {
w = iw;
h = ih;
} else if (degree == 90 || degree == 270) {
w = ih;
h = iw;
} else {
int d = iw + ih;
w = (int) (d * Math.abs(Math.cos(ang)));
h = (int) (d * Math.abs(Math.sin(ang)));
}
x = (w / 2) - (iw / 2);//确定原点坐标
y = (h / 2) - (ih / 2);
BufferedImage rotatedImage = new BufferedImage(w, h, sourceImage.getType());
Graphics2D gs = (Graphics2D)rotatedImage.getGraphics();
if(bgcolor==null){
rotatedImage = gs.getDeviceConfiguration().createCompatibleImage(w, h, Transparency.TRANSLUCENT);
}else{
gs.setColor(bgcolor);
gs.fillRect(0, 0, w, h);//以给定颜色绘制旋转后图片的背景
}
//有两种旋转使用方式,第一使用AffineTransformOp,第二使用Graphics2D
/*
* AffineTransform at = new AffineTransform();
at.rotate(ang, w / 2, h / 2);//旋转图象
at.translate(x, y);
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
op.filter(sourceImage, rotatedImage);
sourceImage = rotatedImage;
ImageIO.write(sourceImage, "PNG", file);//这里的格式化请使用PNG格式,否则旋转后会出现红眼效果
*/
BufferedImage bufferedImage = new BufferedImage(w, h, sourceImage.getType());
Graphics2D g = bufferedImage.createGraphics();
if(bgcolor==null){
g.setColor(Color.WHITE);
}else{
g.setColor(bgcolor);
}
g.fillRect(0, 0, w, h);//以给定颜色绘制旋转后图片的背景
g.rotate(Math.toRadians(degree), w/2, h/2);
g.translate(x, y);
g.drawImage(sourceImage, 0, 0, null);
g.dispose();
ImageIO.write(bufferedImage, "JPEG", file);//这里的JPEG也可以是PNG
}
/**
* 采用指定宽度、高度或压缩比例 的方式对图片进行压缩
* @param imgsrc 源图片地址
* @param imgdist 目标图片地址
* @param widthdist 压缩后图片宽度(当rate==null时,必传)
* @param heightdist 压缩后图片高度(当rate==null时,必传)
* @param rate 压缩比例
*/
public static void reduceImg(String imgsrc, String imgdist, int widthdist,
int heightdist, Float rate) {
try {
File srcfile = new File(imgsrc);
// 检查文件是否存在
if (!srcfile.exists()) {
return;
}
// 如果rate不为空说明是按比例压缩
if (rate != null && rate > 0) {
// 获取文件高度和宽度
int[] results = getImgWidth(srcfile);
if (results == null || results[0] == 0 || results[1] == 0) {
return;
} else {
widthdist = (int) (results[0] * rate);
heightdist = (int) (results[1] * rate);
}
}
// 开始读取文件并进行压缩
Image src = javax.imageio.ImageIO.read(srcfile);
BufferedImage tag = new BufferedImage((int) widthdist,
(int) heightdist, BufferedImage.TYPE_INT_RGB);
tag.getGraphics().drawImage(
src.getScaledInstance(widthdist, heightdist,
Image.SCALE_SMOOTH), 0, 0, null);
FileOutputStream out = new FileOutputStream(imgdist);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(tag);
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
/** 获取图片宽度
*
* @param file
* 图片文件
* @return 宽度
*/
public static int[] getImgWidth(File file) {
InputStream is = null;
BufferedImage src = null;
int result[] = { 0, 0 };
try {
is = new FileInputStream(file);
src = javax.imageio.ImageIO.read(is);
result[0] = src.getWidth(null); // 得到源图宽
result[1] = src.getHeight(null); // 得到源图高
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
代码是不是太多的呢? 没事,我这封装成一个类了,直接拷贝就好,不谢
来看看生成后的效果吧!
- 原图
- 运行示例1
try {
ImageHelper imge=new ImageHelper("D:/eclipsetest/old/1.jpg","D:/eclipsetest/old/11.jpg");
ImageHelper imge=new ImageHelper("D:/eclipsetest/old/水印图片.png","D:/eclipsetest/old/00.png");
imge.resizeFix(100, 100);
System.out.println("压缩成功!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
压缩后的图片
- 运行示例2
try {
ImageHelper.pressImage("D:/eclipsetest/old/2.jpg", "D:/eclipsetest/old/00.png", 150, 250, 0.5f);
System.out.println("水印图片成功!");
} catch (java.lang.Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
加水印的图片
- 运行示例3
ImageHelper.pressText("D:/eclipsetest/old/3.jpg", "阿明", "黑体", Font.BOLD, 20, Color.blue, 150, 250, 0.5f);
System.out.println("水印文字成功!");
加文字水印的图片
- 运行示例4
try {
ImageHelper.rotateImage("D:/eclipsetest/old/5.jpg", 70,Color.blue);
System.out.println("旋转成功!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
旋转后的图片
- 运行示例5
ImageHelper.reduceImg("D:/eclipsetest/old/1.jpg", "d:/eclipsetest/old/32.jpg", 100, 100,0.3f);
System.out.println("压缩图片成功!");
压缩后的图片
经历过黑暗,才有对光明的渴望;经历过风雨,才懂得阳光的温暖;经历过沧桑,才拥有温柔的内心;经历人生最好的成长。
共同学习,共同进步,技术交流群:210470210