使用Java生成图片——功能强大的图形工具

一、引言

        Java是一种广泛使用的编程语言,它具有强大的功能和卓越的性能,可以用来创建各种类型的应用程序,包括生成图像。在Java中,可以使用Java的内置类库和第三方库来生成图片。下面是一篇关于Java生成图片的介绍文章。

二、具体代码

PrescriptionPictureGenerateUtil.java

package com.sinohealth.sdc.ehr.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.google.common.collect.Lists;
import com.sinohealth.commons.utils.StringPool;
import com.sinohealth.commons.utils.StringUtils;
import com.sinohealth.sdc.ehr.dto.PrescriptionInfoDTO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;

/**
 * @Title: PrescriptionPictureGenerateUtil
 * @Package com.sinohealth.sdc.ehr.util
 * @Copyright: Copyright (C) SinoHealth Co. Ltd, All Rights Reserved
 * @Author xiao.xl 2020/9/27 11:53
 * @Description: 处方图片生成工具
 */
@Slf4j
public class PrescriptionPictureGenerateUtil {

    /**
     * 签名图片最大宽度
     */
    private static final int SIGNAL_MAX_WIDTH = 100;

    /**
     * 签名图片最大高度
     */
    private static final int SIGNAL_MAX_HEIGHT = 60;


    /**
     * 处方笺图片宽
     */
    private static final int PIC_WIDTH = 700;

    /**
     * 处方笺图片高
     */
    private static final int PIC_HEIGHT = 1000;

    /**
     * 顶部与底部留白
     */
    private static final int MARGIN_Y = 30;

    /**
     * 左右留白
     */
    private static final int MARGIN_X = 20;

    /**
     * 行高
     */
    private static final int LINE_HEIGHT = 10;

    /**
     * 处方笺图片字体
     */
    private static final String FONT_NAME = "方正兰亭黑简体";

    /**
     * 画布一行设置列数
     */
    private static final int COLUMNS = 24;

    /**
     * 标题字体大小
     */
    public static final int FONT_SIZE_TITLE = 20;

    /**
     * 正文字体大小
     */
    public static final int FONT_SIZE_BODY = 15;

    /**
     * Rp字体大小
     */
    public static final int FONT_SIZE_RP = 25;


    /**
     * 生成图片后缀
     */
    private static final String file_suffix = "jpg";


    /**
     * 处方笺字体存放路径
     */
    private static final String FONT_LOCATION = "font/fzlthjw.ttf";

    /**
     * 图片绘制使用字体
     */
    private static Font FONT;

