图像旋转与翻转姿势解锁,HTML5边玩边学

canvas 图像旋转与翻转姿势解锁

2017/05/26 · HTML5 ·
Canvas

初稿出处:
坑坑洼洼实验室   

多图预警,数学倒霉可径直跳至文末小结。

Canvas图片API十分强劲,有四个最基础的点子,一是显示图片,二是像素级的改动图片后再把它打印到画布上。

一、基本绘图

一、状态及其保存和恢复

在这一节开始之前,我们要先理解一下什么是状态以及状态的保存和恢复。玩过 MFC 编程的人经常能碰到这样的代码:

pOldPen=pDC->SelectObject(pNewPen)

我们在选择一个新画笔对象的同时,总是要保存住旧画笔对象,为什么要这样做呢?因为新画笔对象只是临时用一下,等用完了,我们想恢复到原来的画笔配置时,如果旧的配置事先没有被保存,这些配置就丢失了,也就没办法恢复了。

在 HTML5 绘图中,某一刻的状态就是当前这一刻上下文对象的一系列属性的配置值,只是,决定一个画笔状态的属性比较少,如颜色、粗细、线型之类的,而确定上下文状态的属性比较多,包括下面这些:

需要背景

从一个戏耍需求说起:
澳门葡京 1

  1. 技能选型:canvas
    上图所出示的玩耍场景,“可乐瓶”里有八个“气泡”,要求安装不一样的动画效果,且事关
    deviceOrientation
    的并行,需求有恢宏统计改变元素状态。从性质方面考虑,canvas
    是不二的精选。
  2. 技术点:canvas 绘制图像
    由此对游乐场景的更为分析,可知场景中的“气泡”元素造型都是千篇一律的,且不规则,通过
    canvas 直接绘制形状完成基金较高,因而须求在 canvas 上制图图像。
  3. 技术点:canvas 图像旋转与翻转
    即便“气泡”元素是平等的,可以采纳同样的图像,但图像须求多个角度/三个趋势显示,因而要求对图像进行相应的转动与翻转(镜像),那也是本文所要介绍的关键。

后文代码以下图左边绿框的“气泡”为示范,右侧体现了气象中用到的多个图像:
澳门葡京 2

图像旋转与翻转姿势解锁,HTML5边玩边学。 

 

1、当前上下文对象的移位、旋转、缩放配置

认识 canvas 坐标系

canvas 上图像的团团转和扭转,常见的做法是将 canvas
坐标连串开展转换。由此,大家须求先认识 canvas 坐标种类:
澳门葡京 3
由上图可得,canvas 2D 环境中坐标体系和 Web
的坐标连串是平等的,有以下多少个特征:

  1. 坐标原点 (0,0) 在左上角
  2. X坐标向右边增进
  3. Y坐标向下方延伸

回到上述要求中,大家收获 canvas 对象并安装相应的宽高:

XHTML

<canvas id=’myCanvas’></canvas>

1
<canvas id=’myCanvas’></canvas>

JavaScript

// 获取 canvas 对象 var canvas = document.getElementById(‘myCanvas’)
canvas.width = 750 canvas.height = 1054 // 获取 canvas 2D 上下文对象 var
ctx = canvas.getContext(‘2d’)

1
2
3
4
5
6
// 获取 canvas 对象
var canvas = document.getElementById(‘myCanvas’)
canvas.width = 750
canvas.height = 1054
// 获取 canvas 2D 上下文对象
var ctx = canvas.getContext(‘2d’)

这时候,canvas 的坐标连串如下图所示:
澳门葡京 4

1、通过drawImage()将图片显示在画布上

  首先,定义2D渲染变量ct(这里用了Jquery库):

2、当前上下文对象的 strokeStyle, fillStyle, globalAlpha, lineWidth,
lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur,
shadowColor, globalCompositeOperation 属性值

在 canvas 上制图图像

在 canvas 上制图图像,可以行使 drawImage()
方法,语法如下(详细用法参见
MDN):

JavaScript

void ctx.drawImage(image, dx, dy); void ctx.drawImage(image, dx, dy,
dWidth, dHeight); void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx,
dy, dWidth, dHeight);

1
2
3
void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

亟待留意的是,图像必须加载完毕,才能绘制到 canvas 上,否则会油可是生空白:

JavaScript

