Ver Fonte

feat(image): 添加图片清晰化功能并优化OCR服务

- 新增ImageSharpController提供图片清晰化接口
- 实现ImageSharpTool工具类支持自定义卷积核锐化
- 添加Thumbnailator依赖支持图片处理功能
- 移除OCR服务中的AES加密解密逻辑
- 更新TruForService调用伪造检测接口地址
- 删除控制器中未使用的RequestMapping注解
kongxiangyang há 3 dias atrás
pai
commit
befc52854a

+ 13 - 0
crm-manager/pom.xml

@@ -87,6 +87,19 @@
             <scope>compile</scope>
         </dependency>
 
+        <!-- 纯Java锐化、缩放,无任何本地库依赖 -->
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.20</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.19</version>
+        </dependency>
+
 
     </dependencies>
 

+ 44 - 0
crm-manager/src/main/java/com/crm/manager/controller/ImageSharpController.java

@@ -0,0 +1,44 @@
+package com.crm.manager.controller;
+
+import com.crm.manager.util.ImageSharpTool;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+@RestController
+@RequiredArgsConstructor
+public class ImageSharpController {
+
+    private final ImageSharpTool imageSharpTool;
+
+    /**
+     * 图片清晰化接口
+     * 前端form-data传key=file的图片文件
+     * 响应:直接返回jpg图片流
+     */
+    @PostMapping(value = "/api/image/sharp", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public void sharpUploadImage(@RequestParam("file") MultipartFile file,
+                                 HttpServletResponse response) throws IOException {
+        // 校验文件非空
+        if (file.isEmpty()) {
+            response.setStatus(400);
+            response.getWriter().write("请上传图片文件");
+            return;
+        }
+
+        // 执行清晰化
+        byte[] clearImgBytes = imageSharpTool.sharpImage(file);
+
+        // 设置响应头,输出图片
+        response.setContentType(MediaType.IMAGE_JPEG_VALUE);
+        response.setHeader("Content-Disposition", "inline;filename=clear.jpg");
+        response.getOutputStream().write(clearImgBytes);
+        response.getOutputStream().flush();
+    }
+}

+ 0 - 1
crm-manager/src/main/java/com/crm/manager/controller/TruForController.java

@@ -6,7 +6,6 @@ import com.crm.rely.backend.model.entity.trufor.TruForCheckEntity;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController

+ 2 - 2
crm-manager/src/main/java/com/crm/manager/service/impl/OcrServiceImpl.java

@@ -43,10 +43,10 @@ public class OcrServiceImpl implements OcrService {
      */
     @Override
     public BaseResultDto result(OcrCheckEntity entity) {
-        entity.setImageBase64(AESUtil.decrypt(entity.getImageBase64(),getPropertyKey()));
+//        entity.setImageBase64(AESUtil.decrypt(entity.getImageBase64(),getPropertyKey()));
         // 这里开始调用 python 接口
         ImageConfig imageConfig = getImagePythonConfig();
-        return BaseResultDto.success(Constants.SUCCESS,AESUtil.encrypt(JSON.toJSONString(idCardOcr(entity.getImageBase64(),imageConfig.getOcrRequestUrl())),getPropertyKey()));
+        return BaseResultDto.success(Constants.SUCCESS,JSON.toJSONString(idCardOcr(entity.getImageBase64(),imageConfig.getOcrRequestUrl())));
     }
 
     /**

+ 3 - 3
crm-manager/src/main/java/com/crm/manager/service/impl/TruForServiceImpl.java

@@ -34,11 +34,11 @@ public class TruForServiceImpl implements TruForService {
 
     @Override
     public BaseResultDto result(TruForCheckEntity entity) {
-        entity.setImageBase64(AESUtil.decrypt(entity.getImageBase64(),getPropertyKey()));
+//        entity.setImageBase64(AESUtil.decrypt(entity.getImageBase64(),getPropertyKey()));
         // 这里开始调用 python 接口
         ImageConfig imageConfig = getImagePythonConfig();
-        ImageDetectResult imageDetectResult = imageForgedDetect(entity.getImageBase64(),imageConfig.getOcrRequestUrl());
-        return BaseResultDto.success(Constants.SUCCESS,AESUtil.encrypt(JSON.toJSONString(imageDetectResult),getPropertyKey()));
+        ImageDetectResult imageDetectResult = imageForgedDetect(entity.getImageBase64(),imageConfig.getForgeryRequestUrl());
+        return BaseResultDto.success(Constants.SUCCESS,imageDetectResult);
     }
 
     /**

+ 97 - 0
crm-manager/src/main/java/com/crm/manager/util/ImageSharpTool.java

@@ -0,0 +1,97 @@
+package com.crm.manager.util;
+
+import net.coobird.thumbnailator.Thumbnails;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+@Component
+public class ImageSharpTool {
+
+    /**
+     * 自定义卷积核锐化
+     */
+    public byte[] sharpImage(MultipartFile file) throws IOException {
+        byte[] fileBytes = file.getBytes();
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
+        BufferedImage sourceImg = ImageIO.read(inputStream);
+        if (sourceImg == null) {
+            throw new RuntimeException("不支持的图片格式,请上传jpg/png");
+        }
+
+        // 锐化卷积核 强度可调
+        float[] sharpKernel = {
+                0, -0.3f, 0,
+                -0.3f, 2.2f, -0.3f,
+                0, -0.3f, 0
+        };
+        Kernel kernel = new Kernel(3, 3, sharpKernel);
+        ConvolveOp convolveOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
+
+        // 创建画布渲染锐化后图片
+        BufferedImage sharpImg = new BufferedImage(sourceImg.getWidth(), sourceImg.getHeight(), sourceImg.getType());
+        Graphics2D g2d = sharpImg.createGraphics();
+        try {
+            g2d.drawImage(sourceImg, convolveOp, 0, 0);
+        } finally {
+            g2d.dispose();
+        }
+
+        // 输出jpg字节流
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Thumbnails.of(sharpImg)
+                .scale(1.0)
+                .outputQuality(0.92)
+                .outputFormat("jpg")
+                .toOutputStream(outputStream);
+
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 动态调节锐化强度
+     * @param sharpFactor 强度系数 1.0~3.0
+     */
+    public byte[] sharpImage(MultipartFile file, float sharpFactor) throws IOException {
+        byte[] fileBytes = file.getBytes();
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
+        BufferedImage sourceImg = ImageIO.read(inputStream);
+        if (sourceImg == null) {
+            throw new RuntimeException("不支持的图片格式,请上传jpg/png");
+        }
+
+        float val = (sharpFactor - 1f) * 0.3f;
+        float[] sharpKernel = {
+                0, -val, 0,
+                -val, 1 + 2*val, -val,
+                0, -val, 0
+        };
+        Kernel kernel = new Kernel(3, 3, sharpKernel);
+        ConvolveOp convolveOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
+
+        BufferedImage sharpImg = new BufferedImage(sourceImg.getWidth(), sourceImg.getHeight(), sourceImg.getType());
+        Graphics2D g2d = sharpImg.createGraphics();
+        try {
+            g2d.drawImage(sourceImg, convolveOp, 0, 0);
+        } finally {
+            g2d.dispose();
+        }
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Thumbnails.of(sharpImg)
+                .scale(1.0)
+                .outputQuality(0.92)
+                .outputFormat("jpg")
+                .toOutputStream(outputStream);
+
+        return outputStream.toByteArray();
+    }
+}

+ 53 - 0
crm-manager/src/main/java/com/crm/manager/util/ImageSharpUtil.java

@@ -0,0 +1,53 @@
+//package com.crm.manager.util;
+//
+//import jakarta.annotation.PostConstruct;
+//import org.opencv.core.*;
+//import org.opencv.imgcodecs.Imgcodecs;
+//import org.opencv.imgproc.Imgproc;
+//import org.springframework.stereotype.Component;
+//
+//
+//
+//@Component
+//public class ImageSharpUtil {
+//
+//    @PostConstruct
+//    public void loadOpenCV() {
+//        // 自动加载本地opencv动态库
+//        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+//    }
+//
+//    /**
+//     * 图片清晰化:高斯降噪 + 拉普拉斯锐化
+//     * @param inputPath 原图路径
+//     * @param outputPath 输出清晰图路径
+//     */
+//    public void sharpenImage(String inputPath, String outputPath) {
+//        // 读取图片
+//        Mat src = Imgcodecs.imread(inputPath);
+//        if (src.empty()) {
+//            throw new RuntimeException("读取图片失败");
+//        }
+//
+//        Mat blur = new Mat();
+//        // 1. 高斯模糊降噪(先降噪再锐化,避免放大噪点)
+//        Imgproc.GaussianBlur(src, blur, new Size(3, 3), 0);
+//
+//        Mat laplacian = new Mat();
+//        // 2. 拉普拉斯算子锐化
+//        Imgproc.Laplacian(blur, laplacian, CvType.CV_8U, 1);
+//
+//        Mat result = new Mat();
+//        // 原图 + 锐化细节 = 清晰图
+//        Core.addWeighted(src, 1.5, laplacian, -0.5, 0, result);
+//
+//        // 保存结果
+//        Imgcodecs.imwrite(outputPath, result);
+//
+//        // 释放内存
+//        src.release();
+//        blur.release();
+//        laplacian.release();
+//        result.release();
+//    }
+//}