当前位置: 首页 > news >正文

Android图片涂鸦,Kotlin(1)

Android图片涂鸦,Kotlin(1)

 

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatImageViewclass PaintView @JvmOverloads constructor(context: Context?,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : AppCompatImageView(context!!, attrs, defStyleAttr) {class DrawPath {var id: Long = 0Lvar path: Path? = nullvar paint: Paint? = nullvar points = ArrayList<PointF>()}private var mPaint: Paint? = nullprivate var mPath: Path? = nullprivate var mDownX = 0fprivate var mDownY = 0fprivate var mTempX = 0fprivate var mTempY = 0f//默认的画笔宽度private var mPaintWidth = 10//默认画笔的颜色private var mColor = Color.REDprivate val mDrawPathList: ArrayList<DrawPath>?private val mSavePathList: ArrayList<DrawPath>?companion object {var WIDTH_INCREMENT = 15const val TAG = "PaintView"}init {mDrawPathList = ArrayList()mSavePathList = ArrayList()initPaint()}private fun initPaint() {mPaint = Paint()mPaint?.color = mColormPaint?.isAntiAlias = truemPaint?.strokeWidth = mPaintWidth.toFloat()mPaint?.style = Paint.Style.STROKE}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)if (!mDrawPathList.isNullOrEmpty()) {for (drawPath in mDrawPathList) {if (drawPath.path != null) {canvas.drawPath(drawPath.path!!, drawPath.paint!!)}drawPath.points.forEach {Log.d(TAG, "onDraw ${drawPath.id} ${it.x} ${it.y}")}}}}override fun onTouchEvent(event: MotionEvent): Boolean {when (event.action) {MotionEvent.ACTION_DOWN -> {Log.d(TAG, "ACTION_DOWN ${event.x} ${event.y}")mDownX = event.xmDownY = event.y//每次手指点下去作为一条新路径。mPath = Path()mPath?.moveTo(mDownX, mDownY)val drawPath = DrawPath()drawPath.id = System.currentTimeMillis()drawPath.paint = mPaintdrawPath.path = mPathmDrawPathList?.add(drawPath)//新一轮绘制开始,保存点。drawPath.points.add(PointF(event.x, event.y))invalidate()mTempX = mDownXmTempY = mDownY}MotionEvent.ACTION_MOVE -> {//Log.d(TAG, "ACTION_MOVE ${event.x} ${event.y}")val moveX = event.xval moveY = event.ymPath?.quadTo(mTempX, mTempY, moveX, moveY)mDrawPathList?.filter {it.path == mPath}?.forEach {it.points.add(PointF(event.x, event.y))}invalidate()mTempX = moveXmTempY = moveY}//每次手指抬起重置画笔,不然画笔会保存之前设置的属性会引起bug。MotionEvent.ACTION_UP -> {Log.d(TAG, "ACTION_UP ${event.x} ${event.y}")initPaint()}}return true}/*** 撤销。*/fun undo() {if (mDrawPathList != null && mDrawPathList.size >= 1) {mSavePathList?.add(mDrawPathList[mDrawPathList.size - 1])mDrawPathList.removeAt(mDrawPathList.size - 1)invalidate()}}/*** 反撤销,重新生效。*/fun reundo() {if (!mSavePathList.isNullOrEmpty()) {mDrawPathList?.add(mSavePathList[mSavePathList.size - 1])mSavePathList.removeAt(mSavePathList.size - 1)invalidate()}}/*** 画笔颜色。** @param color*/fun setPaintColor(color: Int) {this.mColor = colormPaint?.color = this.mColor}/*** 画笔的宽度。*/fun setPaintWidth(size: Int) {mPaintWidth += sizemPaint?.strokeWidth = mPaintWidth.toFloat()}/*** 放大,改变画笔的宽度。线条变粗。*/fun enlargePaintWidth() {mPaintWidth += WIDTH_INCREMENTmPaint?.strokeWidth = mPaintWidth.toFloat()}fun getDrawPath(): ArrayList<DrawPath>? {return mDrawPathList}
}

 

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity"><com.pkg1115.PaintViewandroid:id="@+id/paint_view"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@mipmap/p1"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><RelativeLayoutandroid:id="@+id/rl_left"android:layout_width="100dp"android:layout_height="wrap_content"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"><Buttonandroid:id="@+id/btn_undo"android:layout_width="match_parent"android:layout_height="60dp"android:text="撤销" /><Buttonandroid:id="@+id/btn_red"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_undo"android:text="红色" /><Buttonandroid:id="@+id/btn_green"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_red"android:text="绿色" /><Buttonandroid:id="@+id/btn_enlarge"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_green"android:text="放大" /></RelativeLayout></androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

Android图形图像处理:添加涂鸦文字_android 在图片上涂鸦-CSDN博客文章浏览阅读2k次。先看运行效果: 关键的PaintView:package com.zhangphil;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graph..._android 在图片上涂鸦https://blog.csdn.net/zhangphil/article/details/87810653

 

相关文章:

Android图片涂鸦,Kotlin(1)

Android图片涂鸦&#xff0c;Kotlin&#xff08;1&#xff09; import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Path import android.graphics.PointF import android.…...

upload-labs(1-17关攻略详解)

upload-labs pass-1 上传一个php文件&#xff0c;发现不行 但是这回显是个前端显示&#xff0c;直接禁用js然后上传 f12禁用 再次上传&#xff0c;成功 右键打开该图像 即为位置&#xff0c;使用蚁剑连接 连接成功 pass-2 源码 $is_upload false; $msg null; if (isse…...

《 机器人基础 》期末试卷(A)

一、填空题&#xff08;30分&#xff0c;每空2分&#xff09; 1. 按照相机的工作方式&#xff0c;机器人常用相机分为1&#xff09;__ 单目摄像头 2&#xff09;__ 双目摄像头 _ 3&#xff09;_深度摄像头_ 三类。 2. 度量地图强调…...

Azure Machine Learning - Azure AI 搜索中的矢量搜索

矢量搜索是一种信息检索方法&#xff0c;它使用内容的数字表示形式来执行搜索方案。 由于内容是数字而不是纯文本&#xff0c;因此搜索引擎会匹配与查询最相似的矢量&#xff0c;而不需要匹配确切的字词。本文简要介绍了 Azure AI 搜索中的矢量支持。 其中还解释了与其他 Azure…...

3 redis实现一个消息中间件

使用list实现一个队列&#xff0c;可以从左侧入队&#xff0c;也可以从右侧入对 即可以从左侧读取&#xff0c;也可以从右侧读取 1、Lindex Lindex 命令用于通过索引获取列表中的元素 也可以使用负数下标&#xff0c;以 -1 表示列表的最后一个元素&#xff0c; -2 表示列表的…...

js添加dom到指定div之后,并给添加的dom类名,然后设置其样式,以及el-popover层级z-index过高问题解决。

遇到一个需求,Vue项目做一个表格,要求表头与表格内容分开,如下效果所示,表头与表格有个高度间隔边距(箭头所示),因为默认我们的el-table的表头与内容是一起的: 思路:通过querySelector获取el-table__header-wrapper元素,通过createElement创建一个div,通过 newElem…...

C语言结构体

#include <stdio.h> #include <string.h> #include <stdlib.h>//struct Student_s { // int num; // char name[20]; // char gender; // int age; // float Chinese; // float Math; // float English; // char addr[30]; //}; //最后的分号一定要写&#x…...

【Python大数据笔记_day10_Hive调优及Hadoop进阶】

hive调优 hive官方配置url: Configuration Properties - Apache Hive - Apache Software Foundation hive命令和参数配置 hive参数配置的意义: 开发Hive应用/调优时&#xff0c;不可避免地需要设定Hive的参数。设定Hive的参数可以调优HQL代码的执行效率&#xff0c;或帮助定位问…...

React经典初级错误

文章 前言错误场景问题分析解决方案后言 前言 ✨✨ 他们是天生勇敢的开发者&#xff0c;我们创造bug&#xff0c;传播bug&#xff0c;毫不留情地消灭bug&#xff0c;在这个过程中我们创造了很多bug以供娱乐。 前端bug这里是博主总结的一些前端的bug以及解决方案&#xff0c;感兴…...

C# System.Array.CopyTo() 和 System.Array.Clone() 有什么区别

System.Array.CopyTo() 和 System.Array.Clone() 是用于数组复制的两种不同方法&#xff0c;它们在实现和用途上有一些区别。 System.Array.CopyTo() 方法&#xff1a; CopyTo() 方法用于将数组的元素复制到另一个数组。它是 Array 类的实例方法&#xff0c;可以用于复制一个…...

Stable Diffusion 启动时 got an unexpected keyword argument ‘socket_options‘ 错误解决

Stable Diffusion 启动时 got an unexpected keyword argument socket_options 错误解决 问题解决方法 问题 Launching Web UI with arguments: Traceback (most recent call last):File "launch.py", line 48, in <module>main()File "launch.py"…...

CSS 文本属性篇

文字颜色 属性名&#xff1a;color作用&#xff1a;控制文字的颜色可选值&#xff1a; 1.颜色名 color: blue; 2.rgb或rgba color:rgb(132, 220, 254); color:rgba(132, 220, 254,0.5); 3.hex或hexa&#xff08;十六进制&#xff09; color:#0078d4; color:#0078d48b; 4.hsl或h…...

Activiti,Apache camel,Netflex conductor对比,业务选型

Activiti,Apache camel,Netflex conductor对比&#xff0c;业务选型 1.activiti是审批流&#xff0c;主要应用于人->系统交互&#xff0c;典型应用场景&#xff1a;请假&#xff0c;离职等审批 详情可见【精选】activti实际使用_activiti通过事件监听器实现的优势_记录点滴…...

pythom导出mysql指定binlog文件

要求 要求本地有py环境和全局环境变量 先测试直接执行binlog命令执行命令 Windows 本地直接执行命令 # E:\output>E:\phpstudy_pro\Extensions\MySQL5.7.26\bin\mysqlbinlog binglog文件地址 # --no-defaults 不限制编码 # -h mysql链接地址 # -u mysql 链接名称 # -p m…...

TDengine 跨版本迁移实战

TDengine 3.0 已经退出了近一年&#xff0c;目前已经到了 3.2 版本。很遗憾的是 2.x 和 3.x 之间的数据文件不兼容。 如果向从 2.x 升级到 3.x 只能选择数据迁移的方式。 目前数据迁移有三种方法&#xff1a; 使用官方推荐工具 taosx。使用 taosdump 工具。自己写程序。 迁移…...

FPGA设计时序约束八、others类约束之Set_Case_Analysis

目录 一、序言 二、Set Case Analysis 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 命令示例 三、工程示例 四、参考资料 一、序言 在Vivado的时序约束窗口中&#xff0c;存在一类特殊的约束&#xff0c;划分在others目录下&#xff0c;可用于设置忽略或修改默认的时序…...

xftp连接wsl2

在WSL中默认是没有安装OpenSSH&#xff0c;需要自己安装。 安装 sudo apt update sudo apt install openssh-server检查是否安装成功 ssh -V配置ssh sudo vim /etc/ssh/ssh_config设置端口 Port 22启动ssh服务 sudo service ssh startxftp连接 主机地址&#xff1a;127.…...

Cross-View Transformers for Real-Time Map-View Semantic Segmentation 论文阅读

论文链接 Cross-View Transformers for Real-Time Map-View Semantic Segmentation 0. Abstract 提出了 Cross-View Transformers &#xff0c;一种基于注意力的高效模型&#xff0c;用于来自多个摄像机的地图视图语义分割使用相机感知的跨视图注意机制隐式学习从单个相机视…...

MySQL InnoDB 引擎底层解析(一)

6. InnoDB 引擎底层解析 MySQL 对于我们来说还是一个黑盒&#xff0c;我们只负责使用客户端发送请求并等待服务器返回结果&#xff0c;表中的数据到底存到了哪里&#xff1f;以什么格式存放的&#xff1f;MySQL 是以什么方式来访问的这些数据&#xff1f;这些问题我们统统不知…...

redis安装(Windows和linux)

如何实现Redis安装与使用的详细教程 Redis 简介 Redis是一个使用C语言编写的开源、高性能、非关系型的键值对存储数据库。它支持多种数据结构&#xff0c;包括字符串、列表、集合、有序集合、哈希表等。Redis的内存操作能力极强&#xff0c;其读写性能非常优秀&#xff0c;且…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...