mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-26 05:27:35 +02:00
implementing exif/image metadata reading
This commit is contained in:
parent
c66a9b49f3
commit
33347dfd0c
@ -1,9 +1,17 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as mime from "mime";
|
||||
import * as sizeOf from "image-size";
|
||||
import * as iptc from "node-iptc";
|
||||
import * as exif_parser from "exif-parser";
|
||||
import {Directory} from "../../common/entities/Directory";
|
||||
import {Photo} from "../../common/entities/Photo";
|
||||
import {
|
||||
Photo,
|
||||
PhotoMetadata,
|
||||
ImageSize,
|
||||
CameraMetadata,
|
||||
PositionMetaData,
|
||||
GPSMetadata
|
||||
} from "../../common/entities/Photo";
|
||||
|
||||
export class DiskManager {
|
||||
public static scanDirectory(relativeDirectoryName, cb:(error:any, result:Directory) => void) {
|
||||
@ -14,6 +22,7 @@ export class DiskManager {
|
||||
|
||||
let directory = new Directory(1, directoryName, directoryParent, new Date(), [], []);
|
||||
|
||||
let promises:Array< Promise<any> > = [];
|
||||
fs.readdir(absoluteDirectoryName, function (err, list) {
|
||||
|
||||
if (err) {
|
||||
@ -29,12 +38,19 @@ export class DiskManager {
|
||||
}
|
||||
|
||||
if (DiskManager.isImage(fullFilePath)) {
|
||||
let dimensions = sizeOf(fullFilePath);
|
||||
directory.photos.push(new Photo(1, file, directory, dimensions.width, dimensions.height));
|
||||
|
||||
|
||||
let promise = DiskManager.loadPhotoMetadata(fullFilePath).then((photoMetadata)=> {
|
||||
directory.photos.push(new Photo(1, file, directory, photoMetadata));
|
||||
});
|
||||
|
||||
promises.push(promise);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(promises).then(()=> {
|
||||
return cb(err, directory);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@ -60,4 +76,51 @@ export class DiskManager {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static loadPhotoMetadata(fullPath):Promise<PhotoMetadata> {
|
||||
return new Promise<PhotoMetadata>((resolve:(metadata:PhotoMetadata)=>void, reject) => {
|
||||
fs.readFile(fullPath, function (err, data) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
let exif = exif_parser.create(data).parse();
|
||||
let iptcData = iptc(data);
|
||||
|
||||
let imageSize:ImageSize = {width: exif.imageSize.width, height: exif.imageSize.height};
|
||||
let cameraData:CameraMetadata = {
|
||||
ISO: exif.tags.ISO,
|
||||
model: exif.tags.Modeol,
|
||||
maker: exif.tags.Make,
|
||||
fStop: exif.tags.FNumber,
|
||||
exposure: exif.tags.ExposureTime,
|
||||
focalLength: exif.tags.FocalLength,
|
||||
lens: exif.tags.LensModel,
|
||||
};
|
||||
let GPS:GPSMetadata = {
|
||||
latitude: exif.tags.GPSLatitude,
|
||||
longitude: exif.tags.GPSLongitude,
|
||||
altitude: exif.tags.GPSAltitude
|
||||
|
||||
};
|
||||
|
||||
let positionData:PositionMetaData = {
|
||||
GPSData: GPS,
|
||||
country: iptcData.country_or_primary_location_name,
|
||||
state: iptcData.province_or_state,
|
||||
city: iptcData.city
|
||||
};
|
||||
|
||||
let keywords:[string] = iptcData.keywords;
|
||||
let creationDate:Date = iptcData.date_time;
|
||||
|
||||
|
||||
let metadata:PhotoMetadata = new PhotoMetadata(keywords, cameraData, positionData, imageSize, creationDate);
|
||||
resolve(metadata);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
15
backend/model/exif.d.ts
vendored
Normal file
15
backend/model/exif.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
declare module "node-iptc" {
|
||||
|
||||
function e(data):any;
|
||||
|
||||
module e {
|
||||
}
|
||||
|
||||
export = e;
|
||||
}
|
||||
|
||||
|
||||
declare module "exif-parser" {
|
||||
export function create(data):any;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ export class MongoGalleryManager implements IGalleryManager {
|
||||
let directoryName = path.basename(relativeDirectoryName);
|
||||
let directoryParent = path.join(path.dirname(relativeDirectoryName), "/");
|
||||
|
||||
|
||||
DirectoryModel.findOne({
|
||||
name: directoryName,
|
||||
path: directoryParent
|
||||
@ -64,7 +65,7 @@ export class MongoGalleryManager implements IGalleryManager {
|
||||
let directoryEntity = new Directory(directoryModel._id, directoryModel.name, directoryModel.path, directoryModel.lastupdate, [], []);
|
||||
|
||||
directoryModel.photos.forEach((photo) => {
|
||||
let photoEntity = new Photo(photo._id, photo.name, null, photo.width, photo.height);
|
||||
let photoEntity = new Photo(photo._id, photo.name, directoryEntity, photo.metadata);
|
||||
directoryEntity.photos.push(photoEntity);
|
||||
});
|
||||
|
||||
|
@ -4,12 +4,36 @@ import {Schema} from "mongoose";
|
||||
|
||||
export var PhotoModel = DatabaseManager.getInstance().getModel('photo', {
|
||||
name: String,
|
||||
width:Number,
|
||||
height: Number,
|
||||
directory: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'directory'
|
||||
},
|
||||
metadata: {
|
||||
keywords: [String],
|
||||
cameraData: {
|
||||
ISO: Number,
|
||||
maker: String,
|
||||
fStop: Number,
|
||||
exposure: Number,
|
||||
focalLength: Number,
|
||||
lens: String
|
||||
},
|
||||
positionData: {
|
||||
GPSData: {
|
||||
latitude: Number,
|
||||
longitude: Number,
|
||||
altitude: Number
|
||||
},
|
||||
country: String,
|
||||
state: String,
|
||||
city: String
|
||||
},
|
||||
size: {
|
||||
width: Number,
|
||||
height: Number
|
||||
},
|
||||
creationDate: Date
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -19,7 +19,7 @@ export class GalleryRouter {
|
||||
|
||||
private addDirectoryList() {
|
||||
this.app.get(["/api/gallery/content/:directory(*)", "/api/gallery/", "/api/gallery//"],
|
||||
AuthenticationMWs.authenticate,
|
||||
// AuthenticationMWs.authenticate,
|
||||
GalleryMWs.listDirectory,
|
||||
RenderingMWs.renderResult
|
||||
);
|
||||
|
@ -35,7 +35,20 @@ export class Utils {
|
||||
public static setKeys(targetObject, sourceObject) {
|
||||
Object.keys(sourceObject).forEach((key)=> {
|
||||
if (typeof targetObject[key] === "object") {
|
||||
Utils.updateKeys(targetObject[key], sourceObject[key]);
|
||||
Utils.setKeys(targetObject[key], sourceObject[key]);
|
||||
} else {
|
||||
targetObject[key] = sourceObject[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static setKeysForced(targetObject, sourceObject) {
|
||||
Object.keys(sourceObject).forEach((key)=> {
|
||||
if (typeof sourceObject[key] === "object") {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
targetObject[key] = {};
|
||||
}
|
||||
Utils.setKeysForced(targetObject[key], sourceObject[key]);
|
||||
} else {
|
||||
targetObject[key] = sourceObject[key];
|
||||
}
|
||||
|
@ -1,14 +1,47 @@
|
||||
import {Directory} from "./Directory";
|
||||
|
||||
export class Photo {
|
||||
constructor(public id?:number, public name?:string, public directory?:Directory, public width?:number, public height?:number) {
|
||||
constructor(public id?:number,
|
||||
public name?:string,
|
||||
public directory?:Directory,
|
||||
public metadata?:PhotoMetadata) {
|
||||
}
|
||||
}
|
||||
|
||||
/*public static getThumbnailPath(photo:Photo) {
|
||||
return Utils.concatUrls("/api/gallery/content/", photo.directory.path, photo.directory.name, photo.name, "thumbnail");
|
||||
export class PhotoMetadata {
|
||||
constructor(public keywords?:Array<string>,
|
||||
public cameraData?:CameraMetadata,
|
||||
public positionData?:PositionMetaData,
|
||||
public size?:ImageSize,
|
||||
public creationDate?:Date) {
|
||||
}
|
||||
}
|
||||
|
||||
public static getPhotoPath(photo:Photo) {
|
||||
return Utils.concatUrls("/api/gallery/content/", photo.directory.path, photo.directory.name, photo.name);
|
||||
}*/
|
||||
export interface ImageSize {
|
||||
width:number;
|
||||
height:number;
|
||||
}
|
||||
|
||||
export interface CameraMetadata {
|
||||
ISO?:number;
|
||||
model?:string;
|
||||
maker?:string;
|
||||
fStop?:number;
|
||||
exposure?:number;
|
||||
focalLength?:number;
|
||||
lens?:string;
|
||||
}
|
||||
|
||||
export interface PositionMetaData {
|
||||
GPSData?:GPSMetadata;
|
||||
country?:string;
|
||||
state?:string;
|
||||
city?:string;
|
||||
}
|
||||
|
||||
export interface GPSMetadata {
|
||||
latitude?:string;
|
||||
longitude?:string;
|
||||
altitude?:string;
|
||||
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1.0 MiB |
@ -55,7 +55,7 @@ export class GridRowBuilder {
|
||||
public calcRowHeight():number {
|
||||
let width = 0;
|
||||
for (let i = 0; i < this.photoRow.length; i++) {
|
||||
width += ((this.photoRow[i].width) / (this.photoRow[i].height)); //summing up aspect ratios
|
||||
width += ((this.photoRow[i].metadata.size.width) / (this.photoRow[i].metadata.size.height)); //summing up aspect ratios
|
||||
}
|
||||
let height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; //cant be equal -> width-1
|
||||
|
||||
|
@ -104,7 +104,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
|
||||
let imageHeight = rowHeight - (this.IMAGE_MARGIN * 2);
|
||||
|
||||
photoRowBuilder.getPhotoRow().forEach((photo) => {
|
||||
let imageWidth = imageHeight * (photo.width / photo.height);
|
||||
let imageWidth = imageHeight * (photo.metadata.size.width / photo.metadata.size.height);
|
||||
this.photosToRender.push(new GridPhoto(photo, imageWidth, imageHeight));
|
||||
});
|
||||
|
||||
|
@ -176,12 +176,12 @@ export class GalleryLightboxComponent {
|
||||
private calcLightBoxPhotoDimension(photo:Photo):Dimension {
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
if (photo.height > photo.width) {
|
||||
width = Math.round(photo.width * (this.getScreenHeight() / photo.height));
|
||||
if (photo.metadata.size.height > photo.metadata.size.width) {
|
||||
width = Math.round(photo.metadata.size.width * (this.getScreenHeight() / photo.metadata.size.height));
|
||||
height = this.getScreenHeight();
|
||||
} else {
|
||||
width = this.getScreenWidth();
|
||||
height = Math.round(photo.height * (this.getScreenWidth() / photo.width));
|
||||
height = Math.round(photo.metadata.size.height * (this.getScreenWidth() / photo.metadata.size.width));
|
||||
}
|
||||
let top = (this.getScreenHeight() / 2 - height / 2);
|
||||
let left = (this.getScreenWidth() / 2 - width / 2);
|
||||
|
@ -35,14 +35,15 @@
|
||||
"core-js": "^2.4.0",
|
||||
"debug": "^2.2.0",
|
||||
"ejs": "^2.4.1",
|
||||
"exif-parser": "^0.1.9",
|
||||
"express": "^4.13.4",
|
||||
"express-session": "^1.13.0",
|
||||
"image-size": "^0.5.0",
|
||||
"jimp": "^0.2.24",
|
||||
"mime": "^1.3.4",
|
||||
"mongoose": "^4.4.16",
|
||||
"morgan": "^1.7.0",
|
||||
"ng2-cookies": "^0.1.5",
|
||||
"node-iptc": "^1.0.4",
|
||||
"optimist": "^0.6.1",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"ts-loader": "^0.8.2",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"debug": "github:DefinitelyTyped/DefinitelyTyped/debug/debug.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",
|
||||
"express": "github:DefinitelyTyped/DefinitelyTyped/express/express.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",
|
||||
"express-session": "registry:dt/express-session#0.0.0+20160331200931",
|
||||
"image-size": "registry:dt/image-size#0.0.0+20160223165602",
|
||||
"jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#d22516f9f089de107d7e7d5938566377370631f6",
|
||||
"mime": "github:DefinitelyTyped/DefinitelyTyped/mime/mime.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",
|
||||
"mongoose": "registry:dt/mongoose#3.8.5+20160316155526",
|
||||
|
Loading…
x
Reference in New Issue
Block a user