Developer forum

Forum » Dynamicweb 10 » PDF=True
Jan Sangill
Reply

Hi,
PDF=True just shows a 404 page whenever I add it to the URL. Has this been discontinued? Or could it be something else I should do. I am doing an upgrade from dw9 to dw10, and they use this functionality. I am on 10.14.3

//jan


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Hi Jan

Dynamicweb 10 does not support pdf=true - in DW9 it was build on tech that requires a full chrome browser server side and we cannot support that in DW10.

Also a lot has happened on PDF generation since that was originally made - it is very simple to create the PDF directly in the browser using html2pdf.js, pdf.js etc.

Using htmltopdf.js

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.min.js"></script>

<button id="download">Download PDF</button>

<script>
  document.getElementById('download').addEventListener('click', () => {
    const url = 'https://example.com'; // ← your URL here

    fetch(url)
      .then(res => res.text())
      .then(html => {
        const wrapper = document.createElement('div');
        wrapper.style.width = '800px';         // control page width
        wrapper.innerHTML = html;
        document.body.appendChild(wrapper);

        html2pdf()
          .from(wrapper)
          .set({
            margin:       10,
            filename:     'page.pdf',
            image:        { type: 'jpeg', quality: 0.98 },
            html2canvas:  { scale: 2 },
            jsPDF:        { unit: 'mm', format: 'a4', orientation: 'portrait' }
          })
          .save()
          .finally(() => document.body.removeChild(wrapper));
      })
      .catch(console.error);
  });
</script>

An alternative - little more low level:

Using jsPDF + html2canvas

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>

<button id="download2">Download PDF</button>

<script>
  const { jsPDF } = window.jspdf;

  document.getElementById('download2').addEventListener('click', async () => {
    const url = 'https://example.com'; // ← your URL
    const res = await fetch(url);
    const html = await res.text();

    const wrapper = document.createElement('div');
    wrapper.style.width = '800px';
    wrapper.innerHTML = html;
    document.body.appendChild(wrapper);

    const canvas = await html2canvas(wrapper, { scale: 2 });
    const imgData = canvas.toDataURL('image/jpeg', 0.98);

    const pdf = new jsPDF('p', 'mm', 'a4');
    const pdfWidth = pdf.internal.pageSize.getWidth();
    const imgProps = pdf.getImageProperties(imgData);
    const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;

    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight);
    pdf.save('page.pdf');

    document.body.removeChild(wrapper);
  });
</script>
 
Jan Sangill
Reply

Hi Nicolai, Thank you for the response. Appreciated. It is noted. And it makes sense.
 

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Also - here is an example using print mode - printing the page you are on and then use CSS to hide e.g. print buttons and other things you need to hide:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>html2pdf + Print-Mode Example</title>

  <!-- html2pdf bundle (includes html2canvas + jsPDF) -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.min.js"></script>

  <style>
    /* print-mode styles: applied only when generating the PDF */
    .print-mode #export-pdf {
      display: none !important;
    }
    .print-mode body {
      /* make fonts a bit smaller in PDF */
      font-size: 12pt;
      line-height: 1.5;
    }
    .print-mode h2 {
      /* force page-breaks before each section */
      page-break-before: always;
    }
  </style>
</head>
<body>
  <h1>My Awesome Page</h1>
  <p>This content will go into the PDF—without the button.</p>

  <!-- Fixed-position button (hidden in PDF via .print-mode) -->
  <button id="export-pdf"
          style="position:fixed;top:1rem;right:1rem;z-index:1000;">
    Download PDF
  </button>

  <script>
    const button = document.getElementById('export-pdf');
    const opts = {
      margin:       10,
      filename:     'this-page.pdf',
      image:        { type: 'jpeg', quality: 0.98 },
      html2canvas:  { scale: 2 },
      jsPDF:        { unit: 'mm', format: 'a4', orientation: 'portrait' }
    };

    button.addEventListener('click', () => {
      // 1. turn on our print-mode styles
      document.documentElement.classList.add('print-mode');

      // 2. generate & save PDF from the whole body
      html2pdf()
        .from(document.body)
        .set(opts)
        .save()
        .finally(() => {
          // 3. clean up: turn off print-mode styles
          document.documentElement.classList.remove('print-mode');
        });
    });
  </script>
