Refine recipe og image

This commit is contained in:
Sam Becker 2025-03-10 09:15:56 -05:00
parent 80dfad2fe1
commit 1697a83b95
13 changed files with 59 additions and 37 deletions

View File

@ -6,7 +6,7 @@ import {
import FilmSimulationImageResponse from
'@/image-response/FilmSimulationImageResponse';
import { FilmSimulation } from '@/simulation';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
@ -40,7 +40,7 @@ export async function GET(
headers,
] = await Promise.all([
getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_PER_CATEGORY, simulation }),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -3,7 +3,7 @@ import {
IMAGE_OG_DIMENSION_SMALL,
MAX_PHOTOS_TO_SHOW_PER_CATEGORY,
} from '@/image-response';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import FocalLengthImageResponse from
@ -42,7 +42,7 @@ export async function GET(
headers,
] = await Promise.all([
getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_PER_CATEGORY, focal }),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -4,7 +4,7 @@ import {
MAX_PHOTOS_TO_SHOW_OG,
} from '@/image-response';
import HomeImageResponse from '@/image-response/HomeImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { isNextImageReadyBasedOnPhotos } from '@/photo';
@ -19,7 +19,7 @@ export async function GET() {
] = await Promise.all([
getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_OG }).catch(() => []),
getImageResponseCacheControlHeaders(),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
]);
const { width, height } = IMAGE_OG_DIMENSION_SMALL;

View File

@ -1,7 +1,7 @@
import { getPhotoCached } from '@/photo/cache';
import { IMAGE_OG_DIMENSION } from '@/image-response';
import PhotoImageResponse from '@/image-response/PhotoImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import {
@ -34,7 +34,7 @@ export async function GET(
headers,
] = await Promise.all([
getPhotoCached(photoId),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -3,7 +3,7 @@ import {
IMAGE_OG_DIMENSION_SMALL,
MAX_PHOTOS_TO_SHOW_PER_CATEGORY,
} from '@/image-response';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
@ -38,7 +38,7 @@ export async function GET(
headers,
] = await Promise.all([
getPhotosCached({ recipe, limit: MAX_PHOTOS_TO_SHOW_PER_CATEGORY }),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -5,7 +5,7 @@ import {
MAX_PHOTOS_TO_SHOW_PER_CATEGORY,
} from '@/image-response';
import CameraImageResponse from '@/image-response/CameraImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
@ -42,7 +42,7 @@ export async function GET(
limit: MAX_PHOTOS_TO_SHOW_PER_CATEGORY,
camera: camera,
}),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -4,7 +4,7 @@ import {
MAX_PHOTOS_TO_SHOW_PER_CATEGORY,
} from '@/image-response';
import TagImageResponse from '@/image-response/TagImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
@ -38,7 +38,7 @@ export async function GET(
headers,
] = await Promise.all([
getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_PER_CATEGORY, tag }),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -5,7 +5,7 @@ import {
} from '@/image-response';
import TemplateImageResponse from
'@/image-response/TemplateImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { isNextImageReadyBasedOnPhotos } from '@/photo';
@ -20,7 +20,7 @@ export async function GET() {
sortBy: 'priority',
limit: MAX_PHOTOS_TO_SHOW_TEMPLATE_TIGHT,
}).catch(() => []),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -5,7 +5,7 @@ import {
} from '@/image-response';
import TemplateImageResponse from
'@/image-response/TemplateImageResponse';
import { getIBMPlexMonoMedium } from '@/app/font';
import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { isNextImageReadyBasedOnPhotos } from '@/photo';
@ -20,7 +20,7 @@ export async function GET() {
sortBy: 'priority',
limit: MAX_PHOTOS_TO_SHOW_TEMPLATE,
}).catch(() => []),
getIBMPlexMonoMedium(),
getIBMPlexMono(),
getImageResponseCacheControlHeaders(),
]);

View File

