iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 6
2
Modern Web

用 Javascript 當個影像魔術師系列 第 6

Day 06 - 圖片效果 - 曝光度

曝光度調整

接下來繼續介紹一個也很實用的功能,曝光度調整。

一樣傳入 Uint8ClampArray,並且將透過 amount 來調整亮度 ( 使用的區間是 -100 ~ 100 ),大於 0 就是增加亮度, 反之則是降低。通過一次增加三個通道的值讓畫面顯得更亮是最簡單的演算法,實做也很簡單如下


export const brightness = (pixelData, amount) => {
// 每次跳四個索引,也就是一個像素,不處理透明度
  for (let i = 0; i < pixelData.length; i += 4) {
    pixelData[i] = pixelData[i] + amount // red
    pixelData[i + 1] = pixelData[i + 1] + amount // green
    pixelData[i + 2] = pixelData[i + 2] + amount // blue
  }
  return pixelData
}

外觀 & 資料流程

接下來我們做一個簡易的 Slider 來更好操控。這邊為了快速就直接套用 element UI,詳細用法請參照官網。因為接下來會大量使用到這個元件,所以在包了一層方便使用。

<div class="slider">
  <span>{{ title }}</span>
  <el-slider
    :value="value"
    :min="min"
    :max="max"
    @input="handleChange"
  ></el-slider>
</div>

在外層中使用

    <Slider
    title="曝光度"
    :min="-100"
    :max="100"
    :value="brightness"
    @sliderChange="val => sliderChange(val, 'brightness')"
  ></Slider>

接下來把這些透過 Slider 調整的參數以及一開始獲得的 ImageData 放到 Store 裡面方便之後使用。所以當滑動更新參數時,editImageData,也會相對應更新。

  state: {
    sliderValue: {
      brightness: 0
    },
    originalEditData: {}
  },
  mutations: {
    CHANGE_STATE_VALUE(state, { key, val }) {
      if (state[key] !== undefined) {
        state[key] = val
      }
    },
    CHANGE_SLIDER_VALUE(state, { key, val }) {
      if (state.sliderValue[key] !== undefined) {
        state.sliderValue[key] = val
      }
    }
  },
  getters: {
    editImageData({ sliderValue, originalEditData }) {
        if (sliderValue.brightness !== 0) {
          filters.brightness(originalEditData.data, sliderValue.brightness)
        }
        return originalEditData
      }
    }
  }

接下來我們在 watch 更新過後的資料,並且重新繪製到 Canvas 上就可以了

watch: {
  editImageData(pixelData) {
    const canvas = this.$refs.drawCanvas
    const context = canvas.getContext('2d')
    context.putImageData(pixelData, 0, 0)
  }
}

效果

到這邊應該基本的流程已經建立完成,有一些過於瑣碎的傳遞資料處理就不再詳細說明,讀者可能自行需要補足一些地方。到這邊如果沒問題的話,效果應該會如下

一開始好像還算正常,但到後面拖回去原始的值時候卻發現回不去了~

因為在 editImageData 裡面,我們是直接對原始的值做處理,所以假設原本的值是這樣好了

[180, 170, 160, 255] 

當今天是通通加 100 時會變成

// 雖然實際上 + 100 的值不會是這樣,但還記得之前說過的特性嗎,超過 255 的值會被縮成 255

[255, 255, 255, 255] 

也就是說,就算你這時候在往回調,原本的顏色就跟變了心的女朋友一樣回不來了,所以我們修改一下,當需要做運算處理時,我們都複製一份原始的資料,每一次都使用原始的資料做運算

  editImageData({ sliderValue, originalEditData }) {
      if (originalEditData.data) {
        const imageDataCopy = new ImageData(
          new Uint8ClampedArray(originalEditData.data),
          originalEditData.width,
          originalEditData.height
        )
        if (sliderValue.brightness !== 0) {
          filters.brightness(imageDataCopy.data, sliderValue.brightness)
        }
        return imageDataCopy
      }
    }

看一下成果

小結

今天介紹了常用的曝光度調整,以及把一些基本的元件、流程建立起來,方便之後擴增,明天見!


上一篇
Day 05 - 圖片效果 - 灰階、反轉
下一篇
Day 07 - 直方圖顯示
系列文
用 Javascript 當個影像魔術師30

尚未有邦友留言

立即登入留言