demand

The mobile phone will download the PDF first and then open it locally on the mobile phone, but some mobile phones can not parse the PDF, so they will not look at the page, so they ask the PC when uploading, can you parse the PDF into pictures?

Analysis of the

1. The front-end needs to parse the PDF into an image before uploading

2. Parsed PNG images need to be produced by Aliyun

3. Ensure the order of uploading

The solution

According to the survey, the solution to problem 1 is PDFJS. Since we are vUE development, we use the secondary packaging component PDFJS-DIST. The first step is simply to create the component and import it directly

import PDFJS from 'pdfjs-dist'
Copy the code

If you want to get a local file, you have to input it so the template part of the code, you have to beautify the upload style yourself. This article theme function implementation, but more optimization style.

<template>
  <div>
    <input id="file" type="file" name="file" accept="pdf" @change="loadPDF" />
  </div>
</template>
Copy the code

Then click Upload to get the uploaded file and bloB the file. The reason for this is that when the PDF secondary component is passed you will find that it can only parse the BLOB.

public file_name = ' ';

// Load the PDF file
public async loadPDF(e: any) {
  console.log(e.target.files[0]);
  const file = e.target.files[0]
  const reader = new FileReader(); // Read the file method, instantiate

  this.file_name = e.target.files[0].name.split('. ') [0]; // Get the file name for later use

  reader.onload = (e) = > { 
    // Successful callback
    const url: string | null | ArrayBuffer = e.target ? e.target.result : ' ';
    this.showPDF(url as string)}; reader.readAsDataURL(file); }Copy the code

Then we enter the method of showPDF, here is the main logic, without further ado to analyze it

public async showPDF(url: string) {
    const pdf: any = await PDFJS.getDocument(url);  // If the url parameter is local, it needs bloB format.
    const pages = pdf.numPages; // Get the total number of entries
    const imgArr = []; // Finally return a collection of uploaded images

    EventBus.$emit('warning'.'Upload, do not operate');

    for (let i = 1; i <= pages; i++) {
      Html2canvas is also based on this principle
      const canvas = document.createElement('canvas') 
      const page = await pdf.getPage(i)
      const viewport = page.getViewport(2)
      const context = canvas.getContext('2d')

      canvas.height = viewport.height
      canvas.width = viewport.width

      const renderContext = {
        canvasContext: context,
        viewport
      }
      await page.render(renderContext)
			
      // This is where you want to upload oss directly.
      // However, you cannot upload Base64 directly to OSS. You need to convert Base64 to BLOB, and then convert bloB to file
      const image: any = canvas.toDataURL('image/png');
      const _fileBlob = this.dataURLtoBlob(image);
      const fileOfBlob = new File([_fileBlob], `The ${this.file_name}_page_${i}.png`);
      
      // Connect to ali cloud OSS directly and save the return value
      imgArr.push(await this.upload({file: fileOfBlob}))
    }
		
  	// Check whether all uploads are successful
    if(imgArr.length === pages) {
      EventBus.$emit('success'.'Upload successful');
      this.$emit('on-success', imgArr)
    } else {
      EventBus.$emit('error'.'Upload failed'); }}Copy the code

Base64 to BLOB method

public dataURLtoBlob(dataurl: string) {
  const arr = dataurl.split(', ');
  const reg = / : (. *?) ; /
  const res = arr[0].match(reg);
  const mime =  res ? res[1] : ' ';
  const bstr = atob(arr[1]);
  let len = bstr.length;
  const u8arr = new Uint8Array(len);

  while (len--) {
    u8arr[len] = bstr.charCodeAt(len);
  }

  return new Blob([u8arr], { type: mime });
}
Copy the code

Finally, direct connection to OSS

public async upload(option: any) {
    const {file = {}} = option;

    try {
      const credentials = await getPcBasicOss({
        bucket: xxx
      });

      return new Promise(async (res, rej) => {
        const zipfile = new File([file], file.name, {type: 'image/png'.lastModified: Date.now()});

        const client = new OSS({
          region: credentials.region,
          accessKeyId: credentials.AccessKeyId, // Temporary accessKeyId, different from the requested unique key, to prevent leakage
          accessKeySecret: credentials.AccessKeySecret , // Temporary accessKeySecret, which is different from the requested unique key, to prevent leakage
          stsToken: credentials.SecurityToken,
          bucket: credentials.bucket,
        });

        const date = new Date(a);const d = dayjs(date).format('YYYY-MM-DD').replace(/\-/g.' ');
        let code = ' ';
        for (let i = 1; i <= 6; i++) {
          const num = Math.floor(Math.random() * 10);
          code += num;
        }
        
        // There is no return value for aliyun upload
        const name = zipfile.name.substr(0, zipfile.name.lastIndexOf('. ')) + '_' +  d + code + zipfile.name.substr(zipfile.name.lastIndexOf('. '), zipfile.name.length);

        const result = await client.put(` /${name}`, zipfile); res(result); })}catch (e) {
      console.log(e); }}Copy the code

