Skip to content

Commit

Permalink
fix: solve OG image generation
Browse files Browse the repository at this point in the history
  • Loading branch information
ElianCodes committed Aug 9, 2023
1 parent ad2c65f commit bdcfe8c
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 31 deletions.
5 changes: 5 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ export default defineConfig({
: 'https://localhost:3000/',
trailingSlash: 'ignore',
integrations: [sitemap(), UnoCSS({ injectReset: true })],
vite: {
optimizeDeps: {
exclude: ['@resvg/resvg-js'],
},
},
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"devDependencies": {
"@iconify-json/logos": "^1.1.34",
"@iconify-json/uil": "^1.1.5",
"@resvg/resvg-js": "^2.4.1",
"@typescript-eslint/parser": "^6.3.0",
"@unocss/reset": "^0.54.3",
"eslint": "^8.46.0",
Expand Down
129 changes: 129 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/components/layout/BaseHead.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props {
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
if (Astro.props.ogImage === undefined) {
Astro.props.ogImage = new URL('/v1/generate/og/default.svg', Astro.url);
Astro.props.ogImage = new URL('/v1/generate/og/default.png', Astro.url);
}
const { title, description, ogImage } = Astro.props;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Resvg, ResvgRenderOptions } from '@resvg/resvg-js';
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';
import satori from 'satori';
import { html as toReactElement } from 'satori-html';
import { Config } from '@eliancodes/brutal-ui';

const fontFile = await fetch(
'https://og-playground.vercel.app/inter-latin-ext-700-normal.woff'
Expand All @@ -17,26 +17,26 @@ const posts = await getCollection('blog');
export function getStaticPaths() {
return posts.map((post) => ({
params: { slug: post.slug },
props: { title: post.data.title },
props: { title: post.data.title, description: post.data.description },
}));
}

export const get: APIRoute = async ({ params, props }) => {
const bgColor =
Config.colors[Math.floor(Math.random() * Config.colors.length)];
const title = props.title ?? 'Brutal, a theme for Astro.';
const link = params.slug ?? 'https://brutal.elian.codes';

const title = props.title.trim() ?? 'Blogpost';
const description = props.description ?? null;
const html = toReactElement(`
<div style="background-color: ${bgColor}; display: flex; flex-direction: column; height: 100%; padding: 3rem; width: 100%">
<div style="background-color: white; display: flex; flex-direction: column; height: 100%; padding: 3rem; width: 100%">
<div style="display:flex; height: 100%; width: 100%; background-color: white; border: 6px solid black; border-radius: 0.5rem; padding: 2rem; filter: drop-shadow(6px 6px 0 rgb(0 0 0 / 1));">
<div style="display: flex; flex-direction: column; justify-content: space-between; gap: 2rem; width: 100%; filter: drop-shadow()">
<div style="display: flex;">
<p style="font-size: 48px;">${title}</p>
<div style="display: flex; flex-direction: column; justify-content: space-between; width: 100%; filter: drop-shadow()">
<div style="display: flex; justify-content: space-between;">
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
<p style="font-size: 48px;">Brutal theme for Astro</p>
<p style="font-size: 38px;">${title}</p>
</div>
<img src="https://www.elian.codes/assets/img/elian.jpg" width="200px" height="200px" style="border: 3px solid black; border-radius: 0.5rem;" />
</div>
<div style="display: flex; justify-content: space-between; align-items: baseline">
<p style="font-size: 32px">${link}</p>
<img src="https://www.elian.codes/_astro/elian_ZJca6K.jpg" width="200px" height="200px" style="border: 3px solid black; border-radius: 0.5rem;" />
<div style="display: flex;">
<p style="font-size: 24px;">${description}</p>
</div>
</div>
</div>
Expand All @@ -55,9 +55,19 @@ export const get: APIRoute = async ({ params, props }) => {
width,
});

return new Response(svg, {
const opts: ResvgRenderOptions = {
fitTo: {
mode: 'width', // If you need to change the size
value: width,
},
};
const resvg = new Resvg(svg, opts);
const pngData = resvg.render();
const pngBuffer = pngData.asPng();

return new Response(pngBuffer, {
headers: {
'content-type': 'image/svg',
'content-type': 'image/png',
},
});
};
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { Resvg, ResvgRenderOptions } from '@resvg/resvg-js';
import type { APIRoute } from 'astro';
import satori from 'satori';
import { html as toReactElement } from 'satori-html';
import { Config } from '@eliancodes/brutal-ui';

const fontFile = await fetch(
'https://og-playground.vercel.app/inter-latin-ext-700-normal.woff'
);

const fontData: ArrayBuffer = await fontFile.arrayBuffer();

const height = 630;
const width = 1200;

export const get: APIRoute = async () => {
const bgColor =
Config.colors[Math.floor(Math.random() * Config.colors.length)];
// console.log(request);
const title = 'Brutal, a theme for Astro.';
const link = 'https://brutal.elian.codes';

const html = toReactElement(`
<div style="background-color: ${bgColor}; display: flex; flex-direction: column; height: 100%; padding: 3rem; width: 100%">
<div style="background-color: white; display: flex; flex-direction: column; height: 100%; padding: 3rem; width: 100%">
<div style="display:flex; height: 100%; width: 100%; background-color: white; border: 6px solid black; border-radius: 0.5rem; padding: 2rem; filter: drop-shadow(6px 6px 0 rgb(0 0 0 / 1));">
<div style="display: flex; flex-direction: column; justify-content: space-between; gap: 2rem; width: 100%; filter: drop-shadow()">
<div style="display: flex;">
<p style="font-size: 48px;">${title}</p>
<div style="display: flex; flex-direction: column; justify-content: space-between; width: 100%; filter: drop-shadow()">
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
<p style="font-size: 48px;">Brutal</p>
<p style="font-size: 38px;">A theme for Astro</p>
<p style="font-size: 38px;">Brought to you by Elian</p>
</div>
<div style="display: flex; justify-content: space-between; align-items: baseline">
<div style="display: flex; justify-content: space-between; align-items: baseline; padding-top: -2rem;">
<p style="font-size: 32px">${link}</p>
<img src="https://www.elian.codes/_astro/elian_ZJca6K.jpg" width="200px" height="200px" style="border: 3px solid black; border-radius: 0.5rem;" />
<img src="https://www.elian.codes/assets/img/elian.jpg" width="200px" height="200px" style="border: 3px solid black; border-radius: 0.5rem;" />
</div>
</div>
</div>
Expand All @@ -42,13 +40,24 @@ export const get: APIRoute = async () => {
style: 'normal',
},
],

height,
width,
});

return new Response(svg, {
const opts: ResvgRenderOptions = {
fitTo: {
mode: 'width',
value: width,
},
};
const resvg = new Resvg(svg, opts);
const pngData = resvg.render();
const pngBuffer = pngData.asPng();

return new Response(pngBuffer, {
headers: {
'content-type': 'image/svg',
'content-type': 'image/png',
},
});
};

1 comment on commit bdcfe8c

@vercel
Copy link

@vercel vercel bot commented on bdcfe8c Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.