对Activity强制横屏,保证预览方向正确。

使用OrientationEventListener监听设备方向。推断竖拍时,旋转照片后再保存。保证竖拍时预览图片和保存后的图片方向一致。

执行效果:

                     

代码:

TestCameraActivity.java

package com.example.testcamera;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID; import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class TestCameraActivity extends Activity implements OnClickListener,
SurfaceHolder.Callback {
private static final String TAG = "TestCameraActivity";
public static final String KEY_FILENAME = "filename";
private Button mTakePhoto;
private SurfaceView mSurfaceView;
private Camera mCamera;
private String mFileName;
private OrientationEventListener mOrEventListener; // 设备方向监听器
private Boolean mCurrentOrientation; // 当前设备方向 横屏false,竖屏true /* 图像数据处理还未完毕时的回调函数 */
private Camera.ShutterCallback mShutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
// 一般显示运行进度条
}
}; /* 图像数据处理完毕后的回调函数 */
private Camera.PictureCallback mJpeg = new Camera.PictureCallback() { @Override
public void onPictureTaken(byte[] data, Camera camera) {
// 保存图片
mFileName = UUID.randomUUID().toString() + ".jpg";
Log.i(TAG, mFileName);
FileOutputStream out = null;
try {
out = openFileOutput(mFileName, Context.MODE_PRIVATE);
byte[] newData = null;
if (mCurrentOrientation) {
// 竖屏时。旋转图片再保存
Bitmap oldBitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
Matrix matrix = new Matrix();
matrix.setRotate(90);
Bitmap newBitmap = Bitmap.createBitmap(oldBitmap, 0, 0,
oldBitmap.getWidth(), oldBitmap.getHeight(),
matrix, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
newBitmap.compress(Bitmap.CompressFormat.JPEG, 85, baos);
newData = baos.toByteArray();
out.write(newData);
} else {
out.write(data);
} } catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Intent i = new Intent(TestCameraActivity.this, ShowPicture.class);
i.putExtra(KEY_FILENAME, mFileName);
startActivity(i);
finish();
}
}; @SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_camera);
mTakePhoto = (Button) findViewById(R.id.take_photo);
mTakePhoto.setOnClickListener(this); // 拍照button监听器 startOrientationChangeListener(); // 启动设备方向监听器
mSurfaceView = (SurfaceView) findViewById(R.id.my_surfaceView);
SurfaceHolder holder = mSurfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(this); // 回调接口 } private final void startOrientationChangeListener() {
mOrEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int rotation) {
if (((rotation >= 0) && (rotation <= 45)) || (rotation >= 315)
|| ((rotation >= 135) && (rotation <= 225))) {// portrait
mCurrentOrientation = true;
Log.i(TAG, "竖屏");
} else if (((rotation > 45) && (rotation < 135))
|| ((rotation > 225) && (rotation < 315))) {// landscape
mCurrentOrientation = false;
Log.i(TAG, "横屏");
}
}
};
mOrEventListener.enable();
} @Override
public void onClick(View v) {
// 点击拍照
switch (v.getId()) {
case R.id.take_photo:
mCamera.takePicture(mShutter, null, mJpeg);
break;
default:
break;
} } @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// SurfaceView尺寸发生改变时(首次在屏幕上显示相同会调用此方法)。初始化mCamera參数,启动Camera预览 Parameters parameters = mCamera.getParameters();// 获取mCamera的參数对象
Size largestSize = getBestSupportedSize(parameters
.getSupportedPreviewSizes());
parameters.setPreviewSize(largestSize.width, largestSize.height);// 设置预览图片尺寸
largestSize = getBestSupportedSize(parameters
.getSupportedPictureSizes());// 设置捕捉图片尺寸
parameters.setPictureSize(largestSize.width, largestSize.height);
mCamera.setParameters(parameters); try {
mCamera.startPreview();
} catch (Exception e) {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
} } @Override
public void surfaceCreated(SurfaceHolder holder) {
// SurfaceView创建时,建立Camera和SurfaceView的联系
if (mCamera != null) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
} } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
// SurfaceView销毁时。取消Camera预览
if (mCamera != null) {
mCamera.stopPreview();
}
} @SuppressLint("NewApi")
@Override
public void onResume() {
super.onResume();
// 开启相机
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(0);
// i=0 表示后置相机
} else
mCamera = Camera.open();
} @Override
public void onPause() {
super.onPause();
// 释放相机
if (mCamera != null) {
mCamera.release();
mCamera = null;
} } private Size getBestSupportedSize(List<Size> sizes) {
// 取能适用的最大的SIZE
Size largestSize = sizes.get(0);
int largestArea = sizes.get(0).height * sizes.get(0).width;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
largestArea = area;
largestSize = s;
}
}
return largestSize;
}
}

ShowPicture.java

