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

项目中最近需要用到摄像机拍照,起初的时候肯定怎么省事怎么来,直接就是调用系统的摄像机了,那么问题来了,调用系统摄像机的时候,发现不同的手机拍摄出的照片的旋转角度不一样。举个例子来说,小米手机拍摄出的照片旋转角度为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() {
			@Override
			public 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*640
		try {
			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

时间: 2024-12-21 10:20:40

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

Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)

Android自定义照相机实现 近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能. 创建一个项目:FingerTakePicture 首先来搞一下界面: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu

Android自定义照相机注意事项

1.设置预览方向myCamera.setDisplayOrientation(90) 2.设置照片方向parameters.setRotation(90); 3.设置预览显示和照片的分辨率 // 设置照片分辨率 List<Camera.Size> previewSizeList = parameters .getSupportedPreviewSizes(); int previewWidth = 0; int previewHeight = 0; for (int i = 0; i <

android 自定义照相机Camera黑屏 (转至 http://blog.csdn.net/chuchu521/article/details/8089058)

对于一些手机,像HTC,当自定义Camera时,调用Camera.Parameters的 parameters.setPreviewSize(width, height)方法时,如果width和height为奇数情况下,则会出现黑屏现象,解决办法可参考SDK提供的ApiDemos中关于Camera的 例子: List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreview

Android自定义照相机 预览拍照 切换前后置摄像头

Android提供了Camera来控制拍照,步骤如下:(1)调用Camera的open()方法打开相机.(2)调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象.(3)调用Camera.Parameters对象对照相的参数进行设置.(4)调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置.(5)调用Camerade

Android 自定义 ViewPager 打造千变万化的图片切换效果

Android 自定义 ViewPager 打造千变万化的图片切换效果 标签: Android自定义ViewPagerJazzyViewPager 目录(?)[+] 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记 得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主界面通通ViewPager,以及图片切换也抛弃了ImageSwitch之类的,开 始让ViewPager来做.时间长了,ViewPa

Android 实例讲解自定义Camera拍照和预览以及前后置摄像头切换

上一篇博文讲解了怎么去调用本地图片和调用系统拍照图片(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自定义Camera的功效.具体功能如下: 1.实现自定义Camera拍照: 2.实现前后置摄像头的切换: 3.实现Camera拍照后图片缩小显示以及正常预览: 4.实现Camera拍照后图片保存: 在具体实现代码之前,我们先来了解一下Android api对实现自定义Camera的介绍. 根据api的介

Android 调用系统照相机拍照和录像

本文实现android系统照相机的调用来拍照 项目的布局相当简单,只有一个Button: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_heig

Android自定义ViewGroup (选择照片或者拍照)

教你搞定Android自定义ViewGroup http://www.jianshu.com/p/138b98095778 字数1794 阅读7030 评论8 喜欢37 上一篇我们介绍了Android中自定义View的知识,并实现了一个类似Google彩虹进度条的自定义View,今天我们将进一步学习如何去自定义一个ViewGroup. ViewGroup 我们知道ViewGroup就是View的容器类,我们经常用的LinearLayout,RelativeLayout等都是ViewGroup的子

Android中实现自定义的拍照应用

可以参考:http://www.android-doc.com/guide/topics/media/camera.html 一.添加相应的权限 <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /><!-- 拍照的功能 --> <uses-perm