【VUE3.0】如何得到一张像素风格的图片?

目录

  • 引言
  • 网络途径获取
  • 代码转换已有的图片
    • 0. 先看效果
    • 1. 上传图片,这个没什么好说的,前端上传图片基本操作。
    • 2. 通过滑动条提供一个1-10的数字,用于放缩图片画质。
    • 3. 函数拿到图片资源后先对图片进行缩小100倍尺寸处理,此时画质已经崩的的很离谱,不过没关系要的就是这个效果。
    • 4. 再将得到的缩小的图像投射到canvas上放大100倍,注意此时要将抗锯齿关掉,因为我们需要每个像素不平滑。
    • 5. 将结果转换为下载链接赋予一个按钮提供下载图片。
    • 6. 完整代码(基于vue3.0)
  • 总结

引言

像素风图片是一种以像素为基本单位的图像风格。在数字图像中,每一个像素实际上就是一个小方块,它有自己的颜色。在早期的计算机图形学中,由于硬件限制,图像分辨率较低,因此图像由较大且明显的像素组成。随着时间的发展和技术的进步,虽然我们可以创建更高分辨率的图像,但是像素艺术(Pixel Art)作为一种复古的艺术形式依然受到许多人的喜爱。

基于我写的一个像素风组件库教程,引出一个问题:我该如何得到一张像素风的图片?
像素风组件库教程

网络途径获取

获得一种资源的最直接的方式就是白嫖 从网络中查找免费资源。我整理了几个比较喜欢的像素风的资源:

  1. DOTOWN:这是一个来自于前田设计事务所的专注于像素风图片设计的网站,可以用作商业用途(日文猜的=。=),网站素材做了分类,每个种类的数量和质量都还不错。
    网站地址:DOTOWN
    DOTOWN
    网页

  2. KENNEY:这是一个游戏素材网站,我猜测为游戏设计的素材会更强调加载性能,所以不用担心素材的大小问题,应该是已经优化过的状态。素材包含:2d、3d、Audio、Textures等,根据需求选取。下载时会问你要不要捐助,点下边的小字Continue without donating...下载即可。
    网站地址:KENNEY
    在这里插入图片描述

  3. iconfont:阿里巴巴矢量图标库,这个没什么好介绍的,做前端的应该都懂,全局搜pixel像素即可获取到跟像素相关icon。

代码转换已有的图片

这部分代码可以由纯前端来完成,处理逻辑如下:

0. 先看效果

像素化

1. 上传图片,这个没什么好说的,前端上传图片基本操作。

// html部分
<inputclass="fileInput"type="file"accept="image/*"@change="handleFile"
/>
// js部分
let currentImage = ref("");
function handleFile(e) {let file = e.target.files[0];if (!file.type.match("image.*")) {return;}let reader = new FileReader();reader.readAsDataURL(file);reader.onload = function (data) {currentImage.value = data.target.result;render();};
}

2. 通过滑动条提供一个1-10的数字,用于放缩图片画质。

// html部分
<inputclass="slider"type="range"min="1"max="10"v-model="scale"@change="changeScale"
/>
// js部分
let scale = ref(1);
function changeScale() {render();
}

3. 函数拿到图片资源后先对图片进行缩小100倍尺寸处理,此时画质已经崩的的很离谱,不过没关系要的就是这个效果。

function render() {// 判断图片是否存在if (!currentImage.value) {alert("请先上传图片");return;}// 创建临时canvas用于处理图片const canvasTemp = document.createElement("canvas");const context = canvasTemp.getContext("2d");const image = new Image();image.src = currentImage.value;image.onload = function () {// 缩小画面尺寸并绘制在临时canvas上canvasTemp.width = (image.width * scale.value) / 100;canvasTemp.height = (image.height * scale.value) / 100;context.drawImage(image, 0, 0, canvasTemp.width, canvasTemp.height);};
}

4. 再将得到的缩小的图像投射到canvas上放大100倍,注意此时要将抗锯齿关掉,因为我们需要每个像素不平滑。

