多媒体——图片——对图片进行简单加工
当图像视图的缩放类型为fitCenter时,如果图片的尺寸超过4096*4096,App运行会崩溃。
若想解决加载超大图片的问题,有下列几种方案:
(1)在显示图片之前调用setLayerType方法,将图层类型设置为软件加速,此时系统会对该视图关闭硬件加速。
(2)把图像视图的缩放类型改为center,表示保持图片的原尺寸并居中显示。
(3)缩放类型保持fitCenter,同时事先缩小位图的尺寸,直至新位图的宽高均不超过4096。
权限:
<!-- 相机 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 录音 --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 存储卡读写 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
布局:
<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/btn_choose" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="打开相册选取照片" android:textColor="@color/black" android:textSize="17sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:orientation="horizontal" android:layout_marginLeft="5dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="缩放比率:" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_scale" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:spinnerMode="dialog" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="旋转角度:" android:textColor="@color/black" android:textSize="17sp" /> <Spinner android:id="@+id/sp_rotate" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:spinnerMode="dialog" /> </LinearLayout> <ImageView android:id="@+id/iv_photo" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="center" /> </LinearLayout>
item_select.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="50dp" android:singleLine="true" android:gravity="center" android:textSize="17sp" android:textColor="#0000ff" />
代码:
package com.example.myapplication; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; import com.example.myapplication.util.BitmapUtil; import java.io.InputStream; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private final static String TAG = "ImageChangeActivity"; private ImageView iv_photo; // 声明一个图像视图对象 private Bitmap mBitmap; // 声明一个位图对象 private Uri mImageUri; // 图片的路径对象 private int CHOOSE_CODE = 3; // 选择照片的请求码 private float mDegree; // 旋转角度 private float mRatio; // 缩放比例 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iv_photo = findViewById(R.id.iv_photo); findViewById(R.id.btn_choose).setOnClickListener(this); initScaleSpinner(); // 初始化缩放比率下拉框 initRotateSpinner(); // 初始化旋转角度下拉框 } @Override public void onClick(View v) { if (v.getId() == R.id.btn_choose) { // 创建一个内容获取动作的意图(准备跳到系统相册) Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT); albumIntent.setType("image/*"); // 设置内容类型为图像 startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册 } } // 初始化缩放比率下拉框 private void initScaleSpinner() { ArrayAdapter<String> scaleAdapter = new ArrayAdapter<String>(this, R.layout.item_select, scaleArray); Spinner sp_scale = findViewById(R.id.sp_scale); sp_scale.setPrompt("请选择缩放比率"); sp_scale.setAdapter(scaleAdapter); sp_scale.setOnItemSelectedListener(new ScaleSelectedListener()); sp_scale.setSelection(0); } private String[] scaleArray = {"1.0", "0.5", "0.2", "0.10", "0.05", "0.01"}; class ScaleSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { mRatio = Float.parseFloat(scaleArray[arg2]); showChangedImage(); // 显示变更后的图像 } public void onNothingSelected(AdapterView<?> arg0) {} } // 初始化旋转角度下拉框 private void initRotateSpinner() { ArrayAdapter<String> rotateAdapter = new ArrayAdapter<String>(this, R.layout.item_select, rotateArray); Spinner sp_rotate = findViewById(R.id.sp_rotate); sp_rotate.setPrompt("请选择旋转角度"); sp_rotate.setAdapter(rotateAdapter); sp_rotate.setOnItemSelectedListener(new RotateSelectedListener()); sp_rotate.setSelection(0); } private String[] rotateArray = {"0", "45", "90", "135", "180", "225", "270", "315"}; class RotateSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { mDegree = Integer.parseInt(rotateArray[arg2]); showChangedImage(); // 显示变更后的图像 } public void onNothingSelected(AdapterView<?> arg0) {} } // 显示变更后的图像 private void showChangedImage() { if (mBitmap != null) { // 获得缩放后的位图对象 Bitmap bitmap = BitmapUtil.getScaleBitmap(mBitmap, mRatio); // 获得旋转后的位图对象 bitmap = BitmapUtil.getRotateBitmap(bitmap, mDegree); iv_photo.setImageBitmap(bitmap); // 设置图像视图的位图对象 } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { if (intent.getData() != null) { // 从相册选择一张照片 mImageUri = intent.getData(); // 打开指定uri获得输入流对象 try (InputStream is = getContentResolver().openInputStream(mImageUri)) { // 从输入流解码得到原始的位图对象 mBitmap = BitmapFactory.decodeStream(is); iv_photo.setImageBitmap(mBitmap); // 设置图像视图的位图对象 } catch (Exception e) { e.printStackTrace(); } Log.d(TAG, "uri.getPath="+mImageUri.getPath()+",uri.toString="+mImageUri.toString()); } } } }
BitmapUtil
package com.example.myapplication.util; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.net.Uri; import android.util.Log; import java.io.InputStream; public class BitmapUtil { private final static String TAG = "BitmapUtil"; // 获得旋转角度之后的位图对象 public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) { Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象 matrix.postRotate(rotateDegree); // 执行图片的旋转动作 // 创建并返回旋转后的位图对象 return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); } // 获得比例缩放之后的位图对象 public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) { int new_width = (int) (bitmap.getWidth() * scaleRatio); int new_height = (int) (bitmap.getHeight() * scaleRatio); // 创建并返回缩放后的位图对象 return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false); } // 获得自动缩小后的位图对象 public static Bitmap getAutoZoomImage(Context ctx, Uri uri) { Log.d(TAG, "getAutoZoomImage uri="+uri.toString()); Bitmap zoomBitmap = null; // 打开指定uri获得输入流对象 try (InputStream is = ctx.getContentResolver().openInputStream(uri)) { // 从输入流解码得到原始的位图对象 Bitmap originBitmap = BitmapFactory.decodeStream(is); int ratio = originBitmap.getWidth()/2000+1; // 获得比例缩放之后的位图对象 zoomBitmap = BitmapUtil.getScaleBitmap(originBitmap, 1.0/ratio); } catch (Exception e) { e.printStackTrace(); } return zoomBitmap; } }