当前位置: 代码网 > it编程>编程语言>Java > Java后端头像合成到背景图上面代码实践

Java后端头像合成到背景图上面代码实践

2026年01月07日 Java 我要评论
最近在做一个需求;本来头像悬浮到背景图上的功能是由前端来做的,但是自己闲来没事,然后自己用java后端写了一个工具类,供以后使用,在这里写帖子分享出来,有需要的可以借用!仅供参考!一、第一张头像合成到

最近在做一个需求;本来头像悬浮到背景图上的功能是由前端来做的,但是自己闲来没事,然后自己用java后端写了一个工具类,供以后使用,在这里写帖子分享出来,有需要的可以借用!仅供参考!

一、第一张头像合成到背景图固定的位置上

需要用户头像合成到固定位置的背景图上,然后昵称悬浮在头像下面;最后返回一个图片的地址

我们先在项目本地目录新建一个文件夹,存放背景图和头像图片,如图所示;

首先我们需要定义几个固定的参数(实际项目中参数从以上请求返回值中获取);

string bgfilename = "backgroud.png"; //背景图文件名
string avatarfilename = "autohotkey.svg"; //头像文件名
string nickname = "郑州小一"; //头像文件名

string outputfilename = "telegramphoto"; //输出文件名

// 本地文件存储路径 - 使用windows兼容的绝对路径格式
string basepath = "d:\\ideaprojects\\mahjong_java\\gameserver\\src\\core\\file\\";

// 确保路径格式正确
if (!basepath.endswith("\\")) {
    basepath += "\\";
}

然后我们调用图片合成方法传参:

//调用图像合成方法;接收合成后的图片完整路径
string  imgurl = compositeimages.compositeimage(basepath,bgfilename,avatarfilename,nickname)

然后我们在赋值给接口返回参数即可;

以下是图片合成类的全部代码:

/**
 * 合成图片工具类:将头像合成到背景图上
 * @return 合成后的图片完整路径,失败返回null
 */
public class compositeimages{

    /**
     * 合成图片方法:将头像合成到背景图上
     * @param bgfilename 背景图文件名(不含路径)
     * @param avatarfilename 头像文件名(不含路径)
     * @param outputfilename 输出文件名(不含路径)
     * @return 合成后的图片完整路径,失败返回null
     */
    public static string compositeimage(string basepath, string bgfilename, string avatarfilename, string nickname,string outputfilename) {
        // 构建完整的文件路径
        string bgimagepath = basepath + bgfilename;
        string avatarimagepath = basepath + avatarfilename;
        string tempoutputpath = basepath + "composite\\" + outputfilename + "_temp.png";
        string outputpath = basepath + "composite\\" + outputfilename;

        // 添加详细日志以调试路径问题
        commlogd.info("尝试访问背景图片路径: " + bgimagepath);
        file bgfile = new file(bgimagepath);
        commlogd.info("背景图片文件存在: " + bgfile.exists() + ", 是文件: " + bgfile.isfile() + ", 可读: " + bgfile.canread());

        // 验证输入图片是否存在
        if (!imageutils.isimagevalid(bgimagepath)) {
            commlogd.error("背景图片不存在或无效: " + bgimagepath);
            return null;
        }

        commlogd.info("尝试访问头像图片路径: " + avatarimagepath);
        file avatarfile = new file(avatarimagepath);
        commlogd.info("头像图片文件存在: " + avatarfile.exists() + ", 是文件: " + avatarfile.isfile() + ", 可读: " + avatarfile.canread());

        if (!imageutils.isimagevalid(avatarimagepath)) {
            commlogd.error("头像图片不存在或无效: " + avatarimagepath);
            return null;
        }
        int avatarx = 22; //头像x坐标
        int avatary = 240; //头像y坐标
        int avatarwidth = 100; //头像宽度
        int avatarheight = 100; //头像高度
        // 执行头像合成到临时文件
        boolean success = imageutils.compositeavatar(
                bgimagepath,
                avatarimagepath,
                tempoutputpath,
                avatarx,
                avatary,
                avatarwidth,
                avatarheight,
                "png" // 固定输出为png格式,支持透明
        );

        if (!success) {
            commlogd.error("头像合成失败");
            // 清理临时文件
            file tempfile = new file(tempoutputpath);
            if (tempfile.exists()) {
                tempfile.delete();
            }
            return null;
        }

        // 如果提供了昵称,则绘制昵称
        if (nickname != null && !nickname.isempty()) {
            // 计算昵称绘制位置(头像下方居中)
            int textx = avatarx; // 稍微偏移一点
            int texty = avatary + avatarheight + 26; // 头像下方,加上字体大小
            int fontsize = 24;
            java.awt.color fontcolor = new java.awt.color(255, 255, 255); // 白色文字

            // 绘制昵称
            success = imageutils.drawtextonimage(
                    tempoutputpath,
                    outputpath,
                    nickname,
                    textx,
                    texty,
                    fontsize,
                    fontcolor,
                    "png"
            );

            // 清理临时文件
            file tempfile = new file(tempoutputpath);
            if (tempfile.exists()) {
                tempfile.delete();
            }
        } else {
            // 如果没有昵称,直接将临时文件重命名为输出文件
            file tempfile = new file(tempoutputpath);
            file outputfile = new file(outputpath);
            // 确保输出目录存在
            file parentdir = outputfile.getparentfile();
            if (parentdir != null && !parentdir.exists()) {
                parentdir.mkdirs();
            }
            // 先删除可能存在的输出文件
            if (outputfile.exists()) {
                outputfile.delete();
            }
            success = tempfile.renameto(outputfile);
        }

        if (success) {
            commlogd.info("图片合成成功: " + outputpath);
            return outputpath;
        } else {
            commlogd.error("图片合成失败");
            return null;
        }
    }

