這是由 IT邦 的大神留下來的。
作者:淺水員
來源出處: https://ithelp.ithome.com.tw/questions/10206319
以下是對應內容
pdf.js
index.js
這樣就可以簡單的將圖生成PDF。下次再來研究HTML轉PDF
感謝大神的程式碼提供
作者:淺水員
來源出處: https://ithelp.ithome.com.tw/questions/10206319
以下是對應內容
HTML:
<iframe width="800" height="600" frameborder="0"></iframe>
<script src="pdf.js"></script>
<script src="index.js"></script>
pdf.js
JavaScript:
/**
* 產生 pdf 的基本工具
* 先用 addObject 寫入所需的物件
* 最後用 output 輸出
* 注意:這個檔案必須是 utf8 編碼,且換行為 lf
*/
function Pdf() {
this.idCount = 0;
this.data = [];
}
/**
* 加入一個 obj
*
* @param {object} dict
* @param {string|flase} stream
* @param {int|undefined} specId
*/
Pdf.prototype.addObject = function (dict, stream, specId) {
if (typeof stream === 'string') {
dict['Length'] = stream.length;
}
let arr = [];
let id;
if (specId === undefined) {
id = ++this.idCount;
} else {
id = specId;
}
arr.push(`${id} 0 obj`);
arr.push('<<');
for (let key in dict) {
arr.push(`/${key} ${dict[key]}`);
}
arr.push('>>');
if (typeof stream === 'string') {
arr.push('stream');
arr.push(stream);
arr.push('endstream');
}
arr.push('endobj');
this.data[id - 1] = arr.join('\n');
}
/**
* 預留 id
*
* @returns {int} 預留的 id
*/
Pdf.prototype.preserveId = function () {
return ++this.idCount;
}
/**
* 產生 pdf 的內容
*
* @param {int} rootId
* @returns {string} pdf內容
*/
Pdf.prototype.output = function (rootId) {
let header = '%PDF-1.4\n%§§';
let xrefArr = ['0000000000 65535 f '];
let pos = header.length + 3;
this.data.forEach((obj) => {
let s = pos.toString();
s = '0'.repeat(10 - s.length) + s;
xrefArr.push(`${s} 00000 n `);
pos += obj.length + 1;
});
return `${header}
${this.data.join('\n')}
xref
0 ${this.data.length + 1}
${xrefArr.join('\n')}
trailer
<<
/Size ${this.data.length + 1}
/Root ${rootId} 0 R
>>
startxref
${pos}
%%EOF
`;
}
/**
* 產生 pdf 的內容
*
* @param {int} rootId
* @returns {string} pdf 的 dataurl
*/
Pdf.prototype.toDataUrl=function(rootId) {
return 'data:application/pdf;base64,'+btoa_utf8(this.output(rootId));
}
/**
* btoa 的 utf8 版本
* @param {string} str 字串
* @returns {string} base64字串
*/
function btoa_utf8(str) {
const u8enc=new TextEncoder();
return btoa(Array.from(u8enc.encode(str), x=>String.fromCodePoint(x)).join(''));
}
index.js
JavaScript:
/**
* 產生測試圖片
* 一個 200 x 200 中間畫圓的 jpg
*
* @returns {string} base64 data url
*/
function getTestJpg() {
let cvs = document.createElement('canvas');
cvs.width = 200;
cvs.height = 200;
let ctx = cvs.getContext('2d');
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0, 0, 200, 200);
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.stroke();
return cvs.toDataURL('image/jpeg', 1.0);
}
/**
* 把圖片畫到 pdf 上
* 並產生 pdf 的 dataurl
*
* @param {string} jpegBase64 jpeg的dataurl
* @param {object} opt 用來指定位置與長寬 {x:x座標, y:y座標, width:寬度, height:高度}
* @returns {string} pdf 的 dataurl
*/
function drawToPdf(jpegBase64, opt) {
let jpegbase85 = base64ToBase85(jpegBase64.split('base64,')[1]); //轉成 base85
/**
* pdf 的結構請參考
* https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf
*/
let pdf = new Pdf();
let catlogId = pdf.preserveId();
let pagesId = pdf.preserveId();
let firstPageId = pdf.preserveId();
let resourceId = pdf.preserveId();
let imgId = pdf.preserveId();
let contentId = pdf.preserveId();
pdf.addObject({
Type: '/Catalog',
Pages: `${pagesId} 0 R`,
}, false, catlogId);
pdf.addObject({
Type: '/Pages',
Kids: `[${firstPageId} 0 R]`,
Count: 1
}, false, pagesId);
pdf.addObject({
Type: '/Page',
Parent: `${pagesId} 0 R`,
Resources: `${resourceId} 0 R`,
Contents: `[${contentId} 0 R]`,
MediaBox: '[0 0 595.27559 841.88976]' //A4 大小
}, false, firstPageId);
pdf.addObject({
ProcSet: '[/PDF /ImageB ]',
XObject: `<< /Im1 ${imgId} 0 R >>`
}, false, resourceId);
pdf.addObject({
Type: '/XObject',
Subtype: '/Image',
Width: opt.width,
Height: opt.height,
ColorSpace: '/DeviceRGB',
BitsPerComponent: '8',
Filter: '[/ASCII85Decode /DCTDecode]'
}, jpegbase85+'~>', imgId);
pdf.addObject({}, `${opt.width} 0 0 ${opt.height} ${opt.x} ${opt.y} cm /Im1 Do`, contentId);
return pdf.toDataUrl(catlogId);
/**
* 把 base64 轉 base85
* @param {string} base64 base64字串
* @returns {string} base85字串
*/
function base64ToBase85(base64) {
let arr = Array.from(atob(base64), x => x.codePointAt());
let padN = arr.length % 4 > 0 ? 4 - arr.length % 4 : 0;
while (padN-- > 0) {
arr.push(0);
}
//每4個一組
let result = '';
for (let i = 0, n = arr.length; i + 3 < n; i += 4) {
let H = (arr[i] << 8 | arr[i + 1]);
let L = (arr[i + 2] << 8 | arr[i + 3]);
let tmp = '';
for (let j = 0; j < 5; ++j) {
let t = (H % 85 << 16 | L % 85);
let r = t % 85; //對 85 取餘數
//除 85
H = (H - H % 85) / 85;
L = (L - L % 85) / 85 + (t - t % 85) / 85;
H += L >>> 16;
L&=0xffff;
tmp = String.fromCodePoint(33 + r) + tmp;
}
result += tmp;
}
return result;
}
}
const jpgData = getTestJpg();
const pdfDataUrl = drawToPdf(jpgData, {
x: 100,
y: 600,
width: 200,
height: 200
});
document.querySelector('iframe').src = pdfDataUrl;
這樣就可以簡單的將圖生成PDF。下次再來研究HTML轉PDF
感謝大神的程式碼提供