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

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

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

封装了组件代码

父组件直接放就可以了

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

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;

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我会提供一个简单的React聊天应用的后端代码和前端代码。 后端代码: ```javascript const app = require('express')(); const http = require('http').createServer(app); const io = require('socket.io')(http); io.on('connection', (socket) => { console.log('a user connected'); socket.on('sendMessage', (message) => { console.log('message', message); io.emit('newMessage', message); }); socket.on('disconnect', () => { console.log('user disconnected'); }); }); http.listen(3000, () => { console.log('listening on *:3000'); }); ``` 这是一个基于Express和Socket.io的简单后端代码,监听3000端口,处理客户端发来的sendMessage事件,并将消息广播给所有在线用户。 前端代码: ```javascript import React, { useState, useEffect, useRef } from 'react'; import io from 'socket.io-client'; const Chat = () => { const [messages, setMessages] = useState([]); const [message, setMessage] = useState(''); const [username, setUsername] = useState(''); const socketRef = useRef(); useEffect(() => { // 连接Socket.io服务器 socketRef.current = io.connect('http://localhost:3000'); // 监听新消息 socketRef.current.on('newMessage', (message) => { setMessages([...messages, message]); }); return () => { // 断开Socket.io连接 socketRef.current.disconnect(); }; }, [messages]); const handleSubmit = (e) => { e.preventDefault(); // 发送消息 socketRef.current.emit('sendMessage', { username, message }); // 清空消息框 setMessage(''); }; return ( <div> <h1>Chat</h1> <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} /> <input type="text" placeholder="Message" value={message} onChange={(e) => setMessage(e.target.value)} /> <button type="submit">Send</button> </form> <ul> {messages.map((msg, index) => ( <li key={index}> <strong>{msg.username}: </strong> {msg.message} </li> ))} </ul> </div> ); }; export default Chat; ``` 这是一个简单的React聊天组件,使用useState和useRef来管理状态和Socket.io连接,使用useEffect监听新消息并更新聊天记录列表。当用户发送消息时,调用handleSubmit函数发送消息到后端后端将消息广播给所有在线用户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值