Java BufferImage 从初始化到保存

最近做的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;
        }
}

 

你可能感兴趣的:(Java)