Android実戦テクニックの四十七:プレビューなしで写真と画像をズーム・カット
12426 ワード
副題:Take Picture without preview Android
Googleはプライバシー保護のため、Androidアプリケーション開発で写真プログラムを作成するには画像プレビューが必要だという敷居を設けた.これは、Androidに氾濫しているサービスなどの悪意のあるプログラムに対して、バックグラウンドで携帯電話ユーザーの行為や周辺情報をこっそり記録することになります.このような敷居には、携帯電話メーカーが持参したカメラソフトが含まれており、写真を撮るときに音がしなければならないため、盗撮を避けることができます.
技術調査といくつかの特殊な無害なシーンの使用にあり、プレビューを使わない写真を撮る必要があります.この文はこれを背景に、いくつかの調査研究をしています.ただ、5つの携帯電話でテストしないだけで、すべての設備が問題ないことを保証しません.
免責声明:本稿は技術研究に属し、有害なシーンには使用しないでください.
イニシアチブ
Googleが技術的に特定の要求をした以上、ネットユーザーたちは空のSurfaceViewを使ったり、このpreviewを透明にしたりするなど、さまざまなworkaroundの方法を考え出した.しかし、この2つの方法は私は失敗しました.ネットユーザーのSam氏が示したpreviewを1 x 1サイズに設定する案が役に立った.次のdemoは、インタフェースが非常に簡単で、ボタンが写真を撮るために使用され、onClickイベントメソッドはonTakePhotoClickedと呼ばれています.
もうほとんどいいです.pictureCallbackは写真を撮るのに成功した後のコールバックです.私たちはこのコールバックで画像データの処理をします.まず、ピクチャデータはバイト配列の形で返され、プロトタイプは以下の通りである.
Googleはプライバシー保護のため、Androidアプリケーション開発で写真プログラムを作成するには画像プレビューが必要だという敷居を設けた.これは、Androidに氾濫しているサービスなどの悪意のあるプログラムに対して、バックグラウンドで携帯電話ユーザーの行為や周辺情報をこっそり記録することになります.このような敷居には、携帯電話メーカーが持参したカメラソフトが含まれており、写真を撮るときに音がしなければならないため、盗撮を避けることができます.
技術調査といくつかの特殊な無害なシーンの使用にあり、プレビューを使わない写真を撮る必要があります.この文はこれを背景に、いくつかの調査研究をしています.ただ、5つの携帯電話でテストしないだけで、すべての設備が問題ないことを保証しません.
免責声明:本稿は技術研究に属し、有害なシーンには使用しないでください.
イニシアチブ
Googleが技術的に特定の要求をした以上、ネットユーザーたちは空のSurfaceViewを使ったり、このpreviewを透明にしたりするなど、さまざまなworkaroundの方法を考え出した.しかし、この2つの方法は私は失敗しました.ネットユーザーのSam氏が示したpreviewを1 x 1サイズに設定する案が役に立った.次のdemoは、インタフェースが非常に簡単で、ボタンが写真を撮るために使用され、onClickイベントメソッドはonTakePhotoClickedと呼ばれています.
public void onTakePhotoClicked(View view) {
final SurfaceView preview = new SurfaceView(this);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
@Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "Surface created");
Camera camera = null;
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Log.d(TAG, "Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
throw new RuntimeException(e);
}
camera.startPreview();
Log.d(TAG, "Started preview");
camera.takePicture(null, null, pictureCallback);
} catch (Exception e) {
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
});
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1, 1, //Must be at least 1x1
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
0,
//Don't know if this is a safe default
PixelFormat.UNKNOWN);
//Don't set the preview visibility to GONE or INVISIBLE
wm.addView(preview, params);
}
画像のズームと切り取りもうほとんどいいです.pictureCallbackは写真を撮るのに成功した後のコールバックです.私たちはこのコールバックで画像データの処理をします.まず、ピクチャデータはバイト配列の形で返され、プロトタイプは以下の通りである.
@Override
public void onPictureTaken(byte[] data, Camera camera) {}
配列をbitmapに変換するにはBitmapFactoryを使用します.decodeByteArrayメソッドでいいです.しかし、画像は左に逆さまに表示されていることに気づきます.焦らないでください.私たちはそれを正さなければなりません.ここでmatrixを使います.postRotateメソッドにBitmapを付ける.createBitmapは新しいbitmapを作成します.ズームについて話しましょうBitmapを参照してください.createScaledBitmapメソッドでよい.では、裁断は?新しいRectを作成します.bitmap全体に注意してください.例えば、プログラムでは元の図の1/4から切り取ります.これはまだ終わっていません.これらの仕事を終えたら、この3つのbitmapを3枚の画像に保存します.注意bitmapのcompress操作を行う場合、2番目のパラメータqualityは重要であり、画像の品質が高いほど、占有空間が大きくなる.はい、次はコードです.参考にしてください.private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken");
if(null == data){
return;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
camera.stopPreview();
Matrix matrix = new Matrix();
matrix.postRotate((float) 90.0);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
Log.d(TAG, "original bitmap width: " + bitmap.getWidth() +
" height: " + bitmap.getHeight());
Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
bitmap.getWidth()/3, bitmap.getHeight()/3, true);
Log.d(TAG,"size bitmap width "+sizeBitmap.getWidth()+" height "+sizeBitmap.getHeight());
// bitmap
int leftOffset = (int)(sizeBitmap.getWidth() * 0.25);
int topOffset = (int)(sizeBitmap.getHeight() * 0.25);
Rect rect = new Rect(leftOffset, topOffset, sizeBitmap.getWidth() - leftOffset,
sizeBitmap.getHeight() - topOffset);
Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap,
rect.left, rect.top, rect.width(), rect.height());
try {
FileOutputStream outputStream = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()+"/photoResize.jpg");
sizeBitmap.compress(Bitmap.CompressFormat.JPEG, 30, outputStream);
outputStream.close();
FileOutputStream outputStreamOriginal = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()+"/photoOriginal.jpg");
bitmap.compress(Bitmap.CompressFormat.JPEG, 20, outputStreamOriginal);
outputStreamOriginal.close();
FileOutputStream outputStreamCut = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()+"/photoCut.jpg");
rectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStreamCut);
outputStreamCut.close();
Log.d(TAG,"picture saved!");
} catch(Exception e) {
e.printStackTrace();
}
}
};
必要な権限: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
参照先:http://stackoverflow.com/questions/2386025/taking-picture-from-camera-without-preview