jsPDF在生产环境中无法生成PDF(可能与Webpack配置有关?)

huangapple go评论52阅读模式
英文:

jsPDF not generating PDF in production ( maybe an issue with webpack conf ? )

问题

在由JHipster生成的Angular应用中,我成功在开发模式下通过jsPDF生成PDF文件。但是当我构建它并将其部署到VPS上时,在文档中添加图像会导致Web应用程序崩溃。

错误信息如下:

717.1183bdcffdb5d922.js:1 ERROR TypeError: Cannot read properties of undefined (reading 'data')
at i.addimage.getImageFileTypeByImageData (641.074d6c566f08a36e.js:1:287740)
at Object.Zt (641.074d6c566f08a36e.js:1:295400)
at i.addImage (641.074d6c566f08a36e.js:1:295162)
at m.addImageEntete (287.1ee6c0684b572bd4.js:1:800)
at M.getPDF (641.074d6c566f08a36e.js:1:47054)
at M.generatePDFComplet (641.074d6c566f08a36e.js:1:115186)
at 641.074d6c566f08a36e.js:1:139516
at d7 (717.1183bdcffdb5d922.js:1:217724)
at c (717.1183bdcffdb5d922.js:1:217891)
at HTMLButtonElement. (717.1183bdcffdb5d922.js:1:330709)

尽管如此,我可以在地址栏中通过它们的URL显示图像。

以下是相关代码的一部分:

import { jsPDF, jsPDFOptions } from 'jspdf';
import autoTable, { RowInput } from 'jspdf-autotable';

export const ENTETE_PATH_ABMS = '/content/images/prints/abms_entete.jpg';

@Injectable({
  providedIn: 'root',
})
export class PrintService {
  constructor() {}

  getPDF() {
    const options: jsPDFOptions = {
      orientation: 'p',
      unit: 'mm',
      format: 'a4',
      putOnlyUsedFonts: true,
      floatPrecision: 16, // or "smart", default is 16
    };
    const doc = new jsPDF(options); 
    doc.addImage(ENTETE_PATH_ABMS, 'jpg', posX, posY, w, h);
 }
}

希望这有助于解决问题。

英文:

In an Angular app generated by JHipster, I managed to produce PDFs via jsPDF in dev mode.
But when I build it and push it on a VPS, adding images in the doc crashes the webApp.

717.1183bdcffdb5d922.js:1 ERROR TypeError: Cannot read properties of undefined (reading 'data')
    at i.__addimage__.getImageFileTypeByImageData (641.074d6c566f08a36e.js:1:287740)
    at Object.Zt (641.074d6c566f08a36e.js:1:295400)
    at i.addImage (641.074d6c566f08a36e.js:1:295162)
    at m.addImageEntete (287.1ee6c0684b572bd4.js:1:800)
    at M.getPDF (641.074d6c566f08a36e.js:1:47054)
    at M.generatePDFComplet (641.074d6c566f08a36e.js:1:115186)
    at 641.074d6c566f08a36e.js:1:139516
    at d7 (717.1183bdcffdb5d922.js:1:217724)
    at c (717.1183bdcffdb5d922.js:1:217891)
    at HTMLButtonElement.<anonymous> (717.1183bdcffdb5d922.js:1:330709)

I can display them in the address bar whith their URL though.

Here is a bit of relevant code :

<!-- language: typescript -->

import { jsPDF, jsPDFOptions } from &#39;jspdf&#39;;
import autoTable, { RowInput } from &#39;jspdf-autotable&#39;;

export const ENTETE_PATH_ABMS = &#39;/content/images/prints/abms_entete.jpg&#39;;

@Injectable({
  providedIn: &#39;root&#39;,
})
export class PrintService {
  constructor() {}

