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 splitContent(Graphics graphics, String content, int width) {
int realWidth = width - LINE_HEIGHT;
int tempWidth = 0;
FontMetrics fontMetrics = graphics.getFontMetrics();
List 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 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 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 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,
;
}
}