java 绘画心电图,用IText做一个通用的心电报告绘制类

有些时候,我们需要在后台生成某一数据类的报告,如心电图报告,基于这一个需求,我做了一个在iText上绘制心电图报告的类,可以参考此做成自己想要的报告;

1.定义一个数据体,用于存放报告需要的数据;

public class PdfReportDataItem { ......}

2.编写主要的绘制类

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.Reader;

import com.itextpdf.text.BaseColor;

import com.itextpdf.text.Document;

import com.itextpdf.text.DocumentException;

import com.itextpdf.text.Image;

import com.itextpdf.text.PageSize;

import com.itextpdf.text.Rectangle;

import com.itextpdf.text.pdf.BaseFont;

import com.itextpdf.text.pdf.PdfContentByte;

import com.itextpdf.text.pdf.PdfWriter;

public class PDFCreateUtil

{

private float width     ;

private float height     ;

private float A4_Width  ;

private float A4_Height ;

//计算1mm对应的点是多少

private float dx   ;

private float dy  ;

//1个数据点占用的pdf尺寸

private float  xSpaceOnePoint  ;    //X方向一个采样点对应的绘图宽度

private float leftMargin        ;    //左边距

private float topMargin         ;    //上边距

private float rightMargin       ;    //右边距

private float bottomMargin        ;    //下边距

private float ResultTextAreaHeight  ;  //信息窗口高度

private float ChannelTextAreaWidth  ;  //通道字宽度

private float PicWdithOf10Seconds   ;  //10秒钟数据的绘图宽度

private float   Freq ;  //采样频率

private int     OnePagePoints ;

private float   Speed ;  //走纸速度

public PDFCreateUtil()

{

width     = PageSize.A4.rotate().getWidth() ;

height     = PageSize.A4.rotate().getHeight() ;

A4_Width  = (float)297.0 ; //mm

A4_Height = (float)210.0 ; //mm

//计算1mm对应的点是多少

dx = width  / A4_Width  ;

dy = height / A4_Height ;

Freq = 1000 ;

Speed = 25 ;

//1个数据点占用的pdf横向尺寸

xSpaceOnePoint  =  (float)( dx * Speed /Freq ) ;

leftMargin     = dx * 20 ;

topMargin      = dy * 10 ;

rightMargin    = dx * 15 ;

bottomMargin     = dy * 10 ;

ResultTextAreaHeight = dy * 25 ;

ChannelTextAreaWidth = dx * 5  ;

PicWdithOf10Seconds  = xSpaceOnePoint * Freq * 10 ;

OnePagePoints = (int) (Freq * 10) ;

}

public  boolean  CreateJsonPdf(PdfReportDataItem DataItem ) throws IOException

{

if ( DataItem == null || DataItem.getFilePath() == null || DataItem.getFilePath().isEmpty() ) return false  ;

if ( !Tools.FileExists(DataItem.getFilePath())) return false ;

String JsonDatas = this.readJsonFile(DataItem.getFilePath()) ;

String[] ArrayData = JsonDatas.replace("[", "").replace("]", "").split(",") ;

float[] InDatas = new float[ArrayData.length] ;

for( int i = 0 ; i < ArrayData.length ; i++ )

{

InDatas[i] = Float.valueOf(ArrayData[i]).floatValue() * 10 ;  //这个地方应按实际的电压值来,这里放大了10倍。

}

Document document = new Document(PageSize.A4.rotate() , leftMargin , rightMargin , topMargin , bottomMargin );

try {

// 关联文档对象与输出流

PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream(DataItem.getOutFilePath()));

// 打开文档

document.open();

// 获取内容

PdfContentByte cb = writer.getDirectContent();

// 设置文本,使用windox自带字体可显示中文

BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/SIMYOU.TTF",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

//设置坐标系

float curYOrigin =  topMargin   ;

cb.beginText();

cb.setFontAndSize(bf, 5*dx );

cb.setTextMatrix(PageSize.A4.rotate().getWidth()/2 - 5*dx * DataItem.getCenterName().length() /2 , ConvertCoordinate(PageSize.A4.rotate(), curYOrigin + dx)  );        cb.showText(DataItem.getCenterName());

cb.setTextMatrix(PageSize.A4.rotate().getWidth()/2 - 5*dx * DataItem.getReportTitle().length() /2 , ConvertCoordinate(PageSize.A4.rotate(),curYOrigin + dx* 7 ) );    cb.showText(DataItem.getReportTitle());

cb.endText();

//这里要除去中间的间距,要不然尺寸就不对

float waveHeight = dy * 50 ;   //( height - ResultTextAreaHeight - topMargin - bottomMargin - dy * 15 )/3 ;

curYOrigin = topMargin + dx * 8 ;

//只绘制三行

for ( int i = 0  ; i < ( InDatas.length  / OnePagePoints + 1 ) && i < 3 ; i++ )

{

curYOrigin = DrawEcg(InDatas , cb , PicWdithOf10Seconds , waveHeight , ChannelTextAreaWidth ,  leftMargin ,  curYOrigin , dx , i * OnePagePoints ) ;

curYOrigin += dx  ;

}

curYOrigin = DrawResult(DataItem , cb , PicWdithOf10Seconds + ChannelTextAreaWidth , ResultTextAreaHeight , leftMargin ,   curYOrigin , dx ) ;

curYOrigin += dx ;

// 确认直线的绘制

document.newPage();

// 关闭文档

document.close();

return true ;

} catch (FileNotFoundException e)

{

e.printStackTrace();

document.newPage() ;

document.close();

return false ;

} catch (DocumentException e)

{

e.printStackTrace();

document.newPage() ;

document.close();

return false ;

}

}

//绘制波形

private float  DrawEcg(float[] InDatas ,  PdfContentByte cb , float PicWidth , float PicHeight , float ChannelTextWidth , float originX  , float originY  , float pointPer1mm  , int startPos )

{

float prevOriginY = originY ;

originY = this.ConvertCoordinate(PageSize.A4.rotate(), originY )  ;

//先绘制底色

cb.setColorStroke(BaseColor.PINK);

cb.moveTo(originX , originY );

cb.lineTo(originX , this.ConvertCoordinate(PageSize.A4.rotate(), prevOriginY + PicHeight ) );

cb.lineTo(originX + PicWidth + ChannelTextWidth ,this.ConvertCoordinate(PageSize.A4.rotate(), prevOriginY + PicHeight ) );

cb.lineTo(originX + PicWidth + ChannelTextWidth , originY )  ;

cb.lineTo(originX, originY);

//绘制底纹

int numx = (int) ( PicWidth  / (pointPer1mm * 5 ) ) ;

int numy = (int) ( PicHeight / (pointPer1mm * 5 ) ) ;

//画竖起的线

for ( int x = 0 ; x <= numx ; x++  )

{

cb.moveTo(originX + ChannelTextWidth + (int)( x * pointPer1mm* 5  ) , originY   )  ;

cb.lineTo(originX + ChannelTextWidth + (int)( x * pointPer1mm* 5 ) , this.ConvertCoordinate(PageSize.A4.rotate(),prevOriginY + PicHeight)  )  ;

}

//画横起的线

for ( int y = 1  ; y <= numy  ; y++  )

{

cb.moveTo(originX + ChannelTextWidth ,                (int) (this.ConvertCoordinate(PageSize.A4.rotate(),prevOriginY +  y * pointPer1mm* 5 )) )    ;

cb.lineTo(originX + ChannelTextWidth + PicWidth  , (int) ( this.ConvertCoordinate(PageSize.A4.rotate(),prevOriginY +  y * pointPer1mm* 5 ) ) )    ;

}

cb.stroke();

cb.beginText();

float  centerPos =  originY  -   PicHeight / 2   ;

cb.setTextMatrix(originX , centerPos - pointPer1mm * 2);

cb.showText("I");

cb.endText();

cb.setColorStroke(BaseColor.BLACK)  ;

if ( InDatas != null && InDatas.length > 0 ) //有数据就显示

{

int endPos = startPos + OnePagePoints   ;

if ( Freq == 1000 )

{

float  GetData = InDatas[startPos] ;

cb.moveTo( originX + ChannelTextWidth , centerPos + pointPer1mm * GetData );

for ( int i = startPos + 1   ; i < endPos && i < InDatas.length  ; i++ )

{

GetData = InDatas[i] ;

cb.lineTo( originX + ChannelTextWidth + xSpaceOnePoint * (i - startPos ), centerPos + pointPer1mm * GetData );

}

}

}

cb.stroke();

return prevOriginY + PicHeight ;

}

private float  DrawResult(PdfReportDataItem DataItem  ,  PdfContentByte cb , float PicWidth , float PicHeight ,  float originX  , float originY  , float pointPer1mm  ) throws DocumentException, IOException

{

float prevOrigin = originY ;

originY = this.ConvertCoordinate(PageSize.A4.rotate(), originY )  ;

//先绘制底色

cb.setColorStroke(BaseColor.PINK);

cb.moveTo(originX , originY );

cb.lineTo(originX , this.ConvertCoordinate(PageSize.A4.rotate(), prevOrigin +    PicHeight ) );

cb.lineTo(originX + PicWidth   , this.ConvertCoordinate(PageSize.A4.rotate(), prevOrigin + PicHeight) );

cb.lineTo(originX + PicWidth   , originY )  ;

cb.lineTo(originX,  originY);

cb.stroke();

//输出文字

cb.beginText();

BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/SIMYOU.TTF",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

//绘制提示

DrawText(bf ,  cb ,pointPer1mm * 4  ,  originX , prevOrigin  + pointPer1mm  + PicHeight  , pointPer1mm , "本报告仅供参考不能代替医院检查诊断"  ) ;

//绘制医生

DrawText(bf ,  cb ,pointPer1mm * 4  ,  originX + PicWidth - pointPer1mm * 40 ,  prevOrigin + PicHeight + pointPer1mm   , pointPer1mm , "分析师:" + DataItem.getAnalystName()   ) ;

//输出基本信息

float curYPosition = prevOrigin + pointPer1mm ;

float curXPosition = originX + pointPer1mm ;

curYPosition  = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "数据编号:" + DataItem.getDataId()   ) ;

curYPosition  = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "姓    名:"   + DataItem.getUserName()   ) ;

curYPosition  = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "年    龄:"   + DataItem.getAge() ) ;

curYPosition  = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "性    别:"   + DataItem.getSex() ) ;

curYPosition  = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "检测时间:" + DataItem.getExamTime()  ) ;

DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , "分析时间:" + DataItem.getAnalysisTime() ) ;

//输出诊断意见

curXPosition = originX + pointPer1mm * 50 ;

curYPosition = DrawText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , prevOrigin + pointPer1mm , pointPer1mm , "结果与建议"  ) ;

curYPosition = DrawMultiLineText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , DataItem.getContent() , 50   ) ;

DrawMultiLineText( bf ,  cb ,  pointPer1mm * 3 ,  curXPosition  , curYPosition , pointPer1mm , DataItem.getAdvice() , 50   ) ;

cb.endText();

return prevOrigin + PicHeight ;

}

private float DrawText(BaseFont bf ,  PdfContentByte cb ,float FontSize ,  float x , float y , float pointPer1mm , String info  ) throws DocumentException, IOException

{

float prevOriginY = y ;

cb.setFontAndSize(bf, FontSize );

cb.setTextMatrix(x, this.ConvertCoordinate(PageSize.A4.rotate() , prevOriginY + FontSize )  );

cb.showText(info);

return prevOriginY + pointPer1mm + FontSize ;

}

private float DrawMultiLineText(BaseFont bf ,  PdfContentByte cb ,float FontSize ,  float x , float y , float pointPer1mm , String info  , int lineCount  ) throws DocumentException, IOException

{

float prevY = y ;

y = this.ConvertCoordinate(PageSize.A4.rotate(), y + FontSize  )  ;

cb.setFontAndSize(bf, FontSize );

info = "  " + info ;

int line = 1 ;

if ( info.length() % lineCount == 0 )

{

line = info.length() / lineCount ;

}

else

{

line = info.length() / lineCount + 1 ;

}

int getCount = 0 ;

for ( int i = 0 ; i < line ; i++ )

{

cb.setTextMatrix(x , y - i * (FontSize + pointPer1mm)  );

if ( ( info.length() - (i+1 ) * lineCount ) > 0 )

{

getCount = (i+1 ) * lineCount + 1 ;

cb.showText(info.substring(i * lineCount , getCount ) ) ;

}

else

{

cb.showText(info.substring(getCount ) ) ;

}

}

prevY = prevY + line * (FontSize + pointPer1mm) ;

return prevY ;

}

public String readJsonFile(String fileName)

{

String jsonStr = "";

try {

File jsonFile = new File(fileName);

FileReader fileReader = new FileReader(jsonFile);

Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8");

int ch = 0;

StringBuffer sb = new StringBuffer();

while ((ch = reader.read()) != -1) {

sb.append((char) ch);

}

fileReader.close();

reader.close();

jsonStr = sb.toString();

return jsonStr;

} catch (IOException e) {

e.printStackTrace();

return null;

}

}

