Android Canvas和Bitmap结合绘图详解流程

目录
  • Rect/RectF
  • Matrix
  • Canvas
  • Bitmap

Rect/RectF

存储四个值的矩形类:左侧、顶部、右侧和底部。可用于直接在画布上绘制或仅用于存储要绘制的对象的大小。Rect和RectF类之间的区别在于 RectF 存储浮点值,而Rect类存储整数。

private static Bitmap createDrawableBitmap(Drawable drawable) {
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    if (width <= 0 || height <= 0) {
        return null;
    }
    float scale = Math.min(1.0f, ((float) MAX_IMAGE_SIZE) / ((float) (width * height)));
    if ((drawable instanceof BitmapDrawable) && scale == 1.0f) {
        return ((BitmapDrawable) drawable).getBitmap();
    }
    int bitmapWidth = (int) (((float) width) * scale);
    int bitmapHeight = (int) (((float) height) * scale);
    Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    Rect existingBounds = drawable.getBounds();
    int left = existingBounds.left;
    int top = existingBounds.top;
    int right = existingBounds.right;
    int bottom = existingBounds.bottom;
    drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
    drawable.draw(canvas);
    drawable.setBounds(left, top, right, bottom);
    return bitmap;
}

Matrix

一个3 x 3的矩阵,用于存储可用于转换画布的信息。矩阵可以存储以下类型的变换信息:缩放、倾斜、旋转、平移。而每种变换方式都对应着三种方法:set方法将用新值替换当前的Matrix,不管之前Matrix的值是什么。pre和post 方法将在当前Matrix包含的任何内容之前或之后应用新的转换。

Matrix m = new Matrix();
m.setRotate(90);
m.setScale(3f,1f);
m.setTranslate(200, 200);

只有平移,旋转值和缩放值被重置

Matrix m = new Matrix();
m.preScale(3f,1f);
m.preTranslate(200f, 100f);
m.postScale(0.5f, 1f);
m.postTranslate(100f, 0f);

先进行平移(200f, 100f),然后进行缩放(3f, 1f),然后进行缩放(0.5f, 1f),最后进行平移(100f, 0f)

Matrix m = new Matrix();
m.postTranslate(200f, 0f);
m.preScale(0.5f, 1f);
m.setScale(1f, 1f);
m.postScale(5f, 1f);
m.preTranslate(200f, 100f);

先进行平移(200f, 100f),然后进行缩放(1f, 1f),最后进行缩放(5f, 1f)。因为用了set方法所以平移(200f, 0f)和缩放(0.5f, 1f)被覆盖,不起作用

假如先进行平移(x, y),再进行缩放(sx, sy),那么看到的平移效果等同于(x*sx, y*sy),因为缩放是将整个画布或者坐标系进行缩放的

Canvas

Canvas相当于Android的画布,可以把画布想象成一块内存空间,也就是一个Bitmap。Canvas的API提供一整套在这个Bitmap上进行绘图的操作方法。

  • drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

使用指定的矩阵绘制位图,绘制的时候会使用矩阵进行变换,矩阵和画笔可以传入空值

  • drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)

将传入的源图bitmap指定的矩形区域src绘制到目标矩形区域dst中,如果矩形区域src传入空值,则表示绘制整个源图到目标矩形区域dst中,绘制的时候源图或子集自动缩放/平移以填充目标矩形。如果绘制对应的画笔通过方法setMaskFilter指定了超出原始位图宽/高的掩码过滤器(如BlurMaskFilter),则会位图将继续被绘制,就像在具有CLAMP模式的着色器中一样。因此,原始宽/高之外的颜色将是复制的边缘颜色。因为源矩形区域src对应的坐标空间是相对于源图的,而目标矩形区域dst对应的坐标空间是绘制视图对应的坐标空间,因此要控制好对应的缩放因子。

  • drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

矩阵示例:

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888);
float originalWidth = originalImage.getWidth();
float originalHeight = originalImage.getHeight();

Canvas canvas = new Canvas(background);

float scale = width / originalWidth;

float xTranslation = 0.0f;
float yTranslation = (height - originalHeight * scale) / 2.0f;

Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);

Paint paint = new Paint();
paint.setFilterBitmap(true);

canvas.drawBitmap(originalImage, transformation, paint);

