18 Dec 2017
Screenshot automation of 2D Drawings with Forge Viewer and Headless Chrome
Last week I showed you how to run the Forge Viewer headless in Chrome with Puppeteer and an obvious use case of that is automating the generation of high-quality screenshots of your models. The workflow also applies to 2D drawings, however taking a direct shot of a drawing will generate an image that contains not only the drawing sheet but also the borders, which in some cases may not be desirable:
In order to strip down our screenshot to the bare sheet, we need to add a bit of extra code. The first step is to find out the extends of the sheet in model space and convert that to screen coordinates:
var bbox = viewer.model.getBoundingBox()
var screenbbox = {
min: viewer.worldToClient(bbox.min),
max: viewer.worldToClient(bbox.max)
}
We need to pass that information to the Puppeteer code: an easy way to communicate between the client and node code is to use Puppeteer evaluate function. This can execute a function in browser context or retrieve a value from the DOM objects, so I simply set the bounding box result in the document:
viewer.addEventListener(
Autodesk.Viewing.GEOMETRY_LOADED_EVENT,
function () {
viewerDiv.classList.add("geometry-loaded")
var bbox = viewer.model.getBoundingBox()
document.bbox = {
min: viewer.worldToClient(bbox.min),
max: viewer.worldToClient(bbox.max)
}
})
We can then simply access that value from Puppeteer side and use the page.screenshot function, which takes a optional clip argument allowing to clip the image that is being generated:
page.screenshot([options])
options <Object> Options object which might have the following properties:
// ...
clip <Object> An object which specifies clipping region of the page. Should have the following fields:
x <number> x-coordinate of top-left corner of clip area
y <number> y-coordinate of top-left corner of clip area
width <number> width of clipping area
height <number> height of clipping area
So our node code looks like below:
const page = await browser.newPage()
await page.goto(url)
const mainFrame = page.mainFrame()
//waits for .geometry-loaded class being added
await mainFrame.waitForSelector(
'.geometry-loaded', {
timeout: 30000
})
const bbox = await mainFrame.evaluate(() => {
return document.bbox
})
// ensure min >= 0
bbox.min.x = bbox.min.x > 0 ? bbox.min.x : 0
const clip = {
height: bbox.min.y - bbox.max.y - 5, //5 pixels correction
width: bbox.max.x - bbox.min.x,
x: bbox.min.x,
y: bbox.max.y,
}
// saves screenshot in process.env.IMGPATH
// or defaults to test.png
await page.screenshot({
path: process.env.IMGPATH || 'test.png',
clip
})
And here is how our drawing screenshot looks after running the test:
Check out the full project at: https://github.com/leefsmp/forge-viewer-headless