-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Extract ExifReader from ExifRenderer.
- Loading branch information
1 parent
66799e8
commit 0741ad6
Showing
6 changed files
with
161 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// ref: https://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/ | ||
// note: rotating *clockwise* | ||
export enum ExifOrientation { | ||
Normal = 0, | ||
Rotated90 = 8, | ||
Rotated180 = 3, | ||
Rotated270 = 6, | ||
ReflectedVerticalAxis = 2, | ||
Rotated90AndReflectedHorizontalAxis = 7, | ||
Rotated180AndReflectedVerticalAxis = 4, | ||
Rotated270AndReflectedHorizontalAxis = 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import * as fs from "fs"; | ||
import * as path from "path"; | ||
|
||
import { ImageDetail } from "../../../bars/model/ImageDetail"; | ||
import { ExifTagSet } from "./ExifTagSet"; | ||
|
||
const jpegDecoder = require("jpg-stream/decoder"); | ||
|
||
export namespace ExifReader { | ||
export async function getExifTagsForImageAsync( | ||
image: ImageDetail | ||
): Promise<ExifTagSet[] | null> { | ||
if (!hasFileExif(image.originalFilepath)) { | ||
return null; | ||
} | ||
|
||
return new Promise<ExifTagSet[]>((resolve, reject) => { | ||
// decode a JPEG file to RGB pixels | ||
fs.createReadStream(image.originalFilepath) | ||
.pipe(new jpegDecoder({ width: 600, height: 400 })) | ||
.on("meta", (meta: any) => { | ||
// meta contains an exif object as decoded by | ||
// https://github.com/devongovett/exif-reader | ||
|
||
resolve(parseExif(meta)); | ||
}); | ||
}); | ||
} | ||
|
||
function hasFileExif(filepath: string): boolean { | ||
const extension = path.extname(filepath).toLowerCase(); | ||
|
||
// currently we are decoding only JPEG files. | ||
// note: some PNG files can have some EXIF data but it's not yet standard. | ||
|
||
return [".jpg", ".jpeg"].includes(extension); | ||
} | ||
|
||
function parseExif(meta: any): ExifTagSet[] { | ||
return [ | ||
ExifTagSet.fromTags(meta.exif, "Image"), | ||
ExifTagSet.fromTags(meta.image, "Device"), | ||
ExifTagSet.fromTags(meta.gps, "GPS") | ||
].filter(e => !!e) as ExifTagSet[]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import * as jquery from "jquery"; | ||
|
||
import { ImageDetail } from "../../../bars/model/ImageDetail"; | ||
import { ExifReader } from "./ExifReader"; | ||
import { ExifTagSet } from "./ExifTagSet"; | ||
|
||
export namespace ExifRenderer { | ||
export async function renderHtmlForImage(image: ImageDetail, divId: string) { | ||
const html = await getHtmlForImageAsync(image); | ||
|
||
jquery("#" + divId).append(html); | ||
} | ||
|
||
async function getHtmlForImageAsync(image: ImageDetail): Promise<string> { | ||
const tagSets = await ExifReader.getExifTagsForImageAsync(image); | ||
if (!tagSets) { | ||
return ""; | ||
} | ||
|
||
let html = "<pre>"; | ||
|
||
html += tagSets.map(set => renderTagSet(set)).join("\n"); | ||
|
||
html += "</pre>"; | ||
|
||
return html; | ||
} | ||
|
||
function renderTagSet(tagSet: ExifTagSet): string { | ||
let sectionHtml = ""; | ||
|
||
tagSet.map.forEach((value, key) => { | ||
if (value !== null && value !== undefined) { | ||
const valueAsText = value.toString(); | ||
sectionHtml += valueAsText.length > 0 ? `${key}: ${valueAsText}\n` : ""; | ||
} | ||
}); | ||
|
||
if (sectionHtml.length > 0) { | ||
return `--- ${tagSet.title} ---\n` + sectionHtml; | ||
} | ||
|
||
return ""; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
export class ExifTagSet { | ||
static fromTags(tags: any, name: string): ExifTagSet | null { | ||
if (!tags) { | ||
return null; | ||
} | ||
|
||
const interestingTags = Object.keys(ExifTag); | ||
|
||
const tagSet = new ExifTagSet(name); | ||
|
||
interestingTags.forEach(tag => { | ||
const value = tags[tag] ? tags[tag] : null; | ||
|
||
if (value) { | ||
tagSet.map.set(tag as ExifTag, value); | ||
} | ||
}); | ||
|
||
return tagSet; | ||
} | ||
|
||
readonly map = new Map<ExifTag, string>(); | ||
|
||
constructor(readonly title: string) {} | ||
|
||
get(tag: ExifTag): string | null { | ||
if (!this.map.has(tag)) { | ||
return null; | ||
} | ||
|
||
return this.map.get(tag)!; | ||
} | ||
} | ||
|
||
enum ExifTag { | ||
// 'exif' | ||
ApertureValue = "ApertureValue", | ||
BrightnessValue = "BrightnessValue", | ||
FNumber = "FNumber", | ||
Flash = "Flash", | ||
FocalLength = "FocalLength", | ||
ISO = "ISO", | ||
// 'gps' | ||
GPSAltitude = "GPSAltitude", | ||
GPSAltitudeRef = "GPSAltitudeRef", | ||
GPSLatitude = "GPSLatitude", | ||
GPSLatitudeRef = "GPSLatitudeRef", | ||
// 'image' | ||
ModifyDate = "ModifyDate", | ||
Orientation = "Orientation", | ||
Software = "Software", | ||
XResolution = "XResolution", | ||
YResolution = "YResolution", | ||
Make = "Make", | ||
Model = "Model" | ||
} |