个人总结之自定义拍照

喜欢而已 提交于 2019-12-03 01:27:45

这几天有个需求是需要在拍照的时候,截图选定框内的照片,如下,截取绿色框内的照片

  通常我们拍照 的话,都是直接调用系统的相机, 这样的话只能拍出整个屏幕的照片,不能达到我现在想要的效果,所以这时候我们需要重新来自定义个相机拍照

     首先这是主界面的布局,也就是拍照的界面

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <SurfaceView
            android:id="@+id/previewSV"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
        
        <com.example.partialphoto.DrawViewFrame
             android:id="@+id/drawIV"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"
            />
    </FrameLayout>
    

    <RelativeLayout 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ImageButton
            android:id="@+id/takephoto"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:background="#01000000"
            android:src="@drawable/btn_takepic"/>
    </RelativeLayout>
    
</FrameLayout>

    其次这是我程序的入口布局,为的就是拍照结束后,在ImageView上显示出来

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/iv_take"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拍照" />

    <ImageView
        android:layout_gravity="center"
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

 这是程序入口的代码,这里对图片做了些处理

package com.example.partialphoto;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class IntentTakePhoto extends Activity {

    private ImageView iv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_take);
        Button btn = (Button) findViewById(R.id.iv_take);
        iv = (ImageView) findViewById(R.id.iv);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(IntentTakePhoto.this,MainActivity.class);
//                Uri uriPath = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));
//                intent.putExtra("take", uriPath);
                startActivityForResult(intent, 1);
            }
        });
    
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);
        Uri uri = null;
        Bitmap bitmap;
            if(resultCode == 0&&requestCode == 1){
//                newUri = data.getData();
                if(null != data){
                    String path = data.getStringExtra("path");
                    uri = Uri.fromFile(new File(path));
                    
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Config.RGB_565;
                try {
                    bitmap = BitmapFactory.decodeStream(getContentResolver()
                            .openInputStream(uri), null, options);
                
                float width = bitmap.getWidth();
                float height = bitmap.getHeight();
                
                // 创建操作图片用的matrix对象
                Matrix matrix = new Matrix();
                // 计算宽高缩放率
                if (width > 600) {
                    float sacleFactor = 0;
                    if (width < height) {
                        matrix.postRotate(90);
                        sacleFactor = 600 / height;
                    } else {
                        sacleFactor = 600 / width;
                    }
                    matrix.postScale(sacleFactor, sacleFactor);
                    bitmap = Bitmap.createBitmap(bitmap, 0, 0, (int) width,
                            (int) height, matrix, true);
                    float newwidth = bitmap.getWidth();
                    float newheight = bitmap.getHeight();
                }   
                
                ByteArrayOutputStream baos = new ByteArrayOutputStream();  
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中  
                int opt = 100;  
                while ( baos.toByteArray().length / 1024>50) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩         
                    baos.reset();//重置baos即清空baos  
                    bitmap.compress(Bitmap.CompressFormat.JPEG, opt, baos);//这里压缩options%,把压缩后的数据存放到baos中  
                    opt -= 10;//每次都减少10  
                }  
                ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中  
                bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 ,然后再赋值给bitmap
                
                System.out.println("------回来了");

                iv.setImageBitmap(bitmap);
                Toast.makeText(IntentTakePhoto.this, "-------"+bitmap.getWidth(), 0).show();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            
    }
    }
    }
}

 然后这是拍照界面上的代码

package com.example.partialphoto;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.Toast;

public class MainActivity extends Activity implements Callback {

    private static final String tag="PartialPhoto";
    public static int frame = 0;
    private boolean isPreview = false;
    private SurfaceView mPreviewSV = null;
    private DrawViewFrame mDrawIV = null;
    private SurfaceHolder mySurfaceHolder = null;
    private ImageButton mPhotoImgBtn = null;
    private ImageButton btnAdd = null;
    private ImageButton btnMinus = null;
    private Camera myCamera = null;
    private Bitmap mBitmap = null;
    private AutoFocusCallback myAutoFocusCallback = null;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
        Window myWindow = this.getWindow();
        myWindow.setFlags(flag, flag);

