Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture an image of an HTML element, and maintain transparency?

I'm working on a page that will allow a webmaster to add styles to their twitter feed. Several of these styles use transparency in their display. I want to create a list of images for them to choose from. Currently I am taking screenshots on a checked background such as this:

enter image description here

But that isn't really what I want.

Is their some method of capturing an image of an HTML element, and maintaining the transparency?

EDIT: I'm just digging into this, so I'm coming across new topics, such as HTML5 Canvas, and -moz-element. Is it possible to set a canvas background to the html element using -moz-element, then extract the image data from the canvas? I'm going to try this unless someone who's 'been there done that' heads me off.

EDIT: The -moz-element and canvas was a deadend. -moz-element will set the item as a background, but will not allow you to save background image. And canvas doesn't save its background, even when the background is a normal image.

like image 237
BentFX Avatar asked Dec 13 '22 13:12

BentFX


2 Answers

It requires a little bit of work, but it is doable, as long as it's HTML you're laying out. You can't recover the transparency of markup in pages you've downloaded without saving those pages and editing them locally. By rendering the HTML elements multiple times, on different background colors, the opacity can be derived using an image editor. You're going to need a decent image editor, I use GIMP.

  1. Render the elements you want to save three times, on a black, a white and a neutral gray background(#888).

  2. Using a screen capture program, capture those displays and crop them to the exact same areas.

  3. In GIMP open those images as layers and order them black, white and gray, top to bottom.

  4. Set the top, black layer to difference mode. This will give a grayscale difference between the black and white layers.

  5. Merge down the top layer. This will leave us with two layers. The gray background layer and the grayscale difference. Invert the colors of the difference layer, and copy it to the clipboard.

  6. Add a layer mask to the gray background layer and paste the clipboard into the layer mask.

  7. Delete the grayscale layer and apply the layer mask on the gray background layer. That should leave one layer with opacity similar to the original.

  8. The opacity is off by a bit, but if we duplicate the layer and merge it with itself, it's right in the ballpark.

It's probably not pixel perfect, but it is proof of concept. Opacity of HTML markup can be captured.

DerivedOpacity.jpg

like image 146
BentFX Avatar answered Dec 28 '22 07:12

BentFX


Using Puppeteer makes this much easier to do. It runs a web-page in-memory.

Start a local fileserver - python -m SimpleHTTPServer 8080

Then this script should do the trick:

const puppeteer = require('puppeteer')

;(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('http://localhost:8080/index.html', {
    waitUntil: 'networkidle0'
  })
  const elements = await page.$('body')
  await page.evaluate(() => (document.body.style.background = 'transparent'))
  await elements.screenshot({ path: 'myImg.png', omitBackground: true })
  await browser.close()
})()

the docs for .screenshot() are here.

like image 20
spencercooly Avatar answered Dec 28 '22 08:12

spencercooly