Skip to content

Commit 29524b5

Browse files
committed
Add tags ScaleFactorTo35mmEquivalent, FieldOfView
First composite values. Only the simple variants of these values where we have FocalLengthIn35mmFilm that can be used for the calculation. #488 #491
1 parent 0355a83 commit 29524b5

8 files changed

+139
-5
lines changed

dist/exif-reader.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/exif-reader.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/composite.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4+
5+
export default {
6+
get,
7+
};
8+
9+
function get(tags, expanded) {
10+
const compositeTags = {};
11+
let hasCompositeTags = false;
12+
13+
const focalLength = getTagValue(tags, 'FocalLength', expanded);
14+
const focalLengthIn35mmFilm = getTagValue(tags, 'FocalLengthIn35mmFilm', expanded);
15+
16+
const scaleFactorTo35mmEquivalent = getScaleFactorTo35mmEquivalent(focalLength, focalLengthIn35mmFilm);
17+
if (scaleFactorTo35mmEquivalent) {
18+
compositeTags.ScaleFactorTo35mmEquivalent = scaleFactorTo35mmEquivalent;
19+
hasCompositeTags = true;
20+
}
21+
22+
const fieldOfView = getFieldOfView(focalLengthIn35mmFilm);
23+
if (fieldOfView) {
24+
compositeTags.FieldOfView = fieldOfView;
25+
hasCompositeTags = true;
26+
}
27+
28+
if (hasCompositeTags) {
29+
return compositeTags;
30+
}
31+
32+
return undefined;
33+
}
34+
35+
function getTagValue(tags, tagName, expanded) {
36+
if (expanded && tags.exif && tags.exif[tagName]) {
37+
return tags.exif[tagName].value;
38+
}
39+
if (!expanded && tags[tagName]) {
40+
return tags[tagName].value;
41+
}
42+
return undefined;
43+
}
44+
45+
function getScaleFactorTo35mmEquivalent(focalLength, focalLengthIn35mmFilm) {
46+
if (focalLength && focalLengthIn35mmFilm) {
47+
try {
48+
const value = focalLengthIn35mmFilm / (focalLength[0] / focalLength[1]);
49+
return {
50+
value,
51+
description: value.toFixed(1),
52+
};
53+
} catch (error) {
54+
// Ignore.
55+
}
56+
}
57+
return undefined;
58+
}
59+
60+
function getFieldOfView(focalLengthIn35mmFilm) {
61+
const FULL_FRAME_SENSOR_WIDTH_MM = 36;
62+
63+
if (focalLengthIn35mmFilm) {
64+
try {
65+
const value = 2 * Math.atan(FULL_FRAME_SENSOR_WIDTH_MM / (2 * focalLengthIn35mmFilm)) * (180 / Math.PI);
66+
return {
67+
value,
68+
description: value.toFixed(1) + ' deg',
69+
};
70+
} catch (error) {
71+
// Ignore.
72+
}
73+
}
74+
return undefined;
75+
}

src/exif-reader.js

+10
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import PngTags from './png-tags.js';
2929
import Vp8xTags from './vp8x-tags.js';
3030
import GifFileTags from './gif-file-tags.js';
3131
import Thumbnail from './thumbnail.js';
32+
import Composite from './composite.js';
3233
import exifErrors from './errors.js';
3334

3435
export default {
@@ -419,6 +420,15 @@ export function loadView(
419420
}
420421
}
421422

423+
const composite = Composite.get(tags, expanded);
424+
if (composite) {
425+
if (expanded) {
426+
tags.composite = composite;
427+
} else {
428+
tags = objectAssign({}, tags, composite);
429+
}
430+
}
431+
422432
const thumbnail = (Constants.USE_JPEG || Constants.USE_WEBP)
423433
&& Constants.USE_EXIF
424434
&& Constants.USE_THUMBNAIL

