看看图片马赛克风格化效果用CSS怎么实现_第1页
看看图片马赛克风格化效果用CSS怎么实现_第2页
看看图片马赛克风格化效果用CSS怎么实现_第3页
看看图片马赛克风格化效果用CSS怎么实现_第4页
看看图片马赛克风格化效果用CSS怎么实现_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第看看图片马赛克风格化效果用CSS怎么实现?一、image-rendering介绍

CSS中有一个有趣的特性叫image-rendering,它可以通过算法来更好地显示被缩放的图片。

假设我们有一张尺寸较小的二维码截图(下方左,仅为示意图不可扫),将其放大10倍后图像会被虚化(下方右):

这时给放大的图片加上image-rendering:pixelated的特性,CSS会通过算法将其像素化展示,使其图像轮廓具有更锐利的边缘:

该特性非常适合应用在色彩单一、轮廓分明、需要被放大的图片上,可以营造出一种伪矢量的既视感(减少放大后的失真)。

对于色彩丰富、细节较多的照片,image-rendering:pixelated使用后会营造出一种马赛克的外观:

这离本文标题所希望实现的马赛克效果还有段距离目前图片需要被放大后才能显示出效果,而我们希望能在保有原图尺寸的基础上,给图片覆盖等尺寸马赛克。

然而image-rendering特性对尺寸未发生缩放的元素是不会生效的:

MDN-Thispropertyhasnoeffectonnon-scaledimages.

二、踩坑等尺寸马赛克的实现

等尺寸马赛克的原理相当于先把一张照片模糊化,然后再经过锐化算法处理得到各种小方格。

image-rendering:pixelated帮我们实现了锐化的步骤,我们得想想怎么实现模糊。

首先使用滤镜的模糊方案是行不通的,因为image-rendering和图像缩放系数强相关,所以应当思考可以怎样利用图片的缩放能力。

这里得说一句,WEB上的图片像极了Photoshop里的智能对象你可以任意修改它的尺寸(例如放大很多倍让其变模糊),但最后再把图片改回原本的大小时,图片会变回原来的样子(没有任何失真)。

如何保留图片放大后的模糊信息,是优先需要解决的问题。

聪明的小伙伴已经想到了可以尝试使用canvas来处理,毕竟canvas可以轻松获取、绘制图像,且绘制出来的图像信息是纯数据的,而非图形对象(Image),故经其放大绘制的图片数据再进行缩小绘制(到原尺寸)会失真(这正好是我们所希望发生的)。

但这里也存在一些坑:

外部图像通过image-rendering:pixelated算法处理后显示的信息,canvas是无法拿到的,因为那是显示层的东西。canvas拿到的依旧是未经锐化的、模糊的原生图像内容;

canvas本身如果没有缩放的话,给canvas添加image-rendering:pixelated没有任何意义。

这意味着你无法把图片在canvas外面放大锐化,然后再写入canvas去缩小绘制(并不断迭代处理)来得到锐化后的原尺寸图片。

三、有趣的canvas拉伸

在解决上述问题时,我们先来看看canvas一个有趣的特性。

如果我们在canvas标签里定义了宽高:

canvaswidth=100height=50/canvas

同时又给canvas在样式中定义了另一个宽高:

canvas{

width:200px;

height:200px;

}

那么canvas会以哪个尺寸来显示呢?

答案是以CSS的尺寸来显示,但画布的内容尺寸会以画布标签内定义的宽高为准。这意味着虽然我们看到的是200px*200px的画布,但它的内容实际被拉伸了(宽被拉伸了2倍,高被拉伸了4倍)。

注:左边为画布,右边为原图

这也是canvas作为可替换元素的一个特性CSS无法修改其内容。试想一下,如果CSS可以动态地修改canvas内容的尺寸,意味着canvas的内容会被裁剪掉一部分,或者多出来一部分空白区域,这显然是不可取的。所以canvas在保留内容完整的前提下,整体伸缩到样式规定尺寸,是合理的浏览器行为。

利用canvas的这个特性,我们可以这样来实现等尺寸马赛克:

创建一个画布,通过样式规定好其宽高,并设置image-rendering:pixelated特性;

计算图片最佳展示尺寸(以类似background-size:contAIn的形式展示);

将画布的宽高(非样式)设置为样式宽高的1/N;

绘制图像,绘制的图像宽高为最佳展示尺寸的1/N。

如此一来,我们实际绘制了一个尺寸仅为最佳尺寸1/N的图像,再通过canvas的N倍放大又变回了视觉上的最佳尺寸。图像因为走的canvas绘制,所以放大回最佳尺寸后会保持模糊,从而满足了image-rendering的匹配需求。

注:这里提到的最佳尺寸,指的是步骤2里确保完整展示图像所对应的最佳尺寸,而非图片原生尺寸。

