Android调用摄像机,保存图片,添加水印,适配5.0以上版本
公司最近在做一款办公用app,需要用到拍照功能,并添加水印,国际萌新惯例先问下度娘,看了好些资料,埋了一些坑,零零散散总算整理出来了一套方案,具体引用了哪些兄台的也忘记了,总之先贡献出来,希望能帮助到可以用到的兄弟,废话不多说了,上代码先。
众所周知的清单文件权限申请走一波
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--相机所需权限--> <uses-permission android:name="android.permission.CAMERA"/>5.0以后,Android的权限申请有了新的变动,不仅要在清单文件里注册,还要进行动态的权限申请,准备了一个公共的权限动态申请的Activity,把平时能用到的权限直接一步到位全部申请了先。
public class CheckPermissionsActivity extends BaseActivity implements ActivityCompat.OnRequestPermissionsResultCallback { /** * 需要进行检测的权限数组 */ protected String[] needPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE }; private static final int PERMISSON_REQUESTCODE = 0; /** * 判断是否需要检测,防止不停的弹框 */ private boolean isNeedCheck = true; @Override protected void onResume() { super.onResume(); if (isNeedCheck) { checkPermissions(needPermissions); } } /** * @param * @since 2.5.0 */ private void checkPermissions(String... permissions) { List<String> needRequestPermissonList = findDeniedPermissions(permissions); if (null != needRequestPermissonList && needRequestPermissonList.size() > 0) { ActivityCompat.requestPermissions(this, needRequestPermissonList.toArray( new String[needRequestPermissonList.size()]), PERMISSON_REQUESTCODE); } } /** * 获取权限集中需要申请权限的列表 * * @param permissions * @return * @since 2.5.0 */ private List<String> findDeniedPermissions(String[] permissions) { List<String> needRequestPermissonList = new ArrayList<String>(); for (String perm : permissions) { if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED || ActivityCompat.shouldShowRequestPermissionRationale( this, perm)) { needRequestPermissonList.add(perm); } } return needRequestPermissonList; } /** * 检测是否说有的权限都已经授权 * * @param grantResults * @return * @since 2.5.0 */ private boolean verifyPermissions(int[] grantResults) { for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] paramArrayOfInt) { if (requestCode == PERMISSON_REQUESTCODE) { if (!verifyPermissions(paramArrayOfInt)) { showMissingPermissionDialog(); isNeedCheck = false; } } } /** * 显示提示信息 * * @since 2.5.0 */ private void showMissingPermissionDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.notifyTitle); builder.setMessage(R.string.notifyMsg); // 拒绝, 退出应用 builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startAppSettings(); } }); builder.setCancelable(false); builder.show(); } /** * 启动应用的设置 * * @since 2.5.0 */ private void startAppSettings() { Intent intent = new Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { this.finish(); return true; } return super.onKeyDown(keyCode, event); } }
第一步,xml布局走先
懒人,直接粘贴项目代码,类似“
@dimen/margen_10
”边距的话,自己设置就行了
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/margen_10" android:background="@color/white" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/margen_20" android:layout_marginTop="@dimen/margen_10" android:text="*门头照"/> <ImageView android:id="@+id/take_photos_1" android:layout_width="@dimen/photo_w" android:layout_height="@dimen/photo_h" android:layout_marginBottom="@dimen/margen_20" android:layout_marginTop="@dimen/margen_10" android:src="@drawable/selector_camera_press"/> </LinearLayout>
第二步 Activity关键性代码
public class TakePhotosActivity extends CheckPermissionsActivity implements View.OnClickListener { private ImageView photoTv1; private final static int TAKEPHOTOCODE = 110; private String sdState; private ImageView openPhotoIv; // /storage/emulated/0/pic public final static String SAVED_IMAGE_PATH1 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pic";//+"/pic"; // /storage/emulated/0/Pictures public final static String SAVED_IMAGE_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();//.getAbsolutePath()+"/pic";//+"/pic"; String photoPath; Bitmap bp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_take_photos); //获取SD卡安装状态 sdState = Environment.getExternalStorageState(); init(); } private void init() { findViewById(); setListener(); } private void findViewById() { photoTv1 = (ImageView) findViewById(R.id.take_photos_1); } private void setListener() { photoTv1.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.take_photos_1: if (sdState.equals(Environment.MEDIA_MOUNTED)) { //设置图片保存路径 photoPath = SAVED_IMAGE_PATH + "/" + System.currentTimeMillis() + ".png"; File imageDir = new File(photoPath); if (!imageDir.exists()) { //根据一个 文件地址生成一个新的文件用来存照片 try { imageDir.createNewFile(); } catch (IOException e) { e.printStackTrace(); } takePhotos(); } } else { Toast.makeText(TakePhotosActivity.this, "SD卡未插入", Toast.LENGTH_SHORT).show(); } break; } } private void takePhotos() { //考虑到安全机制的问题,Android的SDK25以后对相机调用有了新的限定,在这里要做一下处理 int currentapiVersion = android.os.Build.VERSION.SDK_INT; //根据路径实例化图片文件 File photoFile = new File(photoPath); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (currentapiVersion < 24) { //设置拍照后图片保存到文件中 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); //启动拍照activity并获取返回数据 startActivityForResult(intent, TAKEPHOTOCODE); } else { ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, photoFile.getAbsolutePath()); Uri uri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, TAKEPHOTOCODE); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == TAKEPHOTOCODE && resultCode == Activity.RESULT_OK) { File photoFile = new File(photoPath); if (photoFile.exists()) { //通过图片地址将图片加载到bitmap里面 Bitmap bm = BitmapFactory.decodeFile(photoFile.getAbsolutePath()); //添加日期水印 bp = ImageUtils.addTimeFlag(bm); //将拍摄的照片显示到界面上 photoTv1.setImageBitmap(bp); } else { Toast.makeText(TakePhotosActivity.this, "没有图片数据", Toast.LENGTH_SHORT).show(); } } } }下面放上添加水印的源码,可以抽出来直接用
public class ImageUtils { /** * 添加时间水印 * @param */ public static Bitmap addTimeFlag(Bitmap src){ // 获取原始图片与水印图片的宽与高 int w = src.getWidth(); int h = src.getHeight(); Bitmap newBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas mCanvas = new Canvas(newBitmap); // 往位图中开始画入src原始图片 mCanvas.drawBitmap(src, 0, 0, null); //添加文字 Paint textPaint = new Paint(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String time = sdf.format(new Date(System.currentTimeMillis())); textPaint.setColor(Color.RED) ; textPaint.setTextSize(100); String familyName = "宋体"; // Typeface typeface = Typeface.create(familyName, // Typeface.BOLD_ITALIC); // textPaint.setTypeface(typeface); // textPaint.setTextAlign(Align.CENTER); mCanvas.drawText(time, (float)(w*1)/7, (float)(h*14)/15, textPaint); mCanvas.save(Canvas.ALL_SAVE_FLAG); mCanvas.restore(); return newBitmap ; } }知道你们想看效果,正所谓没图说个xx啊!来张效果图