前端实现图片伽玛值调整,并打印调整后的文件

news2024/11/17 4:28:25

        前段时间去客户现场,客户提出了一个“伽玛值”的需求,啊????伽玛值是什么。。。

        后来看了客户原先系统的“伽玛值”处理效果,结果发现这不就是对图片的锐化值的调整嘛。那么问题来了,这怎么实现呢?属实没接触过啊。但是既然甲方粑粑提出来了,还能怎么办呢,只能硬着头皮写了,又是秃头的一天!!!

1、什么是伽玛值

        在前端开发中,处理伽马值通常涉及到图像的显示和调整,特别是在图像渲染、显示优化和用户交互中。在Web开发中,处理伽马值的操作往往与图像的亮度、对比度以及如何让图像在不同显示设备上表现一致相关。

1.1 伽马值与图像显示

        前端处理伽马值,通常是为了调整图像的显示效果,以便它能够在不同的显示设备上呈现出最佳效果。因为不同的显示器、操作系统和浏览器可能会有不同的色彩和亮度表现,前端开发人员通常需要在图像加载和渲染时对其进行调整。

1.2.伽马校正的应用

在前端开发中,伽马校正通常有以下几种使用场景:

  • 图像加载和显示:在加载图像时,使用JavaScript对其进行伽马值调整,确保图像显示一致,尤其是当图像来源不同,或者浏览器渲染差异较大时。

  • Canvas绘图:在 <canvas> 元素中,伽马校正可能会涉及到像素级别的颜色调整,特别是当绘制图像或进行图像处理时。

  • 色彩空间管理:不同的显示设备和Web环境可能使用不同的色彩空间(例如sRGB或Adobe RGB),前端开发人员可能需要考虑这些色彩空间之间的差异,并对图像或画面进行伽马校正,确保图像显示得尽可能真实。

2、实现代码

        苦苦肝了一天,终于把功能实现了,我这里封装成了一个单独的组件,可以供之后调用,废话不多说,直接上代码。

<template>
  <el-dialog title="伽马值调整"
             :visible.sync="iamgeModel"
             width="80%"
             @open="onDialogOpen"
             @close="onDialogClose">
    <div>
      <!-- <input type="file"
             @change="onFileChange"
             accept="image/*"> -->
      <div v-if="imageSrc"
           style="margin-top: 20px; text-align: center;">
        <img :src="imageSrc"
             alt="预览图"
             ref="previewImage"
             :style="imageStyle">
      </div>
      <el-slider v-model="gammaValue"
                 :min="0.1"
                 :max="3"
                 :step="0.01"
                 label="伽玛值"
                 @change="debouncedAdjustImageGamma" />
      <div style="text-align: center; margin-top: 10px;">
        <el-button type="primary"
                   @click="printImage">打印</el-button>
      </div>
    </div>
  </el-dialog>
</template>
<script>
import { debounce } from 'lodash'
import { findByEfileIdBase64 } from '@/api/v2/tableData'
export default {
  data () {
    return {
      iamgeModel: false,
      originalImageSrc: null,
      imageSrc: null,
      gammaValue: 1,
      imageStyle: {
        maxWidth: '100%',
        maxHeight: '80vh',
        objectFit: 'contain'
      },
      worker: null, // Web Worker 存储变量
      debouncedAdjustImageGamma: null, // 防抖函数
      loadingInstance: null // 加载动画实例
    }
  },
  methods: {
    init (value) {
      console.log('value :>> ', value)
      // 获取图片文件base64
      findByEfileIdBase64(value).then((result) => {
        if (result.status != 0) {
          this.$Message.error('该文件原始文件不是图片类型!')
          return
        }
        console.log('result :>> ', result)
        let base64String = result.data
        const mimeType = 'image/png' // 根据实际文件类型设置 MIME 类型
        const file = this.base64ToFile(base64String, 'image.png', mimeType)
        let efileParams = {
          base64Value: result,
          fileObj: file
        }
        console.log('efileParams :>> ', efileParams)
        this.onFileChange(efileParams)
      })
    },
    // base64转换文件对象
    base64ToFile (base64String, fileName, mimeType) {
      // 可以直接解码整个 Base64 字符串
      const byteCharacters = atob(base64String) // 解码 Base64 字符串

      // 创建一个字节数组
      const byteArrays = []
      for (let offset = 0; offset < byteCharacters.length; offset++) {
        const byte = byteCharacters.charCodeAt(offset)
        byteArrays.push(byte)
      }

      // 创建一个 Blob 对象,指定 MIME 类型
      const byteArray = new Uint8Array(byteArrays)
      const blob = new Blob([byteArray], { type: mimeType })

      // 返回一个 File 对象(可以指定文件名)
      return new File([blob], fileName, { type: mimeType })
    },
    onDialogOpen () {
      // 在对话框打开时初始化 Web Worker
      const workerScript = `
        self.onmessage = function(e) {
          const { imageData, gammaValue } = e.data;
          const data = imageData.data;
          const gamma = gammaValue;

          // 遍历每个像素,调整颜色值
          for (let i = 0; i < data.length; i += 4) {
            for (let j = 0; j < 3; j++) {
              let colorValue = data[i + j];
              colorValue = 255 * Math.pow(colorValue / 255, 1 / gamma);
              data[i + j] = Math.min(255, Math.max(0, colorValue));
            }
          }

          // 返回处理后的图像数据
          self.postMessage({ imageData });
        };
      `
      // 使用 Blob 动态创建 Worker
      const blob = new Blob([workerScript], { type: 'application/javascript' })
      this.worker = new Worker(URL.createObjectURL(blob))

      this.worker.onmessage = (e) => {
        // 从 Worker 中接收修改后的图像数据
        const { imageData } = e.data
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        canvas.width = imageData.width
        canvas.height = imageData.height
        ctx.putImageData(imageData, 0, 0)
        this.imageSrc = canvas.toDataURL() // 获取修改后的图片数据

        // 完成后关闭加载动画
        if (this.loadingInstance) {
          this.loadingInstance.close()
        }
      }

      // 防抖调整图像的函数
      this.debouncedAdjustImageGamma = debounce(this.adjustImageGamma, 100) // 防抖:每100ms触发一次
    },
    onDialogClose () {
      // 在对话框关闭时销毁 Web Worker 和防抖函数
      if (this.worker) {
        this.worker.terminate()
        this.worker = null
      }
      if (this.loadingInstance) {
        this.loadingInstance.close() // 关闭加载动画
      }
    },
    onFileChange (event) {
      const file = event.fileObj
      console.log('file :>> ', file)
      if (file && file.type.startsWith('image')) {
        const reader = new FileReader()
        console.log('reader :>> ', reader)
        reader.onload = (e) => {
          this.originalImageSrc = e.target.result// 需要一个 base64格式图片
          this.imageSrc = this.originalImageSrc
          this.adjustImageGamma() // 文件上传后立刻处理图像
        }
        reader.readAsDataURL(file)
      }
    },
    adjustImageGamma () {
      // 开始加载时显示 loading 动画
      this.loadingInstance = this.$loading({
        lock: true,
        text: '处理中,请稍候...',
        background: 'rgba(0, 0, 0, 0.7)'
      })

      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      const img = new Image()

      img.src = this.originalImageSrc
      img.onload = () => {
        canvas.width = img.width
        canvas.height = img.height
        ctx.drawImage(img, 0, 0)

        // 获取图像数据
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

        // 发送图像数据到 worker 进行处理
        if (this.worker) {
          this.worker.postMessage({ imageData, gammaValue: this.gammaValue })
        }
      }
    },
    printImage () {
      const printWindow = window.open('', '_blank')
      printWindow.document.write('<img src="' + this.imageSrc + '" />')
      printWindow.print()
    }
  }
}
</script>

 

 

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

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

相关文章

qt QFrame详解

1、概述 QFrame是Qt框架中用于提供框架或边框的控件&#xff0c;主要用于在图形用户界面&#xff08;GUI&#xff09;中创建框架&#xff0c;并提供各种边框样式和功能。它是Qt中一个基础的容器类&#xff0c;也是许多基础控件的基类&#xff0c;可以被QLCDNumber、QToolBox、…

python json详解

json 是 Python 中用于处理 JSON 数据的标准库。JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;易于人类阅读和编写&#xff0c;同时也易于机器解析和生成。Python 的 json 模块提供了将 Python 对象与 JSON 数据相互转换的功…

ISUP协议视频平台EasyCVR私有化部署视频平台如何实现RTMP推流将大疆无人机的视频画面回传?

在现代视频监控和流媒体技术领域&#xff0c;EasyCVR视频融合云平台以其卓越的性能和灵活性&#xff0c;成为了跨区域、网络化视频监控综合管理的理想选择。作为TSINGSEE青犀视频“云边端”架构体系中的核心组件&#xff0c;私有化部署视频平台EasyCVR不仅能够实现视频数据的集…

【时间之外】IT人求职和创业应知【37】-AIGC私有化

目录 新闻一&#xff1a;2024智媒体50人成都会议暨每经20周年财经媒体峰会召开 新闻二&#xff1a;全球机器学习技术大会在北京召开 新闻三&#xff1a;区块链技术在金融领域的应用取得新突破 不知不觉的坚持了1个月&#xff0c;按照心理学概念&#xff0c;还要坚持2个月&am…

SqlServer 存储临时数据

WITH 子句中的 公用表表达式&#xff08;CTE&#xff09;、临时表&#xff08;Temporary Table&#xff09; 和 表变量&#xff08;Table Variable&#xff09; 都可以存储临时数据&#xff0c;但它们的使用场景、生命周期、作用范围和性能特性有所不同。下面是这三者之间的主要…

jmeter基础05_第1个http请求

