最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java后端頭像合成到背景圖上面代碼實(shí)踐

 更新時(shí)間:2026年01月07日 09:19:46   作者:小七.布靈  
這篇文章介紹了如何使用Java后端工具類將頭像合成到背景圖上,提供了兩種合成方法:一種是將頭像固定在背景圖的某個(gè)位置,另一種是將頭像合成到背景圖的中心位置,作者分享了圖片合成類的代碼,并總結(jié)了如何根據(jù)需要調(diào)用相關(guān)方法返回圖片地址

最近在做一個(gè)需求;本來頭像懸浮到背景圖上的功能是由前端來做的,但是自己閑來沒事,然后自己用java后端寫了一個(gè)工具類,供以后使用,在這里寫帖子分享出來,有需要的可以借用!僅供參考!

一、第一張頭像合成到背景圖固定的位置上

需要用戶頭像合成到固定位置的背景圖上,然后昵稱懸浮在頭像下面;最后返回一個(gè)圖片的地址

我們先在項(xiàng)目本地目錄新建一個(gè)文件夾,存放背景圖和頭像圖片,如圖所示;

首先我們需要定義幾個(gè)固定的參數(shù)(實(shí)際項(xiàng)目中參數(shù)從以上請(qǐng)求返回值中獲取);

String bgFileName = "backgroud.png"; //背景圖文件名
String avatarFileName = "autohotkey.svg"; //頭像文件名
String nickname = "鄭州小一"; //頭像文件名

String outputFileName = "telegramPhoto"; //輸出文件名

// 本地文件存儲(chǔ)路徑 - 使用Windows兼容的絕對(duì)路徑格式
String basePath = "d:\\IdeaProjects\\mahjong_java\\gameServer\\src\\core\\file\\";

// 確保路徑格式正確
if (!basePath.endsWith("\\")) {
    basePath += "\\";
}

然后我們調(diào)用圖片合成方法傳參:

//調(diào)用圖像合成方法;接收合成后的圖片完整路徑
String  imgURL = CompositeImages.compositeImage(basePath,bgFileName,avatarFileName,nickname)

然后我們?cè)谫x值給接口返回參數(shù)即可;

以下是圖片合成類的全部代碼:

/**
 * 合成圖片工具類:將頭像合成到背景圖上
 * @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) {
        // 構(gòu)建完整的文件路徑
        String bgImagePath = basePath + bgFileName;
        String avatarImagePath = basePath + avatarFileName;
        String tempOutputPath = basePath + "composite\\" + outputFileName + "_temp.png";
        String outputPath = basePath + "composite\\" + outputFileName;

        // 添加詳細(xì)日志以調(diào)試路徑問題
        CommLogD.info("嘗試訪問背景圖片路徑: " + bgImagePath);
        File bgFile = new File(bgImagePath);
        CommLogD.info("背景圖片文件存在: " + bgFile.exists() + ", 是文件: " + bgFile.isFile() + ", 可讀: " + bgFile.canRead());

        // 驗(yàn)證輸入圖片是否存在
        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坐標(biāo)
        int avatarY = 240; //頭像Y坐標(biāo)
        int avatarWidth = 100; //頭像寬度
        int avatarHeight = 100; //頭像高度
        // 執(zhí)行頭像合成到臨時(shí)文件
        boolean success = ImageUtils.compositeAvatar(
                bgImagePath,
                avatarImagePath,
                tempOutputPath,
                avatarX,
                avatarY,
                avatarWidth,
                avatarHeight,
                "png" // 固定輸出為png格式,支持透明
        );

        if (!success) {
            CommLogD.error("頭像合成失敗");
            // 清理臨時(shí)文件
            File tempFile = new File(tempOutputPath);
            if (tempFile.exists()) {
                tempFile.delete();
            }
            return null;
        }

        // 如果提供了昵稱,則繪制昵稱
        if (nickname != null && !nickname.isEmpty()) {
            // 計(jì)算昵稱繪制位置(頭像下方居中)
            int textX = avatarX; // 稍微偏移一點(diǎn)
            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"
            );

            // 清理臨時(shí)文件
            File tempFile = new File(tempOutputPath);
            if (tempFile.exists()) {
                tempFile.delete();
            }
        } else {
            // 如果沒有昵稱,直接將臨時(shí)文件重命名為輸出文件
            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;
        }
    }

    /**
     * 將兩個(gè)頭像合成到背景圖上的方法,并在頭像下方添加昵稱
     * @param bgFileName 背景圖文件名(不含路徑)
     * @param avatar1FileName 第一個(gè)頭像文件名(不含路徑)
     * @param nickname1 第一個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar2FileName 第二個(gè)頭像文件名(不含路徑)
     * @param nickname2 第二個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param outputFileName 輸出文件名(不含路徑)
     * @return 合成后的圖片完整路徑,失敗返回null
     */
    public static String compositeImage2(String basePath, String bgFileName, String avatar1FileName,  String nickname1, String avatar2FileName, String nickname2,
                                         String outputFileName) {


        // 構(gòu)建完整的文件路徑
        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;

        // 添加詳細(xì)日志以調(diào)試路徑問題
        CommLogD.info("嘗試訪問背景圖片路徑: " + bgImagePath);
        File bgFile = new File(bgImagePath);
        CommLogD.info("背景圖片文件存在: " + bgFile.exists() + ", 是文件: " + bgFile.isFile() + ", 可讀: " + bgFile.canRead());

        // 驗(yàn)證輸入圖片是否存在
        if (!ImageUtils.isImageValid(bgImagePath)) {
            CommLogD.error("背景圖片不存在或無效: " + bgImagePath);
            return null;
        }

        // 驗(yàn)證第一個(gè)頭像
        CommLogD.info("嘗試訪問第一個(gè)頭像圖片路徑: " + avatar1ImagePath);
        File avatar1File = new File(avatar1ImagePath);
        CommLogD.info("第一個(gè)頭像圖片文件存在: " + avatar1File.exists() + ", 是文件: " + avatar1File.isFile() + ", 可讀: " + avatar1File.canRead());

        if (!ImageUtils.isImageValid(avatar1ImagePath)) {
            CommLogD.error("第一個(gè)頭像圖片不存在或無效: " + avatar1ImagePath);
            return null;
        }

        // 驗(yàn)證第二個(gè)頭像
        CommLogD.info("嘗試訪問第二個(gè)頭像圖片路徑: " + avatar2ImagePath);
        File avatar2File = new File(avatar2ImagePath);
        CommLogD.info("第二個(gè)頭像圖片文件存在: " + avatar2File.exists() + ", 是文件: " + avatar2File.isFile() + ", 可讀: " + avatar2File.canRead());

        if (!ImageUtils.isImageValid(avatar2ImagePath)) {
            CommLogD.error("第二個(gè)頭像圖片不存在或無效: " + avatar2ImagePath);
            return null;
        }
        int avatar1X = 22; //頭像X坐標(biāo)
        int avatar1Y = 240; //頭像Y坐標(biāo)
        int avatar1Width = 100; //頭像寬度
        int avatar1Height = 100; //頭像高度
        // 先合成第一個(gè)頭像到背景圖,保存為臨時(shí)文件
        boolean successFirst = ImageUtils.compositeAvatar(
                bgImagePath,
                avatar1ImagePath,
                tempOutputPath1,
                avatar1X,
                avatar1Y,
                avatar1Width,
                avatar1Height,
                "png" // 固定輸出為png格式,支持透明
        );

        if (!successFirst) {
            CommLogD.error("合成第一個(gè)頭像失敗");
            return null;
        }
        int avatar2X = 600; //頭像X坐標(biāo)
        int avatar2Y = 240; //頭像Y坐標(biāo)
        int avatar2Width = 100; //頭像寬度
        int avatar2Height = 100; //頭像高度
        // 再將第二個(gè)頭像合成到臨時(shí)文件上,得到最終結(jié)果
        boolean successSecond = ImageUtils.compositeAvatar(
                tempOutputPath1,
                avatar2ImagePath,
                tempOutputPath2,
                avatar2X,
                avatar2Y,
                avatar2Width,
                avatar2Height,
                "png"
        );

        // 刪除第一個(gè)臨時(shí)文件
        File tempFile1 = new File(tempOutputPath1);
        if (tempFile1.exists()) {
            tempFile1.delete();
        }

        if (!successSecond) {
            CommLogD.info("兩個(gè)頭像合成成功: " + outputPath);
            // 刪除第二個(gè)臨時(shí)文件
            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); // 白色文字

        // 繪制第一個(gè)昵稱(如果有)
        if (nickname1 != null && !nickname1.isEmpty()) {
            int text1X = avatar1X; // 稍微偏移一點(diǎn)
            int text1Y = avatar1Y + avatar1Height + 26; // 頭像下方,加上字體大小

            successDrawText = ImageUtils.drawTextOnImage(
                    currentPath,
                    outputPath,
                    nickname1,
                    text1X,
                    text1Y,
                    fontSize,
                    fontColor,
                    "png"
            );

            if (!successDrawText) {
                CommLogD.error("繪制第一個(gè)昵稱失敗");
                // 刪除臨時(shí)文件
                File tempFile2 = new File(tempOutputPath2);
                if (tempFile2.exists()) {
                    tempFile2.delete();
                }
                return null;
            }
            currentPath = outputPath;
        }

        // 繪制第二個(gè)昵稱(如果有)
        if (nickname2 != null && !nickname2.isEmpty()) {
            int text2X = avatar2X; // 稍微偏移一點(diǎn)
            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("繪制第二個(gè)昵稱失敗");
                // 清理文件
                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;
            }

            // 如果創(chuàng)建了最終文件,需要重命名
            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)) {
            // 如果沒有第二個(gè)昵稱,直接將臨時(shí)文件重命名為輸出文件
            File tempFile2 = new File(tempOutputPath2);
            if (outputFile.exists()) {
                outputFile.delete();
            }
            tempFile2.renameTo(outputFile);
        }

        // 刪除可能存在的臨時(shí)文件
        File tempFile2 = new File(tempOutputPath2);
        if (tempFile2.exists()) {
            tempFile2.delete();
        }

        CommLogD.info("兩個(gè)頭像和昵稱合成成功: " + outputPath);
        return outputPath;
    }

    /**
     * 將三個(gè)頭像合成到背景圖上的方法
     * @param basePath 基礎(chǔ)路徑
     * @param bgFileName 背景圖文件名(不含路徑)
     * @param avatar1FileName 第一個(gè)頭像文件名(不含路徑)
     * @param nickname1 第一個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar2FileName 第二個(gè)頭像文件名(不含路徑)
     * @param nickname2 第二個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar3FileName 第三個(gè)頭像文件名(不含路徑)
     * @param nickname3 第三個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @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) {
        // 構(gòu)建完整的文件路徑
        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;

        // 添加詳細(xì)日志以調(diào)試路徑問題
        CommLogD.info("嘗試訪問背景圖片路徑: " + bgImagePath);
        File bgFile = new File(bgImagePath);
        CommLogD.info("背景圖片文件存在: " + bgFile.exists() + ", 是文件: " + bgFile.isFile() + ", 可讀: " + bgFile.canRead());

        // 驗(yàn)證輸入圖片是否存在
        if (!ImageUtils.isImageValid(bgImagePath)) {
            CommLogD.error("背景圖片不存在或無效: " + bgImagePath);
            return null;
        }

        // 驗(yàn)證第一個(gè)頭像
        CommLogD.info("嘗試訪問第一個(gè)頭像圖片路徑: " + avatar1ImagePath);
        File avatar1File = new File(avatar1ImagePath);
        CommLogD.info("第一個(gè)頭像圖片文件存在: " + avatar1File.exists() + ", 是文件: " + avatar1File.isFile() + ", 可讀: " + avatar1File.canRead());

        if (!ImageUtils.isImageValid(avatar1ImagePath)) {
            CommLogD.error("第一個(gè)頭像圖片不存在或無效: " + avatar1ImagePath);
            return null;
        }

        // 驗(yàn)證第二個(gè)頭像
        CommLogD.info("嘗試訪問第二個(gè)頭像圖片路徑: " + avatar2ImagePath);
        File avatar2File = new File(avatar2ImagePath);
        CommLogD.info("第二個(gè)頭像圖片文件存在: " + avatar2File.exists() + ", 是文件: " + avatar2File.isFile() + ", 可讀: " + avatar2File.canRead());

        if (!ImageUtils.isImageValid(avatar2ImagePath)) {
            CommLogD.error("第二個(gè)頭像圖片不存在或無效: " + avatar2ImagePath);
            return null;
        }

        // 驗(yàn)證第三個(gè)頭像
        CommLogD.info("嘗試訪問第三個(gè)頭像圖片路徑: " + avatar3ImagePath);
        File avatar3File = new File(avatar3ImagePath);
        CommLogD.info("第三個(gè)頭像圖片文件存在: " + avatar3File.exists() + ", 是文件: " + avatar3File.isFile() + ", 可讀: " + avatar3File.canRead());

        if (!ImageUtils.isImageValid(avatar3ImagePath)) {
            CommLogD.error("第三個(gè)頭像圖片不存在或無效: " + avatar3ImagePath);
            return null;
        }

        // 第一個(gè)頭像的位置和大小
        int avatar1X = 22; // 頭像X坐標(biāo)
        int avatar1Y = 240; // 頭像Y坐標(biāo)
        int avatar1Width = 100; // 頭像寬度
        int avatar1Height = 100; // 頭像高度

        // 先合成第一個(gè)頭像到背景圖,保存為臨時(shí)文件1
        boolean successFirst = ImageUtils.compositeAvatar(
                bgImagePath,
                avatar1ImagePath,
                tempOutputPath1,
                avatar1X,
                avatar1Y,
                avatar1Width,
                avatar1Height,
                "png" // 固定輸出為png格式,支持透明
        );

        if (!successFirst) {
            CommLogD.error("合成第一個(gè)頭像失敗");
            return null;
        }

        // 第二個(gè)頭像的位置和大小
        int avatar2X = 600; // 頭像X坐標(biāo)
        int avatar2Y = 240; // 頭像Y坐標(biāo)
        int avatar2Width = 100; // 頭像寬度
        int avatar2Height = 100; // 頭像高度
        // 再將第二個(gè)頭像合成到臨時(shí)文件1上,得到臨時(shí)文件2
        boolean successSecond = ImageUtils.compositeAvatar(
                tempOutputPath1,
                avatar2ImagePath,
                tempOutputPath2,
                avatar2X,
                avatar2Y,
                avatar2Width,
                avatar2Height,
                "png"
        );

        if (!successSecond) {
            CommLogD.error("合成第二個(gè)頭像失敗");
            // 刪除已生成的臨時(shí)文件
            File tempFile1 = new File(tempOutputPath1);
            if (tempFile1.exists()) {
                tempFile1.delete();
            }
            return null;
        }

        // 第三個(gè)頭像的位置和大小
        int avatar3X = 310; // 頭像X坐標(biāo)
        int avatar3Y = 450; // 頭像Y坐標(biāo)
        int avatar3Width = 100; // 頭像寬度
        int avatar3Height = 100; // 頭像高度

        // 將第三個(gè)頭像合成到臨時(shí)文件2上,得到臨時(shí)文件3
        boolean successThird = ImageUtils.compositeAvatar(
                tempOutputPath2,
                avatar3ImagePath,
                tempOutputPath3,
                avatar3X,
                avatar3Y,
                avatar3Width,
                avatar3Height,
                "png"
        );

        // 刪除臨時(shí)文件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("合成第三個(gè)頭像失敗");
            // 刪除臨時(shí)文件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); // 白色文字

        // 繪制第一個(gè)昵稱(如果有)
        if (nickname1 != null && !nickname1.isEmpty()) {
            int text1X = avatar1X; // 稍微偏移一點(diǎn)
            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("繪制第一個(gè)昵稱失敗");
                // 刪除臨時(shí)文件
                File tempFile3 = new File(tempOutputPath3);
                if (tempFile3.exists()) {
                    tempFile3.delete();
                }
                return null;
            }
            currentPath = nextPath;
        }

        // 繪制第二個(gè)昵稱(如果有)
        if (nickname2 != null && !nickname2.isEmpty()) {
            int text2X = avatar2X; // 稍微偏移一點(diǎn)
            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("繪制第二個(gè)昵稱失敗");
                // 清理文件
                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;
        }

        // 繪制第三個(gè)昵稱(如果有)
        if (nickname3 != null && !nickname3.isEmpty()) {
            int text3X = avatar3X; // 稍微偏移一點(diǎn)
            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("繪制第三個(gè)昵稱失敗");
                // 清理文件
                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)) {
            // 如果沒有昵稱,直接將臨時(shí)文件重命名為輸出文件
            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);
        }

        // 刪除可能存在的臨時(shí)文件
        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("三個(gè)頭像和昵稱合成成功: " + outputPath);
        return outputPath;
    }


    /**
     * 將四個(gè)頭像合成到背景圖上的方法,并在頭像下方添加昵稱
     * @param basePath 基礎(chǔ)路徑
     * @param bgFileName 背景圖文件名(不含路徑)
     * @param avatar1FileName 第一個(gè)頭像文件名(不含路徑)
     * @param nickname1 第一個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar2FileName 第二個(gè)頭像文件名(不含路徑)
     * @param nickname2 第二個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar3FileName 第三個(gè)頭像文件名(不含路徑)
     * @param nickname3 第三個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @param avatar4FileName 第四個(gè)頭像文件名(不含路徑)
     * @param nickname4 第四個(gè)頭像對(duì)應(yīng)的用戶昵稱
     * @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) {
        // 構(gòu)建完整的文件路徑
        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;

        // 添加詳細(xì)日志以調(diào)試路徑問題
        CommLogD.info("嘗試訪問背景圖片路徑: " + bgImagePath);
        File bgFile = new File(bgImagePath);
        CommLogD.info("背景圖片文件存在: " + bgFile.exists() + ", 是文件: " + bgFile.isFile() + ", 可讀: " + bgFile.canRead());

        // 驗(yàn)證輸入圖片是否存在
        if (!ImageUtils.isImageValid(bgImagePath)) {
            CommLogD.error("背景圖片不存在或無效: " + bgImagePath);
            return null;
        }

        // 驗(yàn)證第一個(gè)頭像
        CommLogD.info("嘗試訪問第一個(gè)頭像圖片路徑: " + avatar1ImagePath);
        File avatar1File = new File(avatar1ImagePath);
        CommLogD.info("第一個(gè)頭像圖片文件存在: " + avatar1File.exists() + ", 是文件: " + avatar1File.isFile() + ", 可讀: " + avatar1File.canRead());

        if (!ImageUtils.isImageValid(avatar1ImagePath)) {
            CommLogD.error("第一個(gè)頭像圖片不存在或無效: " + avatar1ImagePath);
            return null;
        }

        // 驗(yàn)證第二個(gè)頭像
        CommLogD.info("嘗試訪問第二個(gè)頭像圖片路徑: " + avatar2ImagePath);
        File avatar2File = new File(avatar2ImagePath);
        CommLogD.info("第二個(gè)頭像圖片文件存在: " + avatar2File.exists() + ", 是文件: " + avatar2File.isFile() + ", 可讀: " + avatar2File.canRead());

        if (!ImageUtils.isImageValid(avatar2ImagePath)) {
            CommLogD.error("第二個(gè)頭像圖片不存在或無效: " + avatar2ImagePath);
            return null;
        }

        // 驗(yàn)證第三個(gè)頭像
        CommLogD.info("嘗試訪問第三個(gè)頭像圖片路徑: " + avatar3ImagePath);
        File avatar3File = new File(avatar3ImagePath);
        CommLogD.info("第三個(gè)頭像圖片文件存在: " + avatar3File.exists() + ", 是文件: " + avatar3File.isFile() + ", 可讀: " + avatar3File.canRead());

        if (!ImageUtils.isImageValid(avatar3ImagePath)) {
            CommLogD.error("第三個(gè)頭像圖片不存在或無效: " + avatar3ImagePath);
            return null;
        }

        // 驗(yàn)證第四個(gè)頭像
        CommLogD.info("嘗試訪問第四個(gè)頭像圖片路徑: " + avatar4ImagePath);
        File avatar4File = new File(avatar4ImagePath);
        CommLogD.info("第四個(gè)頭像圖片文件存在: " + avatar4File.exists() + ", 是文件: " + avatar4File.isFile() + ", 可讀: " + avatar4File.canRead());

        if (!ImageUtils.isImageValid(avatar4ImagePath)) {
            CommLogD.error("第四個(gè)頭像圖片不存在或無效: " + avatar4ImagePath);
            return null;
        }

        // 第一個(gè)頭像的位置和大小
        int avatar1X = 22; // 頭像X坐標(biāo)
        int avatar1Y = 240; // 頭像Y坐標(biāo)
        int avatar1Width = 100; // 頭像寬度
        int avatar1Height = 100; // 頭像高度

        // 先合成第一個(gè)頭像到背景圖,保存為臨時(shí)文件1
        boolean successFirst = ImageUtils.compositeAvatar(
                bgImagePath,
                avatar1ImagePath,
                tempOutputPath1,
                avatar1X,
                avatar1Y,
                avatar1Width,
                avatar1Height,
                "png" // 固定輸出為png格式,支持透明
        );

        if (!successFirst) {
            CommLogD.error("合成第一個(gè)頭像失敗");
            return null;
        }

        // 第二個(gè)頭像的位置和大小
        int avatar2X = 600; // 頭像X坐標(biāo)
        int avatar2Y = 240; // 頭像Y坐標(biāo)
        int avatar2Width = 100; // 頭像寬度
        int avatar2Height = 100; // 頭像高度
        // 再將第二個(gè)頭像合成到臨時(shí)文件1上,得到臨時(shí)文件2
        boolean successSecond = ImageUtils.compositeAvatar(
                tempOutputPath1,
                avatar2ImagePath,
                tempOutputPath2,
                avatar2X,
                avatar2Y,
                avatar2Width,
                avatar2Height,
                "png"
        );

        if (!successSecond) {
            CommLogD.error("合成第二個(gè)頭像失敗");
            // 刪除已生成的臨時(shí)文件
            File tempFile1 = new File(tempOutputPath1);
            if (tempFile1.exists()) {
                tempFile1.delete();
            }
            return null;
        }

        // 第三個(gè)頭像的位置和大小
        int avatar3X = 310; // 頭像X坐標(biāo)
        int avatar3Y = 450; // 頭像Y坐標(biāo)
        int avatar3Width = 100; // 頭像寬度
        int avatar3Height = 100; // 頭像高度

        // 將第三個(gè)頭像合成到臨時(shí)文件2上,得到臨時(shí)文件3
        boolean successThird = ImageUtils.compositeAvatar(
                tempOutputPath2,
                avatar3ImagePath,
                tempOutputPath3,
                avatar3X,
                avatar3Y,
                avatar3Width,
                avatar3Height,
                "png"
        );

        // 刪除臨時(shí)文件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("合成第三個(gè)頭像失敗");
            // 刪除臨時(shí)文件3
            File tempFile3 = new File(tempOutputPath3);
            if (tempFile3.exists()) {
                tempFile3.delete();
            }
            return null;
        }

        // 第四個(gè)頭像的位置和大?。ㄔO(shè)置為頂部居中)
        int avatar4X = 310; // 頭像X坐標(biāo)
        int avatar4Y = 35; // 頭像Y坐標(biāo)
        int avatar4Width = 100; // 頭像寬度
        int avatar4Height = 100; // 頭像高度

        // 將第四個(gè)頭像合成到臨時(shí)文件3上,得到臨時(shí)文件4
        boolean successFourth = ImageUtils.compositeAvatar(
                tempOutputPath3,
                avatar4ImagePath,
                tempOutputPath4,
                avatar4X,
                avatar4Y,
                avatar4Width,
                avatar4Height,
                "png"
        );

        // 刪除臨時(shí)文件3
        File tempFile3 = new File(tempOutputPath3);
        if (tempFile3.exists()) {
            tempFile3.delete();
        }

        if (!successFourth) {
            CommLogD.error("合成第四個(gè)頭像失敗");
            // 刪除臨時(shí)文件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); // 白色文字

        // 繪制第一個(gè)昵稱(如果有)
        if (nickname1 != null && !nickname1.isEmpty()) {
            int text1X = avatar1X; // 稍微偏移一點(diǎn)
            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("繪制第一個(gè)昵稱失敗");
                // 刪除臨時(shí)文件
                File tempFile4 = new File(tempOutputPath4);
                if (tempFile4.exists()) {
                    tempFile4.delete();
                }
                return null;
            }
            currentPath = nextPath;
        }

        // 繪制第二個(gè)昵稱(如果有)
        if (nickname2 != null && !nickname2.isEmpty()) {
            int text2X = avatar2X; // 稍微偏移一點(diǎn)
            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("繪制第二個(gè)昵稱失敗");
                // 清理文件
                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;
        }

        // 繪制第三個(gè)昵稱(如果有)
        if (nickname3 != null && !nickname3.isEmpty()) {
            int text3X = avatar3X; // 稍微偏移一點(diǎn)
            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("繪制第三個(gè)昵稱失敗");
                // 清理文件
                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;
        }

        // 繪制第四個(gè)昵稱(如果有)
        if (nickname4 != null && !nickname4.isEmpty()) {
            int text4X = avatar4X; // 稍微偏移一點(diǎn)
            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("繪制第四個(gè)昵稱失敗");
                // 清理文件
                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)) {
            // 如果沒有昵稱,直接將臨時(shí)文件重命名為輸出文件
            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);
        }

        // 刪除可能存在的臨時(shí)文件
        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("四個(gè)頭像和昵稱合成成功: " + 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) {
        // 本地文件存儲(chǔ)路徑 - 使用Windows兼容的絕對(duì)路徑格式
        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;

        // 添加詳細(xì)日志以調(diào)試路徑問題
        CommLogD.info("嘗試訪問背景圖片路徑: " + bgImagePath);
        File bgFile = new File(bgImagePath);
        CommLogD.info("背景圖片文件存在: " + bgFile.exists() + ", 是文件: " + bgFile.isFile() + ", 可讀: " + bgFile.canRead());

        // 驗(yàn)證輸入圖片是否存在
        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;
        }

        // 執(zhí)行居中合成
        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坐標(biāo)
     * @param avatarY 頭像在背景圖上的Y坐標(biāo)
     * @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")) {
                // 對(duì)于SVG格式,我們需要特殊處理
                // 這里使用簡(jiǎn)化的方式,創(chuàng)建一個(gè)占位圖像
                // 實(shí)際項(xiàng)目中可以使用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;
                }
            }
            // 創(chuàng)建Graphics2D對(duì)象進(jìn)行繪制
            Graphics2D g2d = bgImage.createGraphics();
            
            // 設(shè)置繪制質(zhì)量
            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;
        }
    }

    /**
     * 創(chuàng)建SVG占位圖像
     * 在沒有SVG庫的情況下,創(chuàng)建一個(gè)簡(jiǎn)單的占位圖像
     * 實(shí)際項(xiàng)目中可以使用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();

        // 設(shè)置背景為透明
        g2d.setComposite(AlphaComposite.Clear);
        g2d.fillRect(0, 0, width, height);
        g2d.setComposite(AlphaComposite.Src);

        // 繪制一個(gè)簡(jiǎn)單的彩色圓形作為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;
            }

            // 計(jì)算頭像居中的位置
            int bgWidth = bgImage.getWidth();
            int bgHeight = bgImage.getHeight();
            int avatarX = (bgWidth - avatarWidth) / 2;
            int avatarY = (bgHeight - avatarHeight) / 2;

            // 調(diào)用合成方法
            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 目標(biāo)寬度
     * @param targetHeight 目標(biāo)高度
     * @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;
            }

            // 創(chuàng)建縮放后的圖片
            BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, 
                    BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = resizedImage.createGraphics();
            
            // 設(shè)置縮放質(zhì)量
            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;
        }
    }

    /**
     * 獲取圖片的字節(jié)數(shù)組
     * @param imagePath 圖片路徑
     * @param format 圖片格式
     * @return 字節(jié)數(shù)組
     */
    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);
                // 對(duì)于SVG,我們只驗(yàn)證文件存在且可讀,不嘗試用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坐標(biāo)
     * @param y 文本起始Y坐標(biāo)
     * @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;
            }

            // 創(chuàng)建Graphics2D對(duì)象進(jìn)行繪制
            Graphics2D g2d = image.createGraphics();

            // 設(shè)置繪制質(zhì)量
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                    RenderingHints.VALUE_RENDER_QUALITY);

            // 設(shè)置字體和顏色
            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;
        }
    }
}