    /**
     * 将两个头像合成到背景图上的方法,并在头像下方添加昵称
     * @param bgfilename 背景图文件名(不含路径)
     * @param avatar1filename 第一个头像文件名(不含路径)
     * @param nickname1 第一个头像对应的用户昵称
     * @param avatar2filename 第二个头像文件名(不含路径)
     * @param nickname2 第二个头像对应的用户昵称
     * @param outputfilename 输出文件名(不含路径)
     * @return 合成后的图片完整路径,失败返回null
     */
    public static string compositeimage2(string basepath, string bgfilename, string avatar1filename,  string nickname1, string avatar2filename, string nickname2,
                                         string outputfilename) {


        // 构建完整的文件路径
        string bgimagepath = basepath + bgfilename;
        string avatar1imagepath = basepath + avatar1filename;
        string avatar2imagepath = basepath + avatar2filename;
        string tempoutputpath1 = basepath + "composite\\" + outputfilename + "_temp1.png";
        string tempoutputpath2 = basepath + "composite\\" + outputfilename + "_temp2.png";
        string outputpath = basepath + "composite\\" + outputfilename;

        // 添加详细日志以调试路径问题
        commlogd.info("尝试访问背景图片路径: " + bgimagepath);
        file bgfile = new file(bgimagepath);
        commlogd.info("背景图片文件存在: " + bgfile.exists() + ", 是文件: " + bgfile.isfile() + ", 可读: " + bgfile.canread());

        // 验证输入图片是否存在
        if (!imageutils.isimagevalid(bgimagepath)) {
            commlogd.error("背景图片不存在或无效: " + bgimagepath);
            return null;
        }

        // 验证第一个头像
        commlogd.info("尝试访问第一个头像图片路径: " + avatar1imagepath);
        file avatar1file = new file(avatar1imagepath);
        commlogd.info("第一个头像图片文件存在: " + avatar1file.exists() + ", 是文件: " + avatar1file.isfile() + ", 可读: " + avatar1file.canread());

        if (!imageutils.isimagevalid(avatar1imagepath)) {
            commlogd.error("第一个头像图片不存在或无效: " + avatar1imagepath);
            return null;
        }

        // 验证第二个头像
        commlogd.info("尝试访问第二个头像图片路径: " + avatar2imagepath);
        file avatar2file = new file(avatar2imagepath);
        commlogd.info("第二个头像图片文件存在: " + avatar2file.exists() + ", 是文件: " + avatar2file.isfile() + ", 可读: " + avatar2file.canread());

        if (!imageutils.isimagevalid(avatar2imagepath)) {
            commlogd.error("第二个头像图片不存在或无效: " + avatar2imagepath);
            return null;
        }
        int avatar1x = 22; //头像x坐标
        int avatar1y = 240; //头像y坐标
        int avatar1width = 100; //头像宽度
        int avatar1height = 100; //头像高度
        // 先合成第一个头像到背景图,保存为临时文件
        boolean successfirst = imageutils.compositeavatar(
                bgimagepath,
                avatar1imagepath,
                tempoutputpath1,
                avatar1x,
                avatar1y,
                avatar1width,
                avatar1height,
                "png" // 固定输出为png格式,支持透明
        );

        if (!successfirst) {
            commlogd.error("合成第一个头像失败");
            return null;
        }
        int avatar2x = 600; //头像x坐标
        int avatar2y = 240; //头像y坐标
        int avatar2width = 100; //头像宽度
        int avatar2height = 100; //头像高度
        // 再将第二个头像合成到临时文件上,得到最终结果
        boolean successsecond = imageutils.compositeavatar(
                tempoutputpath1,
                avatar2imagepath,
                tempoutputpath2,
                avatar2x,
                avatar2y,
                avatar2width,
                avatar2height,
                "png"
        );

        // 删除第一个临时文件
        file tempfile1 = new file(tempoutputpath1);
        if (tempfile1.exists()) {
            tempfile1.delete();
        }

        if (!successsecond) {
            commlogd.info("两个头像合成成功: " + outputpath);
            // 删除第二个临时文件
            file tempfile2 = new file(tempoutputpath2);
            if (tempfile2.exists()) {
                tempfile2.delete();
            }
            return null;
        }

        // 确保输出目录存在
        file outputfile = new file(outputpath);
        file parentdir = outputfile.getparentfile();
        if (parentdir != null && !parentdir.exists()) {
            parentdir.mkdirs();
        }

        // 绘制昵称到图片上
        boolean successdrawtext = true;
        string currentpath = tempoutputpath2;
        int fontsize = 24;
        java.awt.color fontcolor = new java.awt.color(255, 255, 255); // 白色文字

        // 绘制第一个昵称(如果有)
        if (nickname1 != null && !nickname1.isempty()) {
            int text1x = avatar1x; // 稍微偏移一点
            int text1y = avatar1y + avatar1height + 26; // 头像下方,加上字体大小

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    outputpath,
                    nickname1,
                    text1x,
                    text1y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第一个昵称失败");
                // 删除临时文件
                file tempfile2 = new file(tempoutputpath2);
                if (tempfile2.exists()) {
                    tempfile2.delete();
                }
                return null;
            }
            currentpath = outputpath;
        }

        // 绘制第二个昵称(如果有)
        if (nickname2 != null && !nickname2.isempty()) {
            int text2x = avatar2x; // 稍微偏移一点
            int text2y = avatar2y + avatar2height + 26; // 头像下方,加上字体大小

            string nextpath = (currentpath.equals(tempoutputpath2)) ? outputpath : outputpath + "_final.png";

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname2,
                    text2x,
                    text2y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第二个昵称失败");
                // 清理文件
                file tempfile2 = new file(tempoutputpath2);
                if (tempfile2.exists()) {
                    tempfile2.delete();
                }
                if (currentpath.equals(outputpath)) {
                    file outputfileobj = new file(outputpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }

            // 如果创建了最终文件,需要重命名
            if (nextpath.equals(outputpath + "_final.png")) {
                file finalfile = new file(nextpath);
                file targetfile = new file(outputpath);
                if (targetfile.exists()) {
                    targetfile.delete();
                }
                finalfile.renameto(targetfile);
            }
        } else if (currentpath.equals(tempoutputpath2)) {
            // 如果没有第二个昵称,直接将临时文件重命名为输出文件
            file tempfile2 = new file(tempoutputpath2);
            if (outputfile.exists()) {
                outputfile.delete();
            }
            tempfile2.renameto(outputfile);
        }

        // 删除可能存在的临时文件
        file tempfile2 = new file(tempoutputpath2);
        if (tempfile2.exists()) {
            tempfile2.delete();
        }

        commlogd.info("两个头像和昵称合成成功: " + outputpath);
        return outputpath;
    }

