文档章节

如何使用Android MediaStore裁剪大图片

yolinfeng
 yolinfeng
发布于 2015/05/04 16:02
字数 1414
阅读 34
收藏 0

这篇文章相当经典而实用,想当初我做手机拍照截图的时候,大多都是在网上抄来抄去的内容,从来没有人考虑过实际项目中的需求。实际上,拍照传大图片,如果用普通方式会耗用极大的内存,Android一个App原则上的16M内存限制可以一下子被耗光。Android在拍照上有一个隐藏的设计,如果拍照图片过大,只返回一张缩略图。具体到不同手机,都是不一样的。

-------------------------------------------------------------------------------------

译文:

概述

我写这篇文章是为了发表我对MediaStore裁剪图片功能的一些简要研究。基本上,如果你要写一个应用程序,使用已有的Media Gallery并允许用户在你的应用里选取TA的图片的一部分(可选功能:人脸识别)。 可以使用一个Intent做到这个,但是也存在着相应的问题,总的来说也缺少这方面的文档告诉我们怎么实现它。 另外,这篇文章基于2.1并且在Nexus One上做了测试。 Nexus One上的实现似乎被这群人写在了这里: Media Gellery for Nexus One 。

反馈

这篇文章需要使用基于我的研究所写的程序。如果你对我推荐的实现方案有所改进,请让我知道。我会相应的更新这篇文章。

Intent细节

