PhantomJSのテキストから画像を作成します

こんばんは、ハブロフスク! 年末年始は終わり、週末の後はだれもがゆっくりと作業リズムに入ります。つまり、新年の楽しみを説明する時です。







PhantomJSと小さな魔法を使用して簡単な写真から画像を生成する方法を学びたい場合は、catへようこそ!







少しの背景



友達と私はこの珍しい一年を過ごすことに決め、誰にも依存しない双方向性を追加しました。 私の友人の輪の大部分は何らかの形でコンピューターゲームに関係しているため、私と私の友人(以下Nikita)は新年の成果(または成果)のリストを作成することにしました。 リストは数日で編集され、成果が受領後5分で忘れられないように、何らかの形でそれらを整理して発行することが決定されました。 その結果、彼らは印刷し、水彩紙に貼り付け、右上隅と左隅に2つの穴を開け、首にアチーブメントのあるカードを掛けることにしました。 技術的なプロセスを完全に理解したニキータは、白黒プリンターで完全に印刷されるシンプルなデザインを描き、それを記入し始めました。







私はすぐに、手で50回以上PSDファイルにテキストを追加したくないと判断しました。適切なプログラマと同様に、1時間のタスクの自動化に2時間強を費やしました。







達成設計の例:







画像







実装



技術プールは即座に選択されました。 テキストおよびhtmlページを生成するNode.js、レンダリングおよび保存するPhantomJS。







Parsimファイル



実績を設定するための形式は次のように設定されました。

-- --



(引用オプション)

