副标题: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.0holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);holder.addCallback(new SurfaceHolder.Callback() {@Override//The preview must happen at or after this point or takePicture failspublic 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);}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}@Overridepublic 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 1x1WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,0,//Don't know if this is a safe defaultPixelFormat.UNKNOWN);//Don't set the preview visibility to GONE or INVISIBLEwm.addView(preview, params);}

图片缩放与裁剪

现在几乎就可以了,pictureCallback是拍照成功后的回调,我们将在此回调中做一些对图片数据的处理工作。
首先,图片数据以字节数组的形式返回的,原型如下:

        @Overridepublic 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() {@Overridepublic 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());//裁剪bitmapint 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实战技巧之四十七:不用预览拍照与图片缩放剪裁相关推荐

  1. Android实战技巧之四十:Android5.1.1源代码编译与烧写

    购买Nexus手机的朋友大多是为了自己修改系统玩,再加上其较高的性价比,在开发者中还是广受欢迎的.我的5太子被我升级到了6.0预览版,玩的正嗨,舍不得换回到5.1时代了.不过鉴于距6.0源码发布还有段 ...

  2. Android实战技巧之四十 Android5 1 1源代码编译与烧写

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 购买Ne ...

  3. Android实战技巧之三十七:图片的Base64编解码

    通经常使用Base64这样的编解码方式将二进制数据转换成可见的字符串格式,就是我们常说的大串.10块钱一串的那种,^_^. Android的android.util包下直接提供了一个功能十分完备的Ba ...

  4. android 速度传感器,Android实战技巧之四十二:加速度传感器

    传感器字面上的意思就是传递感觉的仪器,哪些感觉呢? 视觉.听觉.味觉.触觉.嗅觉等等. 所以有人说,传感器的存在和发展,让物体有了触觉.味觉和嗅觉等感官,让物体慢慢变得活了起来. 当前Android设 ...

  5. Android实战技巧之十一:Android Studio和Gradle

    2019独角兽企业重金招聘Python工程师标准>>> 经过两个多月的AS体验,我认为是时候将Android的开发环境迁移到AS上了.目前最新版本是1.0.2(大年30当天升级到1. ...

  6. Android实战技巧:深入解析AsyncTask

    AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复. AsyncTask引发的一个问题 上 ...

  7. 谷歌发布 Android 8.1 首个开发者预览版,优化内存效率

    今晨,谷歌推出了 Android 8.1 首个开发者预览版,此次升级涵盖了针对多个功能的提升优化,其中包含对 Android Go (设备运行内存小于等于 1 GB)和加速设备上对机器学习的全新神经网 ...

  8. android自定义相机预览尺寸,相机在Android中,如何获得最佳尺寸,预览尺寸,图片尺寸,视图尺寸,图像扭曲...

    混合来自OpenGL和 Android相机的视图时图像失真,以便在使用takepicture方法时获取两者的图像.我查了一下,发现相机图片设置为640X480,openGL视图和相机预览都设置为128 ...

  9. android p dp5,谷歌释出Android P第5个开发者预览版更新!

    原标题:谷歌释出Android P第5个开发者预览版更新! [PConline资讯]今天凌晨,谷歌正式推出了AndroidP的第五个开发者预览版(DP5),这标志着AndroidP终于准备好在2018 ...

最新文章

  1. java 语言实现的随机数生成算法
  2. python最简单的账号密码验证_Python之简单的用户名密码验证
  3. 软件工程实践2017结对第二次作业
  4. [转载] 浅析Java OutOfMemoryError
  5. 计算机c盘内部图片,C盘爆满?教你如何释放系统盘空间,瞬间多出10个G!
  6. 干掉 Jenkins?顶级 DevOps 工具链大盘点
  7. 【数据产品案例】阿里生意参谋-用户分析
  8. 大米云主机首批优秀体验师新鲜出炉——综合篇
  9. MP3参数,格式,术语有关一切内容详解
  10. 计算机证件照无法上传,计算机IE浏览器为什么不能上传照片
  11. php更改文件为只读,word只读模式怎么修改
  12. 市场上的智能语音助理,主要的工作原理是什么?
  13. Spring Boot多数据源配置并通过注解实现动态切换数据源
  14. excel排序求和:如何统计前几名数据合计 上篇
  15. 微信公众号怎么为用户提供文件下载功能
  16. Oracle ERP 仓库(inventory) 词汇 2
  17. java B2B2C源码电子商务平台 -SpringCloud服务相互调用RestTemplate
  18. 【调参15】如何配置神经网络的学习率
  19. NVT SDK开关机LOGO替换实践
  20. Cobalt strike的使用

热门文章

  1. 个人电脑重装WINDOWN XP 论坛
  2. linux mp3插件名,Linux 福利:TAL Software 八款插件开始支持 Linux ,其中有两款免费...
  3. Centos7 搭建Nginx图片服务超详细新手小白教程
  4. Matlab绘制面积堆叠图/面积图
  5. postman 下载图片_postman测试上传图片接口步骤教程
  6. python----列表 例题 创建一个列表,命名为foods, 在列表中保存5个食物士豆,西红柿面条,苹果,披萨并打印出每一个食物的名字
  7. 智慧农场,51单片机上实现DS18B20与YL69土壤湿度传感器,并将两个获取的数据在LCD上显示出来
  8. 2019年20个最佳产品信息管理(PIM)软件(一)
  9. xe10 自带DEMO集合
  10. 【点云路标提取】一个用于点云道路标志提取,分类和完善的的深度学习框架