Android 自定义照相机拍照截图并仿照nice添加标签

来源:互联网 发布:中冶南方自动化知乎 编辑:程序博客网 时间:2024/05/16 01:20

项目中最近需要用到摄像机拍照,起初的时候肯定怎么省事怎么来,直接就是调用系统的摄像机了,那么问题来了,调用系统摄像机的时候,发现不同的手机拍摄出的照片的旋转角度不一样。举个例子来说,小米手机拍摄出的照片旋转角度为0度(照片是正的),三星手机拍摄出的照片,照片用同样的方法加载出来,而照片旋转了90度,(照片是反的),shit,这是为什么?

刚开始的时候肯定将照片旋转一定的角度来解决,但是发现这样有一点low啊,并且设计上要求在拍照界面中要自己绘制一个框框,用户看到这个框框后拍照,拍照后自动截取图片,并压缩到640*640,shit,这样以来调用系统的照相机肯定就是不行了啊。。。。。

没有办法了,只能到网上去搜索相关的解决方案了,但是搜索了好久基本上就是简单的预览,哎,最后到google官方的例子里面发现了一个比较好的SurfaceView,这个SurfaceView起码根据你的手机计算出了最合适的拍照比例,好吧。这还是不够的,还是太简单了。最后通过多方途径(参考以前项目的实现,问一个大哥),大概明白了摄像机的基本原理。

下面简单的大致描述一下摄像机:

1:我们要想拍照正确,自定义的拍照界面的屏幕现实方式要是横屏拍摄,最好设置为全屏并且没有标题,这样拍摄出的照片才是正确,否则你就哭去吧,这也是血泪摸索出来的,下面简单粘贴一个配置文件:

<activity                android:name="com.example.AndroidCaptureCropTags.camera.ActivityCapture"                android:configChanges="keyboardHidden|orientation|screenSize"                android:screenOrientation="landscape"                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"                android:windowSoftInputMode="adjustResize|stateHidden">        </activity>

2:其实我们拍照预览的时候,google把摄像头封装了一系列的API,主要是再预览之前计算最佳的预览比例,防止预览的时候变形。并计算最佳的拍摄出的图片的现实比例,这样拍摄出的图片也不会变形。

3:接下来就是摄像机界面白色框框的绘制,就是自定义了一个View而已。

4:最后拍摄出来照片后根据屏幕中显示的白色的框框来截取图片(这个地方也挺蛋疼的。。。);

