瀏覽代碼

排版pdf导出

24282 1 年之前
父節點
當前提交
2ebf9cfd8e

+ 8 - 0
sd-business/src/main/java/com/sd/business/controller/work/WorkOrderController.java

@@ -93,4 +93,12 @@ public class WorkOrderController {
         workOrderService.reschedule(dto.getId());
     }
 
+    /**
+     * pdf导出
+     */
+    @PostMapping("/pdfExport")
+    public String pdfExport(@RequestBody BaseSelectDto dto) {
+        return workOrderService.pdfExport(dto.getId());
+    }
+
 }

+ 16 - 1
sd-business/src/main/java/com/sd/business/entity/work/constant/MaterialsConstant.java

@@ -3,9 +3,19 @@ package com.sd.business.entity.work.constant;
 public interface MaterialsConstant {
 
     /**
+     * 收缩
+     */
+    double SHRINK = 0.5;
+
+    /**
+     * 边距
+     */
+    double MARGIN = 0.3;
+
+    /**
      * 出血长度
      */
-    double RESERVE = 0.8;
+    double RESERVE = SHRINK + MARGIN;
 
     /**
      * 卷材长度
@@ -17,4 +27,9 @@ public interface MaterialsConstant {
      */
     int MASTER_WIDTH = 163;
 
+    /**
+     * 图片dpi
+     */
+    double DPI = 600;
+
 }

+ 5 - 0
sd-business/src/main/java/com/sd/business/service/work/WorkOrderService.java

@@ -58,4 +58,9 @@ public interface WorkOrderService extends BaseService<WorkOrder> {
      */
     void reschedule(Long id);
 
+    /**
+     * pdf导出
+     */
+    String pdfExport(Long id);
+
 }

+ 245 - 0
sd-business/src/main/java/com/sd/business/service/work/impl/WorkOrderServiceImpl.java

@@ -1,11 +1,17 @@
 package com.sd.business.service.work.impl;
 
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.HashBasedTable;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfWriter;
 import com.ruoyi.common.constant.StatusConstant;
 import com.ruoyi.common.core.domain.BaseIdPo;
 import com.ruoyi.common.exception.ServiceException;
@@ -52,11 +58,23 @@ import com.sd.business.util.packing.model.Item;
 import com.sd.framework.util.Assert;
 import com.sd.framework.util.TransactionUtil;
 import com.sd.framework.util.sql.Sql;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.imageio.ImageIO;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.math.BigDecimal;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -64,6 +82,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -78,6 +102,7 @@ import java.util.stream.Stream;
  * @author
  * @since 2024-01-02
  */
