Java Graphics2D 在图片上画(微信昵称)含有特殊符号(Emoji)的文字

其实这是个蛋疼的需求, 除了需要画文字之外还需要 把不同用户的二维码也要合成上去,交给前端来做的画 有可能会导致浏览器版本差点的手机会长时间白屏没有反应。现在只能交给后端API方式去请求。

进入正题:

我找了很久都没有找到很好的解决方案,只能取巧的解决一下(笨方法):

如果有其他方法希望大佬们留言告知告知!!!!!!谢谢(*^_^*)(*^_^*)(*^_^*)(*^_^*)

解决方案就是对文字进行判断是否含有Emoji表情符号,然后使用支持符号表情的字体去画,如果是中文的话就很好解决了 直接使用普通字体来画,所以说这是个很笨的方法,一个字符一个字符的去画。。。。。。。我都觉得笨  先用着把  哈哈哈啊哈

第一步:判断字符中是否含有特殊表情符号也就是(UniCode)

   /**
     * 检测是否有emoji字符
     * @param source
     * @return 一旦含有就抛出
     */
public static boolean containsEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return false;
        }

        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);

            // 文字
            if (!isEmojiCharacter(codePoint)) {
                return true;
            }
        }

        return false;
    }

    public static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) ||
                (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

第二步:使用上面的第二个方法(isEmojiCharacter)判断该字符是否是特殊符号(\uD83C\uDF40),

如果是特殊符号的话,加载支持符号的字体进行画即可(这里不是重点)

重点:在画特殊符号之前是需要转义的 不然画出来的还是会乱码 上代码

/**
     * unicode 转义输出 "\\ud3c4\\us3f4" 输出表情符号
     * @param ascii
     * @return
     */
    public static String ascii2native(String ascii) {
        List<String> ascii_s = new ArrayList<String>();

        String zhengz= "\\\\u[0-9,a-f,A-F]{4}";

        Pattern p = Pattern.compile(zhengz);

        Matcher m=p.matcher(ascii);

        while (m.find()){
            ascii_s.add(m.group());
        }
        System.out.println(ascii_s);
        for (int i = 0, j = 2; i < ascii_s.size(); i++) {
            String code = ascii_s.get(i).substring(j, j + 4);
            char ch = (char) Integer.parseInt(code, 16);

            ascii = ascii.replace(ascii_s.get(i),String.valueOf(ch));
        }

        return ascii;
    }

这个方法是这坑  如果没有这个转义的话使用字符进行循环 取每一个字符的char在转成String进行绘画的时候他会把

\uD83C中的D83c给转成String,转成String的时候需要把\\u加上,而且需要注意(\uD83C\uDF40)两个一起画才是一个特殊符号

还有一点就是如果把(\uD83C\uDF40)转义后在进行绘画的话也是会乱码的 原因也很简单 

String tv = "\uD83C\uDF40";

System.out.println(tv);
System.out.println(ascii2native("\\uD83C\\uDF40"));
System.out.println("\\uD83C\\uDF40");

--------------
输出:
?
?
\uD83C\uDF40

这样就很清楚了  

上完整一点的代码:

if (containsEmoji(tv)) {
            Font enmojiF = Font.createFont(Font.TRUETYPE_FONT, new ClassPathResource("seguiemj.ttf").getFile());
            Font emnoji = enmojiF.deriveFont(Font.PLAIN, 30);
            int chars = -1;
            int len = x;
            for (int i = 0; i < tv.length(); i++) {
                if (!isEmojiCharacter(tv.charAt(i))) {
                    if (chars == i) {
                        continue;
                    }
                    chars = i + 1;
                    ImageUtil.drawText(baseMapBufferedImage, emnoji, color, StringUtils.ascii2native("\\u" + Integer.toHexString((int) tv.charAt(i)) + "\\u" + Integer.toHexString((int) tv.charAt(i + 1))), len, y, null, false);
                    len += FontDesignMetrics.getMetrics(emnoji).charWidth(tv.charAt(i)) * 2;
                }
                else {
                    ImageUtil.drawText(baseMapBufferedImage, font, color, String.valueOf(tv.charAt(i)), len, y, null, false);
                    len += FontDesignMetrics.getMetrics(font).stringWidth(String.valueOf(tv.charAt(i))) - 5;
                }

            }
        }
        else {
            ImageUtil.drawText(baseMapBufferedImage, font, color, tv, x, y, null, false);
        }

到这里就可以解决 这是个很笨的方法,后来发现一种方法 使用下面的字体可以解决符号文字一起绘画,但是在linux服务器上面会乱码原因也很简单 liinux上面没有这种字体 我本地测试是window  在window服务器上应该是没有上面问题

 Font font = new Font("Menlo", Font.BOLD, 30)

到此结束啦 !!!!! 有更好的方法欢迎留言!!!!!!!!!!!!!!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值