最近需要做手机拍照【两种方式:调用系统相机(博客最后);自己写照相机布局】,预览,上传功能。特地研究了下android的手机拍照。
参考地址:
http://blog.csdn.net/cfwdl/article/details/5746708
http://mjbb.iteye.com/blog/1018006
http://blog.csdn.net/hellogv/article/details/5962494
1、上传文件功能网上很多讲的,只要细心点,按照格式来写发送的数据,都是没有问题的。
2、预览使用Gallery和ImageSwitcher就行,我做的很简单(参考代码)。
----------------------------------------------------------------------------------------------------------------------
修改内容:
1、照相功能使用系统自带照相机(自己写的照相机属性设置根据不同照相机会有问题,所以舍弃)
2、预览功能不再使用Gallery+ImageSwitcher;实用性不强,并且显示慢且卡。改用异步加载
3、上传图片时,对图片进行压缩,增加上传速度。
4、长按gridView进入编辑模式,批量删除图片。参考http://aokunsang.iteye.com/blog/1668902;
5、今天又做修改,之前写的压缩图片方法的竟然会变形(没有测试大的图片),修改后不会变形了。
以此,希望能做到最好的用户体验。
附上流程图:
拍照功能:【预览尺寸有知道的朋友留言告知。】
* 拍照 * @author Administrator */ public class TakePhotoAct extends Activity implements SurfaceHolder.Callback{ private static String imgPath = Environment.getExternalStorageDirectory().getPath() + "/"+Const.imageDir; private SurfaceView surfaceView; //相机画布 private SurfaceHolder surfaceHolder; private Button takePicView,exitView; private Camera mCamera; //照相机 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //这里我在AndroidManifest.xml的activity中添加了android:theme="@android:style/Theme.NoTitleBar.Fullscreen" /** * 隐藏状态栏和标题栏 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); */ //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏 /** * 获取Button并且设置事件监听 */ takePicView = (Button)this.findViewById(R.id.takepic); takePicView.setOnClickListener(TakePicListener); exitView = (Button)this.findViewById(R.id.exit); exitView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); surfaceView = (SurfaceView)this.findViewById(R.id.surface_camera); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); checkSoftStage(); //首先检测SD卡是否存在 } /** * 检测手机是否存在SD卡,网络连接是否打开 */ private void checkSoftStage(){ if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //判断是否存在SD卡 // String rootPath = Environment.getExternalStorageDirectory().getPath(); //获取SD卡的根目录 File file = new File(imgPath); if(!file.exists()){ file.mkdir(); } }else{ new AlertDialog.Builder(this).setMessage("检测到手机没有存储卡!请插入手机存储卡再开启本应用。") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); } } /** * 点击拍照按钮,启动拍照 */ private final OnClickListener TakePicListener = new OnClickListener(){ @Override public void onClick(View v) { mCamera.autoFocus(new AutoFoucus()); //自动对焦 } }; /** * 自动对焦后拍照 * @author aokunsang * @Date 2011-12-5 */ private final class AutoFoucus implements AutoFocusCallback{ @Override public void onAutoFocus(boolean success, Camera camera) { if(success && mCamera!=null){ mCamera.takePicture(mShutterCallback, null, mPictureCallback); } } } /** * 重点对象、 此处实例化了一个本界面的PictureCallback * 当用户拍完一张照片的时候触发,这时候对图片处理并保存操作。 * */ private final PictureCallback mPictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { try { String fileName = System.currentTimeMillis()+".jpg"; File file = new File(imgPath,fileName); Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); bm.compress(Bitmap.CompressFormat.JPEG, 60, bos); bos.flush(); bos.close(); Intent intent = new Intent(TakePhotoAct.this,PictureViewAct.class); intent.putExtra("imagePath", file.getPath()); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } }; /** * 在相机快门关闭时候的回调接口,通过这个接口来通知用户快门关闭的事件, * 普通相机在快门关闭的时候都会发出响声,根据需要可以在该回调接口中定义各种动作, 例如:使设备震动 */ private final ShutterCallback mShutterCallback = new ShutterCallback() { public void onShutter() { Log.d("ShutterCallback", "...onShutter..."); } }; @Override /** * 初始化相机参数,比如相机的参数: 像素, 大小,格式 */ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters param = mCamera.getParameters(); /** * 设置拍照图片格式 */ param.setPictureFormat(PixelFormat.JPEG); /** * 设置预览尺寸【这里需要注意:预览尺寸有些数字正确,有些会报错,不清楚为啥】 */ //param.setPreviewSize(320, 240); /** * 设置图片大小 */ param.setPictureSize(Const.width, Const.height); mCamera.setParameters(param); /** * 开始预览 */ mCamera.startPreview(); } @Override /** * 打开相机,设置预览 */ public void surfaceCreated(SurfaceHolder holder) { try { mCamera = Camera.open(); //打开摄像头 mCamera.setPreviewDisplay(holder); } catch (IOException e) { mCamera.release(); mCamera = null; } } @Override /** * 预览界面被关闭时,或者停止相机拍摄;释放相机资源 */ public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); if(mCamera!=null) mCamera.release(); mCamera = null; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_CAMERA){ //按下相机实体按键,启动本程序照相功能 mCamera.autoFocus(new AutoFoucus()); //自动对焦 return true; }else{ return false; } } }
xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <SurfaceView android:id="@+id/surface_camera" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:text="拍照" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/takepic" /> <Button android:text="退出" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/exit" /> </LinearLayout> </LinearLayout>
预览功能:
/**
* 图片预览 * @author: aokunsang * @date: 2012-8-1 */ public class PictureScanAct extends Activity { private GridView gridView; private ImageAdapter imgAdapter; private List<String> fileNameList = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.picturescan); gridView = (GridView)findViewById(R.id.picture_grid); imgAdapter = new ImageAdapter(this); gridView.setAdapter(imgAdapter); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String fileName = fileNameList.get(position); startActivity(new Intent(PictureScanAct.this, PictureViewAct.class).putExtra("flag","upload").putExtra("imagePath",fileName)); } }); //setProgressBarIndeterminateVisibility(true); Toast.makeText(this, "加载图片中....", Toast.LENGTH_LONG).show(); new AsyncLoadedImage().execute(); } /** * 向适配器添加图片 * @param bitmap */ private void addImage(Bitmap... loadImages){ for(Bitmap loadImage:loadImages){ imgAdapter.addPhoto(loadImage); } } /** * 释放内存 */ protected void onDestroy() { super.onDestroy(); final GridView grid = gridView; final int count = grid.getChildCount(); ImageView v = null; for (int i = 0; i < count; i++) { v = (ImageView) grid.getChildAt(i); ((BitmapDrawable) v.getDrawable()).setCallback(null); } } /** * 异步加载图片展示 * @author: aokunsang * @date: 2012-8-1 */ class AsyncLoadedImage extends AsyncTask<Object, Bitmap, Boolean> { @Override protected Boolean doInBackground(Object... params) { File fileDir = new File(Const.imgPath); File[] files = fileDir.listFiles(); boolean result = false; if(files!=null){ for(File file:files){ String fileName = file.getName(); if (fileName.lastIndexOf(".") > 0 && fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).equals("jpg")){ Bitmap bitmap; Bitmap newBitmap; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 10; bitmap = BitmapFactory.decodeFile(file.getPath(), options); newBitmap = ThumbnailUtils.extractThumbnail(bitmap, 100, 100); bitmap.recycle(); if (newBitmap != null) { fileNameList.add(file.getPath()); publishProgress(newBitmap); result = true; } } catch (Exception e) { e.printStackTrace(); } } } } return result; } @Override public void onProgressUpdate(Bitmap... value) { addImage(value); } @Override protected void onPostExecute(Boolean result) { if(!result){ showDialog(1); } } } @Override protected Dialog onCreateDialog(int id) { AlertDialog dialog = new AlertDialog.Builder(PictureScanAct.this).setTitle("温馨提示").setMessage("暂时还没有照片,请先采集照片!") .setPositiveButton("确定", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(PictureScanAct.this,TakePhotoAct.class)); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); return dialog; } }
GridView适配器:
public class ImageAdapter extends BaseAdapter {
private List<Bitmap> picList = new ArrayList<Bitmap>(); private Context mContext; public ImageAdapter(Context mContext){ this.mContext = mContext; } @Override public int getCount() { return picList.size(); } /* (non-Javadoc) * @see android.widget.Adapter#getItem(int) */ @Override public Object getItem(int position) { // TODO Auto-generated method stub return picList.get(position); } /** * 添加图片 * @param bitmap */ public void addPhoto(Bitmap loadImage){ picList.add(loadImage); notifyDataSetChanged(); } /* (non-Javadoc) * @see android.widget.Adapter#getItemId(int) */ @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = null; if(convertView == null){ imageView = new ImageView(mContext); imageView.setLayoutParams(new GridView.LayoutParams(110, 110)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(5,5,5,5); }else{ imageView = (ImageView)convertView; } imageView.setImageBitmap(picList.get(position)); return imageView; } }
图片预览界面:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/picture_grid" android:layout_width="match_parent" android:layout_height="match_parent" android:numColumns="4" android:verticalSpacing="5dip" android:horizontalSpacing="5dip" android:stretchMode="columnWidth" android:columnWidth="120dip" android:gravity="center" > </GridView>
预览图片:
上传工具类:
import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import java.util.Map.Entry; import android.util.Log; import com.peacemap.photo.po.FileInfo; /** * POST上传文件 * @author aokunsang * @Date 2011-12-6 */ public class PostFile { private static PostFile postFile = new PostFile(); private final static String LINEND = "\r\n"; private final static String BOUNDARY = "---------------------------7da2137580612"; //数据分隔线 private final static String PREFIX = "--"; private final static String MUTIPART_FORMDATA = "multipart/form-data"; private final static String CHARSET = "utf-8"; private final static String CONTENTTYPE = "application/octet-stream"; private PostFile(){} public static PostFile getInstance(){ return postFile; } /** * HTTP上传文件 * @param actionUrl 请求服务器的路径 * @param params 传递的表单内容 * @param files 多个文件信息 * @return */ public String post(String actionUrl,Map<String,String> params,FileInfo[] files){ try { URL url = new URL(actionUrl); HttpURLConnection urlConn = (HttpURLConnection)url.openConnection(); urlConn.setDoOutput(true); //允许输出 urlConn.setDoInput(true); //允许输入 urlConn.setUseCaches(false); urlConn.setRequestMethod("POST"); urlConn.setRequestProperty("connection", "Keep-Alive"); urlConn.setRequestProperty("Charset", CHARSET); urlConn.setRequestProperty("Content-Type", MUTIPART_FORMDATA+";boundary="+BOUNDARY); DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream()); //构建表单数据 String entryText = bulidFormText(params); Log.i("-------描述信息---------------", entryText); dos.write(entryText.getBytes()); StringBuffer sb = new StringBuffer(""); for(FileInfo file : files){ sb.append(PREFIX).append(BOUNDARY).append(LINEND); sb.append("Content-Disposition: form-data; name=\""+file.getFileTextName()+"\"; filename=\""+file.getFile().getAbsolutePath()+"\""+LINEND); sb.append("Content-Type:"+CONTENTTYPE+";charset="+CHARSET+LINEND); sb.append(LINEND); dos.write(sb.toString().getBytes()); InputStream is = new FileInputStream(file.getFile()); byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) != -1) { dos.write(buffer, 0, len); } is.close(); dos.write(LINEND.getBytes()); } //请求的结束标志 byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); dos.write(end_data); dos.flush(); //----------------------------------- 发送请求数据结束 ---------------------------- //---------------------------------- 接收返回信息 ------------------------ int code = urlConn.getResponseCode(); if(code!=200){ urlConn.disconnect(); return ""; }else{ BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); String result = ""; String line = null; while((line = br.readLine())!=null){ result += line; } br.close(); urlConn.disconnect(); return result; } } catch (Exception e) { Log.e("--------上传图片错误--------", e.getMessage()); return null; } } /** * HTTP上传单个文件 * @param actionUrl 请求服务器的路径 * @param params 传递的表单内容 * @param files 单个文件信息 * @return */ public String post(String actionUrl,Map<String,String> params,FileInfo fileInfo){ return post(actionUrl, params, new FileInfo[]{fileInfo}); } /** * 封装表单文本数据 * @param paramText * @return */ private String bulidFormText(Map<String,String> paramText){ if(paramText==null || paramText.isEmpty()) return ""; StringBuffer sb = new StringBuffer(""); for(Entry<String,String> entry : paramText.entrySet()){ sb.append(PREFIX).append(BOUNDARY).append(LINEND); sb.append("Content-Disposition:form-data;name=\"" + entry.getKey() + "\"" + LINEND); // sb.append("Content-Type:text/plain;charset=" + CHARSET + LINEND); sb.append(LINEND); sb.append(entry.getValue()); sb.append(LINEND); } return sb.toString(); } /** * 封装文件文本数据 * @param files * @return */ private String buildFromFile(FileInfo[] files){ StringBuffer sb = new StringBuffer(); for(FileInfo file : files){ sb.append(PREFIX).append(BOUNDARY).append(LINEND); sb.append("Content-Disposition: form-data; name=\""+file.getFileTextName()+"\"; filename=\""+file.getFile().getAbsolutePath()+"\""+LINEND); sb.append("Content-Type:"+CONTENTTYPE+";charset="+CHARSET+LINEND); sb.append(LINEND); } return sb.toString(); } }
上传图片时对图片进行压缩处理(压缩处理程序):
/**
* 压缩图片上传 * @param picPath * @return */ private synchronized File compressPicture(String picPath){ int maxWidth = 640,maxHeight=480; //设置新图片的大小 String fileName = picPath.substring(picPath.lastIndexOf("/")); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap image = BitmapFactory.decodeFile(picPath, options); double ratio = 1D; if (maxWidth > 0 && maxHeight <= 0) { // 限定宽度,高度不做限制 ratio = Math.ceil(options.outWidth / maxWidth); } else if (maxHeight > 0 && maxWidth <= 0) { // 限定高度,不限制宽度 ratio = Math.ceil(options.outHeight / maxHeight); } else if (maxWidth > 0 && maxHeight > 0) { // 高度和宽度都做了限制,这时候我们计算在这个限制内能容纳的最大的图片尺寸,不会使图片变形 double _widthRatio = Math.ceil(options.outWidth / maxWidth); double _heightRatio = (double) Math.ceil(options.outHeight / maxHeight); ratio = _widthRatio > _heightRatio ? _widthRatio : _heightRatio; } if (ratio > 1) options.inSampleSize = (int) ratio; options.inJustDecodeBounds = false; options.inPreferredConfig = Bitmap.Config.RGB_565; image = BitmapFactory.decodeFile(picPath, options); //保存入sdCard File file = new File(Const.thumbnailPath+fileName); try { FileOutputStream out = new FileOutputStream(file); if(image.compress(Bitmap.CompressFormat.JPEG, 100, out)){ out.flush(); out.close(); } } catch (Exception e) { e.printStackTrace(); return new File(picPath); }finally{ if(image!=null && !image.isRecycled()){ image.recycle(); } } return file; }
-------------------------------------我是个华丽的分割线,哇哈哈-----------------------------------------------
做完这个拍照后,感觉功能太简单,比如:设置图片大小,白天夜晚照相等等一些系统照相机带的功能都没有,因此用在项目中感觉不炫。 然后就用了简单点的,直接调用系统照相机了。本来想着简单呢,后来也遇到点问题。
(1)根据Camera Activity返回的时候,会带一个名为data的Bitmap对象,照片的缩略图(这个地方可以做各种修改,我没用到不说了),上代码:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); checkSoftStage(); try { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, TAKE_PICTURE); } catch (Exception e) { e.printStackTrace(); } } /** * 检测手机是否存在SD卡,网络连接是否打开 */ private void checkSoftStage(){ if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //判断是否存在SD卡 File file = new File(imgPath); if(!file.exists()){ file.mkdir(); } }else{ new AlertDialog.Builder(this).setMessage("检测到手机没有存储卡!请插入手机存储卡再开启本应用。") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == TAKE_PICTURE) { // 拍照Activity保存图像数据的key是data,返回的数据类型是Bitmap对象 Bitmap cameraBitmap = (Bitmap) data.getExtras().get("/sdcard/rtest.jpg"); // 在ImageView组件中显示拍摄的照片 image.setImageBitmap(cameraBitmap); // 做自己的业务操作。。。。 } super.onActivityResult(requestCode, resultCode, data); }
(2)以上代码在我的小米手机上测试时,出现问题了。 返回的name为data的Bitmap对象是个Null,我发现小米照完相片之后,他会先跳到一个预览的界面(系统自带的页面),所以得不到Bitmap对象了。
因此我就先保存照片以及其路径,然后在onActivityResult中获取图片,做业务操作,代码如下:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); checkSoftStage(); try { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, TAKE_PICTURE); } catch (Exception e) { e.printStackTrace(); } try { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); String fileName = System.currentTimeMillis()+".jpg"; newImgPath = imgPath + "/" + fileName; Uri uri = Uri.fromFile(new File(imgPath,fileName)); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, TAKE_PICTURE); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.i("--------图片路径---------", "------"+newImgPath+"---------"); //.....做一些业务操作 } catch (Exception e) { e.printStackTrace(); } super.onActivityResult(requestCode, resultCode, data); }
相关推荐
在Android开发中,有时我们需要实现一些特殊的相机功能,比如不预览的拍照或者后台拍照。这些需求可能出现在一些需要高效能、低资源消耗或者隐私保护的场景。本篇将详细探讨如何实现这样的功能。 首先,要理解“不...
在Android平台上,无预览拍照是指在用户拍摄照片时,不显示实时的摄像头预览画面。这种功能在某些特定的应用场景下很有用,比如后台拍摄、安全应用或者是为了节省资源和提升性能。以下是对实现这一功能的详细讲解。 ...
在Android开发中,TextureView是一种可以显示动态图形的视图,它可以用来实现实时的视频流,例如摄像头预览和拍照功能。本教程将详细讲解如何利用TextureView来实现这一目标,并讨论如何优化用户界面。 首先,理解...
在Android开发中,有时我们可能需要创建一个独特的用户体验,比如设计一个圆形的相机预览窗口。这个场景就涉及到了Android的SurfaceView以及如何定制它的显示效果。本文将深入探讨如何实现一个圆形的相机预览窗口。 ...
在Android开发中,实现视频和图片的预览功能是一项常见的需求。这通常涉及到用户界面设计、多媒体处理以及性能优化等多个方面。"android 视频图片预览"这一主题,主要涵盖了以下几个关键知识点: 1. **多媒体文件...
在Android应用开发中,"附件预览效果"通常是指用户能够查看和操作各种类型的文件,如文档、图片、音频或视频等。这个过程涉及到多个关键知识点,包括文件管理、权限控制、第三方应用交互以及Android系统版本的兼容性...
本文将深入探讨如何使用`Android Studio`和`Camera2` API来实现实时预览以及拍照功能,并将照片以`.fpg`格式保存到手机中。 首先,我们需要在`build.gradle`文件中添加必要的依赖项,确保项目可以使用`Camera2` API...
Android 端本地预览 PDF 文件,使用 AS2.3.3 Gradle 4.1 下载下来可以直接编译运行,内部支持加载本地 File ,也可以加载一个 URL 类型的 PDF 文件,如果恰恰你的 APP 不想调用第三方软件的话 这个 DEMO 非常适合你...
android 8.0 webview 拍照、预览、二维码扫描比较完整的例子,对于权限检查控制,有比较完善的提示写法。可以下载后,直接在android studid上运行,编译版本和target版本均是SDK android 8.0,最低版本设置成了...
本文将深入探讨如何在Android中实现自定义相机,包括预览、拍照以及切换前后置摄像头的功能。 一、Android Camera API基础 Android提供了两个主要的相机API:Camera API1(在API level 9引入)和Camera2 API(在...
在Android平台上,有时候开发者需要实现一个功能,即在用户不知情的情况下进行拍照,这通常被称为“无预览静默拍照”。这种技术常用于自动化测试、安全监控或者后台数据获取等场景。下面我们将深入探讨如何在Android...
本文将深入探讨如何使用Camera2 API来实现预览和拍照功能。 一、Camera2 API概述 Camera2 API是Android Lollipop(API级别21)引入的,旨在提供对相机硬件更直接和全面的访问。它包含了一系列类和接口,如...
在Android平台上,开发一款应用来实现前置摄像头的预览功能,并进行实时的人脸检测与人脸区域亮度分析是一项常见的任务。这个任务涉及到多个Android系统级别的API和技术,包括Camera API、SurfaceView、OpenCV以及...
在Android开发中,自定义相机预览界面的拉伸问题是一个常见的挑战,尤其是在处理不同设备和屏幕方向变化时。本文将深入探讨这个问题,并提供解决方案。 首先,理解问题的根本原因至关重要。当我们在Android应用中...
这个“Android本地预览Excel,Word,PPT,PDF源代码”项目提供了解决这一需求的解决方案。它允许用户在不离开应用程序的情况下,在Android设备上预览这些常见办公格式的文件。 首先,我们要关注的是“asposed转Excel...
在API Level 9(Android 2.3)及更高版本中,我们可以使用`Camera`类来实现摄像头的预览、拍照和录像功能。而在API Level 14(Android 4.0)引入的`Camera2` API则提供了更高级的功能和更好的性能,但同时对设备硬件...
这个压缩包"Android图片上传,可以选择多张图片,缩放预览,拍照上传等.rar"提供了实现这一功能的具体代码示例,可以帮助开发者理解并实现在自己的项目中集成类似功能。这个功能包括了以下几个重要的知识点: 1. **...
修改Android5.0 launcher 小部件预览图片大小
在Android应用开发中,有时我们需要实现一些特殊的功能,如调用相机拍照、截取界面视图,甚至在没有用户预览的情况下进行静默拍照。这些功能在特定场景下有着广泛的应用,例如创建自定义相机应用或者需要后台拍摄的...
在Android平台上,开发一款应用程序以实现通过相机预览来捕捉并标定人脸是一项常见的任务。这个项目名为"Android通过相机预览使用原生接口捕捉人脸并取框",使用了Android Studio作为集成开发环境(IDE),并且直接...