【Android】DrawingView 応用編:タッチ座標のズレを完全に補正する方法(CameraX)

Java / Android

Android の CameraX を使ってカメラプレビュー上に描画を重ねる場合、 PreviewView と DrawingView の座標がズレる問題 が頻繁に発生します。

本記事では、以下の問題をすべて解決します:

  • PreviewView の内部スケーリングによる座標ズレ
  • DrawingView のサイズとカメラ画像サイズの不一致
  • 合成時に赤丸がズレる
  • 2回目以降の保存で失敗する
  • DrawingView が PreviewView を隠してしまう

CameraX を使ったアプリで タッチ位置に正確に描画したい人向けの完全版ガイド です。

1. 座標ズレが起きる理由:PreviewView の内部スケーリング

CameraX の PreviewView は、端末の画面サイズに合わせて 内部で画像を拡大・縮小 します。

そのため:

  • DrawingView のタッチ座標(画面上の座標)
  • CameraX のプレビュー座標(内部の座標)

が一致しません。

✔ よくあるズレの例

  • タッチした位置より少し右上に赤丸が描画される
  • 合成した画像では赤丸が別の位置に保存される
  • 端末によってズレ量が変わる

2. DrawingView と CameraBitmap のサイズ不一致

CameraX の ImageProxy実際のカメラ画像サイズ(例:1920×1080) を返します。 しかし、DrawingView は 画面サイズ(例:1080×2400) で描画されます。

この差がズレの原因になります。

3. スケール補正の計算方法(完全版)

✔ 必要な値

  • previewView.width
  • previewView.height
  • cameraBitmap.width
  • cameraBitmap.height

✔ 補正式

java

float scaleX = (float) cameraBitmap.getWidth() / previewView.getWidth();
float scaleY = (float) cameraBitmap.getHeight() / previewView.getHeight();

✔ 補正後の座標

java

float correctedX = touchX * scaleX;
float correctedY = touchY * scaleY;

4. 補正済み DrawingView(完全版コード)

java

public class DrawingView extends View {

    private Paint paint;
    private List<PointF> points = new ArrayList<>();
    private float scaleX = 1f;
    private float scaleY = 1f;

    public DrawingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
    }

    public void setScale(float sx, float sy) {
        this.scaleX = sx;
        this.scaleY = sy;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (PointF p : points) {
            canvas.drawCircle(p.x, p.y, 20, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN ||
            event.getAction() == MotionEvent.ACTION_MOVE) {

            float correctedX = event.getX() * scaleX;
            float correctedY = event.getY() * scaleY;

            points.add(new PointF(correctedX, correctedY));
            invalidate();
            return true;
        }
        return false;
    }

    public void reset() {
        points.clear();
        invalidate();
    }
}

5. 合成時のズレを防ぐための保存処理(完全版)

java

private void saveImage(Bitmap cameraBitmap) {

    float scaleX = (float) cameraBitmap.getWidth() / previewView.getWidth();
    float scaleY = (float) cameraBitmap.getHeight() / previewView.getHeight();
    drawingView.setScale(scaleX, scaleY);

    Bitmap drawingBitmap = Bitmap.createBitmap(
            cameraBitmap.getWidth(),
            cameraBitmap.getHeight(),
            Bitmap.Config.ARGB_8888);

    Canvas drawingCanvas = new Canvas(drawingBitmap);
    drawingView.draw(drawingCanvas);

    Bitmap combinedBitmap = Bitmap.createBitmap(
            cameraBitmap.getWidth(),
            cameraBitmap.getHeight(),
            Bitmap.Config.ARGB_8888);

    Canvas combinedCanvas = new Canvas(combinedBitmap);
    combinedCanvas.drawBitmap(cameraBitmap, 0, 0, null);
    combinedCanvas.drawBitmap(drawingBitmap, 0, 0, null);

    drawingView.reset();
}

6. よくある失敗と対処

● タッチ位置がズレる

→ スケール補正を必ず入れる → PreviewView のサイズを正しく取得する

● 合成画像で赤丸がズレる

→ DrawingView の Bitmap を cameraBitmap と同じサイズにする

● 2回目以降の保存で失敗する

java

image.close();
drawingView.reset();

● DrawingView が PreviewView を隠す

xml

android:background="@android:color/transparent"

7. まとめ:DrawingView 応用編は CameraX の必須知識

CameraX を使うアプリでは、 PreviewView の内部スケーリングによる座標ズレ が必ず発生します。

本記事の内容を使えば:

  • タッチ位置が正確に描画される
  • 合成画像でもズレない
  • 端末依存のズレを防げる
  • 保存処理が安定する

あなたのカメラアプリの品質が大きく向上します。

8. これを利用したアプリ

【プライバシー保護】撮影と同時にデータを暗号化、写真閲覧アプリ。

撮影同時に暗号化: 毎日残したい写真(寝起き顔、体重計、体形、髪型)を撮影と同時にローカルに暗号化保存。閲覧機能も装備。

徹底したプライバシー保護: ファイルはローカル環境で暗号化・管理されます。クラウドに依存しません。

📥 広告 アプリ紹介「暗号化動画プレイヤー守」をPlayストアでチェックする

・価格:無料
・仕様:完全ローカル・通信なし
・広告:ファイル一覧下部のみ(写真・動画再生中はなし)

👉 Google Play ストアでダウンロード

▼ アプリのダウンロードはこちら(Google Playに移動します) Google Play で手に入れよう

コメント