一份完整的拍照后加水印代码
大家好,好久没有写博客了,因为公司需要,所以最近有在学习Java后台方面的一些知识。虽然在学后台,但是安卓积累也是木有放下滴,今天我想分享一下拍照后给照片加水印这样一个小功能的实现。首先镇博图奉上:
就简单的实现了下拍完照片后在照片的左上角打上拍照时的时间,后续也可以加其他一些信息,操作都是一样。在上代码之前首先要贴出我参考的其他大神的成果链接
图片加水印工具类:http://blog.csdn.net/dawanganban/article/details/51148070
大神封装的这个工具类还有里面的描述非常的详细,在此作为一枚安卓小菜的我灰常感谢大神的分享。但是在使用过程中我发现如果操作同一张图片的时候在任何一款手机上效果都非常好,如果是拍完照片后操作拍摄的这张照片的话,会出现一点点的不完美,因为现在的安卓手机像素差别非常大,所以拍出的照片高清,超清,标清各种效果。可以给大家看一下我做适配的两款效果
这是我用公司的华为TAG_AL00拍的图片,大家可以看一下他的图片大小,然后我用乐视在拍一张照片,比较一下拍出图片的大小
差距还是挺大的有木有,正是因为有这样的差距然后你用大神封装的工具类的时候会出现加的图片或是文字在不同的图片上显示的效果会差别很大。接下来就是小菜我在大神的基础上做文章了,其实在工具类里面已经有一个可以解决这个问题的方法了,只是好像在添加的时候那个方法没有被调用而已,有木有发现是那个方法,就是它:
/**
* 缩放图片
* @param src
* @param w
* @param h
* @return
*/
public static Bitmap scaleWithWH(Bitmap src, double w, double h) {
if (w == 0 || h == 0 || src == null) {
return src;
} else {
// 记录src的宽高
int width = src.getWidth();
int height = src.getHeight();
// 创建一个matrix容器
Matrix matrix = new Matrix();
// 计算缩放比例
float scaleWidth = (float) (w / width);
float scaleHeight = (float) (h / height);
// 开始缩放
matrix.postScale(scaleWidth, scaleHeight);
// 创建缩放后的图片
return Bitmap.createBitmap(src, 0, 0, width, height, matrix, true);
}
}
怎么调用呢,我的思路是缩放成和屏幕宽高的图片然后在图片上面进行加水印,代码修改如下:
/** * 缩放图片 * @param src * @param w * @param h * @return */ public static Bitmap scaleWithWH(Context context,Bitmap src, double w, double h) { if (w == 0 || h == 0 || src == null) { return src; } else { // 记录src的宽高 int width = src.getWidth(); int height = src.getHeight(); // 创建一个matrix容器 Matrix matrix = new Matrix(); // 计算缩放比例 WindowManager wm = (WindowManager) (context.getSystemService(Context.WINDOW_SERVICE)); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); float scaleWidth=(dm.widthPixels/(float)width); float scaleHeight=(dm.heightPixels/(float)height); /*float scaleWidth = (float) (w / width); float scaleHeight = (float) (h / height);*/ // 开始缩放 matrix.postScale(scaleWidth, scaleHeight); // 创建缩放后的图片 return Bitmap.createBitmap(src, 0, 0, width, height, matrix, true); } }在给图片加水印之前调用该方法即可。(获取屏幕的宽高一般是放在在一个项目的开始工作中,我这样写仅仅是为了实现效果)切记调用该方法时宽度和高度不能传0,原因应该都懂的。另外我用了另外一种对图片的压缩方法,具体喜欢用那个看大家自己认为的了,下面附上我的完整代码:
首先布局文件activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="sangu.com.picwartermartest.MainActivity"> <TextView android:id="@+id/textView" android:layout_width="0dp" android:layout_height="50dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:text="拍照" android:gravity="center" android:textAppearance="@style/TextAppearance.AppCompat.Button" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp" /> <ImageView android:id="@+id/imageView" android:layout_width="0dp" android:layout_height="0dp" app:srcCompat="@mipmap/ic_launcher" android:layout_marginRight="5dp" app:layout_constraintRight_toRightOf="parent" android:layout_marginLeft="5dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp" android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/textView" /> </android.support.constraint.ConstraintLayout>很简单的一个拍照按钮和一个显示图片的控件,接下来是MainActivity的代码,对于ConstraintLayout布局的编辑我还是比较喜欢直接拖拽那种
import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; public class MainActivity extends AppCompatActivity { private static final int TAKE_PICTURE = 520; public static final String APP_SD_ROOT_DIR = "/bobo"; private File mediaFile; private String timeStamp,cameraPath,fileCache; private int width,height; TextView tv_ope; ImageView iv_show; private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds = true;//只读取图片,不加载到内存中 BitmapFactory.decodeFile(cameraPath, options); options.inSampleSize=computeSampleSize(options, -1, width*height);//返回合适的inSampleSize值 options.inJustDecodeBounds = false;//加载到内存中 Bitmap bitMap = BitmapFactory.decodeFile(cameraPath, options); Bitmap bitmap1 = ImageUtil.drawTextToLeftTop(MainActivity.this, bitMap, new SimpleDateFormat(" yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis())), 20, Color.RED, 5, 10); if(bitmap1!=null){ iv_show.setImageBitmap(bitmap1); } } }; //获取一个较为合理的inSampleSize值得方法 public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } public static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initEvent(); } //实例化点击事件 private void initEvent() { tv_ope.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { openCamare(); } }); } //实例化控件 private void initView() { WindowManager wm = (WindowManager) (getSystemService(Context.WINDOW_SERVICE)); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); width=dm.widthPixels; height=dm.heightPixels; tv_ope= (TextView) findViewById(R.id.textView); iv_show= (ImageView) findViewById(R.id.imageView); fileCache= Environment.getExternalStorageDirectory()+APP_SD_ROOT_DIR+File.separator+"Cache"; } //打开系统摄像头用于拍照 private void openCamare() { //适配安卓6.0的动态申请权限 if(ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED&&ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED&&ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED) { Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri imageUri = getOutputMediaFileUri(fileCache); openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(openCameraIntent, TAKE_PICTURE); }else { ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},1); } } /** * 用于拍照时获取输出的Uri */ protected Uri getOutputMediaFileUri(String fileCache) { File file=new File(fileCache); if (!file.exists()) { if (!file.mkdirs()) { return null; } } timeStamp= new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); mediaFile = new File(fileCache + File.separator + "IMG_" + timeStamp + ".jpg"); cameraPath = mediaFile.getAbsolutePath(); //匹配安卓7.0的Uri获取方法 Uri imageUri=null; if (Build.VERSION.SDK_INT >= 24) { imageUri = FileProvider.getUriForFile(this,"com.bobo.android.MainActivity",mediaFile); }else { imageUri = Uri.fromFile(mediaFile); } return imageUri; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode==RESULT_OK){ if(requestCode==TAKE_PICTURE){ Message message=Message.obtain(); message.what=100; //延迟半秒是担心图片保存到本地会耗时 handler.sendMessageDelayed(message,500); } } } }最后记得在AndroidManifest.xml清单文件中配置权限和FileProvider
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="自己的包名"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:authorities="com.bobo.android.MainActivity" android:name="android.support.v4.content.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_path"> </meta-data> </provider> </application> </manifest>最后还有file_path.xml文件
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path=""/> <root-path name="root_path" path="."/> </paths>好了,一份比较完整的为照片添加时间标签的代码到此结束,希望可以对有需要的朋友有一丢丢的帮助,最后如果大神看到文章认为那块不合适的话,希望能得到您的指点,因为毕竟我也接触安卓没多久,属于小菜级别的那种程序员,偶尔把自己的一些见解写出来,分享给大家,希望能对大家有所帮助同时也是对自己能力的一个提升吧。
参考链接:http://blog.csdn.net/dawanganban/article/details/51148070
http://blog.csdn.net/hustpzb/article/details/8363372
推荐阅读