ps:我觉得这个还是写在前面比较好。
做这个功能遇到了一个问题就是拍照后通过uri获得bitmap保存到本地特别大,压缩到50%都有10mb左右,而相机拍摄后保存到sd的照片才两三兆左右,所以就对图片进行了采样处理,宽高为800*1200,这样保存到sd的图片只有300kb~500kb,而且清晰度还可以,保存速度也比之前不处理的快很多。
最近做了一个拍照然后给照片添加时间并保存到本地的功能。一共分三步。
一、拍照
首先添加权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
然后,记得添加权限申请,这里没写。
Intent intent = new Intent((MediaStore.ACTION_IMAGE_CAPTURE)); File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
photoUri = FileProvider.getUriForFile(activity, FP_AUTHORITIES, file); //第二种方式,无需其他操作 ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath()); photoUri = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
} else { photoUri = Uri.fromFile(file); } intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); if(fragment == null) activity.startActivityForResult(intent, CODE_PHOTO); else fragment.startActivityForResult(intent,CODE_PHOTO);
其中getUriForFile()方法的第二个参数是在清单文件中添加的provider的authorities属性值
provider配置
<provider android:name="android.support.v4.content.FileProvider" android:authorities="(这里随便写)" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
file_paths添加:
这样拍照功能就写完了,拍照完成后photoUri中就会有图片的路径等信息。
二、添加时间
添加时间需要拿到bitmap对象,但是刚拍完照的照片直接拿到内存会特别大,避免内存溢出,先对图片做下采样处理,降低像素。
//采样 public static Bitmap getResizeBitmap(Uri uri, int destHeight, int destWidth) { if(uri == null) return null; //第一次采样 BitmapFactory.Options options = new BitmapFactory.Options(); //该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点 options.inJustDecodeBounds = true; //第一次加载图片,这时只会加载图片的边框进来,并不会加载图片中的像素点 BitmapFactory.decodeFile(uri.getPath(), options); //获得原图的宽和高 int outWidth = options.outWidth; int outHeight = options.outHeight; //定义缩放比例 int sampleSize = 1; while (outHeight / sampleSize > destHeight || outWidth / sampleSize > destWidth) { //如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例 //sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值 sampleSize *= 2; } /********************************************************************************************/ //至此,第一次采样已经结束,我们已经成功的计算出了sampleSize的大小 /********************************************************************************************/ //二次采样开始 //二次采样时我需要将图片加载出来显示,不能只加载图片的框架,因此inJustDecodeBounds属性要设置为false options.inJustDecodeBounds = false; //设置缩放比例 options.inSampleSize = sampleSize; options.inPreferredConfig = Config.RGB_565; //加载图片并返回 return BitmapFactory.decodeFile(uri.getPath(), options); }
然后给bitmap添加白色文字
//在bitmap右下角添加字体,默认白色 public static Bitmap getBitmapWithText(Bitmap bitmap, String text) { if(bitmap == null) return bitmap; int w = bitmap.getWidth(); int h = bitmap.getHeight(); Bitmap newBitmap = Bitmap.createBitmap(w, h, Config.RGB_565); Canvas mCanvas = new Canvas(newBitmap); // 往位图中开始画入src原始图片 mCanvas.drawBitmap(bitmap, 0, 0, null); //添加文字 TextPaint tp = new TextPaint(); tp.setTypeface(Typeface.DEFAULT); tp.setAntiAlias(true); tp.setColor(Color.WHITE); int textSize = h/10 > w/15 ? w/15 : h/10; tp.setTextSize(textSize); float textWidth = tp.measureText(text); mCanvas.drawText(text, w-textWidth-textSize, h-(textSize/2), tp); mCanvas.save(Canvas.ALL_SAVE_FLAG); mCanvas.restore(); return newBitmap; }
三、保存bitmap到sd卡
public static boolean saveBitmapToSD(Bitmap bitmap, String path) { boolean flag = false; if(bitmap == null || path == null || path.length() == 0) return flag; File file = new File(path); FileOutputStream fos = null; try { fos = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG,100,fos); fos.flush(); } catch (Exception e) { e.printStackTrace(); }finally { if(fos != null) { flag = true; try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } return flag; }
因为保存图片到sd卡可能会造成卡顿,而且项目后面用到的图片需要是处理完成的,所以这里我就用了asynctask来处理了一下。
class SaveImageAsyncTask extends AsyncTask<Void,Void,Boolean> { private Bitmap bitmap; private String path; public SaveImageAsyncTask(Bitmap bitmap, String path) { this.bitmap = bitmap; this.path = path; } @Override protected void onPreExecute() { super.onPreExecute(); showSaveImageDialog(); } @Override protected Boolean doInBackground(Void... voids) { return ImageFactory.saveBitmapToSD(bitmap,path); } @Override protected void onPostExecute(Boolean aBoolean) { super.onPostExecute(aBoolean); bitmap = null; hideSaveImageDialog(); onEditImageOver(); } }
其中的dialog自己随便写就好了。