LoginSignup
2
1

More than 5 years have passed since last update.

LaTeXとImageMagickとNode.jsを使ってスライド作成

Posted at

LaTeX→DVI→PDF→(複数枚の)画像→結合した画像という順番で処理します。

LaTeXをDVIに変換するには

platex -guess-input-enc -interaction=nonstopmode xxx.tex

とします。

DVIをPDFに変換するには

dvipdfmx -f ptex-ipaex.map xxx.dvi

とします(ptex-ipaex.mapはフォント埋め込みの設定ファイルです)。

PDFをPNG画像に変換するにはImageMagickのコマンドであるconvertを使用します。

convert -density 800 xxx.pdf -quality 100 -resize 800 xxx.png

とします(-densityは解像度、-qualityは品質、-resizeはサイズです)。PDFが複数ページの場合は複数枚の画像が生成されます。複数枚の画像が生成される場合、それぞれの画像のファイル名はxxx-1.pngxxx-2.png、・・・、xxx-9.pngxxx-10.png、・・・となります。

画像を結合するには

montage +frame +shadow +label -tile 2x -geometry 800x600+0+0 xxx-*.png xxx.png

とします(+frame +shadow +labelmontageに画像の結合以外の余計なことをさせないための設定、-tileは縦横何枚ずつ画像を並べるか、-geometryは画像を並べる場所(タイル)のサイズです。-tile 2xで横2枚ずつ並べるという設定です。-geometry 800x600+0+0でタイルのサイズが横800px、縦600pxとなります。+0+0は余白なしということです)。


このような処理をNode.jsを使って行うプログラムを書きました。

ただし、PDFから生成された画像が10枚以上の場合、ファイルの名の所為で、montageで結合を行うと10枚目~19枚目の画像が2枚目の画像の前に結合されてしまいます。

これでは不味いのでPDFから生成された画像が10枚以上ある場合には1枚目から9枚目までの画像のファイル名の連番部分の冒頭に0を挿入するようにしました。

これで画像が10枚以上100枚未満の場合には対応できていますが、100枚以上の場合には対応できていないので注意してください(スライドの枚数が100枚以上になることは稀だと思うので100枚以上の場合には対応していません)。

あと、このプログラムを実行する前には同じフォルダにある画像ファイルは全て削除するか、どこか別の場所に移動してください。そうしないと、無関係の画像が結合されてしまうかもしれません(プログラムの最初に自動で削除するようにしても良いかもしれません)。

var childProcess = require('child_process');
var fs = require('fs');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

var tex = process.argv[2] + '.tex';
var dvi = process.argv[2] + '.dvi';
var pdf = process.argv[2] + '.pdf';
var pngs = process.argv[2] + '-*.png';
var png = process.argv[2] + '.png';

function pngn(n) {
    return process.argv[2] + '-' + + n + '.png';
}

function pngn2(n) {
    return process.argv[2] + '-0' + + n + '.png';
}

processPlatex(0);

function processPlatex(i) {
    var platex = childProcess.spawn('platex', ['-guess-input-enc', '-interaction=nonstopmode', tex], { stdio: 'inherit' });
    platex.on('close', function (code) {
        if (i == 0) {
            processPlatex(1)
        }
        else if (i == 1) {
            processDvipdfmx();
        }
        else {
            console.error('coding error.');
            process.exit(1);
        }
    });
    platex.on('error', function (err) {
        console.error(err);
        process.exit(1);
    });
}

function processDvipdfmx() {
    var dvipdfmx = childProcess.spawn('dvipdfmx', ['-f', 'ptex-ipaex.map', dvi], { stdio: 'inherit' });
    dvipdfmx.on('close', function (code) {
        processConvert();
    });
    dvipdfmx.on('error', function (err) {
        console.error(err);
        process.exit(1);
    });
}

function processConvert() {
    var convert = childProcess.spawn('convert', ['-density', '800', pdf, '-quality', '100', '-resize', '800', png], { stdio: 'inherit' });
    convert.on('close', function (code) {
        fs.stat(pngn(10), function (err, stats) {
            if (!err) {
                processRename(1);
            }
            else {
                processMontage();
            }
        });
    });
    convert.on('error', function (err) {
        console.error(err);
        process.exit(1);
    });
}

function processRename(i) {
    if (i == 10) {
        processMontage();
    }
    else {
        fs.rename(pngn(i), pngn2(i), function (err) {
            if (err) {
                console.error(err);
                process.exit(1);
            }
            else {
                processRename(++i);
            }
        });
    }
}

function processMontage() {
    var montage = childProcess.spawn('montage', ['+frame', '+shadow', '+label', '-tile', '2x', '-geometry', '800x600+0+0', pngs, png], { stdio: 'inherit' });
    montage.on('close', function (code) {
        console.log('finished!!');
    });
    montage.on('error', function (err) {
        console.error(err);
        process.exit(1);
    });
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1