    static {
        InputStream inputStream = null;
        try {
            ClassPathResource resource = new ClassPathResource(FONT_LOCATION);
            inputStream = resource.getInputStream();
            FONT = Font.createFont(Font.TRUETYPE_FONT, inputStream);
        } catch (Exception e) {
            log.error("加载自定义字体<{}>失败", FONT_LOCATION, e);
            FONT = new Font(FONT_NAME, Font.PLAIN, 15);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                }
            }
        }
    }

    @Getter
    @Setter
    public static class Margin {
        /**
         * 上
         */
        private int top;

        /**
         * 底
         */
        private int bottom;

        /**
         * 左
         */
        private int left;

        /**
         * 右
         */
        private int right;

        public Margin(int top, int bottom, int left, int right) {
            this.top = top;
            this.bottom = bottom;
            this.left = left;
            this.right = right;
        }
    }

    @Getter
    @Setter
    public static class Point {
        /**
         * X
         */
        private int x;

        /**
         * Y
         */
        private int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public void offsetY(int offsetY, boolean negative) {
            if (negative) {
                this.y -= offsetY;
            } else {
                this.y += offsetY;
            }
        }

        public void offsetX(int offsetX) {
            this.x += offsetX;
        }
    }

    /**
     * 新建图片
     *
     * @param width     图片宽
     * @param height    图片高
     * @param imageType 图片类型
     * @return 图片实体
     * @Comment comment by liming.wang 2020/11/24 16:30
     */
    private static BufferedImage createImage(int width, int height, int imageType) {
        // 新建图片
        return new BufferedImage(width, height, imageType);
    }

    /**
     * 绘制背景
     *
     * @param image    画布
     * @param graphics 画笔
     * @param bgColor  背景颜色
     * @Comment comment by liming.wang 2020/11/24 16:30
     */
    private static void fillBackground(BufferedImage image, Graphics graphics, Color bgColor) {
        int width = image.getWidth();
        int height = image.getHeight();
        graphics.setClip(0, 0, width, height);
        // 设置画笔颜色
        graphics.setColor(bgColor);
        // 绘制背景
        graphics.fillRect(0, 0, width, height);
    }

    /**
     * 设置画笔颜色和字样
     *
     * @param graphics  画笔
     * @param color     颜色
     * @param fontSize  字体大小
     * @param fontStyle 字体类型
     * @Comment comment by liming.wang 2020/11/25 8:41
     */
    private static void setGraphics(Graphics2D graphics, Color color,
                                    int fontSize, int fontStyle) {
        graphics.setFont(FONT.deriveFont(fontStyle, fontSize));
        //消除文字锯齿
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        graphics.setColor(color);
    }

    /**
     * 绘制空行
     *
     * @param point    坐标
     * @param number   空行数
     * @param negative 是否从底部开始绘制
     * @Comment comment by liming.wang 2020/11/24 19:01
     */
    private static void drawBlankLine(Point point, int number, boolean negative) {
        point.offsetY(number * LINE_HEIGHT, negative);
    }

    /**
     * 画水平线
     *
     * @param image    画布
     * @param graphics 画笔
     * @param point    坐标
     * @param margin   间距
     * @param negative 是否从底部开始绘制
     * @Comment comment by liming.wang 2020/11/25 8:40
     */
    private static void drawHorizontalLine(BufferedImage image, Graphics graphics,
                                           Point point, Margin margin, boolean negative) {
        int x = point.getX();
        int y = point.getY();
        int x2 = image.getWidth() - margin.getRight();
        graphics.drawLine(x, y, x2, y);
        int height = (int) (graphics.getFontMetrics().getLineMetrics("", graphics).getHeight());
        point.offsetY(LINE_HEIGHT + height, negative);
    }

    /**
     * 画下水平线
     *
     * @param image    画布
     * @param graphics 画笔
     * @param point    坐标
     * @param margin   间距
     * @param negative 是否从底部开始绘制
     * @Comment comment by liming.wang 2020/11/25 8:40
     */
    private static void drawDownHorizontalLine(BufferedImage image, Graphics graphics,
                                               Point point, Margin margin, boolean negative) {
        int height = (int) (graphics.getFontMetrics().getLineMetrics("", graphics).getHeight());
        int x = point.getX();
        int y = point.getY();
        y = (y - height + LINE_HEIGHT / 2);
        int x2 = image.getWidth() - margin.getRight();
        graphics.drawLine(x, y, x2, y);
        point.offsetY(LINE_HEIGHT + height, negative);
    }

    /**
     * 拆分绘制内容
     *
     * @param graphics 画笔
     * @param content  绘制内容
     * @param width    可用宽度
     * @return 拆分后内容
     * @Comment comment by liming.wang 2020/11/25 10:39
     */
    private static List<String> splitContent(Graphics graphics, String content, int width) {
        int realWidth = width - LINE_HEIGHT;
        int tempWidth = 0;
        FontMetrics fontMetrics = graphics.getFontMetrics();
        List<String> contents = Lists.newLinkedList();
        StringBuilder sb = new StringBuilder();
        for (int index = 0; index < content.length(); index++) {
            String ch = content.charAt(index) + "";
            Rectangle2D rectangle2D = fontMetrics.getStringBounds(ch, graphics);
            int chWidth = (int) rectangle2D.getWidth();
            tempWidth += chWidth;
            if (tempWidth >= realWidth) {
                tempWidth = 0;
                contents.add(sb.toString());
                sb = new StringBuilder(ch);
                continue;
            }
            sb.append(ch);
        }
        if (StringUtils.isNotBlank(sb.toString())) { contents.add(sb.toString()); }
        return contents;
    }

    /**
     * 绘制图片内容
     *
     * @param graphics 画笔
     * @param point    绘制开始坐标
     * @param layout   内容布局
     */
    private static void drawImage(Graphics graphics, Point point, Layout layout) {
        BufferedImage image = layout.getImage();
        if (image == null) { return; }
        int width = SIGNAL_MAX_WIDTH;
        int height = SIGNAL_MAX_HEIGHT;
        graphics.drawImage(image.getScaledInstance(width, height, Image.SCALE_SMOOTH), point.getX(), point.getY() - height / 2, width, height, Color.RED, null);
    }

    /**
     * 绘制处方内容
     *
     * @param image    画布
     * @param graphics 画笔
     * @param point    坐标
     * @param margin   间隔
     * @param layouts  内容布局
     * @Comment comment by liming.wang 2020/11/25 8:41
     */
    private static void drawString(BufferedImage image, Graphics graphics,
                                   Point point, Margin margin, boolean negative,
                                   Layout... layouts) {
        // 内容为空
        if (layouts == null || layouts.length <= 0) { return; }
        // 画布的宽
        int width = image.getWidth() - (margin.getLeft() + margin.getRight());
        int x = point.getX();
        int offsetY = 0;
        for (Layout layout : layouts) {
            String content = layout.getContent();
            if (StringUtils.isBlank(content)) { content = StringPool.EMPTY; }
            Integer col = layout.getCol();
            if (col == null || col < 0) { continue; }
            int colWidth = (col * width) / COLUMNS;
            Rectangle2D rectangle2D = graphics.getFontMetrics().getStringBounds(content, graphics);
            int layoutHeight = (int) rectangle2D.getHeight();
            int layoutWidth = (int) rectangle2D.getWidth();
            // 不需要换行
            Align align = layout.getAlign();
            if (colWidth > layoutWidth) {
                if (StringUtils.isNotBlank(content)) {
                    int tempX = x;
                    if (align == Align.CENTER) { tempX += (colWidth - layoutWidth) / 2; }
                    if (align == Align.RIGHT) { tempX += (colWidth - layoutWidth); }
                    graphics.drawString(content, tempX, point.getY());
                } else if (layout.getImage() != null) {
                    Point newPoint = new Point(x, point.getY());
                    drawImage(graphics, newPoint, layout);
                }
                if (offsetY == 0) { offsetY = point.getY() + LINE_HEIGHT + layoutHeight; }
            }
            // 需要换行
            else {
                List<String> contentList = splitContent(graphics, content, colWidth);
                Point newPoint = new Point(x, point.getY());
                contentList.forEach(item -> {
                    Layout tempLayout = new Layout(item, align, layout.getCol());
                    drawString(image, graphics, newPoint, margin, negative, tempLayout);
                });
                if (newPoint.getY() > offsetY) { offsetY = newPoint.getY(); }
            }
            x += colWidth;
        }
        // 设置Y
        point.offsetY(offsetY - point.getY(), negative);
    }

    public static void main(String[] args) throws Exception {
        // 新建图片
        BufferedImage image = createImage(PIC_WIDTH, PIC_HEIGHT, BufferedImage.TYPE_INT_BGR);
        // 创建画笔
        Graphics2D graphics = image.createGraphics();
        // 初始化背景色
        fillBackground(image, graphics, Color.WHITE);
        // 定义margin
        Margin margin = new Margin(MARGIN_Y, MARGIN_Y, MARGIN_X, MARGIN_X);
        // 初始化坐标
        Point point = new Point(margin.getLeft(), margin.getTop());

        // 绘制空行
        drawBlankLine(point, 5, false);
        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_TITLE, Font.BOLD);
        // 绘制处方头
        String content = "珠江新城医院  处方笺";
        drawString(image, graphics, point, margin, false, new Layout(content, Align.CENTER, COLUMNS));
        // 绘制空行
        drawBlankLine(point, 3, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_BODY, Font.PLAIN);
        // 绘制横线
        drawHorizontalLine(image, graphics, point, margin, false);
        // 绘制患者信息
        drawString(image, graphics, point, margin, false, patientLayouts());
        // 绘制空行
        drawBlankLine(point, 1, false);
        // 绘制病例信息
        drawString(image, graphics, point, margin, false, caseLayouts());
        // 绘制空行
        drawBlankLine(point, 1, false);
        // 绘制诊断
        drawString(image, graphics, point, margin, false, diagnoseLayouts());
        // 绘制横线
        drawDownHorizontalLine(image, graphics, point, margin, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_RP, Font.BOLD);
        // 绘制空行
        drawBlankLine(point, 2, false);
        // 绘制Rp
        drawString(image, graphics, point, margin, false, rpLayouts());
        // 绘制空行
        drawBlankLine(point, 2, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_BODY, Font.PLAIN);
        for (int index = 1; index <= 5; index++) {
            // 绘制药品信息
            drawString(image, graphics, point, margin, false, drugLayouts(index));
            // 绘制用法
            drawString(image, graphics, point, margin, false, usageLayouts());
            // 绘制空行
            drawBlankLine(point, 1, false);
        }
        // 绘制空行
        drawBlankLine(point, 2, false);
        // 处方药品结束
        drawString(image, graphics, point, margin, false, new Layout("(以下空白)", Align.CENTER, COLUMNS));

        // 重置坐标
        point.setY(image.getHeight() - margin.getBottom());
        // 绘制空行
        drawBlankLine(point, 2, true);
        // 底部签名信息
        drawString(image, graphics, point, margin, true, signLayouts());
        // 绘制空行
        drawBlankLine(point, 2, true);
        // 底部横线
        drawHorizontalLine(image, graphics, point, margin, true);
        // 设置画笔
        setGraphics(graphics, Color.RED, FONT_SIZE_BODY, Font.PLAIN);
        // 设置处方有效期
        drawString(image, graphics, point, margin, false, new Layout("该处方有效期3天", Align.CENTER, COLUMNS));

        // 销毁画笔,结束绘制
        graphics.dispose();
        System.out.println(FileUtil.writeFromStream(imageInputStream(image), "test.jpg"));
    }

    private static Layout[] patientLayouts() {
        Layout[] layouts = new Layout[6];
        layouts[0] = new Layout("姓名:", Align.RIGHT, 3);
        layouts[1] = new Layout("王大大", Align.LEFT, 5);
        layouts[2] = new Layout("性别:", Align.RIGHT, 2);
        layouts[3] = new Layout("男", Align.LEFT, 5);
        layouts[4] = new Layout("年龄:", Align.RIGHT, 3);
        layouts[5] = new Layout("27", Align.LEFT, 6);
        return layouts;
    }

    private static Layout[] caseLayouts() {
        Layout[] layouts = new Layout[6];
        layouts[0] = new Layout("病历号:", Align.RIGHT, 3);
        layouts[1] = new Layout("ZXY12083012", Align.LEFT, 5);
        layouts[2] = new Layout("科室:", Align.RIGHT, 2);
        layouts[3] = new Layout("全科诊室", Align.LEFT, 5);
        layouts[4] = new Layout("开具日期:", Align.RIGHT, 3);
        layouts[5] = new Layout(DateUtil.now(), Align.LEFT, 6);
        return layouts;
    }

    private static Layout[] diagnoseLayouts() {
        Layout[] layouts = new Layout[2];
        layouts[0] = new Layout("诊断:", Align.RIGHT, 3);
        layouts[1] = new Layout("感冒,发烧,头痛....", Align.LEFT, 21);
        return layouts;
    }

    private static Layout[] rpLayouts() {
        Layout[] layouts = new Layout[1];
        layouts[0] = new Layout("Rp", Align.LEFT, 24);
        return layouts;
    }

    private static Layout[] drugLayouts(int index) {
        Layout[] layouts = new Layout[4];
        layouts[0] = new Layout(index + ". ", Align.RIGHT, 1);
        layouts[1] = new Layout("阿珍养血口服液", Align.LEFT, 13);
        layouts[2] = new Layout("10ml*9支/盒", Align.LEFT, 5);
        layouts[3] = new Layout("1盒", Align.LEFT, 5);
        return layouts;
    }

    private static Layout[] usageLayouts() {
        Layout[] layouts = new Layout[2];
        layouts[0] = new Layout(" ", Align.RIGHT, 1);
        layouts[1] = new Layout("用法:口服  每次2支  每天1次  用药2天", Align.LEFT, 23);
        return layouts;
    }

    private static Layout[] signLayouts() {
        Layout[] layouts = new Layout[6];
        layouts[0] = new Layout("总价:", Align.RIGHT, 3);
        layouts[1] = new Layout("100元", Align.LEFT, 5);
        layouts[2] = new Layout("药师签名:", Align.RIGHT, 3);
        BufferedImage signImage = null;
        try {
            signImage = ImageIO.read(new File("C:\\47105c10f1783ba7bb94d3c417efcb54.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        layouts[3] = new Layout(signImage, Align.LEFT, 5);
        layouts[4] = new Layout("医生签名:", Align.RIGHT, 3);
        layouts[5] = new Layout(signImage, Align.LEFT, 5);
        return layouts;
    }

    /**
     * 生成处方图片
     *
     * @param prescriptionInfo      图片文本所需内容
     * @param doctorSignPicture     医生签名
     * @param pharmacistSignPicture 药师签名
     * @return java.io.InputStream
     * @author liu.zr 2020/11/23 13:57
     */
    public static InputStream createImage(PrescriptionInfoDTO prescriptionInfo, BufferedImage doctorSignPicture, BufferedImage pharmacistSignPicture) throws Exception {
        // 新建图片
        BufferedImage image = createImage(PIC_WIDTH, PIC_HEIGHT, BufferedImage.TYPE_INT_BGR);
        // 创建画笔
        Graphics2D graphics = image.createGraphics();

        // 初始化背景色
        fillBackground(image, graphics, Color.WHITE);
        // 定义margin
        Margin margin = new Margin(MARGIN_Y, MARGIN_Y, MARGIN_X, MARGIN_X);
        // 初始化坐标
        Point point = new Point(margin.getLeft(), margin.getTop());

        // 绘制空行
        drawBlankLine(point, 5, false);
        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_TITLE, Font.BOLD);
        // 绘制处方title
        String content = prescriptionInfo.getChainName() + "  处方笺";
        drawString(image, graphics, point, margin, false,
                new Layout(content, Align.CENTER, COLUMNS));
        // 绘制空行
        drawBlankLine(point, 3, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_BODY, Font.PLAIN);
        // 绘制横线
        drawHorizontalLine(image, graphics, point, margin, false);
        // 绘制病例,科室,日期
        List<Layout> layouts = Lists.newLinkedList();
        layouts.add(new Layout("病历号:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getCode(), Align.LEFT, 5));
        layouts.add(new Layout("科室:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getDepartmentName(), Align.LEFT, 5));
        layouts.add(new Layout("开具日期:", Align.RIGHT, 3));
        String dateStr = DateUtil.format(prescriptionInfo.getCfDate(), DatePattern.NORM_DATE_PATTERN);
        layouts.add(new Layout(dateStr, Align.LEFT, 5));
        drawString(image, graphics, point, margin, false, layouts.toArray(new Layout[6]));
        layouts.clear();

        // 绘制姓名,性别,年龄
        layouts.add(new Layout("姓名:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getName(), Align.LEFT, 5));
        layouts.add(new Layout("性别:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getSex(), Align.LEFT, 5));
        layouts.add(new Layout("年龄:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getAge(), Align.LEFT, 5));
        drawString(image, graphics, point, margin, false, layouts.toArray(new Layout[6]));
        layouts.clear();

        // 绘制诊断
        layouts.add(new Layout("诊断:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getDiagnosis(), Align.LEFT, 21));
        drawString(image, graphics, point, margin, false, layouts.toArray(new Layout[2]));
        layouts.clear();
        // 绘制横线
        drawDownHorizontalLine(image, graphics, point, margin, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_RP, Font.BOLD);
        // 绘制空行
        drawBlankLine(point, 3, false);
        // 绘制Rp
        drawString(image, graphics, point, margin, false,
                new Layout("Rp", Align.LEFT, COLUMNS));
        // 绘制空行
        drawBlankLine(point, 2, false);

        // 设置画笔
        setGraphics(graphics, Color.BLACK, FONT_SIZE_BODY, Font.PLAIN);
        // 绘制药品信息
        List<PrescriptionInfoDTO.DrugInfo> drugInfos = prescriptionInfo.getDrugInfos();
        if (CollectionUtil.isNotEmpty(drugInfos)) {
            int index = 1;
            for (PrescriptionInfoDTO.DrugInfo drugInfo : drugInfos) {
                // 药品信息
                layouts.add(new Layout(index + ". ", Align.RIGHT, 1));
                layouts.add(new Layout(drugInfo.getCommonName(), Align.LEFT, 13));
                layouts.add(new Layout(drugInfo.getSpec(), Align.LEFT, 5));
                layouts.add(new Layout(drugInfo.getTotalTimes() + drugInfo.getUnit(), Align.LEFT, 5));
                drawString(image, graphics, point, margin, false, layouts.toArray(new Layout[4]));
                layouts.clear();

                // 用法
                layouts.add(new Layout(" ", Align.RIGHT, 1));
                String usage = "用法:" + drugInfo.getUsage() + StringUtils.SPACE
                        + "每次" + drugInfo.getSingleDose() + drugInfo.getSingleDoseUnit() + StringUtils.SPACE
                        + drugInfo.getFrequency() + StringUtils.SPACE
                        + "用药" + drugInfo.getDayNum() + "天";
                layouts.add(new Layout(usage, Align.LEFT, 23));
                drawString(image, graphics, point, margin, false, layouts.toArray(new Layout[2]));
                layouts.clear();

                // 绘制空行
                drawBlankLine(point, 1, false);

                index++;
            }
            // 绘制空行
            drawBlankLine(point, 2, false);
            // 处方药品结束
            drawString(image, graphics, point, margin, false, new Layout("(以下空白)", Align.CENTER, COLUMNS));
        }

        // 重置坐标
        point.setY(image.getHeight() - margin.getBottom());

        // 绘制空行
        drawBlankLine(point, 2, true);
        // 底部签名信息
        layouts.add(new Layout("合计金额:", Align.RIGHT, 3));
        layouts.add(new Layout(prescriptionInfo.getTotalPrice() + "元", Align.LEFT, 5));
        layouts.add(new Layout("医生签名:", Align.RIGHT, 3));
        layouts.add(new Layout(doctorSignPicture, Align.LEFT, 5));
        layouts.add(new Layout("药师签名:", Align.RIGHT, 3));
        layouts.add(new Layout(pharmacistSignPicture, Align.LEFT, 5));
        drawString(image, graphics, point, margin, true, layouts.toArray(new Layout[6]));
        layouts.clear();

        // 绘制空行
        drawBlankLine(point, 2, true);
        // 底部横线
        drawHorizontalLine(image, graphics, point, margin, true);
        // 设置画笔
        setGraphics(graphics, Color.RED, FONT_SIZE_BODY, Font.PLAIN);
        // 设置处方有效期
        drawString(image, graphics, point, margin, false,
                new Layout("该处方有效期3天", Align.CENTER, COLUMNS));

        // 完成绘制
        graphics.dispose();
        return imageInputStream(image);
    }

    private static InputStream imageInputStream(BufferedImage image) throws IOException {
        // 输出png图片
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        JPEGEncodeParam param = JPEGCodec.getDefaultJPEGEncodeParam(image);
        param.setDensityUnit(JPEGEncodeParam.DENSITY_UNIT_DOTS_INCH);
        param.setQuality(1f, false);
        param.setXDensity(96);
        param.setYDensity(96);
        JPEGCodec.createJPEGEncoder(os).encode(image, param);
        image.flush();
        return new ByteArrayInputStream(os.toByteArray());
    }


    @Getter
    public static class Layout {
        /**
         * 内容
         */
        private String content;

        /**
         * 图片
         */
        private BufferedImage image;

        /**
         * 对齐方式
         */
        private Align align;

        /**
         * 占列数
         */
        private Integer col;

        public Layout(String content, Align align) {
            this.content = content;
            this.align = align;
        }

        public Layout(String content, Align align, Integer col) {
            this.content = content;
            this.align = align;
            this.col = col;
        }

        public Layout(BufferedImage image, Align align, Integer col) {
            this.image = image;
            this.align = align;
            this.col = col;
        }

        public Layout(String content, BufferedImage image, Align align, Integer col) {
            this.content = content;
            this.image = image;
            this.align = align;
            this.col = col;
        }
    }

    public enum Align {
        CENTER,
        LEFT,
        RIGHT,
        ;
    }
}

三、代码呈现效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/147905.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【概率论】Python:实现求联合分布函数 | 求边缘分布函数 | Joint distribution | Marginal distribution

猛戳订阅&#xff01; &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a;本章我们将通过 Python 手动实现联合分布函数和边缘分布函数&#xff0c;部署的测试代码放到文后了&#xff0c;运行所需环境 python version > 3.6&#xff0c;numpy &g…

2023美亚杯个人赛复盘(一)火眼+取证大师

第一次参加美亚杯&#xff0c;手忙脚乱&#xff0c;不过也学到了很多东西&#xff0c;接下来会分篇介绍writeup&#xff0c;感兴趣的小伙伴可以持续关注。 案件基本情况&#xff1a; &#xff08;一&#xff09;案情 2023月8月的一天&#xff0c;香港警方在调查一起网络诈骗案…

Ubuntu20.04配置深度学习环境

默认你已经完成Ubuntu20.04的安装&#xff0c;如果没安装的话可以参考其他博客&#xff0c;我的显卡是GTX1660Ti 一、NVIDIA显卡驱动安装 大多数人在安装Ubutnu20.04系统的时候为了节约时间&#xff0c;通常不会勾选“图形或无线硬件&#xff0c;以及其他媒体格式安装第三方软…

Python小白之“没有名称为xlwings‘的模块”

题外话&#xff1a;学习和安装Python的第一个需求就是整理一个Excel&#xff0c;需要读取和写入Excel 背景&#xff1a;取到的模板代码&#xff0c;PyCharm本地运行报错&#xff1a;没有名称为xlwings的模块 解决办法&#xff1a;这类报模板找不到的错&#xff0c;即是模块缺…

爆款元服务!教你如何设计高使用率卡片

元服务的概念相信大家已经在 HDC 2023 上有了很详细的了解&#xff0c;更轻便的开发方式&#xff0c;让开发者跃跃欲试。目前也已经有很多开发者开发出了一些爆款元服务&#xff0c;那么如何让你的元服务拥有更高的传播范围、更高的用户使用率和更多的用户触点呢&#xff1f;设…

ACM练习——第三天

今天继续练习C和ACM模式 在写题之前先了解一些新的知识 1.#include <algorithm> #include <algorithm> 是 C 标准库中的头文件之一&#xff0c;其中包含了一系列用于处理各种容器&#xff08;如数组、向量、列表等&#xff09;和其他数据结构的算法。这个头文件提供…

分享 8 个 4k 壁纸站点

今天分享 8 个 4k 壁纸站点&#xff0c;换换心情&#xff01; bz.zzzmh 网址&#xff1a;https://bz.zzzmh.cn/ 一个免费的极简壁纸网站。 可以在这里找到所有极简壁纸&#xff0c;不需要注册登录就可以下载&#xff0c;它不限制分类、尺寸&#xff0c;想要什么样的壁纸直接搜…

2023最新版本 从零基础入门C++与QT(学习笔记) -4- C/C++混合编程

&#x1f38f;在C兼容C只需要调用C头文件 &#x1f384;格式 &#x1f388; -1- extern(关键字) “C”{ }(花括号) &#x1f388; -2- 花括号里面填写要包含的头文件 &#x1f384;代码段格式 extern "C" {#include “stdio.h”#include “string.h” }&#x…

【Beyond Compare】大小写对比的设置

1.点击会话设置 2.把大小写打勾 3.对比效果

Linux常用命令用法及实现方式有哪些?

接上一篇&#xff0c;它来啦&#xff01; 5.文本文件编辑命令 (1)touch命令&#xff1a;touch命令用于创建空白文件或设置文件的时间&#xff0c;语法格式为“touch [参数] 文件名称”。 (2)mkdir命令&#xff1a;mkdir命令用于创建空白的目录&#xff0c;英文全称为“make dir…

微同城生活圈小程序源码系统 专业搭建本地生活服务的平台 带完整搭建教程

在互联网的影响下&#xff0c;越来越多的用户开始依赖手机进行日常生活。为了满足本地居民的需求&#xff0c;源码小编来给大家分享一款全新的微同城生活圈小程序源码系统。该系统旨在为本地居民提供一站式的生活服务解决方案&#xff0c;让您的生活更加便捷、高效。 以下是部…

StableDiffusion(四)——高清修复与放大算法

目录 一、高清修复与放大算法 1.高清修复 ①文生图 ②图生图 2.SD放大&#xff08;SD Upscale&#xff09; 3.附加功能放大 4.总结 一、高清修复与放大算法 1.高清修复 概念&#xff1a;分两步&#xff0c;第一步生成低分辨率的图画&#xff0c;第二步使用它指定的高清…

内网Jenkins 部署.net(dotnet)项目

一、前置条件 内网部署Jenkins&#xff0c;并安装好所需插件 此篇内容需承接内网搭建Jenkins自动化远程部署项目到Windows服务器_jenkins内网安装-CSDN博客 &#xff0c;才更好操作与理解 二、在Jenkins中创建项目 三、配置项目 General Source Code Management Build Envi…

源码级JVS低代码功能新增:动态配置、逻辑多级循环嵌套等等

低代码更新功能 新增: 1.下拉组件选项新增动态配置&#xff1b; 选项的内容可以根据特定的条件或数据源进行动态变化的功能&#xff0c;通过动态配置&#xff0c;用户可以灵活地设置下拉组件的选项内容&#xff0c;例如从数据库或其他数据源中获取选项数据&#xff0c;或者根…

AdaBoost:提升机器学习的力量

一、介绍 机器学习已成为现代技术的基石&#xff0c;为从推荐系统到自动驾驶汽车的一切提供动力。在众多机器学习算法中&#xff0c;AdaBoost&#xff08;Adaptive Boosting的缩写&#xff09;作为一种强大的集成方法脱颖而出&#xff0c;为该领域的成功做出了重大贡献。AdaBoo…

docker 安装xxl-job

1.拉取镜像 docker pull xuxueli/xxl-job-admin:2.4.0 2.docker镜像创建并运行 docker run -e PARAMS"--spring.datasource.urljdbc:mysql://xxxxx:3306/xxl_job?useUnicodetrue&characterEncodingUTF-8&autoReconnecttrue&serverTimezoneAsia/Shanghai&…

全彩LED显示屏的质量怎样判断

判断全彩LED显示屏的质量需要考虑多个方面&#xff0c;包括平整度、白平衡、可视角度、分辨率、亮度、可靠性和稳定性等。以下是一些建议&#xff0c;供你参考&#xff1a; 平整度&#xff1a;LED显示屏的表面平整度应在1mm以内&#xff0c;以保证显示图像不发生扭曲。局部凸起…

使用 requests 2.11 版本时的 Site ID 类型问题及解决方案

在使用ebaysdk-python库时&#xff0c;一些用户可能会遇到一个特定问题&#xff0c;这个问题与requests库的版本有关。具体问题是&#xff0c;当使用requests库的2.11版本时&#xff0c;用户需要在请求头中传递的值必须为字符串或字节类型&#xff0c;但是传入的值却是整数类型…

文件包含漏洞

文章目录 文件包含漏洞php中文件包含的语句文件包含动态包含 相关配置本地文件包含远程文件包含 漏洞原理特点 利用方法包含图片木马读取敏感文件 读取php源码执行php代码包含图片马写 shell包含日志文件包含防御 文件包含漏洞 ​ 程序开发人员通常会把可重复使用函数或语句写…

从零到一:抖音小程序开发全指南及预算规划

在数字时代&#xff0c;抖音小程序的开发成为企业实现品牌推广、服务提供的重要途径。本文将为您提供从零到一的抖音小程序开发全指南&#xff0c;包括预算规划以及一些关键的技术代码示例。 1. 项目准备 在开始抖音小程序开发之前&#xff0c;需要进行一些项目准备工作。 …