uni-app开发小程序,根据图片提取主题色值

需求,在页面根据传入的图片提取图片主色值并用来设置区块背景色

<template><view class="icon-container"><view class="sport-icon" :style="{ backgroundColor: mainColor }"><image :src="'/static/images/sport/'+item.image" @load="handleImageLoad" class="li-img" mode="widthFix" /></view><view class="sport-right"><view><text class="sport-name">{{ item.name }}</text></view><view class="sport-text">{{ item.calorie }}千卡/{{ item.unit }}分钟</view></view><view class="align-self-end"><product-change :selected.sync="item.selected" @onChange="onChange" /></view><!-- Canvas 2D画布(隐藏) --><canvas type="2d" id="colorCanvas"style="position: absolute; left: -1000px; top: -1000px; width: 100px; height: 100px;"></canvas></view>
</template><script>import productChange from './product-change.vue'export default {name: 'productItem',components: {productChange},props: {name: {type: String,default: ''},item: {type: Object,default: () => {}}},data() {return {imgUrl: '@/static/images/sport/icon-sport-default.png', // 示例图片mainColor: '#ffffff', // 初始背景色textColor: '#000000', // 文字颜色,根据背景色自动调整canvas: null, // Canvas实例ctx: null // Canvas 2D上下文};},mounted() {console.log(this.item)// 初始化Canvas 2D上下文(在组件挂载后获取)this.initCanvas();},methods: {onChange() {this.$emit('onChange', {name: this.name,item: this.item})},// 初始化Canvas 2D上下文initCanvas() {// 通过ID获取Canvas实例(兼容uni-app的获取方式)const query = uni.createSelectorQuery().in(this);query.select('#colorCanvas').fields({node: true,size: true}).exec(res => {if (!res[0]) {console.error('未找到Canvas元素');return;}this.canvas = res[0].node;this.ctx = this.canvas.getContext('2d'); // 获取2D上下文// 设置Canvas尺寸(与样式尺寸一致)this.canvas.width = 100;this.canvas.height = 100;});},// 图片加载完成后触发handleImageLoad(e) {if (!this.canvas || !this.ctx) {console.error('Canvas未初始化完成');return;}const imgSrc = "/static/images/sport/" + this.item.image;// 获取图片信息(转为本地路径)uni.getImageInfo({src: imgSrc,success: (res) => this.drawToCanvas(res.path), // 绘制本地图片fail: (err) => {console.error('获取图片信息失败:', err);this.useDefaultColor();}});},// 绘制图片到Canvas(Canvas 2D方式)drawToCanvas(imagePath) {// 创建Image对象(Canvas 2D需要通过Image加载图片)const img = this.canvas.createImage();if (!imagePath.startsWith('/')) {imagePath = '/' + imagePath;}img.src = imagePath;// 图片加载完成后绘制到Canvasimg.onload = () => {// 清空画布(避免残留旧内容)this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);// 绘制图片(缩放到100x100,覆盖整个画布)this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);// 延迟100ms后获取数据(确保绘制完成)setTimeout(() => this.extractMainColor(), 100);};// 图片加载失败处理img.onerror = (err) => {console.error('图片绘制失败:', err);this.useDefaultColor();};},// 提取主色extractMainColor() {try {// 读取Canvas像素数据(Canvas 2D的getImageData)const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);this.processImageData(imageData.data); // 处理像素数据} catch (err) {console.error('色值提取失败:{}', err);}},// 处理像素数据,计算主色processImageData(pixelData) {const colorFreq = {}; // 颜色出现频率let maxFreq = 0;let mainR = 255,mainG = 255,mainB = 255;// 遍历像素(每4个值为一组:R, G, B, A)for (let i = 0; i < pixelData.length; i += 4) {const r = pixelData[i];const g = pixelData[i + 1];const b = pixelData[i + 2];const a = pixelData[i + 3];// 忽略透明像素(透明度>50%的不统计)if (a < 128) continue;// 颜色量化(减少颜色种类,如每20阶合并一次)const key = `${Math.floor(r / 20)}-${Math.floor(g / 20)}-${Math.floor(b / 20)}`;colorFreq[key] = (colorFreq[key] || 0) + 1;// 记录出现频率最高的颜色if (colorFreq[key] > maxFreq) {maxFreq = colorFreq[key];mainR = r;mainG = g;mainB = b;}}// 设置主色和文字对比色this.mainColor = `rgb(${mainR}, ${mainG}, ${mainB},0.2)`;// 计算亮度(决定文字颜色)const luminance = (mainR * 299 + mainG * 587 + mainB * 114) / 1000;this.textColor = luminance > 130 ? '#000000' : '#ffffff';},// 使用默认颜色(失败时)useDefaultColor() {this.mainColor = '#f0f0f0';this.textColor = '#000000';}}}
</script><style lang="scss" scoped>.icon-container {border-bottom: 1px solid #F2F6FC;padding: 20rpx 40rpx;display: flex;}.li-img {// width: 55rpx;// height: 55rpx;}.sport-icon {width: 85rpx;height: 85rpx;padding: 15rpx;border-radius: 20rpx;}.sport-right {flex: 1;margin-left: 25rpx;width: 100%;}.sport-name {font-size: 32rpx;}.sport-text {color: #999;font-size: 26rpx;}.align-self-end {align-self: flex-end}.flex-end {display: flex;flex-direction: column;justify-content: flex-end;}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32-Cam三脚架机器人:DIY你的智能移动监控平台

项目概述 在物联网与机器人技术融合发展的今天&#xff0c;基于ESP32的创意项目层出不穷。今天为大家介绍一款极具创新性的ESP32-Cam三脚架机器人&#xff08;Dodge&#xff09;&#xff0c;它将传统三脚架结构与智能监控功能完美结合&#xff0c;通过巧妙的机械设计和开源硬件…

Kotlin集合过滤

过滤操作 在处理集合时&#xff0c;根据特定条件过滤集合或检查集合中是否包含符合特定条件的元素是软件开发中的常见任务。为了解决这个问题&#xff0c;我们可以使用 Kotlin 中实现的函数式 API。 在本主题中&#xff0c;我们将介绍如何使用谓词过滤集合&#xff0c;并获得满…

14.8 LLaMA2-7B×Dolly-15K实战:从准确率63%到89%,如何用优质数据让大模型性能飙升42%?

LLaMA2-7BDolly-15K实战:从准确率63%到89%,如何用优质数据让大模型性能飙升42%? 在大模型微调中,“数据质量”往往比“数据数量”更能决定最终效果。Databricks发布的Dolly-15K数据集以“全人工标注+多维度校验”的特点,成为指令微调的“黄金样本”——用它微调后的LLaMA…

OpenCV中常用特征提取算法(SURF、ORB、SIFT和AKAZE)用法示例(C++和Python)

OpenCV 中提供了多种常用的特征提取算法&#xff0c;广泛应用于图像匹配、拼接、SLAM、物体识别等任务。以下是 OpenCV 中几个主流特征提取算法的 用法总结与代码示例&#xff0c;涵盖 C 和 Python 两个版本。常用特征提取算法列表算法特点是否需额外模块SIFT&#xff08;尺度不…

复杂度+包装类型+泛型

什么是集合框架什么是数据结构什么是算法时间复杂度与空间复杂度的概念时间复杂度的表达方式时间复杂度的大 O 的渐近表示法时间复杂度函数的大小排序包装类和泛型基本数据类型和对应的包装类型包装类型出现的原因什么叫做装箱&#xff08;装包&#xff09;和拆箱&#xff08;拆…

硬件设计学习DAY15——自举电容:MOSFET高端驱动的核心奥秘

每日更新教程&#xff0c;评论区答疑解惑&#xff0c;小白也能变大神&#xff01;" 目录 一.自举电容 1.自举电容的作用 2.自举电路原理 3.工作过程分析 4.实际应用中的问题 5.关键要点 二.自举电容实现MOSFET高端驱动 2.1MOSFET半桥高端驱动的基本原理 2.2自举电…

【SpringAI实战】实现仿DeepSeek页面对话机器人

一、实现效果 二、代码实现 2.1 后端代码 2.2 前端代码 一、实现效果 可以保存聊天记录与会话记录 二、代码实现 2.1 后端代码 pom.xml <!-- 继承Spring Boot父POM&#xff0c;提供默认依赖管理 --><parent><groupId>org.springframework.boot</grou…

RedisJSON 指令精讲JSON.STRLEN 高效统计字符串长度

1 场景与价值 在日志累加、指标采集、消息追踪等场景中&#xff0c;我们常需快速判断某个字符串字段“到底有多长”&#xff0c;以便&#xff1a; 阻止过大日志&#xff1a;若长度超限则截断或归档&#xff1b;动态分桶&#xff1a;按长度选择不同存储策略&#xff1b;性能监控…

大数据量查询计算引发数据库CPU告警问题复盘

大数据量查询计算引发数据库CPU告警问题复盘一、背景二、根因分析三、解决方案方案1&#xff1a;多线程缓存方案2&#xff1a;利用中间表缓存四、总结一、背景 2025年7月份某天&#xff0c;CDP系统每天不定时推送我们的Portal服务&#xff0c;生产环境运营看板会展示统计数据&…

2025最新版虚幻引擎5(UE5)C++入门教程:前言——你的随身教程和学习笔记

大家好&#xff0c;我是开发游戏的老王&#xff0c;一名高校教师&#xff0c;我主讲游戏开发已有十余年时间&#xff0c;通过我的博客大家应该可以了解我所涉猎的游戏技术范畴非常广泛&#xff0c;除了Unreal,Unity,Godot等主流游戏引擎&#xff0c;还包括Blender、Houdini、3D…

(3)重定向 | 时间相关指令 | 文件查找 | 打包与压缩

Ⅰ . 初始重定向01 输出重定向 >在上一节中我们为了方便讲解 head 和 tail 指令&#xff0c;我们用到了 > 去生成了一千行文本。通过 > 将生成的一千行文本写入到了 large.txt 中……我们现在来正式介绍一下&#xff1a;$ echo "内容" > [目标] 本来应…

DTH11测量温湿度学习(第十一天)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-削好皮的Pineapple! &#x1f468;‍&#x1f4bb; hello 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 削好皮的Pineapple! 原创 &#x1f468;‍&#x1f4…

Go语言初识--标识符 可见性

Go语言初识–标识符 可见性 和C语言相似&#xff0c;go语言的基本组成有&#xff1a; 包声明&#xff0c;编写源文件时&#xff0c;必须在非注释的第一行指明这个文件属于哪个包&#xff0c;如package main。引入包&#xff0c;其实就是告诉Go 编译器这个程序需要使用的包&…

Python实例之画小猪佩奇

效果图&#xff1a;python代码以及解释&#xff0c;没有运用模块。 """ 绘制小猪佩奇 """ from turtle import *def nose(x,y):"""画鼻子"""penup()# 将海龟移动到指定的坐标goto(x,y)pendown()# 设置海龟的方向&…

Unity笔记——事件中心

事件中心是什么事件中心是 Unity 游戏开发中常用的架构设计&#xff0c;它基于观察者模式 或 发布-订阅模式&#xff0c;通过委托和事件构建的一种消息管理系统。主要用于降低代码耦合度&#xff0c;实现模块间的松耦合通信的消息处理系统能大幅提升代码的可维护性和扩展性&…

Java: 反射机制的 ParameterizedType(参数化类型)

在 Java 中&#xff0c;ParameterizedType 是 java.lang.reflect 包下的一个接口&#xff0c;属于反射 API 的一部分&#xff0c;主要用于表示参数化类型&#xff08;即带有类型参数的泛型类型&#xff09;。它是 Java 反射机制中处理泛型类型信息的关键接口之一。 一、什么是参…

OkHttp 与 Retrofit 完美结合:打造高效的 Android 网络请求

前言在现代 Android 开发中&#xff0c;网络请求是几乎每个应用都必不可少的功能。OkHttp 和 Retrofit 作为当前最流行的网络请求库组合&#xff0c;为开发者提供了简洁高效的解决方案。本文将详细介绍如何将这两者结合使用&#xff0c;充分发挥它们的优势。一、OkHttp 和 Retr…

系统辨识建模

系统辨识建模 一、系统辨识建模的作用 1. 建立真实物理系统的数学模型 2. 为后续控制器/强化学习算法提供仿真环境 3. 提高控制精度和安全性 二、本文的系统辨识是怎么做的 1. 实验采集 2. 数学建模 3. 在控制系统中的作用 三、实际用法流程(简化版) 1. 系统辨识阶段 2. 强化…

Android开发:Java与Kotlin深度对比

1. 语言特性与现代性 Java (特别是 Android 主要使用的 Java 8 及之前版本): 相对冗长&#xff1a; 需要编写更多的样板代码&#xff08;如 getter/setter、findViewById 的显式类型转换、匿名内部类等&#xff09;。空指针异常 (NPE)&#xff1a; 类型系统默认允许 null&#…

米家打印机驱动:Wi-Fi 无线打印丝滑顺畅不卡顿,从此告别对打印机干瞪眼

各位小米家居控们&#xff0c;你们有没有过这种经历&#xff0c;新买的打印机回家&#xff0c;结果电脑跟它像俩傲娇的小情侣&#xff0c;死活不搭话&#xff1f;急得你想当场表演一个“打印机抱头痛哭”&#xff1f;别急&#xff0c;今天就给你们安利个神队友——米家打印机驱…