ホームページ開発ツール>Xojo Cocoa Plugin 覚書・応用編1・画像の回転

 Xojo Cocoa Plugin 覚書

応用編1・画像の回転

目次
 はじめに

 以前作ったMach-O対応版(Carbon版)と同等の機能を持つCocoa版についての話題です。
 今回は、画像の回転です。

 テスト環境は前回と同じく、以下の通りです。
 ・Mac mini mid 2010 (intel) / Mac OS X 10.9.4 / Xojo 2014 Release 2 / Xcode 5.1.1


 画像を回転するプラグインを作る(アルゴリズム編)

 Carbon版ではQuickDrawを使いましたが、Cocoa版ではCore Graphics(Quartz 2D)を使ってみました。
 Core Graphicsではマトリクスの操作ができますので、それを使って回転させます。(ちなみに、反転とかにも容易に応用が可能。)
 処理の流れは以下の通りです。
  1. 入力画像データを元に、CGImageRefを取得
  2. 空のコンテキスト生成(この時にrawデータ領域を組み込む)
  3. マトリクス演算により、コンテキストを回転
  4. コンテキストに画像を描画
  5. (コンテキスト生成時に組み込んだ)rawデータ(領域の中身)を、REALpicture形式に変換して返す
 ポイントは、コンテキスト生成時に指定するCGImageAlphaInfoとCGColorSpaceRefは、元々の入力データから取得することでしょうか。
(例えばCGColorSpaceRefに、一般的な「CGColorSpaceCreateDeviceRGB」とかを指定すると、色化けを起こす場合があります。)


 まずデバッグ用プロジェクトを作る

 プラグインの作成で最も困ることは、デバッグです。
 Xcode上でオンラインでデバッグすることができない(というか、単に知らないだけかも。もしオンラインでデバッグできる方法をご存知でしたらお知らせ頂けると嬉しいです。)ため、プラグインをビルドしてはXojoに組み込んで実行し、ダメならまたXcodeに戻って書き直す、という、効率の悪いことをしなければなりません。

 今回は、CGImageRefの取得後からrawデータの生成までは、プラグイン/デスクトップアプリケーションで共通化できるので、Cocoa Applicationプロジェクトを新規作成して、アプリケーション用コードでプラグイン用コードを挟み込んだものを作っておくと、デバッグ効率が大幅にアップします。(以下は抜粋。)
- (void)RotateImage:(NSInteger)mode {
	NSImage *testImage = [NSImage imageNamed:@"RB-66C.jpg"];  // テストに使う画像ファイルは予め組み込んでおく
	if ( ![testImage isValid] ) {
		NSLog(@"Image Not Found");
		return;
	}
	CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)[testImage TIFFRepresentation], NULL);
	CGImageRef image_ref =  CGImageSourceCreateImageAtIndex(source, 0, NULL);
	double pdWidth = 160, pdHeight = 131;  // 上で組み込んだ画像の幅と高さ
// ------------------------------------------------------ ここからプラグイン
	(省略)
// ------------------------------------------------------ ここまでプラグイン
	CGImageRef image_ref2 = CGBitmapContextCreateImage(context);
	NSSize size = NSMakeSize(ww, hh);
	NSImage *testImage2 = [[NSImage alloc] initWithCGImage:image_ref2 size:size];
	[imgWell setImage:testImage2];// WindowにImage Wellを配置して、描画している
	CGContextRelease(context);  // プラグインではreturn前にリリースするが、アプリケーションではここでリリース
}
注1)フルバージョンの実装部はこちら。ヘッダはこちら
注2)別途、ウィンドウ上にButton4個とImage Well1個を用意して接続する。また、サンプル画像も別途用意して、プロジェクトに追加しておく。


 画像を回転するプラグインを作る(実装編)

 アプリケーションによるテストが一段落したら、プラグイン固有の処理に切り替えます。

 プラグイン作成手順は前回と同じですので、そちらを参照して下さい。

 ソースコードはこちら
注1)入力のPictureは32bitカラーのみを想定しています。16bitカラー他も扱いたい場合は拡張が必要です。
注2)当初は、CGImageRelease()の前にCGColorSpaceRelease()を記述していたのですが、そうすると(連続10回位操作すると)エラーが発生してしまいます。調べてみたら、解放してはいけないとのことでしたので、削除しました。

 参考サイト(1):retainしていないものをreleaseしてはいけない - mTsurutaのiPhoneゲーム造りや思う事など

 動作テストする

  1. Xojoを起動する。
  2. Window1のプロパティに以下を追加。
    p1 As Picture
    p2 As Picture
    
  3. Window1にCanvasを2個置き、Paintイベントに以下を記述。(上段はCanvas1用、下段はCanvas2用)
    if p1<>nil then
      g.drawpicture p1,0,0,me.Width,me.Height,0,0,p1.Width,p1.Height
    end if
    
    if p2<>nil then
      g.drawpicture p2,0,0,me.Width,me.Height,0,0,p2.Width,p2.Height
    end if
    
  4. Window1にPushButtonとLabelを置き、PushButtonのActionイベントに以下を記述。
    Dim t1,t2 As Integer
    
    t1=Ticks
    p2=PluginModule1.RotateImage(p1,1)  // プラグイン。必要に応じて第2パラメータを2,3にするか、別ボタンを用意する。
    t2=Ticks
    Label1.Text=Str((t2-t1)/60)
    
    if p2<>nil then
      Canvas2.refresh
    else
      msgBox "err"
    end if
    
  5. Window1のopenイベントハンドラに以下を記述。
    Dim f As FolderItem
    
    f=GetFolderItem("hoge.jpg")  // あらかじめプロジェクトと同じフォルダ内に画像ファイルを用意
    if f<>nil and f.exists then
      p1=f.OpenAsPicture
      Canvas1.Refresh
    end if
    
  6. 実行する。(Canvas1に元画像が表示される)
  7. PushuButtonを押す。Canvas2に回転した画像が表示されればOK。
注)動作テストが目的なので、縦横比の維持は考えていません。
 性能も計ってみました。
 テストマシンはmac mini(Intel Core 2 Duo 2.4GHz, 4GB)
 テストデータはデジカメの画像で、2560x1920ピクセル、RGBカラーのjpegファイルです。

  90, 270度 0.35秒前後
  180度   0.12秒前後

で、まずまず実用範囲内かと思われます。


 おわりに

 90, 270度の処理時間は、(Carbon版と比較しても)もう少しなんとかならないか、という気もします、
 マトリクスを使わずに、(Carbon版でやったように)ピクセル単位のコピーもやってみて、比較してみるのもいいかもしれません。

 注)上述のサンプルはあくまで動作確認用で、配布を前提としたものではありません。(配布用とするにはいくつかの配慮が必要なようです。)


 お世話になったサイト

 貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)

 参考サイト(1):retainしていないものをreleaseしてはいけない - mTsurutaのiPhoneゲーム造りや思う事など


 更新履歴

 2014.08.26 新規作成


[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]