Silhouette of a color image

6

Thanks to Rene Limón's response , I was able to create a CSS silhouette like this:

#silueta img {
  -webkit-filter: grayscale(100%) brightness(0); /* Safari 6.0 - 9.0 */
  filter: grayscale(100%) brightness(0);
  opacity: 0.6;
}
<div id="original">
  <img src="https://i.stack.imgur.com/JJ6Vs.png" height="150px" width="auto" />
</div>
<div id="silueta">
  <img src="https://i.stack.imgur.com/JJ6Vs.png" height="150px" width="auto" />
</div>

But there is a problem: the silhouette is black / gray and I would like it to be of other colors to superimpose several and to easily differentiate what corresponds to each of them.

I have tried changing the filter values to add hue-rotate , but it has been unsuccessful. I tried combining with the most voted solutions to this question (in English), but They did not work either. I also tried adding different filters to div e img , but I was not lucky.

I imagine that the problem is that when you set the brightness to zero, the silhouette is black and even if you change the value of hue-rotation it will not affect because it will continue to be black.

How could you get a silhouette with color using CSS? What combination of filters would work?

    
asked by Alvaro Montoro 01.03.2017 в 01:50
source

3 answers

2

If you decrease the grasycale , what will happen is that the image will not be "opaque" and you will see the color if you break the hue and if you use contrast and saturation . It would be very simple if there was a "fill" option. One way to get the desired effect is through Canvas. All you have to do is draw the image, get its imageData and overwrite the painted colors.

Example

let palette = {
  orange: {
    red: '243',
    green: '156',
    blue: '18'
  },
  midnight: {
    red: '44',
    green: '62',
    blue: '80'
  },
  greensea: {
    red: '22',
    green: '160',
    blue: '130'
  }
}

let orange = document.getElementById('orange');
let midnight = document.getElementById('midnight');
let greensea = document.getElementById('greensea');

drawImage(orange, palette.orange);
drawImage(midnight, palette.midnight);
drawImage(greensea, palette.greensea);

function drawImage(canvas, color) {
  let ctx = canvas.getContext('2d');
  let img = new Image();

  img.onload = draw;
  fetchImage("https://i.imgur.com/XXJf1A7.png")
    .then(b64 => img.src = b64);

  function draw() {
    let hRatio = canvas.width / img.width;
    let vRatio = canvas.height / img.height;
    let ratio = Math.min(hRatio, vRatio);
    let centerX = (canvas.width - img.width * ratio) / 2;
    let centerY = (canvas.height - img.height * ratio) / 2
    ctx.drawImage(
      img,
      0,
      0,
      img.width,
      img.height,
      centerX,
      centerY,
      img.width * ratio,
      img.height * ratio
    );

    let imageData = ctx.getImageData(0, 0, img.width, img.height);
    let data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
      // rojo
      data[i] = color.red;
      // verde
      data[i + 1] = color.green;
      // azul
      data[i + 2] = color.blue;
    }

    // sobreescribe la imagen original
    ctx.putImageData(imageData, 0, 0);
  }
}

function fetchImage(image) {
  return new Promise((resolve) => {
    let http = new XMLHttpRequest();
    http.open('GET', image);
    http.responseType = 'arraybuffer';

    http.onload = function() {
      if (this.status === 200 && this.readyState === 4) {
        let blob = new Blob(
          [this.response], {
            type: 'image/png'
          }
        );
        let url = window.URL.createObjectURL(blob);
        let reader = new FileReader();
        reader.readAsDataURL(blob);
        reader.onloadend = function() {
          resolve(reader.result);
        }
      }
    }
    http.send();
  });
}
*,
*:before,
*:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  align-items: center;
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  padding: 20px;
}
<!-- Para navegadores que no implementen Promise -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.0.5/es6-promise.auto.min.js"></script>

<canvas id="orange" width="500" height="300"></canvas>
<canvas id="midnight" width="500" height="300"></canvas>
<canvas id="greensea" width="500" height="300"></canvas>

Obviously you can draw the three shapes in a single Canvas stage to be able to move them. If you want to move them, you must associate a handler for the drag event in Canvas, obtain the shape according to the coordinates of the pointer and repaint the shape by updating the position according to the pointer.

Note: The images submitted to this procedure must be hosted locally or via base64, otherwise you will get the error "The canvas has been tainted by cross-origin data . at drawImage ", which means that it can not deal with an image from another domain.

    
answered by 01.03.2017 / 19:06
source
0

In this post suggest the combination of three coloring filters the image:

red

filter: grayscale(100%) sepia(100%) hue-rotate(360deg);
filter: grayscale(100%) sepia(100%) hue-rotate(0deg);

green

filter: grayscale(100%) sepia(100%) hue-rotate(100deg);

blue

filter: grayscale(100%) sepia(100%) hue-rotate(200deg);

I think it's the closest thing to what you're looking for in what you can use "filter"

    
answered by 01.03.2017 в 05:46
0
  

Translation of the r answer that chazsolo wrote on the site in English.

Instead of using a gray scale, you could set the contrast to 0 and then play with the other values. A high value of saturate will help to mark more colors.

Here you can see it working:

#silhouette img {
  -webkit-filter: contrast(0) sepia(100%) hue-rotate(190deg) saturate(2000%) brightness(100%);
  filter: contrast(0) sepia(100%) hue-rotate(190deg) saturate(2000%) brightness(100%);
  opacity: 1;
}
<div id="original">
  <img src="https://i.stack.imgur.com/JJ6Vs.png" height="150px" width="auto" />
</div>
<div id="silhouette">
  <img src="https://i.stack.imgur.com/JJ6Vs.png" height="150px" width="auto" />
</div>
    
answered by 23.05.2017 в 14:39