@ -3,18 +3,31 @@ import path from 'path';
import { cwd } from 'process';
const FONT_IBM_PLEX_MONO_FAMILY = 'IBMPlexMono';
const FONT_IBM_PLEX_MONO_PATH = '/public/fonts/IBMPlexMono-Medium.ttf';
const getFontData = async () =>
fs.readFileSync(path.join(cwd(), FONT_IBM_PLEX_MONO_PATH));
const FONT_IBM_PLEX_MONO_PATH_REGULAR = '/public/fonts/IBMPlexMono-Regular.ttf';
const FONT_IBM_PLEX_MONO_PATH_MEDIUM = '/public/fonts/IBMPlexMono-Medium.ttf';
export const getIBMPlexMonoMedium = () => getFontData()
.then(data => ({
const getFontData = async (fontPath: string) =>
fs.readFileSync(path.join(cwd(), fontPath));
export const getIBMPlexMono = async () => {
const [regular, medium] = await Promise.all([
getFontData(FONT_IBM_PLEX_MONO_PATH_REGULAR),
getFontData(FONT_IBM_PLEX_MONO_PATH_MEDIUM),
]);
return {
fontFamily: FONT_IBM_PLEX_MONO_FAMILY,
fonts: [{
name: FONT_IBM_PLEX_MONO_FAMILY,
data,
data: regular,
weight: 400,
style: 'normal',
} as const, {
name: FONT_IBM_PLEX_MONO_FAMILY,
data: medium,
weight: 500,
style: 'normal',
} as const],
}));
} as const,
],
};
};

View File

@ -15,12 +15,14 @@ export default function RecipeImageResponse({
width,
height,
fontFamily,
smallText = true,
}: {
recipe: string,
photos: Photo[]
width: NextImageSize
height: number
fontFamily: string
smallText?: boolean
}) {
const photo = getPhotoWithRecipeFromPhotos(photos);
@ -51,7 +53,7 @@ export default function RecipeImageResponse({
tw="flex absolute inset-0"
style={{
background:
'linear-gradient(to right, rgba(0, 0, 0, .5) 40%, transparent 75%)',
'linear-gradient(to right, rgba(0, 0, 0, .5) 30%, transparent 60%)',
}}
/>
<ImageCaption {...{
@ -71,12 +73,19 @@ export default function RecipeImageResponse({
}}>
{photo?.recipeData &&
<div
tw="opacity-60"
// tw="opacity-70"
style={{
display: 'flex',
flexDirection: 'column',
paddingTop: height * .03,
lineHeight: 1.22,
...smallText ? {
paddingTop: height * .03,
lineHeight: 1.45,
letterSpacing: '0.03em',
fontSize: height * .06,
} : {
paddingTop: height * .02,
opacity: 0.7,
},
}}
>
{recipeLines.map(text => (

View File

@ -33,6 +33,7 @@ export default function ImageCaption({
color: 'white',
backgroundBlendMode: 'multiply',
fontFamily,
fontWeight: 500,
fontSize: height *.08,
gap,
lineHeight: 1.2,

View File

@ -59,19 +59,18 @@ export const generateRecipeText = ({
simulation,
}: RecipeProps) => {
const lines = [
`${labelForFilmSimulation(simulation).large.toLocaleUpperCase()}`,
`${labelForFilmSimulation(simulation).small.toLocaleUpperCase()}`,
`DR${recipe.dynamicRange.development} NR${formatNoiseReduction(recipe)}`,
// eslint-disable-next-line max-len
`${formatWhiteBalance(recipe).toLocaleUpperCase()} ${formatWhiteBalanceColor(recipe)}`,
];
if (recipe.highlight || recipe.shadow) {
// eslint-disable-next-line max-len
lines.push(`HIGH/SHAD ${addSign(recipe.highlight)}/${addSign(recipe.shadow)}`);
lines.push(`HI/SH ${addSign(recipe.highlight)}/${addSign(recipe.shadow)}`);
}
// eslint-disable-next-line max-len
lines.push(`COL${addSign(recipe.color)} SHARP${addSign(recipe.sharpness)} CLAR${addSign(recipe.clarity)}`);
lines.push(`CO${addSign(recipe.color)} SH${addSign(recipe.sharpness)} CL${addSign(recipe.clarity)}`);
if (recipe.colorChromeEffect) {
lines.push(`CHROME ${recipe.colorChromeEffect.toLocaleUpperCase()}`);
@ -141,15 +140,15 @@ export const formatWhiteBalanceColor = ({
whiteBalance: { red, blue },
}: FujifilmRecipe) =>
(red || blue)
? `(R${addSign(red)}/B${addSign(blue)})`
? `R${addSign(red)}/B${addSign(blue)}`
: '';
export const formatGrain = ({ grainEffect }: FujifilmRecipe) =>
grainEffect.roughness === 'off'
? 'OFF'
: grainEffect.roughness === 'weak'
? `WEAK/${grainEffect.size.toLocaleUpperCase()}`
: `STRONG/${grainEffect.size.toLocaleUpperCase()}`;
? `WEAK/${grainEffect.size === 'small' ? 'SM' : 'LG'}`
: `STRONG/${grainEffect.size === 'small' ? 'SM' : 'LG'}`;
export const formatNoiseReduction = ({
highISONoiseReduction,