3

Is there a way to blend two PNG images to make perfect match when they both have border with alpha on it?

This is an example of the issue that I have:

img {
  position: absolute;
  left: 0px;
  top: 0px;
}

.container {
  height: 512px;
  width: 512px;
}
<div class="container">
  <img src="https://image.prntscr.com/image/VmxphMVDQSu-OXXnHQm1Tg.png" alt="Sphere">
  <img src="https://image.prntscr.com/image/n0cbaO-4QVOk_PQ8ESQRqQ.png" alt="Cube">
</div>

Or a link to CodePen

The situation is that I have two 3D renders that are saved as PNG's, and both have alpha border with 50% transparency that will do a perfect match if you merge them in Photoshop and/or After Effects.

But when creating the same situation in HTML/CSS we got a white line between the elements. After doing some reading about mix-blending-mode and background-blending-mode and do some testing with them it doesn't seems to help. We think that both of the images (their alpha channels) pre-multiplies with the background and that is why you would get semi transparent line between them (where the border is).

Is there a way to achieve this with CSS, or even maybe JavaScript/jQuery?

Edit: So we won't get into more comments on images moving and css tricks on that. It is not an option to remove that 1px, or to hide it since the big picture would not have the same look.

Pece
  • 637
  • 3
  • 8
  • 20
  • *"will do a perfect match if you merge them in Photoshop"* hum nope https://i.stack.imgur.com/X9D3Q.png – Kaiido Sep 15 '17 at 13:38
  • @Kaiido they do if you use Alpha Add Mode in AF. I am not sure if prntscr saves the png's as indexed, if it does in Photoshop you would have to convert the image in sRGB as Photoshop doesn't handle indexed images very good – Pece Sep 15 '17 at 14:06

4 Answers4

3

This isn't a matter of premultiplying with the background -- it's that along the border you have partially-transparent pixels from both images in the same position, which lets the background bleed through. 50% transparency plus 50% transparency doesn't equal 100% opaque.

Rather than fiddling with dropshadows or pixel-adjustments to patch over the problem after the fact, I think you'll need to adjust the image masks themselves. (I don't believe there will be a CSS or JS solution to this because there's no programmatic way to determine what the intended result is.)

If you're only stacking two images, this is easy -- don't put any alpha channel on the "bottom" image, put one only on the "top" image, and you're done.

If you need to stack more than two (or if you need a mask on the background image to allow the page background to show through), you'll have a few options:

  1. wherever the border between images would cause this bleed-through, use a 1-bit alpha channel on the "bottom" image in the stack. So if you were stacking the "sphere" image above the "cube" image, the cube would have no partial transparency along the border between sphere and cube, all the pixels along the border would be 100% opaque. The sphere's partial transparency would smooth out the border so you don't see a pixelated fringe.
  2. Make the masks on the bottom images one pixel bigger than they currently are. This is the lazy way of accomplishing (1).
  3. pre-multiply the color within the images themselves - not with the background but with the other images that would otherwise overlap. The colors along the border darken to make up for the white color that would otherwise bleed through. (As is probably obvious this one's a little outside my area of expertise so I can't suggest exactly how to calculate the precise colors...)
Daniel Beck
  • 16,972
  • 5
  • 29
  • 49
  • Thanks for the answer Daniel, yes your options are a way to fix the problem, but we were trying to avoid changing of the images since we would have situations with different elements and number of images with different colors, so that would mean that every object in 3D would need to be manually adjusted. That is why I am searching a solution with CSS3, HTML5 or JavaScript/jQuery so we won't have to change every picture manualy – Pece Sep 15 '17 at 13:39
  • Yup, totally understand -- I wish I had a simpler solution for you but I don't think there's any way to do this after the fact. If it were me I'd try the "make the masks bigger" approach first, since it'd be the least work, and see if the results are acceptable. – Daniel Beck Sep 15 '17 at 13:42
  • @Pece, why not generate these shapes with webGL directly if you're ok with js solutions? – Kaiido Sep 15 '17 at 13:57
  • @Kaiido since these are example shapes, the 3D models can and will be more complex than this – Pece Sep 15 '17 at 14:08
  • webgl can handle complex models, don't worry. – Kaiido Sep 15 '17 at 14:17
  • It is not that I worry on making the complex models in webgl, it is that all the models would have to be re-created so it would be double work. And again I am not sure that the details would be the same as in Maya or 3DMax – Pece Sep 15 '17 at 15:48
0

There is a minor pixel difference. shift you cube by 1px to the top and tothe left and you are good to go.

img {
  position: absolute;
  left: 0px;
  top: 0px;
}
#cube{
  top:-1px;
  left:-1px;
}
.container {
  height: 512px;
  width: 512px;
}
<div class="container">
        <img src="https://image.prntscr.com/image/VmxphMVDQSu-OXXnHQm1Tg.png" alt="Sphere">
        <img src="https://image.prntscr.com/image/n0cbaO-4QVOk_PQ8ESQRqQ.png" id="cube" alt="Cube">
    </div>
ab29007
  • 7,170
  • 2
  • 14
  • 42
  • Thanks for your replay, but it is not a solution to lose those 1px. – Pece Sep 15 '17 at 13:01
  • then which white line are you talking about? – ab29007 Sep 15 '17 at 13:06
  • As I said this is part of the images, they have 1px border with alpha of 50%, and if you correlate them together you should get the right color for that border. We are not trying to loose that pixel since the big picture would look different – Pece Sep 15 '17 at 13:09
0

Try it help full solution

i have add only some css .container img:last-child{ left: -1px; top:-1px; position:absolute }

img {
            position: absolute;
            left: 0px;
            top: 0px;
        }
        
 .container img:last-child{ left: -1px; top:-1px; position:absolute }
 
        .container {
            height: 512px;
            width: 512px;
        }
<div class="container">
        <img src="https://image.prntscr.com/image/VmxphMVDQSu-OXXnHQm1Tg.png" alt="Sphere">
        <img src="https://image.prntscr.com/image/n0cbaO-4QVOk_PQ8ESQRqQ.png" alt="Cube">
    </div>
Sanjay Prajapati
  • 173
  • 2
  • 14
  • Thanks for your reply, but I am not trying move the image so they would mix, this is just a quick fix, but not a solution. Imagine if you would have more elements in the picture you would have to play with every one of them and at the end you won't get the same image as before – Pece Sep 15 '17 at 12:59
0

Unfortunately, there's no way of removing that gap without actually moving the elements around or modifying the actual images. However you, can fake it by applying a drop shadow to each of the images to hide it. Kind of like applying makeup to remove blemishes. This does add a slight blur on the edges of the images, though, so it's not a perfect solution.

img {
    position: absolute;
    left: 0px;
    top: 0px;
    filter: drop-shadow(0 0 1px #000);
}

.container {
    height: 512px;
    width: 512px;
}
<div class="container">
    <img src="https://image.prntscr.com/image/VmxphMVDQSu-OXXnHQm1Tg.png" alt="Sphere">
    <img src="https://image.prntscr.com/image/n0cbaO-4QVOk_PQ8ESQRqQ.png" alt="Cube">
</div>
Quangdao Nguyen
  • 1,122
  • 8
  • 22