2012/02/10

リトルエンディアン・バイトエンディアン バイトオーダー相互変換関数

PSDを読み込むとき、バイトオーダーがビッグエンディアンなので自前でリトルエンディアン・ビッグエンディアンの相互変換マクロを作って読み込み・書き込みをしていたが、どうも標準でCライブラリに搭載されているらしい。

  「リトルエンディアン」 「ビッグエンディアン」 のキーワードで検索するから見つからないらしく、これらの別名として 「ホストバイトオーダー」 「ネットワークバイトオーダー」 というキーワードがあり、こちらで検索すると相互変換関数が見つかる。



 それでも用意されている関数だけだと16bit(2byte)と32bit(4byte)の値しか扱えないので、自前で実装する余地が残っているのが救いか?

ネットワークバイトオーダー<->ホストバイトオーダー変換関数(BYTEORDER関数)




  • #include <arpa/inet.h>

  • u_long htonl (u_long hostlong) : 32 ビットホストバイトオーダーをネットワークバイトオーダーに変換します

  • u_short htons (u_short hostshort) : 16 ビットホストバイトオーダーをネットワークバイトオーダーに変換します

  • u_long ntohl (u_long netlong) : 32 ビットネットワークバイトオーダーをホストバイトオーダーに変換します

  • u_short ntohs (u_short netshort) : 16 ビットネットワークバイトオーダーをホストバイトオーダーに変換します


 また、隣接するバイトを変換するswab(swap byte)関数が用意されている。



  • #include <string.h>

  • void swab(const void *from, void *to, size_t n) : from で指された配列から n バイトを to で指された配列に、隣接した偶数/奇数バイトを交換しながらコピーする。この関数は異なるバイトオーダーを持つマシン間でのデータ交換に使用される

2012/02/04

C++によるlibpngを使用したpngファイルの読込と表示・描画メモ

掲載予定のサンプルソースコードは現在調整中です
環境情報
WindowsXP SP3
VisualStduio2005 SP1

本稿の対象者


 自分でlibpngを利用したpng読込・書込処理を実装したいWindows(VisualStudio)ユーザー。足がかりになるための資料として活用してもらえることを目標に投稿しています。
 必要最低限のライブラリのみ参考にしたいというのであれば、libpngの中の下記ディレクトリにWindows/VisualStudio向けにPngの読み込み・書き込み実装されているlibpngライセンスのソースコードがありますので、そちらを導入して微調整をするといいでしょう。


  • libpng/contrib/visupng/PngFile.c

  • libpng/contrib/visupng/PngFile.h


 単純にC/C++でpngを手軽に読み込みたい場合はSDLやGDI+等の画像ライブラリを使用することをお勧めします。

導入


 sourceforgeから最新版のlibpngとzlibをダウンロードしてください。

http://sourceforge.net/projects/libpng/files/

 解凍後はlibpng-x.x.xとzlib-x.x.xはフォルダのバージョン名等をリネームして「libpng」「zlib」というフォルダ名で同レベルの階層に配置してください。

 次に、libpng/projects/visualc71/libpng.slnを開いてください。VC6.0以前だと開けない場合がありますが、その場合は独自にプロジェクトを作成してコンパイル環境を構築するか、無料版のVSの最新版を利用してlibpng/projects/vstudio/vstudio.slnを利用してください。
 後はビルド構成をDebug/Releaseに切り替えてリビルドすれば、libpngd.libとlibpng.libが生成されます。

 プロジェクトで使用するにはプロジェクトに直接png.h,zlib.h,zconf.h等のヘッダファイルを取り込み、pragmaプリプロセッサかプロジェクトの依存ライブラリにlibpng.libをリンクしてください。詳細な手順は別サイトで画像付で詳しく書かれていると思いますので、そちらに任せます。


自力解決に向けてのアドバイス


 libpng,zlib等の3rdparty製のライブラリの使用方法をネットで探して実装しようとしている人はネットに落ちていない問題が出ると、結構な確率で開発に行き詰ります。その時に状況を打破するためのアドバイスを一つ。
 libpngのフォルダ内にはpng導入用のテストコードやマニュアルが用意されています。それを順に追っていくことで、そもそもlibpngの開発者たちがどのように使うことを想定しているかを知ることができます。
 英語だから読めない?技術文書は文学作品と違い、形容詞の微妙なニュアンスがわからなくても理解することが可能です。
 プログラマーという人種は白黒つけるのが職業病みたいなもので、誤訳が少なくなるようにわかりづらい文法、一般的でない慣用句はほぼ使用されません。そのため、ネット翻訳や辞書を使えばそれなりの精度で訳してもくれます。
 文書を完全に訳せなくとも、開発者たちが何を言いたいのかわかるレベルさえあれば理解可能です。
 我々には言語や文化の差を埋めてくれるプログラム言語という共通言語があります。
 本質的に何が言いたいのかは、ソースコードに書いてあるのでそこから読み取ればいいだけです。

 さて、また脱線しましたがlibpngでは下記ファイルを基点に調査してみてください。


  • contrib/visupng - このフォルダのPngFile.cはWindowsの開発環境であればC&Pを行い、調整すればすぐに使えるzlib/libpngライセンスなソースコードが含まれています。VS使用者には取り付きやすいサンプルです。


  • example.c - 実装前にどのようなlibpngの使い方について学習するのに使えそうです。

  • pngtest.c - pngの読み込み・書き込みテスト用コード。コンパイル可能。

  • libpng-manual.txt - libpngのマニュアルテキスト。各関数がどのような動作をするのかを調べたいときに使用できそうです。


  • contrib - このフォルダ内にはサンプルソースコードが数点含まれています。デコーダー・エンコーダーの実装例等も含まれているので研究用に使えそうです。


