当前位置:   article > 正文

android给图片加水印的极简实现方式_addtextwatermark

addtextwatermark

工作日志:其实这是两年前就碰到的需求,之前没有整理,也没有继续优化和实现,这次又用到这样的需求,所以记录下来,既是一种代码记录,也是一种复习bitmap和canvas的好手段,这里提供一种思路,就是将原图的bitmap生成的canvas上绘制图片或者文字。

 

按照惯例上实现图:

效果图

上代码:

  1. package com.example.testretrifit;
  2. import androidx.appcompat.app.AlertDialog;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.Paint;
  9. import android.graphics.Rect;
  10. import android.os.Bundle;
  11. import android.os.Environment;
  12. import android.text.Layout;
  13. import android.text.StaticLayout;
  14. import android.text.TextPaint;
  15. import android.util.Log;
  16. import android.view.View;
  17. import android.widget.ImageView;
  18. import android.widget.TextView;
  19. import android.widget.Toast;
  20. import com.google.gson.Gson;
  21. import com.trello.rxlifecycle4.RxLifecycle;
  22. import com.trello.rxlifecycle4.components.support.RxFragmentActivity;
  23. import org.json.JSONObject;
  24. import java.io.File;
  25. import java.io.FileOutputStream;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.text.SimpleDateFormat;
  29. import java.util.Date;
  30. import java.util.HashMap;
  31. import java.util.Map;
  32. import java.util.Objects;
  33. import java.util.concurrent.TimeUnit;
  34. import io.reactivex.android.schedulers.AndroidSchedulers;
  35. import io.reactivex.disposables.Disposable;
  36. import io.reactivex.schedulers.Schedulers;
  37. import okhttp3.MediaType;
  38. import okhttp3.OkHttpClient;
  39. import okhttp3.RequestBody;
  40. import retrofit2.Retrofit;
  41. import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
  42. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  43. private TextView tv_text;
  44. private Service service;
  45. private ImageView iv_bitmap;
  46. private ImageView iv_bitmap2;
  47. private Bitmap bitmap;
  48. @Override
  49. protected void onCreate(Bundle savedInstanceState) {
  50. super.onCreate(savedInstanceState);
  51. setContentView(R.layout.activity_main);
  52. tv_text = findViewById(R.id.tv_text);
  53. iv_bitmap = findViewById(R.id.iv_bitmap);
  54. iv_bitmap2 = findViewById(R.id.iv_bitmap2);
  55. bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a);
  56. // iv_bitmap.setImageBitmap(addTextWatermark(bitmap, 100, Color.WHITE, 0, bitmap.getHeight() / 2, true, "wdnmd,什么情况"));
  57. Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.mipmap.timg);
  58. iv_bitmap2.setImageBitmap(addTextWatermark(bitmap2, 20, Color.WHITE, 0, bitmap.getHeight() / 2, true, "wdnmd,什么情况"));
  59. tv_text.setOnClickListener(this);
  60. OkHttpClient client = new OkHttpClient()
  61. .newBuilder()
  62. .readTimeout(10000, TimeUnit.SECONDS)
  63. .connectTimeout(10000, TimeUnit.SECONDS)
  64. .addNetworkInterceptor(new HeaderInpterceptor())
  65. .build();
  66. Retrofit retrofit = new Retrofit.Builder()
  67. .baseUrl("http://192.168.2.156/")
  68. .addConverterFactory(CommonGsonFactory.create())
  69. .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  70. .client(client)
  71. .build();
  72. service = retrofit.create(Service.class);
  73. Map<String, Object> map = new HashMap<>();
  74. map.put("username", "13666666666");
  75. map.put("password", "zaq1@WSX");
  76. Disposable disposable = service.login(RequestBody.create(MediaType.get("application/json"), new Gson().toJson(map)))
  77. .subscribeOn(Schedulers.newThread())
  78. .observeOn(AndroidSchedulers.mainThread())
  79. .subscribe(responseBody -> {
  80. Configs.token = new JSONObject(responseBody.string()).getString("access_token");
  81. getUserInfo();
  82. }, throwable -> Toast.makeText(this, "出错", Toast.LENGTH_SHORT).show()
  83. );
  84. /*
  85. Observable.create(new ObservableOnSubscribe<ResponseBody>() {
  86. @Override
  87. public void subscribe(ObservableEmitter<ResponseBody> emitter) throws Exception {
  88. }
  89. }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<ResponseBody>() {
  90. @Override
  91. public void accept(ResponseBody responseBody) throws Exception {
  92. }
  93. }).dispose();
  94. */
  95. /* Observable.just("hehe").subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
  96. @Override
  97. public void accept(String s) throws Exception {
  98. tv_text.setText(s);
  99. }
  100. }).dispose();*/
  101. }
  102. private void getUserInfo() {
  103. Disposable disposable = service.getInfo(new HashMap<>())
  104. .subscribeOn(Schedulers.newThread())
  105. .observeOn(AndroidSchedulers.mainThread())
  106. .subscribe(responseBody -> {
  107. tv_text.setText(responseBody.string());
  108. });
  109. }
  110. public void downLoadFile() {
  111. Map<String, Object> map = new HashMap<>();
  112. map.put("fileUrl", "http://192.168.2.126:80/group1/M00/45/91/wKgCfl8RA9CAS4tZAAAtjJqlrzg697.png");
  113. Disposable disposable = service.downLoadFile(map)
  114. .subscribeOn(Schedulers.newThread())
  115. .observeOn(AndroidSchedulers.mainThread())
  116. .subscribe(responseBody -> {
  117. InputStream is = null;
  118. byte[] buf = new byte[512];
  119. int len = 0;
  120. FileOutputStream fos = null;
  121. //储存下载文件的目录
  122. File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
  123. if (!dir.exists()) {
  124. dir.mkdirs();
  125. }
  126. File file = new File(dir, "hehe");
  127. try {
  128. is = responseBody.byteStream();
  129. Toast.makeText(MainActivity.this, is.available() + "", Toast.LENGTH_SHORT).show();
  130. long total = is.available();
  131. fos = new FileOutputStream(file);
  132. long sum = 0;
  133. while ((len = is.read(buf)) != -1) {
  134. fos.write(buf, 0, len);
  135. sum += len;
  136. int progress = (int) (sum * 1.0f / total * 100);
  137. //下载中更新进度条
  138. // listener.onDownloading(progress);
  139. tv_text.setText(progress + "");
  140. }
  141. fos.flush();
  142. //下载完成
  143. // listener.onDownloadSuccess(file);
  144. } catch (Exception e) {
  145. // listener.onDownloadFailed(e);
  146. } finally {
  147. try {
  148. if (is != null) {
  149. is.close();
  150. }
  151. if (fos != null) {
  152. fos.close();
  153. }
  154. } catch (IOException e) {
  155. }
  156. }
  157. });
  158. }
  159. @Override
  160. public void onClick(View view) {
  161. downLoadFile();
  162. }
  163. /**
  164. * 给图片添加水印 当需要换行的时候,推荐使用StaticLayout 这种实现方式
  165. * @param src 原bitmap
  166. * @param textSize 文字大小
  167. * @param x 距离图片位图的左边距
  168. * @param y 距离图片位图的上边距
  169. * @param recycle 是否回收bitmap,建议true
  170. * @param text 绘制内容
  171. * */
  172. public Bitmap addTextWatermark(Bitmap src, int textSize, int color, float x, float y, boolean recycle, String text) {
  173. Objects.requireNonNull(src, "src is null");
  174. Bitmap ret = src.copy(src.getConfig(), true);
  175. TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
  176. Canvas canvas = new Canvas(ret);
  177. paint.setColor(color);
  178. paint.setTextSize(src.getWidth() / 20);
  179. Rect bounds = new Rect();
  180. String content = "时 间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" + "内 容:" + text;
  181. /*
  182. 单行文字的实现代码
  183. paint.getTextBounds(content, 0, content.length(), bounds);
  184. canvas.drawText(content, x, y, paint);*/
  185. canvas.translate(x, y);
  186. StaticLayout myStaticLayout = new StaticLayout(content, paint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
  187. myStaticLayout.draw(canvas);
  188. // canvas.drawBitmap(bitmap, 0, 0, null);//绘制小图片使用的代码
  189. if (recycle && !src.isRecycled()) src.recycle();
  190. return ret;
  191. }
  192. }

