【Android】Bitmap图片旋转、缩放、翻转等变换(90/100)
自定义BitmapChangeView:
package top.lc951.myandroid.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import top.lc951.myandroid.utils.BitmapUtil;
/**
* @author lichong
* 2022年07月27日15:38:28
*/
public class BitmapChangeView extends View {
public static final String TAG = BitmapChangeView.class.getSimpleName();
private float mScaleRatio=1.0f;
private float mRotateDegree=0;
private Bitmap mBitmap;
private int mBitmapWidth;
private int mBitmapHeight;
private int mOffsetX;
private int mOffsetY;
public BitmapChangeView(Context context) {
super(context);
}
public BitmapChangeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
// 设置位图对象
public void setImageBitmap(Bitmap bitmap) {
mBitmap = bitmap;
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
postInvalidate(); // 立即刷新视图(线程安全方式)
}
// 左右翻转图像
public void flip() {
// 水平翻转图像,也就是把镜中像左右翻过来
mBitmap = BitmapUtil.getFlipBitmap(mBitmap);
postInvalidate(); // 立即刷新视图(线程安全方式)
}
// 设置缩放比例。isReset为true表示按照原始尺寸进行缩放,为false表示按照当前尺寸进行缩放
public void setScaleRatio(float ratio, boolean isReset) {
if (isReset) {
mScaleRatio = ratio;
} else {
mScaleRatio *= ratio;
}
postInvalidate(); // 立即刷新视图(线程安全方式)
}
// 设置旋转角度。isReset为true表示按照原始方向进行旋转,为false表示按照当前方向进行缩放
public void setRotateDegree(int degree, boolean isReset) {
if (isReset) {
mRotateDegree = degree;
} else {
mRotateDegree += degree;
}
postInvalidate(); // 立即刷新视图(线程安全方式)
}
// 设置偏移距离。isReset为true表示按照原始位置进行移动,为false表示按照当前位置进行移动
public void setOffset(int offsetX, int offsetY, boolean isReset) {
if (isReset) {
mOffsetX = offsetX;
mOffsetY = offsetY;
} else {
mOffsetX += offsetX;
mOffsetY += offsetY;
}
postInvalidate(); // 立即刷新视图(线程安全方式)
}
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
int width = getMeasuredWidth(); // 获取视图的实际宽度
int height = getMeasuredHeight(); // 获取视图的实际高度
int new_width = (int) (mBitmapWidth * mScaleRatio);
int new_height = (int) (mBitmapHeight * mScaleRatio);
Bitmap bitmap = mBitmap;
if (mScaleRatio != 1) {
// 生成缩放后的位图对象
bitmap = BitmapUtil.getScaleBitmap(mBitmap, mScaleRatio);
}
if (mRotateDegree != 0) {
// 生成旋转后的位图对象
bitmap = BitmapUtil.getRotateBitmap(bitmap, mRotateDegree);
}
// 在画布上的指定位置绘制位图对象
canvas.drawBitmap(bitmap, (width - new_width) / 2 + mOffsetX,
(height - new_height) / 2 + mOffsetY, new Paint());
}
}
工具类:
// 水平翻转图像,也就是把镜中像左右翻过来
public static Bitmap getFlipBitmap(Bitmap bitmap) {
Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
matrix.postScale(-1, 1); // 执行图片的旋转动作
// 创建并返回旋转后的位图对象
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
}
// 获得比例缩放之后的位图对象
public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) {
Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
matrix.postScale((float) scaleRatio, (float) scaleRatio);
// 创建并返回缩放后的位图对象
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
}
// 获得旋转角度之后的位图对象
public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) {
Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
matrix.postRotate(rotateDegree); // 执行图片的旋转动作
// 创建并返回旋转后的位图对象
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
}
布局引用:
<top.lc951.myandroid.views.BitmapChangeView
android:id="@+id/view_bitmap_change"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintStart_toStartOf="@id/tv_scale"
app:layout_constraintTop_toBottomOf="@id/ck_flip" />
应用如下:
package top.lc951.myandroid.activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Spinner;
import android.widget.Toast;
import top.lc951.myandroid.R;
import top.lc951.myandroid.utils.BitmapUtil;
import top.lc951.myandroid.views.BitmapChangeView;
/**
* 图片翻转、缩放、旋转等
* */
public class BitmapChangeActivity extends AppCompatActivity {
private BitmapChangeView bitmapChangeView;
public static void actionActivity(Context context) {
Intent intent = new Intent(context, BitmapChangeActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bitmap_change);
CheckBox flipCb = findViewById(R.id.ck_flip);
bitmapChangeView=findViewById(R.id.view_bitmap_change);
flipCb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
bitmapChangeView.flip();
}
});
Button saveBtn=findViewById(R.id.btn_save_image);
saveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = bitmapChangeView.getDrawingCache(); // 从绘图缓存获取位图对象
// 生成图片文件的保存路径
// String path = String.format("%s/%s.jpg",
// getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
// DateUtil.getNowDateTime());
// BitmapUtil.saveImage(path, bitmap); // 把位图保存为图片文件
// BitmapUtil.notifyPhotoAlbum(this, path); // 通知相册来了张新图片
// Toast.makeText(this, "成功保存图片文件:" + path, Toast.LENGTH_LONG).show();
}
});
initScaleSpinner();
initRotateSpinner();
}
@Override
protected void onStart() {
super.onStart();
bitmapChangeView.setDrawingCacheEnabled(true);
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_img06);
bitmapChangeView.setImageBitmap(bitmap);
}
@Override
protected void onStop() {
super.onStop();
bitmapChangeView.setDrawingCacheEnabled(false);
}
private String[] scaleArray = {"0.25", "0.5", "0.75", "1.0", "1.5", "2.0", "4.0"};
private String[] rotateArray = {"0", "45", "90", "135", "180", "225", "270", "315"};
private void initRotateSpinner() {
ArrayAdapter<String> scaleAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, rotateArray);
Spinner sp_scale = findViewById(R.id.spinner_rotate);
sp_scale.setPrompt("请选择旋转角度");
sp_scale.setAdapter(scaleAdapter);
sp_scale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
bitmapChangeView.setRotateDegree(Integer.parseInt(rotateArray[position]), true);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_scale.setSelection(0);
}
private void initScaleSpinner() {
ArrayAdapter<String> scaleAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, scaleArray);
Spinner sp_scale = findViewById(R.id.spinner_scale);
sp_scale.setPrompt("请选择缩放比率");
sp_scale.setAdapter(scaleAdapter);
sp_scale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
bitmapChangeView.setScaleRatio(Float.parseFloat(scaleArray[position]), true);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
sp_scale.setSelection(3);
}
}
自研产品推荐
历时一年半多开发终于smartApi-v1.0.0版本在2023-09-15晚十点正式上线
smartApi是一款对标国外的postman的api调试开发工具,由于开发人力就作者一个所以人力有限,因此v1.0.0版本功能进行精简,大功能项有:
- api参数填写
- api请求响应数据展示
- PDF形式的分享文档
- Mock本地化解决方案
- api列表数据本地化处理
- 再加上UI方面的打磨
为了更好服务大家把之前的公众号和软件激活结合,如有疑问请大家反馈到公众号即可,下个版本30%以上的更新会来自公众号的反馈。
嗯!先解释不上服务端原因,API调试工具的绝大多数时候就是一个数据模型、数据处理、数据模型理解共识的问题解决工具,所以作者结合自己十多年开发使用的一些痛点来打造的,再加上服务端开发一般是面向企业的,作者目前没有精力和时间去打造企业服务。再加上没有资金投入所以服务端开发会滞后,至于什么时候会进行开发,这个要看募资情况和用户反馈综合考虑。虽然目前国内有些比较知名的api工具了,但作者使用后还是觉得和实际使用场景不符。如果有相关吐槽也可以在作者的公众号里反馈蛤!
下面是一段smartApi使用介绍: