本文链接    http://blog.csdn.net/xiaodongrush/article/details/29173567

參考链接    http://stackoverflow.com/questions/12758425/how-to-set-the-output-image-use-com-android-camera-action-crop

1. 缘起

要开发一个头像上传的模块。头像上传过程分两步。

第一步。相机拍照或者从图库选取照片。产生一个照片,第二步,提供头像剪裁,通常是剪裁为方形的。第三步,上传头像。删除不必要的缓存文件。

    拍照和图库选择照片都能够使用系统的方案。

自制相机能够搞滤镜,这个开发成本比較大,一般的APP也不用支持。

图库选择照片这个能够自己做,訪问sd卡。比較简单。问题出在图片剪裁上。网上有一些技术方案,迁移过来之后。效果不好,比方缩放的敏感度问题,缩放之后剪裁不准确的问题,缩放不流畅的问题。后来发现使用com.android.camera.action.CROP能够调用系统剪裁页面。可是该页面不是官方公开的页面,所以,某些厂商可能不支持这个。

T_T。

    看了下几款APP的头像截取,QQ、微信和易信都是自己做的。效果也不是非常好,360手机助手是调用的系统的。

系统的截取比較流畅,效果较好,除了前面的隐患,另一个问题就是,在一些定制手机上面。剪裁的页面总体比較暗,或者上面有一层阴影。当然剪裁完之后图片是正常的。

     考虑到360手机助手用户量这么大的APP,也在使用系统剪裁,所以我们也考虑使用系统剪裁。假设发现系统剪裁不可用,再调用自己的剪裁。

2. 拍照代码

这里用了MediaStore.EXTRA_OUTPUT,拍照图像不会通过intnet返回,要通过uri来读取,这样可以读小一点的图像进来。假设不这样。系统会在intent里面返回一个压缩图片,这个压缩的图像有多大不是可以控制的,所以可能比較大。

Intent newIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
newIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(newIntent, REQUEST_CODE_TAKE_PHOTO);

3. 方形剪裁

这里的代码与拍照类似,也用了MediaStore.EXTRA_OUTPUT,处理结果要通过路径来读取。

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true"); // 开启剪裁
intent.putExtra("aspectX", 1); // 宽高比例
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 150); // 宽高
intent.putExtra("outputY", 150);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mOutputFile.getAbsoluteFile() + "tmp")));
startActivityForResult(intent, REQUEST_CODE_CLIP_PHOTO);

4. 相对完整的代码

代码下载链接,内附APK    http://download.csdn.net/detail/u011267546/7460367

public class MainActivity extends Activity {

    private static final int REQUEST_CODE_TAKE_PHOTO = 0;

    private static final int REQUEST_CODE_CLIP_PHOTO = 1;

    private File mOutputFile;

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout. activity_main);
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_TAKE_PHOTO) {
onTakePhotoFinished(resultCode, data);
} else if (requestCode == REQUEST_CODE_CLIP_PHOTO ) {
onClipPhotoFinished(resultCode, data);
}
} public void onClick(View v) {
if (v.getId() == R.id.take_photo) {
if (hasCarema() == false) {
return;
}
takePhoto();
}
} private boolean hasCarema() {
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA )
&& !pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT )) {
Toast. makeText(this, "no camera found", Toast.LENGTH_SHORT).show();
return false ;
}
return true ;
} private void takePhoto() {
String sdPath = Environment.getExternalStorageDirectory()
.getAbsolutePath();
mOutputFile = new File(sdPath, System.currentTimeMillis() + ".tmp");
Uri uri = Uri. fromFile(mOutputFile);
Intent newIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
newIntent.putExtra(MediaStore. EXTRA_OUTPUT, uri);
startActivityForResult(newIntent, REQUEST_CODE_TAKE_PHOTO );
} private void onTakePhotoFinished(int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED) {
Toast. makeText(this, "take photo canceled", Toast.LENGTH_SHORT)
.show();
return;
} else if (resultCode != RESULT_OK) {
Toast. makeText(this, "take photo failed", Toast.LENGTH_SHORT)
.show();
} else {
clipPhoto(Uri. fromFile(mOutputFile));
}
} // http://www.xuanyusong.com/archives/1743
private void clipPhoto(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP" );
intent.setDataAndType(uri, "image/*");
// 以下这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra( "crop", "true" );
// aspectX aspectY 是宽高的比例
intent.putExtra( "aspectX", 1);
intent.putExtra( "aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra( "outputX", 150);
intent.putExtra( "outputY", 150);
intent.putExtra(MediaStore. EXTRA_OUTPUT,
Uri. fromFile(new File(mOutputFile.getAbsoluteFile() + "tmp" )));
startActivityForResult(intent, REQUEST_CODE_CLIP_PHOTO );
} private void onClipPhotoFinished(int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED) {
Toast. makeText(this, "clip photo canceled", Toast.LENGTH_SHORT)
.show();
return;
} else if (resultCode != RESULT_OK) {
Toast. makeText(this, "take photo failed", Toast.LENGTH_SHORT)
.show();
}
Bitmap bm = BitmapFactory.decodeFile(mOutputFile.getAbsolutePath()
+ "tmp");
ImageView photoIv = (ImageView) findViewById(R.id.photo );
photoIv.setImageBitmap(bm);
}
}

