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 9f986b59469fc9a5af156e4d52d441a3dc88583e 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}