java后端实现多张图片合并为一个pdf文件

需求

需要将前端传来的多张图片合并成一个pdf文件。

Pdfbox方式实现

依赖

在pom.xml里导入pdfbox依赖, Apache PDFBox 库是一个用于处理 PDF 文档的开源 Java 工具。商用也是免费

<!--   pdf文件处理包导入     -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version>
</dependency>

代码

    /**
     * @Description: 多张图片转化为pdf文件
     * @author: yqk
     * @date: 2024/5/16 20:47
     * @param images: 前端传来的图片文件List
     * @param savePdfName: 保存的pdf文件名
     * @Return: com.mt.webtest.entity.ComResult
     */
    @RequestMapping("/imageToPdf")
    public ComResult imageToPdf(@RequestParam("images") List<MultipartFile> images, String savePdfName){
        try{
            //存放pdf文件的目录
            String folderPath = "D:\\WorkData\\uploadTest";
            File outFolder = new File(folderPath);
            if(!outFolder.exists()){
                //递归创建文件夹
                outFolder.mkdirs();
            }
            if(images!=null || images.size()>0){
                try(PDDocument document = new PDDocument()){//创建pdf文件对象
                    for (MultipartFile multipartImage : images) {
                        if (!multipartImage.isEmpty()) {
                            String fileName = multipartImage.getOriginalFilename();
                            String fileHouZui = getFileType(fileName);
                            if (!isImage(fileHouZui)) {
                                //传来的文件不是图片就跳过
                                continue;
                            }
                            PDImageXObject image = PDImageXObject.createFromByteArray(document, multipartImage.getBytes(), "image");
                            // pdf文件里添加新的一页,页的宽高按照图片的宽高设置
                            PDRectangle pageSize = new PDRectangle(image.getWidth(), image.getHeight());
                            PDPage page = new PDPage(pageSize);
                            document.addPage(page);

                            try( PDPageContentStream contentStream = new PDPageContentStream(document, page);){
                                // 计算图片在pdf页中的起始点(x,y)、宽度(scaledWidth)和高度(scaledHeight)。
                                float pageWidth = pageSize.getWidth();
                                float pageHeight = pageSize.getHeight();
                                float imageWidth = image.getWidth();
                                float imageHeight = image.getHeight();
                                float scale = Math.min(pageWidth / imageWidth, pageHeight / imageHeight);
                                float scaledWidth = imageWidth * scale;
                                float scaledHeight = imageHeight * scale;
                                float x = (pageWidth - scaledWidth) / 2;
                                float y = (pageHeight - scaledHeight) / 2;
                                //将图片填充入pdf页
                                contentStream.drawImage(image, x, y, scaledWidth, scaledHeight);
                            }catch (Exception e){
                                return  ComResult.fail(e);
                            }

                        }
                    }
                    // 4. 保存PDF
                    document.save(new File(folderPath+File.separator+savePdfName+".pdf"));
//                    document.save(folderPath+File.separator+savePdfName+".pdf");
                }catch (Exception e){
                    return  ComResult.fail(e.toString());
                }
            }
            return  ComResult.success("文件上传成功",savePdfName);
        }   catch (Exception e){
            return  ComResult.fail("操作异常"+e.toString());
        }
    }
    
    /**
    * @Description: 提取后缀名
    * @author: yqk
    * @date: 2024/5/16 20:45
    * @param name: 文件名
    * @Return: java.lang.String
    */
    private String getFileType(String name){
        if(StrUtil.isEmpty(name)){
            return null;
        }
        int index = 0;
        if((index=name.lastIndexOf("."))>-1){
            return  name.substring(index+1).toLowerCase();
        }
        return null;
    }
    
    /**
    * @Description: 判断后缀名是否属于文件类型
    * @author: yqk
    * @date: 2024/5/16 20:44
    * @param name: 后缀名
    * @Return: boolean false不是图片,true是图片
    */
    private boolean isImage(String name){
        if(StrUtil.isEmpty(name)){
            return false;
        }
        return    name.equals("jpg")
                ||name.equals("jpeg")
                ||name.equals("png")
                ||name.equals("gif")
                ||name.equals("bmp");
    }

返回的实体类,可以不用此类直接返回字符串

package com.mt.webtest.entity;

import lombok.Data;

/**
 * @author:yqk
 * @create: 2024-05-15 15:51
 * @Description:
 */
@Data
public class ComResult <T>{
    private boolean isSuccess;
    private int code;
    private String msg;
    private T data;
    public ComResult(boolean isSuccess,int code,String msg,T data){
        this.isSuccess = isSuccess;
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public static ComResult success(){
        return success("操作成功",null);
    }
    public static  <T> ComResult success(T data){
        return success("操作成功",data);
    }
    public static ComResult success(String msg){
        return success(msg,null);
    }
    public static <T> ComResult success(String msg ,T data){
        return new ComResult(true,200,msg,data);
    }

    public static <T> ComResult fail(String msg ,T data){
        return new ComResult(false,444,msg,data);
    }

    public static <T> ComResult fail(){
        return  fail("操作失败",null);
    }

    public static  ComResult fail(String msg){
        return  fail(msg,null);
    }

    public static <T> ComResult fail(T data){
        return  fail("操作失败",data);
    }
}

itextpdf方式实现

依赖

在pom.xml里导入itextpdf依赖,itextpdf的性能要比pdfbox好,但是商用是收费的,个人使用免费。

<!--   pdf文件处理包导入     -->
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itextpdf</artifactId>
	<version>5.4.3</version>
</dependency>

代码

    /**
    * @Description: 图片转pdf单线程版本
    * @author: yqk
    * @date: 2024/5/20 10:59
    * @param data:
    * @Return: byte[]
    */
    public static byte[] multipartFileToPdf(List<MultipartFile> data,UploadFileMsg uploadFileMsg) {
        Document document = new Document();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try{
            PdfWriter.getInstance(document, bos);
            document.open();
            for (MultipartFile datum : data) {
                Image   image = null;
                if (uploadFileMsg.getIsCompress()!= null&&uploadFileMsg.getIsCompress().equals("1")) {//压缩图片
                    try{
                        List<MultipartFile> multipartCompressFilesList = UploadUtil.compressToFile(UploadUtil.transferToFile(datum),"1","1",null,null);
                        image =  Image.getInstance(multipartCompressFilesList.get(0).getBytes());
                    }catch (Exception e){
                        log.error("图片压缩失败:"+e);
                    }
                }
                if(image==null){//不压缩图片
                    image = Image.getInstance(datum.getBytes());//加载图片
                }
                float imageWidth = image.getWidth();
                float imageHeight = image.getHeight();
                // 计算图片在pdf中的缩放比例(scale),和页边距(x,y)。
                Rectangle pageSize = null;
                if(StrUtil.isNotEmpty(uploadFileMsg.getPageSize())){
                    switch (uploadFileMsg.getPageSize().toUpperCase()){
                        case "A0":pageSize = PageSize.A0;break;
                        case "A1":pageSize = PageSize.A1;break;
                        case "A2":pageSize = PageSize.A2;break;
                        case "A3":pageSize = PageSize.A3;break;
                        case "A4":pageSize = PageSize.A4;break;
                        case "A5":pageSize = PageSize.A5;break;
                        case "A6":pageSize = PageSize.A6;break;
                        case "A7":pageSize = PageSize.A7;break;
                        case "A8":pageSize = PageSize.A8;break;
                        case "A9":pageSize = PageSize.A9;break;
                    }
                }
                if(pageSize == null){
                    pageSize = new Rectangle(imageWidth,imageHeight);
                }
                float pageWidth = pageSize.getWidth();
                float pageHeight = pageSize.getHeight();
                float scale = Math.min(pageWidth / imageWidth, pageHeight / imageHeight);
                float scaledWidth = imageWidth * scale;
                float scaledHeight = imageHeight * scale;
                float x = (pageWidth - scaledWidth) / 2;
                float y = (pageHeight - scaledHeight) / 2;
                image.scalePercent(scale*100);
                //设置pdf页大小, 和newPage位置不能对调,否则生成烂图
                document.setPageSize(pageSize);
                document.setMargins(x,x,y,y);
                document.newPage();
                document.add(image);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            document.close();
        }
        return bos.toByteArray();
    }

保存为文件

    @Override
    public CommResult uploadImagesConverPdfByItext(List<MultipartFile> uploadFiles, UploadFileMsg uploadFileMsg,
                                            HttpServletRequest request, ResourceManagerUploadVO resourceManagerUpload){
        System.out.println("开始:"+System.currentTimeMillis());
        if(uploadFiles==null || uploadFiles.size()==0){
            return CommResult.fail(400, "未检测到上传的文件!", "");
        }
        String foldername = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
        String username = null;
        LoginUser loginUser = (LoginUser) request.getSession().getAttribute("login");
        if(loginUser == null){//当session里面没有人员信息时使用前端上传过来的username
            username = resourceManagerUpload.getUserName();
        }else{
            username = loginUser.getUserName();
        }

        try{
            long startTime = System.currentTimeMillis();
            System.out.println("pdf转化开始:"+startTime);
            byte[] bytes = multipartFileToPdfDuoXianChen(uploadFiles,uploadFileMsg);
//            byte[] bytes = multipartFileToPdf(uploadFiles,uploadFileMsg);

            if(bytes==null || bytes.length==0){
                return CommResult.fail(400, "图片转化为pdf失败!", "");
            }
            long endTime = System.currentTimeMillis();
            System.out.println("pdf转化结束:"+endTime);
            System.out.println("pdf转化时间:"+(endTime-startTime));
            if(StrUtil.isEmpty(uploadFileMsg.getSaveName())){
                String saveName = uploadFiles.get(0).getOriginalFilename();
                uploadFileMsg.setSaveName(saveName.substring(0,saveName.lastIndexOf(".")));
            }
            uploadFileMsg.setSaveName(uploadFileMsg.getSaveName()+".pdf");
            MultipartFile NewMultipartFileYB =new MockMultipartFile("file", uploadFileMsg.getSaveName(), "text/plain", bytes);
            Map<String, Object> map = new HashMap();
            System.out.println("pdf保存到服务器开始:"+System.currentTimeMillis());
            String url = OSSUtils.uploadFileToOSSNotFileName(MTConstants.aliyun_bucketcommon, NewMultipartFileYB);
            System.out.println("pdf保存到服务器完成:"+System.currentTimeMillis());
            if(StrUtil.isEmpty(url)){
                return CommResult.fail(400, "文件保存失败!", "");
            }
            map.put("url",url);//路径
            map.put("name",uploadFileMsg.getSaveName());//文件名
            map.put("userName",username);//提交人
            long size = NewMultipartFileYB.getSize();//文件大小
            map.put("size", size);
            map.put("createTime",foldername);//提交时间
            System.out.println("结束:"+System.currentTimeMillis());
            return CommResult.success(200,"文件上传结果返回!",map);
        }catch (Exception e){
            log.error("文件合并异常"+e);
            return CommResult.fail(400, "文件合并异常!", "");
        }
    }

图片压缩方法

	//压缩图片文件
	public static List<MultipartFile> compressToFile(File file,  String scaleType,String scaleA,  String scaleWidth,  String scaleHeight) throws  Exception {
		List<MultipartFile>  multipartFileList =new ArrayList<>();

		try {
			String uuid=UUID.randomUUID().toString().replace("-","");
			String originalFilename = file.getName();
			String path = file.getPath();
			String name = file.getName();
			File fileSL = new File(path.replace(name,uuid+originalFilename));
			boolean pDImage =true;
			if (pDImage) {
				if (scaleType!=null&&scaleType.equals("1")) {
					float scale = 1;
					scale = Float.valueOf(scaleA);
					if (scaleA == null) {
						scale=	0.5f;
					}
					ImgUtil.scale(
							file,
							fileSL,
							scale//缩放比例
					);
				}else {
					int scaleWidthA = 0;
					int scaleHeightA = 0;
					try {
						scaleWidthA = Integer.parseInt(scaleWidth);
						scaleHeightA = Integer.parseInt(scaleHeight);
					} catch (NumberFormatException e) {
						throw  new RuntimeException("图片压缩比例错误");
					}
					if (scaleWidthA !=0&&scaleHeightA!=0) {
						ImgUtil.scale(
								file,
								fileSL,
								scaleWidthA,//缩放宽
								scaleHeightA,//缩放高
								null
						);
					}
				}
				FileInputStream inputSL = null;
				MultipartFile multipartFileSL = null;
				inputSL = new FileInputStream(fileSL);
				multipartFileSL =new MockMultipartFile("file", originalFilename, "text/plain", IOUtils.toByteArray(inputSL));
				multipartFileList.add(multipartFileSL);
			}
			return multipartFileList;
		} catch (RuntimeException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return multipartFileList;
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值