从相册去图片
调用相机拍照
图片的压缩
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_fith"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="相册" />
<Button
android:id="@+id/button_camber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="相机" />
<ImageView
android:id="@+id/iv"
android:layout_width="250dp"
android:layout_height="250dp" />
</LinearLayout>
代码
public class MainActivity extends AppCompatActivity {
public static final int CAMERA = 1;
public static final int PHONE = 2;
private ImageView iv;
private Uri imageuri;
private File outPutImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button photo = (Button) findViewById(R.id.button_fith);
Button camera = (Button) findViewById(R.id.button_camber);
iv = (ImageView) findViewById(R.id.iv);
photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
openAibum();
}
}
});
assert camera != null;
camera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建File对象,用于存储拍照后的图片
outPutImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outPutImage.exists()) {
outPutImage.delete();
}
outPutImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= 24) {//
imageuri = FileProvider.getUriForFile(MainActivity.this,
"com.example.cameraalbumtest.fileprovider", outPutImage);
} else {
imageuri = Uri.fromFile(outPutImage);
}
//启动相机
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageuri);
startActivityForResult(intent, CAMERA);
}
});
}
/**
* 打开相册
*/
private void openAibum() {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, PHONE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAibum();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case PHONE:
if (resultCode == RESULT_OK) {
if (Build.VERSION.SDK_INT >= 19) {
handleImageKitKat(data);
} else {
handleImageBeforeKitKat(data);
}
}
break;
case CAMERA:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageuri));
iv.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
/**
* 大于= API 19 de
*
* @param data
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private void handleImageKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
if (DocumentsContract.isDocumentUri(this, uri)) {
//如果是document 类型的URI,则通过document Id处理;
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1];//解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagetPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagetPath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
imagePath = getImagetPath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
imagePath = uri.getPath();
}
Log.d("TAG", "imagePath" + imagePath);
displayImage(imagePath);//根据图片路径显示图片
}
/**
* * 小于 API 19 de
*
* @param data
*/
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagetPath(uri, null);
Log.d("TAG", "imagePath" + imagePath);
displayImage(imagePath);//根据图片路径显示图片
}
private String getImagetPath(Uri uri, String selection) {
String path = null;
//通过Uri和selection来获取真实的图片路径
Cursor cuesor = getContentResolver().query(uri, null, selection, null, null);
if (cuesor != null) {
if (cuesor.moveToFirst()) {
path = cuesor.getString(cuesor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cuesor.close();
}
return path;
}
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
Log.d("TAG1", "bitmap压缩前占用空间大小:" + bitmap.getByteCount() / 1024 / 1024 + "M"
+ " 宽:" + bitmap.getWidth() + " 高:" + bitmap.getHeight());
qualityCompression(bitmap, 30);
SamplingRateCompression(imagePath);
matrixCompression(bitmap);
geshiCompression(imagePath);
createScaledBitmapCompression(bitmap);
iv.setImageBitmap(bitmap);
Log.d("TAG", "bitmap:" + bitmap);
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
/**
* 可以用图片框架加载
* @param imagePath
*/
private void displayImage1(String imagePath) {
if (imagePath != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath,options);
int outHeight = options.outHeight;
int outWidth = options.outWidth;
options.inJustDecodeBounds = false;
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
/**
* 中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小,首先要知道bitmap所占内存大小计算方式:
图片长度 x 图片宽度 x 一个像素点占用的字节数
以下是图片的压缩格式:
这里写图片描述
其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。
ALPHA_8
表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度
ARGB_4444
表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节
ARGB_8888
表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节
RGB_565
表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节
可以看到,图片的大小是没有变的,因为质量压缩不会减少图片的像素,它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,这也是为什么该方法叫质量压缩方法。那么,图片的长,宽,像素都不变,那么bitmap所占内存大小是不会变的。
但是我们看到bytes.length是随着quality变小而变小的。这样适合去传递二进制的图片数据,比如微信分享图片,要传入二进制数据过去,限制32kb之内。
这里要说,如果是bit.compress(CompressFormat.PNG, quality, baos);这样的png格式,quality就没有作用了,bytes.length不会变化,因为png图片是无损的,不能进行压缩。
*/
/**
* 质量压缩
*
* @param bitmap
* @param quality 30 压缩70%
*/
private void qualityCompression(Bitmap bitmap, int quality) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
byte[] bytes = baos.toByteArray();
Bitmap bit = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Log.d("TAG1", "压缩后图片的大小:" + (bit.getByteCount() / 1024 / 1024)
+ "M 宽度为:" + bit.getWidth() + " 高度为:" + bit.getHeight()
+ " bytes.length:" + (bytes.length / 1024) + "KB"
+ " 压缩率:" + quality);
}
/**
* 设置inSampleSize的值(int类型)后,假如设为2,则宽和高都为原来的1/2,宽高都减少了,自然内存也降低了。
我上面的代码没用过options.inJustDecodeBounds = true; 因为我是固定来取样的数据,为什么这个压缩方法叫采样率压缩,是因为配合inJustDecodeBounds,先获取图片的宽、高【这个过程就是取样】,然后通过获取的宽高,动态的设置inSampleSize的值。
当inJustDecodeBounds设置为true的时候,BitmapFactory通过decodeResource或者decodeFile解码图片时,将会返回空(null)的Bitmap对象,这样可以避免Bitmap的内存分配,但是它可以返回Bitmap的宽度、高度以及MimeType。
*/
/**
* 采样率压缩
* @param imagePath
*/
private void SamplingRateCompression(String imagePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bit = BitmapFactory.decodeFile(imagePath, options);
Log.d("TAG1", "压缩后图片的大小:" + (bit.getByteCount() / 1024 / 1024)
+ "M 宽度为:" + bit.getWidth() + " 高度为:" + bit.getHeight());
}
/**
* 可以看出来,bitmap的长度和宽度分别缩小了一半,图片大小缩小了四分之一。
* 缩放法压缩
* @param bitmap
*/
private void matrixCompression(Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 0.5f);
Bitmap bit = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
Log.d("TAG1", "压缩后图片的大小:" + (bit.getByteCount() / 1024 / 1024)
+ "M 宽度为:" + bit.getWidth() + " 高度为:" + bit.getHeight());
}
/**
* 我们看到图片大小直接缩小了一半,长度和宽度也没有变,相比argb_8888减少了一半的内存。
注意:由于ARGB_4444的画质惨不忍睹,一般假如对图片没有透明度要求的话,可以改成RGB_565,相比ARGB_8888将节省一半的内存开销
* .RGB_565法
* @param imagePath
*/
private void geshiCompression(String imagePath) {
BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bit = BitmapFactory.decodeFile(imagePath, options2);
Log.d("TAG1", "压缩后图片的大小:" + (bit.getByteCount() / 1024 / 1024)
+ "M 宽度为:" + bit.getWidth() + " 高度为:" + bit.getHeight());
}
private void createScaledBitmapCompression(Bitmap bitmap) {
Bitmap bit = Bitmap.createScaledBitmap(bitmap, 150, 150, true);
Log.d("TAG1", "压缩后图片的大小:" + (bit.getByteCount() / 1024 )
+ "k 宽度为:" + bit.getWidth() + " 高度为:" + bit.getHeight());
}
}
适配7.0 FileUriExposeException 异常 https://blog.csdn.net/qq_35698774/article/details/107007405
权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
转发表明出处:https://blog.csdn.net/qq_35698774/article/details/74358793
android互助群:
感谢:郭霖的《第一行代码 第二版》