布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <TextView
  9. android:layout_width="wrap_content"
  10. android:layout_height="100dp"
  11. android:text="Hello World!"
  12. android:id="@+id/tv_text"
  13. app:layout_constraintBottom_toBottomOf="parent"
  14. app:layout_constraintLeft_toLeftOf="parent"
  15. app:layout_constraintRight_toRightOf="parent"
  16. app:layout_constraintTop_toTopOf="parent" />
  17. <ImageView
  18. android:layout_width="match_parent"
  19. android:layout_height="match_parent"
  20. android:id="@+id/iv_bitmap2"
  21. app:layout_constraintLeft_toLeftOf="parent"
  22. app:layout_constraintRight_toRightOf="parent"
  23. app:layout_constraintTop_toTopOf="parent"
  24. app:layout_constraintBottom_toBottomOf="parent"
  25. />
  26. <ImageView
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:id="@+id/iv_bitmap"
  30. app:layout_constraintLeft_toLeftOf="parent"
  31. app:layout_constraintRight_toRightOf="parent"
  32. app:layout_constraintTop_toTopOf="parent"
  33. app:layout_constraintBottom_toBottomOf="parent"
  34. />
  35. </androidx.constraintlayout.widget.ConstraintLayout>

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/261955
推荐阅读
相关标签
  

闽ICP备14008679号