diff --git a/ui/package-lock.json b/ui/package-lock.json index 3293b21652d276580c78897ee00c0d25a22ae4d0..eb0ce5cee7e783ecb44d18b2f9243a9b4082bcc8 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -16,6 +16,7 @@ "@types/node": "^12.20.17", "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", + "mdi-material-ui": "^6.22.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-query": "^3.19.1", @@ -13581,6 +13582,15 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/mdi-material-ui": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-6.22.1.tgz", + "integrity": "sha512-wndaFXJhoFr9g5kPw31TZajTa9uf/21jb2jD1rJ5Vi+sj2GZYnZz2BYbrfp1qFgd7tZz8XAcnpsSNMdLbe+dtw==", + "peerDependencies": { + "@material-ui/core": "^4.0.0", + "react": "^16.8.0 || ^17.0.0" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -32318,6 +32328,12 @@ "safe-buffer": "^5.1.2" } }, + "mdi-material-ui": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-6.22.1.tgz", + "integrity": "sha512-wndaFXJhoFr9g5kPw31TZajTa9uf/21jb2jD1rJ5Vi+sj2GZYnZz2BYbrfp1qFgd7tZz8XAcnpsSNMdLbe+dtw==", + "requires": {} + }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", diff --git a/ui/package.json b/ui/package.json index 9f137687b4282c981bb2b661f0da172132165543..efbbf5d273e22be2afb0b5ea3875684d77f361ad 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,6 +12,7 @@ "@types/node": "^12.20.17", "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", + "mdi-material-ui": "^6.22.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-query": "^3.19.1", diff --git a/ui/src/components/ImageView.tsx b/ui/src/components/ImageView.tsx index 9d57bc6f32a9ed88c09cbf0fc444a8aaddb44ee7..cf98f573538874b3c82d40c494dfa263ee117447 100644 --- a/ui/src/components/ImageView.tsx +++ b/ui/src/components/ImageView.tsx @@ -1,5 +1,5 @@ import {Image} from "../api/model/Image"; -import React, {useMemo, useState} from "react"; +import React, {Fragment, useMemo, useState} from "react"; import {useUpdateImage} from "../api/useUpdateImage"; import {useDeleteImage} from "../api/useDeleteImage"; import {parseMetadata, ratioToTime} from "../metadata/ImageMetadata"; @@ -13,6 +13,9 @@ import {SceneMode} from "../metadata/SceneMode"; import {ContrastProcessing} from "../metadata/ContrastProcessing"; import {SharpnessProcessing} from "../metadata/SharpnessProcessing"; import {SubjectDistanceRange} from "../metadata/SubjectDistanceRange"; +import {BrightnessMedium, Camera, Copyright, Event, Exposure, PhotoCamera, ZoomIn} from "@material-ui/icons"; +import {AngleAcute, ArrowExpandHorizontal, Blur, CameraTimer, Flash, WhiteBalanceIncandescent} from "mdi-material-ui"; +import {FlashMode} from "../metadata/FlashMode"; export interface ImageProps { image: Image @@ -61,39 +64,92 @@ export default function ImageView({image}: ImageProps) { <p>{image.updated_at}</p> <p>{image.state}</p> <h3>Metadata</h3> - <p><b>Make</b>: {metadata.make}</p> - <p><b>Model</b>: {metadata.model}</p> - <p><b>Software</b>: {metadata.software}</p> - <p><b>Copyright</b>: {metadata.copyright}</p> - <p><b>DateTime Created</b>: {metadata.dateTimeCreated?.toISOString()}</p> - <p><b>DateTime Digitized</b>: {metadata.dateTimeDigitized?.toISOString()}</p> - <p><b>DateTime Original</b>: {metadata.dateTimeOriginal?.toISOString()}</p> - <p><b>Digital Zoom</b>: {ratioToFloat(metadata.digitalZoomRatio)}</p> - <p><b>Exposure</b>: {ratioToFloat(metadata.exposure)}</p> - <p><b>Exposure Mode</b>: {metadata.exposureMode !== undefined ? - ExposureMode[metadata.exposureMode] : "null"}</p> - <p><b>Exposure Program</b>: {metadata.exposureProgram !== undefined ? - ExposureProgram[metadata.exposureProgram] : "null"}</p> - <p><b>Exposure Time</b>: {ratioToTime(metadata.exposureTime)}</p> - <p><b>Aperture</b>: {ratioToFloat(metadata.aperture)}</p> - <p><b>Focal Length</b>: {ratioToFloat(metadata.focalLength)}</p> - <p><b>Focal Length (35mm equivalent)</b>: {ratioToFloat(metadata.focalLength35mm)}</p> - <p><b>ISO</b>: {metadata.isoSpeedRating}</p> - <p><b>Light source</b>: {metadata.lightSource !== undefined ? - LightSource[metadata.lightSource] : "null"}</p> - <p><b>Metering mode</b>: {metadata.meteringMode !== undefined ? - MeteringMode[metadata.meteringMode] : "null"}</p> - <p><b>White balance</b>: {metadata.whiteBalance !== undefined ? - WhiteBalance[metadata.whiteBalance] : "null"}</p> - <p><b>Scene Mode</b>: {metadata.sceneMode !== undefined ? - SceneMode[metadata.sceneMode] : "null"}</p> - <p><b>Contrast Processing</b>: {metadata.contrast !== undefined ? - ContrastProcessing[metadata.contrast] : "null"}</p> - <p><b>Sharpness Processing</b>: {metadata.sharpness !== undefined ? - SharpnessProcessing[metadata.sharpness] : "null"}</p> - <p><b>Subject Distance</b>: {metadata.subjectDistance}</p> - <p><b>Subject Distance Range</b>: {metadata.subjectDistanceRange !== undefined ? - SubjectDistanceRange[metadata.subjectDistanceRange] : "null"}</p> + {metadata.make !== undefined && ( + <p><b>Make</b>: {metadata.make}</p> + )} + {metadata.model !== undefined && ( + <p><PhotoCamera/><b>Model</b>: {metadata.model}</p> + )} + {metadata.software !== undefined && ( + <p><b>Software</b>: {metadata.software}</p> + )} + {metadata.copyright !== undefined && ( + <p><Copyright/><b>Copyright</b>: {metadata.copyright}</p> + )} + {metadata.dateTimeCreated !== undefined && ( + <p><Event/><b>DateTime Created</b>: {metadata.dateTimeCreated?.toISOString()}</p> + )} + {metadata.dateTimeDigitized !== undefined && ( + <p><Event/><b>DateTime Digitized</b>: {metadata.dateTimeDigitized?.toISOString()}</p> + )} + {metadata.dateTimeOriginal !== undefined && ( + <p><Event/><b>DateTime Original</b>: {metadata.dateTimeOriginal?.toISOString()}</p> + )} + {metadata.digitalZoomRatio !== undefined && ( + <p><ZoomIn/><b>Digital Zoom</b>: {ratioToFloat(metadata.digitalZoomRatio)}</p> + )} + {metadata.exposure !== undefined && ( + <p><Exposure/><b>Exposure</b>: {ratioToFloat(metadata.exposure)}</p> + )} + {metadata.exposureMode !== undefined && ( + <p><Exposure/><b>Exposure Mode</b>: {ExposureMode[metadata.exposureMode]}</p> + )} + {metadata.exposureProgram !== undefined && ( + <p><Exposure/><b>Exposure Program</b>: {ExposureProgram[metadata.exposureProgram]}</p> + )} + {metadata.shutterSpeed !== undefined && ( + <p><CameraTimer/><b>Shutter Speed</b>: {ratioToTime(metadata.shutterSpeed)}</p> + )} + {metadata.aperture !== undefined && ( + <p><Camera/><b>Aperture</b>: {ratioToFloat(metadata.aperture)}</p> + )} + {metadata.focalLength !== undefined && ( + <p><AngleAcute/><b>Focal Length</b>: {ratioToFloat(metadata.focalLength)}mm</p> + )} + {metadata.focalLength35mm !== undefined && ( + <p><AngleAcute/><b>Focal Length (35mm equivalent)</b>: {ratioToFloat(metadata.focalLength35mm)}mm</p> + )} + {metadata.isoSpeedRating !== undefined && ( + <p><b>ISO</b>: {metadata.isoSpeedRating}</p> + )} + {metadata.flash !== undefined && ( + <Fragment> + <p><Flash/><b>Flash</b></p> + <p><b>Available</b>: {metadata.flash.available ? "Yes" : "No"}</p> + <p><b>Fired</b>: {metadata.flash.fired ? "Yes" : "No"}</p> + <p><b>Red Eye Reduction</b>: {metadata.flash.redEyeReduction ? "Yes" : "No"}</p> + <p><b>Strobe Detection Available</b>: {metadata.flash.strobeDetection.available ? "Yes" : "No"}</p> + <p><b>Strobe Detection Used</b>: {metadata.flash.strobeDetection.detected ? "Yes" : "No"}</p> + {metadata.flash.mode !== undefined && ( + <p><b>Flash Mode</b>: {FlashMode[metadata.flash.mode]}</p> + )} + </Fragment> + )} + {metadata.lightSource !== undefined && ( + <p><WhiteBalanceIncandescent/><b>Light source</b>: {LightSource[metadata.lightSource]}</p> + )} + {metadata.meteringMode !== undefined && ( + <p><b>Metering mode</b>: {MeteringMode[metadata.meteringMode]}</p> + )} + {metadata.whiteBalance !== undefined && ( + <p><WhiteBalanceIncandescent/><b>White balance</b>: {WhiteBalance[metadata.whiteBalance]}</p> + )} + {metadata.sceneMode !== undefined && ( + <p><b>Scene Mode</b>: {SceneMode[metadata.sceneMode]}</p> + )} + {metadata.contrast !== undefined && ( + <p><BrightnessMedium/><b>Contrast Processing</b>: {ContrastProcessing[metadata.contrast]}</p> + )} + {metadata.sharpness !== undefined && ( + <p><Blur/><b>Sharpness Processing</b>: {SharpnessProcessing[metadata.sharpness]}</p> + )} + {metadata.subjectDistance !== undefined && ( + <p><ArrowExpandHorizontal/><b>Subject Distance</b>: {metadata.subjectDistance}</p> + )} + {metadata.subjectDistanceRange !== undefined && ( + <p><ArrowExpandHorizontal/><b>Subject Distance + Range</b>: {SubjectDistanceRange[metadata.subjectDistanceRange]}</p> + )} <img src={image.url + "t"} alt=""/> <br/> <input diff --git a/ui/src/metadata/ContrastProcessing.ts b/ui/src/metadata/ContrastProcessing.ts index 91405fb701cdbb9500ba8a3fb38df3edd87330b3..01b2e15092ad24b897c4b70692822a01090e5a68 100644 --- a/ui/src/metadata/ContrastProcessing.ts +++ b/ui/src/metadata/ContrastProcessing.ts @@ -1,5 +1,18 @@ +import {parseNumber} from "./ImageMetadata"; + export enum ContrastProcessing { NORMAL = 0, SOFT = 1, HARD = 2, } + +export function parseContrastProcessing(value: string | undefined): ContrastProcessing | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(ContrastProcessing).includes(numericValue)) { + return numericValue as ContrastProcessing; + } + return undefined; +} diff --git a/ui/src/metadata/ExposureMode.ts b/ui/src/metadata/ExposureMode.ts index 2518b99022f968eb336e1d0cf0dfb4c2c82b1508..ce81dd4bc182710b861506749275ba9cedbb2933 100644 --- a/ui/src/metadata/ExposureMode.ts +++ b/ui/src/metadata/ExposureMode.ts @@ -1,5 +1,18 @@ +import {parseNumber} from "./ImageMetadata"; + export enum ExposureMode { AUTO = 0, MANUAL = 1, BRACKET = 2, } + +export function parseExposureMode(value: string | undefined): ExposureMode | undefined { + const numericValue = parseNumber(value) + if (numericValue === undefined) { + return undefined; + } + if (Object.values(ExposureMode).includes(numericValue)) { + return numericValue as ExposureMode; + } + return undefined; +} diff --git a/ui/src/metadata/ExposureProgram.ts b/ui/src/metadata/ExposureProgram.ts index c0569270344e88f9fa4b204b4dff1aa690613529..8d5528d194cbad3779208059c7a64a0d571213b2 100644 --- a/ui/src/metadata/ExposureProgram.ts +++ b/ui/src/metadata/ExposureProgram.ts @@ -1,3 +1,5 @@ +import {parseNumber} from "./ImageMetadata"; + export enum ExposureProgram { MANUAL = 1, NORMAL = 2, @@ -8,3 +10,14 @@ export enum ExposureProgram { PORTRAIT = 7, LANDSCAPE = 8, } + +export function parseExposureProgram(value: string | undefined): ExposureProgram | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(ExposureProgram).includes(numericValue)) { + return numericValue as ExposureProgram; + } + return undefined; +} diff --git a/ui/src/metadata/Flash.test.tsx b/ui/src/metadata/Flash.test.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d561d69e8950a57c7b55ad3e215de92e1f5f181f --- /dev/null +++ b/ui/src/metadata/Flash.test.tsx @@ -0,0 +1,291 @@ +import {parseFlash} from "./Flash"; +import {FlashMode} from "./FlashMode"; + +describe("parseFlash", () => { + test("Flash did not fire", () => { + expect(parseFlash(0x00.toString(), undefined)).toStrictEqual({ + available: true, + fired: false, + strobeDetection: { + available: false, + detected: false, + }, + mode: undefined, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired", () => { + expect(parseFlash(0x01.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: undefined, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Strobe return light not detected", () => { + expect(parseFlash(0x05.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: undefined, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Strobe return light detected", () => { + expect(parseFlash(0x07.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: undefined, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode", () => { + expect(parseFlash(0x09.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode, return light not detected", () => { + expect(parseFlash(0x0D.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode, return light detected", () => { + expect(parseFlash(0x0F.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash did not fire, compulsory flash mode", () => { + expect(parseFlash(0x10.toString(), undefined)).toStrictEqual({ + available: true, + fired: false, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.ALWAYS_OFF, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash did not fire, auto mode", () => { + expect(parseFlash(0x18.toString(), undefined)).toStrictEqual({ + available: true, + fired: false, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.AUTO, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, auto mode", () => { + expect(parseFlash(0x19.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.AUTO, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, auto mode, return light not detected", () => { + expect(parseFlash(0x1D.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: FlashMode.AUTO, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, auto mode, return light detected", () => { + expect(parseFlash(0x1F.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: FlashMode.AUTO, + redEyeReduction: false, + strength: undefined, + }) + }) + test("No flash function", () => { + expect(parseFlash(0x20.toString(), undefined)).toStrictEqual({ + available: false, + fired: false, + strobeDetection: { + available: false, + detected: false, + }, + mode: undefined, + redEyeReduction: false, + strength: undefined, + }) + }) + test("Flash fired, red-eye reduction mode", () => { + expect(parseFlash(0x41.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: undefined, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, red-eye reduction mode, return light not detected", () => { + expect(parseFlash(0x45.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: undefined, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, red-eye reduction mode, return light detected", () => { + expect(parseFlash(0x47.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: undefined, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode, red-eye reduction mode", () => { + expect(parseFlash(0x49.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", () => { + expect(parseFlash(0x4D.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", () => { + expect(parseFlash(0x4F.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: FlashMode.ALWAYS_ON, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, auto mode, red-eye reduction mode", () => { + expect(parseFlash(0x59.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: false, + detected: false, + }, + mode: FlashMode.AUTO, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, auto mode, return light not detected, red-eye reduction mode", () => { + expect(parseFlash(0x5D.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: false, + }, + mode: FlashMode.AUTO, + redEyeReduction: true, + strength: undefined, + }) + }) + test("Flash fired, auto mode, return light detected, red-eye reduction mode", () => { + expect(parseFlash(0x5F.toString(), undefined)).toStrictEqual({ + available: true, + fired: true, + strobeDetection: { + available: true, + detected: true, + }, + mode: FlashMode.AUTO, + redEyeReduction: true, + strength: undefined, + }) + }) +}) diff --git a/ui/src/metadata/Flash.ts b/ui/src/metadata/Flash.ts index 2a966779caefecf93428f0b2bd6883a630d0eb49..e122ce0923a07fd73401dda54360308e48790c57 100644 --- a/ui/src/metadata/Flash.ts +++ b/ui/src/metadata/Flash.ts @@ -1,4 +1,6 @@ -import {FlashMode} from "./FlashMode"; +import {FlashMode, parseFlashMode} from "./FlashMode"; +import {parseRatio, Ratio} from "./Ratio"; +import {parseNumber} from "./ImageMetadata"; export interface Flash { available: boolean, @@ -7,6 +9,33 @@ export interface Flash { available: boolean, detected: boolean, }, - mode: FlashMode | null, + mode: FlashMode | undefined, redEyeReduction: boolean, + strength: Ratio | undefined, +} + +const MASK_FIRED = 0x0001; +const MASK_STROBE_DETECTED = 0x0002; +const MASK_STROBE_DETECTION_AVAILABLE = 0x0004; +const MASK_MODE = 0x0003; +const MASK_UNAVAILABLE = 0x0020; +const MASK_REDEYE = 0x0040; + +export function parseFlash(flash: string | undefined, strength: string | undefined): Flash | undefined { + const value = parseNumber(flash); + if (value === undefined) { + return undefined; + } + + return { + available: (value & MASK_UNAVAILABLE) === 0, + fired: (value & MASK_FIRED) !== 0, + strobeDetection: { + available: (value & MASK_STROBE_DETECTION_AVAILABLE) !== 0, + detected: (value & MASK_STROBE_DETECTED) !== 0, + }, + redEyeReduction: (value & MASK_REDEYE) !== 0, + strength: parseRatio(strength), + mode: parseFlashMode((value >> 3) & MASK_MODE), + }; } diff --git a/ui/src/metadata/FlashMode.ts b/ui/src/metadata/FlashMode.ts index 02f73791c3a43e45ca9004f6f7a2637509e96831..0330cc9af82863976924d619b72286fd0d8dbdc2 100644 --- a/ui/src/metadata/FlashMode.ts +++ b/ui/src/metadata/FlashMode.ts @@ -3,3 +3,11 @@ export enum FlashMode { ALWAYS_OFF = 2, AUTO = 3 } + +export function parseFlashMode(value: number): FlashMode | undefined { + if (Object.values(FlashMode).includes(value)) { + return value as FlashMode; + } else { + return undefined; + } +} diff --git a/ui/src/metadata/ImageMetadata.ts b/ui/src/metadata/ImageMetadata.ts index 12ff5d23c6b30d4dcd9f8b9dad4c4f2a6d8d3763..1ca8219a97cc5bd30d85b65ea9fcd493b791c56f 100644 --- a/ui/src/metadata/ImageMetadata.ts +++ b/ui/src/metadata/ImageMetadata.ts @@ -1,14 +1,14 @@ import {parseRatio, Ratio} from "./Ratio"; -import {Flash} from "./Flash"; -import {ExposureMode} from "./ExposureMode"; -import {ExposureProgram} from "./ExposureProgram"; -import {LightSource} from "./LightSource"; -import {MeteringMode} from "./MeteringMode"; -import {WhiteBalance} from "./WhiteBalance"; -import {SceneMode} from "./SceneMode"; -import {ContrastProcessing} from "./ContrastProcessing"; -import {SharpnessProcessing} from "./SharpnessProcessing"; -import {SubjectDistanceRange} from "./SubjectDistanceRange"; +import {Flash, parseFlash} from "./Flash"; +import {ExposureMode, parseExposureMode} from "./ExposureMode"; +import {ExposureProgram, parseExposureProgram} from "./ExposureProgram"; +import {LightSource, parseLightSource} from "./LightSource"; +import {MeteringMode, parseMeteringMode} from "./MeteringMode"; +import {parseWhiteBalance, WhiteBalance} from "./WhiteBalance"; +import {parseSceneMode, SceneMode} from "./SceneMode"; +import {ContrastProcessing, parseContrastProcessing} from "./ContrastProcessing"; +import {parseSharpnessProcessing, SharpnessProcessing} from "./SharpnessProcessing"; +import {parseSubjectDistanceRange, SubjectDistanceRange} from "./SubjectDistanceRange"; export interface ImageMetadata { make?: string, @@ -22,7 +22,7 @@ export interface ImageMetadata { exposure?: Ratio, exposureMode?: ExposureMode, exposureProgram?: ExposureProgram, - exposureTime?: Ratio, + shutterSpeed?: Ratio, aperture?: Ratio, flash?: Flash, focalLength?: Ratio, @@ -38,7 +38,7 @@ export interface ImageMetadata { subjectDistanceRange?: SubjectDistanceRange, } -export function parseMetadata(metadata: { [key: string]: string }): ImageMetadata { +export function parseMetadata(metadata: { [key: string]: string | undefined }): ImageMetadata { return { make: metadata["Make"], model: metadata["Model"], @@ -51,9 +51,9 @@ export function parseMetadata(metadata: { [key: string]: string }): ImageMetadat exposure: parseRatio(metadata["ExposureBiasValue"]), exposureMode: parseExposureMode(metadata["ExposureMode"]), exposureProgram: parseExposureProgram(metadata["ExposureProgram"]), - exposureTime: parseRatio(metadata["ExposureTime"]), + shutterSpeed: parseRatio(metadata["ExposureTime"]), aperture: parseRatio(metadata["FNumber"]), - flash: undefined, + flash: parseFlash(metadata["Flash"], metadata["FlashEnergy"]), focalLength: parseRatio(metadata["FocalLength"]), focalLength35mm: parseRatio(metadata["FocalLengthIn35mmFilm"]), isoSpeedRating: parseNumber(metadata["ISOSpeedRatings"]), @@ -68,7 +68,10 @@ export function parseMetadata(metadata: { [key: string]: string }): ImageMetadat } } -export function parseDate(value: string): Date | undefined { +export function parseDate(value: string | undefined): Date | undefined { + if (value === undefined) { + return undefined; + } const split = value.split(" "); if (split.length !== 2) { return undefined; @@ -85,7 +88,10 @@ export function parseDate(value: string): Date | undefined { } } -export function parseNumber(value: string): number | undefined { +export function parseNumber(value: string | undefined): number | undefined { + if (value === undefined) { + return undefined; + } const number = parseInt(value); if (isNaN(number) || number === Infinity || number === -Infinity) { return undefined; @@ -93,105 +99,6 @@ export function parseNumber(value: string): number | undefined { return number; } -export function parseExposureMode(value: string): ExposureMode | undefined { - const numericValue = parseNumber(value) - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(ExposureMode)) { - return numericValue as ExposureMode; - } - return undefined; -} - -export function parseExposureProgram(value: string): ExposureProgram | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(ExposureProgram)) { - return numericValue as ExposureProgram; - } - return undefined; -} - -export function parseLightSource(value: string): LightSource | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(LightSource)) { - return numericValue as LightSource; - } - return undefined; -} - -export function parseMeteringMode(value: string): MeteringMode | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(MeteringMode)) { - return numericValue as MeteringMode; - } - return undefined; -} - -export function parseWhiteBalance(value: string): WhiteBalance | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(WhiteBalance)) { - return numericValue as WhiteBalance; - } - return undefined; -} - -export function parseSceneMode(value: string): SceneMode | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(SceneMode)) { - return numericValue as SceneMode; - } - return undefined; -} - -export function parseContrastProcessing(value: string): ContrastProcessing | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(ContrastProcessing)) { - return numericValue as ContrastProcessing; - } - return undefined; -} - -export function parseSharpnessProcessing(value: string): SharpnessProcessing | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(SharpnessProcessing)) { - return numericValue as SharpnessProcessing; - } - return undefined; -} - -export function parseSubjectDistanceRange(value: string): SubjectDistanceRange | undefined { - const numericValue = parseNumber(value); - if (numericValue === undefined) { - return undefined; - } - if (numericValue in Object.values(SubjectDistanceRange)) { - return numericValue as SubjectDistanceRange; - } - return undefined; -} - export function ratioToTime(value: Ratio | undefined): string | undefined { if (value === undefined) { return undefined; diff --git a/ui/src/metadata/LightSource.ts b/ui/src/metadata/LightSource.ts index 46d3c65bd6f85046cccc392b73e9e9e1e32f971f..c119a032297884120ae0bbd45067a5ecfea4ea5f 100644 --- a/ui/src/metadata/LightSource.ts +++ b/ui/src/metadata/LightSource.ts @@ -1,3 +1,5 @@ +import {parseNumber} from "./ImageMetadata"; + export enum LightSource { DAYLIGHT = 1, FLUORESCENT = 2, @@ -19,3 +21,14 @@ export enum LightSource { D50 = 23, ISO_STUDIO_INCANDESCENT = 24, } + +export function parseLightSource(value: string | undefined): LightSource | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(LightSource).includes(numericValue)) { + return numericValue as LightSource; + } + return undefined; +} diff --git a/ui/src/metadata/MeteringMode.ts b/ui/src/metadata/MeteringMode.ts index 38572e86564c9815a7deccb94de441b3c11a2f4f..2ac111b6dae7f4c3ad6447f5c1309e0f46649186 100644 --- a/ui/src/metadata/MeteringMode.ts +++ b/ui/src/metadata/MeteringMode.ts @@ -1,3 +1,5 @@ +import {parseNumber} from "./ImageMetadata"; + export enum MeteringMode { AVERAGE = 1, CENTER_WEIGHTED_AVERAGE = 2, @@ -6,3 +8,14 @@ export enum MeteringMode { PATTERN = 5, PARTIAL = 6, } + +export function parseMeteringMode(value: string | undefined): MeteringMode | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(MeteringMode).includes(numericValue)) { + return numericValue as MeteringMode; + } + return undefined; +} diff --git a/ui/src/metadata/Ratio.ts b/ui/src/metadata/Ratio.ts index f5a3c5e4594e27ddbb607d0a13043fd1247068ac..e91d22e5020a25d4ad7360b1f0c72e913fbf5fe2 100644 --- a/ui/src/metadata/Ratio.ts +++ b/ui/src/metadata/Ratio.ts @@ -3,7 +3,10 @@ export interface Ratio { denominator: number } -export function parseRatio(value: string): Ratio | undefined { +export function parseRatio(value: string | undefined): Ratio | undefined { + if (value === undefined) { + return undefined; + } const splitValues = value.split("/"); if (splitValues.length < 1) { return undefined; diff --git a/ui/src/metadata/SceneMode.ts b/ui/src/metadata/SceneMode.ts index 9c04599239fd45be6d5418e5873fe349d1e20dfc..def728207103a32a0fc7fda3eb15b0b4699a1532 100644 --- a/ui/src/metadata/SceneMode.ts +++ b/ui/src/metadata/SceneMode.ts @@ -1,6 +1,19 @@ +import {parseNumber} from "./ImageMetadata"; + export enum SceneMode { STANDARD = 0, LANDSCAPE = 1, PORTRAIT = 2, NIGHT_SCENE = 3, } + +export function parseSceneMode(value: string | undefined): SceneMode | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(SceneMode).includes(numericValue)) { + return numericValue as SceneMode; + } + return undefined; +} diff --git a/ui/src/metadata/SharpnessProcessing.ts b/ui/src/metadata/SharpnessProcessing.ts index f8d0a5fd96c3e0418fc98c0dd4ca1e5eb8db9ad6..8183930bc42386b7d7ef43498246dd4347533f78 100644 --- a/ui/src/metadata/SharpnessProcessing.ts +++ b/ui/src/metadata/SharpnessProcessing.ts @@ -1,5 +1,18 @@ +import {parseNumber} from "./ImageMetadata"; + export enum SharpnessProcessing { NORMAL = 0, SOFT = 1, HARD = 2, } + +export function parseSharpnessProcessing(value: string | undefined): SharpnessProcessing | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(SharpnessProcessing).includes(numericValue)) { + return numericValue as SharpnessProcessing; + } + return undefined; +} diff --git a/ui/src/metadata/SubjectDistanceRange.ts b/ui/src/metadata/SubjectDistanceRange.ts index f28a4b7a9b97e0987fad2b7783a60458eb3de425..0bd4b465bf500388236e70a29f9a987e92598d75 100644 --- a/ui/src/metadata/SubjectDistanceRange.ts +++ b/ui/src/metadata/SubjectDistanceRange.ts @@ -1,5 +1,18 @@ +import {parseNumber} from "./ImageMetadata"; + export enum SubjectDistanceRange { MACRO = 1, CLOSE = 2, DISTANT = 3, } + +export function parseSubjectDistanceRange(value: string | undefined): SubjectDistanceRange | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(SubjectDistanceRange).includes(numericValue)) { + return numericValue as SubjectDistanceRange; + } + return undefined; +} diff --git a/ui/src/metadata/WhiteBalance.ts b/ui/src/metadata/WhiteBalance.ts index 7b13f42f16a531bb7b88dc225c3bed79068809d4..86a22ad4a43e254a500ec29b060e212b0008929b 100644 --- a/ui/src/metadata/WhiteBalance.ts +++ b/ui/src/metadata/WhiteBalance.ts @@ -1,4 +1,17 @@ +import {parseNumber} from "./ImageMetadata"; + export enum WhiteBalance { AUTO = 0, MANUAL = 1, } + +export function parseWhiteBalance(value: string | undefined): WhiteBalance | undefined { + const numericValue = parseNumber(value); + if (numericValue === undefined) { + return undefined; + } + if (Object.values(WhiteBalance).includes(numericValue)) { + return numericValue as WhiteBalance; + } + return undefined; +}