二、將一張頭像合成到背景圖中間固定的位置上

首先我們需要定義幾個(gè)固定的參數(shù)(實(shí)際項(xiàng)目中參數(shù)從以上請(qǐng)求返回值中獲?。?,還是如一所示

//調(diào)用圖像合成方法;接收合成后的圖片完整路徑
String  imgURL = CompositeImages.compositeImageToCenter(basePath,bgFileName,backName,20,20)

這個(gè)是將頭像合成到背景圖中心位置的便捷方法;返回值也是一個(gè)String類型的url圖片地址;

三、總結(jié)

我們根據(jù)自己的需要調(diào)用圖片合成類相關(guān)的方法即可返回一個(gè)String類型的url圖片地址;后期我們?nèi)绻枰祷氐氖且粋€(gè)在線可訪問的圖片鏈接,可以考慮把返回的圖片上傳到云存儲(chǔ)即可。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java整合SSM框架的圖文教程

    java整合SSM框架的圖文教程

    下面筆者就為大家分享一篇java整合SSM框架的圖文教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨筆者過來看看吧
    2017-11-11
  • Java通過接口實(shí)現(xiàn)匿名類的實(shí)例代碼

    Java通過接口實(shí)現(xiàn)匿名類的實(shí)例代碼

    這篇文章介紹了Java通過接口實(shí)現(xiàn)匿名類的實(shí)例代碼,有需要的朋友可以參考一下
    2013-10-10
  • 深入介紹Java對(duì)象初始化

    深入介紹Java對(duì)象初始化

    本文對(duì)Java如何執(zhí)行對(duì)象的初始化做一個(gè)詳細(xì)深入地介紹。有需要的小伙伴們可以參考。
    2016-07-07
  • springboot集成redis lettuce

    springboot集成redis lettuce

    目前java操作redis的客戶端有jedis跟Lettuce。本文主要介紹了springboot集成redis lettuce,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • java 中歸并排序算法詳解

    java 中歸并排序算法詳解

    這篇文章主要介紹了java 中歸并排序算法詳解的相關(guān)資料,歸并排序算法又稱為合并排序算法,是一種時(shí)間復(fù)雜度為O(N logN)的排序算法,因而其在平常生活工作中應(yīng)用非常廣泛,需要的朋友可以參考下
    2017-09-09
  • Netty的Handler鏈調(diào)用機(jī)制及如何組織詳解

    Netty的Handler鏈調(diào)用機(jī)制及如何組織詳解

    這篇文章主要為大家介紹了Netty的Handler鏈調(diào)用機(jī)制及如何組織示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • MyBatis Plus邏輯刪除和分頁插件使用詳解

    MyBatis Plus邏輯刪除和分頁插件使用詳解

    這篇文章主要介紹了MyBatis Plus之邏輯刪除和分頁插件使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Compare And Swap底層原理及代碼示例詳解

    Compare And Swap底層原理及代碼示例詳解

    這篇文章主要介紹了Compare And Swap底層原理及代碼示例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java教程之引用類型數(shù)組和繼承的意義詳解

    Java教程之引用類型數(shù)組和繼承的意義詳解

    這篇文章主要介紹了Java教程之引用類型數(shù)組和繼承的意義詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟

    Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟

    這篇文章主要介紹了Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02

最新評(píng)論

延安市| 乡城县| 江安县| 昔阳县| 富锦市| 林州市| 长子县| 明水县| 长乐市| 西乌珠穆沁旗| 大关县| 靖安县| 曲阳县| 延津县| 太仆寺旗| 屏南县| 金门县| 林甸县| 潮州市| 襄垣县| 楚雄市| 鄂托克旗| 河东区| 横峰县| 永登县| 巴林右旗| 包头市| 六安市| 黄龙县| 府谷县| 永仁县| 香港 | 屏东市| 郴州市| 同心县| 静安区| 太仆寺旗| 洪洞县| 建昌县| 江城| 玛曲县|