Parse dynamic range for recipe

This commit is contained in:
Sam Becker 2025-02-18 23:22:27 -06:00
parent 8249e2929b
commit c9ffb96082
4 changed files with 52 additions and 11 deletions

View File

@ -15,6 +15,7 @@ import {
PRESERVE_ORIGINAL_UPLOADS,
} from '@/app/config';
import { isExifForFujifilm } from '@/platforms/fujifilm';
import { getFujifilmRecipeFromMakerNote } from '@/platforms/fujifilm/recipe';
const IMAGE_WIDTH_RESIZE = 200;
const IMAGE_WIDTH_BLUR = 200;
@ -78,6 +79,9 @@ export const extractImageDataFromBlobPath = async (
const makerNote = exifDataBinary.tags?.MakerNote;
if (Buffer.isBuffer(makerNote)) {
filmSimulation = getFujifilmSimulationFromMakerNote(makerNote);
console.log({
recipe: getFujifilmRecipeFromMakerNote(makerNote),
});
}
}

View File

@ -11,9 +11,6 @@ const BYTES_PER_TAG = 12;
const BYTE_OFFSET_TAG_TYPE = 2;
const BYTE_OFFSET_TAG_VALUE = 8;
export const TAG_ID_SATURATION = 0x1003;
export const TAG_ID_FILM_MODE = 0x1401;
export const isExifForFujifilm = (data: ExifData) =>
data.tags?.Make === MAKE_FUJIFILM;

View File

@ -1,20 +1,61 @@
import { parseFujifilmMakerNote } from '.';
// const TAG_ID_DYNAMIC_RANGE = 0x1400;
// const TAG_ID_DYNAMIC_RANGE_SETTING = 0x1402;
const TAG_ID_DEVELOPMENT_DYNAMIC_RANGE = 0x1403;
// const TAG_ID_AUTO_DYNAMIC_RANGE = 0x140b;
// const TAG_ID_HIGHLIGHT = 0x1041;
// const TAG_ID_SHADOW = 0x1040;
// const TAG_ID_COLOR = 0x1003;
// const TAG_ID_NOISE_REDUCTION = 0x100b;
// const TAG_ID_SHARPNESS = 0x1001;
// const TAG_ID_CLARITY = 0x100f;
// const TAG_ID_GRAIN_EFFECT_ROUGHNESS = 0x1047;
// const TAG_ID_GRAIN_EFFECT_SIZE = 0x104c;
// const TAG_ID_COLOR_CHROME_EFFECT = 0x1048;
// const TAG_ID_COLOR_CHROME_FX_BLUE = 0x104e;
// const TAG_ID_WHITE_BALANCE = 0x1002;
// const TAG_ID_WHITE_BALANCE_FINE_TUNE = 0x1003;
// TBD
// const TAG_ID_TONE = 0x1004;
// const TAG_ID_CONTRAST = 0x1006;
export interface FujifilmRecipe {
dynamicRange: number
highlight: number
shadow: number
color: number
noiseReduction: number
sharpening: number
sharpness: number
clarity: number
grainEffect: {
type: 'strong' | 'medium' | 'weak'
roughness: 'strong' | 'medium' | 'weak'
size: 'small' | 'large'
}
colorChromeEffect: 'strong' | 'medium' | 'weak'
colorChromeEffectBlue: 'off' | 'weak' | 'strong'
colorChromeFXBlue: 'off' | 'weak' | 'strong'
whiteBalance: {
type: string
red: number
blue: number
}
}
export const getFujifilmRecipeFromMakerNote = (
bytes: Buffer,
): Partial<FujifilmRecipe> => {
const recipe: Partial<FujifilmRecipe> = {};
parseFujifilmMakerNote(
bytes,
(tag, value) => {
switch (tag) {
case TAG_ID_DEVELOPMENT_DYNAMIC_RANGE:
recipe.dynamicRange = value;
break;
}
},
);
return recipe;
};

View File

@ -1,8 +1,7 @@
import {
TAG_ID_FILM_MODE,
parseFujifilmMakerNote,
TAG_ID_SATURATION,
} from '.';
import { parseFujifilmMakerNote } from '.';
const TAG_ID_SATURATION = 0x1003;
const TAG_ID_FILM_MODE = 0x1401;
type FujifilmSimulationFromSaturation =
'monochrome' |