前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用java生成海报

利用java生成海报

作者头像
botkenni
发布2022-05-23 08:52:53
1.9K0
发布2022-05-23 08:52:53
举报
文章被收录于专栏:IT码农

控制器:

代码语言:javascript
复制
@ApiOperation("营销课题/ 生成课程海报图")
@PostMapping("generatePoster")
@ApiOperationSupport(order = 7)
public R<String> generatePoster(@RequestBody PosterDTO posterDTO) {
    return courseService.generatePoster(posterDTO);
}

service:

代码语言:javascript
复制
R<String> generatePoster(PosterDTO posterDTO);

service实现类:

代码语言:javascript
复制
/**
 * 生成海报图
 *
 * @param posterDTO 参数对象
 * @return R
 */
@Override
public R<String> generatePoster(PosterDTO posterDTO) {
    BufferedImage bufferedImage = null;
    if (null == posterDTO.getCourseDataDTO() || null == posterDTO.getTeacherMessage()) {
        return R.failMsg("课程或教授不能为空!");
    }
    //如果没有海报背景底图,返回默认图
    String posterBackground = posterDTO.getCourseDataDTO().getPosterBackground();
    if (StringUtils.isEmpty(posterBackground)) {
        //直接返回默认的资源id值
        return R.success(PosterEnum.DEFAULT_POSTER_IMG_RESOURCE_ID);
    }
    if (StringUtils.isEmpty(posterBackground.substring(posterBackground.lastIndexOf("/") + 1))) {
        //如果没有资源id,返回默认的id值
        return R.success(PosterEnum.DEFAULT_POSTER_IMG_RESOURCE_ID);
    }
    if (PosterEnum.POSTER_TYPE_CIS.equals(posterDTO.getCourseDataDTO().getType().toUpperCase())) {
        //生成cis海报
        bufferedImage = generateCisPoster(posterDTO);
    } else {
        //iemp海报固定底图
        bufferedImage = generateIempPoster(posterDTO);
    }
    //生成海报图
    if (null == bufferedImage) {
        return R.failMsg("生成海报图失败");
    }
    //图片压缩处理
    ByteArrayOutputStream out = ImageUtil.scale(bufferedImage, 0.96, "jpg");

    //课程id
    String id = posterDTO.getCourseDataDTO().getId();
    //上传图片到资源库,返回资源id
    String sourceId = attachmentUpload(out, id, bufferedImage, "jpg");

    //释放内存
    bufferedImage.getGraphics().dispose();
    return R.success(sourceId);
}
代码语言:javascript
复制
/**
 * 生成cis海报
 *
 * @param posterDTO 参数对象
 * @return BufferedImage对象
 */