本节课使用网站“httpbin.org”进行基础的http请求全流程。 请求获取httpbin.org的首页&#xff1a; 请求方法&#xff1a;GET URL&#xff1a;http://httpbin.org 参数&#xff1a;无 1、操作步骤 ① 打开jmeter&#xff1a;命令行窗口输入“jmeter”并回车。 ② 添加线程组…

SpringBoot+MyBatis+MySQL的Point实现范围查找

前言 最近做了一个功能&#xff0c;需要通过用户当前位置点获取指定范围内的数据。由于后端存储用的是 MySQL&#xff0c;故选择使用 MySQL 中的 Point 实现范围查找功能。ORM 框架用的是 MyBatis&#xff0c;MyBatis 原生并不支持 Point 字段与 POJO 的映射&#xff0c;需要自…

计算机网络中的数据包传输机制详解

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 引言 数据包的基本概念…

DAY110代码审计-PHP框架开发篇ThinkPHP版本缺陷不安全写法路由访问利用链

https://blog.csdn.net/m0_60571842/article/details/139057898 看这个原作者 知识点&#xff1a; 1、PHP框架学习-ThinkPHP-架构&调试&路由&接受2、PHP框架审计-ThinkPHP-不安全写法&版本漏洞 框架审计总结方向&#xff1a; 1、版本不安全写法怎么检测 -本…

【日志】力扣11.盛水最多的容器

2024.11.15 【力扣刷题】 11.盛水最多的容器 - 力扣&#xff08;LeetCode&#xff09; int maxArea(int* height, int heightSize) {int max 0;int V 0;int left 0;int right heightSize - 1;while (left < right) {if (height[left] > height[right]) {V height[r…

leetcode100:相同的树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true示例 2&…

❤React-React 组件基础(类组件)

❤React-React 组件基础 1、组件化开发介绍 组件化开发思想&#xff1a;分而治之 React的组件按照不同的方式可以分成类组件&#xff1a; 划分方式一&#xff08;按照组件的定义方式&#xff09; 函数组件(Functional Component )和类组件(Class Component)&#xff1b; …

SQL面试题——抖音SQL面试题 主播播出时长

主播播出时长 现有如下数据,主播id、房间号、播出的批次号,每个批次号进出房间的时间戳、分区时间: 每一次直播都有一个上播和下播,每个房间里,同一个批次号会有两条数据,分别记录了上播和下播时间,求每个主播的播出时长? 通过上面的数据,可以清晰的看出,同一个批次…

无人机检测车辆——多目标检测

目录 YOLOv3&#xff08;You Only Look Once version 3&#xff09;简介 YOLOv3 的主要特点 YOLOv3 的结构 1. 特征提取网络&#xff08;Backbone&#xff09; 2. 检测头&#xff08;Head&#xff09; 3. 输出层 YOLOv3 损失函数 YOLOv3 的优势 YOLOv3 的应用 YOLOv3…

【MyBatis操作数据库】XML配置

【配置连接字符串和MyBatis】 注意&#xff0c;这行代码代表着xml必须在mapper文件夹的下面&#xff08;路径必须保持一致&#xff09; 配置完文件后&#xff0c;需要写持久层代码 添加 mapper 接⼝&#xff1a; 添加 UserInfoXMLMapper这样的xml文件&#xff1a; 单元测试&a…

基础:用卷积神经网络(CNN)进行猫狗图像分类

在本篇教程中&#xff0c;我们将通过卷积神经网络&#xff08;CNN&#xff09;实现一个简单的猫狗图像分类器。我们将介绍如何处理数据、构建CNN模型、训练模型并在测试集上进行预测。最终&#xff0c;你将能够用这个模型对未知图像进行猫狗分类。 1. 环境准备 首先&#xf…

node对接ChatGpt的流式输出的配置

node对接ChatGpt的流式输出的配置 首先看一下效果 将数据用流的方式返回给客户端,这种技术需求在传统的管理项目中不多见,但是在媒体或者有实时消息等功能上就会用到,这个知识点对于前端还是很重要的。 即时你不写服务端,但是服务端如果给你这样的接口,你也得知道怎么去使用联…

聊聊Flink:Flink的运行时架构

一、运行时架构 上一篇我们可以看到Flink的核心组件的Deploy层&#xff0c;该层主要涉及了Flink的部署模式&#xff0c;Flink支持多种部署模式&#xff1a;本地、集群&#xff08;Standalone/YARN&#xff09;、云&#xff08;GCE/EC2&#xff09;。 Local&#xff08;本地&am…

【动手学电机驱动】 STM32-FOC(7)MCSDK Pilot 上位机控制与调试

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 三路互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…

华为云前台用户可挂载数据盘和系统盘是怎么做到的?

用户可以选择磁盘类型和容量&#xff0c;其后台是管理员对接存储设备 1.管理员如何在后台对接存储设备&#xff08;特指业务存储&#xff09; 1.1FusionSphere CPS&#xff08;Cloud Provisionivice&#xff09;云装配服务 它是first node https://10.200.4.159:8890 对接存…