微信小程序码生成+水印(太阳码)

入参

import lombok.Data;
import org.apache.commons.lang3.StringUtils;

@Data
public class WxScanCodeParam {

    private String accessToken;

    private String scene;

    private String path;

    private String writeContent;

    private String fileName;

    private String filePath;

    public boolean isWrite() {
        if (StringUtils.isNotBlank(this.writeContent)) {
            return true;
        }
        return false;
    }

}

工具类

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 太阳码+水印处理
 *
 * @author 
 * @since 2024年03月11日
 */
@Slf4j
public class WxQrCodeImageUtil {

    public static void main(String[] args) throws Exception {
        String accessToken = getAccessToken("您的appid", "您的appsecret");
        System.out.println("accessToken:" + accessToken);
        WxScanCodeParam param = new WxScanCodeParam();
        param.setAccessToken(accessToken);
        param.setScene("a=b");
        param.setPath("pages/index");
        param.setWriteContent("测试:20240904");// 无需水印删除这一行
        param.setFilePath("D:/tests");
        param.setFileName(System.currentTimeMillis() + "");
        generatUnlimitSunCode(param);
    }

    public static String getAccessToken(String appid, String appsecret)
    {
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+appsecret+"";
        String accessToken = null;
        try
        {
            String response = HttpUtil.post(requestUrl,new HashMap<>());
            JSONObject json = JSONObject.parseObject(response);
            accessToken = String.valueOf(json.get("access_token"));
        }
        catch (Exception e)
        {
            log.error("getAccessToken error", e);
        }

        return accessToken;
    }


