使用 KendoPDF 转换成 PDF canvas 的 PDF 质量低
Low quality in PDF converting canvas in PDF using KendoPDF
我使用 html canvas 创建了一个图表。结果希望使用 Kendo 将其打印为 PDF 文件。它有效,但图形质量很差。对于我需要的解决方案,由于限制原因我不能使用 kendo 图表
report.html
<div class="width-100-perc text-center">
<canvas id="canvas" width="100" height="100"></canvas>
<br />
</div>
report.ts
drawChart() {
console.log( 'foi');
const canvas: HTMLCanvasElement = (<HTMLCanvasElement>document.getElementById('canvas'));
console.log(this.series);
if (canvas) {
const ctx = canvas.getContext('2d');
// Base offset distance of 10
const offset = 0;
let beginAngle = 0;
let endAngle = 0;
// Used to calculate the X and Y offset
let offsetX, offsetY, medianAngle;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fill();
for (let i = 0; i < this.angles.length; i = i + 1) {
beginAngle = endAngle;
endAngle = endAngle + this.angles[i];
// The medium angle is the average of two consecutive angles
medianAngle = (endAngle + beginAngle) / 2;
// X and Y calculations
offsetX = Math.cos(medianAngle) * offset;
offsetY = Math.sin(medianAngle) * offset;
ctx.beginPath();
ctx.fillStyle = this.series[0].data[i].color;
// Adding the offsetX and offsetY to the center of the arc
ctx.moveTo(50 + offsetX, 50 + offsetY);
ctx.arc(50 + offsetX, 50 + offsetY, 40, beginAngle, endAngle);
ctx.lineTo(50 + offsetX, 50 + offsetY);
ctx.fill();
}
if (this.angles.length > 0) {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(50, 50, 15, 0, 2 * Math.PI);
ctx.fill();
}
}
}
这不是 kendo 的 pdf 导出问题。相反,它是 HTML canvas 工作方式所固有的。您的导出看起来失真且像素化,因为归根结底,它只是一张 100x100 的图像,分辨率相当低。我假设您希望它那么小,因为它是为了适应页面的特定部分而设计的。如果你直接导出这个canvas,那个像素化的图像就是你应该期待的。
我可以提出这个解决方法。您需要重构 drawChart()
方法以考虑比例(数字)。这意味着将所有 x,y 坐标和尺寸乘以该值。默认情况下,比例为 1。导出为 pdf 时,您将按照以下步骤操作:
- 将比例更改为更高的值,比如 10
- 绘图
- 导出为 pdf
- 再次将比例更改为 1
- 绘图
这样,图表会暂时使用更高分辨率 canvas 重新绘制。在高分辨率状态下,它被导出,然后以其原始尺寸重新绘制。
如果您提供 this.angles
和 this.series
的一些示例值,我可以重构您的 drawChart()
函数以将其考虑在内。就目前而言,我不能。不过我准备了一个类似的例子here。这是我创建的ReportComponent
。
report.component.html
<button (click)="savePdf(false)">bad pdf</button>
<button (click)="savePdf(true)">good pdf</button>
<br/>
<kendo-pdf-export #pdf>
<canvas #canvas [width]="baseWidth" [height]="baseHeight"></canvas>
</kendo-pdf-export>
report.component.ts
export class ReportComponent implements AfterViewInit {
@ViewChild("canvas", { static: false })
public canvasRef: ElementRef<HTMLCanvasElement>;
@ViewChild("pdf", { static: false })
public pdf: PDFExportComponent;
@Input() public title: string = "";
public scale: number = 1;
public baseWidth: number = 100;
public baseHeight: number = 100;
constructor() {}
ngAfterViewInit() {
this.draw();
}
draw() {
const canvas = this.canvasRef.nativeElement;
canvas.width = this.baseWidth * this.scale; // scaled
canvas.height = this.baseHeight * this.scale; // scaled
const context = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 31.4 * this.scale; // scaled
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "green";
context.fill();
context.lineWidth = 5 * this.scale; // scaled
context.strokeStyle = "#003300";
context.stroke();
}
savePdf(good: boolean) {
if (good) {
// scale 10x and re-draw
this.scale = 10;
this.draw();
this.pdf.saveAs("good.pdf");
this.scale = 1;
this.draw();
} else {
// just draw as is
this.pdf.saveAs("bad.pdf");
}
}
}
PDF 错误
好PDF
我使用 html canvas 创建了一个图表。结果希望使用 Kendo 将其打印为 PDF 文件。它有效,但图形质量很差。对于我需要的解决方案,由于限制原因我不能使用 kendo 图表
report.html
<div class="width-100-perc text-center">
<canvas id="canvas" width="100" height="100"></canvas>
<br />
</div>
report.ts
drawChart() {
console.log( 'foi');
const canvas: HTMLCanvasElement = (<HTMLCanvasElement>document.getElementById('canvas'));
console.log(this.series);
if (canvas) {
const ctx = canvas.getContext('2d');
// Base offset distance of 10
const offset = 0;
let beginAngle = 0;
let endAngle = 0;
// Used to calculate the X and Y offset
let offsetX, offsetY, medianAngle;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fill();
for (let i = 0; i < this.angles.length; i = i + 1) {
beginAngle = endAngle;
endAngle = endAngle + this.angles[i];
// The medium angle is the average of two consecutive angles
medianAngle = (endAngle + beginAngle) / 2;
// X and Y calculations
offsetX = Math.cos(medianAngle) * offset;
offsetY = Math.sin(medianAngle) * offset;
ctx.beginPath();
ctx.fillStyle = this.series[0].data[i].color;
// Adding the offsetX and offsetY to the center of the arc
ctx.moveTo(50 + offsetX, 50 + offsetY);
ctx.arc(50 + offsetX, 50 + offsetY, 40, beginAngle, endAngle);
ctx.lineTo(50 + offsetX, 50 + offsetY);
ctx.fill();
}
if (this.angles.length > 0) {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(50, 50, 15, 0, 2 * Math.PI);
ctx.fill();
}
}
}
这不是 kendo 的 pdf 导出问题。相反,它是 HTML canvas 工作方式所固有的。您的导出看起来失真且像素化,因为归根结底,它只是一张 100x100 的图像,分辨率相当低。我假设您希望它那么小,因为它是为了适应页面的特定部分而设计的。如果你直接导出这个canvas,那个像素化的图像就是你应该期待的。
我可以提出这个解决方法。您需要重构 drawChart()
方法以考虑比例(数字)。这意味着将所有 x,y 坐标和尺寸乘以该值。默认情况下,比例为 1。导出为 pdf 时,您将按照以下步骤操作:
- 将比例更改为更高的值,比如 10
- 绘图
- 导出为 pdf
- 再次将比例更改为 1
- 绘图
这样,图表会暂时使用更高分辨率 canvas 重新绘制。在高分辨率状态下,它被导出,然后以其原始尺寸重新绘制。
如果您提供 this.angles
和 this.series
的一些示例值,我可以重构您的 drawChart()
函数以将其考虑在内。就目前而言,我不能。不过我准备了一个类似的例子here。这是我创建的ReportComponent
。
report.component.html
<button (click)="savePdf(false)">bad pdf</button>
<button (click)="savePdf(true)">good pdf</button>
<br/>
<kendo-pdf-export #pdf>
<canvas #canvas [width]="baseWidth" [height]="baseHeight"></canvas>
</kendo-pdf-export>
report.component.ts
export class ReportComponent implements AfterViewInit {
@ViewChild("canvas", { static: false })
public canvasRef: ElementRef<HTMLCanvasElement>;
@ViewChild("pdf", { static: false })
public pdf: PDFExportComponent;
@Input() public title: string = "";
public scale: number = 1;
public baseWidth: number = 100;
public baseHeight: number = 100;
constructor() {}
ngAfterViewInit() {
this.draw();
}
draw() {
const canvas = this.canvasRef.nativeElement;
canvas.width = this.baseWidth * this.scale; // scaled
canvas.height = this.baseHeight * this.scale; // scaled
const context = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 31.4 * this.scale; // scaled
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "green";
context.fill();
context.lineWidth = 5 * this.scale; // scaled
context.strokeStyle = "#003300";
context.stroke();
}
savePdf(good: boolean) {
if (good) {
// scale 10x and re-draw
this.scale = 10;
this.draw();
this.pdf.saveAs("good.pdf");
this.scale = 1;
this.draw();
} else {
// just draw as is
this.pdf.saveAs("bad.pdf");
}
}
}
PDF 错误
好PDF