Created
June 22, 2023 17:45
-
-
Save kibolho/f4ab69b76c559acae7013f569a3aa10b to your computer and use it in GitHub Desktop.
Generate Image from HTML
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import chrome from 'chrome-aws-lambda'; | |
| const chromeExecPaths = { | |
| win32: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', | |
| linux: '/usr/bin/google-chrome', | |
| darwin: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', | |
| }; | |
| const exePath = chromeExecPaths[process.platform]; | |
| interface Options { | |
| args: string[]; | |
| executablePath: string; | |
| headless: boolean; | |
| } | |
| export async function getOptions(isDev: boolean): Promise<Options> { | |
| let options: Options; | |
| if (isDev) { | |
| options = { | |
| args: [], | |
| executablePath: exePath, | |
| headless: true, | |
| }; | |
| } else { | |
| options = { | |
| args: chrome.args, | |
| executablePath: await chrome.executablePath, | |
| headless: chrome.headless, | |
| }; | |
| } | |
| return options; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import puppeteer, { Page } from 'puppeteer-core'; | |
| import chrome from 'chrome-aws-lambda'; | |
| let _page: Page | null; | |
| const chromeExecPaths = { | |
| win32: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', | |
| linux: '/usr/bin/google-chrome', | |
| darwin: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', | |
| }; | |
| const exePath = chromeExecPaths[process.platform]; | |
| interface Options { | |
| args: string[]; | |
| executablePath: string; | |
| headless: boolean; | |
| } | |
| export async function getOptions(isDev: boolean): Promise<Options> { | |
| let options: Options; | |
| if (isDev) { | |
| options = { | |
| args: [], | |
| executablePath: exePath, | |
| headless: true, | |
| }; | |
| } else { | |
| options = { | |
| args: chrome.args, | |
| executablePath: await chrome.executablePath, | |
| headless: chrome.headless, | |
| }; | |
| } | |
| return options; | |
| } | |
| async function getPage(isDev: boolean): Promise<Page> { | |
| if (_page) { | |
| return _page; | |
| } | |
| const options = await getOptions(isDev); | |
| const browser = await puppeteer.launch(options); | |
| _page = await browser.newPage(); | |
| return _page; | |
| } | |
| export async function getScreenshot( | |
| html: string, | |
| isDev: boolean | |
| ): Promise<Buffer | string> { | |
| const page = await getPage(isDev); | |
| await page.setViewport({ width: 1200, height: 630 }); | |
| await page.setContent(html); | |
| const file = await page.screenshot({ type: 'png' }); | |
| return file; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { NextApiRequest, NextApiResponse } from 'next'; | |
| import { getHtml } from './thumbnailTemplate'; | |
| import { getScreenshot } from './chromium'; | |
| const isDev = !process.env.AWS_REGION; | |
| const isHtmlDebug = process.env.OG_HTML_DEBUG === '1'; | |
| const async = async ( | |
| req: NextApiRequest, | |
| res: NextApiResponse | |
| ): Promise<any> => { | |
| try { | |
| const { query } = req; | |
| const title = String(query.title); | |
| const thumbnail_bg = String(query.thumbnail_bg); | |
| const image_avatar_url = String(query.image_avatar_url); | |
| const image_post_url = String(query.image_post_url); | |
| const avatar_name = String(query.avatar_name); | |
| const html = getHtml({ | |
| title, | |
| thumbnailBG: thumbnail_bg, | |
| avatarImg: image_avatar_url, | |
| postImg: image_post_url, | |
| avatarName: avatar_name, | |
| }); | |
| if (isHtmlDebug) { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.end(html); | |
| return; | |
| } | |
| const file = await getScreenshot(html, isDev); | |
| res.statusCode = 200; | |
| res.setHeader('Content-Type', `image/png`); | |
| res.setHeader( | |
| 'Cache-Control', | |
| 'public, immutable, no-transform, s-maxage=31536000, max-age=31536000' | |
| ); | |
| res.end(file); | |
| } catch (e) { | |
| res.statusCode = 500; | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.end( | |
| `<h1>Internal Error</h1><p>Sorry, there was a problem: ${e.message}</p>` | |
| ); | |
| } | |
| }; | |
| export default async; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| interface GetHtmlProps { | |
| title: string; | |
| thumbnailBG?: string; | |
| avatarImg?: string; | |
| postImg?: string; | |
| avatarName?: string; | |
| } | |
| export function getHtml({ | |
| title, | |
| thumbnailBG = '#8257e5', | |
| avatarImg = '', | |
| postImg = null, | |
| avatarName = 'Abílio Azevedo', | |
| }: GetHtmlProps) { | |
| return `<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charSet="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Thumbnail</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| margin: 0; | |
| font-family: Roboto, sans-serif; | |
| color: #FFF; | |
| background: ${thumbnailBG}; | |
| background-image: | |
| radial-gradient(circle at 25px 25px, rgba(255, 255, 255, 0.2) 2%, transparent 0%), | |
| radial-gradient(circle at 75px 75px, rgba(255, 255, 255, 0.2) 2%, transparent 0%); | |
| background-size: 100px 100px; | |
| height: 100vh; | |
| } | |
| #wrapper { | |
| width: 100%; | |
| height: 100%; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| text-align: center; | |
| } | |
| #wrapper-post-img { | |
| position: relative; | |
| max-height: 220px; | |
| width: 300px; | |
| margin-bottom: 30px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| overflow: hidden | |
| } | |
| #wrapper-post-img img { | |
| flex-shrink: 0; | |
| max-width: 100%; | |
| max-height: 100% | |
| } | |
| #wrapper-avatar-img { | |
| display: flex; | |
| flex-direction: row; | |
| } | |
| #wrapper-avatar-img img { | |
| border-radius: 50%; | |
| background-color: #e2e8f0; | |
| margin-right: 20px; | |
| width: 100px; | |
| height: 100px; | |
| } | |
| svg { | |
| height: 40px; | |
| margin-top: 80px; | |
| } | |
| h1 { | |
| font-size: 300%; | |
| line-height: 80px; | |
| max-width: 80%; | |
| } | |
| h2 { | |
| font-size: 32px; | |
| line-height: 40px; | |
| max-width: 80%; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="wrapper"> | |
| <h1>${title}</h1> | |
| <div id="wrapper-post-img"> | |
| <img | |
| id="image" | |
| src=${postImg} | |
| alt="post" | |
| /> | |
| </div> | |
| <div id="wrapper-avatar-img"> | |
| <img | |
| id="img" | |
| src=${avatarImg} | |
| alt="me" | |
| /> | |
| <h2>${avatarName}</h2> | |
| </div> | |
| <script> | |
| var image_x = document.getElementById("image"); | |
| if(${postImg}===undefined){ | |
| image_x.parentNode.removeChild(image_x); | |
| } | |
| </script> | |
| </body> | |
| </html>`; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment