react的pdf转图片格式上传到后端

这个东西做的我真的是头昏脑涨

主要需求是,upload上传pdf,pdf转图片格式展示,以图片格式上传到后端

封装了组件代码

父组件直接放就可以了

使用的插件pdfjs-dist,版本是 "pdfjs-dist": "2.5.207",

javascript 复制代码
import React, { useState, useEffect, useRef } from 'react';
import { Spin, Pagination } from 'antd';
import { Form, UploadProps, Image } from "antd";
import { message, Modal, Upload, Button } from "antd";
import { useDispatch, useSelector } from 'react-redux';
import type RootState from '@/types/rootState';
import { getToken } from "@/utils/login";
import config from "@/utils/config";
import type { RcFile, UploadChangeParam } from "antd/lib/upload";
import type { UploadFile } from "antd/es/upload/interface";
import { Toast } from "antd-mobile";
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
import type { PurchaseOrderAction } from "@/pages/purchase/purchaseOrder/model";
var pdfjsLib = require('pdfjs-dist/build/pdf.js');
import 'pdfjs-dist/build/pdf.worker.entry';

interface PdfViewerProps {
    url: string;
}
const formItemLayout = {
    labelCol: {
        span: 3,
    },
    wrapperCol: {
        span: 12,
    },
};
const PdfViewer = () => {
    const [pageNumbers, setPageNumbers] = useState(1);
    const [loading, setLoading] = useState(true);
    const [supportImages, setSupportImages] = useState<string[]>([]);
    const [uploadingImages, setUploadingImages] = useState<boolean>(false);
    const [supportFileList, setSupportFileList] = useState<UploadFile[]>([]);
    const [previewImage, setPreviewImage] = useState<string>('');
    const [previewVisible, setPreviewVisible] = useState<boolean>(false);
    const dispatch = useDispatch();
    const pdfRef: any = useRef(null);
    const processPage = async (pageNumbers: any, pdfFile: any, pdfName: any, uid: any, type: any) => {
       //  转base64
        let canvas: any = document.getElementById('pdf');
        let canvasContext = canvas.getContext('2d');
        const page = await pdfFile.getPage(pageNumbers);
        const viewport = page.getViewport({ scale: 5 });
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        canvasContext.clearRect(0, 0, canvas.width, canvas.height);

        const renderContext = {
            canvasContext: canvasContext,
            viewport: viewport,
            rotate: 90,
        };

        await page.render(renderContext).promise;
        // 转base64
        const imgUrl = canvas.toDataURL('image/jpg');
        const thumbimg = dataURLtoFile(imgUrl, 'image/png');
        const fileOfBlob = new File([thumbimg], `${pdfName}.png`);

        const formData = new FormData();
        formData.append('file', fileOfBlob, `${pdfName}.png`);
        formData.append('dir', 'purchase');
        
        const response = await fetch(config.api.pictureUpload, {
            method: 'POST',
            headers: {
                'x-access-token': getToken(),
            },
            body: formData,
        });

        if (response.ok) {
            const data = await response.json();
            return {
                uid: uid,
                name: `${pdfName}.png`,
                status: 'done',
                url: data.data,
            };
        }
        return null;
    }
   //  pdf转图片
    const processAllPages = async (numpage: any, pdfFile: any, pdfName: any, uid: any, type: any) => {
        const arr: any = [];
        const pdfImgArr:any = []
       //  pdf可能不止一个页面,循环提取
        for (let i = 1; i < numpage; i++) {
            const imgData = await processPage(i, pdfFile, pdfName, uid, type);
            if (imgData) {
                arr.push(imgData);
                pdfImgArr.push(imgData.url)
            }
        }
        setUploadingImages(false);
       //  因为我需要跟别的接口上传的图合并 ,所以做了存储
        dispatch<PurchaseOrderAction>({
            type: 'purchaseOrder/updateState',
            payload: {pdfImgArr},
        })
        
        setSupportFileList(arr);
    };
    const uploadProps: UploadProps = {
        action: config.api.pictureUpload,
        headers: {
            'x-access-token': getToken()!,
        },
        data: { dir: 'purchase' },
        listType: 'picture-card',
        showUploadList: false,
    };
    //  生成图片格式
    function dataURLtoFile(dataURI: any, type: any) {
        let binary = atob(dataURI.split(',')[1]);
        let array = [];
        for (let i = 0; i < binary.length; i++) {
            array.push(binary.charCodeAt(i));
        }
        return new Blob([new Uint8Array(array)], { type: type });
    }
   //  上传的文件 
    const handleUploadSupportImages = (file: UploadChangeParam<UploadFile<any>>) => {
        let name = file.file.name.split('.')[0]
        let uid = file.file.uid
        let type = 'image/png'
        const reader = new FileReader()
        reader.readAsArrayBuffer(file.file.originFileObj)
        reader.onload = function () {
            const pdfFile = reader.result;
            let loadingTask = pdfjsLib.getDocument(pdfFile);
            loadingTask.promise
                .then((pdf: any) => {
                    setPageNumbers(pdf.numPages);
                    let numpage = Number(pdf.numPages) + 1
                    if (numpage > 9) {
                        Toast.fail("超过数量限制!");
                        return
                    }
                    processAllPages(numpage, pdf, name, uid, type);
                })
                .catch((error: any) => {
                    console.log(error);
                })
                .finally(() => {
                    setLoading(false);
                });

        }
        if (file.file.status === 'uploading') {
            setUploadingImages(true);
            return;
        }
        if (file.file.status === 'done') {
            const { response } = file.file;
            supportImages.push(response.data);
            setSupportImages(supportImages);
            if (response.success) {
                dispatch<PurchaseOrderAction>({
                    type: 'deliveryDetail/updateState',
                    payload: {},
                });
                setUploadingImages(false);
            } else {
                message.error(response.message);
                setUploadingImages(false);
            }
        }

    };
    //预览
    const handlePreview = (file: UploadFile<any>) => {
        setPreviewImage(file.url! || file.thumbUrl!)
        setPreviewVisible(true)
    }
    const uploadImagesButton = (
        <div>
            {uploadingImages ? <LoadingOutlined /> : <PlusOutlined />}
            <div style={{ marginTop: 8 }}>上传pdf</div>

        </div>
    );
    const handleCancelPreview = () => {
        setPreviewVisible(false)
    }
    return (
        <>
            <Form.Item
                {...formItemLayout}
                label="导入pdf文件"
                hasFeedback
                style={{ marginTop: '15px' }}
            >
                <Upload
                    {...uploadProps}
                    showUploadList={true}
                    multiple={true}
                    accept='.pdf'
                    maxCount={1}
                    onPreview={handlePreview}
                    onChange={(info) => {
                        handleUploadSupportImages(info)
                    }}
                    showUploadList={{showRemoveIcon:false}}
                    fileList={supportFileList}
                >
                    {uploadImagesButton}
                </Upload>
            </Form.Item>

            <Modal
                open={previewVisible}
                title='图片预览'
                footer={null}
                onCancel={handleCancelPreview}
            >
                <img alt="example" style={{ width: '100%' }} src={previewImage} />
            </Modal>
            <canvas id="pdf" style={{ width: '0px' }} />
        </>
    );
};

export default PdfViewer;

写的可能还有些需要优化的,但是我已经累了,暂时先这样吧

相关推荐
Rattenking42 分钟前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
一名技术极客1 小时前
Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览
pdf·powerpoint·excel·文件在线预览
熊的猫2 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
小牛itbull6 小时前
ReactPress:重塑内容管理的未来
react.js·github·reactpress
S. Dylan15 小时前
Edge浏览器打开PDF无法显示电子签章
edge·pdf
一马平川的大草原15 小时前
如何基于pdf2image实现pdf批量转换为图片
计算机视觉·pdf·文件拆分
m0_5945263015 小时前
Python批量合并多个PDF
java·python·pdf
hairenjing112315 小时前
将图片添加到 PDF 的 5 种方法
pdf
✿゚卡笨卡15 小时前
pdf 添加页眉页脚,获取前五页
java·pdf
blegn15 小时前
PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)
pdf·办公软件·office