はじめに
建築系のCG制作プロダクションで3DCGモデラーをしています。
建築の仕事をしていると、広範囲・高解像度の地図とか航空写真が欲しい時があります。
一番簡単なのは、国土地理院の地理院地図から画像を保存することです。
無料ですし、簡単で大変便利です。ただ、この地図、若干、古いんです。
もっと新しい地図が欲しければ、ゼンリンやMapFanみたいな地図会社の有料サービスを利用するか、
GoogleマップやYahooマップでスクリーンショットを撮るしかありません。
##高解像度のスクリーンショット
"無料で"というと、スクリーンショットを撮ることになります。
ただ、"広範囲・高解像度" となると、デスクトップよりずっと大きな画像になります。
普通にスクリーンショットを撮ろうとすると1画面に収まりません。デュアルディスプレイでも無理です。
ブラウザのエクステンションに、"ページ全体のスクリーンショットを撮る"ものがありますが、
画像のキャッシュなどの問題で、キレイに撮るのはなかなか大変です。
なので以前は、仕方なくスクリーンショットをたくさん撮って、Photoshopで合成してました...。
Chromeを自動操作出来るpuppeteer
puppeteerはnode.js上で動くChromeを自動操作するためのライブラリです。
大変短いコードで簡単にWEBページのスクリーンショットを撮れます。
Puppeteer API
本来、WEBテスト用のツールですが、"ウィンドウサイズを指定"出来るので、
4kでも8kでも任意のサイズのスクリーンショットを撮れます。
インストール
node.js Install
puppeteer Install
実践
以下、Yahooマップの写真モードでやってみました。
// yahoo maps in Japan
const url = 'https://yahoo.jp/scdMa0'; //マップの表示設定をした後、URLを取得(アドレスバーのじゃなくて、アイコンの"URLボタン"のほうから取る)
(async() => {
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(120000);
const response = await page.goto(url,{waitUntil:"networkidle2"});
let n = 4;
let k = 1024;
// 4k = 4096 pixel x 4096 pixel
try {
let map_area = '#map';
await page.setViewport({width:n*k,height:n*k}); // ウィンドウサイズを指定
for (let i = 2; i > 0; i--) { // ブラウザにキャッシュさせるために2回繰り返す
await page.waitFor(90000); //通信環境にもよると思いますが、少し待たないと画像が全部来ないです。
if(i == 1){
let img_name = 'map_'+ n +'k' + i + '.jpg';
const map_area_Handle = await page.$(map_area);
await map_area_Handle.screenshot({path: img_name});
console.log(img_name);
}
}
} catch (e) {
console.log(e);
throw e;
} finally{
await browser.close();
}
})();
node main.js
結果
最大ズームで8k画像(8192 pixel x 8192 pixel)を取得出来ました。
画像サイズについて
ウチの通信環境だと、8kはうまくいかない時があります。
画像タイルが全部ロードされず、歯抜けになってしまうことがあります。
12kでも試してみましたが、全然撮れません...。半分しか画像が来ません。
4kくらいまでならちゃんと撮れます。
扱いやすいサイズにする
そもそも、あまり画像サイズがデカいと後で扱いにくいので、
最終的に、大きくても4kに収まるようにするのがよいと思います。
理想的には2k以下が軽くていいです。大抵は事足ります。
広さが足りなければ、ズームアウトすればいいですし、
一部分だけでも高解像度が欲しければ、そのエリアと周囲を分けるといいと思います。
動くことは動くけど
シンプルなコードですが、ちゃんと絵が撮れるようになるまでちょっと苦労しました。
画像が全部ロードされるまで待つ方法が分からず、結局、時間指定です。
node.jsって何?ってところから始めたので、エンジニアでもなんでもない自分にとっては上出来ですが...。
うまい方法わかる方いらっしゃいましたら、ご教授ください。