java实现,PDF转换为TIF

目录

■JDK版本

■java代码・实现效果

■POM引用

■之前TIF相关的问题(两张TIF合并)

■对于成果物TIF,需要考虑的点

■问题

■问题1:无法生成TIF,已解决

■问题2:生成的TIF过大,已解决

[解决方法1:使用LZW方式压缩 (质量高)](#解决方法1:使用LZW方式压缩 (质量高))

[解决方法2:让图片位深度为黑白(binary),并且使用CCITT方式压缩 (质量低)](#解决方法2:让图片位深度为黑白(binary),并且使用CCITT方式压缩 (质量低))

■相关工具

SVF

foxit

■相关知识

[ImageIO.write 的结果是 false 的原因](#ImageIO.write 的结果是 false 的原因)

[转换时报错 type 4 gsub lookup table is not supported](#转换时报错 type 4 gsub lookup table is not supported)

DPI是什么

[一英寸 是多少厘米](#一英寸 是多少厘米)

[图片的 位深度](#图片的 位深度)

■功能扩展

转换为TIF时,能否在TIF中的某个坐标点,再追加什么信息

4页的PDF,取出一部分,生成3页的PDF

印章(在右上角)

印章(改进版)(坐标自己定义)

PDF生成jpg图片

[代码比较(印章 和 JPG),代码原理](#代码比较(印章 和 JPG),代码原理)

[介绍一下 java中的Graphics2D 类](#介绍一下 java中的Graphics2D 类)

印章代码参照


=================

■JDK版本

1.8

■java代码・实现效果

java 复制代码
package com.sxz.study.pdf;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIF {

    public static void main(String[] args) {
        try {
            // Load the PDF document
            PDDocument document = PDDocument.load(new File("E:\\Users\\sxz\\Desktop\\PDF\\Test.pdf"));
            
            // Create a PDF renderer
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            
            // Iterate over each page in the PDF document
            for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
                // Render the PDF page to a BufferedImage
                // BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300, ImageType.RGB);
            	BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);
                
                // Save the BufferedImage as a TIF file
                boolean flg = ImageIO.write(image, "tif", new File("E:\\Users\\sxz\\Desktop\\PDF\\output_" + (pageNumber + 1) + ".tif"));
                System.out.println(flg);
            }
            
            // Close the PDF document
            document.close();
            
            System.out.println("PDF converted to TIF successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

===

====

=====

■POM引用

XML 复制代码
		<dependency>
		    <groupId>org.apache.pdfbox</groupId>
		    <artifactId>pdfbox</artifactId>
		    <version>2.0.24</version> <!-- 可以根据需要选择最新版本 -->
		</dependency>
		<dependency>
		    <groupId>org.apache.pdfbox</groupId>
		    <artifactId>pdfbox-tools</artifactId>
		    <version>2.0.24</version> <!-- 可以根据需要选择最新版本 -->
		</dependency>
		<dependency>
		    <groupId>org.apache.pdfbox</groupId>
		    <artifactId>fontbox</artifactId>
		    <version>2.0.24</version> <!-- 可以根据需要选择最新版本 -->
		</dependency>
		
		<dependency>
		    <groupId>com.github.jai-imageio</groupId>
		    <artifactId>jai-imageio-core</artifactId>
		    <version>1.4.0</version>
		</dependency>

====

====

■之前TIF相关的问题(两张TIF合并)

TIF合并Java代码_jai-codec-CSDN博客

====

■对于成果物TIF,需要考虑的点

不是单纯生成TIF就可以了,还要考虑以下问题

①白黒閾値

②解像度 (分辨率) (DPI) ⇒ 一般设置为200

③圧縮方式 -----CCITT T.4

④位深度 1,8,24,32 // 代码  ⇒  ImageType.BINARY

⑤XXXX高 XXXX幅  ⇒ 影响坐标位置

⑥ファイルのサイズ  XXXXKB

⑦分辨率单位 // TODO 代码如何指定

⑧是否还要在生成的TIF上写入什么(番号),或者重新写入什么(比如页码 1/4 ⇒1/5)// 已经实现

⑨4页的PDF,出力1,2,4页**// 已经实现**

⑩処理スピード(处理速度)

⑪事前確認 上流SystemのInput (PDF)

下流Systemへ連携のTIF (受到上面①~⑦影響、下流系统能否正常读取)

====

====

■问题

■问题1:无法生成TIF,已解决

问题:结果全部为false。

解决:

方法1:pom中添加如下引用

XML 复制代码
		<dependency>
		    <groupId>com.github.jai-imageio</groupId>
		    <artifactId>jai-imageio-core</artifactId>
		    <version>1.4.0</version>
		</dependency>

方法2:使用jdk9

====

■问题2:生成的TIF过大,已解决

====

我原本文件才0.3M,生成的TIF有3M的大小。。。。

====方法2解决后的效果

===

解决方法1:使用LZW方式压缩 (质量高)

java 复制代码
package com.sxz.study.pdf;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIFCompress {

	public static void main(String[] args) {
		try {
			// Load the PDF document
			PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Test.pdf"));

			// Create a PDF renderer
			PDFRenderer pdfRenderer = new PDFRenderer(document);

			// Iterate over each page in the PDF document
			for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);

		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("LZW");
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
}

===

ImageType.GRAY

位深度是 8

====

解决方法2:让图片位深度为黑白(binary),并且使用CCITT方式压缩 (质量低)

===

ImageType.GRAY 时,代码运行会报错

Caused by: javax.imageio.IIOException: Bits per sample must be 1 for T4 compression!

==

java 复制代码
package com.sxz.study.pdf;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIFCompress {

	public static void main(String[] args) {
		try {
			// Load the PDF document
			PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Test.pdf"));

			// Create a PDF renderer
			PDFRenderer pdfRenderer = new PDFRenderer(document);

			// Iterate over each page in the PDF document
			for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);

		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("LZW");
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
}

===

===

■相关工具

SVF

====4141

1.1. SVF Connect for Java APIの機能概要 (wingarc.com)

==== ウイングアーク1stコーポレートサイト

会社概要 | ウイングアーク1stコーポレートサイト (wingarc.com)

===

foxit

xxx

===

■相关知识

ImageIO.write 的结果是 false 的原因

如果ImageIO.write方法返回false,可能有几种原因导致无法成功将BufferedImage写入TIF文件。以下是一些常见原因和可能解决方法:

  1. 缺少合适的ImageWriter:ImageIO在写入图像时需要能够识别和处理指定格式(这里是TIF)的ImageWriter。可能需要确保已经安装了支持TIF格式的插件。通常,这些插件会提供相应的ImageWriter类。

    解决方法:可以尝试安装支持TIF格式的插件,例如JAI Image I/O Tools。您可以在Maven中添加以下依赖项:

XML 复制代码
		<dependency>
		    <groupId>com.github.jai-imageio</groupId>
		    <artifactId>jai-imageio-core</artifactId>
		    <version>1.4.0</version>
		</dependency>

转换时报错 type 4 gsub lookup table is not supported

报错"Type 4 gsub lookup table is not supported"通常是由于字体文件中的某种字符映射表(lookup table)不受支持而导致的。字形字体(OpenType字体)中的子集(subset)可能包含一些复杂的字符映射表,而某些库可能无法正确解析或处理这些表。您可以尝试以下解决方法:

  1. 使用全字形字体(Full OpenType Font):如果可能,尝试使用未经子集化的完整字形字体,而不是子集化的字体。全字形字体包含完整的字符集和字符映射表,可能更容易被解析和处理。

  2. 更新软件版本:检查您使用的库或工具是否存在更新版本,有时新版本可能会修复一些已知的问题。

  3. 选择其他字体或库:尝试使用其他字体或处理字体的库来查看能否解决该问题。不同的库可能有不同的实现方式,可能支持更多的字符映射表类型。

  4. 解析错误:检查报错代码所在的地方,看看是否可以在代码中进行特定的处理,例如跳过不支持的部分或者采取其他替代方案。

DPI是什么

DPI代表"每英寸点数"(Dots Per Inch),是衡量输出设备打印或显示分辨率的度量单位。它表示在每英寸内打印机或显示器能够输出多少个像素点。在打印领域中,DPI表示每英寸的打印点密度,越高的DPI通常意味着更高的打印质量和更细致的图像。在显示器领域中,DPI用来描述屏幕的像素密度,影响屏幕展示的清晰度和细节。

例如,如果一台打印机的DPI为600,则表示在打印一英寸长度的纸张上,这台打印机可以输出600个点(像素),从而打印出高分辨率的图像或文档。

在设计和图像处理中,DPI也很重要,因为它决定了图像在输出时的清晰度和质量。对于印刷品、海报、名片等需要高质量印刷的材料,通常需要使用高DPI的图像以确保印刷效果。

总之,DPI是衡量输出设备分辨率的重要指标,对于打印、显示和图像处理等领域都有着重要作用。

一英寸 是多少厘米

一英寸等于2.54厘米。这是国际上普遍接受的英制和公制长度单位之间的换算关系。根据这个换算关系,1英寸等于2.54厘米。

图片的 位深度

图片的位深度是指图像中每个像素的颜色值所占用的位数。位深度越高,可以表示的颜色范围就越大,图像也会更加细致。常见的位深度有:

1位深度:每个像素只有两种颜色,通常用于黑白图像或简单的图标。 ImageType.BINARY

8位深度:每个像素有256种颜色,通常用于网页图像或简单的照片。 ImageType.GRAY

24位深度:每个像素有约1677万种颜色,通常用于高质量的照片。

32位深度:除了颜色信息外,还包含Alpha通道信息,用于透明度处理。

不同的位深度会影响图像的颜色表现和细节展现,选择合适的位深度能够更好地展现图片的效果。

==

■功能扩展

转换为TIF时,能否在TIF中的某个坐标点,再追加什么信息

==

要在TIF图像的某个坐标点追加额外信息,你可以使用Java开发中的图像处理库,如ImageMagick或Java自带的图像处理库,来在生成的TIF图像上绘制文本或其他图形。

下面是一个示例代码,演示如何使用Java的Graphics2D来在TIF图像的指定坐标绘制文本信息:

例子代码

java 复制代码
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;

public class PdfToTifConverter {

    public static void main(String[] args) {
        try {
            File pdfFile = new File("input.pdf");
            PDDocument document = PDDocument.load(pdfFile);
            PDFRenderer pdfRenderer = new PDFRenderer(document);

            for (int page = 0; page < document.getNumberOfPages(); ++page) {
                BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);

                // 在图像上绘制文本信息
                Graphics2D g = bim.createGraphics();
                g.setColor(Color.RED);
                g.setFont(new Font("Arial", Font.PLAIN, 20));
                g.drawString("Additional Info", 100, 100);
                g.dispose();

                ImageIOUtil.writeImage(bim, "output_" + page + ".tif", 300);
            }

            document.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

===

完整代码

java 复制代码
package com.sxz.study.pdf;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPdfToTifComPressCCITTWithInfo {

	public static void main(String[] args) {
		try {
			// Load the PDF document
			PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\0830.pdf"));

			// Create a PDF renderer
			PDFRenderer pdfRenderer = new PDFRenderer(document);

			// Iterate over each page in the PDF document
			for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.BINARY);

				
		        // 在图像上绘制文本信息
                // 抹去之前的信息
                Graphics2D g2 = image.createGraphics();
                g2.setColor(Color.white);
                g2.setFont(new Font("Arial", Font.PLAIN, 80));
                g2.drawString("■■■■■■■■■■■■■■■■■■■■■■■■", 400, 400);
                g2.dispose();

                Graphics2D g3 = image.createGraphics();
                g3.setColor(Color.white);
                g3.setFont(new Font("Arial", Font.PLAIN, 80));
                g3.drawString("■■■■■■■■■■■■■■■■■■■■■■■■", 405, 400);
                g3.dispose();
                
                Graphics2D g4 = image.createGraphics();
                g4.setColor(Color.white);
                g4.setFont(new Font("Arial", Font.PLAIN, 80));
                g4.drawString("■■■■■■■■■■■■■■■■■■■■■■■■", 410, 400);
                g4.dispose();
                
                Graphics2D g5 = image.createGraphics();
                g5.setColor(Color.white);
                g5.setFont(new Font("Arial", Font.PLAIN, 80));
                g5.drawString("■■■■■■■■■■■■■■■■■■■■■■■■", 415, 400);
                g5.dispose();
                
                // 写上想要的信息
                Graphics2D g = image.createGraphics();
                g.setColor(Color.BLACK);
                g.setFont(new Font("Arial", Font.PLAIN, 20));
                g.drawString("66666666666666666666666666666666666666666", 410, 400);
                g.dispose();
                

		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("CCITT T.4");
		        //writeParam.setCompressionQuality(1.0f);
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
}

===

===

4页的PDF,取出一部分,生成3页的PDF

==

java 复制代码
package com.sxz.study.pdf;

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;

public class TestPdfAllToPDF {

	// java代码实现,iput1:1到页的PDF,output :1,2,4页的PDF
    public static void main(String[] args) {
        try {
            File inputFile = new File("C:\\test\\PDF\\input.pdf");
            PDDocument document = PDDocument.load(inputFile);

            PDDocument outputDocument = new PDDocument();
            int[] selectedPages = {0, 1, 3}; // 选择要提取的页面,索引从0开始

            for (int pageNumber : selectedPages) {
                if (pageNumber < document.getNumberOfPages()) {
                    PDPage page = document.getPage(pageNumber);
                    outputDocument.addPage(page);
                } else {
                    System.out.println("Invalid page number: " + (pageNumber + 1));
                }
            }

            outputDocument.save("C:\\test\\PDF\\output.pdf");
            outputDocument.close();

            document.close();
            System.out.println("Selected pages extracted successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

xxx

===

印章(在右上角)

部分代码(参考)

java 复制代码
public static void main(String[] args) throws IOException {
    int imageSize = 150;
    BufferedImage bufferedImage = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = bufferedImage.createGraphics();
    // 防止出现锯齿
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
    g2d.setComposite(AlphaComposite.Src);
    g2d.setColor(Color.red);
    g2d.setStroke(new BasicStroke(3));
    // 绘画起点xy坐标并非圆心坐标
    g2d.drawOval(2, 2, imageSize - 4, imageSize - 4);

    // 绘画五角星
    int r = 20;
    int centerPoint = imageSize / 2;
    Map<String, List<Integer>> pointersMap = new HashMap<>();
    // 五角星6点坐标 O为圆心点
    pointersMap.put("O", Arrays.asList(centerPoint, centerPoint));
    pointersMap.put("A", Arrays.asList(centerPoint, centerPoint - r));
    pointersMap.put("B", Arrays.asList((int)(centerPoint + Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
    pointersMap.put("C", Arrays.asList((int)(centerPoint + Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
    pointersMap.put("D", Arrays.asList((int)(centerPoint - Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
    pointersMap.put("E", Arrays.asList((int)(centerPoint - Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
    // 6点组合绘画图像
    List<String> pointerComposes = Arrays.asList("A,D,O,C", "B,E,O,D", "C,A,O,E", "D,A,O,B", "E,C,O,B");
    // 查找绘画点进行绘画
    for (String pointerCompose : pointerComposes) {
      String[] pointerKeys = pointerCompose.split(",");
      Polygon polygon = new Polygon();
      for (String pointerKey : pointerKeys) {
        polygon.addPoint(pointersMap.get(pointerKey).get(0), pointersMap.get(pointerKey).get(1));
      }
      g2d.fillPolygon(polygon);
    }

    int whiteSpace = 75;
    double padding = 1.5;
    String companyName = "XXXXXXXXXXXXXXXXXX";
    // 根据名称长度 动态设置字体大小 防止文字过多发生文字碰撞
    int fontSize = (60 - companyName.length()) / 3;
    // 平移画布使环形文字在圆圈内
    g2d.translate(centerPoint - fontSize / 2, 0);
    // 文字开始位置 大概在左下角
    g2d.rotate(((double) whiteSpace / 360) * Math.PI + Math.PI, fontSize / 2, centerPoint);
    Font font = new Font("FangSong_GB2312", Font.ROMAN_BASELINE, fontSize);
    g2d.setFont(font);
    // 在文字开始位置 第二个字符开始进行按计算角度进行旋转 从而生成环形文字
    double rotateAngle = (double) (360 - whiteSpace) * Math.PI / (180 * (companyName.length() - 1));
    for (int i = 0; i < companyName.toCharArray().length; i++) {
      if (i != 0) {
        g2d.rotate(rotateAngle, fontSize/2, centerPoint);
      }
      g2d.drawString(String.valueOf(companyName.toCharArray()[i]), 0, (int) (fontSize * padding));
    }

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bufferedImage, "png", baos);

    String path = String.format("D:/data/seal_image/seal.%s.png",
        DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(
            LocalDateTime.now()));
    File file = new File(path);
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    fileOutputStream.write(baos.toByteArray());
    baos.close();
    fileOutputStream.close();
  }

全部代码

java 复制代码
package com.sxz.study.pdf;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIFCompressLZWWithStamp {

    public static void main(String[] args) {
        try {
            // Load the PDF document
            PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Test.pdf"));
            
            // Create a PDF renderer
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            
            // Iterate over each page in the PDF document
            for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);

				
				
		        // 在图像上绘制  印章
                Graphics2D g2d = image.createGraphics();
 
                int imageSize = 150;
                // 防止出现锯齿
                g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
                g2d.setComposite(AlphaComposite.Src);
                g2d.setColor(Color.red);
                g2d.setStroke(new BasicStroke(3));
                // 绘画起点xy坐标并非圆心坐标
                g2d.drawOval(2, 2, imageSize - 4, imageSize - 4);
             
                // 绘画五角星
                int r = 20;
                int centerPoint = imageSize / 2;
                Map<String, List<Integer>> pointersMap = new HashMap<>();
                // 五角星6点坐标 O为圆心点
                pointersMap.put("O", Arrays.asList(centerPoint, centerPoint));
                pointersMap.put("A", Arrays.asList(centerPoint, centerPoint - r));
                pointersMap.put("B", Arrays.asList((int)(centerPoint + Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
                pointersMap.put("C", Arrays.asList((int)(centerPoint + Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
                pointersMap.put("D", Arrays.asList((int)(centerPoint - Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
                pointersMap.put("E", Arrays.asList((int)(centerPoint - Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
                // 6点组合绘画图像
                List<String> pointerComposes = Arrays.asList("A,D,O,C", "B,E,O,D", "C,A,O,E", "D,A,O,B", "E,C,O,B");
                // 查找绘画点进行绘画
                for (String pointerCompose : pointerComposes) {
                  String[] pointerKeys = pointerCompose.split(",");
                  Polygon polygon = new Polygon();
                  for (String pointerKey : pointerKeys) {
                    polygon.addPoint(pointersMap.get(pointerKey).get(0), pointersMap.get(pointerKey).get(1));
                  }
                  g2d.fillPolygon(polygon);
                }
             
                int whiteSpace = 75;
                double padding = 1.5;
                String companyName = "中国足球七比零";
                // 根据名称长度 动态设置字体大小 防止文字过多发生文字碰撞
                int fontSize = (60 - companyName.length()) / 3;
                // 平移画布使环形文字在圆圈内
                g2d.translate(centerPoint - fontSize / 2, 0);
                // 文字开始位置 大概在左下角
                g2d.rotate(((double) whiteSpace / 360) * Math.PI + Math.PI, fontSize / 2, centerPoint);
                Font font = new Font("FangSong_GB2312", Font.ROMAN_BASELINE, fontSize);
                g2d.setFont(font);
                // 在文字开始位置 第二个字符开始进行按计算角度进行旋转 从而生成环形文字
                double rotateAngle = (double) (360 - whiteSpace) * Math.PI / (180 * (companyName.length() - 1));
                for (int i = 0; i < companyName.toCharArray().length; i++) {
                  if (i != 0) {
                    g2d.rotate(rotateAngle, fontSize/2, centerPoint);
                  }
                  g2d.drawString(String.valueOf(companyName.toCharArray()[i]), 0, (int) (fontSize * padding));
                }
             
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                
				g2d.setColor(Color.BLACK);
				g2d.dispose();
             
//                String path = String.format("D:/data/seal_image/seal.%s.png",
//                    DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(
//                        LocalDateTime.now()));
//                File file = new File(path);
//                FileOutputStream fileOutputStream = new FileOutputStream(file);
//                fileOutputStream.write(baos.toByteArray());
//                baos.close();
//                fileOutputStream.close();
			
                // ----end
				
				
		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("LZW");
		        //writeParam.setCompressionQuality(1.0f);
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
}

===

===

印章(改进版)(坐标自己定义)

初版 (修改前 Base)

java 复制代码
package com.sxz.study.pdf;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIFCompressLZWWithStampXY {

    public static void main(String[] args) {
        try {
            // Load the PDF document
            PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Test.pdf"));
            
            // Create a PDF renderer
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            
            // Iterate over each page in the PDF document
            for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);

				
				// 打印图章
				printStamp(image, 0, 0);


		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("LZW");
		        //writeParam.setCompressionQuality(1.0f);
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
    
    
    public static void printStamp(BufferedImage image, int xxx ,int yyy){
    	
        // 在图像上绘制  印章
        Graphics2D g2d = image.createGraphics();

        int imageSize = 150;
        // 防止出现锯齿
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
        g2d.setComposite(AlphaComposite.Src);
        g2d.setColor(Color.red);
        g2d.setStroke(new BasicStroke(3));
        // 绘画起点xy坐标并非圆心坐标
        g2d.drawOval(2, 2, imageSize - 4, imageSize - 4);
     
        // 绘画五角星
        int r = 20;
        int centerPoint = imageSize / 2;
        Map<String, List<Integer>> pointersMap = new HashMap<>();
        // 五角星6点坐标 O为圆心点
        pointersMap.put("O", Arrays.asList(centerPoint, centerPoint));
        pointersMap.put("A", Arrays.asList(centerPoint, centerPoint - r));
        pointersMap.put("B", Arrays.asList((int)(centerPoint + Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
        pointersMap.put("C", Arrays.asList((int)(centerPoint + Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
        pointersMap.put("D", Arrays.asList((int)(centerPoint - Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
        pointersMap.put("E", Arrays.asList((int)(centerPoint - Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
        // 6点组合绘画图像
        List<String> pointerComposes = Arrays.asList("A,D,O,C", "B,E,O,D", "C,A,O,E", "D,A,O,B", "E,C,O,B");
        // 查找绘画点进行绘画
        for (String pointerCompose : pointerComposes) {
          String[] pointerKeys = pointerCompose.split(",");
          Polygon polygon = new Polygon();
          for (String pointerKey : pointerKeys) {
            polygon.addPoint(pointersMap.get(pointerKey).get(0), pointersMap.get(pointerKey).get(1));
          }
          g2d.fillPolygon(polygon);
        }
     
        int whiteSpace = 75;
        double padding = 1.5;
        String companyName = "中国足球七比零";
        // 根据名称长度 动态设置字体大小 防止文字过多发生文字碰撞
        int fontSize = (60 - companyName.length()) / 3;
        // 平移画布使环形文字在圆圈内
        g2d.translate(centerPoint - fontSize / 2, 0);
        // 文字开始位置 大概在左下角
        g2d.rotate(((double) whiteSpace / 360) * Math.PI + Math.PI, fontSize / 2, centerPoint);
        Font font = new Font("FangSong_GB2312", Font.ROMAN_BASELINE, fontSize);
        g2d.setFont(font);
        // 在文字开始位置 第二个字符开始进行按计算角度进行旋转 从而生成环形文字
        double rotateAngle = (double) (360 - whiteSpace) * Math.PI / (180 * (companyName.length() - 1));
        for (int i = 0; i < companyName.toCharArray().length; i++) {
          if (i != 0) {
            g2d.rotate(rotateAngle, fontSize/2, centerPoint);
          }
          g2d.drawString(String.valueOf(companyName.toCharArray()[i]), 0, (int) (fontSize * padding));
        }
     
		g2d.setColor(Color.BLACK);
		g2d.dispose();
     	
    }
    
    
    
}

定义坐标位置

效果

代碼(修改后可用代碼)

java 复制代码
package com.sxz.study.pdf;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToTIFCompressLZWWithStampXY {

    public static void main(String[] args) {
        try {
            // Load the PDF document
            PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Test.pdf"));
            
            // Create a PDF renderer
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            
            // Iterate over each page in the PDF document
            for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.GRAY);

				
				// 打印图章
				printStamp(image, 600, 500);


		        ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		        writeParam.setCompressionType("LZW");
		        //writeParam.setCompressionQuality(1.0f);
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".tif"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
    
    
    public static void printStamp(BufferedImage image, int xxx ,int yyy){
    	
        // 在图像上绘制  印章
        Graphics2D g2d = image.createGraphics();

        int imageSize = 150;
        // 防止出现锯齿
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
        g2d.setComposite(AlphaComposite.Src);
        g2d.setColor(Color.red);
        g2d.setStroke(new BasicStroke(3));
        // 绘画起点xy坐标并非圆心坐标
		g2d.drawOval(2 + xxx, 2 + yyy, imageSize - 4, imageSize - 4);
     
        // 绘画五角星
        int r = 20;
        int centerPoint = imageSize / 2;
        Map<String, List<Integer>> pointersMap = new HashMap<>();
        // 五角星6点坐标 O为圆心点
        pointersMap.put("O", Arrays.asList(centerPoint, centerPoint));
        pointersMap.put("A", Arrays.asList(centerPoint, centerPoint - r));
        pointersMap.put("B", Arrays.asList((int)(centerPoint + Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
        pointersMap.put("C", Arrays.asList((int)(centerPoint + Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
        pointersMap.put("D", Arrays.asList((int)(centerPoint - Math.sin(0.2 * Math.PI) * r), (int)(centerPoint + Math.cos(0.2 * Math.PI) * r)));
        pointersMap.put("E", Arrays.asList((int)(centerPoint - Math.sin(0.4 * Math.PI) * r), (int)(centerPoint - Math.cos(0.4 * Math.PI) * r)));
        // 6点组合绘画图像
        List<String> pointerComposes = Arrays.asList("A,D,O,C", "B,E,O,D", "C,A,O,E", "D,A,O,B", "E,C,O,B");
        // 查找绘画点进行绘画
        for (String pointerCompose : pointerComposes) {
          String[] pointerKeys = pointerCompose.split(",");
          Polygon polygon = new Polygon();
          for (String pointerKey : pointerKeys) {
            polygon.addPoint(pointersMap.get(pointerKey).get(0) + xxx, pointersMap.get(pointerKey).get(1) + yyy);
          }
          g2d.fillPolygon(polygon);
        }
     
        int whiteSpace = 75;
        double padding = 1.5;
        String companyName = "中国足球七比零";
        // 根据名称长度 动态设置字体大小 防止文字过多发生文字碰撞
        int fontSize = (60 - companyName.length()) / 3;
        // 平移画布使环形文字在圆圈内
		g2d.translate((centerPoint - fontSize / 2) + xxx, 0 + yyy);
        // 文字开始位置 大概在左下角
        g2d.rotate(((double) whiteSpace / 360) * Math.PI + Math.PI, fontSize / 2, centerPoint);
        Font font = new Font("FangSong_GB2312", Font.ROMAN_BASELINE, fontSize);
        g2d.setFont(font);
        // 在文字开始位置 第二个字符开始进行按计算角度进行旋转 从而生成环形文字
        double rotateAngle = (double) (360 - whiteSpace) * Math.PI / (180 * (companyName.length() - 1));
        for (int i = 0; i < companyName.toCharArray().length; i++) {
          if (i != 0) {
            g2d.rotate(rotateAngle, fontSize/2, centerPoint);
          }
          g2d.drawString(String.valueOf(companyName.toCharArray()[i]), 0 , (int) (fontSize * padding) );
        }
     
		g2d.setColor(Color.BLACK);
		g2d.dispose();
     	
    }
    
    
    
}

====

PDF生成jpg图片

java 复制代码
package com.sxz.study.pdf;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class TestPDFToJpg {

	public static void main(String[] args) {
		try {
			// Load the PDF document
			PDDocument document = PDDocument.load(new File("C:\\test\\PDF\\Java.pdf"));

			// Create a PDF renderer
			PDFRenderer pdfRenderer = new PDFRenderer(document);

			// Iterate over each page in the PDF document
			for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
				// Render the PDF page to a BufferedImage
				// BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 300,
				// ImageType.RGB);
				BufferedImage image = pdfRenderer.renderImageWithDPI(pageNumber, 200, ImageType.RGB);

		        ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
		        ImageWriteParam writeParam = writer.getDefaultWriteParam();
		        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
//		        writeParam.setCompressionType("LZW");
				
		        // 创建输出文件流
		        FileImageOutputStream output = new FileImageOutputStream(new File("C:\\test\\PDF\\output_" + (pageNumber + 1) + ".jpg"));
		        writer.setOutput(output);

		        // 写入压缩后的TIF图像
		        writer.write(null, new IIOImage(image, null, null), writeParam);

		        // 关闭输出流
		        output.close();
		        
			}

			// Close the PDF document
			document.close();

			System.out.println("PDF converted to TIF successfully");
		} catch (Exception e) {
			e.printStackTrace();

		}
	}
}

==

===

代码比较(印章 和 JPG),代码原理

==

介绍一下 java中的Graphics2D 类

Graphics2D类是Java 2D图形库中的一个关键类,它扩展了Graphics类,提供了更强大和灵活的绘图功能。Graphics2D类允许开发人员在屏幕上绘制2D图形,包括线条、形状、文本和图像等。以下是Graphics2D类的一些重要特性和用途:

  1. 继承自Graphics类:Graphics2D类继承自Graphics类,因此可以使用所有Graphics类中定义的方法,并添加了更多的高级图形绘制方法。

  2. 支持图形的平移、旋转、缩放等操作:通过Graphics2D类提供的方法,可以轻松地对绘制的2D图形进行平移、旋转、缩放等变换操作,从而实现更灵活的绘图效果。

  3. 支持抗锯齿渲染:Graphics2D类可以实现图形的抗锯齿渲染,使绘制出来的图形边缘更加平滑,提高图形绘制的质量。

  4. 绘制简单图形:通过drawLine()drawRect()drawOval()等方法,可以在画布上绘制直线、矩形、椭圆等简单形状。

  5. 绘制复杂图形:Graphics2D类提供了一系列高级绘图方法,使开发人员可以创建和绘制复杂的图形,如贝塞尔曲线、路径、复杂的多边形等。

  6. 绘制文本和图像:除了绘制图形外,Graphics2D类还提供了绘制文本和图像的方法,可以在图形上添加文字或插入图片。

总的来说,Graphics2D类是Java中2D图形绘制的一个核心类,提供了丰富的功能和方法,使开发人员可以实现各种各样的绘图效果。如果您需要在Java应用程序中进行2D图形绘制和渲染操作,Graphics2D类是一个非常有用和强大的工具。

==

印章代码参照

java圆形印章生成_java.awt 画印章-CSDN博客

====

相关推荐
一个处女座的程序猿9 小时前
LLMs之PDF:zeroX(一款PDF到Markdown 的视觉模型转换工具)的简介、安装和使用方法、案例应用之详细攻略
pdf·markdown·zerox
Dxy12393102169 小时前
python下载pdf
数据库·python·pdf
周亚鑫9 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
一名技术极客10 小时前
Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览
pdf·powerpoint·excel·文件在线预览
S. Dylan1 天前
Edge浏览器打开PDF无法显示电子签章
edge·pdf
一马平川的大草原1 天前
如何基于pdf2image实现pdf批量转换为图片
计算机视觉·pdf·文件拆分
m0_594526301 天前
Python批量合并多个PDF
java·python·pdf
hairenjing11231 天前
将图片添加到 PDF 的 5 种方法
pdf
✿゚卡笨卡1 天前
pdf 添加页眉页脚,获取前五页
java·pdf
blegn1 天前
PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)
pdf·办公软件·office