When incorporating HTML5 Canvas fonts into a PDF using jspdf, the text may appear blurry

I have developed a function that scales down the font size until the text width is smaller than the canvas width. This text is then added to a canvas containing a QR code.

Subsequently, this canvas is included in a PDF file.

The issue I am encountering is that while the QR code remains crisp and clean, the text becomes blurry.

Take a look at the resulting QR code with text in this screenshot:

https://i.sstatic.net/4mPxE.png

For comparison, here is the QR code at the same size and using the same font created in Word:

https://i.sstatic.net/MT6KU.png

Here are full-size screenshots to confirm they are the same size. Both were taken from the PDF file:

Code, Word

Below is the code responsible for generating this QR code with text:

 printQRCode(){
const width = 150; // will be dynamic in the future
const ratio = 8 / 100;
const fontSize = width * ratio; 
const text = `[${this.getCode()}]`;

toCanvas(text,
{errorCorrectionLevel: 'H', width},
(_err, canvas) => {
  const ctx = canvas.getContext('2d');
  this.setOptimalFontSizeForCanvas(ctx, fontSize, text, width); 
  ctx.fillText(text, this.getCenterPositionForCanvasText(ctx, text, width), width - 5);
  const contentDataURL = canvas.toDataURL('image/png');

  const pdf = new jsPDF('p', 'px', 'a4');
  pdf.addImage(contentDataURL, 'PNG', 0, 0, canvas.width, canvas.height);
  pdf.autoPrint();
  pdf.output('dataurlnewwindow');
});
}

setOptimalFontSizeForCanvas(ctx: CanvasRenderingContext2D, fontSize: number, text: string, width: number){
    ctx.font = fontSize + 'px Arial';
    do{
      fontSize--;
      ctx.font = fontSize + 'px Arial';
    }while(ctx.measureText(text).width>width- Math.floor(width / 10));
  }

What adjustments should I make to prevent the text from appearing blurry?


Edit:

I inspected the dataURL of the canvas and noticed that the original canvas is much smaller than the one ultimately printed on the PDF file. I attempted changing the input unit of the PNG to 'pt', which did reduce the canvas size, yet it still exceeds the image from the dataURL.

How can I accurately determine the necessary width and height to pass to the PNG function?

Answer №1

Here's the current workaround that I implemented:

I decided to switch the input unit format to pixels and determine the size factor between the code generated and the original size obtained from the dataURL. After some calculations, I discovered that the code generated is exactly 1.7784 times larger.

By dividing the size with this factor, I was able to resolve the issue:

pdf.addImage(contentDataURL, 'PNG', 0, 0, Math.floor(canvas.width / 1.7784), Math.floor(canvas.height / 1.7784));

While this solution works, I believe there might be a more efficient way to accomplish this task.


Update:

I have found a more optimal approach. By setting both the width and height parameters to 0 when adding the image, it will automatically adjust to the actual size of the image:

pdf.addImage(contentDataURL, 'PNG', 0, 0, 0, 0);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Breaking apart a combination of unions into a collective group of tuples within TypeScript

Looking for a solution similar to TypeScript extract union type from tuple, this question delves into how to split ['a' | 'b', number] into ['a', number] | ['b', number] rather than focusing on why they are not direc ...

Having an issue with forkJoin where the code seems to get stuck and does not continue execution after

The following script is retrieving two values from the database. I am using forkJoin for this purpose, which is a new approach for me. The reason behind utilizing this method is that there is a specific function that requires both values to be fetched bef ...

Exploring the differences between Angular's @Input and @Output directives and utilizing Injectable Services

When considering the differences between @Input/@Output in parent and child components versus using services that are instantiated only once with dependency injection (@Injectable()), I find myself questioning whether there are any distinctions beyond the ...

Got a value of `false` for an attribute `closable` that is not meant to be a

Here's the code snippet I have: import { Modal } from "antd"; import styled from "styled-components"; export const StANTModal = styled(Modal)` & .ant-modal-content { border-radius: 20px; overflow: hidden; } `; And ...

In TypeScript, combining the numbers 0 and 1 results in the value 01

