2010-11-18 4 views
10

多くのUIImageViewsを持つUIViewがサブビューとして用意されています。アプリはiOS4で動作し、網膜ディスプレイ解像度の画像を使用します(つまり、画像はスケール= 2でロードされます)iOS 4のUIViewコンテンツを実際の画像サイズで保存する(つまり、保存するためのスケールコンテンツ)

私はUIViewの内容を保存したいと思います...しかし、実際の画像サイズ内部。私。ビューにはサイズ200x200、スケール2にはイメージがありますが、400x400のイメージとすべてのイメージを実際のサイズで保存します。

ここで最初に気になるのは、新しい画像コンテキストを作成し、scale = 1の内部にあるすべての画像を再度読み込むことです。これを行うにはもっとエレガントな方法があるのでしょうか?すでに完了しているので、すべてを再度読み込むためのメモリとプロセッサ時間の腰のように見える...

p.s.もし誰かが答えを持っていれば - コードは素晴らしいだろう。

答えて

25

レンダリング用の実装任意のUIViewをイメージ化する(網膜表示用にも機能する)。

helper.hファイル:

@interface UIView (Ext) 
- (UIImage*) renderToImage; 
@end 

とhelper.mファイルに実装所属:

#import <QuartzCore/QuartzCore.h> 

@implementation UIView (Ext) 
- (UIImage*) renderToImage 
{ 
    // IMPORTANT: using weak link on UIKit 
    if(UIGraphicsBeginImageContextWithOptions != NULL) 
    { 
    UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0); 
    } else { 
    UIGraphicsBeginImageContext(self.frame.size); 
    } 

    [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return image; 
} 

0.0スケールファクタです。ビットマップに適用する倍率。 0.0の値を指定すると、倍率はデバイスのメイン画面の倍率に設定されます。

QuartzCore.frameworkも、レイヤーオブジェクトのfunctionを呼び出すため、プロジェクトに配置する必要があります。

弱いリンクを有効にするには、左のナビゲータでプロジェクト項目をクリックし、プロジェクトターゲット→ビルドフェーズ→リンクバイナリをクリックし、UIKitフレームワークで「オプション」(弱い)タイプを選択します。ここ

は、UIColor、UIImage、NSArrayの、NSDictionaryのための同様の拡張子を持つlibraryある...

+0

'UIGraphicsBeginImageContextWithOptions'を使うことができるかどうかチェックする点は何ですか?下位互換性のためですか? – pixelfreak

+0

このソリューションには、renderInContextメソッド用のQuartzCoreフレームワークも必要です。 – arlomedia

+0

@pixelfreakこれは、UIGraphicsBeginImageContextWithOptionsがiOS 4 +でのみ利用可能であるためです。 – shannoga

0

新しいグラフィックスコンテキストを希望のサイズで作成し、CGAffineTransformを使って縮小し、ルートUIViewのルートレイヤーをレンダリングし、コンテキストを元のサイズと画像をレンダリング?私は保存するためにそのようなことを行ってきました

CGSize originalSize = myOriginalImage.size; //or whatever 

//create context 
UIGraphicsBeginImageContext(originalSize); 
CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(context); //1 original context 

// translate/flip the graphics context (for transforming from CG* coords to UI* coords 
CGContextTranslateCTM(context, 0, originalSize.height); 
CGContextScaleCTM(context, 1.0, -1.0); 

//original image 
CGContextDrawImage(context, CGRectMake(0,0,originalSize.width,originalSize.height), myOriginalImage.CGImage); 

CGContextRestoreGState(context);//1 restore to original for UIView render; 

//scaling 
CGFloat wratio = originalSize.width/self.view.frame.size.width; 
CGFloat hratio = originalSize.height/self.view.frame.size.height; 

//scale context to match view size 
CGContextSaveGState(context); //1 pre-scaled size 
CGContextScaleCTM(context, wratio, hratio); 

//render 
[self.view.layer renderInContext:context]; 