+@Slf4j
 @Service
 public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder> implements WorkOrderService {
 
@@ -104,6 +129,17 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
     @Autowired
     private OrderSkuBomService orderSkuBomService;
 
+    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
+            8,
+            16,
+            60,
+            TimeUnit.SECONDS,
+            new LinkedBlockingQueue<>(16),
+            Executors.defaultThreadFactory(),
+            new ThreadPoolExecutor.CallerRunsPolicy()
+    );
+
+
     @Override
     public Page<WorkOrderVo> getPage(WorkOrderSelectDto dto) {
 
@@ -351,6 +387,215 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
     }
 
     /**
+     * 旋转图片
+     */
+    public static BufferedImage rotateImage(BufferedImage bi) {
+        // 获取原图像的宽和高
+        int width = bi.getWidth();
+        int height = bi.getHeight();
+
+        // 创建一个新图像,宽高与原图相反
+        BufferedImage rotatedImage = new BufferedImage(height, width, bi.getType());
+
+        // 创建 AffineTransform 对象
+        AffineTransform at = new AffineTransform();
+
+        // 设置旋转中心为原图像的中心点
+        int centerX = width / 2;
+        int centerY = height / 2;
+        at.rotate(Math.toRadians(90), centerX, centerY); // 角度转换为弧度
+        at.translate(centerX - centerY, centerX - centerY); // 注意这里的平移是逆向的
+
+        // 使用 AffineTransformOp 进行旋转
+        AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
+        return op.filter(bi, rotatedImage);
+    }
+
+    /**
+     * 缩放图片
+     */
+    public static void convert(BufferedImage imageNew, String target) {
+        // 宽度保持不变
+        int subImageWidth = imageNew.getWidth();
+        int subImageHeight = 14400;
+
+        Document document = new Document();
+        //设置文档页边距
+        document.setMargins(0, 0, 0, 0);
+        FileOutputStream fos = null;
+
+        try {
+            fos = new FileOutputStream(target);
+            PdfWriter.getInstance(document, fos);
+
+            //打开文档
+            document.open();
+
+            int y = 0;
+            while (y < imageNew.getHeight()) {
+
+                int heightToCut = Math.min(subImageHeight, imageNew.getHeight() - y);
+
+                // 截取图片的一部分
+                BufferedImage subImage = imageNew.getSubimage(0, y, subImageWidth, heightToCut);
+
+                // 将截取的图片转换为iTextPDF的Image对象
+                com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(subImage, null);
+
+                //图片居中
+                img.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
+
+                //设置页面宽高与图片一致
+                Rectangle rectangle = new Rectangle(subImageWidth, heightToCut);
+                document.setPageSize(rectangle);
+
+                // 添加到PDF文档
+                document.newPage();
+                document.add(img);
+
+                y += subImageHeight;
+            }
+
+            //关闭文档
+            document.close();
+
+        } catch (Exception e) {
+            log.error("生成pdf失败", e);
+            throw new ServiceException("生成pdf失败");
+        } finally {
+            IoUtil.flush(fos);
+            IoUtil.close(fos);
+        }
+    }
+
+    /**
+     * 毫米转像素
+     *
+     * @param mm 毫米
+     * @return 像素值
+     */
+    static int mmToPx(double mm) {
+        // 因为1英寸等于25.4毫米
+        return Convert.toInt(Math.round(mm * MaterialsConstant.DPI / 25.4));
+    }
+
+    /**
+     * 图片缩放
+     *
+     * @param image  图片
+     * @param width  缩放后的宽
+     * @param height 缩放后的高
+     * @return 缩放后的图片
+     */
+    public static BufferedImage scale(BufferedImage image, int width, int height) {
+
+        Image newImage = ImgUtil.scale(image, width, height);
+
+        // 创建一个具有相同尺寸和类型(ARGB)的新BufferedImage
+        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+
+        // 获取Graphics2D对象以绘制图像
+        Graphics2D g2d = bufferedImage.createGraphics();
+
+        // 将源图像绘制到BufferedImage上
+        g2d.drawImage(newImage, 0, 0, null);
+
+        // 关闭Graphics2D以释放资源
+        g2d.dispose();
+
+        return bufferedImage;
+    }
+
+    @Override
+    public String pdfExport(Long id) {
+        WorkOrder workOrder = getById(id);
+        List<WorkOrderDetail> list = workOrderDetailService.list(q -> q.eq(WorkOrderDetail::getWorkOrderId, id));
+        Set<Long> orderSkuIdList = list.stream().map(WorkOrderDetail::getOrderSkuId).collect(Collectors.toSet());
+        Map<Long, String> map = orderSkuService.mapKV(BaseIdPo::getId, OrderSku::getBlueprint, q -> q.in(BaseIdPo::getId, orderSkuIdList));
+
+        int canvasWidth = mmToPx(MaterialsConstant.MASTER_WIDTH);
+        int canvasHeight = mmToPx(workOrder.getMaxLength().doubleValue());
+
+        // 创建一个画布,并设置白色背景
+        BufferedImage imageNew = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_RGB);
+        Graphics graphics = imageNew.getGraphics();
+        graphics.setColor(Color.WHITE);
+        graphics.fillRect(0, 0, canvasWidth, canvasHeight);
+
+        Map<String, BufferedImage> bufferedImageMap = new ConcurrentHashMap<>();
+
+        CountDownLatch downLatch = new CountDownLatch(list.size());
+
+        for (WorkOrderDetail workOrderDetail : list) {
+
+            executor.execute(() -> {
+
+                try {
+
+                    // 外边框填充黑色
+                    int marginWidth = mmToPx(workOrderDetail.getWidth().doubleValue() + MaterialsConstant.RESERVE);
+                    int marginHeight = mmToPx(workOrderDetail.getLength().doubleValue() + MaterialsConstant.RESERVE);
+                    int x = mmToPx(workOrderDetail.getX().doubleValue());
+                    int y = mmToPx(workOrderDetail.getY().doubleValue());
+
+                    // 设置画笔颜色
+                    graphics.setColor(Color.BLACK);
+                    // 填充图片背景色为黑色
+                    graphics.fillRect(x, y, marginWidth, marginHeight);
+
+                    // 中间填充图片
+                    String filePath = map.get(workOrderDetail.getOrderSkuId());
+
+                    BufferedImage bi = bufferedImageMap.computeIfAbsent(filePath, item -> {
+                        try {
+                            // 读取图片
+                            URL url = new URL(filePath);
+                            return ImageIO.read(url);
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    });
+
+                    if (Objects.equals(workOrderDetail.getRotate(), StatusConstant.YES)) {
+                        bi = rotateImage(bi);
+                    }
+
+                    int width = mmToPx(workOrderDetail.getWidth().doubleValue() + MaterialsConstant.SHRINK);
+                    int height = mmToPx(workOrderDetail.getLength().doubleValue() + MaterialsConstant.SHRINK);
+                    bi = scale(bi, width, height);
+
+                    int[] ImageArrays = bi.getRGB(0, 0, width, height, new int[width * height], 0, width);
+
+                    imageNew.setRGB(
+                            x + (marginWidth - width) / 2,
+                            y + (marginHeight - height) / 2,
+                            width,
+                            height,
+                            ImageArrays, 0, width);
+
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                } finally {
+                    downLatch.countDown();
+                }
+
+            });
+
+        }
+
+        try {
+            downLatch.await();
+        } catch (InterruptedException e) {
+            log.error("downLatch异常", e);
+            throw new ServiceException("生成pdf失败");
+        }
+
+        convert(imageNew, "E:\\test2.pdf");
+
+        return null;
+    }
+
+    /**
      * 排版
      */
     private void scheduling(Long bomSpecId, Long printingPaperBomSpecId, List<OrderSku> list, Map<Long, SkuSpec> skuSpecMap) {

+ 25 - 0
sd-framework/pom.xml

@@ -48,6 +48,31 @@
             <version>33.0.0-jre</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>opencv</artifactId>
+            <version>4.7.0-1.5.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-imaging</artifactId>
+            <version>1.0-alpha3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itextpdf</artifactId>
+            <version>5.5.13.3</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.lowagie/itext -->
+        <dependency>
+            <groupId>com.lowagie</groupId>
+            <artifactId>itext</artifactId>
+            <version>4.2.2</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 0 - 25
sd-starter/pom.xml

@@ -30,31 +30,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.bytedeco</groupId>
-            <artifactId>opencv</artifactId>
-            <version>4.7.0-1.5.9</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-imaging</artifactId>
-            <version>1.0-alpha3</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.itextpdf</groupId>
-            <artifactId>itextpdf</artifactId>
-            <version>5.5.13.3</version>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/com.lowagie/itext -->
-        <dependency>
-            <groupId>com.lowagie</groupId>
-            <artifactId>itext</artifactId>
-            <version>4.2.2</version>
-        </dependency>
-
-        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>