Android實戰技巧之四十七:不用預覽拍照與圖片縮放剪裁

來源:互聯網
上載者:User

標籤:無預覽拍照   no-preview   take-photo   

副標題:Take Picture without preview Android

Google出於對隱私的保護,制定了一條門檻,即在Android應用開發中編寫拍照程式是必需要有映像預覽的。這會對那些惡意程式比如Android中泛濫的Service在後台偷偷記錄手機使用者的行為與周邊資訊。這樣的門檻還包括手機廠商內建的相機軟體在拍照時必須是有聲音,這樣要避免一些偷拍的情況。

處於技術調研與一些特殊無害情境的使用,我們要用到不用預覽的拍照。此文就是以此為背景,做的一些調研。只是用不多與五款手機測試,不保證所有的裝置都無問題。

免責聲明:本文純屬技術研究,請勿用於有害情境!方案

既然Google在技術上做出了特定要求,網友們想出各種workaround的方法,比如用一個空的SurfaceView或將此preview設成透明。
但這兩個辦法我都失敗了。而網友Sam給出的將preview設定成1x1大小的方案起了作用。下面的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處裁剪。
這還沒完,做完這些工作,我會將這三個bitmap存成三張圖片。注意在做bitmap的compress操作時,第二個參數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

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Android實戰技巧之四十七:不用預覽拍照與圖片縮放剪裁

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.