  getPDF() {
    const options: jsPDFOptions = {
      orientation: &#39;p&#39;,
      unit: &#39;mm&#39;,
      format: &#39;a4&#39;,
      putOnlyUsedFonts: true,
      floatPrecision: 16, // or &quot;smart&quot;, default is 16
    };
    const doc = new jsPDF(options); 
    doc.addImage(ENTETE_PATH_ABMS, &#39;jpg&#39;, posX, posY, w, h);
 }
}

答案1

得分: 1

我发现问题是jsPDF经常出现的问题:我在完全加载图像之前就添加了图像,由于生产环境性能比我的开发计算机差,所以问题出现了。

在一个名为CommonUtils的实用类中,借助于一个著名的聊天机器人,我想出了这个解决方案,使用了observables和html2canvas。

npm install html2canvas rxjs

在CommonUtils实用类中:

export type ImageWrapper = {
  imagePath: string,
  x: number,
  y: number,
  width: number,
  height: number,
}

private static loadImage(url: string): Observable<HTMLImageElement> {
  return new Observable((observer) => {
    const img = new Image();
    img.crossOrigin = 'Anonymous'; // 允许从外部URL加载图像
    img.onload = () => {
      observer.next(img);
      observer.complete();
    };
    img.src = url;
  });
}

private static convertImageToCanvas(img: HTMLImageElement, width: number, height: number): Observable<HTMLCanvasElement> {
  return from(html2canvas(img, { width, height }));
}

public static addImagesAndSave(images: Array<ImageWrapper>, doc: jsPDF, docname: string): void {
  const imageObservables = images.map(({ imagePath }) => this.loadImage(imagePath));

  forkJoin(imageObservables)
    .pipe(
      map((loadedImages) => {
        return loadedImages.map((img, index) => {
          document.body.appendChild(img);
          return this.convertImageToCanvas(img, images[index].width, images[index].height);
        });
      }),
      switchMap((canvasObservables) => forkJoin(canvasObservables))
    )
    .subscribe((canvases) => {
      canvases.forEach((canvas, index) => {
        const imgData = canvas.toDataURL('image/jpeg');
        const { x, y, width, height } = images[index];
        console.log('add image ' + x + ' ' + y + ' ' + width + ' ' + height + ' ' + imgData);
        doc.addImage(imgData, 'PNG', x, y, width, height);
      });
      doc.save(docname);
    });
}

这个服务可以这样调用:

var imageList: ImageWrapper[] = []
// 根据需要设置路径、高度、宽度、x和y
imageList.push({
  imagePath: '/assets/images.jpeg',
  height: h,
  width: w,
  x: posX,
  y: posY
})
CommonUtils.addImagesAndSave(imageList, doc, 'pdfname.pdf')

我仍然需要对图像大小的问题进行一些调整,但它们已经被加载并显示在PDF中了。

英文:

I figured out that the issue was one that is recurrent with jsPDF : I was adding image before loading it completely , and the issue appeared in production because of his lesser performance than my dev computer.

With the help of a famous chatbot, I came up with this solution, featuring observables and html2canvas.

npm install html2cavas rxjs

In a utility class named CommonUtils :

  export type ImageWrapper = {
imagePath : string,
x : number,
y : number,
width : number,
height : number,
}
private static loadImage(url: string): Observable&lt;HTMLImageElement&gt; {
return new Observable((observer) =&gt; {
const img = new Image();
img.crossOrigin = &#39;Anonymous&#39;; // Allow loading images from external URLs
img.onload = () =&gt; {
observer.next(img);
observer.complete();
};
img.src = url;
});

}

 private static convertImageToCanvas(img: HTMLImageElement, width: number, height: number): Observable&lt;HTMLCanvasElement&gt; {
return from(html2canvas(img, { width, height }));

}

 public static addImagesAndSave(images: Array&lt;ImageWrapper&gt;, doc : jsPDF, docname:string): void {
const imageObservables = images.map(({ imagePath }) =&gt; this.loadImage(imagePath));
forkJoin(imageObservables)
.pipe(
map((loadedImages) =&gt; {
return loadedImages.map((img, index) =&gt; {
document.body.appendChild(img);
return this.convertImageToCanvas(img, images[index].width, images[index].height)
}
);
}),
switchMap((canvasObservables) =&gt; forkJoin(canvasObservables))
)
.subscribe((canvases) =&gt; {
canvases.forEach((canvas, index) =&gt; {
const imgData = canvas.toDataURL(&#39;image/jpeg&#39;);
const { x, y, width, height } = images[index];
console.log(&#39;add image &#39; + &#39; &#39; + x + &#39; &#39; +  y + &#39; &#39; + width + &#39; &#39; + height  + &#39; &#39; +  imgData  )
doc.addImage(imgData, &#39;PNG&#39;, x, y, width, height);
});
doc.save(docname);
});

}

This service is called like this

 var imageList : ImageWrapper[] = []
// set your path , height, width, x and y accordingly
imageList.push({
imagePath : &#39;/assets/images.jpeg&#39;,
height : h,
width : w,
x : posX,
y : posY
})
CommonUtils.addImagesAndSave(imageList , doc, &#39;pdfname.pdf&#39;)

I have still to do some tuning because of issues with images' size but they are loaded and displayed in the pdf

huangapple
  • 本文由 发表于 2023年7月10日 19:55:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76653492.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定