// html部分<section class="outputImg" ref="outputImg"><h3>preview:</h3><canvas ref="conversionView"></canvas></section>
// js部分// 继续在步骤三的image.onload函数中添加逻辑const dataURL = canvasTemp.toDataURL();const ctx = conversionView.value.getContext("2d");const img = new Image();img.src = dataURL;img.onload = function () {let defaultWidth = outputImg.value.offsetWidth * 0.8;// 这里的0.618只是个自己定的比例没啥特殊含义,主要是为了放置图片宽高比太离谱超出页面宽高。let defaultHeight = defaultWidth * 0.618;// 将图片大小还原回去let imgWidth = (img.width * 100) / scale.value;let imgHeight = (img.height * 100) / scale.value;// 这里处理好宽高比例让投射出来的图像不要超出屏幕范围导致产生滚动就好。if (imgWidth >= imgHeight / 0.618) {imgHeight = (defaultWidth / imgWidth) * imgHeight;imgWidth = defaultWidth;} else {imgWidth = (defaultHeight / imgHeight) * imgWidth;imgHeight = defaultHeight;}// 确定好画框的宽高conversionView.value.width = imgWidth;conversionView.value.height = imgHeight;// 关闭抗锯齿ctx.imageSmoothingEnabled = false;ctx.mozImageSmoothingEnabled = false;ctx.webkitImageSmoothingEnabled = false;ctx.msImageSmoothingEnabled = false;// 绘制图片到预览区域ctx.drawImage(img, 0, 0, imgWidth, imgHeight);

5. 将结果转换为下载链接赋予一个按钮提供下载图片。

// html区域
<a ref="downloadBtn" class="downloadBtn">download</a>
// js部分// 继续在步骤四的img.onload函数中添加逻辑
downloadBtn.value.download = "pixel.png";
downloadBtn.value.href = conversionView.value.toDataURL();

6. 完整代码(基于vue3.0)

此处某些样式可能在这里找不到来源,不过不影响使用。如果对样式部分有需求的朋友,可以参考我的

<template><div class="container"><section class="inputImg"><label class="inputArea"><inputclass="fileInput"type="file"accept="image/*"@change="handleFile"/><span class="placeholder" v-show="!currentImage">点击上传图片或拖拽图片至此处</span><img v-show="currentImage" class="preview" :src="currentImage" /></label><label class="pixelSlider"><span class="sliderTitle">像素大小</span><inputclass="slider"type="range"min="1"max="10"v-model="scale"@change="changeScale"/><span class="sliderText">{{ scale }}</span></label></section><section class="outputImg" ref="outputImg"><h3>preview:</h3><canvas ref="conversionView"></canvas><a ref="downloadBtn" class="downloadBtn">download</a></section></div>
</template>
<script setup>
import { ref } from "@vue/reactivity";
let currentImage = ref("");
let scale = ref(1);
const conversionView = ref(null);
const outputImg = ref(null);
const downloadBtn = ref(null);
function handleFile(e) {let file = e.target.files[0];if (!file.type.match("image.*")) {return;}let reader = new FileReader();reader.readAsDataURL(file);reader.onload = function (data) {currentImage.value = data.target.result;render();};
}
function changeScale() {render();
}
function render() {if (!currentImage.value) {alert("请先上传图片");return;}const canvasTemp = document.createElement("canvas");const context = canvasTemp.getContext("2d");const image = new Image();image.src = currentImage.value;image.onload = function () {canvasTemp.width = (image.width * scale.value) / 100;canvasTemp.height = (image.height * scale.value) / 100;context.drawImage(image, 0, 0, canvasTemp.width, canvasTemp.height);const dataURL = canvasTemp.toDataURL();const ctx = conversionView.value.getContext("2d");const img = new Image();img.src = dataURL;img.onload = function () {let defaultWidth = outputImg.value.offsetWidth * 0.8;let defaultHeight = defaultWidth * 0.618;let imgWidth = (img.width * 100) / scale.value;let imgHeight = (img.height * 100) / scale.value;if (imgWidth >= imgHeight / 0.618) {imgHeight = (defaultWidth / imgWidth) * imgHeight;imgWidth = defaultWidth;} else {imgWidth = (defaultHeight / imgHeight) * imgWidth;imgHeight = defaultHeight;}conversionView.value.width = imgWidth;conversionView.value.height = imgHeight;ctx.imageSmoothingEnabled = false;ctx.mozImageSmoothingEnabled = false;ctx.webkitImageSmoothingEnabled = false;ctx.msImageSmoothingEnabled = false;ctx.drawImage(img, 0, 0, imgWidth, imgHeight);downloadBtn.value.download = "pixel.png";downloadBtn.value.href = conversionView.value.toDataURL();};};
}
</script>
<style scoped>
.container {width: 100%;display: grid;grid-template-columns: 2fr 3fr;
}
.inputArea {margin: 0 auto;margin-top: 70px;display: block;width: 80%;height: 300px;position: relative;border-radius: 5px;border: 1px solid #333;box-shadow: 5px 5px #333;
}
.placeholder {display: block;text-align: center;line-height: 300px;font-family: pixel_en, pixel_ch;font-weight: bold;
}
.pixelSlider {margin: 30px auto;display: grid;grid-template-columns: 2fr 3fr 1fr;align-items: center;justify-items: center;width: 80%;cursor: var(--cursor_normal);
}
.sliderTitle {font-family: pixel_en, pixel_ch;
}
.slider {width: 100%;cursor: var(--cursor_pointer);
}
.sliderText {font-family: pixel_en, pixel_ch;
}
.fileInput {width: 100%;height: 100%;position: absolute;z-index: 10;opacity: 0;cursor: var(--cursor_pointer);
}
.preview {position: absolute;width: 100%;height: 100%;object-fit: contain;top: 0;cursor: var(--cursor_pointer);
}
.outputImg {display: flex;flex-direction: column;align-items: flex-start;
}
h3 {margin-top: 30px;font-family: pixel_en, pixel_ch;font-size: var(--title_large);margin-left: 20%;
}
canvas {border: 1px solid;border-radius: 5px;box-shadow: 5px 5px #333;align-self: center;
}
.downloadBtn {display: block;width: 180px;height: 80px;text-align: center;line-height: 80px;border: 1px solid;border-radius: 50%;box-shadow: 5px 5px #333;transform: skewX(-8deg);margin-top: 40px;font-family: pixel_en, pixel_ch;font-size: var(--text_large);cursor: var(--cursor_pointer);align-self: center;text-decoration: none;color: black;margin-bottom: 40px;
}
</style>

