develop

프론트엔드가 이미지 색상을 실시간으로 바꾸는 법 - hex-to-css-filter

crab. 2023. 1. 20. 16:12

팔레트 라이브러리

  • 나의 경우 React Color를 사용했다.
  • 제일 사용자가 많았고 레퍼런스도 좋았으며 우리가 추구하는 팔레트 기능과 모양에 가장 부합했다.
  • React Color는 유저가 선택한 컬러를 hex코드로 변환한다.

hex코드? 문제없네

  • 아니 당연히 문제가 있다.
  • 지금 하려고 하는 건 실시간으로 색상이 변해야 하는 것이다
  • 중요한건 단색 div의 백그라운드 컬러를 바꾸는게 아니라!
  • 이미 있는 이미지의, 실생활 사진의 이미지의 색상을 전부 자연스럽게 바꿔주는 것이다.
  • 이때 hex코드를 그대로 쓴다는 건 svg시절로 돌아가는 것과 마찬가지이며
  • 이미지마다 들어간 색상들을 찾아내 그 색상들을 하나하나 계산해서 넣어줘야한다.

filter

  • 결과적으로 필터를 써야만한다.
  • 그렇다면 어떤 필터를 써야 할까?
  • 제일 먼저 든 생각을 hue-rotate였다.
  • 당장 hue-rotate를 이용해서 색상을 변경해보는데 색상이 있는경우(채도가 있는 경우)는 색상이 잘 변경되지만 검은색과 흰색의 경우는 변경이 안되었다.
  • 그렇다면 어떤 필터를 써야하지? → 색상마다 계산해서 필터를 복합적으로 써야하나? → color picker로 부터 받은 hex코드의 경우의 수는 16의 6제곱=1677만 7216가지인데? → 이건 누군가 분명 계산해놓은게 있을거야! 도와줘요 구글

구글은 답을 알고있다. 늘 그래왔듯이.

case closed

  • 있다!
  • https://www.npmjs.com/package/hex-to-css-filter
    • 이름부터가 hex to css filter이다.
  • 이제부터는 술술이다. (사실 svg 버리고 이 방법 할때부터 술술이었다..)
  • color picker로 받은 hex를 hex-to-css-filter로 filter로 변환해주고 그 필터를 인라인으로 해당이미지 배경이미지의 속성값에 넣어주면 된다.
// ColorPicker

"use strict";

import React from "react";
import reactCSS from "reactcss";
import { SketchPicker } from "react-color";

class SketchExample extends React.Component {
  state = {
    displayColorPicker: false,
    color: {
      r: "0",
      g: "0",
      b: "0",
      a: "1",
    },
  };

  handleClick = () => {
    this.setState({ displayColorPicker: !this.state.displayColorPicker });
  };

  handleClose = () => {
    this.setState({ displayColorPicker: false });
  };

  handleChange = color => {
    this.setState({ color: color.rgb });
    this.props.ColorBox({ color: color.hex, alpha: color.rgb.a });
  };

  render() {
    const styles = reactCSS({
      default: {
        color: {
          width: "45px",
          height: "45px",
          borderRadius: "10px",
          background: `rgba(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b}, ${this.state.color.a})`,
        },
        swatch: {
          padding: "0px",
          background: "#fff",
          borderRadius: "10px",
          boxShadow: "0 0 0 1px rgba(0,0,0,.1)",
          display: "inline-block",
          cursor: "pointer",
        },
        popover: {
          position: "absolute",
          zIndex: "2",
        },
        cover: {
          position: "fixed",
          top: "0px",
          right: "0px",
          bottom: "0px",
          left: "0px",
        },
      },
    });

    return (
      <div>
        <div style={styles.swatch} onClick={this.handleClick}>
          <div style={styles.color} />
        </div>
        {this.state.displayColorPicker ? (
          <div style={styles.popover}>
            <div style={styles.cover} onClick={this.handleClose} />
            <SketchPicker
              color={this.state.color}
              onChange={this.handleChange}
            />
          </div>
        ) : null}
      </div>
    );
  }
}

export default SketchExample;
import ColorPicker from "../../elements/ColorPicker";
import { hexToCSSFilter } from "hex-to-css-filter";

const [customColor, setCustomColor] = useState({
    color: "#ffffff",
    alpha: 0,
  });

const cssFilter = hexToCSSFilter(customColor.color);

<ColorPicker ColorBox={setCustomColor} />

<ImgBackGround
                    src={`${mapBlack}`}
                    alt=""
                    style={{
                      filter: cssFilter.filter.slice(0, -1),
                      opacity: customColor.alpha,
                    }}
                  />

const Img1 = styled.img`
  width: 700px;
  height: 700px;
  position: absolute;
  background-blend-mode: overlay;
`;
const Img2 = styled.img`
  width: 700px;
  height: 700px;

  position: absolute;
  mix-blend-mode: soft-light;
`;

후기

  • 꽤 규모가 있던(?) 기능을 끝냈다.
  • 매번 다짐하지만, 못지키지만, 다시 다짐하는 것은
    • 나는 아무것도 모른다 라는 사실만 안다는 점을 명심하자는 것이다.
  • 이번에 하고 있는 것도 박사님께서 캐시라는 힌트를 이미 주신 것 같은데 우선 cafe24측에 질문을 올렸다. (왜냐면 거기서 우선 회신을 달라했기 때문에.. fun cool sexy)
    • 답변 오면 그 문제를 캐시방면으로 해결해보아야겠다.
  • 계속 느끼는 건 회사에서 뭔가 다들 답을 아는데 나를 성장시켜 주시려고 풀게 하는 느낌이 든다.. 덕분에 나름 무럭무럭(?) 성장하고 있는 것 같다. 몰래카메라 같은 느낌, 싫지만은 않은 느낌, 일인분을 해야 하는 느낌, 나는 언제 프로다운 프로가 될까 하는 느낌, 성장해야 한다.

출처

https://homzzang.com/b/css-330

https://hyoni-k.tistory.com/48

https://casesandberg.github.io/react-color/#api-individual

https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode

https://m.blog.naver.com/shl745/181200588

https://paint.sumo.app/?lang=ko

https://devbirdfeet.tistory.com/196

https://codepen.io/sosuke/pen/Pjoqqp

https://stackoverflow.com/questions/7415872/change-color-of-png-image-via-css

https://www.npmjs.com/package/hex-to-css-filter