Test function passed, can have a good year, attached the entire file code

<script lang="ts"> import {Vue, Component} from 'vue-property-decorator'; import PDFJS from 'pdfjs-dist' import * as OSS from 'ali-oss'; import dayjs from 'dayjs'; import { getPcBasicOss } from '@/model'; import { EventBus } from 'feok-lib'; export interface DataType { path: string; // Path name: string; } @component export default class PdfToImg extends Vue {public file_name = "; Public async loadPDF(e: any) {console.log(e.target.files[0]); const file = e.target.files[0] const reader = new FileReader(); this.file_name = e.target.files[0].name.split('.')[0]; reader.onload = (e) => { const url: string | null | ArrayBuffer = e.target ? e.target.result : ''; this.showPDF(url as string) }; reader.readAsDataURL(file); } public async showPDF(url: string) { const pdf: any = await PDFJS.getDocument(url); const pages = pdf.numPages; const imgArr = []; EventBus.$emit('warning', 'uploaded, do not operate '); for (let i = 1; i <= pages; i++) { const canvas = document.createElement('canvas') const page = await pdf.getPage(i) const viewport = page.getViewport(2) const context = canvas.getContext('2d') canvas.height = viewport.height canvas.width = viewport.width const renderContext = { canvasContext: context, viewport } await page.render(renderContext) const image: any = canvas.toDataURL('image/png'); const _fileBlob = this.dataURLtoBlob(image); const fileOfBlob = new File([_fileBlob], `${this.file_name}_page_${i}.png`); Imgarr.push (await this.upload({file: fileOfBlob}))} if(imgarr.length === pages) {EventBus.$emit('success', 'upload successfully '); $emit('on-success', imgArr)} else {EventBus.$emit('error', 'upload failed '); } } public dataURLtoBlob(dataurl: string) { const arr = dataurl.split(','); const reg = /:(.*?) ; / const res = arr[0].match(reg); const mime = res ? res[1] : ''; const bstr = atob(arr[1]); let len = bstr.length; Const u8arr = new Uint8Array(len); While (len--) {u8arr[len] = bstr.charcodeat (len); } return new Blob([u8arr], {type: mime}); } public async upload(option: any) { const {file = {}} = option; try { const credentials = await getPcBasicOss({ bucket: process.env.NODE_ENV === 'production' ? 'asal':'zxtest001' }); return new Promise(async (res, rej) => { const zipfile = new File([file], file.name, {type: 'image/png', lastModified: Date.now()}); const client = new OSS({ region: credentials.region, accessKeyId: credentials.AccessKeyId, accessKeySecret: credentials.AccessKeySecret , stsToken: credentials.SecurityToken, bucket: credentials.bucket, }); const date = new Date(); const d = dayjs(date).format('YYYY-MM-DD').replace(/\-/g, ''); let code = ''; for (let i = 1; i <= 6; i++) { const num = Math.floor(Math.random() * 10); code += num; } const name = zipfile.name.substr(0, zipfile.name.lastIndexOf('.')) + '_' + d + code + zipfile.name.substr(zipfile.name.lastIndexOf('.'), zipfile.name.length); const result = await client.put(`/l-web-pc/${name}`, zipfile); res(result); }) } catch (e) { console.log(e); } } } </script> <template> <div> <input id="file" type="file" name="file" accept="pdf" @change="loadPDF" /> </div> </template> <style lang="less"> </style>Copy the code

In the pit of

Pdfjs-dist: “2.0.943”

reference

Developer.aliyun.com/article/716…

www.cnblogs.com/ssszjh/p/11…

Blog.csdn.net/ju__ju/arti…


If this article is useful, feel free to comment, like, and follow.

I’m Leo: I wish you all an early promotion and pay rise.