    /**
     * 生成无限制的小程序码
     * @param param
     * @return
     * @throws Exception
     */
    public static String generatUnlimitSunCode(WxScanCodeParam param) throws Exception
    {
        String token =param.getAccessToken();
        Map<String, String> params = new HashMap<>();
        params.put("scene", param.getScene());
        params.put("page", param.getPath());
        //默认430
        params.put("width", "430");
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+token);
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
        String body = JSON.toJSONString(params);
        StringEntity entity = new StringEntity(body);
        entity.setContentType("image/jpg");
        httpPost.setEntity(entity);
        HttpResponse response = httpClient.execute(httpPost);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_OK)
        {
            HttpEntity entity2 = response.getEntity();
            if(!entity2.getContentType().getValue().equals("image/jpeg"))
            {
                String result = EntityUtils.toString(entity2, "UTF-8");
                log.error("generate sun code error,http execute result:" + result);
                return null;
            }
        }
        else
        {
            log.error("generate sun code error,http execute result:" + statusCode);
        }

        InputStream inputStream = response.getEntity().getContent();

        //太阳码写标题
        String content=param.getWriteContent();
        if(StringUtils.isNotEmpty(content) && param.isWrite())
        {
           inputStream = addImageTitle(param.getWriteContent(), inputStream, 450, 450);
        }

        String name = param.getFileName()+".jpg";//文件名加后缀,跟上面对应


        int flag = saveImg(inputStream, param.getFilePath(), name);// 保存图片
        if (flag == 0)
        {
            throw new RuntimeException("保存图片[" + name + "]失败");
        }
        else
        {
            log.info("太阳码[{}]生成成功", name);
        }
        return param.getFilePath() + File.separatorChar + name;
    }



    public static int saveImg(InputStream inputStream, String filePath, String name) {
        int result = 0;
        FileOutputStream fos = null;
        try {
            byte[] buffer = new byte[1024];
            int len;
            fos = new FileOutputStream(new File(filePath, name));
            while ((len = inputStream.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            result = 1;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close(); // 关闭文件输出流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 创建一个水印图片
     *
     * @param imageWidth  图片的宽度 px
     * @param imageHeight 图片的高度 px
     * @return
     */
    public static BufferedImage createWatermarkImage(Integer imageWidth,
                                                     Integer imageHeight) {
        BufferedImage bufferedImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D = bufferedImage.createGraphics();

        graphics2D.setColor(Color.white);
        graphics2D.fillRect(1,1,imageWidth-1,imageHeight-1);
        graphics2D.setColor(Color.GRAY);
        graphics2D.drawRect(0,0,imageWidth-1,imageHeight-1);

        graphics2D.dispose();
        return bufferedImage;
    }


    public static InputStream addImageTitle(String title, InputStream inputStream, int width, int height) {
        try {
            // 将InputStream转换为BufferedImage
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            int addHeight = 60;
            height = height + addHeight;
            // 新建一个图层,大小为原图层的宽度和高度加上标题的高度
            BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            BufferedImage watermarkImage = createWatermarkImage(width, addHeight);

            // 在新图层上绘制原图层
            Graphics2D g2d = newImage.createGraphics();
            g2d.drawImage(bufferedImage, 0, 0, width, height-addHeight, null);

            // 设置字体样式
            int fontSize = 4;
            String fontName = "宋体";
            while (true){
                Font font = new Font(fontName, Font.BOLD, fontSize);
                int fontWight = g2d.getFontMetrics(font).stringWidth(title);
                if (fontSize >= 30) {
                    fontSize = 30;
                    break;
                }
                if (fontWight + (3 * fontSize) <  width) {
                    fontSize = fontSize + 2;
                } else {
                    if (fontSize != 4) {
                        fontSize = fontSize - 2;
                    }
                    break;
                }
            }
            Font font = new Font(fontName, Font.BOLD, fontSize);
            g2d.setFont(font);
            g2d.setColor(Color.BLACK);

            int heightDiff = height - fontSize;

            g2d.drawImage(watermarkImage, 0, height-addHeight, null);
            // 水印透明设置
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1F));
            int strWidth = getStrWidth(title, fontSize);
            drawString(g2d, font, title, width, (width-strWidth)/2,  heightDiff,0);
            // 释放资源
            g2d.dispose();

            // 将新图层转换为InputStream
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(newImage, "jpg", byteArrayOutputStream);
            byte[] byteArray = byteArrayOutputStream.toByteArray();

            return new ByteArrayInputStream(byteArray);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static boolean drawString(Graphics2D g, Font font, String text, int widthLength, int x, int y, int yn) {
        FontMetrics fg = g.getFontMetrics(font);
        List<String> ls = new ArrayList<>(2);
        getListText(fg, text, widthLength, ls);
        for (int i = 0; i < ls.size(); i++) {
            if (i == 0) {
                g.drawString(ls.get(i), x, y);
            } else {
                // 水平水印偏移
//          g.drawString(ls.get(i), x, (y + yn));
                // 倾斜水印 偏移
                g.drawString(ls.get(i), x+yn, (y + yn));
            }
        }
        if (ls.size() > 1) {
            return true;
        }
        return false;
    }

    public static void getListText(FontMetrics fg, String text, int widthLength, List<String> ls) {
        String ba = text;
        boolean b = true;
        int i = 1;
        while (b) {
            if (fg.stringWidth(text) > widthLength) {
                text = text.substring(0, text.length() - 1);
                i++;
            } else {
                b = false;
            }
        }
        if (i != 1) {
            ls.add(ba.substring(0, ba.length() - i));
            getListText(fg, ba.substring(ba.length() - i), widthLength, ls);
        } else {
            ls.add(text);
        }
    }

    /**
     * 获取字符串占用的宽度
     * <br>
     * @param str     字符串
     * @param fontSize 文字大小
     * @return 字符串占用的宽度
     */
    public static int getStrWidth(String str, int fontSize) {
        char[] chars = str.toCharArray();
        int fontSize2 = fontSize / 2;

        int width = 0;

        for (char c : chars) {
            int len = String.valueOf(c).getBytes().length;
            // 汉字为3,其余1
            // 可能还有一些特殊字符占用2等等,统统计为汉字
            if (len != 1) {
                width += fontSize;
            } else {
                width += fontSize2;
            }
        }

        return width;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值