non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

mruby-mrmagickにMrmagick#formatsを追加した

こんばんは。次男と実家にちょっと前にきたと思ったら、今度は長男が発熱で保育園から呼び出され、そのまま実家に来ている@kjunichiです。

背景

自分自身がどの様な画像フォーマットに対応しているかの一覧を取得することで、 利用者に、別のImageMagickや、指定したオプションやライブラリをサポートしたものを 組み込んでくれ!といったAI的な動きが可能になり、ユーザーフレンドリーになれるのではないかと考え作業を始めた。 (RMagickが対応しているのにしてないからともいう)

思い出したことや学んだこと

  • mrbgemでC++のコードを呼び出す
  • C++での文字列連結
  • メッソッドにブロックが指定されているかを判定するには
  • ImageMagickでデフォルトでサポートされている画像形式に関して
  • Cでのmrubyのハッシュの作り方

mrbgemでC++のコードを呼び出す

C++側では「extern "C"」を付けて宣言しておく。一時期、この辺り、mrubyではC++の扱いが 変わって混乱があったと記憶しているが、今は、一般的なCとC++の連携方法で通用するようになったっぽい。

extern "C" mrb_value
mrb_mrmagick_formats(mrb_state *mrb, mrb_value self)

C側で

extern mrb_value
mrb_mrmagick_formats(mrb_state *mrb, mrb_value self);

とexternで受けて、以下の様に直接mrb_define_module_functionにC++側の関数を直接指定できる。

mrb_define_module_function(mrb, mrmagick_module, "capi_formats", mrb_mrmagick_formats, MRB_ARGS_NONE());

mrb_define_module_functionに登録するのにいったんCで関数をかます必要はない。

C++での文字列連結

最近のC++での文字列はホント便利。

#include <string>
using namespace std;

string str;

とstring型で変数strを宣言すれば、あとはメモリ領域の事など考えずに代入したり、つなげたり出来る。

str = "*";
if ( entry->isReadable() ) 
  str += "r"; 
else 
  str += "-"; 
if ( entry->isWritable() ) 
  str += "w"; 
else 
  str += "-"; 
if ( entry->isMultiFrame() ) 
  str += "+"; 
else 
  str += "-";

編集して出来たC++の文字列は以下の様にmrb_str_newにてmrubyの文字列に変換できる。

mrb_value val = mrb_str_new(mrb, str.c_str(), str.length());

メッソッドにブロックが指定されているかを判定するには

ブロックはそのメソッドの最後の引数でしか取れないという制限があった記憶があるが、 今回は、そもそもブロックがあれば、ブロックを受け取るだけなので、引数の順番は特に考慮する必要がなかった。 受け取る際には「&」を変数名の前につける事さえ忘れなければ、あとは特に気にするところは無い。 具体的には以下の様に記述。

def self.formats(&blk)
    #puts "formats"
    h = self.capi_formats
    if blk then
      h.each {|item|
        blk.call(item)
      }
    else 
      return h
    end
end

ImageMagickでデフォルトでサポートされている画像形式に関して

これは、テストを書く際に必要になった。

ImageMagick - File Formats

を読む限り、

は、ImageMagick単独でサポートされているようだった。

Webでよく使うJPEGPNGはライブラリを入れてる必要がある。

Cでのmrubyのハッシュの作り方

本家のRMagickで#formtsメソッドはハッシュを返すので、mruby-mrmagickもこれに合わせて、 ハッシュを返すようにした。

そのため、取得した対応フォーマットの文字列からハッシュを作成する方法を学んだ。

// ハッシュの用意
mrb_value table = mrb_hash_new(mrb);

// キー
string keystr = "key";
mrb_value key = mrb_str_new(mrb, keystr.c_str(), keystr.length());
// 値
mrb_value val = mrb_str_new(mrb, str.c_str(), str.length());

// キーと値をハッシュにセットする
mrb_hash_set(mrb, table, key, val);

課題

最初のフィールドがダミー。RMagickではネイティブブロブの対応有無のフィールドとなっているが、 Magick++ APIでどうやって取得するにか分からなかった。

あと、このことを英語でドキュメント化すること

関連記事

13年前の記事

8年前の記事

7年前の記事