src/tag-names-exif-ifd.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,12 @@ export default {
295295
}
296296
},
297297
0xa405: {
298-
'name': 'FocalLengthIn35mmFilm',
298+
'name': 'FocalLengthIn35mmFilm', // Sometimes called FocalLengthIn35mmFormat.
299299
'description': (value) => {
300300
if (value === 0) {
301301
return 'Unknown';
302302
}
303-
return value;
303+
return value + ' mm';
304304
}
305305
},
306306
0xa406: {

test/unit/composite-spec.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4+
5+
import {expect} from 'chai';
6+
import Composite from '../../src/composite';
7+
8+
describe('composite', () => {
9+
it('should return undefined when there is nothing to calculate', () => {
10+
expect(Composite.get({}, false)).to.be.undefined;
11+
expect(Composite.get({exif: {}}, true)).to.be.undefined;
12+
});
13+
14+
it('should calculate ScaleFactorTo35mmEquivalent', () => {
15+
const tags = {FocalLength: {value: [4500, 1000]}, FocalLengthIn35mmFilm: {value: 24}};
16+
const expected = {
17+
value: 5.333333333333333,
18+
description: '5.3'
19+
};
20+
21+
expect(Composite.get(tags, false).ScaleFactorTo35mmEquivalent).to.deep.equal(expected);
22+
expect(Composite.get({exif: tags}, true).ScaleFactorTo35mmEquivalent).to.deep.equal(expected);
23+
});
24+
25+
it('should calculate FieldOfView', () => {
26+
const tags = {FocalLengthIn35mmFilm: {value: 24}};
27+
const expected = {
28+
value: 73.73979529168804,
29+
description: '73.7 deg'
30+
};
31+
32+
expect(Composite.get(tags, false).FieldOfView).to.deep.equal(expected);
33+
expect(Composite.get({exif: tags}, true).FieldOfView).to.deep.equal(expected);
34+
});
35+
});

test/unit/exif-reader-spec.js

+14
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ describe('exif-reader', function () {
3232
ExifReaderRewireAPI.__ResetDependency__('Vp8xTags');
3333
ExifReaderRewireAPI.__ResetDependency__('GifFileTags');
3434
ExifReaderRewireAPI.__ResetDependency__('Thumbnail');
35+
ExifReaderRewireAPI.__ResetDependency__('Composite');
3536
});
3637

3738
it('should throw an error if the passed buffer is non-compliant', () => {
@@ -598,6 +599,19 @@ describe('exif-reader', function () {
598599
expect(ExifReader.loadView({}, {expanded: true})).to.deep.equal({...myTags, file: {FileType: {value: 'webp', description: 'WebP'}}});
599600
});
600601

602+
it('should calculate composite values', () => {
603+
const myTags = {MyExifTag: 42};
604+
const compositeTags = {MyCompositeTag: 4711};
605+
rewireForLoadView({tiffHeaderOffset: OFFSET_TEST_VALUE}, 'Tags', myTags);
606+
ExifReaderRewireAPI.__Rewire__('Composite', {
607+
get() {
608+
return compositeTags;
609+
}
610+
});
611+
612+
expect(ExifReader.loadView()).to.deep.equal({...myTags, ...compositeTags});
613+
});
614+
601615
describe('gps group', () => {
602616
it('should not create a "gps" group if there are no GPS values', () => {
603617
const myTags = {MyExifTag: 43};

test/unit/tag-names-exif-ifd-spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ describe('tag-names-exif-ifd', () => {
424424
it('should report correct name and description for FocalLengthIn35mmFilm', () => {
425425
expect(TagNamesExifIfd[0xa405].name).to.equal('FocalLengthIn35mmFilm');
426426
expect(TagNamesExifIfd[0xa405].description(0)).to.equal('Unknown');
427-
expect(TagNamesExifIfd[0xa405].description(4711)).to.equal(4711);
427+
expect(TagNamesExifIfd[0xa405].description(4711)).to.equal('4711 mm');
428428
});
429429

430430
it('should report correct name and description for SceneCaptureType', () => {

0 commit comments

Comments
 (0)