最近做的java项目有涉及到生成图片的模块,考虑到资料多为英文,需要在stackoverflow和oracle API文档寻找。
特此记录,也许能帮到一样寻找api的人 。代码从项目中做了小修改,可以直接使用 Version: java 1.8 Editor: IntelliJ
步骤1 :初始化image和对应painter
//在最后保存图片前,建议用TYPE_INT_ARGB
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_ARGB);
public Graphics2D initPainter(BufferedImage image){
Graphics2D g2Painter = image.createGraphics();
//给painter带上反锯齿属性,否则生成图片会像被蚂蚁啃过
painter.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
painter.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
return g2Painter;
}
步骤2 :画用户头像 要求圆形带边框
int x = 40, y = 40, border = 1;
BufferImage avatarImage = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
Graphics2D avatarPainter = initPainter(avatarImage); //如步骤1
//切割头像区域为圆形
Ellipse2D.Double shape = new Ellipse2D.Double(border, border,
x - border * 2, y - border * 2);
avatarPainter.setClip(shape);
String imageUrl = ""; //要导入头像的url,自行替换
String backupUrl = ""; //默认头像url,用于找不到imageUrl时
BufferImage avatar;
try{
avatar = ImageIO.read(new URL(imageUrl);
catch(FileNotFoundException e){
avatar = ImageIO.read(new URL(backupUrl));
}
//画头像
avatarPainter.drawImage(avatar, border, border, x - border * 2, y - border * 2, null);
//画边框
Stroke s = new BasicStroke(1F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
avatarPainter.setStroke(s);
avatarPainter.setColor(Color.white);
avatarPainter.drawOval(border, border, x - border * 2, y - border * 2);
//释放图像处理资源
avatarPainter.dispose();
步骤3 :字体处理
// 字体处理工具类 以Pingfang HK为例,代码中有字符串常量,自行替换
public class FontUtil {
private static FontUtil instance = null;
private GraphicsEnvironment ge;
private String rootPath;
//获取实例,避免每次调用都新建
public static FontUtil getInstance(ServletRequest request){
if(instance != null){
instance.checkFonts();
return instance;
}
instance = new FontUtil(request);
return instance;
}
//初始化工具类
private FontUtil(ServletRequest request){
setGe(GraphicsEnvironment.getLocalGraphicsEnvironment());
setRootPath(UrlUtil.getRootPath(request));
registerFont(FONT_FILE_PINGFANG);
}
//注册字体
private void registerFont(String fontPath){
try{
String path = rootPath + fontPath;
ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(path)));
}catch (IOException | FontFormatException e){
e.printStackTrace();
}
}
//每次调用实例前检查一下是否漏字体
private void checkFonts(){
List fontNameList = Arrays.asList(ge.getAvailableFontFamilyNames());
//check Pingfang
if(!fontNameList.contains(FONT_NAME_PINGFANG)){
registerFont(FONT_FILE_PINGFANG);
}
}
//将px值转化为java的size 比例是4px = 3JavaSize
private int translatePx2Size(int pxSize){
return (int) Math.round(pxSize * 0.75);
}
//用于调用时生成Font
public Font getFontPingfang(int style, int size){
return new Font(FONT_NAME_PINGFANG, style, translatePx2Size(size));
}
public Font getFontPingfang(int size){
return new Font(FONT_NAME_PINGFANG, Font.PLAIN, translatePx2Size(size));
}
//获取字符串长度,按painter当前font计算
public int getWordWidth(Graphics2D g, String content){
FontMetrics metrics = g.getFontMetrics();
int width = 0;
for(int i = 0; i < content.length(); i++){
width += metrics.charWidth(content.charAt(i));
}
return width;
}
//限制超长字符串,超出部分由...代替 TEXT_OMIT = "..."
public String limitText(String primitive, Graphics2D g, int maxLength){
if(primitive.length() < 3){
return primitive;
}
int actualMaxWidth = maxLength - getWordWidth(g, TEXT_OMIT);
FontMetrics metrics = g.getFontMetrics();
int width = 0;
String str = "";
for(int i = 0; i < primitive.length(); i++){
width += metrics.charWidth(primitive.charAt(i));
if(width < actualMaxWidth){
str += primitive.charAt(i);
}else{
return str;
}
}
return str;
}
public GraphicsEnvironment getGe() {
return ge;
}
public void setGe(GraphicsEnvironment ge) {
this.ge = ge;
}
public String getRootPath() {
return rootPath;
}
public void setRootPath(String rootPath) {
this.rootPath = rootPath;
}
}
步骤4 :将待保存的图像 由ARGB 转化为 RGB
以避免生成图片 有一层红色 mask
public static BufferedImage convert2RGB(BufferedImage image){
int w = image.getWidth();
int h = image.getHeight();
BufferedImage productImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int[] rgb = image.getRGB(0, 0, w, h, null, 0, w);
productImage.setRGB(0, 0, w, h, rgb, 0, w);
return productImage;
}
步骤5 :保存图片
public static Boolean saveImage(BufferedImage productImage, String path){
try{
File outputFile = new File(path);
if(!outputFile.exists()){
outputFile.getParentFile().mkdirs();
Boolean isSuccess = outputFile.createNewFile();
if(!isSuccess){
return false;
}
}
Iterator iter = ImageIO.getImageWritersByFormatName(fileType);
ImageWriter writer = iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(quality);
writer.setOutput(ImageIO.createImageOutputStream(outputFile));
writer.write(null, new IIOImage(img ,null,null), iwp);
writer.dispose();
return true;
}catch (IOException e){
e.printStackTrace();
return false;
}
}