首先,让我们探讨下Intent以及它的特点。在看了一些代码示例以后,我发现我可以很轻松的使用如下的Intent调用裁剪功能:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType(“image/*”);
intent.putExtra(“crop”, “true”);

然而,这是在我缺少附加的文档,不知道这些选项的具体含义等等情况之下的选择。所以,我将我的yanj整理成一个表格 ,并写了一个演示程序,力图演示控制此功能的所有可供选项。

你可以在你的程序中使用使用我的代码,并且扩展它。我会将之附加在这篇文章上。

Exta Options Table for image/* crop:

附加选项 数据类型 描述
crop String 发送裁剪信号
aspectX int X方向上的比例
aspectY int Y方向上的比例
outputX int 裁剪区的宽
outputY int 裁剪区的高
scale boolean 是否保留比例
return-data boolean 是否将数据保留在Bitmap中返回
data Parcelable 相应的Bitmap数据
circleCrop String 圆形裁剪区域?
MediaStore.EXTRA_OUTPUT ("output") URI 将URI指向相应的file:///...,详见代码示例

现在,最令人困惑的是MediaStore.EXTRA_OUTPUT以及return-data选项。

你主要有两种方式从这个Intent中取得返回的bitmap:获取内部数据或者提供一个Uri以便程序可以将数据写入。

方法1:如果你将return-data设置为“true”,你将会获得一个与内部数据关联的Action,并且bitmap以此方式返回:(Bitmap)extras.getParcelable("data")。注意:如果你最终要获取的图片非常大,那么此方法会给你带来麻烦,所以你要控制outputX和outputY保持在较小的尺寸。鉴于此原因,在我的代码中没有使用此方法((Bitmap)extras.getParcelable("data"))。

下面是CropImage.java的源码片段:

// Return the cropped image directly or save it to the specified URI.
Bundle myExtras = getIntent().getExtras();
if (myExtras != null && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data")))
{
    Bundle extras = new Bundle();
    extras.putParcelable("data", croppedImage);
    setResult(RESULT_OK,(new Intent()).setAction("inline-data").putExtras(extras));
    finish();
}

方法2: 如果你将return-data设置为“false”,那么在onActivityResult的Intent数据中你将不会接收到任何Bitmap,相反,你需要将MediaStore.EXTRA_OUTPUT关联到一个Uri,此Uri是用来存放Bitmap的。

但是还有一些条件,首先你需要有一个短暂的与此Uri相关联的文件地址,当然这不是个大问题(除非是那些没有sdcard的设备)。

下面是CropImage.java关于操作Uri的源码片段:

if (mSaveUri != null) {
    OutputStream outputStream = null;
    try {
        outputStream = mContentResolver.openOutputStream(mSaveUri);
        if (outputStream != null) {
            croppedImage.compress(mOutputFormat, 75, outputStream);
        }
    } catch (IOException ex) {
        // TODO: report error to caller
        Log.e(TAG, "Cannot open file: " + mSaveUri, ex);
    } finally {
        Util.closeSilently(outputStream);
    }
    Bundle extras = new Bundle();
    setResult(RESULT_OK, new Intent(mSaveUri.toString()).putExtras(extras));
}

代码示例:

我已经附上了一些代码示例,应该可以让你测试多种配置。请让我知道它对你是否有用。

代码下载: MediaStoreTest

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2012年资料/11月/11日/如何使用Android MediaStore裁剪大图片

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 thiz = this;
 setContentView(R.layout.main);
 mBtn = (Button) findViewById(R.id.btnLaunch);
 photo = (ImageView) findViewById(R.id.imgPhoto);
 mBtn.setOnClickListener(new OnClickListener() {

  public void onClick(View v) {
   try {
    // Launch picker to choose photo for selected contact
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
    intent.setType("image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", aspectX);
    intent.putExtra("aspectY", aspectY);
    intent.putExtra("outputX", outputX);
    intent.putExtra("outputY", outputY);
    intent.putExtra("scale", scale);
    intent.putExtra("return-data", return_data);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
    intent.putExtra("outputFormat",
      Bitmap.CompressFormat.JPEG.toString());  

      intent.putExtra("noFaceDetection", !faceDetection);
    if (circleCrop) {
     intent.putExtra("circleCrop", true);
    }

    startActivityForResult(intent, PHOTO_PICKED);
   } catch (ActivityNotFoundException e) {
    Toast.makeText(thiz, R.string.photoPickerNotFoundText,
      Toast.LENGTH_LONG).show();
   }
  }
 });

}

private Uri getTempUri() {
 return Uri.fromFile(getTempFile());
}

private File getTempFile() {
 if (isSDCARDMounted()) {

  File f = new File(Environment.getExternalStorageDirectory(),
    TEMP_PHOTO_FILE);
  try {
   f.createNewFile();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   Toast.makeText(thiz, R.string.fileIOIssue, Toast.LENGTH_LONG)
     .show();
  }
  return f;
 } else {
  return null;
 }
}

private boolean isSDCARDMounted() {
 String status = Environment.getExternalStorageState();

 if (status.equals(Environment.MEDIA_MOUNTED))
  return true;
 return false;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 super.onActivityResult(requestCode, resultCode, data);

 switch (requestCode) {
 case PHOTO_PICKED:
  if (resultCode == RESULT_OK) {
   if (data == null) {
    Log.w(TAG, "Null data, but RESULT_OK, from image picker!");
    Toast t = Toast.makeText(this, R.string.no_photo_picked,
      Toast.LENGTH_SHORT);
    t.show();
    return;
   }

   final Bundle extras = data.getExtras();
   if (extras != null) {
    File tempFile = getTempFile();
    // new logic to get the photo from a URI
    if (data.getAction() != null) {
     processPhotoUpdate(tempFile);
    }
   }
  }
  break;
 }
}

本文转载自:http://www.linuxidc.com/Linux/2012-11/73939.htm

yolinfeng
粉丝 12
博文 196
码字总数 11946
作品 0
珠海
架构师
私信 提问
Android大图片裁剪终极解决方案(中:从相册截图)

转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86853 在这篇博客中,我将向大家展示如何从相册截图。 ...

RyanHoo
2012/11/03
1.6W
14
Android大图片裁剪终极解决方案(下:拍照截图)

转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86865 上一篇博客中,我们学习到了如何使用Android相册...

RyanHoo
2012/11/03
1.6W
11
Android大图片裁剪终极解决方案(上:原理分析)

转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正为公司的APP在Android手机上实现...

RyanHoo
2012/11/03
2W
11
【译】如何使用Android MediaStore裁剪大图片

转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86843 译者:Ryan Hoo 来源:http://www.androidworks...

RyanHoo
2012/11/03
9.6K
2
Android大图片裁剪解决方案

截图原理 在Android中,Intent触发Camera程序,拍好照片后,将会返回数据,但是考虑到内存问题,Camera不会将全尺寸的图像返回给调用的Activity,一般情况下,有可能返回的是缩略图,比如120...

今日竹石
2014/04/15
398
0

没有更多内容

加载失败,请刷新页面

加载更多

六、Spring Cloud之配置中心config

前言 前面我们讲了微服务的注册中心、负载均衡、熔断处理、网管服务。接下来我们讲配置中心,为什么要用配置中心呢? 其实我们接触一段时间就可以发现,我们的项目还是非常多的,每个项目都有...

quellanan2
4分钟前
13
0
在Android的EditText视图中允许多行?

如何在Android的EditText视图中允许多行? #1楼 这对我有用 ,实际上这两个属性很重要: inputType和lines 。 此外,您可能需要一个滚动条,下面的代码显示了如何制作一个: <EditText ...

技术盛宴
8分钟前
13
0
分享自己写的JS版日期格式化和解析工具类,绝对好用!

前言 本来想模仿Java里面的SimpleDateFormat()对象的,但是感觉这样用起来不方便,所以还是直接写成单独的方法算了。 原文链接 日期格式化 2.1. 使用说明 formatDate(date, fmt),其中fmt支持...

SuShine
18分钟前
27
0
快递鸟api物流查询接口实现订阅物流轨迹单号查询功能对接调用

背景: 分享一篇关于在电商系统中同步物流轨迹到本地服务器的文章,当前方案使用了快递鸟集成api做为数据来源接口,这个接口是免费使用的,不过提供的功能还是非常强大的,有专门的售后维护团...

程序的小猿
22分钟前
24
0
Day08多态,abstract,接口

1.A:多态的概述:事物存在的多种形态。 B:多态前提:要有继承关系,方法重写和父类引用子类对象。 父类引用子类对象:Animal a = new Cat(); a.eat(); //效果等同于c.eat(); 2.多态中的...

Lao鹰
28分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部