grain.social is a photo sharing platform built on atproto. grain.social
atproto photography appview
50
fork

Configure Feed

Select the types of activity you want to include in your feed.

at f2930131d5335ecd8a8711c4d1b8701e8a692852 54 lines 1.3 kB view raw
1export const tags = [ 2 "DateTimeOriginal", 3 "ExposureTime", 4 "FNumber", 5 "Flash", 6 "FocalLengthIn35mmFormat", 7 "ISO", 8 "LensMake", 9 "LensModel", 10 "Make", 11 "Model", 12]; 13 14export const SCALE_FACTOR = 1000000; 15 16export type Exif = Record< 17 string, 18 number | string | boolean | Array<number | string> | undefined | Date 19>; 20 21export function normalizeExif( 22 exif: Exif, 23 scale: number = SCALE_FACTOR, 24): Exif { 25 const normalized: Record< 26 string, 27 number | string | boolean | Array<number | string> | undefined 28 > = {}; 29 30 for (const [key, value] of Object.entries(exif)) { 31 const camelKey = key[0].toLowerCase() + key.slice(1); 32 33 if (typeof value === "number") { 34 normalized[camelKey] = Math.round(value * scale); 35 } else if (Array.isArray(value)) { 36 normalized[camelKey] = value.map((v) => 37 typeof v === "number" ? Math.round(v * scale) : v 38 ); 39 } else if (value instanceof Date) { 40 normalized[camelKey] = value.toISOString(); 41 } else if (typeof value === "string") { 42 normalized[camelKey] = value; 43 } else if (typeof value === "boolean") { 44 normalized[camelKey] = value; 45 } else if (value === undefined) { 46 normalized[camelKey] = undefined; 47 } else { 48 // fallback for unknown types 49 normalized[camelKey] = String(value); 50 } 51 } 52 53 return normalized; 54}