        setContentView(R.layout.activity_rect_photo);

        mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);
        mPreviewSV.setZOrderOnTop(false);
        mySurfaceHolder = mPreviewSV.getHolder();
        mySurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
        mySurfaceHolder.addCallback(this);

        mDrawIV = (DrawViewFrame)findViewById(R.id.drawIV);
        mDrawIV.onDraw(new Canvas());
                     
        myAutoFocusCallback = new AutoFocusCallback() {
            public void onAutoFocus(boolean success, Camera camera) {
                // TODO Auto-generated method stub
                if(success)    //focus successfully
                    Log.i(tag, "myAutoFocusCallback: success...");
                else
                    Log.i(tag, "myAutoFocusCallback: failure");
            }
        };
        
        
        
        mPhotoImgBtn = (ImageButton)findViewById(R.id.takephoto);
        mPhotoImgBtn.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if(isPreview && myCamera!=null){
//                    myCamera.takePicture(null, null, myJpegCallback);  //without shutter sound
                    myCamera.takePicture(new ShutterCallback() {
                        @Override
                        public void onShutter() {
                            Toast.makeText(MainActivity.this,"myShutterCallback:onShutter..." , MODE_PRIVATE).show();
                        }
                    }, null, myJpegCallback);  //with shutter sound
                }
            }
        });
    }

    //three important callback functions of SurfaceHolder.Callback as follows:
    //surfaceChanged, surfaceCreated, surfaceDestroyed
    
    //This is called immediately after any structural changes have been made to the surface.
    public void surfaceChanged(SurfaceHolder holder, int format, int prevWidth,int prevHeight) {
        // TODO Auto-generated method stub        
        Toast.makeText(MainActivity.this, "surface改变了   了... ... ", 0).show();
        if(isPreview){
            myCamera.stopPreview();
        }
        if(null != myCamera){            
            Camera.Parameters myParam = myCamera.getParameters();
            myParam.setPictureFormat(ImageFormat.JPEG);   //set the stored picture format
            
            int width = mDrawIV.getWidth();
            int height = mDrawIV.getHeight();
            
            myParam.setPictureSize(width, height);
            
            //NOTE: 
            //set the size of preview interface
            if (getWindowManager().getDefaultDisplay().getRotation() == 0){
                myCamera.setDisplayOrientation(90); 
                myParam.setPreviewSize(prevHeight, prevWidth);  
            } 
            else   
                myParam.setPreviewSize(prevWidth, prevHeight);
            
            try
            {
                myCamera.setParameters(myParam);    
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            myCamera.startPreview();
            myCamera.autoFocus(myAutoFocusCallback);
            isPreview = true;
        }

    }

    
    
    //This is called immediately after the surface is first created.
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub    
        myCamera = Camera.open();
        try {
            myCamera.setPreviewDisplay(mySurfaceHolder);
        } 
        catch (IOException e) {
            // TODO Auto-generated catch block
            if(null != myCamera){
                myCamera.release();
                myCamera = null;
                //Writes a printable representation of this Throwable's stack trace
                e.printStackTrace();
            }
        }
    }

    

    //This is called immediately before a surface is being destroyed.
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        if(null != myCamera)
        {
            myCamera.setPreviewCallback(null); 
            myCamera.stopPreview(); 
            isPreview = false; 
            myCamera.release();
            myCamera = null;    
        }
    }
    
    //supply original image data from a photo capture
    PictureCallback myJpegCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            if(null != data){
                mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                myCamera.stopPreview();
                isPreview = false;
            }
            
            int width = mDrawIV.getWidth();
            int height = mDrawIV.getHeight();
            
            int point_dw = (int)(width/10);
            int point_dh = (int)(5*height/12-height*10/30);
            
            int rect_dw = width-2*point_dw;
            int rect_dh = height-2*point_dh;
            
//            Bitmap sizeBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
            mBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
            
            //NOTE: 
            //set the format of the picture of the interception