矩形区域示例:

public Bitmap cropCircle(Bitmap bitmap) {
  Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
      bitmap.getHeight(), Config.ARGB_8888);
  Canvas canvas = new Canvas(output);
  final int color = 0xff424242;
  final Paint paint = new Paint();
  final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
  paint.setAntiAlias(true);
  canvas.drawARGB(0, 0, 0, 0);
  paint.setColor(color);
  canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
      bitmap.getWidth()/2, paint);
  paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
  canvas.drawBitmap(bitmap, rect, rect, paint);
  return output;
}

Bitmap

位图,点阵图,可以理解为int[] buffer,用来存储每个像素点的容器。

  • Bitmap.createBitmap(int width, int height, Bitmap.Config config)
  • Bitmap.createBitmap(Bitmap src)
  • Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height)
  • Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter)
  • BitmapFactory.decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
  • BitmapFactory.decodeFile(String pathName, Options opts)
  • BitmapFactory.decodeStream(InputStream is, Rect outPadding,Options opts)

createBitmap生成示例:

public Bitmap transform(Bitmap source) {
  int size = Math.min(source.getWidth(), source.getHeight());
  int x = (source.getWidth() - size) / 2;
  int y = (source.getHeight() - size) / 2;
  Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
  if (squaredBitmap != source) {
    source.recycle();
  }
  Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
  Canvas canvas = new Canvas(bitmap);
  Paint avatarPaint = new Paint();
  BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
  avatarPaint.setShader(shader);
  Paint outlinePaint = new Paint();
  outlinePaint.setColor(Color.WHITE);
  outlinePaint.setStyle(Paint.Style.STROKE);
  outlinePaint.setStrokeWidth(STROKE_WIDTH);
  outlinePaint.setAntiAlias(true);
  float r = size / 2f;
  canvas.drawCircle(r, r, r, avatarPaint);
  canvas.drawCircle(r, r, r - STROKE_WIDTH / 2, outlinePaint);
  squaredBitmap.recycle();
  return bitmap;
}

BitmapFactory生成示例:

private static Bitmap decodeSampledBitmapFromUrl(String url, int reqWidth, int reqHeight) throws IOException {

	    // First decode with inJustDecodeBounds=true to check dimensions
	    final Options options = new Options();
	    options.inJustDecodeBounds = true;

	    InputStream stream = fetchStream(url);
	    BitmapFactory.decodeStream(stream, null, options);
	    stream.close();

	    // Calculate inSampleSize
	    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
	    // Decode bitmap with inSampleSize set
	    options.inJustDecodeBounds = false;

	    stream = fetchStream(url);
	    Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
	    stream.close();

	    return bitmap;
	}

	private static InputStream fetchStream(String urlString) throws IllegalStateException, IOException {

		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet request = new HttpGet(urlString);
		HttpResponse response = httpClient.execute(request);
		return response.getEntity().getContent();
	}

	private static int calculateInSampleSize(Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			// Calculate ratios of height and width to requested height and width
			final int heightRatio = Math.round((float) height / (float) reqHeight);
			final int widthRatio = Math.round((float) width / (float) reqWidth);

			// Choose the smallest ratio as inSampleSize value, this will guarantee
			// a final image with both dimensions larger than or equal to the
			// requested height and width.
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}

注意:通过Bitmap.createBitmap生成的Bitmap对象是可变对象,可以向Bitmap上绘制内容,而通过BitmapFactory生成的Bitmap对象必须指定BitmapFactory.Options.inMutable = true,否则就是不可变对象,不能向上面绘制内容。

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

