0

画像の上にグラフィックを描画し、リアルタイムでグラフィックを変更しながら、画像の上に描画された画像の同じ場所にグラフィックを置いたまま、画像を拡大縮小できるAndroidアプリを作成しようとしています。 。

しかし、画像の中心を維持しながら実際にズームインするのに多くの問題がありました。画像を更新するスレッドがあるコードを作成しました。更新は、ArrayBlockingQueueを介して「PendingUpdate」と呼ばれる私が作成したクラスを使用して渡されます。このアップデートには、キャンバスピクセルと画像中心に対する画像ピクセルの比率であると想定される目的のズームレベルが含まれています。ただし、次のコードは、ズーム中にパンするため、混乱します。

//Scale the image
canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom());

//Translate the image
double updateCx = pendingUpdate.getCenter().getX();
double updateCy = pendingUpdate.getCenter().getY();
double halfCanvasWidthInImagePixels = pendingUpdate.getZoom()*(canvas.getWidth()/2);
double halfCanvasHeightInImagePixels = pendingUpdate.getZoom()*(canvas.getHeight()/2);
double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
canvas.translate(-(float)imageTranslateX, -(float)imageTranslateY);
canvas.drawBitmap(pendingUpdate.getImage(), matrix, new Paint());

お手伝いありがとう!

編集:これが完全な機能です。これが役立つ場合は、PendingUpdateを投稿することもできますが、これは単なるデータクラスです。

    private void doDraw(Canvas canvas, PendingUpdate pendingUpdate) {
        int iWidth = pendingUpdate.getImage().getWidth();
        int iHeight = pendingUpdate.getImage().getHeight();
        Matrix matrix = new Matrix();

        canvas.drawColor(Color.BLACK);
        //TODO: add scrolling functionality to this
        if(pendingUpdate.getZoom()>0) {

            //Scale the image
            canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom());

            //Translate the image
            double updateCx = pendingUpdate.getCenter().getX();
            double updateCy = pendingUpdate.getCenter().getY();
            double halfCanvasWidthInImagePixels = pendingUpdate.getZoom()*(canvas.getWidth()/2);
            double halfCanvasHeightInImagePixels = pendingUpdate.getZoom()*(canvas.getHeight()/2);
            double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
            double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
            canvas.translate(-(float)imageTranslateX, -(float)imageTranslateY);
            canvas.drawBitmap(pendingUpdate.getImage(), matrix, new Paint());

        }else {
            //matrix.postTranslate(canvas.getWidth()-iWidth/2, canvas.getWidth()-iHeight/2);
            canvas.drawBitmap(pendingUpdate.getImage(),
                    (canvas.getWidth()-iWidth)/2,
                    (canvas.getHeight()-iHeight)/2, null);
        }
        //TODO: draw other stuff on canvas here such as current location

    }

編集2:これは私が最終的にそれを機能させる方法でした、それはそれを翻訳する前にそれを単にスケーリングすることの問題でした。

    private void doDraw(Canvas canvas, PendingUpdate pendingUpdate) {
        int iWidth = pendingUpdate.getImage().getWidth();
        int iHeight = pendingUpdate.getImage().getHeight();

        canvas.drawColor(Color.BLACK);
        //TODO: add scrolling functionality to this
        if(pendingUpdate.getZoom()>0) {

            //Scale the image
            canvas.save();
            double updateCx = pendingUpdate.getCenter().getX();
            double updateCy = pendingUpdate.getCenter().getY();
            double halfCanvasWidthInImagePixels = (canvas.getWidth()/2);
            double halfCanvasHeightInImagePixels = (canvas.getHeight()/2);
            double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
            double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
            //canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom(), (float)pendingUpdate.getCenter().getX(), (float)pendingUpdate.getCenter().getY());

            canvas.scale(pendingUpdate.getZoom(),
                    pendingUpdate.getZoom(),
                    canvas.getWidth()/2,
                    canvas.getHeight()/2);

            canvas.translate(-(float)imageTranslateX,
                    -(float)imageTranslateY);
            canvas.drawBitmap(pendingUpdate.getImage(), 0, 0, null);

            canvas.restore();
        }else {
            //TODO: update this so it displays image scaled to screen and updates current zoom somehow
            canvas.drawBitmap(pendingUpdate.getImage(),
                    (canvas.getWidth()-iWidth)/2,
                    (canvas.getHeight()-iHeight)/2, null);
        }
        //TODO: draw other stuff on canvas here such as current location    
    }
}
4

1 に答える 1

1

もし私があなたなら、あなたがCanvas.scale(float sx, float sy, float px, float py)望むことを正確に行う方法を使うでしょう。

ただし、コードを見ると、一度に多くの変換をいじっている可能性があり、デバッグが困難です。

  1. 常に(そして私は常に)呼び出しCanvas.save()て、それを変更することを計画している場合Canvas.restore()は、最初のマトリックスで取得します。Canvasこれは、Canvas描画できるのが、現在描画しているコントロールの境界にクリッピングが設定されたウィンドウ全体などのキャンバスである可能性があるためです。

  2. メソッドによって提供される行列変換メソッドCanvasを使用し、最も単純な呼び出しを使用してビットマップを描画します。

これらの2つのアドバイスに従って、View私が作成したばかりの全体を見てください。これは、ポイントをピボットとして設定しbitmapた係数でスケーリングします(変更されていないポイント-スケーリングの中心)。テスト済み-動作中。3(16,16)

public class DrawingView extends View {
    Bitmap bitmap;

    public DrawingView(Context context) {
        super(context);
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        float sx = 3;
        float sy = 3;
        float px = 16;
        float py = 16;
        canvas.save();
        canvas.scale(sx, sy, px, py);
        canvas.drawBitmap(bitmap, 0, 0, null);
        canvas.restore();
    }
}
于 2013-02-03T23:45:31.030 に答える