Recibir PDF y darle el formato necesario

Para recibir archivos PDF del backend, se nos enviarán como un array de bytes. Si se nos envía directamente ese array como cuerpo de la respuesta, podemos especificar desde Axios el tipo de respuesta, así:

return axios.get(url, { responseType: "arraybuffer" });

El otro caso posible es que dicho array de bytes sea parte de un objeto, sólo un campo entre otros. Para transformarlo al formato de arraybuffer que queremos es más complicado. Para ello, podemos utilizar unas funciones auxiliares que hay definidas en este archivo: pdfUtil.js. Además, también se incluyen los métodos para devolver un objeto con el formato del visor de pdfs, y para descargarlo.

Este archivo lo podemos colocar en nuestro proyecto en src/util/pdfUtil.js. Contiene el siguiente código.

export default {
  b64ToUint6(nChr) {
    return nChr > 64 && nChr < 91 ? nChr - 65 : nChr > 96 && nChr < 123 ? nChr - 71 : nChr > 47 && nChr < 58 ? nChr + 4 : nChr === 43 ? 62 : nChr === 47 ? 63 : 0;
  },
  base64DecToArr(sBase64, nBlocksSize) {
    var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""),
      nInLen = sB64Enc.length,
      nOutLen = nBlocksSize ? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize : (nInLen * 3 + 1) >> 2,
      taBytes = new Uint8Array(nOutLen);

    for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
      nMod4 = nInIdx & 3;
      nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (18 - 6 * nMod4);
      if (nMod4 === 3 || nInLen - nInIdx === 1) {
        for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
          taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255;
        }
        nUint24 = 0;
      }
    }

    return taBytes;
  },
  descargarPdf(pdfArrayBuf, nombre) {
    var blob = new Blob([pdfArrayBuf], { type: "application/pdf" });
    // IE doesn't allow using a blob object directly as link href
    // instead it is necessary to use msSaveOrOpenBlob
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(blob);
      return;
    }
    // For other browsers:
    // Create a link pointing to the ObjectURL containing the blob.
    const data = window.URL.createObjectURL(blob);
    var link = document.createElement("a");
    link.href = data;
    link.download = nombre;
    link.click();
    setTimeout(function() {
      // For Firefox it is necessary to delay revoking the ObjectURL
      window.URL.revokeObjectURL(data);
    }, 100);
  },
  pdfVisor(pdfArrayBuf) {
      return { data: pdfArrayBuf }
  }
};

Para utilizarlo en nuestros componentes, sólo tendríamos que importarlo y ya podríamos usarlo con pdfUtil.metodo(), así:

<script>
import pdfUtil from "@/util/pdfUtil.js";

export default {
  ...
  computed: {
    // Para el visor de pdf
    pdfVisor: function() {
      if(this.objConPdf) {
        return pdfUtil.pdfVisor(this.objConPdf.pdf)
      }
      return null
    }
  },
  methods: {
    getObjConPdf() {
      this.servicioRest.getPdf().then((response) => {
        if (response.status == 200) {
          this.objConPdf = response.data;
          this.objConPdf.pdf = pdfUtil.base64DecToArr(this.objConPdf.pdf).buffer;
        }
      });
    },
	// Mapeamos el método del pdfUtil a uno del componente, pues desde el <template> no se pueden acceder a los métodos importados
    descargarPdf: pdfUtil.descargarPdf,
  },
};
</script>

Visor de PDF

Para Vue tenemos disponible vue-pdf, que podemos descargar con:

npm i vue-pdf

Y lo utilizaríamos de esta forma:

<div class="visorPdf" style="width: 60%; margin-left:auto; margin-right:auto">
      <pdf v-if="objConPdf" :src="pdfVisor" style="border: solid 1px grey" />
    </div>

En el parámetro src le tenemos que indicar un objeto con una estructura, que podemos obtener con pdfUtil.pdfVisor(pdfArrayBuffer).