总结

不论使用哪种方式,能够获得自己喜欢的像素风图片,那就太棒了!这种简约而不简单的抽象画风实在太让人上头了。我也会基于这种画风去开发完善一套像素风组件库,等做好了分享出来。像素风组件库教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145959.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

服务器非法关闭后MySQL服务启动失败

在写这篇文章前&#xff0c;我弄好了&#xff0c;写完之后把成功安装的几个MySQL都删除了&#xff0c;只留了最后测试成功的服务“mysql-test” ,然后点击运行&#xff0c;发现又出现上图的错误。心态炸了。 本以为定位到问题了&#xff0c;但是这个错误让我迷茫了。我只能临时…

为什么你的广告规模无法扩大

许多跑facebook的广告主可能都遇到过这样的情况&#xff0c;小额测试广告的时候效果不错&#xff0c;一旦加预算想扩大规模广告往往就会崩掉&#xff0c;始终无法把广告提升一个level,如果你尝试了很多投放策略调整都无法挽救的话&#xff0c;可能问题是出在广告素材上。 对于一…

多重指针变量(n重指针变量)实例分析

0 前言 指针之于C语言&#xff0c;就像子弹于枪械。没了子弹的枪械虽然可以用来肉搏&#xff0c;却失去了迅速解决、优雅解决战斗的能力。但上了膛的枪械也非常危险&#xff0c;时刻要注意是否上了保险&#xff0c;使用C语言的指针也是如此&#xff0c;要万分小心&#xff0c;…

杀死端口占用的进程

1、查看端口的进程&#xff0c;以9023为例 &#xff08;1&#xff09;方法1 netstat -tunpl|grep 9023 &#xff08;2&#xff09;方法2 ss -tulpan |grep 9023 &#xff08;3&#xff09;方法3 netstat -ntlp |grep 9023 &#xff08;4&#xff09;方法4 lsof -i:9023 …

A Simple Encoder-Decoder for Open-Vocabulary Semantic Segmentation

FAM: Feature Aggregation Module&#xff0c;Circle with R represents removing feature maps of non-selected categories 辅助信息 权重有1.3G&#xff0c;不建议复现

变压器空载时是否有必要做无功补偿

在电力系统中&#xff0c;变压器作为关键设备之一&#xff0c;其运行状态对整个系统的功率质量和效率具有重要影响。关于“变压器空载时是否有必要做无功补偿”这一问题&#xff0c;答案取决于具体的应用场景、系统需求以及经济性考虑。以下将从变压器空载特性、无功补偿的原理…

360手机黑科技“位置穿越”功能修复 360位置穿越使用

​ 360手机刷机 360手机黑科技 360手机位置穿越 360手机位置修复 360手机站&#xff1a;360os.top 资源免费下载: os.360os.top 备用资源站&#xff1a;360手机-360手机刷机RootTwrp 360手机位置穿越 360手机位置穿越‌&#xff0c;是一款虚拟定位软件&#xff0c;无需进行r…

毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

块匹配算法简介(上)

