0
点赞
收藏
分享

微信扫一扫

Java使用PDFBOX操作pdf文件(二,绘制图形和水印)

四月天2021 2022-04-15 阅读 98

在上一篇文章之中,我们已经知道怎样创建和操作加载pdf文件了。现在来看一看使用PDFBOX进行图形的和文字的绘制
(友情提示:pdfbox的坐标轴是以左下角为原点-----宽边为X轴,高边为Y轴)

在PDF中绘制图形

通过流对象不仅可以绘制文字信息,也可以绘制一些简单的图形。

例:在PDF中绘制一个实心的长方形。

public static void main(String[] args) throws IOException {
	PDDocument docment = new PDDocument();
	PDPage pageOne = new PDPage(PDRectangle.A4);
	docment.addPage(pageOne);
	
	PDPageContentStream stream = new PDPageContentStream(docment, pageOne);
	
	stream.setNonStrokingColor(0.12f, 0.34f, 0.62f);
	//直接绘制一个正方形,参数x,y为在pdf中的坐标,width和height为长方形的长宽
	stream.addRect(20f, 30f, 100f, 100f);
	//填充,如果不掉用则不会进行绘制,如果想要设置边框的话可以使用fillandStroke
	//但是目前好像无法设置边框的宽度
	stream.fill();
	stream.close();
	
	docment.save(new File("drawPic.pdf"));
}

请添加图片描述

例:使用PDFBOX绘制曲线

pdfbox也支持绘制曲线,他主要由流对象的curseTo方法来实现。
下图为该方法的实现
在这里插入图片描述
第一种方法是直接给出三个点,画出的弧线由(X1,Y1)到(X2,Y2)再到(X3,Y3)
如果三个坐标间可以在一条整点的直线上,则会绘制成直线。

第二种和第三种方法要配合使用,同样也是和第一种的方法同理,只不过把坐标点拆开了。
代码示例:

public static void DrawCurve() throws IOException {
		PDDocument doc = new PDDocument();
		PDPage page = new PDPage(PDRectangle.A4);
		doc.addPage(page);
		
		PDPageContentStream stream = new PDPageContentStream(doc, page);
		
		stream.saveGraphicsState();
		//设置绘制区域的背景色
		stream.setNonStrokingColor(0.3f, 0.87f, 0.56f);
		//设置起始点
		stream.moveTo(0.0f, 0.0f);
		//根据坐标点绘制曲线
		stream.curveTo(11.23f, 11.12f, 100.0f, 100.0f, 299.0f, 0.0f);
		//填充区域
		stream.fillAndStroke();
		
		stream.close();
		
		doc.save("curve.pdf");
		
}

请添加图片描述

使用PDFBOX的曲线绘制饼图

既然可以使用PDFBOX绘制曲线,那么只要给出的点足够多,则可以绘制圆形,进一步则可以用于各种图标,以下是一个绘制饼图的示例。
这个例子是从网上找的,有时间可以分析一下里面绘制的具体细节。