//            Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap, (int)width/30, (int)width/45,width-20*width/30, height-20*width/45);
            mBitmap = Bitmap.createBitmap(mBitmap, point_dw,point_dh,  rect_dw,rect_dh);
            
            myCamera.startPreview();
            isPreview = true;
        
          if(null != mBitmap) {
                String CurrentPhotoFile = "";
                CurrentPhotoFile = saveJpeg(mBitmap);   //save bitmap as a picture in sdcard
                
                Intent intent = new Intent();
                intent.putExtra("path", CurrentPhotoFile);
                setResult(0, intent);
                finish();
            }
        }
    };

    
    //save the picture
    public String saveJpeg(Bitmap bm){
        String jpegName = "";
        String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pp/";   //save directory
        File folder = new File(savePath);
        if(!folder.exists())
            folder.mkdir();
        
        long dataTake = System.currentTimeMillis();
        jpegName = savePath + dataTake +".jpg";
        
        try {
            FileOutputStream fout = new FileOutputStream(jpegName);
            BufferedOutputStream bos = new BufferedOutputStream(fout);

            bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
            bos.close();
            Log.i(tag, "saveJpeg锛歴torage completed!");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.i(tag, "saveJpeg: storage failed!");
            e.printStackTrace();
        }
        
        return jpegName;
    }

}

最后这是自定义指定框的类

package com.example.partialphoto;

import android.app.Activity;
import android.content.Context;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Paint.Style;  
import android.graphics.Rect;  
import android.util.AttributeSet;  
import android.util.DisplayMetrics;
import android.widget.ImageView; 
  
public class DrawViewFrame extends ImageView{  
    public DrawViewFrame(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        // TODO Auto-generated constructor stub  
    }  
      
    Paint paint1 = new Paint();  
    {  
        paint1.setAntiAlias(true);  
        paint1.setColor(Color.GREEN);  
        paint1.setStyle(Style.STROKE);  
        paint1.setStrokeWidth(8f);
        paint1.setAlpha(100);  
    };  
    
    Paint paint2 = new Paint();  
    {  
        paint2.setAntiAlias(true);  
        paint2.setColor(Color.BLACK);  
        paint2.setStyle(Style.FILL); 
        paint2.setAlpha(150);  
    }; 
    
    protected void onDraw(Canvas canvas) {  
        // TODO Auto-generated method stub  
        super.onDraw(canvas);  
        DisplayMetrics dm = new DisplayMetrics();
        ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width = dm.widthPixels;
        int height = dm.heightPixels;
        
        int point_dw1 = (int)(width/10);
        int point_dh1 = (int)(5*height/12-height*10/30);
        //int point_dh1 = (int)(height/3);
        
        int point_dw2 = width-point_dw1;
        int point_dh2 = height-point_dh1;
        
        //draw a rectangle around viewing frame
        canvas.drawRect(new Rect(point_dw1, point_dh1, point_dw2, point_dh2), paint1);
//        canvas.drawRect(new Rect((int)width/30,(int)width/45,(int)11*height/7,(int)19*height/20), paint1);
        
        //这里是框外 阴影部分
        canvas.drawRect(new Rect(0, 0, point_dw1, height), paint2);
        canvas.drawRect(new Rect(point_dw2, 0, width, height), paint2);
        canvas.drawRect(new Rect(point_dw1, 0, point_dw2, point_dh1), paint2);
        canvas.drawRect(new Rect(point_dw1, point_dh2, point_dw2, height), paint2); 
    }  
}

 

 值得说一下:起初我用的是Intent直接传递的Bimap对象,但是试了几次,有时候成功,有时候不成功(onActivityResult方法执行不到),后来百度半天才知道,原来用Intent传递Bitmap对象很吃力,因为他只能传递小于40k的Bitmap,超过的就不行了,所以最后选择传递Bitmap的保存路径,然后再根据传递的String路径,通过Uri.fronFile()转化成Uri,然后通过BitmapFactory.decodeStream(getContentResolver.openInputStream(uri),null,options)来转化成bitmap


补充一下,有时候拍照的话,会很模糊, 原因是聚焦可能失败,所以可以添加下面的方法,调用surfaceview的touch事件

mPreviewSV.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                myCamera.autoFocus(myAutoFocusCallback);
                System.out.println("点击聚焦");
                return false;
            }
        });


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!