    /**
     * 将三个头像合成到背景图上的方法
     * @param basepath 基础路径
     * @param bgfilename 背景图文件名(不含路径)
     * @param avatar1filename 第一个头像文件名(不含路径)
     * @param nickname1 第一个头像对应的用户昵称
     * @param avatar2filename 第二个头像文件名(不含路径)
     * @param nickname2 第二个头像对应的用户昵称
     * @param avatar3filename 第三个头像文件名(不含路径)
     * @param nickname3 第三个头像对应的用户昵称
     * @param outputfilename 输出文件名(不含路径)
     * @return 合成后的图片完整路径,失败返回null
     */
    public static string compositeimage3(string basepath, string bgfilename, string avatar1filename,string nickname1,
                                         string avatar2filename,string nickname2, string avatar3filename,string nickname3, string outputfilename) {
        // 构建完整的文件路径
        string bgimagepath = basepath + bgfilename;
        string avatar1imagepath = basepath + avatar1filename;
        string avatar2imagepath = basepath + avatar2filename;
        string avatar3imagepath = basepath + avatar3filename;
        string tempoutputpath1 = basepath + "composite\\" + outputfilename + "_temp1.png";
        string tempoutputpath2 = basepath + "composite\\" + outputfilename + "_temp2.png";
        string tempoutputpath3 = basepath + "composite\\" + outputfilename + "_temp3.png";
        string outputpath = basepath + "composite\\" + outputfilename;

        // 添加详细日志以调试路径问题
        commlogd.info("尝试访问背景图片路径: " + bgimagepath);
        file bgfile = new file(bgimagepath);
        commlogd.info("背景图片文件存在: " + bgfile.exists() + ", 是文件: " + bgfile.isfile() + ", 可读: " + bgfile.canread());

        // 验证输入图片是否存在
        if (!imageutils.isimagevalid(bgimagepath)) {
            commlogd.error("背景图片不存在或无效: " + bgimagepath);
            return null;
        }

        // 验证第一个头像
        commlogd.info("尝试访问第一个头像图片路径: " + avatar1imagepath);
        file avatar1file = new file(avatar1imagepath);
        commlogd.info("第一个头像图片文件存在: " + avatar1file.exists() + ", 是文件: " + avatar1file.isfile() + ", 可读: " + avatar1file.canread());

        if (!imageutils.isimagevalid(avatar1imagepath)) {
            commlogd.error("第一个头像图片不存在或无效: " + avatar1imagepath);
            return null;
        }

        // 验证第二个头像
        commlogd.info("尝试访问第二个头像图片路径: " + avatar2imagepath);
        file avatar2file = new file(avatar2imagepath);
        commlogd.info("第二个头像图片文件存在: " + avatar2file.exists() + ", 是文件: " + avatar2file.isfile() + ", 可读: " + avatar2file.canread());

        if (!imageutils.isimagevalid(avatar2imagepath)) {
            commlogd.error("第二个头像图片不存在或无效: " + avatar2imagepath);
            return null;
        }

        // 验证第三个头像
        commlogd.info("尝试访问第三个头像图片路径: " + avatar3imagepath);
        file avatar3file = new file(avatar3imagepath);
        commlogd.info("第三个头像图片文件存在: " + avatar3file.exists() + ", 是文件: " + avatar3file.isfile() + ", 可读: " + avatar3file.canread());

        if (!imageutils.isimagevalid(avatar3imagepath)) {
            commlogd.error("第三个头像图片不存在或无效: " + avatar3imagepath);
            return null;
        }

        // 第一个头像的位置和大小
        int avatar1x = 22; // 头像x坐标
        int avatar1y = 240; // 头像y坐标
        int avatar1width = 100; // 头像宽度
        int avatar1height = 100; // 头像高度

        // 先合成第一个头像到背景图,保存为临时文件1
        boolean successfirst = imageutils.compositeavatar(
                bgimagepath,
                avatar1imagepath,
                tempoutputpath1,
                avatar1x,
                avatar1y,
                avatar1width,
                avatar1height,
                "png" // 固定输出为png格式,支持透明
        );

        if (!successfirst) {
            commlogd.error("合成第一个头像失败");
            return null;
        }

        // 第二个头像的位置和大小
        int avatar2x = 600; // 头像x坐标
        int avatar2y = 240; // 头像y坐标
        int avatar2width = 100; // 头像宽度
        int avatar2height = 100; // 头像高度
        // 再将第二个头像合成到临时文件1上,得到临时文件2
        boolean successsecond = imageutils.compositeavatar(
                tempoutputpath1,
                avatar2imagepath,
                tempoutputpath2,
                avatar2x,
                avatar2y,
                avatar2width,
                avatar2height,
                "png"
        );

        if (!successsecond) {
            commlogd.error("合成第二个头像失败");
            // 删除已生成的临时文件
            file tempfile1 = new file(tempoutputpath1);
            if (tempfile1.exists()) {
                tempfile1.delete();
            }
            return null;
        }

        // 第三个头像的位置和大小
        int avatar3x = 310; // 头像x坐标
        int avatar3y = 450; // 头像y坐标
        int avatar3width = 100; // 头像宽度
        int avatar3height = 100; // 头像高度

        // 将第三个头像合成到临时文件2上,得到临时文件3
        boolean successthird = imageutils.compositeavatar(
                tempoutputpath2,
                avatar3imagepath,
                tempoutputpath3,
                avatar3x,
                avatar3y,
                avatar3width,
                avatar3height,
                "png"
        );

        // 删除临时文件1和2
        file tempfile1 = new file(tempoutputpath1);
        if (tempfile1.exists()) {
            tempfile1.delete();
        }

        file tempfile2 = new file(tempoutputpath2);
        if (tempfile2.exists()) {
            tempfile2.delete();
        }

        if (!successthird) {
            commlogd.error("合成第三个头像失败");
            // 删除临时文件3
            file tempfile3 = new file(tempoutputpath3);
            if (tempfile3.exists()) {
                tempfile3.delete();
            }
            return null;
        }
        // 确保输出目录存在
        file outputfile = new file(outputpath);
        file parentdir = outputfile.getparentfile();
        if (parentdir != null && !parentdir.exists()) {
            parentdir.mkdirs();
        }

        // 绘制昵称到图片上
        boolean successdrawtext = true;
        string currentpath = tempoutputpath3;
        int fontsize = 24;
        java.awt.color fontcolor = new java.awt.color(255, 255, 255); // 白色文字

        // 绘制第一个昵称(如果有)
        if (nickname1 != null && !nickname1.isempty()) {
            int text1x = avatar1x; // 稍微偏移一点
            int text1y = avatar1y + avatar1height + 26; // 头像下方,加上字体大小

            string nextpath = (currentpath.equals(tempoutputpath3)) ? outputpath : outputpath + "_final1.png";

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname1,
                    text1x,
                    text1y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第一个昵称失败");
                // 删除临时文件
                file tempfile3 = new file(tempoutputpath3);
                if (tempfile3.exists()) {
                    tempfile3.delete();
                }
                return null;
            }
            currentpath = nextpath;
        }

