前端jsPDF生成高清图片的方案

540 阅读5分钟

一、jsPDF介绍?

  • jsPDF 是一个基于 HTML5 的客户端解决方案,用于在客户端 JavaScript 中生成 PDF 的库。

  • jsPDF 使用简单,只要引入 jsPDF 库,然后调用内置的方法就可以了。

  • jsPDF 支持的格式丰富:文本、数字、图形、图片,并且我们还可以自由地编辑标题或者其它类型元素。

  • 优点:生成的图片清晰度高,放大缩小不会模糊

二、官网地址

三、基本用法

  • 安装过程跳过,具体安装方式看官网介绍,懂得都懂。。。
  • 页面引入jsPDF

image.png

  • 创建pdf实例
 let doc = new JsPDF({
    orientation: 'l', // 横版
    unit: 'pt',
    format: 'a4',
    precision: '12',
    putOnlyUsedFonts: false,
    floatPrecision: "smart" // default is 16
  })
  
  doc.text(200, 550, '123-遮蔽角图')
  
  let pdfName = 'pdf文件名.pdf'
  doc.save(pdfName)

注意事项

  1. 中文乱码问题

如果按照上述示例直接使用jspdf导出有中文文本的PDF,会发现有乱码的情况,这是因为jspdf默认情况下不支持中文字符集。我们可以通过添加中文字体库,来解决乱码问题。步骤如下:

  • 下载中文字体

1.方式一:下载地址: https://github.com/Pal3love/Source-Han-TrueType/releasesimage.png

2.方式二:下载Windows系统自带的字体

222222000.png

  • 转换字体,打开jspdf提供的在线字体转化网站: https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.htmlimage.png 选择我们下载好的字体文件,不同的字体样式,选择不同的fontStyle。然后将转换后的文件扔到我们的项目下,并在使用的地方进行引用。

生成高清图的核心代码

import JsPDF from 'jspdf'
// 引入转换后的字体文件
import "@/assets/jspdf_font/simhei-normal"

// 遮蔽角图下载
function downloadImg() {
  // 根据A4纸尺寸是210毫米×297毫米,而1英寸=2.54厘米,我们可以得出当分辨率是多少像素时,得出A4纸大小尺寸为多少毫米。如下是我们较长用到的规格尺寸:
  // 当分辨率是72像素/英寸时,A4纸像素长宽分别是842×595;
  // 当分辨率是120像素/英寸时,A4纸像素长宽分别是2105×1487;
  // 当分辨率是150像素/英寸时,A4纸像素长宽分别是1754×1240;
  // 当分辨率是300像素/英寸时,A4纸像素长宽分别是3508×2479;

  let list = props.shieldAngleList
  let stationInfo = props.stationInfo
  let stationName = stationInfo.name // 站名
  let height = Number(stationInfo.height - stationInfo.altitude).toString()
  height = height.indexOf('.') !== -1 ? parseFloat(height).toFixed(1) : height // 天线架高

  let longitude = stationInfo.longitude // 经度
  let latitude = stationInfo.latitude // 纬度
  let altitude = stationInfo.altitude // 海拔高度
  let maxRange = stationInfo.maxRange // 探测距离

  let doc = new JsPDF({
    orientation: 'l', // 横版
    unit: 'pt',
    format: 'a4',
    precision: '12',
    putOnlyUsedFonts: false,
    floatPrecision: "smart" // default is 16
  })
  //添加并设置字体
  doc.setFont('simhei')

  doc.setFontSize(20)

  // 站点信息
  doc.text(560, 300, '候选站址:' + stationName)
  doc.text(560, 330, '经    度:' + longitude + '°')
  doc.text(560, 360, '纬    度:' + latitude + '°')
  doc.text(560, 390, '海拔高度:' + altitude + 'm')
  doc.text(560, 420, '天线架高:' + height + 'm')
  doc.text(560, 450, '探测距离:' + maxRange + 'Km')

  // 方向
  doc.text(295, 30, 'N')
  doc.text(530, 265, 'E')
  doc.text(295, 500, 'S')
  doc.text(60, 265, 'W')

  // 0-5
  doc.text(330, 258, '5')
  doc.text(370, 258, '4')
  doc.text(405, 258, '3')
  doc.text(440, 258, '2')
  doc.text(475, 258, '1')
  doc.text(510, 258, '0')

  //修改线条粗细
  doc.setLineWidth(1);

  doc.rect(80, 40, 440, 440) // 矩形

  doc.circle(300, 260, 35) // 圆1
  doc.circle(300, 260, 75) // 圆2
  doc.circle(300, 260, 110) // 圆3
  doc.circle(300, 260, 145) // 圆4
  doc.circle(300, 260, 180) // 圆5
  doc.circle(300, 260, 215) // 圆6

  doc.line(300, 45, 300, 475) // 竖线
  doc.line(85, 260, 515, 260) // 横线
  doc.line(486.2, 152.5, 113.8, 367.5)
  doc.line(407.5, 73.8, 192.5, 446.2)
  doc.line(192.5, 73.8, 407.5, 446.2)
  doc.line(113.8, 152.5, 486.2, 367.5)
  doc.setFontSize(30)
  doc.text(200, 550, stationName + '-遮蔽角图')

  //修改线条颜色
  doc.setDrawColor(0, 0, 255);

  let points = pointList.value
  for (let i = 0; i < 360; i++) {
    if (i == 359) {
      doc.line(points[i][0], points[i][1], points[0][0], points[0][1])
    } else {
      doc.line(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1])
    }
  }

  let pdfName = stationName + '遮蔽角图_架高' + height + 'm.pdf'
  doc.save(pdfName)
}