pngファイルの読み込み実装


 pngの高レベル関数を使用した画像の読み込みはそれほど難しくありません。
 pngの読み込み処理の流れは最低限かつ簡単にまとめると、下記のようになります。


  • pngのシグネチャ比較(png_sig_cmp)

  • png読込構造体を生成(png_create_read_struct)

  • png情報構造体を生成(png_create_info_struct)

  • pngファイルのファイルからの読み込み(png_init_io)

  • pngファイルフォーマットへ読込済みデータを変換(png_read_png)

  • pngファイルの画像データ部分の抽出(png_get_rows)

  • png処理の後始末(png_read_end等)


 順番に実行していくだけであれば簡単に見えますね。
 この間にエラー時処理・画像用メモリ領域の確保・高さ、幅、深度の計算等を含めていく必要があります。



png_init_ioとpng_set_read_fnはどちらを使用すれば?


 ドキュメントを意訳すると下記のようになるはず。超意訳なのでこんな文章がどこに書いてあるのかとか探さないでください。
png_init_ioは「Stardard C」で実装されており、内部処理としてfreadで実装されています。
そのため、freadを使用できる環境であるのであれば、png_init_ioを使用することが可能です。
組み込み環境等特殊な実行環境である場合、png_set_read_fnを使用して、ファイルIO処理を行ってください。


 Windows + VisualStudioが実行環境であるならば、png_init_ioを使用すれば問題ないでしょう。
 何らかの手法で高速に読み出したい場合や特殊な機器構成により低レベルなファイルIO処理を利用しないといけない場合などはpng_set_read_fnを使用して呼ばれる関数内で読み込み処理を実装するといいでしょう。
 例えば、libpngの中に含まれているexample.cの中で「Progressively read a file」という実装について書かれており、この実装はpng_set_read_fnに指定した関数内でpngの読み込み状況の進捗度合を算出しています。巨大なpngファイルが対象となっている場合には便利な処理です。

 不明点等コメントいただければ可能であれば補足します。

以上

2012/02/02

TortoiseSVNで外部参照(svn:externals)を使用する方法

Mercurial(hg)のsubreposみたいなことをSVNでもできたんですね……
これがあれば別々のプロジェクトでも共有ライブラリが使用できるから管理が楽です。

外部参照(svn:externals)設定手順


前提条件としてtortoiseSVNは次のバージョンを使用しています。
また、言語は英語のまま使用しているので、ところどころ日本語に置き換えてください。
TortoiseSVN 1.6.16, Build 21511 - 32 Bit , 2011/06/01 19:00:35
Subversion 1.6.17, 
apr 1.3.12
apr-utils 1.3.12
neon 0.29.6
OpenSSL 1.0.0d 8 Feb 2011
zlib 1.2.5

取り込みたいディレクトリでSVNメニューからプロパティを選択。
新規プロパティに下記のように設定。

[Property Name]=[svn:externals]
[Property Value]=[dirname http://path/to/Repos]


※[]の記号は入力不要なので注意。

例として、下記のような構成で外部参照リポジトリを設定する。
[root]
  ├[ProjectX]
  ├[SubProjectY]
  └[SUbProjectZ]

ここではrootフォルダの直下に別プロジェクトで使用しているcommonlibリポジトリを設置したいとする。
まずは[root]ディレクトリ上でプロパティを下記のように設定する。
commonlib http://svnserver-xxxx/svn/ProjectA/trunk/commonlib

この状態でUpdateを行うとpath/to/reposで設定したリポジトリからチェックアウトしてきます。
[root]
  ├[ProjectX]
  ├[SubProjectY]
  ├[SubProjectZ]
  └[commonlib] (svn:externals = http://svnserver-xxxx/svn/ProjectA/trunk/commonlib)

この状態でrootディレクトリをコミットしてやれば以降はこのリポジトリをアクセスした人も外部参照先からcommonlibをリポジトリにUpdateします。

注意したいことは、この外部参照リポジトリを変更し、コミットしたら参照先リポジトリ分も更新されます。読み取り専用にしたいのであれば、commonlibに対して、新しく[svn:needs-lock]プロパティを設けて共通ライブラリの編集はロックを行わないとできない形に変更してしまう方法が考えられます。

もしくは該当リポジトリ側の書き込み制限をユーザー・グループ毎に区切って、そもそも権限がないと変更できないようにしてしまうかという形でしょう。

ローカルのワークに対して変更しないようにしたいだけであれば、フォルダのプロパティ自体を読み取り専用にして外部参照リポジトリ直下のフォルダを書き込み禁止にするといいかもしれない。.svnフォルダも書き込めなくなるかもしれないので注意。

本文を用いて外部参照リポジトリの設定して、わからないこと、躓いたこと等があればコメントしていただかえれば可能な限り補足使用と思います。

以上