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.widthpreviewView.heightcameraBitmap.widthcameraBitmap.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ストアでチェックする
・価格:無料
・仕様:完全ローカル・通信なし
・広告:ファイル一覧下部のみ(写真・動画再生中はなし)


コメント