使用Java生成图片——功能强大的图形工具
时间:2024-04-03 16:15:39 来源:网络cs 作者:欧阳逸 栏目:卖家故事 阅读:
阅读本书更多章节>>>>
一、引言
Java是一种广泛使用的编程语言,它具有强大的功能和卓越的性能,可以用来创建各种类型的应用程序,包括生成图像。在Java中,可以使用Java的内置类库和第三方库来生成图片。下面是一篇关于Java生成图片的介绍文章。
二、具体代码
PrescriptionPictureGenerateUtil.javapackage 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: 处方图片生成工具 */@Slf4jpublic 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, ; }}
三、代码呈现效果
阅读本书更多章节>>>>本文链接:https://www.kjpai.cn/gushi/2024-04-03/153401.html,文章来源:网络cs,作者:欧阳逸,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。