0
    async function saveBlob() {
        const doc = <TableDocument/>;
        const asPdf = pdf([]);
        await asPdf.updateContainer(doc);
        const blob = await asPdf.toBlob();
        saveAs(blob, 'instructions.pdf');
    }

    return (
        <IconButton
            onClick={() => saveBlob()}>
        </IconButton>
    );

This is how I am trying to generate my pdf doc by getting blob and then download it. I am doing all things at client side only using reactJS.

On Chrome and Edge browsers it takes 3-4 seconds only but on IE it takes around 30-40 seconds. Its a 3 page pdf doc with simple table (For single page IE takes around 8-9 seconds).

And even after using async await it blocks the UI. Any help to reduce time to generate pdf on IE will be highly appreciated.

Sachin Jagtap
  • 527
  • 6
  • 16
  • Have you used IE's dev tools' profiler (if there is such a thing) to see where it's spending its time? It might just be that IE is dog slow with the library. – AKX Jun 16 '21 at 13:46
  • @AKX I am not good at using profiler but for single page it takes around 8-9 seconds and for 3 page it takes 30-40 seconds to generate. Thanks for quick response – Sachin Jagtap Jun 16 '21 at 14:12
  • Well, you might want to post some of the profiler output here too. – AKX Jun 16 '21 at 14:14
  • @SachinJagtap Have you resolved the issue? Cos I'm facing the same problem – deymbwoi Nov 10 '21 at 12:01
  • @deymbwoi No I could not find solution, so we are going with server side pdf generation approach. – Sachin Jagtap Nov 11 '21 at 04:04
  • @deymbwoi i am using pdfmake library and its quite fast(https://pdfmake.github.io/docs/0.1/) – Sachin Jagtap Jan 05 '22 at 04:46

1 Answers1

0

I found pdfmake(https://pdfmake.github.io/docs/0.1/) library which is very fast in generating pdf from client side. on IE also it takes merely 2 seconds to generate pdf.

function TablePDF(t, headerGroups, rows, pageName, messageTitle, messageBody, fontLocale, fontMargin, rowFlag) {
  const moreRows = [...rows];

  const createTableHeader = col => {
    const val = t(col.Header);
    return { text: val && val.replace(/<\/br>|<br>/g, '\n'), style: 'tableHeader' };
  };

  const createTableRow = row => {
    const rowElement = [];
    Object.entries(row).map(([key, val]) => {
      if (key === 'notes' || (rowFlag && key === 'fileNameFileReference')) return null;
      const rowCellFormatted =
        key === 'instructionStatus'
          ? mapInstructionStatus(val)
          : key === 'instructionType'
          ? t(mapInstructionTypeStoreData(val))
          : val;

      const cellText =
        (rowCellFormatted &&
          (typeof rowCellFormatted === 'string' && rowCellFormatted.replace(/<\/br>|<br>/g, '\n'))) ||
        rowCellFormatted ||
        '';
      rowElement.push({
        text: cellText,
        margin: [5, fontMargin(getLanguageFont(cellText)), 5, 5],
        font: getLanguageFont(cellText)
      });
      return null;
    });
    return rowElement;
  };

  const getTableHeader = () => {
    const arrOfHeader =
      headerGroups &&
      headerGroups.length &&
      headerGroups[0].headers
        .filter(col => {
          if (
            col.render('Header') === 'ila.notes' ||
            (rowFlag && col.render('Header') === 'ila.fileNameFileReference')
          ) {
            return false;
          }
          return true;
        })
        .map((col, index) => createTableHeader(col, index));
    return arrOfHeader;
  };

  const arrOfHeader = getTableHeader();

  const getTableRows = () => moreRows.map(row => createTableRow(row.values));

  const pdfNote = t('ila.pdfNote');

  const mapInstructionStatus = status => {
    let statusToReturn = '';
    const INSTRUCTION_STATUS = ROW_INSTRUCTION_STATUS;
    switch (status) {
      case 'PA':
        statusToReturn = INSTRUCTION_STATUS[0].label;
        break;
      case 'RA':
        statusToReturn = INSTRUCTION_STATUS[1].label;
        break;
      case 'P2':
        statusToReturn = INSTRUCTION_STATUS[2].label;
        break;
      case 'R2':
        statusToReturn = INSTRUCTION_STATUS[3].label;
        break;
      case 'P3':
        statusToReturn = INSTRUCTION_STATUS[4].label;
        break;
      case 'R3':
        statusToReturn = INSTRUCTION_STATUS[5].label;
        break;
      case 'P4':
        statusToReturn = INSTRUCTION_STATUS[6].label;
        break;
      case 'P5':
        statusToReturn = INSTRUCTION_STATUS[7].label;
        break;
      case 'RB':
        statusToReturn = 'ila.receivedByBank';
        break;
      case 'JB':
        statusToReturn = 'ila.rejectedByBank';
        break;
      case 'JC':
        statusToReturn = 'ila.rejectedByCustomer';
        break;
      case 'RF':
        statusToReturn = 'ila.receivedFwdInstr';
        break;
      default:
        statusToReturn = t(`ila.instructionStatus_${status}`) ? `ila.instructionStatus_${status}` : '';
        break;
    }
    return t(statusToReturn);
  };

  const mapInstructionTypeStoreData = type => {
    switch (type) {
      case 'C0':
      case 'C1':
      case 'PP':
        return 'ila.pp';
      case 'CS':
      case 'COS':
        return 'ila.cos';
      case 'AP':
      case 'ACH':
      case 'APC':
        return 'ila.achCredit';
      case 'AD':
      case 'APD':
        return 'ila.achDebit';
      default:
        return type;
    }
  };

  const tableDoc = {
    pageOrientation: 'landscape',
    pageMargins: [25, 74, 25, 60],
    footer: (currentPage, pageCount) => PDFFooter(pageName, pageCount, currentPage),
    header: () => PDFHeader(fontMargin(fontLocale), pageName),
    content: [
      {
        text: [{ text: messageTitle, bold: true, color: 'black' }, { text: messageBody }, '\n', { text: pdfNote }],
        style: 'note'
      },
      {
        style: 'tableStyle',
        table: {
          headerRows: 1,
          dontBreakRows: true,
          body: [arrOfHeader, ...getTableRows()],
          widths:
            arrOfHeader.length === 9
              ? ['13.3%', '11.3%', '11.3%', '13.3%', '12.3%', '9.1%', '9.1%', '8.6%', '11.6%']
              : ['12.8%', '12.8%', '14.8%', '13.8%', '10.6%', '10.6%', '11.4%', '13.1%']
        },
        layout: {
          vLineWidth: () => 1.2,
          hLineWidth: hLineIndex => (hLineIndex === 1 ? 0 : 1.2),
          hLineColor: () => '#E4E8EA',
          // eslint-disable-next-line no-confusing-arrow
          vLineColor: (i, node, rowIndex) =>
            rowIndex === 0 || (i === 0 || i === arrOfHeader.length) ? 'white' : '#E4E8EA',
          fillColor: rowIndex => (rowIndex === 0 ? '#E4E8EA' : null)
        }
      }
    ],
    styles: {
      tableStyle: {
        margin: [0, fontMargin(fontLocale), 0, 20]
      },
      tableHeader: {
        bold: true,
        color: 'black',
        margin: [5, fontMargin(fontLocale), 5, 5]
      },
      note: {
        lineHeight: 2,
        italics: false
      }
    },
    defaultStyle: {
      columnGap: 10,
      font: fontLocale,
      color: '#333333',
      fontSize: 8
    }
  };
  return tableDoc;
}
export default TablePDF;

const date = new Date();
const gmtString = date.toGMTString();

const finalDate =
  JSON.stringify(gmtString).slice(6, 17) +
  ',' +
  JSON.stringify(gmtString).slice(17, 23) +
  JSON.stringify(gmtString).slice(26, 30);

const PDF_Footer = (pageName, totalPages, pageNumber, reference) => ({
  margin: [30, 20, 30, 10],
  stack: [
    {
      table: {
        headerRows: 1,
        widths: ['*'],
        body: [[''], ['']]
      },
      layout: {
        hLineWidth: i => (i === 0 ? 1 : 0),
        vLineWidth: () => 0,
        hLineColor: () => 'black'
      }
    },
    {
      columns: [
        finalDate + ' | ' + pageName + (reference || ''),
        {
          text: pageNumber && totalPages && `Page ${pageNumber} of ${totalPages}`,
          alignment: 'right'
        }
      ]
    }
  ],
  color: '#333333',
  bold: false
});

export default PDF_Footer;



export function getLanguageFont(text) {
  const universal = /^[a-zA-Z0-9_\-/.!@#$%^&*' 'wığüşöçĞÜŞÖÇİÀ-ÿ/]+$/;
  const arabic = /[\u0600-\u06FF]/;
  const hebrew = /[\u0590-\u05FF]/;
  const greek = /[\u0370-\u03ff\u1f00-\u1fff]/;
  const japanese = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/;
  const korean = /[\u3130-\u318F\uAC00-\uD7AF]/g;
  const russian = /[\u0401\u0451\u0410-\u044f]/;
  const vietnamese = /^[a-zA-ZÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ\s\W|_]+$/;
  const chinese = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/;
  if (universal.test(text)) {
    return 'UniverseNextHSBC';
  } else if (arabic.test(text)) {
    return 'arabicFont';
  } else if (hebrew.test(text)) {
    return 'hebrewFont';
  } else if (greek.test(text)) {
    return 'hebrewFont';
  } else if (japanese.test(text)) {
    return 'chineseSimple';
  } else if (korean.test(text)) {
    return 'korean';
  } else if (vietnamese.test(text)) {
    return 'vietnamese';
  } else if (chinese.test(text)) {
    return 'chineseSimple';
  }

  return 'UniverseNextHSBC';
}

      pdfMake.createPdf(tableDoc, null, fontCategories).download(('file.pdf', () => setDownloading(false)));


    
Sachin Jagtap
  • 527
  • 6
  • 16