</body>
</html>
 
Andreas Rundgren
Reply

Hi, 

I tried the html2pdf version in the first comment up here. Is anyone knowing how to get the css to work correct? 
I import my css like this in my cshtml file but it seems that it not gets the css. <link rel="stylesheet" href="https://mysite.se/Files/Templates/Designs/Rapido/css/printable/printable.min.css?v=1.0">

Ín the html property which is returned by the fetch i can see the <link> in my <head> tag.

However if i go directly to my site and page where the PDF is rendering, it works good. The css is loaded correctly, i guess it works becuase it can find the file specified becuase it act as a "regular page" then.

Regards
Andreas

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Andreas,
Can you try adding media="print" to your css link?
Adrian

 
Andreas Rundgren
Reply

Hi, 

I tried to add it. But it looks really odd from the direct page link which has nice design. But something happend becuase it had other design than it use to have. 

For example when add media="print" 

 

But when i surf directly to the page without the "media=print":

Regards
Andreas

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Not exactly a DW question - but here goes:

I think the issue is that the CSS from the fetched page is not necessarily active in the DOM that html2pdf/html2canvas is rendering.

In the example, the fetched HTML is inserted like this:

const wrapper = document.createElement('div');
wrapper.innerHTML = html;
document.body.appendChild(wrapper);

If the fetched HTML contains a full document with <html>, <head>, <link rel="stylesheet">, and <body>, the stylesheet inside the fetched <head> will not reliably be loaded/applied just because the HTML string is inserted into a <div>.

html2pdf.js/html2canvas renders the DOM as it currently exists in the browser. It does not automatically process the fetched document’s <head> as if that page had been loaded normally.

So yes, I would try explicitly loading the CSS into the current document and waiting for it before calling html2pdf().

For example:

function loadCss(href) {
  return new Promise((resolve, reject) => {
    const existing = Array.from(document.styleSheets)
      .some(sheet => sheet.href && sheet.href.includes(href));

    if (existing) {
      resolve();
      return;
    }

    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = href;
    link.onload = resolve;
    link.onerror = reject;

    document.head.appendChild(link);
  });
}

async function waitForImages(element) {
  const images = Array.from(element.querySelectorAll('img'));

  await Promise.all(images.map(img => {
    if (img.complete) {
      return Promise.resolve();
    }

    return new Promise(resolve => {
      img.onload = resolve;
      img.onerror = resolve;
    });
  }));
}

document.getElementById('download').addEventListener('click', async () => {
  const url = 'https://example.com'; // page to render
  const res = await fetch(url);
  const html = await res.text();

  // Load the CSS into the current document
  await loadCss('/Files/Templates/Designs/Rapido/css/printable/printable.min.css');

  const parser = new DOMParser();
  const doc = parser.parseFromString(html, 'text/html');

  const wrapper = document.createElement('div');
  wrapper.style.width = '800px';

  // Use the body content, not the full HTML document
  wrapper.innerHTML = doc.body.innerHTML;

  document.body.appendChild(wrapper);

  // Optional, but useful if layout depends on web fonts
  if (document.fonts) {
    await document.fonts.ready;
  }

  // Wait for images before rendering the PDF
  await waitForImages(wrapper);

  await html2pdf()
    .from(wrapper)
    .set({
      margin: 10,
      filename: 'page.pdf',
      image: { type: 'jpeg', quality: 0.98 },
      html2canvas: {
        scale: 2,
        useCORS: true,
        windowWidth: 800
      },
      jsPDF: {
        unit: 'mm',
        format: 'a4',
        orientation: 'portrait'
      }
    })
    .save();

  document.body.removeChild(wrapper);
});

I would also avoid relying on media="print" unless that is specifically tested with this setup. html2pdf/html2canvas captures the browser DOM/canvas; it is not the same as invoking the browser’s native print rendering. So a stylesheet with media="print" may not behave as expected.

A safer approach is to load a normal stylesheet for the PDF rendering, or add a specific class to the wrapper:

wrapper.classList.add('pdf-mode');

and then use CSS like:

.pdf-mode .some-button {
  display: none;
}

Also keep in mind that CORS may affect images, fonts, background images, etc., especially if they are loaded from another domain or subdomain. useCORS: true can help for images, but the server still needs to allow it.

 

You must be logged in to post in the forum