四、代码实现

我们按照上方步骤来书写对应代码,当然我们希望灵活一些,例如上述的N可以由用户自定义。另外本章的代码可以在Github上获取。

4.1HTML部分

主要为选择图片的input控件、画布、方便画布获取图像的img、供用户自定义缩放倍数的文本框、执行按钮:

inputid=filetype=fileaccept=image/*/

canvasid=canvas/canvas

imgid=img-raw/

labelfor=compress-times压缩倍数:/label

inputid=compress-timestype=numbervalue=12

button马赛克化/button

4.2CSS部分

我们需要通过样式规定好画布的外观尺寸,并配置image-rendering:pixelated特性。另外img标签只是一个传递用户所选图片到画布的中介,可以直接隐藏:

canvas{

display:block;

border:graysolid1px;

width:600px;

height:600px;

image-rendering:pixelated;

img{

display:none;

}

4.3JS部分

letimgBlobUrl;

constfile=document.getElementById(file

constimg=document.getElementById(img-raw

constcompressTimes=document.getElementById(compress-times

constdefaultCompressTimes=compressTimes.value|0;

constcanvas=document.getElementById(canvas

constbutton=document.querySelector(button

constboundingRect=canvas.getBoundingClientRect();

constctx=canvas.getContext(2d

constcanvas_w=boundingRect.width;

constcanvas_h=boundingRect.height;

//以background-size:contain形式设置图片尺寸

functionmatchImgSizeToCanvas(imgElem=img){

letw=imgElem.width;

leth=imgElem.height;

if(wcanvas_w||hcanvas_h){

letradio=Math.max(h/canvas_h,w/canvas_w);

radio=Number(radio.toFixed(2));

imgElem.width=parseInt(w/radio);

imgElem.height=parseInt(h/radio);

//绘制1/N大小的图像,画布宽高属性设为样式宽高的1/N,从而实现画布内容的N倍放大

functionrun(){

letct=parseInt(compressTimes.value)||defaultCompressTimes;

canvas.width=parseInt(canvas_w/ct);

canvas.height=parseInt(canvas_h/ct);

ctx.drawImage(img,0,0,parseInt(img.width/ct),parseInt(img.height/ct));

functioncleanCanvas(){

ctx.clearRect(0,0,canvas_w,canvas_h);

functionreset(){

img.removeAttribute(width

img.removeAttribute(height

cleanCanvas();

matchImgSizeToCanvas(img);

run();

file.addEventListener(change,function(e){

window.URL.revokeObjectURL(imgBlobUrl);

constpicFile=this.files[0];

imgBlobUrl=window.URL.createObjectURL(picFile);

img.onload=functioninit(){

reset();

img.src=imgBlobUrl;

},false);

button.addEventListener(click,reset,false);

执行效果:

选中文件/点击按钮后,能按压缩倍数得到对应的像素风格艺术照。

五、Mosaic插件封装

通过上方示例我们学习了如何利用canvas特性来设计等尺寸的马赛克效果,现在我们尝试把该功能封装为一个简易插件,可以让页面上的图片列表一键Mosaicing。

插件的实现方案也很简单用户点击按钮时,往图片容器上插入一个和容器等尺寸的画布(尺寸通过样式设置),再绘制覆盖画布的图像,并缩小画布的宽高属性来放大画布内容:

5.1插件脚本

/**@filemosaic.js**/

classMosaic{

constructor(url,container,options={}){

if(typeofcontainer===string){

container=document.querySelector(container);

if(!url||!container.style){

console.error(参数不正确

this.url=url;

this.options=options;

this.container=container;

this.init();

init(){

constimg=newImage();

constcanvas=document.createElement(canvas

canvas.style.position=absolute

canvas.style.zIndex=999;

canvas.style.imageRendering=pixelated

this.img=img;

this.canvas=canvas;

this.ctx=canvas.getContext(2d

constcontainerBoundingRect=this.container.getBoundingClientRect();

constcontainer_w=containerBoundingRect.width;

constcontainer_h=containerBoundingRect.height;

//通过样式初始化画布尺寸为容器尺寸

canvas.style.width=container_w+px

canvas.style.height=container_h+px

img.onload=()={

this.run(container_w,container_h);

img.src=this.url;

run(w,h){

//缩小倍数,可以由参数传入,默认为12

constcompressTimes=parseInt(pressTimes)||12;

letcompress_w=parseInt(w/compressTimes);

letcompress_h=parseInt(h/compressTimes);

//修改画布尺寸属性为1/缩小倍数

this.canvas.width=compress_w;

this.canvas.height=compress_h;

//绘制图片覆盖缩小后的画布

this.ctx.drawImage(this.img,0,0,compress_w,compress_h);

this.container.prepend(this.c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论