com.google.zxing 解析 电子发票pdf 内容 转图片

  1. 场景,将电子发票pdf 文件解析后,再通过google.zxing解析(主要是根据发票二维码<图>)
    由于电子发票文件本身并非纯粹的图片 & pdf 文件,所以处理方案为将pdf 按照 page 内容转图片再去验证发票内容;

使用
// 利用PdfBox生成图像
PDDocument pdDocument = PDDocument.load(pdfFile);
PDFRenderer renderer = new PDFRenderer(pdDocument);
BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);
将pdf 转图片后

遇到问题:
1、发票中的二维码转换成图片后无法识别; 原因(因为光点干扰、换句话说就是 pdf 转换图片不够保真);
2、极个别电子发票,二维码无法和发票内容 无法整体识别转图片;(也就是转存图片后,二维码丢失了);

以上两种情况 google.zxing 解析时候,矩阵均会抛出 com.google.zxing.NotFoundException: null

此时,只要将pdf 解析后的图片输出; 就可以发现问题所在了;
当然,问题1 的场景比较难,直观看出; 博主也是搜索他人经验后猜测可能是这种情况;(最后证实确实;)

处理方式:
采用使用多种方式结合; 如果 方式1 无法解析,那么采用方式2去重新解析; 最后还解析不能的话,才报错;

针对问题1,
将pdf 读取成黑白格式的图片可以解决;
renderer.renderImageWithDPI(pageIndex, 296, ImageType.GRAY);
方法 pdfToImage(); 代码下面贴上

针对问题 2:
采用
PDPage page = document.getPage(pageIndex);
PDResources resources = page.getResources();
PDImageXObject obj = (PDImageXObject) resources.getXObject(name);
这种方式去直接提取电子发票的图片讯息;(二维码等)
方法 retryAgain();代码下面贴上

依赖引用;

1)、
	<dependency>
	       <groupId>org.icepdf.os</groupId>
	       <artifactId>icepdf-core</artifactId>
	       <version>6.2.2</version>
	</dependency>
    <dependency>
        	<groupId>org.apache.pdfbox</groupId>
        	<artifactId>pdfbox</artifactId>
        	<version>2.0.19</version>
        </dependency> 
      
	<dependency>
		    <groupId>com.levigo.jbig2</groupId>
		    <artifactId>levigo-jbig2-imageio</artifactId>
		    <version>2.0</version>
	</dependency> 

另外遇到一个奇特的现象;
暂时不知道原因;
便是,同一代码;

PDDocument pdDocument = PDDocument.load(pdfFile);
PDFRenderer renderer = new PDFRenderer(pdDocument);
BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);

单引入 pdfbox 包时 ,google.zxing 解析报错;
引入 pdfbox & levigo-jbig2-imageio 两个包;google.zxing 解析 成功;

总结:
如果单纯读取 pdf 内容转图片的话,采用方式 1 即可; 引入 pdfbox & levigo-jbig2-imageio 两个包;

代码:

 public static List<File> pdfToImage(File pdfFile) {
        List<File> list = new ArrayList<>();
        try {
            logger.debug(">>处理开始");
            // System.setProperty(PROPERTY_KEY, PROPERTY_VALUE);
            // 图像合并使用参数
            // 总宽度
            int width = 0;
            // 保存一张图片中的RGB数据
            int[] singleImgRGB;
            int shiftHeight = 0;
            // 保存每张图片的像素值
            BufferedImage imageResult = null;
            // 利用PdfBox生成图像
            PDDocument pdDocument = PDDocument.load(pdfFile);
            PDFRenderer renderer = new PDFRenderer(pdDocument);
            // 生成目录
            String fileRealName = pdfFile.getName().replace(".pdf", "");
            // 循环每个页码
            for (int i = 0, len = pdDocument.getNumberOfPages(); i < len; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);
                int imageHeight = image.getHeight();
                int imageWidth = image.getWidth();
                // 计算高度和偏移量
                // 使用第一张图片宽度;
                width = imageWidth;
                // 保存每页图片的像素值
                imageResult = new BufferedImage(width, imageHeight, BufferedImage.TYPE_INT_RGB);
                singleImgRGB = image.getRGB(0, 0, width, imageHeight, null, 0, width);
                // 写入流中
                imageResult.setRGB(0, shiftHeight, width, imageHeight, singleImgRGB, 0, width);

                // 对图片进行等比例缩放0.95
                AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(1, 1), null);
                
                imageResult = ato.filter(image, null);

                File file = new File(fileRealName + "_" + (i + 1) + ".png");
                // 写图片
                ImageIO.write(imageResult, DEFAULT_FORMAT, file);

                if (i % 10 == 0 || i + 1 == len) {
                    logger.debug("处理进度:{}/{}", i + 1, len);
                }
                list.add(file);
            }
            pdDocument.close();
            logger.debug("处理结束>>");
            return list;
        } catch (Exception e) {
            logger.error("PDF转图片失败:{}", e);
        }
        return list;
    }
