如何让Puppeteer加载本地图片与自定义字体?
解决Puppeteer生成图片时的本地资源加载问题
针对你遇到的本地图片无法加载和自定义字体加载的问题,我整理了具体的解决方案:
一、修复本地图片路径加载问题
当你使用page.setContent()时,页面默认的基准URL是about:blank,相对路径(比如./1.jpg)会基于这个空白页面解析,自然找不到脚本同目录的图片。有两种简单的解决方式:
方法1:设置页面的基准URL(推荐)
直接在setContent时指定baseURL为脚本所在的目录,这样HTML里的相对路径会自动解析为正确的本地文件路径:
const path = require('path'); const _ = require('lodash'); const puppeteer = require('puppeteer'); (async () => { const html = _.template(` <html> <body> <div class="testing"> <h1>Hello {{ test }}!</h1> <img src="./1.jpg" alt="alt text" /> </div> </body> </html> `); const browser = await puppeteer.launch(); const page = await browser.newPage(); // 设置基准URL为当前脚本所在目录 const baseUrl = `file://${path.resolve(__dirname)}/`; const data = html({ test: 'World' }); await page.setContent(data, { baseURL: baseUrl }); const take = await page.$('.testing'); await take.screenshot({ path: 'screenshot.png', omitBackground: true }); await browser.close(); })();
方法2:使用绝对文件路径
把图片路径转成file://协议的绝对URL,直接替换HTML中的相对路径:
const path = require('path'); const _ = require('lodash'); const puppeteer = require('puppeteer'); (async () => { const html = _.template(` <html> <body> <div class="testing"> <h1>Hello {{ test }}!</h1> <img src="{{ imageUrl }}" alt="alt text" /> </div> </body> </html> `); const browser = await puppeteer.launch(); const page = await browser.newPage(); // 生成图片的绝对file URL const imagePath = path.resolve(__dirname, './1.jpg'); const imageUrl = `file://${imagePath}`; const data = html({ test: 'World', imageUrl }); await page.setContent(data); const take = await page.$('.testing'); await take.screenshot({ path: 'screenshot.png', omitBackground: true }); await browser.close(); })();
二、加载自定义字体
加载自定义字体同样需要确保字体文件的路径被正确解析,这里提供两种常用方法:
方法1:在HTML中通过@font-face引入
直接在HTML模板里添加样式,用绝对路径引入字体文件:
const path = require('path'); const _ = require('lodash'); const puppeteer = require('puppeteer'); (async () => { const html = _.template(` <html> <style> @font-face { font-family: 'MyCustomFont'; src: url('{{ fontUrl }}') format('truetype'); /* 如果是woff2等其他格式,修改format参数即可 */ } .testing { font-family: 'MyCustomFont', sans-serif; } </style> <body> <div class="testing"> <h1>Hello {{ test }}!</h1> <img src="./1.jpg" alt="alt text" /> </div> </body> </html> `); const browser = await puppeteer.launch(); const page = await browser.newPage(); const baseUrl = `file://${path.resolve(__dirname)}/`; // 生成字体文件的绝对URL const fontPath = path.resolve(__dirname, './custom-font.ttf'); const fontUrl = `file://${fontPath}`; const data = html({ test: 'World', fontUrl }); await page.setContent(data, { baseURL: baseUrl }); // 等待字体加载完成(可选但推荐,避免截图时字体未渲染) await page.waitForFunction(() => document.fonts.check('16px MyCustomFont')); const take = await page.$('.testing'); await take.screenshot({ path: 'screenshot.png', omitBackground: true }); await browser.close(); })();
方法2:使用page.addFontFace()方法
通过Puppeteer的API直接给页面添加字体,无需修改HTML:
const path = require('path'); const _ = require('lodash'); const puppeteer = require('puppeteer'); (async () => { const html = _.template(` <html> <style> .testing { font-family: 'MyCustomFont', sans-serif; } </style> <body> <div class="testing"> <h1>Hello {{ test }}!</h1> <img src="./1.jpg" alt="alt text" /> </div> </body> </html> `); const browser = await puppeteer.launch(); const page = await browser.newPage(); // 添加自定义字体 const fontPath = path.resolve(__dirname, './custom-font.ttf'); await page.addFontFace({ family: 'MyCustomFont', src: `url(file://${fontPath})`, }); const baseUrl = `file://${path.resolve(__dirname)}/`; const data = html({ test: 'World' }); await page.setContent(data, { baseURL: baseUrl }); await page.waitForFunction(() => document.fonts.check('16px MyCustomFont')); const take = await page.$('.testing'); await take.screenshot({ path: 'screenshot.png', omitBackground: true }); await browser.close(); })();
注意:如果字体加载较慢,建议添加page.waitForFunction()等待字体加载完成,避免截图出现默认字体的情况。
内容的提问来源于stack exchange,提问作者bdrtsky
相关产品推荐
相关产品推荐

