Skip to content
This repository has been archived by the owner on Jan 21, 2023. It is now read-only.

Commit

Permalink
feat: basic generation
Browse files Browse the repository at this point in the history
  • Loading branch information
Qu4k committed Aug 22, 2020
1 parent 9304f7c commit e99c9e6
Show file tree
Hide file tree
Showing 18 changed files with 340 additions and 524 deletions.
1 change: 0 additions & 1 deletion .github/CODEOWNERS

This file was deleted.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ To start hacking, do the following:
1. Clone this repo with `git clone https://github.com/vercel/og-image`
2. Change directory with `cd og-image`
3. Run `yarn` or `npm install` to install all dependencies
4. Run locally with `vercel dev` and visit [localhost:3000](https://localhost:3000) (if nothing happens, run `npm install -g vercel`)
4. Run locally with `vercel dev` and visit [localhost:3000](https://localhost:3000) (if nothing happens, run `npm install -g vercel`)
5. If necessary, edit the `exePath` in [options.ts](https://github.com/vercel/og-image/blob/main/api/_lib/options.ts) to point to your local Chrome executable

Now you're ready to start local development!
Expand Down
82 changes: 17 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,24 @@
<a href="https://vercel.com/new/project?template=vercel/og-image"><img width="128" src="https://vercel.com/button" align="right"></a>
<div align="center">
<h1><code>deps.og</code></h1>

# [Open Graph Image as a Service](https://og-image.vercel.app)
<p>
<strong>Serverless service that generates dynamic Open Graph images that you can embed in your <code>&lt;meta&gt;</code> tags.
</strong>
</p>

<a href="https://twitter.com/vercel">
<img align="right" src="https://og-image.vercel.app/tweet.png" height="300" />
</a>
<sub>Modified with 🕸 by <a href="https://denosaurs.land/">The Denosaurs Team</a></sub>

Serverless service that generates dynamic Open Graph images that you can embed in your `<meta>` tags.
</div>

For each keystroke, headless chromium is used to render an HTML page and take a screenshot of the result which gets cached.

See the image embedded in the tweet for a real use case.


## What is an Open Graph Image?

Have you ever posted a hyperlink to Twitter, Facebook, or Slack and seen an image popup?
How did your social network know how to "unfurl" the URL and get an image?
The answer is in your `<head>`.

The [Open Graph protocol](https://ogp.me) says you can put a `<meta>` tag in the `<head>` of a webpage to define this image.

It looks like the following:

```html
<head>
<title>Title</title>
<meta property="og:image" content="https://example.com/logo.jpg" />
</head>
```

## Why use this service?

The short answer is that it would take a long time to painstakingly design an image for every single blog post and every single documentation page. And we don't want the exact same image for every blog post because that wouldn't make the article stand out when it was shared to Twitter.

That's where `og-image.vercel.app` comes in. We can simply pass the title of our blog post to our generator service and it will generate the image for us on the fly!

It looks like the following:

```html
<head>
<title>Hello World</title>
<meta property="og:image" content="https://og-image.vercel.app/Hello%20World.png" />
</head>
```

Now try changing the text `Hello%20World` to the title of your choosing and watch the magic happen ✨

## Deploy your own

You'll want to fork this repository and deploy your own image generator.

1. Click the fork button at the top right of GitHub
2. Clone the repo to your local machine with `git clone URL_OF_FORKED_REPO_HERE`
3. Change directory with `cd og-image`
4. Make changes by swapping out images, changing colors, etc (see [contributing](https://github.com/vercel/og-image/blob/main/CONTRIBUTING.md) for more info)
5. Hobby plan users will need to remove all configuration inside `vercel.json` besides `rewrites`
6. Run locally with `vercel dev` and visit [localhost:3000](https://localhost:3000) (if nothing happens, run `npm install -g vercel`)
7. Deploy to the cloud by running `vercel` and you'll get a unique URL
8. Setup [GitHub](https://vercel.com/github) to autodeploy on push

If you are using a paid plan, you can do a one-click deploy with the button below.

[![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/new/project?template=vercel/og-image)

Once you have an image generator that sparks joy, you can setup [automatic GitHub](https://vercel.com/github) deployments so that pushing to master will deploy to production! 🚀

## Authors
## Original Authors

- Steven ([@styfle](https://twitter.com/styfle)) - [Vercel](https://vercel.com)
- Evil Rabbit ([@evilrabbit](https://twitter.com/evilrabbit_)) - [Vercel](https://vercel.com)

---

<p align="center">
<a href="https://vercel.com?utm_source=deps">
<img src="https://deps.land/images/vercel/powered_by_vercel.jpg" alt="Powered by Vercel" width="200">
</a>
</p>
124 changes: 0 additions & 124 deletions api/_fonts/Vera-License.txt

This file was deleted.

Binary file removed api/_fonts/Vera-Mono.woff2
Binary file not shown.
34 changes: 19 additions & 15 deletions api/_lib/chromium.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import { launch, Page } from 'puppeteer-core';
import { getOptions } from './options';
import { FileType } from './types';
import { launch, Page } from "puppeteer-core";
import { getOptions } from "./options";
import { FileType } from "./types";
let _page: Page | null;

async function getPage(isDev: boolean) {
if (_page) {
return _page;
}
const options = await getOptions(isDev);
const browser = await launch(options);
_page = await browser.newPage();
if (_page) {
return _page;
}
const options = await getOptions(isDev);
const browser = await launch(options);
_page = await browser.newPage();
return _page;
}

export async function getScreenshot(html: string, type: FileType, isDev: boolean) {
const page = await getPage(isDev);
await page.setViewport({ width: 2048, height: 1170 });
await page.setContent(html);
const file = await page.screenshot({ type });
return file;
export async function getScreenshot(
html: string,
type: FileType,
isDev: boolean
) {
const page = await getPage(isDev);
await page.setViewport({ width: 2048, height: 1170 });
await page.setContent(html);
const file = await page.screenshot({ type });
return file;
}
49 changes: 25 additions & 24 deletions api/_lib/options.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import chrome from 'chrome-aws-lambda';
const exePath = process.platform === 'win32'
? 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
: process.platform === 'linux'
? '/usr/bin/google-chrome'
: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
import chrome from "chrome-aws-lambda";
const exePath =
process.platform === "win32"
? "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
: process.platform === "linux"
? "/usr/bin/google-chrome"
: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";

interface Options {
args: string[];
executablePath: string;
headless: boolean;
args: string[];
executablePath: string;
headless: boolean;
}

export async function getOptions(isDev: boolean) {
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;
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;
}
21 changes: 8 additions & 13 deletions api/_lib/parser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IncomingMessage } from "http";
import { parse } from "url";
import { ParsedRequest, Theme } from "./types";
import { ParsedRequest } from "./types";

export function parseRequest(req: IncomingMessage) {
console.log("HTTP " + req.url);
Expand Down Expand Up @@ -31,13 +31,10 @@ export function parseRequest(req: IncomingMessage) {
text: decodeURIComponent(text),
theme: theme === "dark" ? "dark" : "light",
md: md === "1" || md === "true",
fontSize: fontSize || "100px",
fontSize: fontSize || "200px",
images: getArray(images),
};
parsedRequest.images = getDefaultImages(
parsedRequest.images,
parsedRequest.theme,
);
parsedRequest.images = getDefaultImages(parsedRequest.images);
return parsedRequest;
}

Expand All @@ -51,22 +48,20 @@ function getArray(stringOrArray: string[] | string | undefined): string[] {
}
}

function getDefaultImages(images: string[], theme: Theme): string[] {
const defaultImage = theme === "light"
? "https://nest.land/images/nest.land/logo_light.svg"
: "https://nest.land/images/nest.land/logo_dark.svg";
function getDefaultImages(images: string[]): string[] {
const defaultImage = "https://deps.land/logo.svg";

if (!images || !images[0]) {
return [defaultImage];
}
if (
!images[0].startsWith("https://assets.vercel.com/") &&
!images[0].startsWith("https://nest.land/")
!images[0].startsWith("https://deps.land/")
) {
images.unshift(defaultImage);
}
if (images[0] == "nestDefault") {
if (images[0] == "default") {
images.unshift(defaultImage);
}
return images;
}
}
17 changes: 8 additions & 9 deletions api/_lib/sanitizer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
const entityMap: { [key: string]: string } = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": '&#39;',
"/": '&#x2F;'
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;",
"/": "&#x2F;",
};

export function sanitizeHtml(html: string) {
return String(html).replace(/[&<>"'\/]/g, key => entityMap[key]);
export function sanitize(html: string) {
return String(html).replace(/[&<>"'\/]/g, (key) => entityMap[key]);
}

Loading

0 comments on commit e99c9e6

Please sign in to comment.