/**
	 * @description 仅解析发票漂浮的盖章(二维码 或者 是整个图片);  PDResources
	 * @param file
	 * @param pageIndex
	 * @return
	 */
	public static Map<String, Object> retryAgain(File file, int pageIndex) {

		log.debug("前置位两种方式尝试解析都失败,最后尝试retryAgain方法解析;");

		Map<String, Object> ret = new HashedMap<String, Object>();
		ret.put("status", -1);

		HashMap<DecodeHintType, Object> hints = new HashMap<>();
		// 设置编码字符集
		hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
		hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);

		List<BufferedImage> imageList = new ArrayList<BufferedImage>();
		PDDocument document = null;
		File optFile = null, tempFile = null;
		try {
			document = PDDocument.load(file);

			int number = document.getNumberOfPages();

			if (pageIndex < 0 || pageIndex >= number)
				return ret;

			// 电子发票读取指定一页
			PDPage page = document.getPage(pageIndex);
			PDResources resources = page.getResources();

			// 仅解析发票漂浮的盖章(二维码 或者 是整个图片);
			for (COSName name : resources.getXObjectNames())
				if (resources.isImageXObject(name)) {
					PDImageXObject obj = (PDImageXObject) resources.getXObject(name);
					imageList.add(obj.getImage());
				}

			String savepath = file.getAbsolutePath().replace(".pdf", "");
			// pdfbox_image.png
			tempFile = new File(savepath);
			if (!tempFile.exists())
				tempFile.mkdirs();

			Result result = null;
			BinaryBitmap binaryBitmap;

			String filePath = savepath + "\\pdfbox_image.png";

			for (BufferedImage img : imageList) {
				optFile = new File(filePath);
				ImageIO.write(img, "PNG", optFile);
				// 转灰色
				img = IcePdf.changeImg(optFile);

				binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(img)));
				result = new MultiFormatReader().decode(binaryBitmap, hints);

				if (null != result && !StringUtil.isNullOrEmpty(result.getText())) {
					ret = getInvoiceInfo(result.getText());
					break;
				}
			}

		} catch (Exception e) {
			log.error("retryAgain 异常={}", e);
		} finally {
			try {
				// 关闭document
				document.close();

				// 移除业务过程中生成的目录和文件
				if (null != optFile)
					optFile.delete();

				if (null != tempFile)
					tempFile.delete();
			} catch (Exception e) {
				log.error("关闭document、移除业务过程中生成的目录和文件 异常 Exception={}", e);
			}
		}

		log.debug("retryAgain 执行结束 ret = {}", ret);
		return ret;
	}

com.google.zxing
识别发票方法;