到此这篇关于Android Canvas和Bitmap结合绘图详解流程的文章就介绍到这了,更多相关Android 绘图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android Canvas自定义实现时钟效果

    Android之Canvas自定义画一个时钟,供大家参考,具体内容如下 自定义控件,在安卓是也是一种无所不能的技术了,所有自带控件,以及组合自带控件不能实现的一些效果,我们都可以通过自定义控件来实现,不过,如果能有系统控件使用的就用系统自带的控件去实现,而不必要用自定义去实现,我们都知道,自定义控件在一定的程度上,效率往往会比系统自带的控件效率低,所以我不到万不得已,不要使用自定义控件,今天用自定一控件,实现一个小小的时钟,具体的实现在代码中注释功能. ClockView.java public

  • Android中区别Drawable Bitmap Canvas Paint

    1.概念区别: 很多网友刚刚开始学习Android平台,对于Drawable.Bitmap.Canvas和Paint它们之间的概念不是很清楚,其实它们除了Drawable外早在Sun的J2ME中就已经出现了,但是在Android平台中,Bitmap.Canvas相关的都有所变化. 首先让我们理解下Android平台中的显示类是View,但是还提供了底层图形类android.graphics,今天所说的这些均为graphics底层图形接口. Bitmap - 称作位图 一般位图的文件格式后缀为bm

  • Android使用Canvas对象实现刮刮乐效果

    在淘宝.京东等电商举办活动的时候,经常可以看到在移动客户端推出的各种刮奖活动,而这种活动也受到了很多人的喜爱.从客户端的体验来说,这种效果应该是通过网页来实现的,那么,我们使用Android的自带控件能不能实现这种刮刮乐的效果呢?当然可以,本篇文章将介绍使用Canvas这个对象,如何实现"刮刮乐"的效果. 先看效果图 下面我们看一下如何使用代码实现 布局文件 <FrameLayout xmlns:android="http://schemas.android.com/a

  • Android 使用Canvas在图片上绘制文字的方法

    [Android]Android中 Paint 字体.粗细等属性的一些设置 在Android SDK中使用Typeface类来定义字体,可以通过常用字体类型名称进行设置,如设置默认黑体: Paint mp = new paint(); mp.setTypeface(Typeface.DEFAULT_BOLD) 常用的字体类型名称还有: * Typeface.DEFAULT //常规字体类型 * Typeface.DEFAULT_BOLD //黑体字体类型 * Typeface.MONOSPACE

  • Android canvas drawBitmap方法详解及实例

     Android canvas drawBitmap方法详解及实例 之前自己在自定义view,用到canvas.drawBitmap(Bitmap, SrcRect, DesRect, Paint)的时候,对其中的第2和3个参数的含义含糊不清.看源码函数也没理解,然后看了一些其他的博客加上自己的理解,整理如下.首先,我们看一张图片,今天就要绘制这张图片. 然后将图片用红色的线条分成4个部分,如下: 我们自定义一个View,代码如下: public class PoterDuffLoadingVi

  • Android原生绘图工具Canvas详细

    目录 1.Canvas提供的绘制函数 2.绘制背景 3.绘制矩形drawRect 4.绘制圆角矩形drawRoundRect 5.绘制圆形drawCircle 6.绘制路径drawPath 7.绘制直线drawLine 8.绘制圆弧drawArc 9.绘制椭圆drawOval 10.绘制点drawPoint 11.绘制文本drawText 沿路径绘制文本drawTextOnPath 12.绘制bitmap drawBitmap 如果对上一篇感兴趣的话可以看看Android原生绘图Paint 下面

  • Android Canvas之drawBitmap方法案例详解

    前面讲了paint,后面会花几篇主要讲讲canvas,并且由于最近项目比较紧,所以近期的文章都会"短小精悍": paint 作为画笔,里面有非常多而强大的设置方法,比如设置颜色过滤器,设置位图渲染.渐变,设置图像的混合模式等等,而canvas呢?里面提供了哪些利器可以为我们所用,一起来看看:           通过上图我们可以看到,canvas 里的方法基本可以分为这么几类: save.restore 等与层的保存和回滚相关的方法: scale.rotate.clipXXX 等对画布

  • Android Canvas和Bitmap结合绘图详解流程

    目录 Rect/RectF Matrix Canvas Bitmap Rect/RectF 存储四个值的矩形类:左侧.顶部.右侧和底部.可用于直接在画布上绘制或仅用于存储要绘制的对象的大小.Rect和RectF类之间的区别在于 RectF 存储浮点值,而Rect类存储整数. private static Bitmap createDrawableBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth(); int he

  • Android Canvas方法总结最全面详解API(小结)

    本篇文章主要介绍了Android Canvas方法总结最全面详解API,分享给大家,具体如下: 常用方法 drawXxx方法族:以一定的坐标值在当前画图区域画图,另外图层会叠加, 即后面绘画的图层会覆盖前面绘画的图层. clipXXX方法族:在当前的画图区域裁剪(clip)出一个新的画图区域,这个 画图区域就是canvas对象的当前画图区域了.比如:clipRect(new Rect()), 那么该矩形区域就是canvas的当前画图区域 getXxx方法族:获得与Canvas相关一些值,比如宽高

  • Android自定义View实现体重表盘详解流程

    目录 效果视频 分析 起始角度 圆弧 指针 代码 初始化属性 画布 绘制内圆弧 绘制外圆弧 绘制中间指针 绘制中间文字 绘制左右两边文字 动画 全部代码 下载链接 效果视频 分析 起始角度 如下图所示,起点角度为150,终点角度为240 圆弧 白色圆弧为整个圆弧范围,蓝色圆弧为根据数据变动而覆盖白色圆弧,蓝色圆弧比白色圆弧大一点,突出显示 InnerArcPaint.setStrokeWidth( Width * (float)0.1 ); OuterArcPaint.setStrokeWidt

  • Android实现MVVM架构数据刷新详解流程

    目录 效果图 示例结构图 代码解析 导入dataBinding 实体类 xml视图 VM 绑定视图与数据层 效果图 示例结构图 代码解析 导入dataBinding dataBinding{ enabled = true } 实体类 继承BaseObservable public class Sensor extends BaseObservable 为字段添加@Bindable @Bindable public String getTmpValue() { return tmpValue; }

  • Android MVVM架构实现RecyclerView列表详解流程

    目录 效果图 导入引用 导入Recyclerview依赖 导入dataBinding引用 代码解析 建立实体类 建立RecyclerView子项 适配器 建立适配器 设置子项点击事件 adapter全部代码 建立VM层 子项点击事件的使用 VM层代码 数据与视图交互 效果图 导入引用 导入Recyclerview依赖 implementation 'androidx.recyclerview:recyclerview:1.1.0' 导入dataBinding引用 dataBinding { en

  • Android 美食大转盘详解流程

    目录 效果视频 前言 美食大转盘 初始化SurfaceView 测量 绘制 绘制盘块 开始旋转转盘 停止旋转转盘 自定义转盘等份 控件引用 沉浸式体验 效果图 Reveal Animator 效果视频 自定义转盘代码 XML布局代码 Activity代码 代码下载地址 效果视频 前言 你还在为明天吃什么而烦恼嘛 美食大赏帮你解决选择困难症 帮你做出最佳的选择 做吃货,我们是认真的 美食大转盘 本示例使用SurfaceView绘制而成,接下来逐步分析, 文末会贴出全部代码``文末会贴出全部代码``

  • Android性能优化大图治理示例详解

    目录 引言 1 自定义大图View 1.1 准备工作 1.2 图片宽高适配 1.3 BitmapRegionDecoder 2 大图View的手势事件处理 2.1 GestureDetector 2.2 双击放大效果处理 2.3 手指放大效果处理 引言 在实际的Android项目开发中,图片是必不可少的元素,几乎所有的界面都是由图片构成的:像列表页.查看大图页等,都是需要展示图片,而且这两者是有共同点的,列表展示的Item数量多,如果全部加载进来势必会造成OOM,因此列表页通常采用分页加载,加上

  • Android 网络请求框架Volley实例详解

    Android 网络请求框架Volley实例详解 首先上效果图 Logcat日志信息on Reponse Volley特别适合数据量不大但是通信频繁的场景,像文件上传下载不适合! 首先第一步 用到的RequetQueue RequestQueue.Java RequestQueue请求队列首先得先说一下,ReuqestQueue是如何对请求进行管理的...RequestQueue是对所有的请求进行保存...然后通过自身的start()方法开启一个CacheDispatcher线程用于缓存调度,开

  • Android ListView之EfficientAdapte的使用详解

    Android ListView之EfficientAdapte的使用详解 在做Android手机应用开发时, ListView是一个非常常用的控件.如何更新的使用它呢?其实SDK中的例子已经非常的完整了,并且能满足大多数的需要. 如果大家刚开始学习ListView,我建议大家还是直接先看官方的例子好了,这样大家会学到更好的写法以及养成更好的习惯. 下面就以EfficientAdapter为例,看看官网例子是如何使用ListView的: 请大家格外注意getView的书写方法,大家可能从网上也能

随机推荐