バイトニックソート

データのソート(並び替え)にはいろいろなアルゴリズムがあるけれど、バイトニックソートという名前は初めて耳にした。

バイトニックソート – 高速化プログラミング

Bitonic sort

多少制約があるみたいだけど、かなり高速である模様。

2010年07月28日(水) 23時35分  

大量のJPGファイルをPDFファイルに変換して結合

スキャニングしてできた大量のJPGファイルを1個のPDFファイルに結合する場合、ImageMagickのconvertを使って

convert *.jpg output.pdf

とすれば簡単に作成できる。
しかしこの方法では、作成時に大量のメモリを消費してしまうのが難点。

私のPC環境で、約180個のJPGファイルを1個のPDFファイルに処理するのに約6分かかった。

処理中、物理メモリを約1GB消費、PF使用量が約1.5GB増加、CPU使用率は20%前後増加といった具合。

処理中、ハードディスクのアクセスランプが点灯しっぱなしになっていたから、使用可能な物理メモリが少なくなれば、もっと時間がかかるかもしれない。

で、あれこれ調べてみたところ、pdftkを使用すれば改善できそうなことがわかった。

pdftkのWindows版は、以下のサイトから入手できる。

pdftk – the pdf toolkit

pdftkを使って大量のJPGファイルをPDFファイルへ変換して、1個のPDFファイルへ結合する手順は、以下の通り。

  1. ImageMagicのconvertを使用して、JPGファイルを1個ずついくつかまとめてPDFファイルへ変換する。
  2. 手順1で作成したPDFファイルを結合する。
  3. 手順1で作成したPDFファイルを削除する。
  4. JPGファイルを削除する。

上記の処理するにあたっては、Perlを使用。ソースコードは、以下の通り。

#!/usr/local/bin/perl
use strict;
use warnings;

my @list = &getFileList;
my @pdf;
my @jpg = @list;
my $tmpPdf = "tmp000";

while (scalar(@jpg) > 0) {
    my $arg = join(" ", splice(@jpg, 0, 20));	#一度に結合するJPGファイルの個数
    &execute("convert $arg $tmpPdf.pdf");
    push(@pdf, "$tmpPdf.pdf");
    $tmpPdf++;
}

my $oldPdf = "";
my $newPdf = "new000";

while (scalar(@pdf) > 0) {
    my $arg = join(" ", splice(@pdf, 0, 20));	#一度に結合するPDFファイルの個数
    &execute("pdftk $oldPdf $arg cat output $newPdf.pdf");	#前回結合したPDFファイル($oldPdf)がある場合は、先頭に追加

    if (length($oldPdf) > 0) {
        unlink($oldPdf);
    }

    $oldPdf = $newPdf . ".pdf";
    $newPdf++;
    unlink split(/\s+/, $arg);
}

&execute("rename $oldPdf output.pdf");
unlink @list;
exit;

sub getFileList {
    open(DIR, "dir *.jpg |");
    my $list = join(" ", sort <DIR>);
    my @list = split(/\s+/, $list);
    close(DIR);

    open(DIR, "dir *.JPG |");
    $list = join(" ", sort <DIR>);
    push(@list, split(/\s+/, $list));
    close(DIR);

    sort @list;
}

sub execute {
    print $_[0], "\n";
    system($_[0]);
}

上記のスクリプトをコマンドプロンプトから実行してみた結果、CPU使用率は増えたものの、物理メモリ消費量とPF使用量についてはほとんど変化は見られず、かなりの改善が見られた。

時間的には、240個のJPGファイルをImageMagickのconvertだけで処理した場合、約3分15秒かかったのが、pdftkを併用した上記のスクリプトで処理した場合だと、約1分15秒となった。

ImageMagickのconvertを使って大量の画像ファイルを1個のPDFファイルにする際に時間がかかっている方は、上記のようにpdftkを併用する方法を一度試してみると良いかもしれない。

2010年06月26日(土) 21時38分  

QRコードを読み取って、空メールを送信

2010年04月14日(水) 22時36分  

制限付きユーザーから管理者のユーザー権限でプログラムを実行する

Windowsに制限付きユーザーでログインしている時に管理者のユーザー権限でプログラムを実行したい場合、コンテキストメニューから「別のユーザーとして実行(A)…」を選択するか、runasコマンドを使う。

runasコマンドの基本的な使い方は、以下の通り。

runas /user:ユーザー名 プログラム

詳しい使い方はrunas /?に譲るとして、大抵の場合、管理者のユーザー権限でプログラムを実行したい場合は、ユーザーのパスワードの入力が必要となる。

JScriptを使って管理者のユーザー権限でプログラムを実行し、パスワードを自動的に入力したい場合は、以下のようなスクリプトになる。

var userFile = "user.txt";
var passFile = "pass.txt";
var args = WScript.Arguments;

if (args.length != 1) {
    WScript.Quit(1);
}

var AppPath		= args(0);
var AppExecUserName	= getTextFileData(userFile);
var AppExecUserPass	= getTextFileData(passFile);

//実行したいプログラムを指定する。
//runasコマンドのコマンドラインオプションは、"runas /?"を参照
var WshShell = new ActiveXObject("WScript.Shell");
WshShell.Run("runas /user:" + AppExecUserName + " " + AppPath + " ", 2);
//savecred
delayedSendKeys(AppExecUserPass);

//実行するパスワードを送信
function delayedSendKeys(str) {
    WScript.Sleep(300);
    for (var i = 0; i < str.length; i++) {
        WScript.Sleep(100);
        WshShell.SendKeys(str.substring(i, i + 1));
    }
    WScript.Sleep(300);
    WshShell.SendKeys("{enter}");
}

