日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React + Canvas 像素风格取色器

發布時間:2025/6/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React + Canvas 像素风格取色器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

有時候我們需要通過圖片去獲得具體像素的顏色。而強大的 Canvas 為我們提供了現成的接口。 這個功能其實并不難,只不過我們需要正確的理解 Canvas 并學會利用它的 API 。 如果你急于看到效果,可以直接訪問

演示地

源碼地址

我不會詳細得寫下每一個步驟,但是你可以一邊參照源碼,一邊配合這篇教程進行閱讀。

繪制圖片(-)

首先,我們需要基于圖片去繪制 Canvas。 操作步驟

  • 創建一個與圖片等寬高的canvas
  • 獲得canvas的 context
  • 將圖片繪制到 canvas
  • 我們在React中用最小化模型展示出來 我們在 React 的 DidMount 里拿到 image 實例。當然,你也可以直接創建一個 image 對象。

    import React, { PureComponent } from 'react' import PropTypes from 'prop-types'export class TestPicker extends PureComponent {static propTypes = {src: PropTypes.string.isRequired,width: PropTypes.number.isRequired,height: PropTypes.number.isRequired,}static defaultProps = {width: 1300,height: 769,src: '/sec3.png'}// 在初始化階段注冊 ref 回調函數去獲得 DOM 的實例constructor (props) {super(props)this.imageCanvasRef = ref => this.imageCanvas = refthis.image = new Image()this.image.src = props.src}// 請注意,一定要在圖片加載完全之后才開始繪制 CanvascomponentDidMount () {this.image.onload = () => this.renderImageCanvas()}renderImageCanvas = () => {const { width, height } = this.propsthis.imageCtx = this.imageCanvas.getContext('2d')this.imageCtx.drawImage(this.image, 0, 0, width, height)}render () {const { width, height, src } = this.propsreturn <div><canvaswidth={width}height={height}style={{ width, height }}ref={this.imageCanvasRef}></canvas></div>} } 復制代碼

    只要將它掛載到相應的節點下,你可以看到有一個和圖片一樣大小的 Canvas 并且繪制了圖片。

    但是我們需要注意圖片應該是同源的,如果不是同源,Canvas 繪制圖片時會報錯。具體如何設置可以參考 使用圖像 Using images

    Canvas 畫布與實際寬高

    本質上canvas的寬高設定包含兩個層面,一個是畫布的大小,另外一個則是Canvas 在文檔對象所占據的寬高。由于Canvas內部的繪制區域畫布大小默認是(width: 300px, height: 150px) ,比如當你 通過 css 設定 (width: 3000px;height: 1500px)的時候,內部的繪制區域大小會被強制與整體寬高保持統一,即內部的繪制區域會被放大十倍。像素級別的放大會導致實際的渲染效果變得更加模糊。因為要注意有時候你的繪制區域出現縮放現象。

    實現放大鏡位移(二)

    我們需要讓放大鏡的位置在鼠標正中心,并且跟隨鼠標移動。 實現方式也比較簡單,通過 onmousemove 時獲得當前 clientX 和 clientY, 并且減去當前 Canvas 視窗所占據的 left 和 top 即可。

    首先,我們在構造函數加了初始化的 state用來表示當前鼠標位移。 在鼠標移動時觸發 onmousemove 時去修改 state,通過改變 state 觸發 re-render,修改 left 和 top。

    constructor() {this.glassCanvasRef = ref => this.glassCanvas = refthis.state = {left: 0,top: 0} } handleMouseMove = (e) => {// 計算當前鼠標相對 canvas 中的位置this.calculateCenterPoint({ clientX: e.clientX, clientY: e.clientY })const { centerX, centerY } = this.centerPointthis.setState({ left: centerX, top: centerY }) }calculateCenterPoint = ({ clientX, clientY }) => {const { left, top } = this.imageCanvas.getBoundingClientRect()this.centerPoint = {centerX: Math.floor(clientX - left),centerY: Math.floor(clientY - top)} } render () {const { width, height, src } = this.propsconst { left, top } = this.statereturn <div style={{ position: 'relative' }}><canvaswidth={width}height={height}style={{ width, height }}onMouseMove={this.handleMouseMove}ref={this.imageCanvasRef}></canvas><canvas ref={this.glassCanvasRef}className="glass" style={{ left: left - glassWidth/2, top: top - glassHeight/2, width: glassWidth, height: glassHeight }}></canvas></div> } const glassWidth = 100 const glassHeight = 100 復制代碼

    繪制放大區域內容(三)

    好了,其實我們完成快一半了。接下來就是把放大區域部分的圖像放置到我們的放大鏡中。 在繪制之前,我們先清除一次畫布

    handleMouseMove = (e) => {this.glassCtx.clearRect(0, 0, glassWidth, glassWidth) } 復制代碼

    我們希望將放大鏡部分的元素放大, 我默認取了10倍放大效果。這種情況呈現的樣式比較友好,如果你還需要對元素再放大,你只需要修改 scale 即可。

    const INIT_NUMBER = 10 const finallyScale = INIT_NUMBER * (scale < 1 ? 1 : scale) 復制代碼

    接下來我們使用 canvas 提供的 drawImage 的復雜版本進行截取部分圖像。 CanvasRenderingContext2D.drawImage() 根據 MDN 中的演示圖片,我們知道

  • sx 和 sy 是原圖到我們需要繪制的放大鏡放大的左側以及頂部距離
  • sWidth 和 sHeight 是我們要選擇放大的部分
  • dx 和 dy 是當前繪制內容在放大鏡中的偏移量
  • dWidth 和 dHeight 即為放大鏡大小
  • drawImageSmoothingEnable(this.glassCtx, false) this.glassCtx.drawImage(this.image,Math.floor(centerX - (glassWidth / 2) / finallyScale), Math.floor(centerY - (glassHeight / 2) / finallyScale),Math.floor(glassWidth / finallyScale), Math.floor(glassHeight / finallyScale),-INIT_NUMBER, -INIT_NUMBER,glassWidth, glassHeight )const drawImageSmoothingEnable = (context, enable) => {context.mozImageSmoothingEnabled = enablecontext.webkitImageSmoothingEnabled = enablecontext.msImageSmoothingEnabled = enablecontext.imageSmoothingEnabled = enable } 復制代碼

    我們需要計算放大后的因素。此外,由于在計算鼠標當前位置時,可能會有1像素偏差,但被放大了10倍。所以我增加了10個像素的偏移量。你可以根據實際情況來決定偏移。

    通過drawImageSmoothingEnable函數讓我們最終繪制的圖像產生鋸齒效果。這樣就會有真實的像素風格了。

    繪制網格線(四)

    關于繪制網格線,依然可以參考 MDN 上的文檔。

    const GRID_COLOR = 'lightgray' drawGrid(this.glassCtx, GRID_COLOR, INIT_NUMBER, INIT_NUMBER)const drawGrid = (context, color, stepx, stepy) => {context.strokeStyle = colorcontext.lineWidth = 0.5for (let i = stepx + 0.5; i < context.canvas.width; i += stepx) {context.beginPath()context.moveTo(i, 0)context.lineTo(i, context.canvas.height)context.stroke()}for (let i = stepy + 0.5; i < context.canvas.height; i += stepy) {context.beginPath()context.moveTo(0, i)context.lineTo(context.canvas.width, i)context.stroke()} } 復制代碼

    實現取色(五)

    我們通過 getImageData 獲得具體的像素點的數據,不過還需要轉換一下才能變成可用的數據。

    getColor = () => {const { centerX, centerY } = this.centerPointconst { data } = this.imageCtx.getImageData(centerX, centerY, 1, 1)const color = transform2rgba(data) }const transform2rgba = (arr) => {arr[3] = parseFloat(arr[3] / 255)return `rgba(${arr.join(', ')})` }復制代碼

    結語

    原本我實現了一個在 Canvas 里又繪制一個放大鏡去放大圖像。但這樣的問題就是放大鏡只能在 Canvas 內部活動,添加樣式之類的需要通過 Canvas 繪制,失去了 CSS 的能力。 現在這種分離的方式可以支持自定義 CSS 樣式,而且減少了 Canvas 中繼續繪制 Canvas 放大倍數的復雜度。

    當然,這只是一個 啟發性的demo,依然有許多粗糙的地方。希望能對你有用~

    總結

    以上是生活随笔為你收集整理的React + Canvas 像素风格取色器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。