pictureCallBack = new PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {_isCapturing = false;Bitmap bitmap = null;try {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeByteArray(data, 0, data.length, options);//Debug.debug("width--:" + options.outWidth + "  height--:" + options.outHeight);options.inJustDecodeBounds = false;options.inPreferredConfig = Bitmap.Config.ARGB_8888;//此处就把图片压缩了options.inSampleSize = Math.max(options.outWidth/ kPhotoMaxSaveSideLen, options.outHeight/ kPhotoMaxSaveSideLen);bitmap = BitmapUtil.decodeByteArrayUnthrow(data, options);if (null == bitmap) {options.inSampleSize = Math.max(2, options.inSampleSize * 2);bitmap = BitmapUtil.decodeByteArrayUnthrow(data, options);}} catch (Throwable e) {}if (null == bitmap) {Toast.makeText(ActivityCapture.this, "内存不足,保存照片失败!", Toast.LENGTH_SHORT).show();return;}//long start = System.currentTimeMillis();Bitmap addBitmap = BitmapUtil.rotateAndScale(bitmap, _rotation, kPhotoMaxSaveSideLen, true);Bitmap finalBitmap = cropPhotoImage(addBitmap);File photoFile = PathManager.getCropPhotoPath();boolean successful = BitmapUtil.saveBitmap2file(finalBitmap, photoFile, Bitmap.CompressFormat.JPEG, 100);while (!successful) {successful = BitmapUtil.saveBitmap2file(finalBitmap, photoFile, Bitmap.CompressFormat.JPEG, 100);}if (finalBitmap != null && !finalBitmap.isRecycled()) {addBitmap.recycle();}Intent intent = new Intent();intent.putExtra(kPhotoPath, photoFile.getAbsolutePath());ActivityCapture.this.setResult(RESULT_OK, intent);ActivityCapture.this.finish();}};
上面代码的逻辑是:拍摄后系统会将图片的数据以byte[]的形式传递给我们,options.inJustDecodeBounds = true;先用这种形式避免直接将图片加载进内存中,得到了图片的宽度和高度后,然后计算图片的inSampleSize,这里自己写了一个最大的边长1600,通过实验发现定义成这个边长后,拍摄出的照片无论是手机上看还是电脑上看,体验效果都是不错的,这也是通过询问以前的大哥才了解的,(我想了半天也不知道为什么非要定义成1600.。。。)。下面就是将data加载成一个Bitmap,注意此时的Bitmap可能是旋转的,还要调用这个方法Bitmap addBitmap = BitmapUtil.rotateAndScale(bitmap, _rotation, kPhotoMaxSaveSideLen, true);来将图片摆正,其中的_rotation这个角度是我们在拍摄的过程中不断的计算的(这个有些是从网上找的,正在消化中。。。。,自己不是太明白的就不说了,免的说错了误人子弟)。将图片旋转正确后下面就是所见即所得了,截图。。。。。。。

//根据拍照的图片来剪裁private Bitmap cropPhotoImage(Bitmap bmp) {int dw = bmp.getWidth();int dh = bmp.getHeight();int height;int width;if (dh > dw) {//图片竖直方向//切图片时按照竖屏来计算height = getWindowManager().getDefaultDisplay().getWidth();width = getWindowManager().getDefaultDisplay().getHeight();} else {//图片是水平方向//切图片时按照横屏来计算width = getWindowManager().getDefaultDisplay().getWidth();height = getWindowManager().getDefaultDisplay().getHeight();}Rect rect = new Rect();int left = (width - cropBorderView.getRect().width()) / 2;int top = (height - cropBorderView.getRect().height()) / 2;int right = left + cropBorderView.getRect().width();int bottom = top + cropBorderView.getRect().height();rect.set(left, top, right, bottom);float scale = 1.0f;// 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高if (dw > width && dh <= height) {scale = width * 1.0f / dw;}if (dh > height && dw <= width) {scale = height * 1.0f / dh;}// 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小if (dw > width && dh > height) {scale = Math.max(width * 1.0f / dw, height * 1.0f / dh);}//如果图片的宽度和高度都小于屏幕的宽度和高度,则放大至屏幕大小if (dw < width && dh < height) {scale = width * 1.0f / dw;}Matrix matrix = new Matrix();matrix.postScale(scale, scale);try {Bitmap b2 = Bitmap.createBitmap(bmp, 0, 0, dw, dh, matrix, true);if (null != b2 && bmp != b2) {bmp.recycle();bmp = b2;}} catch (OutOfMemoryError e) {e.printStackTrace();}try {Bitmap b3 = Bitmap.createBitmap(bmp, rect.left, rect.top, rect.width(), rect.height());if (null != b3 && bmp != b3) {bmp.recycle();bmp = b3;}} catch (OutOfMemoryError e) {e.printStackTrace();}//将图片压缩至640*640try {Bitmap b4 = Bitmap.createScaledBitmap(bmp, 640, 640, false);if (null != b4 && bmp != b4) {bmp.recycle();bmp = b4;}} catch (OutOfMemoryError e) {e.printStackTrace();}return bmp;}

经过测试发现,拍摄出的照片并不是你在屏幕中看见是竖直方向就是竖直方向,可能拍摄出的照片是竖直方向也可能是水平方向(即照片是竖的还是横的)。这是两种情况要分别来进行处理的。。。下面简单用文字描述一下这两种情况。

1:照片是竖的,而我们的Activity是横屏的。。。所以计算截取框的时候我们要按照屏幕是竖的来计算,才可以确定截取框的正确的位置。

2:照片是横的,我们的Activity也是横屏的。。。所以正常计算就ok。

3:不要想着我们屏幕那么大,拍摄出的照片就是屏幕那么大,而是比屏幕大得多。。。。,这就需要我们缩放到屏幕的大小,这样才可以做到所见即所得嘛,你说是不是?具体的缩放无非就是图片等比例缩放。图片是等比例缩放了,但是可能担心这种情况,要是缩放后比屏幕小一点或者大一点那不就不准确了嘛?这点我刚开始的时候也是担心的,但是我们在代码中计算了拍照的最合适的预览比例,最合适的照片比例,经过很多的手机测试发现都是没有问题的,他们的比例是保持一致的。

4:接下来就是烦人的截图了,最后将图片压缩到640*640,就ok了。

5:明白一点不要重复的造车子,你的心里面就舒服多了。

截图完了就保存到本地的文件里面就ok了。下面就是给图片添加一个Tag什么的,Tag添加点动画,都是一点点调出来的,没什么技术含量,包括正方形的控件的自定义也很简单,直接看看代码就ok了。。。。。

草,我发现我写博客写不了那么的详细。。。shit


http://download.csdn.net/detail/ly985557461/8199671

1 0