工作日志:其实这是两年前就碰到的需求,之前没有整理,也没有继续优化和实现,这次又用到这样的需求,所以记录下来,既是一种代码记录,也是一种复习bitmap和canvas的好手段,这里提供一种思路,就是将原图的bitmap生成的canvas上绘制图片或者文字。
按照惯例上实现图:
上代码:
package com.example.testretrifit;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Environment;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.components.support.RxFragmentActivity;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_text;
private Service service;
private ImageView iv_bitmap;
private ImageView iv_bitmap2;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_text = findViewById(R.id.tv_text);
iv_bitmap = findViewById(R.id.iv_bitmap);
iv_bitmap2 = findViewById(R.id.iv_bitmap2);
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a);
// iv_bitmap.setImageBitmap(addTextWatermark(bitmap, 100, Color.WHITE, 0, bitmap.getHeight() / 2, true, "wdnmd,什么情况"));
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.mipmap.timg);
iv_bitmap2.setImageBitmap(addTextWatermark(bitmap2, 20, Color.WHITE, 0, bitmap.getHeight() / 2, true, "wdnmd,什么情况"));
tv_text.setOnClickListener(this);
OkHttpClient client = new OkHttpClient()
.newBuilder()
.readTimeout(10000, TimeUnit.SECONDS)
.connectTimeout(10000, TimeUnit.SECONDS)
.addNetworkInterceptor(new HeaderInpterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.2.156/")
.addConverterFactory(CommonGsonFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
service = retrofit.create(Service.class);
Map map = new HashMap<>();
map.put("username", "13666666666");
map.put("password", "zaq1@WSX");
Disposable disposable = service.login(RequestBody.create(MediaType.get("application/json"), new Gson().toJson(map)))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(responseBody -> {
Configs.token = new JSONObject(responseBody.string()).getString("access_token");
getUserInfo();
}, throwable -> Toast.makeText(this, "出错", Toast.LENGTH_SHORT).show()
);
/*
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
@Override
public void accept(ResponseBody responseBody) throws Exception {
}
}).dispose();
*/
/* Observable.just("hehe").subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
tv_text.setText(s);
}
}).dispose();*/
}
private void getUserInfo() {
Disposable disposable = service.getInfo(new HashMap<>())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(responseBody -> {
tv_text.setText(responseBody.string());
});
}
public void downLoadFile() {
Map map = new HashMap<>();
map.put("fileUrl", "http://192.168.2.126:80/group1/M00/45/91/wKgCfl8RA9CAS4tZAAAtjJqlrzg697.png");
Disposable disposable = service.downLoadFile(map)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(responseBody -> {
InputStream is = null;
byte[] buf = new byte[512];
int len = 0;
FileOutputStream fos = null;
//储存下载文件的目录
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, "hehe");
try {
is = responseBody.byteStream();
Toast.makeText(MainActivity.this, is.available() + "", Toast.LENGTH_SHORT).show();
long total = is.available();
fos = new FileOutputStream(file);
long sum = 0;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
sum += len;
int progress = (int) (sum * 1.0f / total * 100);
//下载中更新进度条
// listener.onDownloading(progress);
tv_text.setText(progress + "");
}
fos.flush();
//下载完成
// listener.onDownloadSuccess(file);
} catch (Exception e) {
// listener.onDownloadFailed(e);
} finally {
try {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
}
}
});
}
@Override
public void onClick(View view) {
downLoadFile();
}
/**
* 给图片添加水印 当需要换行的时候,推荐使用StaticLayout 这种实现方式
* @param src 原bitmap
* @param textSize 文字大小
* @param x 距离图片位图的左边距
* @param y 距离图片位图的上边距
* @param recycle 是否回收bitmap,建议true
* @param text 绘制内容
* */
public Bitmap addTextWatermark(Bitmap src, int textSize, int color, float x, float y, boolean recycle, String text) {
Objects.requireNonNull(src, "src is null");
Bitmap ret = src.copy(src.getConfig(), true);
TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
Canvas canvas = new Canvas(ret);
paint.setColor(color);
paint.setTextSize(src.getWidth() / 20);
Rect bounds = new Rect();
String content = "时 间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" + "内 容:" + text;
/*
单行文字的实现代码
paint.getTextBounds(content, 0, content.length(), bounds);
canvas.drawText(content, x, y, paint);*/
canvas.translate(x, y);
StaticLayout myStaticLayout = new StaticLayout(content, paint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
myStaticLayout.draw(canvas);
// canvas.drawBitmap(bitmap, 0, 0, null);//绘制小图片使用的代码
if (recycle && !src.isRecycled()) src.recycle();
return ret;
}
}
布局文件: