Skip to content

Commit 8cb6864

Browse files
authored
Merge pull request #21 from Shopify/mv-1.2.1
Bump to ModelViewer 1.2.1
2 parents f5895f5 + d083687 commit 8cb6864

7 files changed

+319
-189
lines changed

dev.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ type: node
66
up:
77
- railgun
88
- node:
9-
version: v8.16.0
9+
version: v14.3.0
1010
yarn: true
1111
packages:
1212
- .

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
"author": "Stephan Leroux <stephan.leroux@shopify.com>",
1212
"license": "MIT",
1313
"dependencies": {
14-
"@google/model-viewer": "^0.8.0",
15-
"puppeteer": "^2.1.1",
14+
"@google/model-viewer": "^1.2.1",
15+
"mime-types": "^2.1.27",
16+
"puppeteer": "^5.3.1",
1617
"yargs": "^13.3.0"
1718
}
1819
}

src/cli.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ const FileServer = require('./file-server');
88

99
const startBrowser = require('./start-browser')
1010
const loadGLBAndScreenshot = require('./load-glb-and-screenshot');
11+
const scrubOutput = require('./scrub-output');
12+
const colors = require('./colors.js')
1113

1214
const argv = require('yargs')
1315
.alias('i', 'input')
1416
.alias('o', 'output')
17+
.alias('c', 'color')
1518
.alias('w', 'width')
1619
.alias('h', 'height')
1720
.alias('f', 'image_format')
@@ -20,11 +23,12 @@ const argv = require('yargs')
2023
.count('verbose')
2124
.alias('v', 'verbose')
2225
.describe('i', 'Input glTF 2.0 binary (GLB) filepath')
23-
.describe('o', 'Output PNG screenshot filepath')
26+
.describe('o', 'Output screenshot filepath')
2427
.describe('w', 'Output image width')
2528
.describe('h', 'Output image height')
2629
.describe('f', 'Output image format (defaults to \'image/png\')')
2730
.describe('q', 'Quality of the output image (defaults to 0.92)')
31+
.describe('c', 'Output image background color (defaults to transparent, accepts HEX or RGB)')
2832
.describe('t', 'Timeout length')
2933
.describe('v', 'Enable verbose logging')
3034
.demandOption(['i', 'o'])
@@ -71,9 +75,11 @@ function copyModelViewer(){
7175

7276
const width = argv.width || 1024;
7377
const height = argv.height || 1024;
74-
const format = argv.image_format || 'image/png';
7578
const quality = argv.image_quality || 0.92;
7679
const timeout = argv.timeout || 10000;
80+
const [output, format] = scrubOutput(argv.output, argv.image_format)
81+
const defaultBackgroundColor = (format === 'image/jpeg' ? colors.white : colors.transparent);
82+
const backgroundColor = argv.color || defaultBackgroundColor;
7783

7884
const {page, browser} = await startBrowser({width, height, libPort: libServer.port});
7985

@@ -91,7 +97,7 @@ function copyModelViewer(){
9197
process_status = 0;
9298

9399
try {
94-
await loadGLBAndScreenshot(page, { glbPath, outputPath: argv.output, format, quality, timeout });
100+
await loadGLBAndScreenshot(page, { glbPath, outputPath: output, backgroundColor, format, quality, timeout });
95101
t3 = performance.now();
96102
INFO("--- Took snapshot of", argv.input, `(${timeDelta(t2, t3)} s)`);
97103
} catch (err) {

src/colors.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
white: 'rgba(255, 255, 255, 100)',
3+
transparent: 'rgba(255, 255, 255, 0)',
4+
}

src/load-glb-and-screenshot.js

+46-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
module.exports = (page, {glbPath, outputPath, format, quality, timeout}) => {
2-
return page.evaluate((browser_glbPath, browser_outputPath, browser_format, browser_quality, timeout) => {
1+
const colors = require('./colors')
2+
module.exports = (page, {glbPath, outputPath, backgroundColor, format, quality, timeout}) => {
3+
return page.evaluate((browser_glbPath, browser_outputPath, backgroundColor, image_format, browser_quality, timeout, colors) => {
34
return new Promise((resolve, reject) => {
45
var startTime = Number(new Date());
56
var endTime = startTime + timeout;
@@ -13,16 +14,48 @@ module.exports = (page, {glbPath, outputPath, format, quality, timeout}) => {
1314
}
1415
}
1516

16-
modelViewer = document.getElementById('snapshot-viewer');
17-
timeoutSet = setInterval(isTimedOut, 1000);
17+
const rafAsync = function() {
18+
return new Promise(resolve => {
19+
requestAnimationFrame(resolve);
20+
});
21+
}
22+
23+
const checkElementExists = async function(element) {
24+
while (element === null) {
25+
await rafAsync()
26+
}
27+
return element;
28+
}
29+
30+
const modelViewerCanvas = async function(resolveCanvas){
31+
checkElementExists(modelViewer.shadowRoot)
32+
const srcCanvas = modelViewer.shadowRoot.getElementById('webgl-canvas');
33+
checkElementExists(srcCanvas)
34+
if(backgroundColor === colors.transparent){
35+
resolveCanvas(srcCanvas);
36+
}
37+
const destinationCanvas = document.createElement("canvas");
38+
destinationCanvas.width = srcCanvas.width;
39+
destinationCanvas.height = srcCanvas.height;
40+
41+
const destCtx = destinationCanvas.getContext('2d');
42+
destCtx.fillStyle = backgroundColor;
43+
destCtx.fillRect(0,0,srcCanvas.width,srcCanvas.height);
44+
45+
destCtx.drawImage(srcCanvas, 0, 0);
1846

19-
modelViewer.addEventListener('model-visibility', function(){
47+
48+
resolveCanvas(destinationCanvas);
49+
}
50+
51+
const modelViewerVisibleCallback = async function (event){
2052
try {
2153
const visible = event.detail.visible;
2254
if(visible){
2355
let t0 = Number(new Date());
56+
const canvas = await new Promise(modelViewerCanvas)
2457
window.saveDataUrl(
25-
modelViewer.toDataURL(browser_format, browser_quality),
58+
canvas.toDataURL(image_format, browser_quality),
2659
browser_outputPath,
2760
);
2861

@@ -37,8 +70,13 @@ module.exports = (page, {glbPath, outputPath, format, quality, timeout}) => {
3770
} catch(err) {
3871
reject(err);
3972
}
40-
});
73+
}
74+
75+
modelViewer = document.getElementById('snapshot-viewer');
76+
timeoutSet = setInterval(isTimedOut, 1000);
77+
78+
modelViewer.addEventListener('model-visibility', modelViewerVisibleCallback)
4179
modelViewer.src = browser_glbPath;
4280
});
43-
}, glbPath, outputPath, format, quality, timeout);
81+
}, glbPath, outputPath, backgroundColor, format, quality, timeout, colors);
4482
}

src/scrub-output.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const mime = require('mime-types');
2+
const path = require('path');
3+
4+
const appendExtension = function(output, format){
5+
const extension = mime.extension(format);
6+
return `${output}.${extension}`
7+
}
8+
9+
const validExtension = function(extension, format){
10+
const mimeType = mime.lookup(extension);
11+
if(mimeType !== format){
12+
throw new Error(`Output filetype is not valid provided format. Output file extension (${extension}) should have mimeType: ${mimeType}`);
13+
}
14+
return true;
15+
}
16+
17+
module.exports = (output, imageFormat) => {
18+
const format = imageFormat || mime.lookup(output) || 'image/png'
19+
const extension = path.extname(output);
20+
if(extension && validExtension(extension, format)) return [output, format];
21+
return [appendExtension(output, format), format]
22+
}

0 commit comments

Comments
 (0)