I am in the process of developing a Shopping Card feature. private _card: Map<Product, number> = new Map<Product, number>(); ... addToCard(prod: Product, amount: number = 1): void { const totalAmount: number = this._card.get(prod) + amou ...

Angular - Switching Displayed Information

I am currently working with Angular 4 and I am attempting to switch between contenteditable="true" and contenteditable="false" Here is what I have so far: <h1 (dblclick)="edit($event)" contentEditable="true">Double-click Here to edit</h1> Al ...

Exploring TypeScript and node.js development using Visual Studio 2012 express

Is there a way to successfully write, build, and execute a node.js application in Visual Studio? I have already installed the TypeScript extension on VS as well as the node.js package. However, when I attempt to create a new project of the TypeScript type, ...

What is the process for overriding the module declaration for `*.svg` in Next.js?

The recent modification in Next.js (v11.0.x) has introduced new type definitions: For next-env.d.ts (regenerated at every build and not modifiable): /// <reference types="next" /> /// <reference types="next/types/global" /> ...

React Typescript: The specified argument type cannot be assigned to the parameter type

Creating a Check Box Button React component has resulted in an error related to setRSelected(1) and setRSelected(2)... const [cSelected, setCSelected] = useState([]); const [rSelected, setRSelected] = useState(); const onCheckboxBtnClick = (selected ...

What role does the empty object type {} play in typescript?

In the @types/React package of the DefinitelyTyped library, I came across this definition: interface FunctionComponent<P = {}> { (props: PropsWithChildren<P>, context?: any): ReactElement | null; propTypes?: WeakValidationMap&l ...

Angular RxJS: The never-ending reduction

I have developed a component that contains two buttons (searchButton, lazyButton). The ngOnDestroy method is defined as follows: public ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } I have created two observables from ...

Typedi's constructor injection does not produce any defined output

I am utilizing typedi in a Node (express) project and I have encountered an issue related to injection within my service class. It seems that property injection works fine, but constructor injection does not. Here is an example where property injection wo ...

Implementing type inference for response.locals in Express with TypeScript

I need to define types for my response.locals in order to add data to the request-response cycle. This is what I attempted: // ./types/express/index.d.ts declare global { declare namespace Express { interface Response { locals: { ...

Angular routing functions flawlessly on Chrome Mac but encounters issues on Chrome iOS

Encountering a strange issue. My routing is properly configured and has been verified multiple times. Oddly enough, page1, page3, and page5 are functioning correctly, while page2, page4, and page6 fail to redirect as expected. Upon clicking the redirect ...

Where can I locate the newest Typings definitions?

After switching to Typings for Typescript, I've encountered a frustrating issue where upgrading libraries often leads to deprecated typings. The warning during npm install only mentions that a specific typings item is no longer supported. I have spen ...

Cracking the Code: Demystifying TypeScript Syntax within Angular 4

Recently, I delved into the world of Angular 4 and Typescript by following the step-by-step "Angular-tour-of-heroes" tutorial on the Angular.io website. Since Angular 4 relies on typescript for defining components and more, I wanted to deepen my understand ...

Menu with options labeled using IDs in FluentUI/react-northstar

I'm currently working on creating a dropdown menu using the FluentUI/react-northstar Dropdown component. The issue I'm facing is that the 'items' prop for this component only accepts a 'string[]' for the names to be displayed ...

What could be causing the canvas circle to appear distorted and not truly circular?

My simple code is intended to draw a circle, but it's not appearing as expected. The coordinates seem to be shifted oddly. The canvas size is specified with style="width: 600px; height: 600px;". I've tested it on both Chrome and Safari, yet the r ...

Typescript-optimized Npm library utilizing the module-alias feature

As I work on creating an npm library with Typescript, I have made use of the paths setting in tsconfig.json and the module-alias tool to streamline my imports, allowing me to use syntax like import * from '@/utils'. However, I have encountered an ...

Limit input to numbers only in Semantic UI React Form Field

I've developed a custom CurrencyInput React component for users to input numeric values. I set the input type to "number", but unfortunately, this only seems to function properly in Chrome (as Firefox still allows non-numeric entries). Here is the co ...