package com.example.testcamera;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.widget.ImageView; public class ShowPicture extends Activity { private static final String TAG = "ShowPicture";
private ImageView mPicture; public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_picture); mPicture = (ImageView) findViewById(R.id.picture);
String fileName = getIntent().getStringExtra(
TestCameraActivity.KEY_FILENAME);
// 图片路径
Log.i(TAG, fileName);
String path = getFileStreamPath(fileName).getAbsolutePath(); Display display = getWindowManager().getDefaultDisplay(); // 显示屏尺寸
float destWidth = display.getWidth();
float destHeight = display.getHeight(); // 读取本地图片尺寸
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);// 设置为true,options依旧相应此图片,但解码器不会为此图片分配内存 float srcWidth = options.outWidth;
float srcHeight = options.outHeight; int inSampleSize = 1;
if (srcHeight > destHeight || srcWidth > destWidth) { // 当图片长宽大于屏幕长宽时
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / destHeight);
} else {
inSampleSize = Math.round(srcWidth / destWidth);
}
}
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize; Bitmap bitmap = BitmapFactory.decodeFile(path, options);
BitmapDrawable bDrawable = new BitmapDrawable(getResources(), bitmap);
mPicture.setImageDrawable(bDrawable);
} @Override
public void onDestroy() {
if (!(mPicture.getDrawable() instanceof BitmapDrawable))
return;
// 释放bitmap占用的空间
BitmapDrawable b = (BitmapDrawable) mPicture.getDrawable();
b.getBitmap().recycle();
mPicture.setImageDrawable(null);
} }

源代码下载

github:https://github.com/mandmLeee/CustomCameraDemo

Android Camera+SurfaceView实现自己定义拍照的更多相关文章

  1. 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

    杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能. ...

  2. Android Camera进行拍照

    Android应用提供了Camera来控制拍照,使用Camera进行拍照的步骤: 1.调用Camera的open()方法打开相机. 2.调用Camera的getParameters()方法获取拍照参数 ...

  3. Android 举例说明自己的定义Camera图片和预览,以及前后摄像头切换

    如何调用本地图片,并调用系统拍摄的图像上一博文解释(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自己定 ...

  4. Android Camera开发系列(下)——自定义Camera实现拍照查看图片等功能

    Android Camera开发系列(下)--自定义Camera实现拍照查看图片等功能 Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 上 ...

  5. 玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  6. Android Camera开发:使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  7. Android Camera相机功能实现 拍照并保存图片

    AndroidManifest.xml <uses-feature android:name="android.hardware.camera"/> <uses- ...

  8. Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片

    Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一 ...

  9. Android Camera 拍照 三星BUG总结

    Android Camera 三星BUG  : 近期在Android项目中使用拍照功能 , 其他型号的手机执行成功了  只有在三星的相机上遇到了bug . BUG详细体现为 : (1) 摄像头拍照后图 ...

随机推荐

  1. 【BZOJ 1221】 [HNOI2001] 软件开发

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] /* 设一个超级源点S和超级汇点T S和2*i-1各连一条容量为ni的边. 花费为0 表示每天都会产生ni条要洗的毛巾 S和2*i各 ...

  2. ASP.NET-post、get的区别

    post.get的区别 1.get通过把参数加在浏览器的地址栏中提交(最大2K),用post可以进行文件的提交: 2.使用post提交的页面在点击[刷新]按钮的时候浏览器一般会提示"是否重新 ...

  3. 洛谷 P2700 逐个击破

    P2700 逐个击破 题目背景 三大战役的平津战场上,傅作义集团在以北平.天津为中心,东起唐山西至张家口的铁路线上摆起子一字长蛇阵,并企图在溃败时从海上南逃或向西逃窜.为了就地歼敌不让其逃走,毛主席制 ...

  4. 【中山市选2010】【BZOJ2467】生成树

    Description 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈. 在中心的这个n边圈的每一条边同一时候也是某一个五角形的一条边,一共同拥有n个不同的五角形.这些五角 ...

  5. Intellij IDEA插件 - Scroll From Source

    Intellij IDEA插件 - Scroll From Source 学习了:http://blog.csdn.net/luonanqin/article/details/41088171 可以自 ...

  6. Microsoft Updateclient更新

     大家好, 微软Microsoft Update产品组官方博客于昨天宣布了有关最新的Windows Updateclient更新的消息.依据这则博客.微软从当日開始逐渐向全部Windows 7, ...

  7. vargrind 安卓apk

    上层为安卓, 下层为调用c/c++ 库 1.将vargind 按官网方法下载源代码编译  得Inst文件夹 2.通过win 下安卓sdk 中 platform-tools 中的adb push Ins ...

  8. hdoj 1013Digital Roots

     /*Digital Roots Problem Description The digital root of a positive integer is found by summing th ...

  9. google 搜索不跳中间页

    Array.prototype.slice.call(document.links,0).forEach(function(link){link.onmousedown = null}) 插件总失效 ...

  10. oracle 下操作blob字段是否会产生大量redo

    操作blob字段是否会产生大量redo,答案是不会.以下来做一个实验,測试数据库版本号是11.2.0.1.0: --创建一张表做測试之用 create table test_blob (   id n ...