5. 效果图

献上可爱的大熊熊,仅仅截取大熊的上半身。

Android拍照+方形剪裁——附代码与效果图的更多相关文章

  1. Android | 教你如何用代码开发一个拍照翻译小程序

    引子   想必有很多小伙伴喜欢外出旅游,能去海外玩一圈那是更好不过了,旅游前大家一定会对吃.穿.住.行.游玩路线做各种攻略,然后满怀期待的出发- 想象中的旅游   出发前,想象中的旅游目的地可能有漂亮 ...

  2. [Android] 拍照、截图、保存并显示在ImageView控件中

    近期在做Android的项目,当中部分涉及到图像处理的内容.这里先讲述怎样调用Camera应用程序进行拍照,并截图和保存显示在ImageView控件中以及遇到的困难和解决方法.     PS:作者购买 ...

  3. 球体的双目视觉定位(matlab,附代码)

    球体的双目视觉定位(matlab,附代码) 标签(空格分隔): 机器视觉 引言 双目视觉定位是我们的一个课程设计,最近刚做完,拿出来与大家分享一下,实验的目的是在拍摄的照片中识别球体,并求出该球体到相 ...

  4. 一站式解决,Android 拍照 图库的各种问题.

    在android开发中, 在一些编辑个人信息的时候,经常会有头像这么一个东西,就两个方面,调用系统相机拍照,调用系统图库获取图片.但是往往会遇到各种问题: 1.oom 2.图片方向不对 3.activ ...

  5. Android JUnit Test——批量运行测试代码

    转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ Android测试三要素 写Android测试用例有三要素,一是我们用的“安卓模拟器device” ...

  6. 我的Android进阶之旅------>Android拍照小例子

    今天简单的学习了一下android拍照的简单实现. 当然该程序是个小例子,非常简单,没有什么复杂的操作,但是可以学习到Android 拍照API流程. 1.在布局文件中添加一个 surfaceView ...

  7. android——拍照,相册图片剪切其实就这么简单

    接触android这么久了.还没有真正的浩浩看看android拍照,相册图片剪切到底是怎么回事,每次都是从别人的代码一扣,就过来了.其实,谷歌提供的API已经很强大.只需要用的好,就那么几句就可以搞定 ...

  8. Android Permission denied 错误 ( 附Android权限大全 )

    Android Permission denied 错误(附Android权限大全) java.net.SocketException: Permission denied (maybe missin ...

  9. 简单的 Android 拍照并显示以及获取路径后上传

    简单的 Android 拍照并显示以及获取路径后上传 Activity 中的代码,我只贴出重要的事件部分代码 public void doPhoto(View view) { destoryBimap ...

随机推荐

  1. OBD-II Protocol -- SAE J1850 VPW PWM

    http://www.auto-diagnostics.info/j1850 j1850 The SAE J1850 bus bus is used for diagnostics and data ...

  2. oracle存储过程获取异常信息码和异常信息

    oracle存储过程,可以通过sqlcode 获取异常编码.通过sqlerrm获取异常信息. 例子: create or replace procedure write2blob(p_id in nu ...

  3. MyBatis接口的简单实现原理

    MyBatis接口的简单实现原理 用过MyBatis3的人可能会觉得为什么MyBatis的Mapper接口没有实现类,但是可以直接用? 那是因为MyBatis使用Java动态代理实现的接口. 这里仅仅 ...

  4. hdu1015 Safecracker (暴力枚举)

    http://acm.hdu.edu.cn/showproblem.php?pid=1015 Safecracker Time Limit: 2000/1000 MS (Java/Others)    ...

  5. inux下查看.so和可执行文件是否debug编译的方法

    命令 readelf -S libxxx.so |grep debug   如果有打印信息就是debug,否则是release.

  6. Canavs arcTo方法的理解

    arcTo方法有四个參数 參数1,2为第一个控制点的x,y坐标,參数2为第二个控制点的坐标,參数3为绘制圆弧的半径. 起点和第一个控制点组成的延长线与第一个控制点和第二个控制点组成的延长线都是和圆弧相 ...

  7. Latex Error cannot determine the size of graphic 报错的解决的方法

    Latex Error cannot determine the size of graphic 报错的解决的方法 插入jpg文件老是会报错... 追究了半天,原来是编译的命令又问题,不应该使用 la ...

  8. mount nfs 经常出错信息总结(转)

    通常当NFS不能正常使用时候会给出提示,一般给出一下几种: 1)mount: 192.168.1.111:/opt failed, reason given by server: Permission ...

  9. SimpleDateFormat in Java is not Thread-Safe Use Carefully

    SimpleDateFormat in Java  very common and used to format Date to String and parse String into Date i ...

  10. 通过使用第三方开源jar包sigar.jar我们可以获得本地的信息

    1.下载sigar.jar sigar官方主页 sigar-1.6.4.zip 2.按照主页上的说明解压包后将相应的文件copy到java路径.比如windows32位操作系统需要将lib中sigar ...