5

だから私は線を描くことができる基本的な描画アプリをプロセスに持っています. オフスクリーン ビットマップに描画し、そのイメージを で表示しdrawRectます。動作しますが、遅すぎて、指で描いてから約 0.5 秒後に更新されます。私はコードを取得し、このチュートリアルhttp://www.youtube.com/watch?v=UfWeMIL-Nu8&feature=relmfuから適応させ ました。コメントでわかるように、人々は遅すぎると言っていますが、男は持っていませんと答えました。

では、どうすれば高速化できますか?またはそれを行うより良い方法はありますか?任意のポインタをいただければ幸いです。

私のコードはこちらDrawView.mです。

-(id)initWithCoder:(NSCoder *)aDecoder {
     if ((self=[super initWithCoder:aDecoder])) {
         [self setUpBuffer];
     }

     return self;
}

-(void)setUpBuffer {
     CGContextRelease(offscreenBuffer);

     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

     offscreenBuffer = CGBitmapContextCreate(NULL, self.bounds.size.width, self.bounds.size.height, 8, self.bounds.size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
     CGColorSpaceRelease(colorSpace);

     CGContextTranslateCTM(offscreenBuffer, 0, self.bounds.size.height);
     CGContextScaleCTM(offscreenBuffer, 1.0, -1.0);
}


-(void)drawToBuffer:(CGPoint)coordA :(CGPoint)coordB :(UIColor *)penColor :(int)thickness {

     CGContextBeginPath(offscreenBuffer);
     CGContextMoveToPoint(offscreenBuffer, coordA.x,coordA.y);
     CGContextAddLineToPoint(offscreenBuffer, coordB.x,coordB.y);
     CGContextSetLineWidth(offscreenBuffer, thickness);
     CGContextSetLineCap(offscreenBuffer, kCGLineCapRound);
     CGContextSetStrokeColorWithColor(offscreenBuffer, [penColor CGColor]);
     CGContextStrokePath(offscreenBuffer);

}

- (void)drawRect:(CGRect)rect {
    CGImageRef cgImage = CGBitmapContextCreateImage(offscreenBuffer);
    UIImage *image =[[UIImage alloc] initWithCGImage:cgImage];
    CGImageRelease(cgImage);
    [image drawInRect:self.bounds];

}

シミュレータでは完全に動作しますが、デバイスでは動作しません。これはプロセッサの速度に関係していると思います。

ARCを使用しています。

4

7 に答える 7

7

私はあなたのコードを修正しようとしましたが、半分しか投稿していないように見えるので、動作させることができませんでした (コードをコピーして貼り付けると、多くのエラーが発生し、パフォーマンス チューニングを開始することはできません)。

ただし、パフォーマンスを大幅に向上させるために使用できるヒントがいくつかあります。

最初の、そしておそらく最も目立つのは、-setNeedsDisplayInRect: ではなく、-setNeedsDisplay です。これは、変更された小さな四角形のみを再描画することを意味します。1024*768*4 ピクセルの iPad 3 の場合、これは大変な作業です。これをフレームごとに約 20*20 以下に減らすと、パフォーマンスが大幅に向上します。

CGRect rect;
rect.origin.x = minimum(coordA.x, coordB.x) - (thickness * 0.5);
rect.size.width = (maximum(coordA.x, coordB.x) + (thickness * 0.5)) - rect.origin.x;
rect.origin.y = minimum(coordA.y, coordB.y) - (thickness * 0.5);
rect.size.height = (maximum(coordA.y, coordB.y) + (thickness * 0.5)) - rect.origin.y;
[self setNeedsDisplayInRect:rect];

もう 1 つの大きな改善点は、この現在のタッチの CGPath のみを描画することです (これを行います)。ただし、その保存/キャッシュされた画像を描画四角形に描画します。繰り返しになりますが、フレームごとに再描画されます。より良いアプローチは、描画ビューを透明にし、その背後で UIImageView を使用することです。UIImageView は、iOS で画像を表示する最良の方法です。

- DrawView (1 finger)
   -drawRect:
- BackgroundView (the image of the old touches)
   -self.image

描画ビュー自体は、現在のタッチのみを描画し、毎回変化する部分のみを描画します。ユーザーが指を離すと、それを UIImage にキャッシュし、それを現在の背景/キャッシュ UIImageView の画像の上に描画し、imageView.image を新しい画像に設定できます。

画像を結合するときの最後のビットでは、2 つのフルスクリーン画像をオフスクリーン CGContext に描画する必要があるため、メイン スレッドで実行すると遅延が発生します。代わりに、これをバックグラウンド スレッドで実行してから、結果をメイン スレッドにプッシュする必要があります。

* touch starts *
- DrawView : draw current touch
* touch ends *
- 'background thread' : combine backgroundView.image and DrawView.drawRect
    * thread finished *
    send resulting UIImage to main queue and set backgroundView.image to it;
    Clear DrawView's current path that is now in the cache;

これらすべてを組み合わせると、非常にスムーズな 60fps 描画アプリを作成できます。ただし、ビューは期待どおりに更新されないため、図を高速に移動すると描画がギザギザに見えます。これは、CGPath の代わりに UIBezierPath を使用することで改善できます。

CGPoint lastPoint = [touch previousLocationInView:self];
CGPoint mid = midPoint(currentPoint, lastPoint);
-[UIBezierPath addQuadCurveToPoint:mid controlPoint:lastPoint];
于 2012-07-07T13:50:57.297 に答える
5

遅い理由は、すべてのフレームでビットマップを作成し、それを描画しようとしているためです。

あなたはそれを行うためのより良い方法を求めましたか? iOS の描画アプリのアップル サンプル コードを見たことがありますか? それが気に入らない場合は、CCRenderTexture クラス (およびサンプル コード) を提供する cocos2d をいつでも使用できます

現在、効率的でないことがすでにわかっている方法を使用しています。

于 2012-07-02T08:41:47.813 に答える
2

このアプローチでは、画像レンダリングのすべてのハードワークにバックグラウンド スレッドを使用し、UI の更新のみにメイン スレッドを使用することを検討する必要があると思います。

__block UIImage *__imageBuffer = nil;

- (UIImage *)drawSomeImage
{
    UIGraphicsBeginImageContext(self.bounds);

    // draw image with CoreGraphics

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

- (void)updateUI
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // prepare image on background thread

        __imageBuffer = [self drawSomeImage];

        dispatch_async(dispatch_get_main_queue(), ^{

            // calling drawRect with prepared image

            [self setNeedsDisplay];

        });
    });
}

