Pece
Pece

Reputation: 637

Mix two .png images with alpha border with CSS

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.

Upvotes: 3

Views: 923

Answers (4)

Daniel Beck
Daniel Beck

Reputation: 21485

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...)

Upvotes: 3

Quangdao Nguyen
Quangdao Nguyen

Reputation: 1373

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>

Upvotes: 0

Sanjay Prajapati
Sanjay Prajapati

Reputation: 305

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>

Upvotes: 0

ab29007
ab29007

Reputation: 7766

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>

Upvotes: 0

Related Questions