上篇博客提到过,box-shadow属性的本质是对形状的复制,那么如果我设置一个1*1px的i标签,利用box-shadow可以叠加的特性,给每一个1*1px的阴影赋上颜色,那么最后不就是一幅图片了么。

html代码很简单:

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>canvas</title>
<style>
#shadow {
position: relative;
}
#shadow i {
display: block;
width: 1px;
height: 1px;
}
</style>
<script src="shadowShow.class.js" defer="defer"></script>
</head>
<body>
<input id="file" class="file-upload" type="file" accept="image/png, image/gif" />
<canvas id="canvas">
您的浏览器不支持canvas标签
</canvas>
<div id="shadow"><i></i></div>
<script>
var init = {
fileObj: 'file', //input控件的id
canvas: 'canvas', //canvas的标签的id
shadowBox: 'shadow', //用于阴影显示的标签的id
};
</script> </body>
</html>

  做了一个简单的图片上传控件,页面的js里读取了一些简单的控件信息。

  最初在直接用控件获取图片路径时,碰到了路径显示为fakepath的问题(直接给控件赋路径src='#'有效果),所以没法读取图片的路径。

  查询后使用了FileReader()解决了这个问题,FileReader()读取图片信息的使用很简单,请自行百度。

  重点还是用canvas的getImageData()获取了图片每个像素点的rgba信息。图片上的每个点都有rgb三原色加上一个透明度的信息,这些信息都放在getImageData()的data数组里,换句话说,data数组里每4个值组合起来就是一个像素点的颜色信息。而每个像素点的位置可以根据这是第几个像素点(每个像素点都是1*1px),加上原图片的长宽信息来计算得出,宽度上data数组里每4个值宽度加1px,如果像素点的宽度超过了图片的宽度,那么就说明该像素点是下一行的,即将高度加1px,宽度重置。

  又像素点的信息都是保存在一个名叫data的一维数据里,且每4条数据是一个像素点的颜色信息,所以可以每4条数据一读,比如 if (i % 4 === 0),那么像素点的red通道即是image.data[index],green通道是imageData.data[index + 1],blue通道是imageData.data[index + 2],alpha通道是imageData.data[index + 3],最后把这些颜色信息处理下通通push到一个数组里,赋给i标签的box-shadow属性就大功告成。

  下面给出完整的js代码:

(function() {
/**
最初我的init方法是这样的,但是在对象的属性里添加监听事件貌似无效,所以挪到了对象外
init: function() {
console.log(this.fileObj);
this.fileObj.addEventListener('change', function() {
shadowShow.upPic();
});
},
*/
document.getElementById(init.fileObj).addEventListener('change', function() {
shadowShow.init();
}); var shadowShow = {
fileObj: document.getElementById(init.fileObj),
canvas: document.getElementById(init.canvas),
ctx: this.canvas.getContext('2d'),
shadowBox: document.getElementById(init.shadowBox), init: function() {
shadowShow.upPic();
}, /**
*用于获取上传的图片的信息并在canvas1中显示
*@method upPic
*/
upPic: function() {
image = new Image();
this.setImageUrl(image, this.fileObj);
image.onload = function() {
// cavas的宽高用setAttribute设置,用canvas.width也可以,注意值不能加上单位
width = this.width;
height = this.height;
shadowShow.canvas.setAttribute('width', width);
shadowShow.canvas.setAttribute('height', height);
shadowShow.ctx.drawImage(this, 0, 0, width, height);
shadowShow.toShadowShow(this, shadowShow.ctx);
}
}, /**
*用于设置创建的iamge对象的url
*@method setImageUrl
*@param {obj} image 创建的iamge对象
*@param {obj} fileQuery 上传图片的file控件对象
*/
setImageUrl: function(image, fileQuery) {
var file = fileQuery.files[0];
var reader = new FileReader();
reader.onload = function(e) {
image.src = e.target.result;
}
reader.readAsDataURL(file);
}, /**
*用于将上传的图片的用box-shadow表现出来
*@method toBoxShadow
*@param {obj} image 创建的iamge对象
*@param {obj} context 创建的绘图的上下文对象
*/
toShadowShow: function(image, context) {
width = image.width;
height = image.height;
this.shadowBox.style.width = width + 'px';
this.shadowBox.style.height = height + 'px';
var imageData = context.getImageData(0, 0, width, height);
var arrShadow = new Array();
var index = 0;
var interval = setInterval(function() {
if (index < imageData.data.length) {
// 每4个参数处理一次
if (index % 4 === 0) {
var x = index / 4 % width + 1, //x坐标,以index=4为例,index/4=1,表示x是第1个像素点,1%width是为了获得第n行的像素点的x坐标,又index是从0开始的(index=0是真正的第一个像素点),所以x的坐标需要加上1
y = Math.floor(index / 4 / width) + 1, //y坐标,
alpha = Math.round(imageData.data[index + 3] / 255 * 100) / 100; //透明度,imageData.data[index+3]/255需要乘以100是因为(imageData.data[index+3]/255)肯定是小于1的,为了避免round()取整值为1,故需要乘以100
if (alpha == 255) { //像素点没有透明度
//将rgb转为16进制
var redToHex = imageData.data[index].toString(16),
greenToHex = imageData.data[index + 1].toString(16),
blueToHex = imageData.data[index + 2].toString(16);
redToHex = redToHex.length == 1 ? ('0' + redToHex) : redToHex;
greenToHex = greenToHex.length == 1 ? ('0' + greenToHex) : greenToHex;
blueToHex = blueToHex.length == 1 ? ('0' + blueToHex) : blueToHex;
var hex = redToHex + greenToHex + blueToHex;
//对形如#FFF的十六进制颜色作处理
if (redToHex.slice(0,1) == redToHex.slice(-1) && greenToHex.slice(0,1) == greenToHex(-1) && blueToHex.slice(0,1) == blueToHex.slice(-1)) {
hex = redToHex.slice(-1) + greenToHex.slice(-1) + blueToHex.slice(-1);
}
arrShadow.push(x + 'px ' + y + 'px #' + hex);
} else if (alpha > 0) {
a = [imageData.data[index], imageData.data[index + 1], imageData.data[index + 2], alpha].join();
arrShadow.push(x + 'px ' + y + 'px rgba(' + a + ')');
}
}
shadowShow.shadowBox.querySelector('i').style.boxShadow = arrShadow.join();
} else {
clearInterval(interval); //清除setInterval
}
index++;
});
}
};
})();

  这段代码我封装了一下,注释写的比较详细了,同时,加了一个定时器,这样就有了一个像素一个像素显示的效果,就是如果图片的width和height值比较大的话,完整的图片显示出来会比较慢。setInterval()的默认值查了下,如果设置的时间间隔小于10,则以10来算,即10ms,但是还是感觉图片显示的挺慢的,当然了,这要看图片的像素点的数量了。

  补充:

  当然了,如果仅需遍历每个像素点其实也不用像上面那么麻烦(上面主要是为了获得每个点的坐标(x, y)),如下就可以了:

  

//简单的灰阶过滤器
for (i = 0; i < imageData.data.length; i += 4) {
var r = data[i],
g = data[i + 1],
b = data[i + 2],
a = data[i + 3]; var average = Math.floor((r + g + b) / 3);
data[i] = data[i + 1] = data[i + 2] = average;
}

  

  最后更新于2016年11月22日

