用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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tangxingbin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值