そのような行だけで構成されるファイルをJSオブジェクトに変換する必要があります。







 module.exports = (contents) => { return new Promise((resolve, reject) => { return resolve(contents.toString().split('\n').filter(e => e).map(e => { const contents = e.split(' -- '); //   const achieve = {}; const achieveName = capitalizeFirstLetter(contents[0].trim()); let quote = capitalizeFirstLetter(contents[1].trim()); let achieveDescr = capitalizeFirstLetter((contents[2] || '').trim()); if (!achieveDescr) { //   ,    . achieveDescr = quote; quote = null; } achieve.name = achieveName; achieve.description = achieveDescr; if (quote) { achieve.quote = quote; } return achieve; })); }); }
      
      





Buffer



fs.readFile



関数fs.readFile



入力に返し、出力には配列があります。







 [{ "name": "", "quote": "-  ", "description": "   ." }]
      
      





素晴らしい、私たちはさらに働きます。







HTMLページを作成する



PhantomJSでページを開くには、最初にページ自体が必要です。

簡単なtemplate.htmlを作成しました







template.html
 <html> <head> <link rel="stylesheet" href="/index.css"> <meta charset="utf-8"> </head> <body> <div class="achieve"> <div class="achieve__wrapper"> <div class="achieve__text"> <div class="achieve__heading-text{{extraHtmlClass}}"> {{name}} </div> <div class="achieve__main-text"> <div class="achieve__artistic"> {{quote}} </div> <div class="achieve__description"> {{description}} </div> </div> </div> <div class="achieve__image"></div> <div class="clearfix"></div> </div> </div> </body> </html>
      
      





そして、そのためのスタイルの小さなファイルがあり、デザインを正確に繰り返します。







index.css
 body { margin: 0; padding: 0; } .achieve { width: 917px; background: #b3b4b3; position: relative; } .achieve__wrapper { padding-top: 35px; } .achieve__text, .achieve__image { float: left; } .achieve__text { padding-top: 15px; padding-left: 50px; width: 550px; color: #353534; min-height: 293px; } .achieve__heading-text { font-size: 70pt; margin-bottom: 40px; font-weight: bold; font-family: 'Impact', sans-serif; font-style: italic; } .achieve__heading-text--small { font-size: 50pt; line-height: 50pt; margin-bottom: 50px; } .achieve__heading-text--super-small { font-size: 45pt; line-height: 50pt; margin-bottom: 50px; } .achieve__main-text { padding-bottom: 30px; } .achieve__artistic, .achieve__description { font-family: 'Verdana', sans-serif; } .achieve__artistic { font-style: italic; font-size: 20pt; } .achieve__image { background: url('/image.png') no-repeat; width: 300px; height: 309px; background-size: contain; position: absolute; bottom: 0; right: 20px; } .achieve__description { font-size: 25pt; } .clearfix { clear: both; }
      
      





テキストtemplate.htmlには、{{and}}で囲まれたテキストが含まれています。 これらは、パーサーからのデータに基づいてアチーブメントのhtmlファイルの作成を変更する、将来のテンプレートエンジンの始まりです。

テンプレートエンジン自体は8行に収まります。







 function template (template, data) { for (const key in data) { const templateKey = '{{' + key + '}}'; template = template.replace(templateKey, data[key]); } return template; }
      
      





また、アチーブメントの名前にクラスを追加するいくつかのルールを追加しました。 (実験者という名前のAchivkaは、常にフィットすることを望まず、ゴブレットに登りました)







 if (element.name.split(' ').length > 1 || element.name.length >= 9) { data.extraHtmlClass = ' achieve__heading-text--small'; } if (element.name.split(' ').length === 1 && element.name.length >= 14) { data.extraHtmlClass = ' achieve__heading-text--super-small'; }
      
      





これは、htmlが生成するファイルからのクリッピングです 。ファイルの完全なバージョンはこちらにあります







その結果、アチーブメントの名前、引用、説明が置き換えられるHTMLファイルの数を生成する必要があります。







PhantomJSにディレクトリを読み取らせることができなかったことを急いで付け加えましたが、それは単純なはずです。 したがって、htmlファイルと共に、作成されたページのすべての名前を含むnames.json



ファイルを生成します。







写真を作成する



最も簡単な部分は、PhantomJSによってドックからサンプルコードをコピーし、少し修正して実行する必要があります。







 const fs = require('fs'); const data = require('../data/names.json'); const config = require('../config/config.json'); var pageCount = 0; data.forEach(function (e) { //    const page = require('webpage').create(); //  phantomjs  page.open('http://127.0.0.1:' + config.port + '/pages/' + e + '.html', function(status) { //  html setTimeout(function() { if(status === "success") { page.render('achievements/' + e + '.png'); //  html   pageCount++; if (pageCount === data.length) { phantom.exit(); } } }, 2000); }); page.onResourceError = function(resourceError) { console.log('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')'); console.log('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString); }; });
      
      





このphatnom lib/phantom.js



を実行し、htmlファイルから画像を生成します。







ここで何かが間違っています...



本当に、何かが間違っています! PhantomJSはHTTP経由でデータをアップロードしますが、静的ファイルを備えたHTTPサーバーがないため、写真を取得できません。 これは、小さな静的サーバーを作成する必要があることを意味します。これはプログラムの最後で強制終了します。







静的サーバーがすでに作成されていることを神に感謝します。使用する必要があります。







 const static = require('node-static'); const file = new static.Server('./public'); module.exports.spawnServer = (port) => { return new Promise(resolve => { //    ,   const server = require('http').createServer(function (request, response) { request.addListener('end', function () { file.serve(request, response); }).resume(); }).listen(port, () => { resolve(server); }); }); }; module.exports.killServer = (server) => { server.close(); //   .   . }
      
      





テキストからJS配列を作成するパーサー、ページジェネレーター、静的サーバー、およびページを作成するphantomjsスクリプトがあります。 それはすべてを構成するために残り、新年のエンターテイメントは準備ができています!







すべてのコードはPromisesで記述されており、使用されるすべての関数のPromise ラッパーがあるため、メソッドのレイアウトにはそれほど時間がかかりません。







 staticServer.spawnServer(config.port).then((serverInstance) => { staticServerInstance = serverInstance; return folderManager.create(); }) .then(() => promiseFuncs.readFile(listFile)) .then(buffer => parser(buffer)) .then(data => Promise.all(data.map(e => pageGenerator(e)))) .then(names => promiseFuncs.writeFile('./data/names.json', JSON.stringify(names))) .then(() => promiseFuncs.execAndOnClose('./node_modules/.bin/phantomjs', ['lib/phantom.js'])) .then(() => { staticServer.killServer(staticServerInstance); console.log('Achievements generated!'); if (config.removeFolders) { return folderManager.remove(); } return; }).catch(e => { console.log(e); });
      
      





以上です。 創造性のほんの一部を示し、成果の元の名前を(できれば地元のミームを使用して)考え出すことは残っており、楽しみは保証されています。 お祝いの「Hurray!」で各成果の受領を祝うだけで十分です。 そして厳soleにそれを発行します。







残念ながら、実際の生活の中で写真を具体化するとき、私たちは非常に一生懸命努力しましたが、成果の半分でさえ配ることができませんでした。 (50を超える実績が紙に貼り付けられ、穴パンチで穴が開けられ、糸できれいに結び付けられました)。







この記事が、最小限のコストで単純なテキストから画像を生成する方法を理解するのに役立つことを願っています。








All Articles