var img = new Image() img.src = ‘xxxxxxx.png’ img.onload = function() {
// 绘制图像 ctx.drawImage(img, 512, 220, 160, 192); }

1
2
3
4
5
6
var img = new Image()
img.src = ‘xxxxxxx.png’
img.onload = function() {
// 绘制图像
ctx.drawImage(img, 512, 220, 160, 192);
}

那时候,便得以 canvas 上见到一个未旋转/翻转的“气泡”图像,如下图所示:
澳门葡京 5

     var img = new Image();

 

澳门葡京 ,3、当前上下文对象的剪裁路径配置

canvas 坐标变换

接下去,大家再来精晓 canvas 坐标的更换。上述必要仅涉及 2D
绘制上下文,因而仅介绍 2D 绘制上下文支持的各个变换:

  1. 平移 translate:
JavaScript

ctx.translate(x, y)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32683b188872764-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32683b188872764-1" class="crayon-line">
ctx.translate(x, y)
</div>
</div></td>
</tr>
</tbody>
</table>

translate() 方法接受两个参数。x 是左右偏移量,y 是上下偏移量。
  1. 旋转 rotate:
JavaScript

ctx.rotate(angle)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32683e262081345-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32683e262081345-1" class="crayon-line">
ctx.rotate(angle)
</div>
</div></td>
</tr>
</tbody>
</table>

rotate() 方法只接受一个参数。旋转的角度
angle,它是顺时针方向的,以弧度为单位的值。
  1. 缩放 scale:
JavaScript

ctx.scale(x, y)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326841695520558-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326841695520558-1" class="crayon-line">
ctx.scale(x, y)
</div>
</div></td>
</tr>
</tbody>
</table>

scale() 方法接受两个参数。x 和 y
分别是横轴和纵轴的缩放因子。其缩放因子默认是 1,如果比 1
小是缩小,如果比 1 大则放大。
  1. 变形 transform:
JavaScript

ctx.transform (a, b, c, d, e, f)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326844923845216-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326844923845216-1" class="crayon-line">
ctx.transform (a, b, c, d, e, f)
</div>
</div></td>
</tr>
</tbody>
</table>

transform() 方法是对当前坐标系进行矩阵变换。



JavaScript

ctx.setTransform (a, b, c, d, e, f)

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326847245473351-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326847245473351-1" class="crayon-line">
ctx.setTransform (a, b, c, d, e, f)
</div>
</div></td>
</tr>
</tbody>
</table>

setTransform()
方法重置变形矩阵。先将当前的矩阵重置为单位矩阵(即默认的坐标系),再用相同的参数调用
transform() 方法设置矩阵。  
以上两个方法均接受六个参数,具体如下:
参数 含义
a 水平缩放绘图
b 水平倾斜绘图
c 垂直倾斜绘图
d 垂直缩放绘图
e 水平移动绘图
f 垂直移动绘图

     img.src = ”;

var ct = $(#canvasId).get(0).getContext(‘2d’);

地方这一层层安顿决定了脚下这一阵子上下文对象的情景,其中移动、旋转、缩放、globalCompositeOperation(组合)、裁剪下边咱们马上会讲到。

图像旋转的落到实处

澳门葡京 6
上图所示“气泡”,宽为 160,高为 192,x 轴方向距离原点 512,y
轴方向距离原点 220,逆时针旋转 35 度。
要绘制该“气泡”,须要先将坐标系平移(translate),再旋转(rotate)。具体贯彻步骤如下:
澳门葡京 7

save() 方法与 restore() 方法:

  1. save() 方法用来保存 Canvas 状态的,没有参数。每五回调用 save()
    方法,当前的情状就会被推入栈中保存起来。当前事态包括:

    • 当下利用的变形(移动/旋转/缩放)
    • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap,
      lineJoin, miterLimit, shadowOffsetX, shadowOffsetY,
      shadowBlur, shadowColor, globalCompositeOperation 的值
    • 时下的裁切路径(clipping path)
  2. restore() 方法用来平复 Canvas 状态,没有参数。每两遍调用 restore()
    方法,上一个保存的景色就从栈中弹出,所有设定都过来。
  3. 动静保存在栈中,可以嵌套使用 save() 与 restore()。

     

  以下是绘制各类基本图形的方法:

 

图像翻转的落到实处

澳门葡京 8
上图所示“气泡”,宽为 160,高为 192,x 轴方向距离原点 172,y
轴方向距离原点 365,顺时针旋转 35 度。
要绘制该“气泡”,要求先将坐标种类活动(translate),翻转(scale),平移(translate),再旋转(rotate)。具体落实步骤如下:
澳门葡京 9
迄今,完毕了“气泡”的镜像翻转,但转头后的“气泡”还亟需旋转特定的角度,在章程一的底子上此起彼伏对坐标连串开展转换:
澳门葡京 10
以上操作中举办了五遍活动(translate)操作,可以开展联合简化:
澳门葡京 11

     img.onload = function(){

 

二、状态的保存与还原

坐标系列的矩阵变换

前文介绍了 2D
绘制上下文变形(transform)变换,实际是一向改动变换的矩阵,它能够完成前边介绍的活动(translate)/旋转(rotate)/缩放(
scale)变换,还能完成转移/镜像反射变换等。矩阵计算遵从数学矩阵公式规则:
澳门葡京 12
由上公式可得:

x’ = ax + cy + e y’ = bx + dy + f

1
2
x’ = ax + cy + e
y’ = bx + dy + f

矩阵变换可完结以下变换效果:

  1. 平移 translate:
JavaScript

x' = 1x+0y+tx = x+tx y' = 0x+1y+ty = y+ty

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326850164003354-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326850164003354-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326850164003354-1" class="crayon-line">
x' = 1x+0y+tx = x+tx
</div>
<div id="crayon-5b8f33c326850164003354-2" class="crayon-line crayon-striped-line">
y' = 0x+1y+ty = y+ty
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_translate.png)
  1. 旋转 rotate:
JavaScript

x' = x\*cosθ-y\*sinθ+0 = x\*cosθ-y\*sinθ y' = x\*sinθ+y\*cosθ+0 =
x\*sinθ+y\*cosθ

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326853823296543-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326853823296543-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326853823296543-1" class="crayon-line">
x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
</div>
<div id="crayon-5b8f33c326853823296543-2" class="crayon-line crayon-striped-line">
y' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_rotate.png)
  1. 缩放 scale:
JavaScript

x' = Sx\*x+0y+0 = Sx\*x y' = 0x+Sy\*y+0 = Sy\*y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326856096178959-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326856096178959-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326856096178959-1" class="crayon-line">
x' = Sx*x+0y+0 = Sx*x
</div>
<div id="crayon-5b8f33c326856096178959-2" class="crayon-line crayon-striped-line">
y' = 0x+Sy*y+0 = Sy*y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_scale.png)
  1. 切变
JavaScript

x' = x+y\*tan(θx)+0 = x+y\*tan(θx) y' = x\*tan(θy)+y+0 =
x\*tan(θy)+y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326859970129213-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326859970129213-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326859970129213-1" class="crayon-line">
x' = x+y*tan(θx)+0 = x+y*tan(θx)
</div>
<div id="crayon-5b8f33c326859970129213-2" class="crayon-line crayon-striped-line">
y' = x*tan(θy)+y+0 = x*tan(θy)+y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_skew.png)
  1. 镜像反射
JavaScript

// 定义(ux,uy)为直线(y=kx)方向的单位向量 ux=1/sqrt(1+k^2)
uy=k/sqrt(1+k^2) x' = (2\*ux^2-1)\*x+2\*ux\*uy\*y y' =
2\*ux\*uy\*x+(2\*uy^2-1)\*y

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32685c751852723-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32685c751852723-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f33c32685c751852723-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c32685c751852723-1" class="crayon-line">
// 定义(ux,uy)为直线(y=kx)方向的单位向量
</div>
<div id="crayon-5b8f33c32685c751852723-2" class="crayon-line crayon-striped-line">
ux=1/sqrt(1+k^2)
</div>
<div id="crayon-5b8f33c32685c751852723-3" class="crayon-line">
uy=k/sqrt(1+k^2)
</div>
<div id="crayon-5b8f33c32685c751852723-4" class="crayon-line crayon-striped-line">
x' = (2*ux^2-1)*x+2*ux*uy*y
</div>
<div id="crayon-5b8f33c32685c751852723-5" class="crayon-line">
y' = 2*ux*uy*x+(2*uy^2-1)*y
</div>
</div></td>
</tr>
</tbody>
</table>

![](http://misc.aotu.io/Yettyzyt/2017-05-25-canvas-img-rotate-and-flip/matirix_flip.png)

构成上述公式,可推导出图像旋转和扭转的矩阵变换落成:

  1. 图像旋转:
    澳门葡京 13
  2. 图像翻转:
    澳门葡京 14
  3. 图像镜像反射(翻转+旋转):
    澳门葡京 15

          ctx.drawImage(img,0,0)

复制代码

地点大家说某说话的情景由那么多属性决定,大家要封存这一刻的动静就要把那几个属性值一个一个都保存,恢复生机的时候在一个一个都安装回去,那也太费事了。确实是这么的,所以上下文对下提供明白四个简单的不二法门,对事态进行封存和死灰复燃,他们是:

像素操作完毕图像翻转

除却坐标体系转换,canvas
的像素操作同样可以落成图像的扭曲。首先须求驾驭下 getImageData()
方法(详细用法参见MDN)和
putImageData()(详细用法参见MDN)方法:

  1. getImageData()
    CanvasRenderingContext2D.getImageData() 再次回到一个 ImageData
    对象,用来讲述 canvas
    区域隐含的像素数量,那一个区域通过矩形表示,开首点为 (sx, sy)、宽为
    sw、高为 sh。
JavaScript

ImageData ctx.getImageData(sx, sy, sw, sh);

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f33c326860751214897-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f33c326860751214897-1" class="crayon-line">
ImageData ctx.getImageData(sx, sy, sw, sh);
</div>
</div></td>
</tr>
</tbody>
</table>
  1. putImageData()
    CanvasRenderingContext2D.putImageData() 是 Canvas 2D API
    将数据从已有些 ImageData 对象绘制到位图的格局。
    借使提供了脏矩形,只可以绘制矩形的像素。

JavaScript

void ctx.putImageData(imagedata, dx, dy); void
ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth,
dirtyHeight);

1
2
void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);

水平翻转已毕:

JavaScript

// 绘制图像 ctx.drawImage(img, x, y, width, height) // 获取 img_data
数据 var img_data = ctx.getImageData(x, y, width, height), i, i2, t, h
= img_data.height, w = img_data.width, w_2 = w / 2; // 将 img_data
的数额水平翻转 for (var dy = 0; dy < h; dy ++) { for (var dx = 0; dx
< w_2; dx ++) { i = (dy << 2) * w + (dx << 2) i2 = ((dy

  • 1) << 2) * w – ((dx + 1) << 2) for (var p = 0; p < 4;
    p ++) { t = img_data.data[i + p] img_data.data[i + p] =
    img_data.data[i2 + p] img_data.data[i2 + p] = t } } } //
    重绘水平翻转后的图样 ctx.putImageData(img_data, x, y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 绘制图像
ctx.drawImage(img, x, y, width, height)
// 获取 img_data 数据
var img_data = ctx.getImageData(x, y, width, height),
    i, i2, t,
    h = img_data.height,
    w = img_data.width,
    w_2 = w / 2;
// 将 img_data 的数据水平翻转
for (var dy = 0; dy < h; dy ++) {
    for (var dx = 0; dx < w_2; dx ++) {
        i = (dy << 2) * w + (dx << 2)
        i2 = ((dy + 1) << 2) * w – ((dx + 1) << 2)
        for (var p = 0; p < 4; p ++) {
            t = img_data.data[i + p]
            img_data.data[i + p] = img_data.data[i2 + p]
            img_data.data[i2 + p] = t
        }
    }
}
// 重绘水平翻转后的图片
ctx.putImageData(img_data, x, y)

     }

//绘制矩形(填充/描框)

save( ) 和 restore( )

小结

时至今日,作者的数学姿势又过来到了高考水平。

  1. 图像旋转:
    • 基本功变换法:
    JavaScript

    ctx.save() ctx.translate(x + width / 2, y + height / 2)
    ctx.rotate(angle \* Math.PI / 180) ctx.drawImage(img, -width /
    2, -height / 2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686a931313088-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686a931313088-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686a931313088-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32686a931313088-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32686a931313088-2" class="crayon-line crayon-striped-line">
    ctx.translate(x + width / 2,  y + height / 2)
    </div>
    <div id="crayon-5b8f33c32686a931313088-3" class="crayon-line">
    ctx.rotate(angle * Math.PI / 180)
    </div>
    <div id="crayon-5b8f33c32686a931313088-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c32686a931313088-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    ctx.save() var rad = angle \* Math.PI/180 ctx.transform(
    Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x +
    width / 2, y + height / 2) ctx.drawImage(img, -width / 2,
    -height / 2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686d570876064-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32686d570876064-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32686d570876064-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32686d570876064-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32686d570876064-2" class="crayon-line crayon-striped-line">
    var rad = angle * Math.PI/180
    </div>
    <div id="crayon-5b8f33c32686d570876064-3" class="crayon-line">
    ctx.transform( Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x + width / 2,  y + height / 2)
    </div>
    <div id="crayon-5b8f33c32686d570876064-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c32686d570876064-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
  1. 图像翻转:
    • 基础变换法:
    JavaScript

    // 方法一 ctx.save() ctx.translate(canvasWidth, 0) ctx.scale(-1,
    1) ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326870431697867-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326870431697867-6">
    6
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326870431697867-1" class="crayon-line">
    // 方法一
    </div>
    <div id="crayon-5b8f33c326870431697867-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326870431697867-3" class="crayon-line">
    ctx.translate(canvasWidth, 0)
    </div>
    <div id="crayon-5b8f33c326870431697867-4" class="crayon-line crayon-striped-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326870431697867-5" class="crayon-line">
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326870431697867-6" class="crayon-line crayon-striped-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>




    JavaScript

    // 方法二 ctx.save() ctx.scale(-1, 1) ctx.drawImage(img,
    -width-x, y, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326873786084115-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326873786084115-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326873786084115-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326873786084115-1" class="crayon-line">
    // 方法二
    </div>
    <div id="crayon-5b8f33c326873786084115-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326873786084115-3" class="crayon-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326873786084115-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326873786084115-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    // 方法一 ctx.save() ctx.transform(-1, 0, 0, 1, canvasWidth, 0)
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326877860333719-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326877860333719-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326877860333719-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326877860333719-1" class="crayon-line">
    // 方法一
    </div>
    <div id="crayon-5b8f33c326877860333719-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326877860333719-3" class="crayon-line">
    ctx.transform(-1, 0, 0, 1, canvasWidth, 0)
    </div>
    <div id="crayon-5b8f33c326877860333719-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, canvasWidth-width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c326877860333719-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>




    JavaScript

    // 方法二 ctx.save() ctx.transform(-1, 0, 0, 1, 0, 0)
    ctx.drawImage(img, -width-x, y, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687a381566637-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687a381566637-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687a381566637-5">
    5
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32687a381566637-1" class="crayon-line">
    // 方法二
    </div>
    <div id="crayon-5b8f33c32687a381566637-2" class="crayon-line crayon-striped-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c32687a381566637-3" class="crayon-line">
    ctx.transform(-1, 0, 0, 1, 0, 0)
    </div>
    <div id="crayon-5b8f33c32687a381566637-4" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width-x, y, width, height)
    </div>
    <div id="crayon-5b8f33c32687a381566637-5" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   像素操作法:  


    JavaScript

    ctx.drawImage(img, x, y, width, height) var img\_data =
    ctx.getImageData(x, y, width, height), i, i2, t, h =
    img\_data.height, w = img\_data.width, w\_2 = w / 2; for (var dy
    = 0; dy &lt; h; dy ++) { for (var dx = 0; dx &lt; w\_2; dx ++) {
    i = (dy &lt;&lt; 2) \* w + (dx &lt;&lt; 2) i2 = ((dy + 1)
    &lt;&lt; 2) \* w - ((dx + 1) &lt;&lt; 2) for (var p = 0; p &lt;
    4; p ++) { t = img\_data.data\[i + p\] img\_data.data\[i + p\] =
    img\_data.data\[i2 + p\] img\_data.data\[i2 + p\] = t } } }
    ctx.putImageData(img\_data, x, y)

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-10">
    10
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-11">
    11
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-12">
    12
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-13">
    13
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-14">
    14
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-15">
    15
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-16">
    16
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c32687d641942026-17">
    17
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c32687d641942026-18">
    18
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c32687d641942026-1" class="crayon-line">
    ctx.drawImage(img, x, y, width, height)
    </div>
    <div id="crayon-5b8f33c32687d641942026-2" class="crayon-line crayon-striped-line">
    var img_data = ctx.getImageData(x, y, width, height),
    </div>
    <div id="crayon-5b8f33c32687d641942026-3" class="crayon-line">
        i, i2, t,
    </div>
    <div id="crayon-5b8f33c32687d641942026-4" class="crayon-line crayon-striped-line">
        h = img_data.height,
    </div>
    <div id="crayon-5b8f33c32687d641942026-5" class="crayon-line">
        w = img_data.width,
    </div>
    <div id="crayon-5b8f33c32687d641942026-6" class="crayon-line crayon-striped-line">
        w_2 = w / 2;
    </div>
    <div id="crayon-5b8f33c32687d641942026-7" class="crayon-line">
    for (var dy = 0; dy &lt; h; dy ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-8" class="crayon-line crayon-striped-line">
        for (var dx = 0; dx &lt; w_2; dx ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-9" class="crayon-line">
            i = (dy &lt;&lt; 2) * w + (dx &lt;&lt; 2)
    </div>
    <div id="crayon-5b8f33c32687d641942026-10" class="crayon-line crayon-striped-line">
            i2 = ((dy + 1) &lt;&lt; 2) * w - ((dx + 1) &lt;&lt; 2)
    </div>
    <div id="crayon-5b8f33c32687d641942026-11" class="crayon-line">
            for (var p = 0; p &lt; 4; p ++) {
    </div>
    <div id="crayon-5b8f33c32687d641942026-12" class="crayon-line crayon-striped-line">
                t = img_data.data[i + p]
    </div>
    <div id="crayon-5b8f33c32687d641942026-13" class="crayon-line">
                img_data.data[i + p] = img_data.data[i2 + p]
    </div>
    <div id="crayon-5b8f33c32687d641942026-14" class="crayon-line crayon-striped-line">
                img_data.data[i2 + p] = t
    </div>
    <div id="crayon-5b8f33c32687d641942026-15" class="crayon-line">
            }
    </div>
    <div id="crayon-5b8f33c32687d641942026-16" class="crayon-line crayon-striped-line">
        }
    </div>
    <div id="crayon-5b8f33c32687d641942026-17" class="crayon-line">
    }
    </div>
    <div id="crayon-5b8f33c32687d641942026-18" class="crayon-line crayon-striped-line">
    ctx.putImageData(img_data, x, y)
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
  1. 图像镜像对称(翻转+旋转):
    • 基本功变换法:
    JavaScript

    ctx.save() ctx.scale(-1, 1) ctx.translate(-width/2-x,
    y+height/2) ctx.rotate(-angle \* Math.PI / 180)
    ctx.drawImage(img, -width / 2, -height / 2, width, height)
    ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326880900901818-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326880900901818-6">
    6
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326880900901818-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326880900901818-2" class="crayon-line crayon-striped-line">
    ctx.scale(-1, 1)
    </div>
    <div id="crayon-5b8f33c326880900901818-3" class="crayon-line">
    ctx.translate(-width/2-x, y+height/2) 
    </div>
    <div id="crayon-5b8f33c326880900901818-4" class="crayon-line crayon-striped-line">
    ctx.rotate(-angle * Math.PI / 180)
    </div>
    <div id="crayon-5b8f33c326880900901818-5" class="crayon-line">
    ctx.drawImage(img, -width / 2,  -height / 2, width, height)
    </div>
    <div id="crayon-5b8f33c326880900901818-6" class="crayon-line crayon-striped-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

-   矩阵变换法:  


    JavaScript

    ctx.save() var k = Math.tan( (180-angle)/2 \* Math.PI / 180 )
    var ux = 1 / Math.sqrt(1 + k \* k) var uy = k / Math.sqrt(1 +
    k \* k) ctx.transform( (2\*ux\*ux-1), 2\*ux\*uy, 2\*ux\*uy,
    (2\*uy\*uy-1), x + width/2, y + height/2 ) ctx.drawImage(img,
    -width/2, -height/2, width, height) ctx.restore()

    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f33c326883449167631-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f33c326883449167631-7">
    7
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f33c326883449167631-1" class="crayon-line">
    ctx.save()
    </div>
    <div id="crayon-5b8f33c326883449167631-2" class="crayon-line crayon-striped-line">
    var k = Math.tan( (180-angle)/2 * Math.PI / 180 )
    </div>
    <div id="crayon-5b8f33c326883449167631-3" class="crayon-line">
    var ux = 1 / Math.sqrt(1 + k * k)
    </div>
    <div id="crayon-5b8f33c326883449167631-4" class="crayon-line crayon-striped-line">
    var uy = k / Math.sqrt(1 + k * k)
    </div>
    <div id="crayon-5b8f33c326883449167631-5" class="crayon-line">
    ctx.transform( (2*ux*ux-1), 2*ux*uy, 2*ux*uy, (2*uy*uy-1), x + width/2, y + height/2 )
    </div>
    <div id="crayon-5b8f33c326883449167631-6" class="crayon-line crayon-striped-line">
    ctx.drawImage(img, -width/2, -height/2, width, height)
    </div>
    <div id="crayon-5b8f33c326883449167631-7" class="crayon-line">
    ctx.restore()
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>

 

ct.fillRect(x,y,w,h)

save 和 restore 方法可以屡屡调用,每调用三回 save
方法,调用时的景观(即一多级属性值)就压入一个栈中。

参照作品

  • 《W3cplus – CANVAS
    系列》
  • 《html5
    canvas.transform[转]》
  • 《html5 canvas
    学习笔记》
  • 《在HTML5中扭曲图片》

注明:本文琢磨的 canvas 环境均为 2D
环境。若有更好的达成形式,欢迎留言告知。

2 赞 5 收藏
评论

澳门葡京 16

2、截取图片的一有的到画布上

ct.strokeRect(x,y,w,h)

每调用五遍 restore 方法,最终两回 save 的情事就被复苏,即出栈。

 

 

设想一下弹匣,第一颗被发射出去的枪弹,总是末了一个被压入弹匣的。

//(sx , sy )初叶地方

//绘制路径–线条

 

//(sw , sh )目的大小(缩放)

ct.beginPath();

三、变型

//(dx , dy )截取开始地方

ct.moveTo(x0,y0);

1、移动:translate(dx,dy)

//(dw , dh )截取大小

ct.lineTo(x1,y1);

本条点子看起来很粗略,其实它含有了自然的数学意义,你可以认为是所有坐标系的原点暴发了移动,新坐标系下肆意一点(x,y)相当于原坐标系下的坐标为:

 

ct.closePath();

x’=x+dx
y’=y+dy

function drawImage(Image , sx , sy , sw , sh , dx , dy , dw , dh){

ct.stroke();

设若大家调用 ctx.translate(5,8)
改变上下文对象的坐标系状态,然后在新情状下的点(3,2)绘图,相当于图像被绘制到了原状态下的点(8,10)处,即

     //code…

 

x’=5+3=8
y’=5+2=10

 

//绘制路径–圆弧

兴许你会问,为何要那么勤奋,直接在(8,10)处绘制比行吗?比如把

}

ct.beginPath();

ctx.translate(5,8)
ctx.drawImage(img,3,2)

 //看第八个缩放和平移图片的事例就会发觉那几个函数的兵不血刃之处

ct.arc(x,y,r,start,end,true);

改成

3、旋转图片

ct.closePath();

ctx.drawImage(img,8,10)

 

ct.fill();

这么不是更简约、更直白吗?

/*
                    1、将近期的画布背景保存起来,context.save()
                    2、重置变换矩阵,context.setTransform(1,0,0,1,0,0);
                    3、编码转换角度的算法,angle = 90 * Math.PI /
180;使用PI单位
                      context.translate(x,y),因为旋转的任何画布对象
                    4、context.drawImage
                   
               */
               function rotate() {
                    ctx.save();
                    ctx.setTransform(1,0,0,1,0,0);
                    ctx.translate(0,0)
                    var angle = 90 * Math.PI / 180;
                    ctx.rotate(angle);
                    ctx.drawImage(img1,10,30);
                    ctx.restore();
               }

 

自己的精通是,移动越多的景况下是为别的图形变换服务的,恰当的改观坐标原点可以让图形学计算更好领悟,并带来很大方便,上边我举个大概的事例,如果:

 

//绘制文本

有一条线段 ,是 x 轴正迈入的一小段

4、缩放和平移一张图纸

ct.font = “30px serif…”;

y = 0 (1 <= x <= 3),

强有力drawImage()方法可以形成全体需要

ct.fillText(txt,x,y);

比方以坐标原点为圆心,逆时针转动90度,则线段与 y
轴正向重合,旋转后的线条为:

看这么些测试demo:

ct.strokeText(txt,x,y);

x = 0 (1 <= y <= 3)

 

但是咱们不容许每趟旋转都以原点为圆心举办旋转,如果大家以线段的一个端点(1,0)为圆心举行旋转,我们怎么才能收获旋转后线段上每一点的坐标值呢?其实那几个历程能够分为三步:

 

//设置样式

第一步:移动原点坐标到(1,0),新的线条仍旧在 x
轴上,然而方程变为了:y = 0 (0 <= x <= 2)

5、像素处理

ct.fillStyle = “rgb(r,g,b)”;

其次步:以新坐标系的原点为圆心进行旋转,得到新坐标系下的线条 x = 0
(0 <= y <= 2)

 

ct.strokeStyle = “rgb()”;

其三步:将新坐标系的原点移动到新坐标系下(-1,0)处,即将原点恢复生机到原来的职位,此时的线条为:x
= 1 (0 <= y <= 2)

imagedata = context.createImageData(sw, sh)

ct.lineWidth = 5;

其三步所获得的线条就是终极索要绘制的线条。

// 成立一个100×100的区域来存储像素新闻

复制代码

从这几个例子大家得以看出来,固然在这么简单的事态下,若是不运动坐标原点来平昔总括旋转后的图样,也是相比较勤奋的。

imagedata = context.createImageData(imagedata)

  还提供了有些心灵手巧的艺术:

提示当您活动坐标原点此前,千万别忘了封存处境,当然,绘制落成后也别放了还原境况。

// like copy

 

2、缩放 scale(sx, sy)

imagedata = context.createImageData()

//橡皮擦(擦除矩形范围)

以此同样很简短,sx, sy 是缩放比例因子,缩放后新坐标系下肆意一点 (x,y)
相当于原坐标系下的坐标为:

// 创造一个空的图像实例

ct.clearRect(x,y,w,h);

x’ = x * sx
y’ = y * sy

 

 

同一,改变坐标种类连接毫无忘记保存和回复处境

ImageData 对象涵盖三个属性

//重置样式

3、旋转 rotate(A)

imagedata.width,

canvas.attr(“width”,w);

angle 是旋转角度,旋转后新坐标系下肆意一点 (x,y)
约等于原坐标系下的坐标为:

imagedata.height,

 

x’ = x cosA – y sinA
y’ = x sinA + y cosA

imagedata.data:存储着图片像素数据的数组,每多个数分别表示一个像素点的R,G,B,alpha透明度值

 

平等,改变坐标序列连接毫无忘记保存和死灰复燃情形

 

二、高级成效

4、变形 transform(m11, m12, m21, m22, dx, dy)

获取图像数据:

 

实际上后边讲的运动、缩放、旋转都是变形的特例,transform
方法的四个参数组成了一个变形矩阵,如下

imagedata = context.getImageData(sx,sy,sw,sh);

  以下是对画布的有些变换操作:

m11 m21 dx
m12 m22 dy
0 0 1

多少个参数定义地点和尺寸的矩形并从画布上复制到imagedata实例中

 

调用 transform 方法就一定于用这个参数为上下文对象设置了新的变形矩阵,关于变形矩阵的具体内容可以参见图形学相关材料,上边给出多少个大致特例:

 

复制代码

移动 translate(dx,dy):相当于 transform(1,0,0,1,dx,dy)

将图像数据打印到画布上:

ct.save()/restore()  //保存/恢复

缩放 scale(sx,xy):相当于 transform(sx,0,0,sy,0,0)

 

ct.translate(x,y)    //平移

旋转 rotate(A):相当于 transform(cosA,sinA,-sinA,cosA,0,0)

context.putImageData(imagedata,dx,dy)

ct.scale(a,b)        //放大、缩小

以 (dx,dy) 为基准点旋转角度 A:transform(cosA, sinA, -sinA, cosA,
dx(1-cosA) + dysinA, dy(1-cosA) – dxsinA
)

context.putImageData(imagedata,dx,dy
[,dirtyX,dirtyY,dirtyWidth,dirtyHeight])

ct.rotate(Math.PI)   //绕(0,0)旋转

以 (dx,dy) 为基准点举行 (sx,sy)比例缩放:transform(sx, 0, 0, sy,
dx(1-sx), dy(1-sy)
)

 

 

还有不少其他更扑朔迷离的变形,大家可以参考图形学相关资料。

修改像素音讯:

//变换矩阵

上面给出一个基准点变形的事例,鼠标在图像上的某点保持按下处境,图像就会以该点为基准点举行缩放或者旋转,松手按钮后图像复原。

 

ct.transform(xScale,ySkew,xSkew,yScale,xTrans,yTrans)   

提醒:即缩放又转悠这么些例子,并没有动用变形矩阵,而是用了四步简单变形复合而成。效果如下:

/*
          *
对像素的透明属性进行修改时,值范围是0~255(许多地方此值的界定是0-1)
          * 
          */
          for(var j=3;j<imageData.data.length;j+=4){
               imageData.data[j] = 128;
          }

ct.setTransform(xScale,ySkew,xSkew,yScale,xTrans,yTrans) //重置 

您的浏览器不支持 <canvas>标签,请使用 Chrome 浏览器 或者 FireFox浏览器

 

复制代码

运动——在图像上按住鼠标并活动
基准点缩放——在图像某点处按住鼠标
基准点旋转——在图像某点处按住鼠标
基准点缩放同时旋转——在图像某点处按住鼠标


  关于变换矩阵,有一篇很好的稿子可以变本加厉你的精通:

 

由于安全考虑,只可以操作来自同域下的图片资源。而在本地测试时,大多数浏览器会认为来自本地的图形是来源于其它一个域。

 

四、组合

由此测试时,须要搭建一个web服务器

  那是些常用的操作:

所谓组合就是一个图形绘制在另一个图片之上,会产出哪些意义。默许的处境下是地点的图纸覆盖了上面的图形,称之为
source-over 。

 

 

上下文对象总共十二中结合品种,属性 globalCompositeOperation
被用来安装组成品种,如下:

6、将一个canvas对象复制至另一个canvas对象中

复制代码

globalCompositeOperation = type

 thecanvas = d.getElementById(‘canvas’)

ct.globalAlpha = 0.5    //透明度

type 是上面 12 种字符串值之一:

context.drawImage(thecanvas,0,0);

 

注意:上面装有例子中,蓝色方块是先绘制的,即“已有的 canvas
内容”,红色圆形是背后绘制,即“新图形”。


//阴影

ct.shadowBlur = 20;     //扩散

 

ct.shadowOffsetX = 10;

五、裁剪路径

ct.shadowOffsetY = 10;

在率先篇小说中我们就介绍了上下文对象的两大类绘制方法,即绘制线条的
stroke 文山会海措施和填充区域的 fill
多级措施,其实,上下文对象还有一类绘制方法叫做裁剪 clip

ct.shadowColor = rgba;

怎样是裁剪呢?打个不适合的只要吧,你用一块布把电视屏幕遮住了,那时候电视显示屏上的任何变更你都看不见了。

 

不过,假若您布上裁剪出一块区域,那么至少那块区域里的屏幕变化你能瞥见。

//渐变(线性/放射性)

当然剪裁区域之外的屏幕也在不停地扭转(即也在重复绘制),只是你看不见罢了。那就是所谓的剪裁,寻常在拍卖图像时平时会遇见那种要求。

ct.createLinearGradient(x,y,x1,y1)

那就是说如何又是剪裁路径呢?下面说要在布上裁剪出一块区域,那块区域是怎么来的吧?

ct.createRadialGradient(x,y,r,x1,y1,r1)

那块区域是在裁剪动作 clip
从前,由绘图路径设定的,他得以是方形、圆形、五星形和任何任何可以绘制的概况形状。

//设渐变的一味颜色

从而,裁剪路径实际上就是绘图路径,只然而这些途径不是拿来绘图的,而是设定显示区域和屏蔽区域的一个分界线。

addColorStop(0,”rgb()”)/(1,”rgb()”);

比方你不知道怎么是绘图路径,在前的篇章 HTML5边玩边学(2):基础绘图
中有介绍。

复制代码

下边的事例用了三种办法开展裁剪。第一种办法显示一过往移动的圈子裁剪区域,大体流程如下:

  贝塞尔曲线绘制:

1、清空画布

 

2、改变圆心地方

//最后七个参数是极端的坐标点

3、在新的圆心地方处安装一个圆形的剪裁区域

ct.beginPath();

4、在画布上绘制好看的女人图像

ct.moveTo(50,250);

出于我们不停地在新岗位处设定裁剪区域,大家就能瞥见裁剪区域在活动,而裁剪区域之外的图像并从未显得出来

ct.quadraticCurveTo(250,100,450,250)  //四次贝塞尔曲线

 

ct.bezierCurveTo(150,50,350,450,450,250) //一次贝塞尔曲线

我们用 clip
方法设置裁剪区域,之后绘制的图片只可以显示裁剪区域内的一有的,而裁剪区域之外总是显示画布的背景观。

ct.stroke();

如果并不想全盘挡住裁剪区域之外的图像,比如大家想让裁剪区域之内的图像完全浮现出来,可是裁剪区域之外的图像以半晶莹剔透的办法体现出来,该如何做吧?

  画布导出为图像:

那即将动用大家地点说的的咬合知识了。第二中艺术突显半透明的遮光,大体思路如下:

 

1、清空画布

//生成图片的src地址

2、将画布的具备区域用一种半透明的颜色填充,那里我用的是灰色,透明度0.9

var imgURL = canvas.get(0).toDataURL();

3、改变圆心地方

//以下将画布替换为图片

4、在新的圆心地方处以 XOR
格局绘制圆,那样和圆形臃肿的有些将被擦除掉
那时候大家得到的图形效果是一个半透明的画布,上面有一块完全透明的圈子区域

var img = $(“<img></img>”);

5、 在第 4 步的功底上,以 destination-over
格局绘制美人图像,那时候美观的女生图像将会油然则生在第 4
步图形效果的下方,想象一下,正好是大家想要的成效呢?!

img.attr(“src”,imgURL);

效能如下:

canvas.replaceWith(img);

您的浏览器不协助 <canvas>标签,请使用 Chrome 浏览器 或者 FireFox浏览器

 

 

 

享有程序的代码:

三、图片处理

澳门葡京 17澳门葡京 18代码

 

<canvas id=”canvas1″ width=”250″ height=”300″ 
    onmousedown=”trans.transform(event);”  
    onmouseup=”trans.init(event);” 
    onmousemove=”trans.translate(event);” 
    style=”background-color:black”>
    你的浏览器不协助 <canvas>标签,请使用 Chrome 浏览器 或者 FireFox 浏览器
</canvas><br/>
<input type=”radio” name=”r” id=”r1″ checked=”checked”>移动——在图像上按住鼠标并活动<br />
<input type=”radio” name=”r” id=”r2″>基准点缩放——在图像某点处按住鼠标<br />
<input type=”radio” name=”r”  id=”r3″>基准点旋转——在图像某点处按住鼠标<br />
<input type=”radio” name=”r”  id=”r4″>基准点缩放同时旋转——在图像某点处按住鼠标<br />

  图片的引入和调整(图片的转换就是画布的转换,不再介绍):

<canvas id=”canvas3″ width=”250″ height=”300″ style=”background-color:black”>
    你的浏览器不帮忙 <canvas>标签,请使用 Chrome 浏览器 或者 Fire福克斯 浏览器
</canvas><br/>
<input type=”button” onclick=”move(1);” value=”移动裁剪区域”>
<input type=”button” onclick=”move(2);” value=”移动蒙版”>
<input type=”button” onclick=”stop();” value=”截止活动”><br />

 

        <div>
            <table>
                <tr>
                    <td><canvas id=”tut0″ width=”125″ height=”125″></canvas><br/><label id=”lab0″></label></td>
                <td><canvas id=”tut1″ width=”125″ height=”125″></canvas><br/><label id=”lab1″></label></td>
                <td><canvas id=”tut2″ width=”125″ height=”125″></canvas><br/><label id=”lab2″></label></td>
                <td><canvas id=”tut3″ width=”125″ height=”125″></canvas><br/><label id=”lab3″></label></td>
                </tr>
                <tr>
                    <td><canvas id=”tut4″ width=”125″ height=”125″></canvas><br/><label id=”lab4″></label></td>
                <td><canvas id=”tut5″ width=”125″ height=”125″></canvas><br/><label id=”lab5″></label></td>
                <td><canvas id=”tut6″ width=”125″ height=”125″></canvas><br/><label id=”lab6″></label></td>
                <td><canvas id=”tut7″ width=”125″ height=”125″></canvas><br/><label id=”lab7″></label></td>
                </tr>
                <tr>
                    <td><canvas id=”tut8″ width=”125″ height=”125″></canvas><br/><label id=”lab8″></label></td>
                <td><canvas id=”tut9″ width=”125″ height=”125″></canvas><br/><label id=”lab9″></label></td>
                <td><canvas id=”tut10″ width=”125″ height=”125″></canvas><br/><label id=”lab10″></label></td>
                <td><canvas id=”tut11″ width=”125″ height=”125″></canvas><br/><label id=”lab11″></label></td>
                </tr>
            </table>
        </div>

 

<script type=”text/javascript”>
    //美人图的 Base64 编码
    IMG_SRC=’data:image/gif;base64,/9j/4QDfRXhpZgAASUkqAAgAAAAFABIBAwA……’;//省略四十字节

//引入图片

    //==========================================
    //基准点变形类
    //==========================================
    function Transform(){
        //获取画布对象
        this.ctx = document.getElementById(“canvas1”).getContext(“2d”);
        //创造图像对象
        this.img=new Image();
        //指定图像源
        this.img.src=IMG_SRC;
        this.interval = null;
        //鼠标按钮状态
        this.pressed=false;
        this.init();
    }
    
    //开端化图形
    Transform.prototype.init=function(){
        //鼠标按钮状态
        this.pressed=false;
        //截止计时器
        if(this.interval) clearInterval(this.interval);
        //变化值
        this.delta = 0.06;
        //清空
        this.ctx.clearRect(0,0,250,300);
        //重绘
        this.paint();
    }
    
    //绘制图像
    Transform.prototype.paint=function(){
        var that=this;
        var img=this.img
        if(img.complete)
            that.ctx.drawImage(img,0,0);
        else 
            var interval = setInterval(function(){
                if(img.complete){
                    that.ctx.drawImage(img,0,0);
                    clearInterval(interval);
                }
            },300);
    }
    
    //鼠标按钮按下后,早先变形
    Transform.prototype.transform = function(){
        //获取基准点
        this.dx=event.offsetX;
        this.dy=event.offsetY;
        //获取基准点
        this.startx=event.offsetX;
        this.starty=event.offsetY;
        //初叶缩放比例
        this.sc=1;
        //初旋转角度
        this.angle=0;
        
        var that=this;
        if(document.getElementById(“r1”).checked)
            //鼠标按钮状态
            this.pressed=true;
        else if(document.getElementById(“r2”).checked)
            this.interval = setInterval(function(){that.scale()},50);
        else if((document.getElementById(“r3”).checked))
            this.interval = setInterval(function(){that.rotate()},50);
        else 
            this.interval = setInterval(function(){that.scaleAndRotate()},50);
    }
    
    //移动
    Transform.prototype.translate = function(){
        this.ddx=event.offsetX-this.startx;
        this.ddy=event.offsetY-this.starty;
        if(this.pressed){
            //清空
            this.ctx.clearRect(0,0,250,300);
            //保存状态
            this.ctx.save();
            //平移
            this.ctx.translate(this.ddx,this.ddy);
            //重绘
            this.paint();
            //绘制基准点
            this.ctx.fillStyle=”red”;
            this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
            //复苏状态
            this.ctx.restore();
        }
    }

var img = new Image();

    //缩放变形
    Transform.prototype.scale = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        this.sc=this.sc – this.delta;
        if(this.sc<0.2 || this.sc>2) 
            this.delta = -this.delta;
        //保存状态
        this.ctx.save();
        //以 (dx,dy) 为基准点举行 (sx,sy)比例缩放:transform(sx, 0, 0, sy, dx(1-sx), dy(1-sy))
        this.ctx.transform(this.sc, 0, 0, this.sc, this.dx*(1-this.sc), this.dy*(1-this.sc))
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle=”red”;
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //復苏状态
        this.ctx.restore();
    }
    
    //旋转变形
    Transform.prototype.rotate = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        var PI = Math.PI;
        this.angle=this.angle + PI/60;
        //保存状态
        this.ctx.save();
        //以 (dx,dy) 为基准点旋转角度 A:transform(cosA, sinA, -sinA, cosA, dx(1-cosA) + dysinA, dy(1-cosA) – dxsinA)
        this.ctx.transform(Math.cos(this.angle), Math.sin(this.angle), 
                -Math.sin(this.angle), Math.cos(this.angle), 
                this.dx*(1-Math.cos(this.angle)) + this.dy*Math.sin(this.angle), 
                this.dy*(1-Math.cos(this.angle)) – this.dx*Math.sin(this.angle))
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle=”red”;
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //苏醒状态
        this.ctx.restore();
    }
    
    //即缩放又转动变形,没有采用变形矩阵
    Transform.prototype.scaleAndRotate = function(){
        //清空
        this.ctx.clearRect(0,0,250,300);
        //改变缩放比例
        this.sc=this.sc – this.delta;
        if(this.sc<0.2 || this.sc>2) 
            this.delta = -this.delta;
        var PI = Math.PI;
        this.angle=this.angle + PI/60;
        //保存状态
        this.ctx.save();
        //先移动原点到宗旨
        this.ctx.translate(this.dx,this.dy);
        this.ctx.scale(this.sc,this.sc);
        this.ctx.rotate(this.angle);
        this.ctx.translate(-this.dx,-this.dy);
        //用新的变形矩阵重绘
        this.paint();
        //绘制基准点
        this.ctx.fillStyle=”red”;
        this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
        //复苏状态
        this.ctx.restore();
    }
    
    var trans = new Transform();
    
    //==========================================
    function Clip(){
        var canvas = document.getElementById(“canvas3”);
        this.ctx = canvas.getContext(“2d”);
        this.img=new Image();
        this.img.src=IMG_SRC;
        //移动方向
        this.delta=[3,3];
        //起始点
        this.pos_x = 225;
        this.pos_y = 120;
        //半径
        this.radius = 40;
        //画布的长和宽
        this.w = parseInt(canvas.getAttribute(“width”));
        this.h = parseInt(canvas.getAttribute(“height”));
    }
    
    Clip.prototype.draw1=function(){
        //碰撞检测
        if (this.pos_x < this.radius) {
            this.delta[0] = Math.random() % 4 + 5;
        } else if (this.pos_x > this.w – this.radius) {
            this.delta[0] = -(Math.random() % 4 + 5);
        }
        if (this.pos_y < this.radius) {
            this.delta[1] = Math.random() % 4 + 5;
        } else if (this.pos_y > this.h – this.radius) {
            this.delta[1] = -(Math.random() % 4 + 5);
        }
        this.pos_x += this.delta[0];
        this.pos_y += this.delta[1];

img.src = “.jpg”;

        this.ctx.clearRect(0, 0, this.w, this.h);
        //保存状态
        this.ctx.save()
        //移动变形
        this.ctx.translate(this.pos_x,this.pos_y);
        //设置裁剪区域
        this.ctx.beginPath();
        this.ctx.arc(0 ,0,this.radius,0,Math.PI*2,true);
        this.ctx.clip();         
        // 将图片画到画布上
        this.ctx.drawImage(this.img, -this.pos_x, -this.pos_y,this.w, this.h);
        //復苏状态
        this.ctx.restore();
    }
    
    Clip.prototype.draw2=function(){
        //碰撞检测
        if (this.pos_x < this.radius) {
           &nbs

$(img).load(function(){


   ct.drawImage(参数);     

})

 

//图片调整

ct.drawImage(image,x,y,w,h)

//图片裁剪与调整,其中dx/dy/dw/dy为裁剪的参数

ct.drawImage(image,dx,dy,dw,dh,x,y,w,h) 

复制代码

  高级处理(关于图像像素的绘图和处理,仅供明白):

 

 

//imgData对象

var imgData = ct.getImageData(x,y,w,h)  //获取

 

//imgData对象的性质

imgData.width/height    //宽高

imgData.data            //像素集合数组,表示rgba

 

//创制图像

var imgData = ct.createImageData(w,h)   

ct.putImageData(imgData,x,y)

 

 

 

  以上都是相比较基本的知识点统计,没写的太细,只求清晰易查及备忘,倘诺对哪些点不是很清楚,完全能够复制关键字google。

 

  至此,基础知识已经统计完了,可是上述只是是基本的静态画布制作而已,即使您领会灵活利用javascript,结合canvas就能够创建出很美观的卡通片或嬉戏。这么些应用已经重重了,感兴趣可以自行检索有关音讯,可是首先你得学会js.

 

首先,定义2D渲染变量ct(那里用了Jquery库): var ct =
$(#canvasId).get(0).getContext(2d); 以下是绘制各类基本图形的不二法门:
复制代码…

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website