/**
     * 扫描图片二维码并封装发票信息
     *
     * @param file
     * @param companyId
     * @param userId
     * @return
     * @throws IOException
     * @throws ParseException
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static Map<String, Object> readQRCode(File file, String companyId, String userId)
            throws IOException, ParseException {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", 1);
        MultiFormatReader formatReader = new MultiFormatReader();
        // 读取图片
        // BufferedImage image = ImageIO.read(file);
        BufferedImage image = changeImg(file);
        if (null == image) {
            log.error("转换图片异常,image为空");
            return map;
        }
        BinaryBitmap binaryBitmap =
                new BinaryBitmap(
                        new HybridBinarizer(new BufferedImageLuminanceSource(image.getSubimage(0, 0, 800, 800))));

        // 定义二维码的参数
        HashMap hints = new HashMap();
        // 设置编码字符集
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
        // 处理读取结果
        Result result = null;
        try {
            result = formatReader.decode(binaryBitmap, hints);
            if (result != null && !StringUtil.isNullOrEmpty(result.getText())) {
                map = getInvoiceInfo(result.getText());
            }
        } catch (NotFoundException e) {
            map.put("status", -1);
            log.error("readQRCode执行异常={}",e);
        }
        return map;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: com.google.zxing.client.j2se是一个用于在Java平台上实现二维码编码和解码的开源工具包。它是Google提供的ZXing (Zebra Crossing)项目的一部分。 ZXing是一个功能强大的开源条码库,它支持多种条码类型的生成和解码,包括二维码、一维码、PDF417条码等。com.google.zxing.client.j2se是ZXing项目的J2SE (Java 2 Platform, Standard Edition)平台的客户端,提供了在Java中使用ZXing库的接口。 通过com.google.zxing.client.j2se,我们可以轻松地在Java应用程序中生成和解码二维码。要生成二维码,我们可以通过调用库提供的API传入需要编码的文本或数据,并指定生成的二维码的大小、颜色和其他属性。生成的二维码可以保存为PNG、JPEG或其他格式的图像文件,也可以直接显示在应用程序的界面上。 在解码方面,com.google.zxing.client.j2se提供了解码二维码的功能。我们可以将从图像文件或摄像头中读取的二维码图像传递给库,并使用提供的API进行解码。解码结果会返回编码的文本或数据。 com.google.zxing.client.j2se还提供了一些辅助功能,包括通过图像文件或摄像头扫描二维码、从图像文件中读取条形码等。它为开发人员提供了简单易用的接口,使得在Java应用程序中实现二维码编码和解码变得非常方便。 总之,com.google.zxing.client.j2se是一个功能强大且易于使用的Java库,用于在Java应用程序中生成和解码二维码。它是ZXing项目的一部分,为开发人员提供了丰富的功能和接口来实现二维码相关的功能。 ### 回答2: com.google.zxing.client.j2se是一个用于在Java平台上实现条形码和二维码的解码和编码的库。它是GoogleZXing项目的一部分,ZXing是一个开源的条形码和二维码处理库。 com.google.zxing.client.j2se提供了一系列的类和方法,可以方便地在Java应用程序中集成条形码和二维码的扫描和生成功能。它可以用于扫描和解码包括QR码、Aztec码、Data Matrix码和条形码等在内的各种标准码制。 使用com.google.zxing.client.j2se,我们可以通过简单的代码实现扫描设备上的条形码或者解码一张包含条形码的图片。同时,它还提供了生成不同种类的条形码和二维码的功能,我们可以通过设置一些参数,如编码格式、大小、颜色等,来生成符合需求的条形码和二维码。 除了基本的条形码和二维码的解码和编码功能,com.google.zxing.client.j2se还提供了一些附加功能,如解码图片中的所有条形码和二维码、将解码结果保存到本地文件、识别条形码的类型等。这些功能使得它非常实用和灵活。 总的来说,com.google.zxing.client.j2se是一个功能强大的Java库,能够在Java应用程序中方便地实现条形码和二维码的解码和编码功能,提供了丰富的接口和方法,可以满足不同需求的使用场景。 ### 回答3: com.google.zxing.client.j2se是一个Java平台上的开源二维码解码库。它是基于Google ZXing项目开发的,可以用于读取和解码二维码图像。 该库具有丰富的功能和灵活的接口,可以在Java应用程序中方便地集成二维码解码的能力。它支持多种不同类型的二维码,包括QR码、Data Matrix码、Aztec码和PDF417码等。只需导入库文件,开发人员就可以轻松地使用它来解码二维码图像中的数据。 使用com.google.zxing.client.j2se,开发人员可以将二维码解码功能嵌入到各种应用程序中。例如,该库可以用于扫描二维码来获取网址、产品信息或其他数据。它还可以用于读取二维码中的文本或是进行身份验证等操作。 此外,com.google.zxing.client.j2se还提供了一些附加功能,例如生成二维码图像和自定义解码选项等。开发人员可以根据自己的需求来设置解码的参数,例如条码边界的大小、颜色、方向等等。 总的来说,com.google.zxing.client.j2se是一个强大的工具,可用于在Java平台上实现二维码的读取和解码功能。它易于使用,具有丰富的功能和灵活的接口,适用于各种应用场景。无论是开发识别二维码的移动应用程序,还是在企业中实现二维码解码的功能,这个库都是一个不错的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值