- (void)drawRect
{
    // draw image buffer on current context

    [__imageBuffer drawInRect:self.bounds];
}

最適化をより明確にするために、いくつかの詳細を省略しています。に切り替えるとなお良いUIImageView。このようにして、非常に重要なメソッドを取り除き、イメージの準備ができたときに- (void)drawDectイメージ プロパティを更新できます。UIImageView

于 2012-07-03T22:41:26.863 に答える
1

ロジックを変更する必要があると思います。このリンクhttp://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/の助けを借りて、非常に良いアイデアを得ることができ ます。理解する時間がないと思う場合は、このコードに直接アクセスできます https://github.com/levinunnink/Smooth-Line-View :) これが大いに役立つことを願っています。

于 2012-07-04T09:55:21.847 に答える
0

指を動かすたびに画像を作成するのは不適切であるため、提案した方法はどれも非効率的です。

描画する必要があるパスだけの場合はCGMutablePathref、メンバー変数として a を持ち、draw rect でCGPath関数を使用して指定されたポイントに移動します。

さらに重要なことは、ビューを更新しながら、setNeedsDisplayInRect描画する必要がある領域のみを呼び出すことです。それがあなたのために働くことを願っています。

于 2012-07-05T19:08:00.620 に答える
0

私はまさにこのようなことをしました。AppStore で Pixelate アプリをチェックしてください。を描画するために、コードでタイルを使用しました。結局のところ、画面をタッチして何かを描画すると、画像全体を再描画する必要があり、これは非常に重い操作です。Pixelate の動きが気に入った場合は、次のようにします。

1) 画像を nxm タイルに分割します。これは、これらの値を変更して、より大きな/より小さなタイルを取得できるようにするためです。最悪のシナリオ (ユーザーが 4 つのタイルの交差点をタップした場合) では、それらの 4 つのタイルを再描画する必要があります。全体像ではありません。

2) 各タイルのピクセル情報を格納する 3 次元マトリックスを作成します。最初のタイルの最初のピクセルの赤の値 ( pngmatrix[0][0][0]を使用しているか jpg を使用しているかに応じて、各ピクセルには RGB または RGBA 値があります) も同様です。

3) ユーザーが押した位置を取得し、変更が必要なタイルを計算します。

4) マトリックスの値を変更し、更新が必要なタイルを更新します。

注: これは間違いなく最適なオプションではありません。それは単なる代替手段です。私はそれがあなたが今持っているものに近いと思うので、それについて言及しました. iPhone 3GS でも動作しました。>= iPhone 4 をターゲットにしている場合は、問題ありません。

よろしく、

ジョージ

于 2012-07-06T07:52:28.830 に答える
0

CgLayer を使用してパスをキャッシュし、ドキュメントを読み、最適化に最適です。

于 2012-07-05T13:37:43.400 に答える