Android图片编辑,画箭头,画圆,画矩形(等)
来源:互联网 发布:华科何琨 知乎 编辑:程序博客网 时间:2024/06/06 02:18
最近再做聊天功能,遇到需求发送图片前编辑,查了好多没见一个合适的,就自己写了一个,希望对看到的人有所帮助(抛砖引玉),因为时间仓促请忽视编码风格
-箭头原理图
-效果图
-布局代码
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/ll" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv" android:scaleType="fitCenter" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1" android:onClick="pics" android:text="相册" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="photo" android:text="拍照" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_red_dark" android:onClick="red" android:text="红" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_green_dark" android:onClick="green" android:text="绿" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_blue_dark" android:onClick="blue" android:text="蓝" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1" android:onClick="small" android:text="细" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="zhong" android:text="中" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="big" android:text="粗" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="arrow" android:text="箭头" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="fang" android:text="方" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="circle" android:text="圆" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1" android:onClick="one" android:text="单步撤销" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="all" android:text="全部撤销" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout></LinearLayout>
-Activity代码
public class MainActivity extends Activity { private static final int MY_REQUEST_CODE = 3022; private ArrayList<Shapes> shapes = new ArrayList<Shapes>(); private ImageView iv;//展示图片 private Bitmap copyPic;//编辑图片 private Canvas canvas;//画板 private Paint paint;//画笔 private Matrix matrix;//矩阵 private Bitmap srcPic;//原图 private int color = Color.BLACK;//画笔颜色 private int width = 0;//画笔大小 private int circle;//形状 /* 用来标识请求照相功能的activity */ private static final int CAMERA_WITH_DATA = 3023; /* 用来标识请求gallery的activity */ private static final int PHOTO_PICKED_WITH_DATA = 3021; private String photoPath, camera_path, tempPhotoPath; //图片保存路径 public static final String filePath = Environment.getExternalStorageDirectory() + "/PictureTest/"; private int screenWidth; private File mCurrentPhotoFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iv = (ImageView) findViewById(R.id.iv); DisplayMetrics metric = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metric); // 屏幕宽度(像素) screenWidth = metric.widthPixels; } /** * 画画 */ private void drawPic() { srcPic = BitmapFactory.decodeFile(camera_path); copyPic = Bitmap.createBitmap(srcPic.getWidth(), srcPic.getHeight(), srcPic.getConfig()); canvas = new Canvas(copyPic); paint = new Paint(); paint.setAntiAlias(true); //绘制原图 drawOld(); iv.setImageBitmap(copyPic); //触摸事件 iv.setOnTouchListener(new View.OnTouchListener() { private float endY; private float endX; private float startX; private float startY; @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN:// 按下的事件类型 startX = event.getX(); startY = event.getY(); drawGuiji(); break; case MotionEvent.ACTION_MOVE:// 移动的事件类型 // 得到结束位置的坐标点 endX = event.getX(); endY = event.getY(); // 清除之前轨迹 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPaint(paint); drawGuiji(); paint.setStrokeWidth(width); paint.setColor(color); if (circle == 1) { paint.setStyle(Paint.Style.STROKE);//设置边框 canvas.drawRect(startX, startY, endX, endY, paint);// 正方形 } else if (circle == 0) { paint.setStyle(Paint.Style.STROKE);//设置边框 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { canvas.drawOval(startX, startY, endX, endY, paint); } } else if (circle == 2) { paint.setStyle(Paint.Style.FILL);//设置边框 drawArrow(startX, startY, endX, endY, width, paint); } iv.setImageBitmap(copyPic); break; case MotionEvent.ACTION_UP:// 移动的事件类型 shapes.add(new Shapes(startX, startY, endX, endY, width, paint.getColor(), circle));//保存历史轨迹 break; } return true; } }); } private void drawGuiji() { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); drawOld(); for (Shapes sp : shapes) {//画历史轨迹 paint.setColor(sp.color); paint.setStrokeWidth(sp.width); if (sp.circle == 1) { paint.setStyle(Paint.Style.STROKE);//设置边框 canvas.drawRect(sp.startX, sp.startY, sp.endX, sp.endY, paint);// 正方形 } else if (sp.circle == 0) { paint.setStyle(Paint.Style.STROKE);//设置边框 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//api21之后的方法 canvas.drawOval(sp.startX, sp.startY, sp.endX, sp.endY, paint);//椭圆 } } else if (sp.circle == 2) { paint.setStyle(Paint.Style.FILL);//设置边框 drawArrow(sp.startX, sp.startY, sp.endX, sp.endY, sp.width, paint);//箭头 } } iv.setImageBitmap(copyPic); } /** * 绘制底图 */ private void drawOld() { // 给画笔设置默认的颜色,在画画的过程中会使用原图的颜色来画画 paint.setColor(Color.BLACK); // 处理图形 matrix = new Matrix(); // 5、使用画笔在画板上画画 // 参看原图画画 // srcPic 原图 // matrix 表示图形的矩阵对象,封装了处理图形的api // paint 画画时使用的画笔 canvas.drawBitmap(srcPic, matrix, paint); } /** * 红色按钮 * * @param view */ public void red(View view) { color = Color.RED; } /** * 绿色按钮 * * @param view */ public void green(View view) { color = Color.GREEN; } /** * 蓝色按钮 * * @param view */ public void blue(View view) { color = Color.BLUE; } public void small(View view) { //改变刷子的宽度 width = 1; } public void zhong(View view) { //改变刷子的宽度 width = 5; } public void big(View view) { //改变刷子的宽度 width = 10; } /** * 圆形 * * @param view */ public void circle(View view) { circle = 0; } /** * 矩形 * * @param view */ public void fang(View view) { circle = 1; } /** * 矩形 * * @param view */ public void arrow(View view) { circle = 2; } /** * 相册 * * @param view */ public void pics(View view) { getPictureFromPhoto(); } /** * 拍照 * * @param view */ public void photo(View view) { //申请照相机权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_REQUEST_CODE); } else { getPictureFromCamera(); } } } /** * 单步撤销 * * @param view */ public void one(View view) { int size = shapes.size(); if (size > 0) { shapes.remove(size - 1); drawGuiji(); } } /** * 全部撤销 * * @param view */ public void all(View view) { shapes.clear(); drawGuiji(); } /** * 画箭头 * * @param sx * @param sy * @param ex * @param ey * @param paint */ private void drawArrow(float sx, float sy, float ex, float ey, int width, Paint paint) { int size = 5; int count = 20; switch (width) { case 0: size = 5; count = 20; break; case 5: size = 8; count = 30; break; case 10: size = 11; count = 40; break; } float x = ex - sx; float y = ey - sy; double d = x * x + y * y; double r = Math.sqrt(d); float zx = (float) (ex - (count * x / r)); float zy = (float) (ey - (count * y / r)); float xz = zx - sx; float yz = zy - sy; double zd = xz * xz + yz * yz; double zr = Math.sqrt(zd); Path triangle = new Path(); triangle.moveTo(sx, sy); triangle.lineTo((float) (zx + size * yz / zr), (float) (zy - size * xz / zr)); triangle.lineTo((float) (zx + size * 2 * yz / zr), (float) (zy - size * 2 * xz / zr)); triangle.lineTo(ex, ey); triangle.lineTo((float) (zx - size * 2 * yz / zr), (float) (zy + size * 2 * xz / zr)); triangle.lineTo((float) (zx - size * yz / zr), (float) (zy + size * xz / zr)); triangle.close(); canvas.drawPath(triangle, paint); } /* 从相册中获取照片 */ private void getPictureFromPhoto() { Intent openphotoIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(openphotoIntent, PHOTO_PICKED_WITH_DATA); } /* 从相机中获取照片 */ private void getPictureFromCamera() { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); tempPhotoPath = filePath + getNewFileName() + ".png"; mCurrentPhotoFile = new File(tempPhotoPath); if (!mCurrentPhotoFile.exists()) { try { mCurrentPhotoFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCurrentPhotoFile)); startActivityForResult(intent, CAMERA_WITH_DATA); } /** * 根据时间戳生成文件名 * * @return */ public static String getNewFileName() { SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); Date curDate = new Date(System.currentTimeMillis()); return formatter.format(curDate); } /** * 将生成的图片保存到内存中 * * @param bitmap * @param name * @return */ public String saveBitmap(Bitmap bitmap, String name) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File dir = new File(filePath); if (!dir.exists()) dir.mkdir(); File file = new File(filePath + name + ".jpg"); FileOutputStream out; try { out = new FileOutputStream(file); if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) { out.flush(); out.close(); } return file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } } return null; } /** * 根据路径获取图片并且压缩,适应view * * @param filePath 图片路径 * @param contentView 适应的view * @return Bitmap 压缩后的图片 */ public Bitmap compressionFiller(String filePath, View contentView) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; Bitmap bitmap = BitmapFactory.decodeFile(filePath, opt); int layoutHeight = contentView.getHeight(); float scale = 0f; int bitmapHeight = bitmap.getHeight(); int bitmapWidth = bitmap.getWidth(); scale = bitmapHeight > bitmapWidth ? layoutHeight / (bitmapHeight * 1f) : screenWidth / (bitmapWidth * 1f); Bitmap resizeBmp; if (scale != 0) { int bitmapheight = bitmap.getHeight(); int bitmapwidth = bitmap.getWidth(); Matrix matrix = new Matrix(); matrix.postScale(scale, scale); // 长和宽放大缩小的比例 resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmapwidth, bitmapheight, matrix, true); } else { resizeBmp = bitmap; } return resizeBmp; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != RESULT_OK) { return; } switch (requestCode) { case CAMERA_WITH_DATA: photoPath = tempPhotoPath; break; case PHOTO_PICKED_WITH_DATA: Uri selectedImage = data.getData(); String[] filePathColumns = {MediaStore.Images.Media.DATA}; Cursor c = getContentResolver().query(selectedImage, filePathColumns, null, null, null); int columnIndex = c.getColumnIndex(filePathColumns[0]); c.moveToFirst(); photoPath = c.getString(columnIndex); c.close(); break; } shapes.clear(); Bitmap bitmap = compressionFiller(photoPath, iv); camera_path = saveBitmap(bitmap, "saveTemp"); drawPic(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 调用相机 getPictureFromCamera(); } else { //没有权限 Toast.makeText(MainActivity.this, "没有权限", Toast.LENGTH_SHORT).show(); } } }}
-保存轨迹的实体类Shapes
class Shapes { public float startX, startY, endX, endY ; public int width,color,circle; public Shapes(float startX, float startY, float endX, float endY, int width, int color , int circle) { this.startX = startX; this.startY = startY; this.endX = endX; this.endY = endY; this.width = width; this.color = color; this.circle = circle; }}
如果这些不是你想要的效果,可以参考大神的项目,这个效果很全,而且做了封装https://github.com/jarlen/PhotoEditDemo
0 0
- Android图片编辑,画箭头,画圆,画矩形(等)
- drawRect绘制图片、箭头、矩形(Demo)
- android 使用Canvas画箭头
- android 使用Canvas画箭头
- 画箭头
- Word2003画箭头锦囊 斜线箭头、双箭头、折线箭头
- Android Toolbar设置向上箭头,标题等
- Android Toolbar设置向上箭头,标题等
- Android用canvas画随意方向箭头
- GDI+ C# 在图片上画矩形
- opencv--画矩形框与图片截取
- Android画矩形小程序
- Android图片编辑
- Android 图片编辑error
- android 在图片(bitmap)上画矩形框,并显示
- QT QPainter用法(包含画点,画圆,画矩形,画线等)
- table画斜线、直线、圆、矩形、圆角矩形、圆弧、多角形、曲线等
- opencv画轮廓的外界圆矩形椭圆等
- android 5.1 usb调试默认关闭设置方法
- Hadoop三种安装模式:单机模式,伪分布式,真正分布式
- java的代理模式(动态代理和静态代理)
- 总结2
- Bootstrap 过渡效果Transition-模态框(Modal)
- Android图片编辑,画箭头,画圆,画矩形(等)
- C++学习 8 深入 STL 2
- [Java基础要义] HashMap的设计原理和实现分析
- 历史穿梭(git权威指南笔记)
- 字符流和字节流的区别,使用场景,相关类
- Word PDF转图片
- C语言学习笔记3
- js学习记录7
- WdatePicker开始时间结束时间相互控制 并且只限制日期 时间动态控制