こんにちわ。ネクストシステムの江原です!
最近は、仕事でHTML5+CSS3+javascriptで
iOS/Android向けWebアプリをメインでやってます。
Javascriptも面白いですね!!
今日は、UIViewの一部をUIImageとして取得する方法を調べたいと思います。
1) まずUIImageを作成する為作業する場所を確保します。
作業する場所はユーザに見えてはいけないので
オフスクリーン(見えない領域)に作成します。
CGSize size = CGSizeMake( rect.size.width , rect.size.height );
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
2) UIViewの切取り開始位置を左上にあわせます。
CGPoint point = rect.origin;
CGAffineTransform affineMoveLeftTop
= CGAffineTransformMakeTranslation(
-(int)point.x ,
-(int)point.y );
CGContextConcatCTM( context , affineMoveLeftTop );
3)左上にずらしたUIViewのイメージをオフスクリーンに貼付けます。
[(CALayer*)view.layer renderInContext:context];
UIImage *cnvImg = UIGraphicsGetImageFromCurrentImageContext
();
※ オフスクリーンのサイズを超える領域は削除される為
最初に用意した矩形サイズの画像が取得できます。
4)オフスクリーンの破棄をしておしまいです。
UIGraphicsEndImageContext();
以下参考のソースです。
/** UIViewの一部をUIImageとして取得
* @param view 対象のUIImage
* @param rect 切り出したい位置とサイズ
*
* @return 対象のUIImage
*/
-(UIImage *)makeUIImageFromUIView:(UIView *)view
withRect:(CGRect)rect
{
// オフスクリーン(見えない描画領域)を作成
CGSize size = CGSizeMake( rect.size.width , rect.size.height );
UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
// (補足:サイズ , NO:透過有 , 0.0:自動スケール です)
// オフスクリーン(見えない領域)描画よりグラフィックスコンテキスト取得
CGContextRef context = UIGraphicsGetCurrentContext();
// 切り取り開始位置に合わせ
// 左にpoint.x、上にpoint.y移動させるAffine変換を作成します。
CGPoint point = rect.origin;
CGAffineTransform affineMoveLeftTop
= CGAffineTransformMakeTranslation(
-(int)point.x ,
-(int)point.y );
// Affine変換を使用する為、コンテキストに設定
CGContextConcatCTM( context , affineMoveLeftTop );
// Viewの移動返還後のイメージをオフスクリーンに貼付けます。
// (※ オフスクリーンからはみ出た領域は削除されるようです。 )
[(CALayer*)view.layer renderInContext:context];
// オフスクリーンの内容をUIImageとして取り出します。
// (autoreleaseと思います)
UIImage *cnvImg = UIGraphicsGetImageFromCurrentImageContext();
// オフスクリーンを破棄します。
UIGraphicsEndImageContext();
return cnvImg;
}
毎日楽しく刺激的な日々で
こんな環境で仕事ができるチャンスがあることを本当に感謝しています。
このチャンスに甘えない様に
iOSのネイティブ開発とWeb開発の両方をこれからもがんばっていきたいと思います。
スポンサーサイト
Tasakiです。
昨夜CDMA2000版のiPhoneがついに発表されましたね。
生中継サイトがないか探してる間に速報が出ちゃったので、あまりライブで知り得た感覚がありませんでしたけども。
今回発表された端末がそのまま日本で(auから)出る可能性は、物理的に見てありえないそうですが、わざわざ単一キャリアのために特別仕様の端末(OSまでも)を用意する辺り、AppleとしてもこのままAndroidのシェア上昇を黙って見守るつもりはないのでしょうね。
個人的には、次世代iPhoneが半年以内にリリースされる可能性のある中で、どれくらい需要があるのかというのは興味があります。
さて、今回は前回までの応用編、というか用途についてです。
私の場合は、UIImagePickerControllerから得られた写真を表示するのに使用しました。
このときにパラメータで渡される画像は、高精細ディスプレイであってもscaleが1.0に設定されています。
これをなんとかしたかったというわけですね。
まあ、そんなに大きな画像ファイルをそのまま表示するのは間違ってるよってことかもしれませんが…
Tasakiです。
新年明けましておめでとうございます。
今年も当ブログをよろしくお願いいたします。
さて、年をまたいでしまいましたが、前回の続きと参りましょう。
単精度画像を倍精度画像として使用する。ということでしたが、これは厳密に言うと
できない 模様です。
どういうことかと言いますと、前回お話したUIImageのscaleプロパティなんですが、これはreadonlyに設定されており、参照は可能ですが変更することはできません。
じゃあどうするのかと言うと、ここでは少し発想を変えまして、一旦作成した単精度画像オブジェクトから倍精度画像を作成してしまうことにします。
例えば、UIImageに以下のようなメソッドを追加してみましょう。
このメソッドは、引数で渡された画像オブジェクトから、現在の画面解像度に応じたコンテキストを持つ画像オブジェクトを作成するものです。
+ ( id ) scaledImageWithImage:( UIImage* ) image {
CGFloat scale = [[ UIScreen mainScreen ] scale ];
CGSize size = image.size;
if( round( image.scale ) != round( scale )) {
CGSize newSize = CGSizeMake( size.width / scale, size.height / scale );
UIGraphicsBeginImageContextWithOptions( newSize, YES, scale );
[ image drawInRect: CGRectMake( 0.0, 0.0, newSize.width, newSize.height )];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return image;
}
上記コード中で肝になるのがこの関数です。
void UIGraphicsBeginImageContextWithOptions(
CGSize size,
BOOL opaque,
CGFloat scale
);
これは、画像コンテキストを作成する関数の1つで、iOS4.0で追加されたものです。
最後の引数scaleに2.0を渡せばRetina用のコンテキストを作成してくれます。
こうして作成したコンテキストに対して画像を描画し、それを内包した画像オブジェクトを取得する、というわけです。
厳密にはこの書き方だと問題があったりする場合もあるようですが、ひとまずこれで画面解像度に応じた画像オブジェクトを扱うことが可能になります。
当然ですが、こうするとRetinaの場合は画像オブジェクトのsizeは小さくなりますので、ご注意を。
Tasakiです。
前日と気温差10℃なんて日もめずらしくないこの頃、みなさんいかがお過ごしでしょうか。
久しぶりとなりましたが、今回は意外と厄介な問題のあるRetinaディスプレイ対応についてです。
公式ドキュメントにも記載されていますが、
アプリケーションにバンドルする画像は、
例えば通常解像度の画像 image.png があった場合、
image@2x.png という縦横倍精度の画像を準備し、
UIImage* image = [ UIImage imageNamed: @"image" ];
とすると、iPhone3G では、image.png が
iPhone4 では、image@2x.png が読み込まれるというのは、
ご存知の方がほとんどだと思います。
ただ、このメソッドではアプリケーションバンドルに含まれた画像でなければ
参照できないのが欠点です。
そこで、以下のメソッドを代わりに使用することで
フルパスを指定して上記と同様の結果を得ることができます。
- ( id ) initWithContentsOfFile:( NSString* ) path
+ ( id ) imageWithContentsOfFile:( NSString* ) path
これらは、4.0公開時点では上手く行かないようでしたが、
最新版では公式ドキュメントの記述通りの動きをします。
ここで、path には、単精度画像のパスを指定します。
すると倍精度画像が同一ディレクトリに存在すれば、
そちらが読み込まれるようになります。
現在の画像オブジェクトが倍精度画像として読み込まれているか調べるには、
scaleプロパティを使用します。
単精度画像なら1.0
倍精度画像なら2.0が値として取得できると思います。
1点注意が必要なのは、
sizeプロパティは単精度と倍精度で同じ値になることです。
元の画像サイズ = size * scale
という図式が成り立ちます。
ここまでは、まあ問題ないかと。
これを踏まえて次回は、
単精度画像を倍精度画像として使用する例をご紹介します。
そんな必要があるのかって?
そこそこあるんですね。そういう場合が。
ご無沙汰しておりました。Tasakiです。
ここ数ヶ月でハードの方はiPad, iPhone 4, ソフト(OS)の方はiOS3.2→4.0とAppleが怒濤の攻勢に出てきたりして、ついていくどころか、そろそろ先頭集団が見えなくなってきたところです。
さて、今回のテーマはスクリーンキャプチャの実装についてです。
OS3.1でカメラプレビュー画面が公に編集可能になり、生中継アプリが公開され始めた頃に公式フォーラムで使用が認められたのが、UIGetSceenImage()という非公開APIでした。
その後iPadに搭載された3.2では、UICreateScreenImage()という別の名前が与えられたようです。(未確認)
そして、iOS4が登場した訳ですが、カメラのプレビュー画像は公開APIとして正式に追加されたようです。
この辺りについては、おいおい解説していければと思いますが、肝心のスクリーンキャプチャがこれまでの非公開APIが利用不可になっているせいで実現できなくなっているではありませんか。
いろいろ調査をしていくうちにこちらのサイトを発見しました。
http://blog.livedoor.jp/tek_nishi/archives/2434530.htmlなるほど、オフラインレンダリングに以下のAPIを絡めればいいそうです。
- ( void ) renderInContext:( CGContextRef ) ctx
無事スクリーンキャプチャを実現することができました。
めでたし、めでたし。
…あれ?でもリファレンスによれば、このAPIって2.0以降で利用可能ってことになってるような…