图像中的运动估计方法大致分为两类:光流法和块匹配算法(BMA,Block Matching Algorithm)。本文将介绍BMA的相关内容,包括基本原理、相似度计算准则与常见的几种搜索方法,如三步法、四步法、钻石搜索法等。 1. 背景 视频中相邻帧往往存在大量的相似内容,即只有局部的一些…

算法课习题汇总(2)

整数划分问题 将正整数n表示成一系列正整数之和&#xff0c;nn1n2…nk(n1>n2>…>nk,k>1)。正整数n的这种表示称为正整数n的划分。 思路&#xff1a; n表示待划分数&#xff0c;m表示最大减数。 #include<iostream> using namespace std;int q(int n, int…

JIT(即时编译)技术

介绍一下JIT优化技术&#xff1f; 想要把高级语言转变成计算机认识的机器语言有两种方式&#xff0c;分别是编译和解释&#xff0c;虽然Java转成机器语言的过程中有一个步骤是要编译成字节码&#xff0c;但是&#xff0c;这里的字节码并不能在机器上直接执行。 JVM中内置了 解释…

记软件开发者画图(UML),使用WPS应用制图

目录 前言 一、什么是UML 二、使用什么画图工具 三、示例 ​四、IntelliJ IDEA 2021快速生成UML图 前言 做软件开发的从写第一个示例程序到最后写项目程序避不开的需要设计画图&#xff0c;所以今天我们就来梳理一下‌UML&#xff08;统一建模语言&#xff09;图形需要画…

LINUX网络编程:TCP(1)

目录 1.认识Tcp的报头 2.确认应答机制&#xff08;ACK&#xff09; 序号与确认序号 捎带应答 3.超时重传机制 4.Tcp连接管理 三次握手 为什是三次握手 四次挥手 理解TIMEWAIT 1.认识Tcp的报头 源端口和目的端口号没什么说的 32位的序号和确认序号&#xff0c;之后会介…

T9-猫狗识别2(暂时版qaq)

T9周&#xff1a;猫狗识别2 **一、前期工作**1.设置GPU,导入库2.导入数据3.查看数据 **二、数据预处理**1.加载数据2.可视化数据3.配置数据集 **三、构建CNN网络模型****四、编译模型****五、训练模型****六、模型评估****七、预测**八、总结&#xff08;暂时&#xff09; &…

倒排索引(反向索引)

倒排索引&#xff08;Inverted Index&#xff09;是搜索引擎和数据库管理系统中常用的一种数据结构&#xff0c;用于快速检索文档集合中的文档。在全文搜索场景中&#xff0c;倒排索引是一种非常高效的手段&#xff0c;因为它能够快速定位到包含特定关键词的所有文档。 1、基本…

【Python技术】使用akshare、pyecharts绘制K线图

下班回到家&#xff0c;回家途中瞄了下股票&#xff0c;大盘又是3000多只股票待涨&#xff0c; 盘中上证指数一度跌破2700。 估计不少人心里不爽&#xff0c;那就聊聊相关技术学习下。 之前写过【python技术】使用akshare、pandas、mplfinance绘制红绿色K线图简单示例 &#x…

Android Retrofit源码分析(一):Retrofit是什么?和OkHttp的区别是什么?为什么需要他?

目录 一、Retrofit是什么? Retrofit是一个基于OKHttp的RESTful网络请求框架,由Square公司开源,专为Android和Java提供类型安全的HTTP客户端。它可以理解为OKHttp的加强版,底层封装了OKHttp,主要负责网络请求接口的封装,使得网络请求工作更加简洁高效。 简单来说,Retro…

GNN-RAG:用于大模型推理的图神经检索

GNN-RAG&#xff1a;用于大模型推理的图神经检索 秒懂大纲提出背景解法拆解全流程优化创意总结 论文&#xff1a;GNN-RAG: Graph Neural Retrieval for Large Language Model Reasoning 代码&#xff1a;https://github.com/cmavro/GNN-RAG 秒懂大纲 ├── GNN-RAG【主题】…

医疗领域患者监控中的手势识别:一种深度卷积神经网络方法

这篇论文的标题是《Hand Gesture Recognition for Patient Monitoring in the Medical Field: A Deep Convolution Neural Networks Approach》&#xff0c;作者们来自印度的Chaitanya Bharathi Institute of Technology电子与通信工程系。论文主要探讨了在医疗领域&#xff0c…

AI大模型之旅--milvus向量库安装

milvus-向量索引库 milvus的官方文档中看到最新版本的部署方式 :https://milvus.io/docs/install_standalone-docker.md 部署 curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh 如果下载不下来&a…