let pointList = ref([])
// 计算360个点坐标
function gtest() {
  let data = dataList.value
  // console.log('计算360个点坐标', data)
  // 0-1之间实际像素为35
  let a0 = 35
  let r = 215
  // 圆心坐标(300, 260)

  // 以圆心坐标(0, 0) R=215 计算点坐标数据
  // 因为页面以左上角(0, 0)开始进行像素绘制,所以各个象限需要改变正负号
  let pointData = [] // 计算点坐标数据
  for (let i = 0; i < 360; i++) {
    if (i == 0) {
      // 正北方向
      let ir0 = r - data[i].shieldAngle * a0
      let p0 = [0, -ir0]
      pointData.push(p0)
    } else if (i > 0 && i < 90) {
      // 第一象限
      let ir = r - data[i].shieldAngle * a0
      let x = side_length(i, ir).opposite_side
      let y = side_length(i, ir).adjacent_side
      let p = [x, -y]
      pointData.push(p)
    } else if (i == 90) {
      // 正东方向
      let ir1 = r - data[i].shieldAngle * a0
      let p1 = [ir1, 0]
      pointData.push(p1)
    } else if (i > 90 && i < 180) {
      // 第四象限
      let ir = r - data[i].shieldAngle * a0
      let x = side_length(i - 90, ir).adjacent_side
      let y = side_length(i - 90, ir).opposite_side
      let p = [x, y]
      pointData.push(p)
    } else if (i == 180) {
      // 正南方向
      let ir2 = r - data[i].shieldAngle * a0
      let p2 = [0, ir2]
      pointData.push(p2)
    } else if (i > 180 && i < 270) {
      // 第三象限
      let ir = r - data[i].shieldAngle * a0
      let x = side_length(i - 180, ir).opposite_side
      let y = side_length(i - 180, ir).adjacent_side
      let p = [-x, y]
      pointData.push(p)
    } else if (i == 270) {
      // 正西方向
      let ir3 = r - data[i].shieldAngle * a0
      let p3 = [-ir3, 0]
      pointData.push(p3)
    } else if (i > 270 && i < 360) {
      // 第二象限
      let ir = r - data[i].shieldAngle * a0
      let x = side_length(i - 270, ir).adjacent_side
      let y = side_length(i - 270, ir).opposite_side
      let p = [-x, -y]
      pointData.push(p)
    }
  }
  // console.log('计算的点坐标数据pointData', pointData)

  // 根据实际偏移计算正确坐标
  pointList.value = pointData.map(item => {
    return [item[0] + 300, item[1] + 260]
  })
  console.log('计算的点坐标数据pointList.v', pointList.value)
}

//已知直角三角形的斜角度数和斜边长度,求邻边和对边的长度
// side_length(斜角度,斜边长)
function side_length(angle, long) {
  //获得弧度
  var radian = ((2 * Math.PI) / 360) * angle;
  return {
    opposite_side: Math.sin(radian) * long, //斜角对边长度
    adjacent_side: Math.cos(radian) * long //斜角邻边长度
  };
}

成功图片如下

image.png