android:拍照,相册剪裁的实现方式

     一,仅拍照

    首先先给大家看效果图:





   点击拍照,拍照完成然后把照片显示在ImageView中:


   1,拍照功能需要首先在AndroidManifest.xml添加SD卡读写权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  2, 在给大家看一下主布局中的代码:

   

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

    <Button
        android:id="@+id/btn_ok"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="只是拍照"
        android:textSize="30px" />

    <ImageView
        android:id="@+id/image_result"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

  3,接下来看一下Acticity中的代码:

大家应该都可以看懂,其中imageUri  使用来保存拍完照片后存储的数据:

private static final int RESULT_CAMERA_ONLY = 0;
private Button btn_ok;
private ImageView mImage;
private Uri imageUri;
   4,接下来再看OnCreate()中的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String path = getSDCardPath();
    File file = new File(path + "/image.jpg");
    imageUri = Uri.fromFile(file);
    mImage = (ImageView) findViewById(R.id.image_result);
    btn_ok = (Button) findViewById(R.id.btn_ok);
    btn_ok.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Photograph();
        }
    });
}
    这里面做做了两部分:

  1 .初始化了控件

   可能大家下面这块代码看不太明白

	imageUri = Uri.fromFile(file);
    其中的getSDCardPath();是自己写的函数,接下来会给出代码:

     先构造一个image.jpg的URI

	File file = new File(path + "/image.jpg");

/**
 * 其中的获取SD卡路径的代码为:
 *
 * @return
 */
public static String getSDCardPath() {
    String cmd = "cat /proc/mounts";
    Runtime run = Runtime.getRuntime();// 返回与当前 Java 应用程序相关的运行时对象
    try {
        Process p = run.exec(cmd);// 启动另一个进程来执行命令
        BufferedInputStream in = new BufferedInputStream(p.getInputStream());
        BufferedReader inBr = new BufferedReader(new InputStreamReader(in));

        String lineStr;
        while ((lineStr = inBr.readLine()) != null) {
            // 获得命令执行后在控制台的输出信息
            if (lineStr.contains("sdcard")
                    && lineStr.contains(".android_secure")) {
                String[] strArray = lineStr.split(" ");
                if (strArray != null && strArray.length >= 5) {
                    String result = strArray[1].replace("/.android_secure",
                            "");
                    return result;
                }
            }
            // 检查命令是否执行失败。
            if (p.waitFor() != 0 && p.exitValue() == 1) {
                // p.exitValue()==0表示正常结束,1:非正常结束
            }
        }
        inBr.close();
        in.close();
    } catch (Exception e) {

        return Environment.getExternalStorageDirectory().getPath();
    }

    return Environment.getExternalStorageDirectory().getPath();
}
  5.接下来会调用手机照相功能,首先先给大家扩充一下知识:

    

Exta Options Table for image/* crop:

附加选项数据类型描述
cropString发送裁剪信号
aspectXintX方向上的比例
aspectYintY方向上的比例
outputXint裁剪区的宽
outputYint裁剪区的高
scaleboolean是否保留比例
return-databoolean是否将数据保留在Bitmap中返回
dataParcelable相应的Bitmap数据
circleCropString圆形裁剪区域?
MediaStore.EXTRA_OUTPUT ("output")URI将URI指向相应的file:///...,详见代码示例
outputFormatString输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString()
noFaceDetectionboolean是否取消人脸识别功能

  这里的参数可以选择性的使用;

  在这里我们要使用把return-data 这个键始终设置为false;因为你如果将它设置为true的话,它会把始终拍到的照片显示出来为缩列图,上面的这些代码就是用到哪些功能,自己添加就好了,调起拍照就需要用到上面这些功能,接下来就给大家看~

/**
 * 点击按钮时调起拍照Intent,将结果存在imageUri中
 */