public static void main(String[] args) throws IOException 
  { 
    PDDocument doc = new PDDocument(); 
    PDPage page = new PDPage(); 
    doc.addPage(page); 
    PDPageContentStream cs = new PDPageContentStream(doc, page); 

    cs.transform(Matrix.getTranslateInstance(250, 400)); 

    cs.setNonStrokingColor(0.15f,0.54f,0.87f); 
    drawSlice(cs, 100, 0, 80); 
    cs.fill(); 
    cs.setNonStrokingColor(0.32f,0.11f,0.55f); 
    drawSlice(cs, 100, 80, 150); 
    cs.fill(); 
    cs.setNonStrokingColor(0.05f,0.66f,0.71f); 
    drawSlice(cs, 100, 150, 215); 
    cs.fill(); 
    cs.setNonStrokingColor(0.32f,0.77f,0.33f); 
    drawSlice(cs, 100, 215, 305); 
    cs.fill(); 
    cs.setNonStrokingColor(0.15f,0.25f,0.35f); 
    drawSlice(cs, 100, 305, 360); 
    cs.fill(); 

    cs.close(); 
    doc.save("piechart.pdf"); 
    doc.close(); 
  } 

    private static void drawSlice(PDPageContentStream cs, float rad, float startDeg, float endDeg) throws IOException 
    { 
     cs.moveTo(0, 0); 
     List<Float> smallArc = createSmallArc(rad, Math.toRadians(startDeg), Math.toRadians(endDeg)); 
     cs.lineTo(smallArc.get(0), smallArc.get(1)); 
     cs.curveTo(smallArc.get(2), smallArc.get(3), smallArc.get(4), smallArc.get(5), smallArc.get(6), smallArc.get(7)); 
     cs.closePath(); 
    } 

    /** 
    * From https://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html 
    * 
    * Cubic bezier approximation of a circular arc centered at the origin, 
    * from (radians) a1 to a2, where a2-a1 &lt; pi/2. The arc's radius is r. 
    * 
    * Returns a list with 4 points, where x1,y1 and x4,y4 are the arc's end points 
    * and x2,y2 and x3,y3 are the cubic bezier's control points. 
    * 
    * This algorithm is based on the approach described in: 
    * Aleksas Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," 
    * Information Technology and Control, 35(4), 2006 pp. 371-378. 
    */ 
    private static List<Float> createSmallArc(double r, double a1, double a2) 
    { 
     // Compute all four points for an arc that subtends the same total angle 
     // but is centered on the X-axis 
     double a = (a2 - a1)/2; 
     double x4 = r * Math.cos(a); 
     double y4 = r * Math.sin(a); 
     double x1 = x4; 
     double y1 = -y4; 
     double q1 = x1*x1 + y1*y1; 

     double q2 = q1 + x1*x4 + y1*y4; 
     double k2 = 4/3d * (Math.sqrt(2 * q1 * q2) - q2)/(x1 * y4 - y1 * x4); 
     double x2 = x1 - k2 * y1; 
     double y2 = y1 + k2 * x1; 
     double x3 = x2; 
     double y3 = -y2; 

     // Find the arc points' actual locations by computing x1,y1 and x4,y4 
     // and rotating the control points by a + a1 

     double ar = a + a1; 
     double cos_ar = Math.cos(ar); 
     double sin_ar = Math.sin(ar); 

     List<Float> list = new ArrayList<Float>(); 
     list.add((float) (r * Math.cos(a1))); 
     list.add((float) (r * Math.sin(a1))); 
     list.add((float) (x2 * cos_ar - y2 * sin_ar)); 
     list.add((float) (x2 * sin_ar + y2 * cos_ar)); 
     list.add((float) (x3 * cos_ar - y3 * sin_ar)); 
     list.add((float) (x3 * sin_ar + y3 * cos_ar)); 
     list.add((float) (r * Math.cos(a2))); 
     list.add((float) (r * Math.sin(a2))); 
     return list; 
    } 

效果如下。
请添加图片描述

使用PDFBOX绘制水印

同样可以在页面中设置页面水印具体使用如下

public static void main(String[] args) throws IOException {
		
		 PDDocument document = new PDDocument();
		 PDPage pageOne = new PDPage(PDRectangle.A4);
		 document.addPage(pageOne);

		 PDPageContentStream stream = new PDPageContentStream(document, pageOne);
		 
		 // 加载字体
		 PDFont font = PDType0Font.load(document, new FileInputStream("src/SimHei.ttf"), true);

		 //创建拓展显示状态
		 PDExtendedGraphicsState r = new PDExtendedGraphicsState();

		 // 设置透明度(阿尔法混合是一种让图形显示透明的技术,设置其透明度参数)
		 r.setNonStrokingAlphaConstant(0.2f);
		 r.setAlphaSourceFlag(true);
		 stream.setGraphicsStateParameters(r);


		 stream.beginText();
		 stream.setFont(font, 32);
		 stream.newLineAtOffset(0, -15);

		 // 获取PDF页面大小
		 float pageHeight = pageOne.getMediaBox().getHeight();
		 float pageWidth = pageOne.getMediaBox().getWidth();

		 
		 
		                    //设置文本显示矩阵,并设置旋转的角度
        stream.setTextMatrix(Matrix.getRotateInstance(0.4, pageHeight/3, pageWidth/3));
        //写入水印文本
        stream.showText("这是你要的水印");

		            // 结束渲染,关闭流
		 stream.endText();
		 stream.restoreGraphicsState();
		 stream.close();
		 
		 document.save("addwaterGrafh.pdf");
		 
		 }
	}

显示效果:
请添加图片描述

举报

相关推荐

0 条评论