private  float ConvertCoordinate(Rectangle  pageSize , float yPosition )

{

return pageSize.getTop() - yPosition ;

}

}

3. 写一个测试类

public class TestPdf {

public static void main(String[] args) throws IOException

{

PDFCreateUtil pdf = new PDFCreateUtil() ;

String filepath=System.getProperty("user.dir");

PdfReportDataItem DataItem = new PdfReportDataItem() ;

DataItem.setDataId("122314123131");

DataItem.setUserName("张三");

DataItem.setAge("40");

DataItem.setSex("男");

DataItem.setExamTime("2019-09-05 12:00:00") ;

DataItem.setAnalysisTime("2019-09-20 12:00:00");

DataItem.setContent("心电正常");

DataItem.setAdvice("如果你感觉到心慌等症状,请前往医院做进一步的检查");

DataItem.setAnalystName("分析师1");

DataItem.setSignPic("");

DataItem.setFilePath(filepath +File.separator + "src" + File.separator + "measured-waveshape.json");

DataItem.setCenterName("大坪中心");

DataItem.setReportTitle("日常心电分析报告");

DataItem.setJsonFile(true);;

DataItem.setOutFilePath("d:\\Test.pdf");

pdf.CreateJsonPdf(DataItem);

}

}

4. 最终会生成一个PDF文件

代码及数据下载地址: https://download.csdn.net/download/tangxingbin/11798289

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答您的问题。 首先,需要在Java项目中引入Itext8的依赖。可以在Maven或Gradle中添加以下依赖: ```xml <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>7.1.14</version> </dependency> ``` 然后,可以使用Itext8中的Canvas绘制蜘蛛网图。以下是一个简单的示例代码: ```java import com.itextpdf.kernel.color.Color; import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.kernel.pdf.canvas.draw.DottedLine; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.AreaBreak; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.property.AreaBreakType; import com.itextpdf.layout.property.TextAlignment; import com.itextpdf.layout.property.VerticalAlignment; import java.io.IOException; public class SpiderChart { public static void main(String[] args) throws IOException { try (Document document = new Document()) { PdfCanvas canvas = new PdfCanvas(document.getPdfDocument().addNewPage()); // 设置布原点 float x = 250; float y = 400; canvas.concatMatrix(1, 0, 0, 1, x, y); // 绘制蜘蛛网图 int numSides = 6; // 边数 float radius = 200; // 半径 float angle = (float) (2 * Math.PI / numSides); // 每条边对应的角度 float[] xPoints = new float[numSides]; float[] yPoints = new float[numSides]; float startAngle = (float) (-Math.PI / 2); // 起始角度 float[] values = { 90, 70, 80, 50, 60, 75 }; // 数据值 for (int i = 0; i < numSides; i++) { float currentAngle = startAngle + i * angle; xPoints[i] = (float) (radius * Math.cos(currentAngle)); yPoints[i] = (float) (radius * Math.sin(currentAngle)); } canvas.saveState(); canvas.setColor(Color.BLACK, true); canvas.moveTo(xPoints[0], yPoints[0]); for (int i = 1; i < numSides; i++) { canvas.lineTo(xPoints[i], yPoints[i]); } canvas.closePathStroke(); float factor = radius / values.length; float currentRadius = 0; for (int i = values.length - 1; i >= 0; i--) { float value = values[i]; float currentX = xPoints[0] * value / 100; float currentY = yPoints[0] * value / 100; canvas.setLineWidth(1); canvas.setLineDash(8, 8); canvas.moveTo(0, 0); canvas.lineTo(currentX, currentY); canvas.stroke(); canvas.setLineWidth(2); canvas.setLineDash(new DottedLine()); canvas.circle(0, 0, currentRadius += factor); canvas.stroke(); } canvas.restoreState(); // 添加图例 document.add(new Paragraph("图例").setTextAlignment(TextAlignment.CENTER) .setVerticalAlignment(VerticalAlignment.MIDDLE).setFixedPosition(1, 50, 50, 100)); // 添加分页符 document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); } } } ``` 该代码会生成一个PDF文件,其中包含一个蜘蛛网图和一个图例。您可以根据需要修改代码来调整图形的大小、颜色、边框样式等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值