From 381dd43263842d4c94333bc3445cc7abc24de6f7 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 21 Feb 2025 00:18:26 -0600 Subject: [PATCH] Create debug recipe photo overlay --- app/admin/recipe/page.tsx | 28 +++---- src/photo/PhotoRecipeFrost.tsx | 132 +++++++++++++++++++++++++++++++ src/photo/PhotoRecipeOverlay.tsx | 57 +++++++++++++ 3 files changed, 202 insertions(+), 15 deletions(-) create mode 100644 src/photo/PhotoRecipeFrost.tsx create mode 100644 src/photo/PhotoRecipeOverlay.tsx diff --git a/app/admin/recipe/page.tsx b/app/admin/recipe/page.tsx index 47889c51..cf1178a1 100644 --- a/app/admin/recipe/page.tsx +++ b/app/admin/recipe/page.tsx @@ -1,24 +1,22 @@ import SiteGrid from '@/components/SiteGrid'; import { getPhotos } from '@/photo/db/query'; -import PhotoRecipe from '@/photo/PhotoRecipe'; -import clsx from 'clsx/lite'; +import PhotoRecipeOverlay from '@/photo/PhotoRecipeOverlay'; export default async function AdminRecipePage() { - const photos = await getPhotos({ hidden: 'only' }); - const { fujifilmRecipe, filmSimulation } = photos[0]; + const photos = await getPhotos({ limit: 1}); + const photosHidden = await getPhotos({ hidden: 'only' }); + const { fujifilmRecipe, filmSimulation } = photosHidden[0]; return ( - {(fujifilmRecipe && filmSimulation) && - - } - } + contentMain={photos[0] && fujifilmRecipe && filmSimulation + ? + :
+ Can't find photo/recipe +
} /> ); } diff --git a/src/photo/PhotoRecipeFrost.tsx b/src/photo/PhotoRecipeFrost.tsx new file mode 100644 index 00000000..de059b09 --- /dev/null +++ b/src/photo/PhotoRecipeFrost.tsx @@ -0,0 +1,132 @@ +import { FujifilmRecipe } from '@/platforms/fujifilm/recipe'; +import { FilmSimulation } from '@/simulation'; +import PhotoFilmSimulation from '@/simulation/PhotoFilmSimulation'; +import clsx from 'clsx/lite'; + +const addSign = (value = 0) => value < 0 ? value : `+${value}`; + +export default function PhotoRecipe({ + recipe: { + dynamicRange, + whiteBalance, + highISONoiseReduction, + noiseReductionBasic, + highlight, + shadow, + color, + sharpness, + clarity, + colorChromeEffect, + colorChromeFXBlue, + grainEffect, + bwAdjustment, + bwMagentaGreen, + }, + simulation, +}: { + recipe: FujifilmRecipe + simulation: FilmSimulation +}) { + const whiteBalanceFormatted = (whiteBalance?.type ?? 'auto') + .replaceAll('auto', ' ') + .replaceAll('-', ' '); + + const hasCustomizedWhiteBalance = + Boolean(whiteBalance?.red) || + Boolean(whiteBalance?.blue); + + const hasBWAdjustments = + Boolean(bwAdjustment) || + Boolean(bwMagentaGreen); + + const renderDataSquare = (label: string, value: string | number = '0') => ( +
+
{typeof value === 'number' ? addSign(value) : value}
+
+ {label} +
+
+ ); + + return
+
+
+ +
+ DR + {dynamicRange ?? 100} +
+
+
+
+ {whiteBalanceFormatted.length <= 8 && 'AWB: '} + {whiteBalanceFormatted} + {hasCustomizedWhiteBalance && <> + {' '} + {'('} + R {addSign(whiteBalance?.red ?? 0)} + / + B {addSign(whiteBalance?.blue ?? 0)} + {')'} + } +
+
+ {renderDataSquare('Highlight', highlight)} + {renderDataSquare('Shadow', shadow)} +
+
+ {/* TODO: Confirm color vs saturation label */} + {renderDataSquare('Color', color)} + {renderDataSquare('Sharp', sharpness)} + {renderDataSquare('Clarity', clarity)} +
+
+ {renderDataSquare('Chrome', colorChromeEffect)} + {renderDataSquare('FX Blue', colorChromeFXBlue)} +
+
+ {highISONoiseReduction !== undefined + ? <> + High ISO NR: + {addSign(highISONoiseReduction)} + + : <> + Noise Reduction: + {noiseReductionBasic} + + } +
+ {grainEffect && +
+ Grain: + {' '} + {grainEffect.roughness} + {' / '} + {grainEffect.size} +
} + {hasBWAdjustments && +
+ BW Adjustment: {addSign(bwAdjustment)} + {' / '} + MG: {addSign(bwMagentaGreen)} +
} +
+
+
; +} diff --git a/src/photo/PhotoRecipeOverlay.tsx b/src/photo/PhotoRecipeOverlay.tsx new file mode 100644 index 00000000..281f6d2b --- /dev/null +++ b/src/photo/PhotoRecipeOverlay.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { FujifilmRecipe } from '@/platforms/fujifilm/recipe'; +import { FilmSimulation } from '@/simulation'; +import clsx from 'clsx/lite'; +import ImageLarge from '@/components/image/ImageLarge'; +import PhotoRecipeFrost from './PhotoRecipeFrost'; +import FieldSetWithStatus from '@/components/FieldSetWithStatus'; +import { useState } from 'react'; +import PhotoRecipe from './PhotoRecipe'; +export default function PhotoRecipeOverlay({ + backgroundImageUrl, + recipe, + simulation, +}: { + backgroundImageUrl: string + recipe: FujifilmRecipe + simulation: FilmSimulation +}) { + const [isFrosted, setIsFrosted] = useState(true); + + return ( +
+
+ setIsFrosted(!isFrosted)} + /> +
+
+ +
+ {isFrosted + ? : } +
+
+
+ ); +}