private void Photograph() {
    Intent intent = null;
    intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture
    intent.putExtra("return-data", false); //是否将数据保留在Bitmap中返回
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将URI指向相应的file:
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//输出格式,一般设为Bitmap格式
    intent.putExtra("noFaceDetection", true);//是否取消人脸识别功能
    startActivityForResult(intent, RESULT_CAMERA_ONLY);
}
      Intent传值就不给大家讲了,因为这个比较简单

     调用照片功能就通过上面这些代码调起,代码中的备注也已经写好了。

 6.拍完照片以后然后再对返回的数据进行处理。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK)
        return;
    switch (requestCode) {
        case RESULT_CAMERA_ONLY: {
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                mImage.setImageBitmap(bitmap);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        break;

    }
}
    这样的话有时候会报出OOM。  说到这里,其实我是想给大家截图一下报的OOM的代码,可惜我用真机在此测试的时候神奇的它居然不报OOM(尴尬).

    这里出来OOM 我也是百度了一下:Android拍照,内存溢出OutOfMemory问题。


   接下来再说一下加载位图原理分析。

1、BitmapFactory提供了几种解码方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便从多种资源中创建一个Bitmap(位图)对象。可以根据你的图片数据来源选择最合适的解码方式。这些方法视图为构造Bitmap对象分配内存,因此很容易导致OutOfMemory(OOM)异常。每一种解码方式都有额外的特征,你可以通过BitmapFactory.Options类类指定解码方法。
2、尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource直接使用图片路径来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再调用上述方法将其设为ImageView的 source。decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。下面是使用InputStream加载图片的几种方法:
方法一、加载资源文件中指定的图片
InputStream is = getResources().openRawResource(R.drawable.temp);
方法二、加载assest目录下的图片
AssetManager asm=getAssetMg();
InputStream is=asm.open(name);//name:图片的名称
方法三、加载SD卡目录下的图片
String path =Environment.getExternalStorageDirectory().toString()+ "/DCIM/device.png";
inputStream is = new FileInputStream(path)
七、解决方案
private ImageView preview;
//1.加载位图
String path = Environment.getExternalStorageDirectory().toString()+"/DCIM/device.png";
inputStream is = new FileInputStream(path)
//2.为位图设置100K的缓存
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inTempStorage = new byte[100 * 1024];
//3.设置位图颜色显示优化方式
//ALPHA_8:每个像素占用1byte内存(8位)
//ARGB_4444:每个像素占用2byte内存(16位)
//ARGB_8888:每个像素占用4byte内存(32位)
//RGB_565:每个像素占用2byte内存(16位)
//Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存//也最大。也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题:3200*2400*4 bytes //=30M。如此惊人的数字!哪怕生命周期超不过10s,Android也不会答应的。
opts.inPreferredConfig = Bitmap.Config.RGB_565;
//4.设置图片可以被回收,创建Bitmap用于存储Pixel的内存空间在系统内存不足时可以被回收
opts.inPurgeable = true;
//5.设置位图缩放比例
//width,hight设为原来的四分一(该参数请使用2的整数倍),这也减小了位图占用的内存大小;例如,一张//分辨率为2048*1536px的图像使用inSampleSize值为4的设置来解码,产生的Bitmap大小约为//512*384px。相较于完整图片占用12M的内存,这种方式只需0.75M内存(假设Bitmap配置为//ARGB_8888)。
opts.inSampleSize = 4;
//6.设置解码位图的尺寸信息
opts.inInputShareable = true; 
//7.解码位图
Bitmap btp =BitmapFactory.decodeStream(is,null, opts);    
//8.显示位图
preview.setImageBitmap(bitmap);


    这里我是通过上述解释解决了位图OOM问题的。然后接下来再给大家看一下我修改后的代码:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK)
        return;
    switch (requestCode) {
        case RESULT_CAMERA_ONLY: {
            try {
                BitmapFactory.Options opts = new BitmapFactory.Options();
                opts.inTempStorage = new byte[100 * 1024];
                opts.inPreferredConfig = Bitmap.Config.RGB_565;
                opts.inPurgeable = true;
                opts.inSampleSize = 4;
                opts.inInputShareable = true;
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri), null, opts);
                mImage.setImageBitmap(bitmap);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        break;

    }
}
   通过这种方式就解决了手机拍照OOM的问题。




























 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值