image-in-browser
Version:
Package for encoding / decoding images, transforming images, applying filters, drawing primitives on images on the client side (no need for server Node.js)
493 lines • 17.6 kB
JavaScript
import { Rational } from '../common/rational.js';
import { ExifImageTags, ExifTagNameToID } from './exif-tag.js';
import { IfdValueType } from './ifd-value-type.js';
import { IfdContainer } from './ifd-container.js';
import { IfdValue } from './ifd-value/ifd-value.js';
import { IfdAsciiValue } from './ifd-value/ifd-ascii-value.js';
import { IfdShortValue } from './ifd-value/ifd-short-value.js';
import { IfdRationalValue } from './ifd-value/ifd-rational-value.js';
import { IfdByteValue } from './ifd-value/ifd-byte-value.js';
import { IfdLongValue } from './ifd-value/ifd-long-value.js';
import { IfdSByteValue } from './ifd-value/ifd-sbyte-value.js';
import { IfdUndefinedValue } from './ifd-value/ifd-undefined-value.js';
import { IfdSShortValue } from './ifd-value/ifd-sshort-value.js';
import { IfdSLongValue } from './ifd-value/ifd-slong-value.js';
import { IfdSRationalValue } from './ifd-value/ifd-srational-value.js';
import { IfdSingleValue } from './ifd-value/ifd-single-value.js';
import { IfdDoubleValue } from './ifd-value/ifd-double-value.js';
import { StringUtils } from '../common/string-utils.js';
import { ArrayUtils } from '../common/array-utils.js';
export class IfdDirectory {
get sub() {
return this._sub;
}
get keys() {
return this._data.keys();
}
get values() {
return this._data.values();
}
get entries() {
return this._data.entries();
}
get size() {
return this._data.size;
}
get isEmpty() {
return this._data.size === 0 && this._sub.isEmpty;
}
get hasUserComment() {
return this._data.has(0x9286);
}
get userComment() {
var _a;
const data = (_a = this._data.get(0x9286)) === null || _a === void 0 ? void 0 : _a.toData();
return data !== undefined
? StringUtils.utf8Decoder.decode(data)
: undefined;
}
set userComment(v) {
if (v === undefined) {
this._data.delete(0x9286);
}
else {
const codeUnits = StringUtils.getCodePoints(v);
this._data.set(0x9286, new IfdUndefinedValue(codeUnits));
}
}
get hasImageDescription() {
return this._data.has(0x010e);
}
get imageDescription() {
var _a;
return (_a = this._data.get(0x010e)) === null || _a === void 0 ? void 0 : _a.toString();
}
set imageDescription(v) {
if (v === undefined) {
this._data.delete(0x010e);
}
else {
this._data.set(0x010e, new IfdAsciiValue(v));
}
}
get hasMake() {
return this._data.has(0x010f);
}
get make() {
var _a;
return (_a = this._data.get(0x010f)) === null || _a === void 0 ? void 0 : _a.toString();
}
set make(v) {
if (v === undefined) {
this._data.delete(0x010f);
}
else {
this._data.set(0x010f, new IfdAsciiValue(v));
}
}
get hasModel() {
return this._data.has(0x0110);
}
get model() {
var _a;
return (_a = this._data.get(0x0110)) === null || _a === void 0 ? void 0 : _a.toString();
}
set model(v) {
if (v === undefined) {
this._data.delete(0x0110);
}
else {
this._data.set(0x0110, new IfdAsciiValue(v));
}
}
get hasOrientation() {
return this._data.has(0x0112);
}
get orientation() {
var _a;
return (_a = this._data.get(0x0112)) === null || _a === void 0 ? void 0 : _a.toInt();
}
set orientation(v) {
if (v === undefined) {
this._data.delete(0x0112);
}
else {
this._data.set(0x0112, new IfdShortValue(v));
}
}
get hasResolutionX() {
return this._data.has(0x011a);
}
get resolutionX() {
var _a;
return (_a = this._data.get(0x011a)) === null || _a === void 0 ? void 0 : _a.toRational();
}
set resolutionX(v) {
if (!this.setRational(0x011a, v)) {
this._data.delete(0x011a);
}
}
get hasResolutionY() {
return this._data.has(0x011b);
}
get resolutionY() {
var _a;
return (_a = this._data.get(0x011b)) === null || _a === void 0 ? void 0 : _a.toRational();
}
set resolutionY(v) {
if (!this.setRational(0x011b, v)) {
this._data.delete(0x011b);
}
}
get hasResolutionUnit() {
return this._data.has(0x0128);
}
get resolutionUnit() {
var _a;
return (_a = this._data.get(0x0128)) === null || _a === void 0 ? void 0 : _a.toInt();
}
set resolutionUnit(v) {
if (v === undefined) {
this._data.delete(0x0128);
}
else {
this._data.set(0x0128, new IfdShortValue(Math.trunc(v)));
}
}
get hasImageWidth() {
return this._data.has(0x0100);
}
get imageWidth() {
var _a;
return (_a = this._data.get(0x0100)) === null || _a === void 0 ? void 0 : _a.toInt();
}
set imageWidth(v) {
if (v === undefined) {
this._data.delete(0x0100);
}
else {
this._data.set(0x0100, new IfdShortValue(Math.trunc(v)));
}
}
get hasImageHeight() {
return this._data.has(0x0101);
}
get imageHeight() {
var _a;
return (_a = this._data.get(0x0101)) === null || _a === void 0 ? void 0 : _a.toInt();
}
set imageHeight(v) {
if (v === undefined) {
this._data.delete(0x0101);
}
else {
this._data.set(0x0101, new IfdShortValue(Math.trunc(v)));
}
}
get hasSoftware() {
return this._data.has(0x0131);
}
get software() {
var _a;
return (_a = this._data.get(0x0131)) === null || _a === void 0 ? void 0 : _a.toString();
}
set software(v) {
if (v === undefined) {
this._data.delete(0x0131);
}
else {
this._data.set(0x0131, new IfdAsciiValue(v));
}
}
get hasCopyright() {
return this._data.has(0x8298);
}
get copyright() {
var _a;
return (_a = this._data.get(0x8298)) === null || _a === void 0 ? void 0 : _a.toString();
}
set copyright(v) {
if (v === undefined) {
this._data.delete(0x8298);
}
else {
this._data.set(0x8298, new IfdAsciiValue(v));
}
}
get hasGPSLatitudeRef() {
return this._data.has(0x0001);
}
get gpsLatitudeRef() {
var _a;
return (_a = this._data.get(0x0001)) === null || _a === void 0 ? void 0 : _a.toString();
}
set gpsLatitudeRef(v) {
if (v === undefined) {
this._data.delete(0x0001);
}
else {
this._data.set(0x0001, new IfdAsciiValue(v));
}
}
get hasGPSLatitude() {
return this._data.has(0x0002);
}
get gpsLatitude() {
var _a;
return (_a = this._data.get(0x0002)) === null || _a === void 0 ? void 0 : _a.toDouble();
}
set gpsLatitude(v) {
if (v === undefined) {
this._data.delete(0x0002);
}
else {
this._data.set(0x0002, new IfdDoubleValue(v));
}
}
get hasGPSLongitudeRef() {
return this._data.has(0x0003);
}
get gpsLongitudeRef() {
var _a;
return (_a = this._data.get(0x0003)) === null || _a === void 0 ? void 0 : _a.toString();
}
set gpsLongitudeRef(v) {
if (v === undefined) {
this._data.delete(0x0003);
}
else {
this._data.set(0x0003, new IfdAsciiValue(v));
}
}
get hasGPSLongitude() {
return this._data.has(0x0004);
}
get gpsLongitude() {
var _a;
return (_a = this._data.get(0x0004)) === null || _a === void 0 ? void 0 : _a.toDouble();
}
set gpsLongitude(v) {
if (v === undefined) {
this._data.delete(0x0004);
}
else {
this._data.set(0x0004, new IfdDoubleValue(v));
}
}
get hasGPSDate() {
return this._data.has(0x001d);
}
get gpsDate() {
var _a;
return (_a = this._data.get(0x001d)) === null || _a === void 0 ? void 0 : _a.toString();
}
set gpsDate(v) {
if (v === undefined) {
this._data.delete(0x001d);
}
else {
this._data.set(0x001d, new IfdAsciiValue(v));
}
}
get dataSize() {
const numEntries = this.size;
let dataOffset = 2 + 12 * numEntries + 4;
for (const value of this.values) {
const dataSize = value.dataSize;
if (dataSize > 4) {
dataOffset += dataSize;
}
}
for (const [_subName, subDir] of this.sub.entries) {
let subSize = 2 + 12 * subDir.size;
for (const value of subDir.values) {
const dataSize = value.dataSize;
if (dataSize > 4) {
subSize += dataSize;
}
}
dataOffset += subSize;
}
return dataOffset;
}
constructor(data) {
this._sub = new IfdContainer();
this._data = data !== null && data !== void 0 ? data : new Map();
}
setRational(tag, value) {
if (value instanceof Rational) {
this._data.set(tag, IfdRationalValue.from(value));
return true;
}
else if (ArrayUtils.isNumArrayOrTypedArray(value) &&
value.length >= 2) {
const r = new Rational(value[0], value[1]);
this._data.set(tag, IfdRationalValue.from(r));
return true;
}
return false;
}
static from(other) {
return new IfdDirectory(new Map(other._data));
}
static isArrayOfRationalNumbers(value) {
return (Array.isArray(value) &&
value.every((v) => ArrayUtils.isNumArrayOrTypedArray(v) && v.length >= 2));
}
has(tag) {
return this._data.has(tag);
}
getValue(tag) {
let _tag = tag;
if (typeof _tag === 'string') {
_tag = ExifTagNameToID.get(_tag);
}
if (typeof _tag === 'number') {
return this._data.get(_tag);
}
return undefined;
}
setValue(tag, value) {
let _tag = tag;
if (typeof _tag === 'string') {
_tag = ExifTagNameToID.get(_tag);
}
if (typeof _tag !== 'number') {
return;
}
if (value === undefined) {
this._data.delete(_tag);
}
else {
if (value instanceof IfdValue) {
this._data.set(_tag, value);
}
else {
const tagInfo = ExifImageTags.get(_tag);
if (tagInfo !== undefined) {
const tagType = tagInfo.type;
switch (tagType) {
case IfdValueType.byte:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdByteValue(new Uint8Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdByteValue(value));
}
break;
case IfdValueType.ascii:
if (typeof value === 'string') {
this._data.set(_tag, new IfdAsciiValue(value));
}
break;
case IfdValueType.short:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdShortValue(new Uint16Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdShortValue(value));
}
break;
case IfdValueType.long:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdLongValue(new Uint32Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdLongValue(value));
}
break;
case IfdValueType.rational:
if (ArrayUtils.isArrayOfRational(value)) {
this._data.set(_tag, new IfdRationalValue(value));
}
else if (ArrayUtils.isNumArrayOrTypedArray(value) &&
value.length >= 2) {
const r = new Rational(value[0], value[1]);
this._data.set(_tag, new IfdRationalValue(r));
}
else if (value instanceof Rational) {
this._data.set(_tag, new IfdRationalValue(value));
}
break;
case IfdValueType.sByte:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdSByteValue(new Int8Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdSByteValue(value));
}
break;
case IfdValueType.undefined:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdUndefinedValue(new Uint8Array(value)));
}
break;
case IfdValueType.sShort:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdSShortValue(new Int16Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdSShortValue(value));
}
break;
case IfdValueType.sLong:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdSLongValue(new Int32Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdSLongValue(value));
}
break;
case IfdValueType.sRational:
if (ArrayUtils.isArrayOfRational(value)) {
this._data.set(_tag, new IfdSRationalValue(value));
}
else if (ArrayUtils.isNumArrayOrTypedArray(value) &&
value.length >= 2) {
const r = new Rational(value[0], value[1]);
this._data.set(_tag, new IfdSRationalValue(r));
}
else if (value instanceof Rational) {
this._data.set(_tag, new IfdSRationalValue(value));
}
break;
case IfdValueType.single:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdSingleValue(new Float32Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdSingleValue(value));
}
break;
case IfdValueType.double:
if (ArrayUtils.isNumArrayOrTypedArray(value)) {
this._data.set(_tag, new IfdDoubleValue(new Float64Array(value)));
}
else if (typeof value === 'number') {
this._data.set(_tag, new IfdDoubleValue(value));
}
break;
case IfdValueType.none:
break;
}
}
}
}
}
setGpsLocation(latitude, longitude) {
this.gpsLatitude = Math.abs(latitude);
this.gpsLongitude = Math.abs(longitude);
this.gpsLatitudeRef = latitude < 0 ? 'S' : 'N';
this.gpsLongitudeRef = longitude < 0 ? 'W' : 'E';
}
copyFrom(other) {
other._data.forEach((value, tag) => this._data.set(tag, value.clone()));
for (const [tag, value] of other._sub.entries) {
this._sub.set(tag, value.clone());
}
}
clone() {
return IfdDirectory.from(this);
}
}
//# sourceMappingURL=ifd-directory.js.map