        // 绘制第二个昵称(如果有)
        if (nickname2 != null && !nickname2.isempty()) {
            int text2x = avatar2x; // 稍微偏移一点
            int text2y = avatar2y + avatar2height + 26; // 头像下方,加上字体大小

            string nextpath = (currentpath.equals(tempoutputpath3)) ? outputpath :
                    (currentpath.equals(outputpath)) ? outputpath + "_final2.png" : outputpath + "_final3.png";

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname2,
                    text2x,
                    text2y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第二个昵称失败");
                // 清理文件
                file tempfile3 = new file(tempoutputpath3);
                if (tempfile3.exists()) {
                    tempfile3.delete();
                }
                if (currentpath.equals(outputpath)) {
                    file outputfileobj = new file(outputpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }
            currentpath = nextpath;
        }

        // 绘制第三个昵称(如果有)
        if (nickname3 != null && !nickname3.isempty()) {
            int text3x = avatar3x; // 稍微偏移一点
            int text3y = avatar3y + avatar3height + 26; // 头像下方,加上字体大小

            string nextpath;
            if (currentpath.equals(tempoutputpath3)) {
                nextpath = outputpath;
            } else if (currentpath.equals(outputpath)) {
                nextpath = outputpath + "_final4.png";
            } else {
                nextpath = outputpath + "_final5.png";
            }

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname3,
                    text3x,
                    text3y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第三个昵称失败");
                // 清理文件
                file tempfile3 = new file(tempoutputpath3);
                if (tempfile3.exists()) {
                    tempfile3.delete();
                }
                if (currentpath.equals(outputpath) || currentpath.contains("_final")) {
                    file outputfileobj = new file(currentpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }
            currentpath = nextpath;
        } else if (currentpath.equals(tempoutputpath3)) {
            // 如果没有昵称,直接将临时文件重命名为输出文件
            file tempfile3 = new file(tempoutputpath3);
            if (outputfile.exists()) {
                outputfile.delete();
            }
            tempfile3.renameto(outputfile);
        }

        // 处理可能生成的中间文件,确保最终文件名正确
        if (currentpath.contains("_final")) {
            file finalfile = new file(currentpath);
            file targetfile = new file(outputpath);
            if (targetfile.exists()) {
                targetfile.delete();
            }
            finalfile.renameto(targetfile);
        }

        // 删除可能存在的临时文件
        file tempfile3 = new file(tempoutputpath3);
        if (tempfile3.exists()) {
            tempfile3.delete();
        }

        // 删除可能存在的中间文件
        for (int i = 1; i <= 5; i++) {
            file intermediatefile = new file(outputpath + "_final" + i + ".png");
            if (intermediatefile.exists()) {
                intermediatefile.delete();
            }
        }

        commlogd.info("三个头像和昵称合成成功: " + outputpath);
        return outputpath;
    }


    /**
     * 将四个头像合成到背景图上的方法,并在头像下方添加昵称
     * @param basepath 基础路径
     * @param bgfilename 背景图文件名(不含路径)
     * @param avatar1filename 第一个头像文件名(不含路径)
     * @param nickname1 第一个头像对应的用户昵称
     * @param avatar2filename 第二个头像文件名(不含路径)
     * @param nickname2 第二个头像对应的用户昵称
     * @param avatar3filename 第三个头像文件名(不含路径)
     * @param nickname3 第三个头像对应的用户昵称
     * @param avatar4filename 第四个头像文件名(不含路径)
     * @param nickname4 第四个头像对应的用户昵称
     * @param outputfilename 输出文件名(不含路径)
     * @return 合成后的图片完整路径,失败返回null
     */
    public static string compositeimage4(string basepath, string bgfilename, string avatar1filename,string nickname1,
                                         string avatar2filename,string nickname2,  string avatar3filename, string nickname3, string avatar4filename,
                                         string nickname4,string outputfilename) {
        // 构建完整的文件路径
        string bgimagepath = basepath + bgfilename;
        string avatar1imagepath = basepath + avatar1filename;
        string avatar2imagepath = basepath + avatar2filename;
        string avatar3imagepath = basepath + avatar3filename;
        string avatar4imagepath = basepath + avatar4filename;
        string tempoutputpath1 = basepath + "composite\\" + outputfilename + "_temp1.png";
        string tempoutputpath2 = basepath + "composite\\" + outputfilename + "_temp2.png";
        string tempoutputpath3 = basepath + "composite\\" + outputfilename + "_temp3.png";
        string tempoutputpath4 = basepath + "composite\\" + outputfilename + "_temp4.png";
        string outputpath = basepath + "composite\\" + outputfilename;

        // 添加详细日志以调试路径问题
        commlogd.info("尝试访问背景图片路径: " + bgimagepath);
        file bgfile = new file(bgimagepath);
        commlogd.info("背景图片文件存在: " + bgfile.exists() + ", 是文件: " + bgfile.isfile() + ", 可读: " + bgfile.canread());

        // 验证输入图片是否存在
        if (!imageutils.isimagevalid(bgimagepath)) {
            commlogd.error("背景图片不存在或无效: " + bgimagepath);
            return null;
        }

        // 验证第一个头像
        commlogd.info("尝试访问第一个头像图片路径: " + avatar1imagepath);
        file avatar1file = new file(avatar1imagepath);
        commlogd.info("第一个头像图片文件存在: " + avatar1file.exists() + ", 是文件: " + avatar1file.isfile() + ", 可读: " + avatar1file.canread());

        if (!imageutils.isimagevalid(avatar1imagepath)) {
            commlogd.error("第一个头像图片不存在或无效: " + avatar1imagepath);
            return null;
        }

        // 验证第二个头像
        commlogd.info("尝试访问第二个头像图片路径: " + avatar2imagepath);
        file avatar2file = new file(avatar2imagepath);
        commlogd.info("第二个头像图片文件存在: " + avatar2file.exists() + ", 是文件: " + avatar2file.isfile() + ", 可读: " + avatar2file.canread());

        if (!imageutils.isimagevalid(avatar2imagepath)) {
            commlogd.error("第二个头像图片不存在或无效: " + avatar2imagepath);
            return null;
        }

        // 验证第三个头像
        commlogd.info("尝试访问第三个头像图片路径: " + avatar3imagepath);
        file avatar3file = new file(avatar3imagepath);
        commlogd.info("第三个头像图片文件存在: " + avatar3file.exists() + ", 是文件: " + avatar3file.isfile() + ", 可读: " + avatar3file.canread());

        if (!imageutils.isimagevalid(avatar3imagepath)) {
            commlogd.error("第三个头像图片不存在或无效: " + avatar3imagepath);
            return null;
        }

        // 验证第四个头像
        commlogd.info("尝试访问第四个头像图片路径: " + avatar4imagepath);
        file avatar4file = new file(avatar4imagepath);
        commlogd.info("第四个头像图片文件存在: " + avatar4file.exists() + ", 是文件: " + avatar4file.isfile() + ", 可读: " + avatar4file.canread());

        if (!imageutils.isimagevalid(avatar4imagepath)) {
            commlogd.error("第四个头像图片不存在或无效: " + avatar4imagepath);
            return null;
        }

        // 第一个头像的位置和大小
        int avatar1x = 22; // 头像x坐标
        int avatar1y = 240; // 头像y坐标
        int avatar1width = 100; // 头像宽度
        int avatar1height = 100; // 头像高度

        // 先合成第一个头像到背景图,保存为临时文件1
        boolean successfirst = imageutils.compositeavatar(
                bgimagepath,
                avatar1imagepath,
                tempoutputpath1,
                avatar1x,
                avatar1y,
                avatar1width,
                avatar1height,
                "png" // 固定输出为png格式,支持透明
        );

        if (!successfirst) {
            commlogd.error("合成第一个头像失败");
            return null;
        }

        // 第二个头像的位置和大小
        int avatar2x = 600; // 头像x坐标
        int avatar2y = 240; // 头像y坐标
        int avatar2width = 100; // 头像宽度
        int avatar2height = 100; // 头像高度
        // 再将第二个头像合成到临时文件1上,得到临时文件2
        boolean successsecond = imageutils.compositeavatar(
                tempoutputpath1,
                avatar2imagepath,
                tempoutputpath2,
                avatar2x,
                avatar2y,
                avatar2width,
                avatar2height,
                "png"
        );

        if (!successsecond) {
            commlogd.error("合成第二个头像失败");
            // 删除已生成的临时文件
            file tempfile1 = new file(tempoutputpath1);
            if (tempfile1.exists()) {
                tempfile1.delete();
            }
            return null;
        }

        // 第三个头像的位置和大小
        int avatar3x = 310; // 头像x坐标
        int avatar3y = 450; // 头像y坐标
        int avatar3width = 100; // 头像宽度
        int avatar3height = 100; // 头像高度

        // 将第三个头像合成到临时文件2上,得到临时文件3
        boolean successthird = imageutils.compositeavatar(
                tempoutputpath2,
                avatar3imagepath,
                tempoutputpath3,
                avatar3x,
                avatar3y,
                avatar3width,
                avatar3height,
                "png"
        );

        // 删除临时文件1和2
        file tempfile1 = new file(tempoutputpath1);
        if (tempfile1.exists()) {
            tempfile1.delete();
        }

        file tempfile2 = new file(tempoutputpath2);
        if (tempfile2.exists()) {
            tempfile2.delete();
        }

        if (!successthird) {
            commlogd.error("合成第三个头像失败");
            // 删除临时文件3
            file tempfile3 = new file(tempoutputpath3);
            if (tempfile3.exists()) {
                tempfile3.delete();
            }
            return null;
        }

        // 第四个头像的位置和大小(设置为顶部居中)
        int avatar4x = 310; // 头像x坐标
        int avatar4y = 35; // 头像y坐标
        int avatar4width = 100; // 头像宽度
        int avatar4height = 100; // 头像高度

        // 将第四个头像合成到临时文件3上,得到临时文件4
        boolean successfourth = imageutils.compositeavatar(
                tempoutputpath3,
                avatar4imagepath,
                tempoutputpath4,
                avatar4x,
                avatar4y,
                avatar4width,
                avatar4height,
                "png"
        );

        // 删除临时文件3
        file tempfile3 = new file(tempoutputpath3);
        if (tempfile3.exists()) {
            tempfile3.delete();
        }

        if (!successfourth) {
            commlogd.error("合成第四个头像失败");
            // 删除临时文件4
            file tempfile4 = new file(tempoutputpath4);
            if (tempfile4.exists()) {
                tempfile4.delete();
            }
            return null;
        }

        // 确保输出目录存在
        file outputfile = new file(outputpath);
        file parentdir = outputfile.getparentfile();
        if (parentdir != null && !parentdir.exists()) {
            parentdir.mkdirs();
        }

        // 绘制昵称到图片上
        boolean successdrawtext = true;
        string currentpath = tempoutputpath4;
        int fontsize = 24;
        java.awt.color fontcolor = new java.awt.color(255, 255, 255); // 白色文字

        // 绘制第一个昵称(如果有)
        if (nickname1 != null && !nickname1.isempty()) {
            int text1x = avatar1x; // 稍微偏移一点
            int text1y = avatar1y + avatar1height + 26; // 头像下方,加上字体大小

            string nextpath = (currentpath.equals(tempoutputpath4)) ? outputpath : outputpath + "_final1.png";

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname1,
                    text1x,
                    text1y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第一个昵称失败");
                // 删除临时文件
                file tempfile4 = new file(tempoutputpath4);
                if (tempfile4.exists()) {
                    tempfile4.delete();
                }
                return null;
            }
            currentpath = nextpath;
        }

        // 绘制第二个昵称(如果有)
        if (nickname2 != null && !nickname2.isempty()) {
            int text2x = avatar2x; // 稍微偏移一点
            int text2y = avatar2y + avatar2height + 26; // 头像下方,加上字体大小

            string nextpath = (currentpath.equals(tempoutputpath4)) ? outputpath :
                    (currentpath.equals(outputpath)) ? outputpath + "_final2.png" : outputpath + "_final3.png";

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname2,
                    text2x,
                    text2y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第二个昵称失败");
                // 清理文件
                file tempfile4 = new file(tempoutputpath4);
                if (tempfile4.exists()) {
                    tempfile4.delete();
                }
                if (currentpath.equals(outputpath)) {
                    file outputfileobj = new file(outputpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }
            currentpath = nextpath;
        }

        // 绘制第三个昵称(如果有)
        if (nickname3 != null && !nickname3.isempty()) {
            int text3x = avatar3x; // 稍微偏移一点
            int text3y = avatar3y + avatar3height + 26; // 头像下方,加上字体大小

            string nextpath;
            if (currentpath.equals(tempoutputpath4)) {
                nextpath = outputpath;
            } else if (currentpath.equals(outputpath)) {
                nextpath = outputpath + "_final4.png";
            } else {
                nextpath = outputpath + "_final5.png";
            }

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname3,
                    text3x,
                    text3y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第三个昵称失败");
                // 清理文件
                file tempfile4 = new file(tempoutputpath4);
                if (tempfile4.exists()) {
                    tempfile4.delete();
                }
                if (currentpath.equals(outputpath) || currentpath.contains("_final")) {
                    file outputfileobj = new file(currentpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }
            currentpath = nextpath;
        }

        // 绘制第四个昵称(如果有)
        if (nickname4 != null && !nickname4.isempty()) {
            int text4x = avatar4x; // 稍微偏移一点
            int text4y = avatar4y + avatar4height + 26; // 头像下方,加上字体大小

            string nextpath;
            if (currentpath.equals(tempoutputpath4)) {
                nextpath = outputpath;
            } else if (currentpath.equals(outputpath)) {
                nextpath = outputpath + "_final6.png";
            } else if (currentpath.contains("_final")) {
                nextpath = outputpath + "_final7.png";
            } else {
                nextpath = outputpath + "_final8.png";
            }

            successdrawtext = imageutils.drawtextonimage(
                    currentpath,
                    nextpath,
                    nickname4,
                    text4x,
                    text4y,
                    fontsize,
                    fontcolor,
                    "png"
            );

            if (!successdrawtext) {
                commlogd.error("绘制第四个昵称失败");
                // 清理文件
                file tempfile4 = new file(tempoutputpath4);
                if (tempfile4.exists()) {
                    tempfile4.delete();
                }
                if (currentpath.equals(outputpath) || currentpath.contains("_final")) {
                    file outputfileobj = new file(currentpath);
                    if (outputfileobj.exists()) {
                        outputfileobj.delete();
                    }
                }
                return null;
            }
            currentpath = nextpath;
        } else if (currentpath.equals(tempoutputpath4)) {
            // 如果没有昵称,直接将临时文件重命名为输出文件
            file tempfile4 = new file(tempoutputpath4);
            if (outputfile.exists()) {
                outputfile.delete();
            }
            tempfile4.renameto(outputfile);
        }

        // 处理可能生成的中间文件,确保最终文件名正确
        if (currentpath.contains("_final")) {
            file finalfile = new file(currentpath);
            file targetfile = new file(outputpath);
            if (targetfile.exists()) {
                targetfile.delete();
            }
            finalfile.renameto(targetfile);
        }

        // 删除可能存在的临时文件
        file tempfile4 = new file(tempoutputpath4);
        if (tempfile4.exists()) {
            tempfile4.delete();
        }

        // 删除可能存在的中间文件
        for (int i = 1; i <= 8; i++) {
            file intermediatefile = new file(outputpath + "_final" + i + ".png");
            if (intermediatefile.exists()) {
                intermediatefile.delete();
            }
        }

        commlogd.info("四个头像和昵称合成成功: " + outputpath);
        return outputpath;
    }

    /**
     * 将头像合成到背景图中心位置的便捷方法
     * @param bgfilename 背景图文件名
     * @param avatarfilename 头像文件名
     * @param outputfilename 输出文件名
     * @param avatarwidth 头像宽度
     * @param avatarheight 头像高度
     * @return 合成后的图片完整路径,失败返回null
     */
    public static string compositeimagetocenter(string bgfilename, string avatarfilename, string outputfilename,
                                                int avatarwidth, int avatarheight) {
        // 本地文件存储路径 - 使用windows兼容的绝对路径格式
        string basepath = "d:\\ideaprojects\\mahjong_java\\gameserver\\src\\core\\file\\";
        if (!basepath.endswith("\\")) {
            basepath += "\\";
        }

        string bgimagepath = basepath + bgfilename;
        string avatarimagepath = basepath + avatarfilename;
        string outputpath = basepath + "composite\\" + outputfilename;

        // 添加详细日志以调试路径问题
        commlogd.info("尝试访问背景图片路径: " + bgimagepath);
        file bgfile = new file(bgimagepath);
        commlogd.info("背景图片文件存在: " + bgfile.exists() + ", 是文件: " + bgfile.isfile() + ", 可读: " + bgfile.canread());

        // 验证输入图片是否存在
        if (!imageutils.isimagevalid(bgimagepath)) {
            commlogd.error("背景图片不存在或无效: " + bgimagepath);
            return null;
        }

        commlogd.info("尝试访问头像图片路径: " + avatarimagepath);
        file avatarfile = new file(avatarimagepath);
        commlogd.info("头像图片文件存在: " + avatarfile.exists() + ", 是文件: " + avatarfile.isfile() + ", 可读: " + avatarfile.canread());

        if (!imageutils.isimagevalid(avatarimagepath)) {
            commlogd.error("头像图片不存在或无效: " + avatarimagepath);
            return null;
        }

        // 执行居中合成
        boolean success = imageutils.compositeavatartocenter(
                bgimagepath,
                avatarimagepath,
                outputpath,
                avatarwidth,
                avatarheight,
                "png"
        );

        if (success) {
            commlogd.info("头像居中合成成功: " + outputpath);
            return outputpath;
        } else {
            commlogd.error("头像居中合成失败");
            return null;
        }
    }
}

下面是图片工具类的代码:

/**
 * 图片处理工具类
 * 提供图片合成、缩放等功能
 */
public class imageutils {

    /**
     * 将头像合成到背景图上
     * @param bgimagepath 背景图路径
     * @param avatarimagepath 头像路径
     * @param outputpath 输出图片路径
     * @param avatarx 头像在背景图上的x坐标
     * @param avatary 头像在背景图上的y坐标
     * @param avatarwidth 头像宽度
     * @param avatarheight 头像高度
     * @param format 输出图片格式 (jpg, png等)
     * @return 是否成功
     */
    public static boolean compositeavatar(string bgimagepath, string avatarimagepath, 
                                        string outputpath, int avatarx, int avatary, 
                                        int avatarwidth, int avatarheight, string format) {
        try {
            // 加载背景图
            bufferedimage bgimage = imageio.read(new file(bgimagepath));
            if (bgimage == null) {
                commlogd.error("background image not found or format not supported: " + bgimagepath);
                return false;
            }

            // 加载头像
            bufferedimage avatarimage = null;
            // 检查是否为svg格式头像
            if (avatarimagepath.tolowercase().endswith(".svg")) {
                // 对于svg格式,我们需要特殊处理
                // 这里使用简化的方式,创建一个占位图像
                // 实际项目中可以使用apache batik库来渲染svg
                commlogd.info("processing svg avatar: " + avatarimagepath);
                avatarimage = createsvgplaceholder(avatarwidth, avatarheight);
            } else {
                // 加载非svg头像
                avatarimage = imageio.read(new file(avatarimagepath));
                if (avatarimage == null) {
                    commlogd.error("avatar image not found or format not supported: " + avatarimagepath);
                    return false;
                }
            }
            // 创建graphics2d对象进行绘制
            graphics2d g2d = bgimage.creategraphics();
            
            // 设置绘制质量
            g2d.setrenderinghint(renderinghints.key_interpolation,
                    renderinghints.value_interpolation_bilinear);
            g2d.setrenderinghint(renderinghints.key_rendering,
                    renderinghints.value_render_quality);
            g2d.setrenderinghint(renderinghints.key_antialiasing,
                    renderinghints.value_antialias_on);

            // 绘制头像到背景图指定位置和大小
            g2d.drawimage(avatarimage, avatarx, avatary, avatarwidth, avatarheight, null);
            g2d.dispose();

            // 确保输出目录存在
            file outputfile = new file(outputpath);
            file parentdir = outputfile.getparentfile();
            if (parentdir != null && !parentdir.exists()) {
                parentdir.mkdirs();
            }

            // 保存合成后的图片
            boolean result = imageio.write(bgimage, format, outputfile);
            if (!result) {
                commlogd.error("failed to write image, unsupported format: " + format);
            }
            return result;
        } catch (exception e) {
            commlogd.error("error compositing images: " + e.getmessage(), e);
            return false;
        }
    }

    /**
     * 创建svg占位图像
     * 在没有svg库的情况下,创建一个简单的占位图像
     * 实际项目中可以使用apache batik库来正确渲染svg
     *
     * @param width 宽度
     * @param height 高度
     * @return 占位图像
     */
    private static bufferedimage createsvgplaceholder(int width, int height) {
        bufferedimage image = new bufferedimage(width, height, bufferedimage.type_int_argb);
        graphics2d g2d = image.creategraphics();

        // 设置背景为透明
        g2d.setcomposite(alphacomposite.clear);
        g2d.fillrect(0, 0, width, height);
        g2d.setcomposite(alphacomposite.src);

        // 绘制一个简单的彩色圆形作为svg占位符
        g2d.setcolor(new color(70, 130, 180, 200)); // steel blue with some transparency
        g2d.filloval(0, 0, width, height);

        // 可以在这里添加更多的占位符样式

        g2d.dispose();
        return image;
    }

    /**
     * 将头像合成到背景图中心位置
     * @param bgimagepath 背景图路径
     * @param avatarimagepath 头像路径
     * @param outputpath 输出图片路径
     * @param avatarwidth 头像宽度
     * @param avatarheight 头像高度
     * @param format 输出图片格式
     * @return 是否成功
     */
    public static boolean compositeavatartocenter(string bgimagepath, string avatarimagepath, 
                                                string outputpath, int avatarwidth, 
                                                int avatarheight, string format) {
        try {
            // 加载背景图获取尺寸
            bufferedimage bgimage = imageio.read(new file(bgimagepath));
            if (bgimage == null) {
                commlogd.error("background image not found or format not supported: " + bgimagepath);
                return false;
            }

            // 计算头像居中的位置
            int bgwidth = bgimage.getwidth();
            int bgheight = bgimage.getheight();
            int avatarx = (bgwidth - avatarwidth) / 2;
            int avatary = (bgheight - avatarheight) / 2;

            // 调用合成方法
            return compositeavatar(bgimagepath, avatarimagepath, outputpath, 
                    avatarx, avatary, avatarwidth, avatarheight, format);
        } catch (exception e) {
            commlogd.error("error compositing avatar to center: " + e.getmessage(), e);
            return false;
        }
    }

    /**
     * 缩放图片
     * @param imagepath 原始图片路径
     * @param outputpath 输出图片路径
     * @param targetwidth 目标宽度
     * @param targetheight 目标高度
     * @param format 输出格式
     * @return 是否成功
     */
    public static boolean resizeimage(string imagepath, string outputpath, 
                                     int targetwidth, int targetheight, string format) {
        try {
            bufferedimage originalimage = imageio.read(new file(imagepath));
            if (originalimage == null) {
                commlogd.error("image not found or format not supported: " + imagepath);
                return false;
            }

            // 创建缩放后的图片
            bufferedimage resizedimage = new bufferedimage(targetwidth, targetheight, 
                    bufferedimage.type_int_argb);
            graphics2d g = resizedimage.creategraphics();
            
            // 设置缩放质量
            g.setrenderinghint(renderinghints.key_interpolation,
                    renderinghints.value_interpolation_bilinear);
            g.setrenderinghint(renderinghints.key_rendering,
                    renderinghints.value_render_quality);
            g.setrenderinghint(renderinghints.key_antialiasing,
                    renderinghints.value_antialias_on);

            // 绘制缩放后的图片
            g.drawimage(originalimage, 0, 0, targetwidth, targetheight, null);
            g.dispose();

            // 确保输出目录存在
            file outputfile = new file(outputpath);
            file parentdir = outputfile.getparentfile();
            if (parentdir != null && !parentdir.exists()) {
                parentdir.mkdirs();
            }

            // 保存图片
            return imageio.write(resizedimage, format, outputfile);
        } catch (exception e) {
            commlogd.error("error resizing image: " + e.getmessage(), e);
            return false;
        }
    }

    /**
     * 获取图片的字节数组
     * @param imagepath 图片路径
     * @param format 图片格式
     * @return 字节数组
     */
    public static byte[] getimagebytes(string imagepath, string format) {
        try {
            bufferedimage image = imageio.read(new file(imagepath));
            if (image == null) {
                commlogd.error("image not found or format not supported: " + imagepath);
                return null;
            }

            bytearrayoutputstream baos = new bytearrayoutputstream();
            imageio.write(image, format, baos);
            return baos.tobytearray();
        } catch (exception e) {
            commlogd.error("error getting image bytes: " + e.getmessage(), e);
            return null;
        }
    }

    /**
     * 检查图片文件是否存在且可访问
     * @param imagepath 图片路径
     * @return 是否有效
     */
    public static boolean isimagevalid(string imagepath) {
        try {
            file imagefile = new file(imagepath);
            if (!imagefile.exists() || !imagefile.isfile() || !imagefile.canread()) {
                return false;
            }

            // 特殊处理svg格式文件
            if (imagepath.tolowercase().endswith(".svg")) {
                commlogd.info("svg image file detected: " + imagepath);
                // 对于svg,我们只验证文件存在且可读,不尝试用imageio读取
                return true;
            }
            bufferedimage image = imageio.read(imagefile);
            boolean valid = image != null;
            if (!valid) {
                commlogd.info("non-svg image format not supported or invalid: " + imagepath);
            }
            return valid;
        } catch (exception e) {
            commlogd.error("error validating image: " + e.getmessage());
            return false;
        }
    }

    /**
     * 在图片上绘制文本
     * @param imagepath 图片路径
     * @param outputpath 输出图片路径
     * @param text 要绘制的文本
     * @param x 文本起始x坐标
     * @param y 文本起始y坐标
     * @param fontsize 字体大小
     * @param fontcolor 字体颜色
     * @param format 输出图片格式
     * @return 是否成功
     */
    public static boolean drawtextonimage(string imagepath, string outputpath, string text,
                                          int x, int y, int fontsize, color fontcolor, string format) {
        try {
            // 加载图片
            bufferedimage image = imageio.read(new file(imagepath));
            if (image == null) {
                commlogd.error("image not found or format not supported: " + imagepath);
                return false;
            }

            // 创建graphics2d对象进行绘制
            graphics2d g2d = image.creategraphics();

            // 设置绘制质量
            g2d.setrenderinghint(renderinghints.key_text_antialiasing,
                    renderinghints.value_text_antialias_on);
            g2d.setrenderinghint(renderinghints.key_rendering,
                    renderinghints.value_render_quality);

            // 设置字体和颜色
            font font = new font("microsoft yahei", font.plain, fontsize);
            g2d.setfont(font);
            g2d.setcolor(fontcolor);

            // 绘制文本
            g2d.drawstring(text, x, y);
            g2d.dispose();

            // 确保输出目录存在
            file outputfile = new file(outputpath);
            file parentdir = outputfile.getparentfile();
            if (parentdir != null && !parentdir.exists()) {
                parentdir.mkdirs();
            }

            // 保存绘制后的图片
            return imageio.write(image, format, outputfile);
        } catch (exception e) {
            commlogd.error("error drawing text on image: " + e.getmessage(), e);
            return false;
        }
    }
}

二、将一张头像合成到背景图中间固定的位置上

首先我们需要定义几个固定的参数(实际项目中参数从以上请求返回值中获取),还是如一所示

//调用图像合成方法;接收合成后的图片完整路径
string  imgurl = compositeimages.compositeimagetocenter(basepath,bgfilename,backname,20,20)

这个是将头像合成到背景图中心位置的便捷方法;返回值也是一个string类型的url图片地址;

三、总结

我们根据自己的需要调用图片合成类相关的方法即可返回一个string类型的url图片地址;后期我们如果需要返回的是一个在线可访问的图片链接,可以考虑把返回的图片上传到云存储即可。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com