CGContextRestoreGState(context);//1 restore to pre-scaled size; 

UIImage *exportImage = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
+0

こんにちはスティーブンに二つの画像上のrenderInContextを呼び出す(すなわち、画素の1/4を使用して画像データ)を拡大または縮小したものグラフィックスは別の方法で動作しますか? –

+0

私はここで間違っている可能性があります。なぜなら私はQuartzのこの部分の詳細について少しばかげているからですが、上記のテストではスケーリングされたレンダリングではないことがわかりました。最初は、具体的に縮小されたビットマップ・コンテキストを作成し、再スケーリングし、ビットマップ・コンテキストを使用してレンダリングしましたが、結果は駄目でした(期待通りです)。しかしながら、上記の方法は、元のソースが合理的なサイズ/品質である限り、鮮明な画像を提供する。 –

+0

あとで、上記のコードでは、myOriginalImageがUIViewのポイントサイズ(網膜またはそれ以外)よりも大きいと仮定しています –

4

何かのように...網膜コンテンツのためにこれを試してみましたが、これはUIImageViewsに縮小されている大規模なイメージのために働くように思われていません(網膜ディスプレイ)でPNGファイルとしてMKMapViewからピン:MKPinAnnotationView: Are there more than three colors available?

ここでその網膜の定義を用いてUIViewtheView)の保存を実行する重要な部分の抽出は次のとおり

 
-(void) saveMyView:(UIView*)theView { 
    //The image where the view content is going to be saved. 
    UIImage* image = nil; 
    UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, 2.0); 
    [theView.layer renderInContext: UIGraphicsGetCurrentContext()]; 
    image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    NSData* imgData = UIImagePNGRepresentation(image); 
    NSString* targetPath = [NSString stringWithFormat:@"%@/%@", [self writablePath], @"thisismyview.png" ]; 
    [imgData writeToFile:targetPath atomically:YES]; 
}

-(NSString*) writablePath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; return documentsDirectory; }

+0

ちょっと+1 UIGraphicsBeginImageContextWithOptionsを言及して...ああ、すべてのマイナーなiOSのアップデートで出てくるような新しいランダム関数のトンが...ああ、私は疲れている:) –

+0

UIGraphicsBeginImageContextWithOptionsも私に新しいものです。もっと慎重に更新を見てください... –

+0

ヒントのおかげで! –

2

キーがUIGraphicsBeginImageContextWithOptions第3のパラメータは、画像が最終的に書き込まれる方法を決定スケール、ということですでる。

あなたは常に画面の現在の規模を取得するために、[[UIScreen mainScreen]スケール]を使用して、実際のピクセル寸法が必要な場合:あなたはiPhone4の上でスケール= 1.0を使用している場合、あなたは意志

UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);

を次元が点のの画像を取得し、その結果を実際のピクセル数から縮小します。イメージを640x960ディメンションに手作業で書き出す場合(例:ピクセルを最初のパラメータとして渡す)、実際には拡大縮小されたスケーリングされたイメージになり、見た目にはひどく見えます。

+1

ドキュメントによると、scale引数を0.0に設定することは[[UIScreen mainScreen] scale]に設定することと同じです。 – arlomedia

0

インポートQuartzCore(輸入、フェーズを構築し、メインプロジェクトをクリックして)、あなたはそれが追加必要があります:私のimageViewsはプロパティです

#import <QuartzCore/QuartzCore.h> 

あなたがない場合は、.selfを無視して、関数にimageViewsを渡しますパラメータとして、その後、私が間違っているが、その実際のレンダリング縮小持っていないなら、私を修正し、新しいUIGraphicsCurrentContext

- (UIImage *)saveImage 
{ 
    UIGraphicsBeginImageContextWithOptions(self.mainImage.bounds.size, NO, 0.0); 

    [self.backgroundImage.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    [self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()]; 

    UIImage *savedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return savedImage; 
} 
関連する問題