private BufferedImage generateCisPoster(PosterDTO posterDTO) {
    BufferedImage im = null;
    //课程信息
    CoursePosterDataDTO courseDataDTO = posterDTO.getCourseDataDTO();
    //教授信息
    TeacherMessage teacherMessage = posterDTO.getTeacherMessage();
    //1-理科,2-工科,3-商科,4人文
    String majorType = courseDataDTO.getMajorType();
    //如果为null时,给个空避免出错
    if (StringUtils.isEmpty(majorType)) {
        majorType = "";
    }
    try {
        //海报固定底图
        String posterImgUrl = courseDataDTO.getPosterBackground();
        URL url = new URL(posterImgUrl);
        im = ImageIO.read(url);
    } catch (IOException e) {
        log.error("获取CIS海报固定底图异常{}", e.getMessage());
    }
    //不存在时返回
    if (null == im) {
        return null;
    }
    //获取字体
    ClassPathResource resource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);
    InputStream typefaceFileInputStream = null;
    try {
        typefaceFileInputStream = resource.getInputStream();
    } catch (IOException e) {
        log.error("获取写入课程英文名称的字体异常{}", e.getMessage());
    }

    Font customRegularFont = null;
    if (null != typefaceFileInputStream) {
        try {
            customRegularFont = Font.createFont(Font.TRUETYPE_FONT, typefaceFileInputStream).deriveFont(Font.BOLD, 26f);
        } catch (FontFormatException e) {
            log.error("生成字体格式异常{}", e.getMessage());
        } catch (IOException e) {
            log.error("生成字体写入异常{}", e.getMessage());
        }
    }

    String courseNameEn = courseDataDTO.getCourseNameEn();
    if (StringUtils.isNotEmpty(courseNameEn)) {
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(courseNameEn, customRegularFont, BufferedImage.TYPE_INT_RGB, 1002, 26);
        //判断多少字符控制行数
        int length = courseNameEn.length();
        if (length > widthWords) {
            //第一行
            ImageUtil.drawText(im, courseNameEn.substring(0, widthWords),
                    customRegularFont,
                    new Color(255, 255, 255), 800, 26, 116, 220, 1.0);
            //剩余部分重新计算固定行可放字符数量
            String subStr = courseNameEn.substring(widthWords);
            int newWidthWords = ImageUtil.getWidthWords(subStr, customRegularFont, BufferedImage.TYPE_INT_RGB, 1002, 26);
            int newLength = subStr.length();
            //剩余第二行(最大2行)
            if (newLength > newWidthWords) {
                newLength = newWidthWords;
            }
            ImageUtil.drawText(im, subStr.substring(0, newLength),
                    customRegularFont,
                    new Color(255, 255, 255), 800, 26, 116, 253, 1.0);
        } else {
            ImageUtil.drawText(im, courseNameEn,
                    customRegularFont,
                    new Color(255, 255, 255), 800, 26, 116, 220, 1.0);
        }
    }

    //画白线
    BufferedImage lineBi = new BufferedImage(1002, 2, BufferedImage.TYPE_INT_RGB);
    Graphics2D lineGraphics = lineBi.createGraphics();
    //设置背景颜色
    lineGraphics.setColor(new Color(255, 255, 255));
    lineGraphics.fillRect(0, 0, 1002, 2);
    ImageUtil.merge(im, lineBi, 116, 280);

    ClassPathResource typefaceMediumFileResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
    InputStream typefaceMediumFileInputStream = null;
    try {
        typefaceMediumFileInputStream = typefaceMediumFileResource.getInputStream();
    } catch (IOException e) {
        log.error("获取写入课程中文名称的字体异常{}", e.getMessage());
    }
    Font customFont = null;
    if (null != typefaceMediumFileInputStream) {
        try {
            customFont = Font.createFont(Font.TRUETYPE_FONT, typefaceMediumFileInputStream).deriveFont(Font.BOLD, 68f);
        } catch (FontFormatException e) {
            log.error("生成字体格式异常{}", e.getMessage());
        } catch (IOException e) {
            log.error("生成字体写入异常{}", e.getMessage());
        }
        try {
            typefaceMediumFileInputStream.close();
        } catch (IOException e) {
            log.error("字体流关闭异常{}", e.getMessage());
        }
    }

    String courseNameCn = courseDataDTO.getCourseNameCn();
    if (StringUtils.isNotEmpty(courseNameCn)) {
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(courseNameCn, customFont, BufferedImage.TYPE_INT_RGB, 1002, 68);
        //判断多少字符控制行数
        int length = courseNameCn.length();
        if (length > widthWords) {
            //第一行
            ImageUtil.drawText(im, courseNameCn.substring(0, widthWords),
                    customFont,
                    new Color(255, 255, 255), 800, 68, 116, 418, 1.0);
            //剩余部分重新计算固定行可放字符数量
            String subStr = courseNameCn.substring(widthWords);
            int newWidthWords = ImageUtil.getWidthWords(subStr, customFont, BufferedImage.TYPE_INT_RGB, 1002, 68);
            int newLength = subStr.length();
            //剩余第二行(最大2行)
            if (newLength > newWidthWords) {
                newLength = newWidthWords;
            }
            ImageUtil.drawText(im, subStr.substring(0, newLength),
                    customFont,
                    new Color(255, 255, 255), 800, 68, 116, 520, 1.0);
        } else {
            ImageUtil.drawText(im, courseNameCn,
                    customFont,
                    new Color(255, 255, 255), 800, 68, 116, 520, 1.0);
        }
    }

    String keywords = courseDataDTO.getKeywords();
    int width = 0;
    if (StringUtils.isNotEmpty(keywords)) {
        ClassPathResource keywordsResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream keywordsInputStream = null;
        try {
            keywordsInputStream = keywordsResource.getInputStream();
        } catch (IOException e) {
            log.error("获取写入课程关键词的字体异常{}", e.getMessage());
        }
        Font customFeaturesFont = null;
        try {
            if (null != keywordsInputStream) {
                customFeaturesFont = Font.createFont(Font.TRUETYPE_FONT, keywordsInputStream).deriveFont(Font.BOLD, 44f);
            }
        } catch (FontFormatException e) {
            log.error("生成课程关键词字体格式异常{}", e.getMessage());
        } catch (IOException e) {
            log.error("生成课程关键词字体写入异常{}", e.getMessage());
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(keywords, customFeaturesFont, BufferedImage.TYPE_INT_RGB, 1002, 20);
        //绘画横线长度
        int length = keywords.length();
        if (length > widthWords) {
            length = widthWords;
        }
        width = length * 44 + 30;
        BufferedImage strWidthBi = new BufferedImage(width, 20, BufferedImage.TYPE_INT_RGB);
        Graphics2D strWidthBiG = strWidthBi.createGraphics();
        //设置字体方便计算
        strWidthBiG.setFont(customFeaturesFont);
        //获取字符串 字符的总宽度
        int strWidth = ImageUtil.getStringLength(strWidthBiG, keywords.substring(0, length));
        //取最小的(cis增加1px,保持前后相对一致)
        int minWidth = Math.min(width, strWidth) + 1;

        //绘制颜色背景
        BufferedImage bi = new BufferedImage(minWidth, 20, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = bi.createGraphics();
        //设置背景颜色
        //graphics.setColor(new Color(194, 137, 49));
        Color keyWordsLineColor = PosterEnum.getColorByType(majorType);
        graphics.setColor(keyWordsLineColor);
        //覆盖背景(根据字体实际的宽度)
        graphics.fillRect(0, 0, minWidth, 20);
        //graphics.fillRect(0, 0, width, 20);
        ImageUtil.merge(im, bi, 116, 637);

        ImageUtil.drawText(im, keywords.substring(0, length),
                customFeaturesFont,
                new Color(255, 255, 255), 800, 44, 116, 652, 1.0);
    }

    //背景蒙层图(本地文件-区别工科,文理)
    //String majorType = courseDataDTO.getMajorType();
    //可以作为常量
    String fullName = PosterEnum.CIS_MANTLE_IMG_ONE;
    String prefixName = PosterEnum.CIS_MANTLE_IMAGE_PREFIX_NAME_PATH;
    String suffixName = PosterEnum.IMAGE_SUFFIX_NAME_PNG;
    if (StringUtils.isNotEmpty(majorType) && PosterEnum.REQUIRE_TYPE.contains(majorType)) {
        //固定文件名,用于根据不同的类型拼接上数字使用
        fullName = prefixName + majorType + suffixName;
    }
    ClassPathResource mantleFileResource = new ClassPathResource(fullName);
    try {
        InputStream mantleFileInputStream = mantleFileResource.getInputStream();
        if (null != mantleFileInputStream) {
            BufferedImage mantleImg = ImageIO.read(mantleFileInputStream);
            if (null != mantleImg) {
                ImageUtil.merge(im, mantleImg, 116, 1135);
            }
        }
    } catch (IOException e) {
        log.error("获取cis蒙层图异常{}", e.getMessage());
    }

    //头像层图(正方形)
    String face = teacherMessage.getFace();
    if (StringUtils.isNotEmpty(face)) {
        try {
            URL faceUrl = new URL(face);
            //头像切圆
            BufferedImage faceBufferedImage = null;
            try {
                faceBufferedImage = ImageIO.read(faceUrl);
                if (null != faceBufferedImage) {
                    // 返回新的图片
                    BufferedImage zoomImg = ImageUtil.zoomImg(faceBufferedImage, 214, 214);
                    if (null != zoomImg) {
                        //设置好位置,与外层的头像框无缝重叠
                        ImageUtil.merge(im, zoomImg, 150, 1027);
                    }
                }
            } catch (IOException e) {
                log.error("写入cis教授头像异常{}", e.getMessage());
            }
        } catch (MalformedURLException e) {
            log.error("获取cis教授头像异常{}", e.getMessage());
        }

        // 头像外层
        ClassPathResource faceOuterImgResource = new ClassPathResource(PosterEnum.CIS_FACE_OUTER);
        try {
            InputStream faceOuterImgStream = faceOuterImgResource.getInputStream();
            if (null != faceOuterImgStream) {
                BufferedImage faceOuterImg = ImageIO.read(faceOuterImgStream);
                if (null != faceOuterImg) {
                    ImageUtil.merge(im, faceOuterImg, 150, 1026);
                }
            }
        } catch (IOException e) {
            log.error("获取cis蒙层图异常{}", e.getMessage());
        }
    }

    //教授名字
    String teacherName = teacherMessage.getName();
    if (StringUtils.isNotEmpty(teacherName)) {
        InputStream teacherNameInputStream = null;
        ClassPathResource teacherNameResource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);
        try {
            teacherNameInputStream = teacherNameResource.getInputStream();
        } catch (IOException e) {
            log.error("获取cis教授名称字体异常{}", e.getMessage());
        }
        Font teacherNameIFont = null;
        //字体不存在就使用默认字体
        if (null != teacherNameInputStream) {
            try {
                teacherNameIFont = Font.createFont(Font.TRUETYPE_FONT, teacherNameInputStream).deriveFont(Font.BOLD, 46f);
            } catch (FontFormatException e) {
                log.error("写入教授名称字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授名称字体异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(teacherName, teacherNameIFont, BufferedImage.TYPE_INT_RGB, 670, 46);
        int length = teacherName.length();
        if (length > widthWords) {
            length = widthWords;
        }
        //教授名字
        ImageUtil.drawText(im, teacherName.substring(0, length),
                teacherNameIFont,
                new Color(255, 255, 255), 660, 46, 145, 1316, 1.0);
    }
    //教授院校
    String college = teacherMessage.getCollege();
    if (StringUtils.isNotEmpty(college)) {
        ClassPathResource collegeResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream collegeInputStream = null;
        try {
            collegeInputStream = collegeResource.getInputStream();
        } catch (IOException e) {
            log.error("获取cis教授院校字体异常{}", e.getMessage());
        }

        Font collegeFont = null;
        //字体不存在就使用默认字体
        if (null != collegeInputStream) {
            try {
                collegeFont = Font.createFont(Font.TRUETYPE_FONT, collegeInputStream).deriveFont(Font.BOLD, 36f);
            } catch (FontFormatException e) {
                log.error("写入教授院校字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授院校字体异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(college, collegeFont, BufferedImage.TYPE_INT_RGB, 670, 36);
        int length = college.length();
        if (length > widthWords) {
            length = widthWords;
        }
        ImageUtil.drawText(im, college.substring(0, length),
                collegeFont,
                new Color(255, 255, 255), 670, 36, 145, 1391, 1.0);
    }

    //教授职位
    String positionCn = teacherMessage.getPositionCn();
    if (StringUtils.isNotEmpty(positionCn)) {
        ClassPathResource positionCnResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream positionCnInputStream = null;
        try {
            positionCnInputStream = positionCnResource.getInputStream();
        } catch (IOException e) {
            log.error("获取cis教授职位字体异常{}", e.getMessage());
        }

        Font positionCnFont = null;
        if (null != positionCnInputStream) {
            try {
                positionCnFont = Font.createFont(Font.TRUETYPE_FONT, positionCnInputStream).deriveFont(Font.BOLD, 36f);
            } catch (FontFormatException e) {
                log.error("写入教授职位字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授职位字体异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(positionCn, positionCnFont, BufferedImage.TYPE_INT_RGB, 660, 36);
        int length = positionCn.length();
        if (length > widthWords) {
            length = widthWords;
        }
        ImageUtil.drawText(im, positionCn.substring(0, length),
                positionCnFont,
                new Color(255, 255, 255), 660, 36, 145, 1451, 1.0);
    }

    //文字蒙层图-课时安排图片地址
    String coursePlan = courseDataDTO.getCoursePlan();
    URL coursePlanUrl = null;
    try {
        coursePlanUrl = new URL(coursePlan);
        try {
            if (null != coursePlanUrl) {
                BufferedImage coursePlanImg = ImageIO.read(coursePlanUrl);
                if (null != coursePlanImg) {
                    ImageUtil.merge(im, coursePlanImg, 150, 1625);
                }
            }
        } catch (IOException e) {
            log.error("写入课时安排图片异常{}", e.getMessage());
        }
    } catch (MalformedURLException e) {
        log.error("获取课时安排图片异常{}", e.getMessage());
    }

    // 定义到二维码扫描的内容
    //二维码内容:固定文字颜色
    Color colorByType = PosterEnum.getColorByType(majorType);
    //Color qrCodeTextColor = new Color(194, 137, 49);
    Color qrCodeTextColor = colorByType;
    //二维码内容:时间文字颜色
    //Color qrCodeDateTextColor = new Color(194, 137, 49);
    Color qrCodeDateTextColor = colorByType;
    //画横线颜色
    //Color lineColor = new Color(194, 137, 49);
    Color lineColor = colorByType;
    String qrCode = courseDataDTO.getQrCode();
    String qrCodeDateText = courseDataDTO.getStartingDate();
    if (StringUtils.isNotEmpty(qrCodeDateText)) {
        //字符串中间增加空格,满足生成海报二维码样式
        qrCodeDateText = StringUtils.join(qrCodeDateText.replace(" ", "").split(""), " ");
    }
    BufferedImage bufferedImage = this.generateCisQRCodeImage(qrCode, qrCodeDateText, qrCodeTextColor, qrCodeDateTextColor, lineColor, colorByType.getRGB());

    if (null != bufferedImage) {
        ImageUtil.merge(im, bufferedImage, 922, 1830);
    }

    //关闭相关文件
    im.getGraphics().dispose();
    bufferedImage.getGraphics().dispose();
    return im;
}

private BufferedImage generateIempPoster(PosterDTO posterDTO) {
    BufferedImage im = null;
    //课程信息
    CoursePosterDataDTO courseDataDTO = posterDTO.getCourseDataDTO();
    //教授信息
    TeacherMessage teacherMessage = posterDTO.getTeacherMessage();
    //1-理科,2-工科,3-商科,4人文
    String majorType = courseDataDTO.getMajorType();
    //如果为null时,给个空避免出错
    if (StringUtils.isEmpty(majorType)) {
        majorType = "";
    }
    try {
        //海报固定底图
        String posterImgUrl = courseDataDTO.getPosterBackground();
        URL url = new URL(posterImgUrl);
        im = ImageIO.read(url);
    } catch (IOException e) {
        log.error("获取Iemp海报固定底图失败,请检查是否上传海报底图{}", e.getMessage());
    }
    //不存在时返回
    if (null == im) {
        return null;
    }

    //斜切蒙层图
    String fullName = PosterEnum.IEMP_MANTLE_OBLIQUE_IMG_ONE;
    String prefixName = PosterEnum.IEMP_MANTLE_OBLIQUE_IMAGE_PREFIX_NAME_PATH;
    String suffixName = PosterEnum.IMAGE_SUFFIX_NAME_PNG;
    if (StringUtils.isNotEmpty(majorType) && PosterEnum.REQUIRE_TYPE.contains(majorType)) {
        //固定文件名,用于根据不同的类型拼接上数字使用
        fullName = prefixName + majorType + suffixName;
    }
    ClassPathResource mantleObliqueFileResource = new ClassPathResource(fullName);
    try {
        InputStream mantleObliqueFileInputStream = mantleObliqueFileResource.getInputStream();
        if (null != mantleObliqueFileInputStream) {
            BufferedImage mantleObliqueImg = ImageIO.read(mantleObliqueFileInputStream);
            if (null != mantleObliqueImg) {
                ImageUtil.merge(im, mantleObliqueImg, 0, 0);
            }
        }
    } catch (IOException e) {
        log.error("获取iemp蒙层斜切图异常{}", e.getMessage());
    }

    //画白线
    BufferedImage lineBi = new BufferedImage(105, 10, BufferedImage.TYPE_INT_RGB);
    Graphics2D lineGraphics = lineBi.createGraphics();
    //设置背景颜色
    lineGraphics.setColor(new Color(255, 255, 255));
    lineGraphics.fillRect(0, 0, 110, 10);
    ImageUtil.merge(im, lineBi, 92, 392);

    ClassPathResource typefaceFileResource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);
    InputStream typefaceFileInputStream = null;
    try {
        typefaceFileInputStream = typefaceFileResource.getInputStream();
    } catch (IOException e) {
        log.error("获取写入课程中文名称的字体异常{}", e.getMessage());
    }
    Font customFont = null;
    if (null != typefaceFileInputStream) {
        try {
            customFont = Font.createFont(Font.TRUETYPE_FONT, typefaceFileInputStream).deriveFont(Font.PLAIN, 26f);
        } catch (FontFormatException e) {
            log.error("生成字体格式异常{}", e.getMessage());
        } catch (IOException e) {
            log.error("生成字体写入异常{}", e.getMessage());
        }
        try {
            typefaceFileInputStream.close();
        } catch (IOException e) {
            log.error("字体流关闭异常{}", e.getMessage());
        }
    }

    //课程英文名
    String courseNameEn = courseDataDTO.getCourseNameEn();
    if (StringUtils.isNotEmpty(courseNameEn)) {
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(courseNameEn, customFont, BufferedImage.TYPE_INT_RGB, 1060, 26);
        //判断多少字符控制行数(TODO 需要判断是否完整的英文名)
        int length = courseNameEn.length();
        //目前只考虑英文字符
        if (length > widthWords) {
            //第一行
            ImageUtil.drawText(im, courseNameEn.substring(0, widthWords),
                    customFont,
                    new Color(255, 255, 255), 800, 26, 92, 460, 1.0);
            //剩余部分重新计算固定行可放字符数量
            String subStr = courseNameEn.substring(widthWords);
            int newWidthWords = ImageUtil.getWidthWords(subStr, customFont, BufferedImage.TYPE_INT_RGB, 1060, 26);
            int newLength = subStr.length();
            //剩余第二行(最大2行)
            if (newLength > newWidthWords) {
                newLength = newWidthWords;
            }
            ImageUtil.drawText(im, subStr.substring(0, newLength),
                    customFont,
                    new Color(255, 255, 255), 800, 26, 92, 493, 1.0);
        } else {
            ImageUtil.drawText(im, courseNameEn,
                    customFont,
                    new Color(255, 255, 255), 800, 26, 92, 460, 1.0);
        }
    }

    String courseNameCn = courseDataDTO.getCourseNameCn();
    if (StringUtils.isNotEmpty(courseNameCn)) {
        ClassPathResource typefaceMediumFileResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream typefaceMediumFileInputStream = null;
        try {
            typefaceMediumFileInputStream = typefaceMediumFileResource.getInputStream();
        } catch (IOException e) {
            log.error("获取写入课程中文名称的字体异常{}", e.getMessage());
        }
        Font courseNameCnFont = null;
        if (null != typefaceMediumFileInputStream) {
            try {
                courseNameCnFont = Font.createFont(Font.TRUETYPE_FONT, typefaceMediumFileInputStream).deriveFont(Font.BOLD, 68f);
            } catch (FontFormatException e) {
                log.error("生成字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("生成字体写入异常{}", e.getMessage());
            }
            try {
                typefaceMediumFileInputStream.close();
            } catch (IOException e) {
                log.error("字体流关闭异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(courseNameCn, courseNameCnFont, BufferedImage.TYPE_INT_RGB, 1060, 26);
        //判断多少字符控制行数
        int length = courseNameCn.length();
        if (length > widthWords) {
            //第一行
            ImageUtil.drawText(im, courseNameCn.substring(0, widthWords),
                    courseNameCnFont,
                    new Color(255, 255, 255), 800, 68, 92, 620, 1.0);
            //计算固定行可放字符数量
            String subStr = courseNameCn.substring(widthWords);
            int newWidthWords = ImageUtil.getWidthWords(subStr, courseNameCnFont, BufferedImage.TYPE_INT_RGB, 1060, 26);
            int newLength = subStr.length();
            //剩余第二行(最大2行)
            if (newLength > newWidthWords) {
                newLength = newWidthWords;
            }
            ImageUtil.drawText(im, subStr.substring(0, newLength),
                    courseNameCnFont,
                    new Color(255, 255, 255), 800, 68, 92, 718, 1.0);
        } else {
            ImageUtil.drawText(im, courseNameCn,
                    courseNameCnFont,
                    new Color(255, 255, 255), 800, 68, 92, 620, 1.0);
        }
    }

    String keywords = courseDataDTO.getKeywords();
    if (StringUtils.isNotEmpty(keywords)) {
        ClassPathResource typefaceMediumFileResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream typefaceMediumFileInputStream = null;
        try {
            typefaceMediumFileInputStream = typefaceMediumFileResource.getInputStream();
        } catch (IOException e) {
            log.error("获取写入课程关键词的字体异常{}", e.getMessage());
        }
        Font customFeaturesFont = null;
        if (null != typefaceMediumFileInputStream) {
            try {
                customFeaturesFont = Font.createFont(Font.TRUETYPE_FONT, typefaceMediumFileInputStream).deriveFont(Font.BOLD, 44f);

            } catch (FontFormatException e) {
                log.error("生成课程关键词字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("生成课程关键词字体写入异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(keywords, customFeaturesFont, BufferedImage.TYPE_INT_RGB, 1060, 44);
        //绘画横线长度
        int length = keywords.length();
        if (length > widthWords) {
            length = widthWords;
        }
        int width = length * 44 + 50;
        BufferedImage strWidthBi = new BufferedImage(width, 20, BufferedImage.TYPE_INT_RGB);
        Graphics2D strWidthBiG = strWidthBi.createGraphics();
        //设置字体方便计算
        strWidthBiG.setFont(customFeaturesFont);
        //获取字符串 字符的总宽度
        int strWidth = ImageUtil.getStringLength(strWidthBiG, keywords.substring(0, length));
        //取最小的(iemp多增加20px,保持前后相对一致)
        int minWidth = Math.min(width, strWidth) + 20;

        BufferedImage bi = new BufferedImage(minWidth, 60, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = bi.createGraphics();

        //设置背景颜色
        //graphics.setColor(new Color(194, 137, 49));
        //获取关键词横线颜色
        Color keyWordsLineColor = PosterEnum.getColorByType(majorType);
        graphics.setColor(keyWordsLineColor);
        //覆盖背景(根据字体实际的宽度)
        graphics.fillRect(0, 0, minWidth, 60);
        //graphics.fillRect(0, 0, width, 60);
        ImageUtil.merge(im, bi, 92, 771);

        ImageUtil.drawText(im, keywords.substring(0, length),
                customFeaturesFont,
                new Color(255, 255, 255), 800, 44, 102, 820, 1.0);
    }

    //文字蒙层图-课时安排图片地址
    String coursePlan = courseDataDTO.getCoursePlan();
    URL coursePlanUrl = null;
    try {
        coursePlanUrl = new URL(coursePlan);
    } catch (MalformedURLException e) {
        log.error("获取课时安排图片异常{}", e.getMessage());
    }
    if (null != coursePlanUrl) {
        try {
            BufferedImage coursePlanImg = ImageIO.read(coursePlanUrl);
            if (null != coursePlanImg) {
                ImageUtil.merge(im, coursePlanImg, 92, 1056);
            }
        } catch (IOException e) {
            log.error("写入课时安排图片异常{}", e.getMessage());
        }
    }

    //底部背景蒙层图
    majorType = courseDataDTO.getMajorType();
    fullName = PosterEnum.IEMP_MANTLE_IMG_ONE;
    prefixName = PosterEnum.IEMP_IEMP_MANTLE_IMAGE_PREFIX_NAME_PATH;
    suffixName = PosterEnum.IMAGE_SUFFIX_NAME_PNG;
    if (StringUtils.isNotEmpty(majorType) && PosterEnum.REQUIRE_TYPE.contains(majorType)) {
        //固定文件名,用于根据不同的类型拼接上数字使用
        fullName = prefixName + majorType + suffixName;
    }
    ClassPathResource mantleFileResource = new ClassPathResource(fullName);
    try {
        InputStream mantleFileInputStream = mantleFileResource.getInputStream();
        if (null != mantleFileInputStream) {
            BufferedImage mantleImg = ImageIO.read(mantleFileInputStream);
            if (null != mantleImg) {
                ImageUtil.merge(im, mantleImg, 0, 1805);
            }
        }
    } catch (IOException e) {
        log.error("获取iemp蒙层图异常{}", e.getMessage());
    }

    //头像层图(正方形)
    String face = teacherMessage.getFace();
    if (StringUtils.isNotEmpty(face)) {
        try {
            URL faceUrl = new URL(face);
            //头像切圆
            BufferedImage faceBufferedImage = null;
            try {
                faceBufferedImage = ImageIO.read(faceUrl);
            } catch (IOException e) {
                log.error("写入iemp教授头像异常{}", e.getMessage());
            }
            if (null != faceBufferedImage) {
                // 返回新的图片
                BufferedImage zoomImg = ImageUtil.zoomImg(faceBufferedImage, 259, 259);
                if (null != zoomImg) {
                    //设置好位置,与外层的头像框无缝重叠
                    ImageUtil.merge(im, zoomImg, 92, 1872);
                }
            }
        } catch (MalformedURLException e) {
            log.error("获取iemp教授头像异常{}", e.getMessage());
        }

        // 头像外层
        ClassPathResource faceOuterImgResource = new ClassPathResource(PosterEnum.IEMP_FACE_OUTER);
        try {
            InputStream faceOuterImgStream = faceOuterImgResource.getInputStream();
            if (null != faceOuterImgStream) {
                BufferedImage faceOuterImg = ImageIO.read(faceOuterImgStream);
                if (null != faceOuterImg) {
                    ImageUtil.merge(im, faceOuterImg, 92, 1871);
                }
            }
        } catch (IOException e) {
            log.error("获取iemp头像外层图异常{}", e.getMessage());
        }
    }

    //教授名称
    String teacherName = teacherMessage.getName();
    if (StringUtils.isNotEmpty(teacherName)) {
        ClassPathResource teacherNameResource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);
        InputStream teacherNameInputStream = null;
        try {
            teacherNameInputStream = teacherNameResource.getInputStream();
        } catch (IOException e) {
            log.error("获取iemp教授简介字体异常{}", e.getMessage());
        }
        Font teacherNameFont = null;
        if (null != teacherNameInputStream) {
            try {
                teacherNameFont = Font.createFont(Font.TRUETYPE_FONT, teacherNameInputStream).deriveFont(Font.BOLD, 45f);
            } catch (FontFormatException e) {
                log.error("写入教授名称字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授名称字体异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(teacherName, teacherNameFont, BufferedImage.TYPE_INT_RGB, 740, 45);
        int length = teacherName.length();
        if (length > widthWords) {
            length = widthWords;
        }
        ImageUtil.drawText(im, teacherName.substring(0, length),
                teacherNameFont,
                new Color(255, 255, 255), 740, 45, 440, 1923, 1.0);
    }

    //教授职位
    String positionCn = teacherMessage.getCollege() + teacherMessage.getPositionCn();
    if (StringUtils.isNotEmpty(positionCn)) {
        ClassPathResource positionCnResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
        InputStream positionCnInputStream = null;
        try {
            positionCnInputStream = positionCnResource.getInputStream();
        } catch (IOException e) {
            log.error("获取iemp教授职位字体异常{}", e.getMessage());
        }
        Font positionCnFont = null;
        if (null != positionCnInputStream) {
            try {
                positionCnFont = Font.createFont(Font.TRUETYPE_FONT, positionCnInputStream).deriveFont(Font.BOLD, 30f);
            } catch (FontFormatException e) {
                log.error("写入教授职位字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授职位字体异常{}", e.getMessage());
            }
        }
        //计算固定行可放字符数量
        int widthWords = ImageUtil.getWidthWords(positionCn, positionCnFont, BufferedImage.TYPE_INT_RGB, 740, 30);
        //获取固定宽度的字符数
        int length = positionCn.length();
        if (length > widthWords) {
            //第一行
            ImageUtil.drawText(im, positionCn.substring(0, widthWords),
                    positionCnFont,
                    new Color(255, 255, 255), 740, 35, 440, 1967, 1.0);
            //计算固定行可放字符数量
            String subStr = positionCn.substring(widthWords);
            int newWidthWords = ImageUtil.getWidthWords(subStr, positionCnFont, BufferedImage.TYPE_INT_RGB, 740, 30);
            int newLength = subStr.length();
            //剩余第二行(最大2行)
            if (newLength > newWidthWords) {
                newLength = newWidthWords;
            }
            ImageUtil.drawText(im, subStr.substring(0, newLength),
                    positionCnFont,
                    new Color(255, 255, 255), 740, 35, 440, 2000, 1.0);
        } else {
            ImageUtil.drawText(im, positionCn,
                    positionCnFont,
                    new Color(255, 255, 255), 740, 35, 440, 1967, 1.0);
        }
    }

    //教授简介
    String introduceCn = teacherMessage.getIntroduceCn();
    if (StringUtils.isNotEmpty(introduceCn)) {
        //获取教授简介中的p标签内容
        List<String> introduceCnList = handleIntroduceCn(introduceCn, 4);
        if (!org.springframework.util.StringUtils.isEmpty(introduceCnList)) {
            ClassPathResource introduceCnResource = new ClassPathResource(PosterEnum.MEDIUM_FONT_PATH);
            InputStream introduceCnInputStream = null;
            try {
                introduceCnInputStream = introduceCnResource.getInputStream();
            } catch (IOException e) {
                log.error("获取iemp教授简介字体异常{}", e.getMessage());
            }
            Font introduceCnFont = null;
            try {
                introduceCnFont = Font.createFont(Font.TRUETYPE_FONT, introduceCnInputStream).deriveFont(Font.PLAIN, 22f);
            } catch (FontFormatException e) {
                log.error("写入教授简介字体格式异常{}", e.getMessage());
            } catch (IOException e) {
                log.error("写入教授简介字体异常{}", e.getMessage());
            }

            //总段落数
            int paragraphNum = introduceCnList.size();
            //根据段落的行数区分:按照每个段落32字符为一行
            //定义需要几个点和总共几行
            int rowNum = 0;
            //获取圆点的位置
            List<Integer> pointHeightList = new ArrayList<>();
            for (int i = 0; i < paragraphNum; i++) {
                //本次段落占几行
                int currentrowNum = 0;
                //大于32字符算2行
                if (introduceCnList.get(i).length() > 32) {
                    rowNum += 2;
                    currentrowNum += 2;
                } else {
                    rowNum++;
                    currentrowNum++;
                }
                //只取前超过4行,并且计算此时的点数
                if (rowNum > 4) {
                    break;
                }
                if (i > 0) {
                    //用上一个圆点时的行数(总行数-当前行数) +1 计算出本次的圆点的位置
                    pointHeightList.add((rowNum - currentrowNum) * 27);
                } else {
                    pointHeightList.add(0);
                }
            }

            //int length = introduceCn.length();
            //教授简介圆点
            ClassPathResource pointResource = new ClassPathResource(PosterEnum.IEMP_POINT_PATH);
            //初始行数
            int row = 0;
            int pointHeightNum = pointHeightList.size();
            for (int i = 0; i < pointHeightNum; i++) {
                //生成固定行数的点
                try {
                    InputStream pointInputStream = pointResource.getInputStream();
                    if (null != pointInputStream) {
                        BufferedImage pointImg = ImageIO.read(pointInputStream);
                        if (null != pointImg) {
                            //第1行的圆点位置,每增加一个点递增27px
                            ImageUtil.merge(im, pointImg, 440, (2037 + pointHeightList.get(i)));
                        }
                    }
                } catch (IOException e) {
                    log.error("获取iemp圆点图片异常{}", e.getMessage());
                }
                //生成行数
                introduceCn = introduceCnList.get(i);
                //计算固定行可放字符数量
                int widthWords = ImageUtil.getWidthWords(introduceCn, introduceCnFont, BufferedImage.TYPE_INT_RGB, 720, 22);
                int length = introduceCn.length();
                if (length > widthWords) {
                    //第1行文字,每增加一行递增27px
                    ImageUtil.drawText(im, introduceCn.substring(0, widthWords),
                            introduceCnFont,
                            new Color(255, 255, 255), 720, 22, 477, (2048 + row * 27), 1.0);
                    row++;
                    //计算固定行可放字符数量
                    String subStr = introduceCn.substring(widthWords);
                    int newWidthWords = ImageUtil.getWidthWords(subStr, introduceCnFont, BufferedImage.TYPE_INT_RGB, 720, 22);
                    int newLength = subStr.length();
                    //第2行文字
                    if (newLength > newWidthWords) {
                        newLength = newWidthWords;
                    }
                    ImageUtil.drawText(im, subStr.substring(0, newLength),
                            introduceCnFont,
                            new Color(255, 255, 255), 720, 22, 477, (2048 + row * 27), 1.0);
                    row++;
                } else {
                    //第1行文字,每增加一行递增27px
                    ImageUtil.drawText(im, introduceCn,
                            introduceCnFont,
                            new Color(255, 255, 255), 720, 22, 477, (2048 + row * 27), 1.0);
                    row++;
                }
            }
        }
    }
    // 定义到二维码扫描的内容
    //二维码内容:固定文字颜色
    Color qrCodeTextColor = new Color(255, 255, 255);
    //二维码内容:时间文字颜色
    Color qrCodeDateTextColor = new Color(255, 255, 255);
    //画横线颜色
    Color lineColor = new Color(255, 255, 255);
    Color rgbColor = new Color(0, 0, 0);
    //二维码内容-扫码后跳转的地址
    //String urlText = "https://pbl.neoscholar.com/#/Detail?type=0001&id=971&kgid=1496685540206972929";
    String qrCode = courseDataDTO.getQrCode();
    String qrCodeDateText = courseDataDTO.getStartingDate();
    if (StringUtils.isNotEmpty(qrCodeDateText)) {
        //字符串中间增加空格,满足生成海报二维码样式
        qrCodeDateText = StringUtils.join(qrCodeDateText.replace(" ", "").split(""), " ");
    }
    //iemp文字都是同一种-白色
    BufferedImage bufferedImage = this.generateIEMPQRCodeImage(qrCode, qrCodeDateText, qrCodeTextColor, qrCodeDateTextColor, lineColor, rgbColor.getRGB(), majorType);
    if (null != bufferedImage) {
        ImageUtil.merge(im, bufferedImage, 957, 0);
    }

    //关闭文件
    im.getGraphics().dispose();
    if (null != bufferedImage) {
        bufferedImage.getGraphics().dispose();
    }
    return im;
}
代码语言:javascript
复制
/**
 * CIS海报二维码生成及合并
 *
 * @param text           二维码跳转地址
 * @param qrCodeDateText 二维码动态时间内容
 * @return BufferedImage 图形对象
 */
@SneakyThrows
private BufferedImage generateCisQRCodeImage(String text, String qrCodeDateText, Color qrCodeTextColor, Color qrCodeDateTextColor, Color lineColor, int rgbInt) {
    //1、创建二维码
    //二维码内容:固定文字颜色:根据不同的类型传颜色值(动态获取)
    //Color qrCodeTextColor = new Color(194, 137, 49);
    //二维码内容:时间文字颜色
    //Color qrCodeDateTextColor = new Color(255, 255, 255);
    int width = 246;
    int height = 246;
    BufferedImage image = ImageUtil.createQRCodeImage(text, width, height, rgbInt);

    //2、裁剪二维码图片并支持图片指定大小缩放
    image = ImageUtil.cropImage(image, 0, 0, 182, 182, 0, 0);

    //合并处理二维码
    //固定文字
    String qrCodeText = PosterEnum.QR_CODE_TEXT;
    //二维码覆盖到背景图的x,y坐标位置
    int qrCodeX = 10;
    int qrCodeY = 10;

    //二维码英文文字参数
    int qrCodeTextWidth = 183;
    int qrCodeTextHeight = 24;
    int qrCodeTextX = 6;
    int qrCodeTextY = 222;
    int qrCodeTextFontStay = Font.BOLD;
    float qrCodeTextFontSize = 24f;
    int qrCodeTextFontFormat = Font.TRUETYPE_FONT;

    //画线
    int lineImgWidth = 188;
    int lineImgHeight = 2;
    int lineImgType = BufferedImage.TYPE_INT_RGB;
    //根据不同的类型传颜色值(动态获取)
    //Color lineColor = new Color(194, 137, 49);
    int lineFillRectX = 0;
    int lineFillRectY = 0;
    int lineFillRectWidth = 188;
    int lineFillRectHeight = 2;
    int lineImgX = 7;
    int lineImgY = 229;

    //二维码时间参数
    int qrCodeDateTextWidth = 183;
    int qrCodeDateTextHeight = 24;
    int qrCodeDateTextX = 9;
    int qrCodeDateTextY = 259;
    //int qrCodeDateTextFontStay = Font.BOLD;
    //float qrCodeDateTextFontSize = 24f;
    //二维码背景图文件路径+文件名
    ClassPathResource qrBgImgFilePathResource = new ClassPathResource(PosterEnum.CIS_QRCODE_BG_IMG);

    //二维码文字字体路径+文件名
    ClassPathResource typefaceFileResource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);

    //二维码、文字和二维码背景图等合并处理
    BufferedImage handleQRCodeImage = ImageUtil.handleQRCodeImage(image, qrBgImgFilePathResource,
            qrCodeX, qrCodeY, typefaceFileResource, qrCodeText, qrCodeTextColor, qrCodeTextFontStay, qrCodeTextFontSize,
            lineImgWidth, lineImgHeight, lineImgType, lineColor, lineFillRectX, lineFillRectY, lineFillRectWidth, lineFillRectHeight,
            lineImgX, lineImgY, qrCodeDateText, qrCodeDateTextColor,
            qrCodeDateTextWidth, qrCodeDateTextHeight, qrCodeDateTextX, qrCodeDateTextY,
            qrCodeTextWidth, qrCodeTextHeight, qrCodeTextX, qrCodeTextY, qrCodeTextFontFormat);
    return handleQRCodeImage;
}

/**
 * IEMP海报二维码生成及合并
 *
 * @param text           二维码跳转地址
 * @param qrCodeDateText 二维码动态时间内容
 * @return BufferedImage 图形对象
 */
@SneakyThrows
private BufferedImage generateIEMPQRCodeImage(String text, String qrCodeDateText, Color qrCodeTextColor, Color qrCodeDateTextColor, Color lineColor, int rgbInt, String majorType) {
    //1、创建二维码
    //二维码内容:固定文字颜色
    //Color qrCodeTextColor = new Color(255, 255, 255);
    //二维码内容:时间文字颜色
    //Color qrCodeDateTextColor = new Color(255, 255, 255);
    int width = 246;
    int height = 246;
    BufferedImage image = ImageUtil.createQRCodeImage(text, width, height, rgbInt);

    //2、裁剪二维码图片并支持图片指定大小缩放
    image = ImageUtil.cropImage(image, 0, 0, 180, 180, 5, 5);

    //合并处理二维码
    //固定文字
    String qrCodeText = PosterEnum.QR_CODE_TEXT;
    //二维码覆盖到背景图的x,y坐标位置
    int qrCodeX = 7;
    int qrCodeY = 78;
    //二维码文字参数
    int qrCodeTextWidth = 183;
    int qrCodeTextHeight = 24;
    int qrCodeTextX = 2;
    int qrCodeTextY = 33;
    int qrCodeTextFontStay = Font.BOLD;
    float qrCodeTextFontSize = 24f;
    int qrCodeTextFontFormat = Font.TRUETYPE_FONT;
    //画线
    int lineImgWidth = 188;
    int lineImgHeight = 2;
    int lineImgType = BufferedImage.TYPE_INT_RGB;
    //Color lineColor = new Color(255, 255, 255);
    int lineFillRectX = 0;
    int lineFillRectY = 0;
    int lineFillRectWidth = 188;
    int lineFillRectHeight = 2;
    int lineImgX = 3;
    int lineImgY = 40;

    //二维码时间参数
    int qrCodeDateTextWidth = 183;
    int qrCodeDateTextHeight = 24;
    int qrCodeDateTextX = 5;
    int qrCodeDateTextY = 68;
    //int qrCodeDateTextFontStay = Font.BOLD;
    //float qrCodeDateTextFontSize = 24f;
    //默认背景图
    String fullName = PosterEnum.IEMP_QRCODE_BG_IMG_ONE;
    String prefixName = PosterEnum.IEMP_IMAGE_PREFIX_NAME_PATH;
    String suffixName = PosterEnum.IMAGE_SUFFIX_NAME_PNG;
    if (StringUtils.isNotEmpty(majorType) && PosterEnum.REQUIRE_TYPE.contains(majorType)) {
        //固定文件名,用于根据不同的类型拼接上数字使用
        fullName = prefixName + majorType + suffixName;
    }
    ClassPathResource qrBgImgFilePathResource = new ClassPathResource(fullName);

    //二维码文字字体路径+文件名(linux打为jar包后无法获取路径)
    //String typefaceFilePath = this.getClass().getClassLoader().getResource("poster/font/SourceHanSansSC-Regular.otf").getPath();
    //(打为jar包后可获取路径)
    ClassPathResource typefaceFileResource = new ClassPathResource(PosterEnum.REGULAR_FONT_PATH);

    //二维码、文字和二维码背景图等合并处理
    BufferedImage handleQRCodeImage = ImageUtil.handleQRCodeImage(image, qrBgImgFilePathResource,
            qrCodeX, qrCodeY, typefaceFileResource, qrCodeText, qrCodeTextColor, qrCodeTextFontStay, qrCodeTextFontSize,
            lineImgWidth, lineImgHeight, lineImgType, lineColor, lineFillRectX, lineFillRectY, lineFillRectWidth, lineFillRectHeight,
            lineImgX, lineImgY, qrCodeDateText, qrCodeDateTextColor,
            qrCodeDateTextWidth, qrCodeDateTextHeight, qrCodeDateTextX, qrCodeDateTextY,
            qrCodeTextWidth, qrCodeTextHeight, qrCodeTextX, qrCodeTextY, qrCodeTextFontFormat);
    return handleQRCodeImage;
}

常量:

代码语言:javascript
复制
package org.neoscholar.course.release.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.awt.*;
import java.util.Arrays;
import java.util.List;

/**
 * @author Wxq
 * 海报图
 */

@Getter
@AllArgsConstructor
public enum PosterEnum {

    /**
     * 颜色值:1-理科
     */
    SCIENCE("1", new Color(3, 98, 164)),

    /**
     * 颜色值:2-工科
     */
    ENGINEERING("2", new Color(0, 57, 68)),

    /**
     * 颜色值:3-商科
     */
    COMMERCE("3", new Color(194, 137, 49)),

    /**
     * 颜色值:4-人文
     */
    HUMANITY("4", new Color(57, 37, 77));

    /**
     * 类型
     */
    private final String type;

    /**
     * 颜色
     */
    private final Color color;

    public static Color getColorByType(String type) {
        for (PosterEnum location : values()) {
            if (location.getType().equals(type)) {
                return location.getColor();
            }
        }
        return PosterEnum.getColorByType("1");
    }

    /**
     * 海报类型类型(1:CIS;2:IEMP)
     */
    /* 1:CIS海报 */
    public static final String POSTER_TYPE_CIS = "0001";
    /* 2:IEMP海报 */
    public static final String POSTER_TYPE_IEMP = "0002";

    /**
     * 默认的海报图资源id值(当未上传背景图时返回)
     */
    public static final String DEFAULT_POSTER_IMG_RESOURCE_ID = "posterError01";

    /**
     * 生成海报类型(1-理科, 2-工科, 3-商科,4-人文)
     */
    public static final List<String> REQUIRE_TYPE = Arrays.asList("1", "2", "3", "4");

    /**
     * 图片后缀
     */
    public static final String IMAGE_SUFFIX_NAME_PNG = ".png";

    /**
     * 二维码固定内容
     */
    public static final String QR_CODE_TEXT = "STARTING DATE";

    /**
     * 字体路径(SourceHanSansSC-Regular)
     */
    public static final String REGULAR_FONT_PATH = "poster/font/SourceHanSansSC-Regular.otf";

    /**
     * 字体路径(SourceHanSansSC-Medium)
     */
    public static final String MEDIUM_FONT_PATH = "poster/font/SourceHanSansSC-Medium.otf";

    /**
     * cis背景蒙层图片路径
     */
    public static final String CIS_MANTLE_IMAGE_PREFIX_NAME_PATH = "poster/bgimg/cis/cis_mantle_";

    /**
     * 头像外层:cis
     */
    public static final String CIS_FACE_OUTER = "poster/bgimg/cis/cis_face_outer.png";
    /**
     * cis二维码背景图
     */
    public static final String CIS_QRCODE_BG_IMG = "poster/bgimg/cis/cis_qrcode_bg_img.png";

    /**
     * cis背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String CIS_MANTLE_IMG_ONE = "poster/bgimg/cis/cis_mantle_1.png";

    /**
     * cis背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String CIS_MANTLE_IMG_TWO = "poster/bgimg/cis/cis_mantle_2.png";
    /**
     * cis背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String CIS_MANTLE_IMG_THREE = "poster/bgimg/cis/cis_mantle_3.png";
    /**
     * cis背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String CIS_MANTLE_IMG_FOUR = "poster/bgimg/cis/cis_mantle_4.png";

    /**
     * 头像外层:iemp
     */
    public static final String IEMP_FACE_OUTER = "poster/bgimg/iemp/iemp_face_outer.png";

    /**
     * iemp二维码背景图("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_QRCODE_BG_IMG_ONE = "poster/bgimg/iemp/iemp_qrcode_bg_img_1.png";
    /**
     * iemp二维码背景图("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_QRCODE_BG_IMG_TWO = "poster/bgimg/iemp/iemp_qrcode_bg_img_2.png";
    /**
     * iemp二维码背景图("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_QRCODE_BG_IMG_THREE = "poster/bgimg/iemp/iemp_qrcode_bg_img_3.png";
    /**
     * iemp二维码背景图("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_QRCODE_BG_IMG_FOUR = "poster/bgimg/iemp/iemp_qrcode_bg_img_4.png";

    /**
     * iemp背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_IMG_ONE = "poster/bgimg/iemp/iemp_mantle_1.png";
    /**
     * iemp背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_IMG_TWO = "poster/bgimg/iemp/iemp_mantle_2.png";
    /**
     * iemp背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_IMG_THREE = "poster/bgimg/iemp/iemp_mantle_3.png";
    /**
     * iemp背景蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_IMG_FOUR = "poster/bgimg/iemp/iemp_mantle_4.png";

    /**
     * iemp背景斜切蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_OBLIQUE_IMG_ONE = "poster/bgimg/iemp/iemp_mantle_oblique_1.png";

    /**
     * iemp背景斜切蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_OBLIQUE_IMG_TWO = "poster/bgimg/iemp/iemp_mantle_oblique_2.png";
    /**
     * iemp背景斜切蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_OBLIQUE_IMG_THREE = "poster/bgimg/iemp/iemp_mantle_oblique_3.png";
    /**
     * iemp背景斜切蒙层图片路径("1-理科,2-工科,3-商科,4人文")
     */
    public static final String IEMP_MANTLE_OBLIQUE_IMG_FOUR = "poster/bgimg/iemp/iemp_mantle_oblique_4.png";

    /**
     * 教授简介圆点
     */
    public static final String IEMP_POINT_PATH = "poster/bgimg/iemp/iemp_point.png";

    /**
     * iemp二维码背景图片路径
     */
    public static final String IEMP_IMAGE_PREFIX_NAME_PATH = "poster/bgimg/iemp/iemp_qrcode_bg_img_";
    /**
     * iemp背景蒙层图片路径
     */
    public static final String IEMP_IEMP_MANTLE_IMAGE_PREFIX_NAME_PATH = "poster/bgimg/iemp/iemp_mantle_";
    /**
     * iemp背景斜切蒙层图片路径
     */
    public static final String IEMP_MANTLE_OBLIQUE_IMAGE_PREFIX_NAME_PATH = "poster/bgimg/iemp/iemp_mantle_oblique_";
}

工具类:

代码语言:javascript
复制
package org.neoscholar.course.release.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.AttributedString;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class ImageUtil {

    /**
     * 图片合并(上下叠加)
     *
     * @param backImage 底图
     * @param image     上方图像
     * @param x         在底图的x位置
     * @param y         在底图的y位置
     * @return {@link BufferedImage}
     * @throws IOException io异常
     */
    public static BufferedImage merge(InputStream backImage, InputStream image, int x, int y) throws IOException {
        return merge(ImageIO.read(backImage), ImageIO.read(image), x, y);
    }

    /**
     * 图片合并(上下叠加)
     *
     * @param backImage 底图
     * @param image     上方图像
     * @param x         在底图的x位置
     * @param y         在底图的y位置
     * @return {@link BufferedImage}
     */
    public static BufferedImage merge(BufferedImage backImage, BufferedImage image, int x, int y) {
        Graphics backImageGraphics = null;
        try {
            backImageGraphics = backImage.getGraphics();
            backImageGraphics.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
        } finally {
            if (null != backImageGraphics) {
                backImageGraphics.dispose();
            }
        }
        return backImage;
    }

    /**
     * 往图片上绘制文字
     *
     * @param image     图片
     * @param text      文本
     * @param font      字体
     * @param color     颜色
     * @param x         文字在图片上的位置x
     * @param y         文字在图片上的位置y
     * @param widthRate 文字间距
     * @return {@link BufferedImage}
     * @throws IOException IOException
     */
    public static BufferedImage drawText(InputStream image,
                                         String text,
                                         Font font,
                                         Color color,
                                         int width,
                                         int height,
                                         int x,
                                         int y,
                                         Double widthRate) throws IOException {
        return drawText(ImageIO.read(image), text, font, color, width, height, x, y, widthRate);
    }

    /**
     * 往图片上绘制文字
     *
     * @param image     图片
     * @param text      文本
     * @param font      字体
     * @param color     颜色
     * @param x         文字在图片上的位置x
     * @param y         文字在图片上的位置y
     * @param widthRate 文字间距
     * @return {@link BufferedImage}
     */
    public static BufferedImage drawText(BufferedImage image,
                                         String text,
                                         Font font,
                                         Color color,
                                         int width,
                                         int height,
                                         int x,
                                         int y,
                                         Double widthRate) {
        Graphics2D g = null;
        try {
            g = image.createGraphics();
            g.setFont(font);
            g.setColor(color);
            AttributedString ats = new AttributedString(text);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            if (!StringUtils.isEmpty(text)) {
                ats.addAttribute(TextAttribute.FONT, font, 0, text.length());
            }
            //AttributedCharacterIterator iter = ats.getIterator();
            // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            // g.drawString(iter, x, y);
            //drawTextLineFeed(g, image, text, width, height, x, y, 1.0);
            if (StringUtils.isEmpty(widthRate)) {
                widthRate = 1.0;
            }
            drawTextLineFeed(g, image, text, width, height, x, y, widthRate);
        } finally {
            if (null != g) {
                g.dispose();
            }
        }
        return image;
    }

    /**
     * 通过递归的方式由上到下画文案
     */
    private static void drawTextLineFeed(Graphics2D g,
                                         BufferedImage base,
                                         String text,
                                         int rowWidth,
                                         int height,
                                         int loc_X,
                                         int loc_Y,
                                         Double widthRate) {
        int width = getStrWidth(base, text, widthRate);
        if (width <= rowWidth) {
            g.drawString(text, loc_X, loc_Y);
            //rateDrawString(text, loc_X, loc_Y, widthRate, g);
            return;
        }
        for (int i = 1; ; i++) {
            String str = text.substring(0, i);
            int localWidth = getStrWidth(base, str, widthRate);
            // 当字体宽度超过目标行宽,则输出当前文本
            if (localWidth >= rowWidth) {
                g.drawString(str, loc_X, loc_Y);
                //rateDrawString(text, loc_X, loc_Y, widthRate, g);
                int length = text.length();
                // 保存剩余的文本
                text = text.substring(i, length);
                break;
            }
        }
        // 画下一行
        drawTextLineFeed(g, base, text, rowWidth, height, loc_X, loc_Y + height, widthRate);
    }

    /**
     * 一个字一个字写,控制字体间距
     *
     * @param str  要添加的文字
     * @param x    坐标x
     * @param y    坐标y
     * @param rate 字体间距
     * @param g    画笔
     */
    private static void rateDrawString(String str, int x, int y, double rate, Graphics2D g) {
        String tempStr = "";
        int orgStringWight = g.getFontMetrics().stringWidth(str);
        int orgStringLength = str.length();
        int tempx = x;
        int tempy = y;
        while (str.length() > 0) {
            tempStr = str.substring(0, 1);
            str = str.substring(1, str.length());
            g.drawString(tempStr, tempx, tempy);
            tempx = (int) (tempx + (double) orgStringWight / (double) orgStringLength * rate);
        }
    }

    /**
     * 计算当前文案所占宽度
     */
    private static int getStrWidth(BufferedImage base, String str, Double widthRate) {
        char[] c = str.toCharArray();
        double width = base.getGraphics().getFontMetrics().charsWidth(c, 0, str.length()) * widthRate;
        return (int) width;
    }

    /**
     * 缩放图片尺寸
     *
     * @param image     图片
     * @param width     缩放后宽度
     * @param height    缩放后高度
     * @param forceSize 是否强制缩放
     * @return {@link BufferedImage}
     * @throws IOException IOException
     */
    public static BufferedImage resize(BufferedImage image, int width, int height, boolean forceSize) throws IOException {
        if (forceSize) {
            return Thumbnails.of(image).forceSize(width, height).asBufferedImage();
        } else {
            return Thumbnails.of(image).width(width).height(height).asBufferedImage();
        }
    }

    /**
     * rgb转换成十六进制
     *
     * @param r 第一位值
     * @param g 第二位值
     * @param b 第三位值
     * @return 十六进制值
     */
    public static String rgb2Hex(int r, int g, int b) {
        return String.format("%02X%02X%02X", r, g, b);
    }

    /**
     * 16进制转成int类型
     *
     * @param hex 十六进制值
     * @return int
     */
    public static int hex2Int(String hex) {
        return new BigInteger(hex, 16).intValue();
    }

    /**
     * RBG转int类型
     *
     * @param R 第一位颜色值
     * @param G 第二位颜色值
     * @param B 第三位颜色值
     * @return int
     */
    public static int rbg2Int(int R, int G, int B) {
        R = (R << 16) & 0x00FF0000;
        G = (G << 8) & 0x0000FF00;
        B = B & 0x000000FF;
        return 0xFF000000 | R | G | B;
    }

    public static Font getFont() {
        try {
            ClassPathResource resource = new ClassPathResource("poster/font/SourceHanSansCN-Normal.ttf");
            try (InputStream is = resource.getInputStream()) {
                Font font = Font.createFont(java.awt.Font.TRUETYPE_FONT, is).deriveFont(Font.BOLD, 20);
                return font;
            }
        } catch (Exception e) {
            log.error("getFont occur exception.", e.getMessage());
        }
        return null;
    }

    /**
     * 通过流的方式创建字体会产生很多临时文件,
     * 故: 手动复制字体文件到临时目录. 调用传文件的构造方法创建字体
     */
    private static Font getSelfFont(String filepath) {
        Font font = null;
        try {
            InputStream inputStream = ImageUtil.class.getClassLoader().getResourceAsStream(filepath);
            assert inputStream != null;
            File file = new File(filepath);
            FileUtils.copyToFile(inputStream, file);
            font = Font.createFont(Font.TRUETYPE_FONT, file);
        } catch (FontFormatException | IOException e) {
            log.error("getSelfFont occur exception.", e.getMessage());
        }
        return font;
    }

    @SneakyThrows
    public static BufferedImage createQRCodeImage(String text, int width, int height, int rgbInt) {
        // 这里是URL,扫描之后就跳转到这个界面
        int WHITE = 0xFFFFFFFF;
        // rbg转十六进制
        //String goldEnrodStr = ImageUtil.rgb2Hex(194, 137, 49);
        // 十六进制转int类型
        //int goldEnrod = ImageUtil.hex2Int(goldEnrodStr);
        // rbg转int类型
        //int black = ImageUtil.rbg2Int(R, G, B);
        // 设置编码,防止中文乱码
        Hashtable<EncodeHintType, Object> ht = new Hashtable<EncodeHintType, Object>();
        ht.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 设置二维码参数(编码内容,编码类型,图片宽度,图片高度,格式)
        if (StringUtils.isEmpty(text)) {
            text = " ";
        }
        BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, ht);
        int b_width = bitMatrix.getWidth();
        int b_height = bitMatrix.getHeight();
        //创建一个图片缓冲区存放二维码图片
        BufferedImage image = new BufferedImage(b_width, b_height, BufferedImage.TYPE_3BYTE_BGR);
        // 画文字到新的面板
        for (int x = 0; x < b_width; x++) {
            for (int y = 0; y < b_height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? rgbInt : WHITE);
            }
        }
        return image;
    }

    /**
     * 裁剪图片并支持图片指定大小缩放
     *
     * @param bufferedImage    原始图片
     * @param scaleImgX        缩放起始x坐标值
     * @param scaleImgY        缩放起始y坐标值
     * @param scaleImgWidth    缩放宽度
     * @param scaleImgHeight   缩放高度
     * @param reserveImgWidth  预留二维码内边距宽度
     * @param reserveImgHeight 预留二维码内边距高度
     * @return BufferedImage对象
     */
    public static BufferedImage cropImage(BufferedImage bufferedImage, int scaleImgX, int scaleImgY, int scaleImgWidth, int scaleImgHeight, int reserveImgWidth, int reserveImgHeight) {
        /*
         * 原始的二维码图片无论怎么设置都是有内边距的,但是二维码是双色图,最外部的就是需要切剪掉的颜色。所以我们取到x,y 轴  = 0的第一个色值
         * 然后逐次循环到左上方码眼位置。这个码眼位置就是我们需要切割的起始位置。x,y轴循环的次数就是我们需要切割的图片的宽高的二分之一。
         * 目前二维码创建都是正方形的,省略了计算不同宽高的复杂过程
         */
        int cropColor = bufferedImage.getRGB(0, 0);
        int imageWidth = bufferedImage.getWidth();
        int imageHeight = bufferedImage.getHeight();
        int width = 0;
        int height = 0;
        label:
        for (int i = 0; i < imageWidth; i++) {
            for (int j = 0; j < imageHeight; j++) {
                if (bufferedImage.getRGB(i, j) != cropColor) {
                    width = i;
                    height = j;
                    break label;
                }
            }
        }
        //多预留1px-裁剪图片时留下1像素点的位置,避免光秃秃的不太好看,根据需要进行保留像素大小
        width -= reserveImgWidth;
        height -= reserveImgHeight;
        int cropWidth = bufferedImage.getWidth() - (width * 2);
        int cropHeight = bufferedImage.getHeight() - (height * 2);
        //bufferedImage尺寸不同截图二维码内容部分的大小会不一样,比如bufferedImage宽高245和246截图的大小相差很大,因此需要计算好二维码内容部分大小,然后进行缩放处理,建议进行缩小,保证二维码清晰度
        bufferedImage = bufferedImage.getSubimage(width, height, cropWidth, cropHeight);
        //在内存里创建一个特定大小的图像缓冲区
        BufferedImage zoomImg = new BufferedImage(scaleImgWidth, scaleImgHeight, BufferedImage.TYPE_INT_RGB);
        //缩放图片
        zoomImg.getGraphics().drawImage(bufferedImage, scaleImgX, scaleImgY, scaleImgWidth, scaleImgHeight, null);
        return zoomImg;
    }

    @SneakyThrows
    public static BufferedImage handleQRCodeImage(BufferedImage image, ClassPathResource qrBgImgFileResource,
                                                  int qrCodeX, int qrCodeY,
                                                  ClassPathResource typefaceFileResource, String qrCodeText, Color qrCodeTextColor,
                                                  int qrCodeTextFontStay, float qrCodeTextFontSize,
                                                  int lineImgWidth, int lineImgHeight, int lineImgType,
                                                  Color lineColor, int lineFillRectX, int lineFillRectY, int lineFillRectWidth, int lineFillRectHeight,
                                                  int lineImgX, int lineImgY, String qrCodeDateText, Color qrCodeDateTextColor,
                                                  int qrCodeDateTextWidth, int qrCodeDateTextHeight, int qrCodeDateTextX, int qrCodeDateTextY,
                                                  int qrCodeTextWidth, int qrCodeTextHeight, int qrCodeTextX, int qrCodeTextY, int qrCodeTextFontFormat) {
        // 设置自定义内容:自定义文本描述放在二维码背景图上
        //qrBgImgFilePath = this.getClass().getClassLoader().getResource(qrBgImgFilePath).getPath();
        //File file = new File(qrBgImgFilePath);
        InputStream qrBgImgFileInputStream = qrBgImgFileResource.getInputStream();
        BufferedImage bgImage = ImageIO.read(qrBgImgFileInputStream);
        if (null == bgImage) {
            return null;
        }
        ImageUtil.merge(bgImage, image, qrCodeX, qrCodeY);

        //英文固定文字
        //typefaceFilePath = this.getClass().getClassLoader().getResource(typefaceFilePath).getPath();
        //File typefaceFile = new File(typefaceFilePath);
        InputStream typefaceFileInputStream = typefaceFileResource.getInputStream();
        Font qrCodeFont = Font.createFont(qrCodeTextFontFormat, typefaceFileInputStream).deriveFont(qrCodeTextFontStay, qrCodeTextFontSize);
        ImageUtil.drawText(bgImage, qrCodeText,
                qrCodeFont, qrCodeTextColor, qrCodeTextWidth, qrCodeTextHeight, qrCodeTextX, qrCodeTextY, 1.0);

        //画线
        BufferedImage lineBi = new BufferedImage(lineImgWidth, lineImgHeight, lineImgType);
        Graphics2D lineGraphics = lineBi.createGraphics();
        //设置背景颜色
        lineGraphics.setColor(lineColor);
        lineGraphics.fillRect(lineFillRectX, lineFillRectY, lineFillRectWidth, lineFillRectHeight);
        ImageUtil.merge(bgImage, lineBi, lineImgX, lineImgY);

        //时间文字(和文字内容相同,可扩展使用自己的字体)
        ImageUtil.drawText(bgImage, qrCodeDateText,
                qrCodeFont,
                qrCodeDateTextColor, qrCodeDateTextWidth, qrCodeDateTextHeight, qrCodeDateTextX, qrCodeDateTextY, 1.0);

        qrBgImgFileInputStream.close();
        typefaceFileInputStream.close();
        lineBi.getGraphics().dispose();
        bgImage.getGraphics().dispose();
        return bgImage;
    }

    /**
     * 根据最小边截图正方形后缩放到指定大小图片
     *
     * @param faceBufferedImage 图片对象
     * @param scaleImgWidth     缩放的宽
     * @param scaleImgHeight    缩放的高
     * @return BufferedImage
     */
    public static BufferedImage zoomImg(BufferedImage faceBufferedImage, int scaleImgWidth, int scaleImgHeight) {
        //固定到215*215-头像背景图外层218,尺寸计算
        int faceWidth = faceBufferedImage.getWidth();
        int faceHeight = faceBufferedImage.getHeight();
        //原图小于目标图片的宽高
        double widthScale = 1.0;
        double heightScale = 1.0;
        if (faceWidth < scaleImgWidth) {
            widthScale = (double) scaleImgWidth / faceWidth;
        }
        if (faceHeight < scaleImgHeight) {
            heightScale = (double) scaleImgHeight / faceHeight;
        }
        //判断2者比例大的进行放大原图,大于或小于才进行缩放,否则不变
        double scale = heightScale;
        if (new BigDecimal(widthScale).compareTo(new BigDecimal(heightScale)) > 0) {
            scale = widthScale;
        }
        if (new BigDecimal(scale).compareTo(new BigDecimal("1.0")) > 0) {
            faceBufferedImage = scale(faceBufferedImage, scale, true);
        }
        int width = faceBufferedImage.getWidth();
        int height = faceBufferedImage.getHeight();
        BufferedImage resultImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = resultImg.createGraphics();
        Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, width, height);
        // 使用 setRenderingHint 设置抗锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        resultImg = g.getDeviceConfiguration().createCompatibleImage(width, height,
                Transparency.TRANSLUCENT);
        g = resultImg.createGraphics();
        g.setClip(shape);
        g.drawImage(faceBufferedImage, 0, 0, null);
        g.dispose();
        //在内存里创建一个特定大小的图像缓冲区
        BufferedImage zoomImg = new BufferedImage(scaleImgWidth, scaleImgHeight, BufferedImage.TYPE_INT_RGB);
        //缩放图片
        zoomImg.getGraphics().drawImage(resultImg, 0, 0, scaleImgWidth, scaleImgHeight, null);

        //缩放后的头像画圆
        int zoomImgSize = width > height ? height : width;
        BufferedImage newZoomImg = new BufferedImage(scaleImgWidth, scaleImgHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D newZoomImgG = newZoomImg.createGraphics();
        Ellipse2D.Double newZoomImgShape = new Ellipse2D.Double(0, 0, scaleImgWidth, scaleImgHeight);
        // 使用 setRenderingHint 设置抗锯齿
        newZoomImgG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        newZoomImg = newZoomImgG.getDeviceConfiguration().createCompatibleImage(zoomImgSize, zoomImgSize,
                Transparency.TRANSLUCENT);
        newZoomImgG = newZoomImg.createGraphics();
        // 使用 setRenderingHint 设置抗锯齿
        newZoomImgG.setClip(newZoomImgShape);
        newZoomImgG.drawImage(zoomImg, 0, 0, null);
        newZoomImgG.dispose();
        return newZoomImg;
    }

    /**
     * 缩放图片
     *
     * @param scale 缩放比例
     * @param flag  缩放选择:true 放大; false 缩小;
     */
    public static BufferedImage scale(BufferedImage bufferedImage, double scale, boolean flag) {
        // 图片宽度
        double width = bufferedImage.getWidth();
        // 图片高度
        double height = bufferedImage.getHeight();
        if (flag) {
            width = width * scale;
            height = height * scale;
        } else {
            // 缩小
            width = width / scale;
            height = height / scale;
        }
        int newWidth = (int) Math.ceil(width);
        int newHeight = (int) Math.ceil(height);
        //Image image = bufferedImage.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
        BufferedImage tagBufferedImage = new BufferedImage(newWidth, newHeight, bufferedImage.getType());
        Graphics g = tagBufferedImage.getGraphics();
        // 绘制处理后的图片
        //g.drawImage(image, 0, 0, null);//使用image对象写入
        g.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null);//直接使用原来图进行处理
        g.dispose();
        // 输出到文件
        return tagBufferedImage;
    }

    /**
     * 返回字符数量
     *
     * @param text                字符串
     * @param multipleUpperCaseEn 英文大写倍数
     * @param multipleLowercaseEn 英文小写倍数
     * @return int
     */
    public static int strNum(String text, float multipleUpperCaseEn, float multipleLowercaseEn) {
        if (StringUtils.isEmpty(text)) {
            return 0;
        }
        float length = 0f;
        for (char c : text.toCharArray()) {
            if (isContainChinese(String.valueOf(c))) {
                //中文算1个
                length++;
            } else {
                //判断英文大小写,根据比例计算个数
                if (isUpperCase(c)) {
                    length += (1 / multipleUpperCaseEn);
                } else {
                    length += (1 / multipleLowercaseEn);
                }
            }
        }
        return (int) Math.floor(length);
    }

    /**
     * 返回指定长度的字符串
     *
     * @param text                字符串
     * @param needLengthStart     需要截取的起始位置
     * @param needLengthEnd       需要截取的截止位置
     * @param multipleUpperCaseEn 大写英文的倍数
     * @param multipleLowercaseEn 小写英文的倍数
     * @return 截取后的字符串
     */
    public static String needString(String text, int needLengthStart, int needLengthEnd, float multipleUpperCaseEn, float multipleLowercaseEn) {
        if (StringUtils.isEmpty(text)) {
            return "";
        }
        float length = 0f;
        for (char c : text.toCharArray()) {
            if (isContainChinese(String.valueOf(c))) {
                //中文算1个
                length++;
            } else {
                //判断英文大小写,根据比例计算个数
                if (isUpperCase(c)) {
                    length += multipleUpperCaseEn;
                } else {
                    length += multipleLowercaseEn;
                }
            }
            if (needLengthEnd <= length) {
                length = needLengthEnd;
                break;
            }
        }
        //强制转换,暂不考虑丢失精度问题
        return text.substring(needLengthStart, (int) Math.floor(length));
    }

    /**
     * 是否属于中文字符
     *
     * @param str 字符
     * @return boolean
     */
    public static boolean isContainChinese(String str) {
        // 检测是否包含中文
        String regEx = "[\\u4E00-\\u9FA5]+";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断英文大写
     *
     * @param c 字符
     * @return boolean
     */
    public static boolean isUpperCase(char c) {
        return c >= 65 && c <= 90;
    }

    /**
     * 根据字体获取内容的总宽度
     *
     * @param g   Graphics2D
     * @param str 字符串
     * @return int
     */
    public static int getStringLength(Graphics2D g, String str) {
        char[] strChar = str.toCharArray();
        int strWidth = g.getFontMetrics().charsWidth(strChar, 0, str.length());
        g.dispose();
        return strWidth;
    }

    /**
     * 根据字体计算固定宽度的一行可放字符数量
     *
     * @param str        字符
     * @param font       文字font
     * @param imageType  需要生成的图片类型
     * @param lineWidth  固定宽度
     * @param lineHeight 固定高度
     * @return 返回的可放字符数量
     */
    public static int getWidthWords(String str, Font font, int imageType, int lineWidth, int lineHeight) {
        //计算固定行可放字符数量
        BufferedImage im = new BufferedImage(lineWidth, lineHeight, imageType);
        Graphics2D g = im.createGraphics();
        //设置字体方便计算
        g.setFont(font);
        char[] strCharArray = str.toCharArray();
        int strCharArrayLength = strCharArray.length;
        int strWidth = 0;
        int wordNum = 1;
        for (int i = 0; i < strCharArrayLength; i++) {
            String charStr = String.valueOf(strCharArray[i]);
            strWidth += g.getFontMetrics().charsWidth(charStr.toCharArray(), 0, charStr.length());
            if (strWidth > lineWidth) {
                break;
            }
            wordNum = i + 1;
        }
        g.dispose();
        return wordNum;
    }

    /**
     * 压缩图片
     *
     * @param bufferedImage BufferedImage对象
     * @param quality       压缩的程度(0-1越小压缩的比列越大)
     * @param suffix        后缀
     * @return ByteArrayOutputStream
     */
    public static ByteArrayOutputStream scale(BufferedImage bufferedImage, double quality, String suffix) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            Thumbnails.of(bufferedImage).scale(1f).outputQuality(quality).outputFormat(suffix).toOutputStream(out);
            try {
                out.close();
            } catch (IOException e) {
                log.error("关闭输出流失败{}", e.getMessage());
            }
        } catch (IOException e) {
            log.error("压缩图片处理失败{}", e.getMessage());
        }
        return out;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图片处理
图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档