利用box-shadow绘图的更多相关文章

  1. 如何设置box shadow的透明度

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-04-24) 今天发现使用box-shadow属性,可以很好的给div添加阴影效果,但是添加的效果如果是: -moz-box- ...

  2. css3盒模型学习--利用box自适应布局

    box-flex是css3新添加的盒子模型属性,它的出现可以解决我们通过N多结构.css实现的布局方式.经典   的一个布局应用就是布局的垂直等高.水平均分.按比例划分. 目前box-flex属性还没 ...

  3. 利用numpy+matplotlib绘图的基本操作教程

    简述 Matplotlib是一个基于python的2D画图库,能够用python脚本方便的画出折线图,直方图,功率谱图,散点图等常用图表,而且语法简单.具体介绍见matplot官网. Numpy(Nu ...

  4. 【Matplotlib】利用Python进行绘图

    [Matplotlib] 教程:https://morvanzhou.github.io/tutorials/data-manipulation/plt/ 官方文档:https://matplotli ...

  5. PHP利用GD库绘图和生成验证码图片

    首先得确定php.ini设置有没有打开GD扩展功能,測试例如以下 print_r(gd_info()); 假设有打印出内容例如以下,则说明GD功能有打开: Array ( [GD Version] = ...

  6. Core Graphics框架 利用Quartz 2D绘图

    首先,什么是Core Graphics和Quartz 2D? Core Graphics:是基于Quartz 2D绘图引擎的一个C语言的API绘图框架.它也是iOS开发中最基本的框架(Framewor ...

  7. 科赫雪花利用python海龟绘图代码

    #KochDraw.py import turtle //海龟绘图 def koch(size, n): if n == 0: turtle.fd(size) else: for angle in [ ...

  8. 利用Form()使绘图可以不消失

    1: public Form1() 2: { 3: InitializeComponent(); 4: this.Show(); 5: Graphics grp = this.CreateGraphi ...

  9. 分享div、text、Box Shadow(阴影)演示及代码的页面

    附图: 直接上链接:www.css88.com/tool/css3Preview/Box-Shadow.html

  10. 利用box-shadow制作loading图

    我们见过很多利用css3做的loading图,像下面这种应该是很常见的.通常制作这种loading,我们会一个标签对应一个圆,八个圆就要八个标签.但是这种做法很浪费资源.我们可以只用一个标签,然后利用 ...

随机推荐

  1. tyvj1102 单词的划分

    描述 有一个很长的由小写字母组成字符串.为了便于对这个字符串进行分析,需要将它划分成若干个部分,每个部分称为一个单词.出于减少分析量的目的,我们希望划分出的单词数越少越好.你就是来完成这一划分工作的. ...

  2. Coursera系列-R Programming第三周-词法作用域

    完成R Programming第三周 这周作业有点绕,更多地是通过一个缓存逆矩阵的案例,向我们示范[词法作用域 Lexical Scopping]的功效.但是作业里给出的函数有点绕口,花费了我们蛮多心 ...

  3. PHP数组函数: array_map()

    定义和用法 array_map() 函数返回用户自定义函数作用后的数组.回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致. 语法 array_map(function,a ...

  4. 【JSOI2007】麻将 bzoj 1028

    Description 麻 将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到 九的九种牌),每种牌各四张 ...

  5. 基于winner 滤波平稳降噪效果

    https://en.wikipedia.org/wiki/Wiener_filter Wiener filter solutions The Wiener filter problem has so ...

  6. NVelocity介绍,NVelocity中文手册文档及实例下载

    NVelocity是什么velocity英音:[vi'lɔsiti]美音:[və'lɑsətɪ]近在做一个项目,客户要求有网站模板功能,能够自主编辑网站的风格,因为这个系统是为政府部门做子站系统,举个 ...

  7. ecshop常用二次开发修改

    修改ecshop支付宝的支付按钮  http://www.68ecshop.com/article-1081.html 去掉ecshop收货人信息页面的电子邮件必填和电话.手机选填一个  http:/ ...

  8. 基于 React.js + Redux + Bootstrap 的 Ruby China 示例 (转)

    一直学 REACT + METEOR 但路由部分有点问题,参考一下:基于 React.js + Redux + Bootstrap 的 Ruby China 示例 http://react-china ...

  9. selenium+testng+ant+jenkins 手记

    会不会搭建测试平台是一般测试工程师和高级测试工程师分水岭 ----tobecrazy 我们项目有现成的测试平台,使用的是selenium grid+testng+ant+jenkins+VM 但是我平 ...

  10. spring集成常用技术的配置

    使用spring集成其他技术,最基本的配置都是模板化的,比如配置视图模板引擎.数据库连接池.orm框架.缓存服务.邮件服务.rpc调用等,以spring的xml配置为例,我将这些配置过程整理出来,并不 ...