function getTextFileData(fileName) {
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var s = fso.OpenTextFile(fileName, 1, false).ReadAll();
    return s;
}

パスワードの自動入力は、SendKeysで行なっている。

このスクリプトを使うと、管理者のユーザー権限とパスワードが設定済みならば、制限付きユーザーであってもほぼ何でも実行できてしまうようになるので、スクリプトの取り扱い(特に利用環境)とパスワードの漏洩には十分に注意しましょう。使用する場合は、自己責任で。

このJScriptを一歩進めてExcelVBAで実装してみると、以下のような感じになった。

パスワードの管理がほんの少しだけましになるけれど、やっぱり取り扱いには十分な注意が必要。

2010年03月13日(土) 23時53分  

32ビット(2の32乗)の語呂合わせ

突然、「2の32乗はいくら?」と質問された時、すぐに思い出せないことが多い。

2の32乗は、4294967296。この10桁の数字を即座に答えられる人は、どれくらいいるのだろうか。

というわけで、語呂合わせで覚えておけば思い出しやすいだろう思って4294967296のメジャーな語呂合わせはないものかとぐぐってみたのだけれど、これというものが見つけられなかったので、勝手に語呂合わせを考えてみた。

429 49 67 2 96

ようふく しっく むね に くろ(洋服シック胸に黒)

429 4967 296

ようふく しくむな つくろう(洋服仕組むな繕う)

ついでに4294967296の半分の値、2147483648(=2の31乗)も考えてみた。

21474 83 648

ついしなし はちみつ むしゃ(追試なし蜂蜜武者)

21474 83 648

ついしなし はちみつ むしば(追試なし蜂蜜虫歯)

これでもう、質問が来ても平気ですな(?)

4294967296のメジャーな語呂合わせを探している途中、語呂合わせジェネレータがヒットしたので紹介。語呂合わせに困った時や、その他いろいろと使えます。

興味を持たれた方はぜひ、「4294967296」や「214748364」など、いろいろ試してみましょう。同サイトでは、他にもいろいろなジェネレータを公開されています。

2010年02月10日(水) 23時03分  

strlen関数を、ループを使用しないで実現してください

とある書籍を読み返していて、

strlen関数を、ループを使用しないで実現してください

という文章が目に留まってちょいと気になった(スイッチが入った)ので、実際に書いてみた。所要時間は10分らしい。

久しぶりのC言語で、以下、私なりの答え。

#include <stdio.h>
#include <stdlib.h>
size_t strlen(const char *s) {
    return (*s != '\0' ? 1 + strlen(++s) : 0);
}
int main(void) {
    char *s = "hello, world.";
    printf("strlen(%s): %d\n", s, strlen(s));
    return EXIT_SUCCESS;
}

……所要時間約8分。

‘\0′を検出するまで再帰的に調べる方法ぐらいしか思いつかなかった。

2010年01月20日(水) 23時12分  

Webブラウザからコマンドライン版Webキャプチャーを実行(その2)

昨日の続き。無事、PHPからコマンドライン版Webキャプチャーを起動することができるようになったので、次はクライアント寄りのプログラムの作成。

言語はPHPとJavaScriptを使用。JavaScriptはJQueryも少し使用。

クロスブラウザ対応が面倒なので……。

そうしてできたのが、下のようなもの。

ところどころ手を抜いているけれど、一応動いてます。実際に動いているやつはこちら

対象サイトによってはキャプチャーに失敗することがあるみたい……。

※自宅Webサーバーを停止しているときは動きませんので、あしからず。

2009年12月06日(日) 23時44分  

Webブラウザからコマンドライン版Webキャプチャーを実行(その1)

先月作成したWebページキャプチャーのコマンドライン版を、Webブラウザから実行できるようにしてみようと思い立つ。
やろうとしていることは下のようなもの。適当に書いたので、間違っているかもいないかも。

クライアントPCから直接自宅Webサーバーにアクセスしていないのは、自宅Webサーバーをできるだけ外部に晒したくないのと、動的にIPが変わるという理由から。無料DDNSサービスを利用すれば済む話なのだけれど。

VBS+Perlを使って15分毎に自宅WebサーバーのIPアドレスを取得&更新しているけれど、今のところ特に困っていない。

さて、本題。手始めに自宅Webサーバーにコマンドライン版Webキャプチャーを起動するPHPを書いたのだけれど、きちんと実行してくれない。
コマンドプロンプトから実行すると問題なく実行してくれるのだが、PHPから起動すると、起動してそのままプロセスが終了せずにタイムアウトとなってしまう。
調べてみた結果、どうやらシステムアカウント権限で実行されていることが原因であることがわかった。コマンドライン版WebキャプチャーをAdobe AIRで作成しているため、同時にAdobe AIR Updater(下図)も実行されて、これが待ち状態になっているらしい。システムアカウント権限で実行されているので、プロセス上に存在していても表示されていないので、手が出せず(苦笑)

ならばユーザーアカウント権限で起動してやればと思い、runasコマンドで起動を試みるもユーザーアカウント権限で起動する際のユーザーアカウントのパスワード入力の段階でアウト。どうもシステムアカウント権限からユーザーアカウント権限で起動することはできないっぽい(苦笑)

結局、PHPを起動しているApacheをユーザーアカウント権限で再起動することで解決。

無事、PHPからコマンドライン版Webキャプチャーを実行することに成功。やれやれ。

2009年12月05日(土) 23時33分