mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-25 02:04:15 +02:00
implementing thumbnail sizes
This commit is contained in:
parent
d6b8b611b3
commit
c66a9b49f3
@ -8,7 +8,6 @@ export var Config = new ConfigClass();
|
||||
|
||||
Config.Server = {
|
||||
port: 80,
|
||||
thumbnailSizes: [200],
|
||||
imagesFolder: "/demo/images",
|
||||
thumbnailFolder: "/demo/TEMP",
|
||||
databaseType: DatabaseType.mongoDB
|
||||
|
@ -20,33 +20,47 @@ export class ThumbnailGeneratorMWs {
|
||||
if (!req.resultPipe)
|
||||
return next();
|
||||
|
||||
//load parameters
|
||||
let imagePath = req.resultPipe;
|
||||
let size:number = parseInt(req.params.size) || Config.Server.thumbnailSizes[0];
|
||||
let size:number = parseInt(req.params.size) || Config.Client.thumbnailSizes[0];
|
||||
let thumbnailFolder = ThumbnailGeneratorMWs.getThumbnailFolder();
|
||||
|
||||
if (Config.Server.thumbnailSizes.indexOf(size) === -1) {
|
||||
size = Config.Server.thumbnailSizes[0];
|
||||
//validate size
|
||||
if (Config.Client.thumbnailSizes.indexOf(size) === -1) {
|
||||
size = Config.Client.thumbnailSizes[0];
|
||||
}
|
||||
|
||||
//generate thumbnail path
|
||||
let thPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));
|
||||
|
||||
|
||||
req.resultPipe = thPath;
|
||||
|
||||
//check if thumbnail already exist
|
||||
if (fs.existsSync(thPath) === true) {
|
||||
return next();
|
||||
}
|
||||
|
||||
//create thumbnail folder if not exist
|
||||
if (!fs.existsSync(thumbnailFolder)) {
|
||||
fs.mkdirSync(thumbnailFolder);
|
||||
}
|
||||
|
||||
//generate thumbnail
|
||||
Jimp.read(imagePath).then((image) => {
|
||||
if (image.bitmap.with < image.bitmap.height) {
|
||||
image.resize(size, Jimp.AUTO); // resize
|
||||
} else {
|
||||
image.resize(Jimp.AUTO, size); // resize
|
||||
}
|
||||
/**
|
||||
* newWidth * newHeight = size*size
|
||||
* newHeight/newWidth = height/width
|
||||
*
|
||||
* newHeight = (height/width)*newWidth
|
||||
* newWidth * newWidth = (size*size) / (height/width)
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
let ratio = image.bitmap.height / image.bitmap.width;
|
||||
let newWidth = Math.sqrt((size * size) / ratio);
|
||||
|
||||
image.resize(newWidth, Jimp.AUTO, Jimp.RESIZE_BEZIER);
|
||||
|
||||
image.quality(60); // set JPEG quality
|
||||
image.write(thPath, () => { // save
|
||||
@ -55,6 +69,7 @@ export class ThumbnailGeneratorMWs {
|
||||
}).catch(function (err) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static generateThumbnailName(imagePath:string, size:number):string {
|
||||
|
5
backend/middlewares/jimp.d.ts
vendored
5
backend/middlewares/jimp.d.ts
vendored
@ -1,5 +1,10 @@
|
||||
declare module "jimp" {
|
||||
function read(filaname);
|
||||
|
||||
var RESIZE_NEAREST_NEIGHBOR;
|
||||
var RESIZE_BILINEAR;
|
||||
var RESIZE_BICUBIC;
|
||||
var RESIZE_HERMITE;
|
||||
var RESIZE_BEZIER;
|
||||
var AUTO:any;
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
import * as _express from "express";
|
||||
import * as _session from "express-session";
|
||||
import * as _bodyParser from "body-parser";
|
||||
import * as _compress from "compression";
|
||||
import * as _debug from "debug";
|
||||
import * as _http from "http";
|
||||
import {PublicRouter} from "./routes/PublicRouter";
|
||||
@ -29,6 +28,7 @@ export class Server {
|
||||
this.debug = _debug("PiGallery2:server");
|
||||
this.app = _express();
|
||||
|
||||
|
||||
this.app.set('view engine', 'ejs');
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
@ -36,9 +36,7 @@ export class Server {
|
||||
this.app.use(_morgan('dev'));
|
||||
}
|
||||
|
||||
//enable gzip
|
||||
this.app.use(_compress());
|
||||
|
||||
|
||||
/**
|
||||
* Session above all
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@ export class Utils {
|
||||
}
|
||||
|
||||
public static updateKeys(targetObject, sourceObject) {
|
||||
Object.keys(sourceObject).forEach((key)=> {
|
||||
Object.keys(sourceObject).forEach((key)=> {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
return;
|
||||
}
|
||||
@ -56,4 +56,24 @@ export class Utils {
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
public static findClosest(number:number, arr:Array<number>) {
|
||||
|
||||
let curr = arr[0];
|
||||
let diff = Math.abs(number - curr);
|
||||
|
||||
arr.forEach((value)=> {
|
||||
|
||||
let newDiff = Math.abs(number - value);
|
||||
|
||||
if (newDiff < diff) {
|
||||
diff = newDiff;
|
||||
curr = value;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ export enum DatabaseType{
|
||||
|
||||
interface ServerConfig {
|
||||
port:number;
|
||||
thumbnailSizes:Array<number>;
|
||||
imagesFolder:string;
|
||||
thumbnailFolder:string;
|
||||
databaseType:DatabaseType;
|
||||
@ -17,6 +16,7 @@ interface SearchConfig {
|
||||
}
|
||||
|
||||
interface ClientConfig {
|
||||
thumbnailSizes:Array<number>;
|
||||
Search:SearchConfig;
|
||||
}
|
||||
export class ConfigClass {
|
||||
@ -24,6 +24,7 @@ export class ConfigClass {
|
||||
public Server:ServerConfig = null;
|
||||
|
||||
public Client:ClientConfig = {
|
||||
thumbnailSizes: [200, 400, 600],
|
||||
Search: {
|
||||
searchEnabled: true,
|
||||
instantSearchEnabled: true,
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {Utils} from "../Utils";
|
||||
import {Directory} from "./Directory";
|
||||
|
||||
export class Photo {
|
||||
constructor(public id?:number, public name?:string, public directory?:Directory, public width?:number, public height?:number) {
|
||||
}
|
||||
|
||||
public static getThumbnailPath(photo:Photo) {
|
||||
/*public static getThumbnailPath(photo:Photo) {
|
||||
return Utils.concatUrls("/api/gallery/content/", photo.directory.path, photo.directory.name, photo.name, "thumbnail");
|
||||
}
|
||||
|
||||
public static getPhotoPath(photo:Photo) {
|
||||
return Utils.concatUrls("/api/gallery/content/", photo.directory.path, photo.directory.name, photo.name);
|
||||
}
|
||||
}*/
|
||||
}
|
18
frontend/app/gallery/grid/GridPhoto.ts
Normal file
18
frontend/app/gallery/grid/GridPhoto.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {Config} from "../../config/Config";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
export class GridPhoto {
|
||||
constructor(public photo:Photo, public renderWidth:number, public renderHeight:number) {
|
||||
|
||||
}
|
||||
|
||||
getThumbnailPath() {
|
||||
let renderSize = Math.sqrt(this.renderWidth * this.renderHeight);
|
||||
let size = Utils.findClosest(renderSize, Config.Client.thumbnailSizes);
|
||||
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString());
|
||||
}
|
||||
|
||||
getPhotoPath() {
|
||||
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name);
|
||||
}
|
||||
}
|
@ -3,7 +3,8 @@ div {
|
||||
line-height: normal;
|
||||
font-size: 0;
|
||||
}
|
||||
gallery-photo {
|
||||
|
||||
gallery-grid-photo {
|
||||
display: inline-block;
|
||||
|
||||
cursor: pointer;
|
||||
|
@ -1,12 +1,12 @@
|
||||
<div #gridContainer (window:resize)="onResize()">
|
||||
<gallery-photo
|
||||
*ngFor="let gridPhoto of photosToRender"
|
||||
(click)="lightbox.show(gridPhoto.photo)"
|
||||
[photo]="gridPhoto.photo"
|
||||
[style.width.px]="gridPhoto.renderWidth"
|
||||
[style.height.px]="gridPhoto.renderHeight"
|
||||
[style.marginLeft.px]="IMAGE_MARGIN"
|
||||
[style.marginRight.px]="IMAGE_MARGIN">
|
||||
<gallery-grid-photo
|
||||
*ngFor="let gridPhoto of photosToRender"
|
||||
(click)="lightbox.show(gridPhoto.photo)"
|
||||
[gridPhoto]="gridPhoto"
|
||||
[style.width.px]="gridPhoto.renderWidth"
|
||||
[style.height.px]="gridPhoto.renderHeight"
|
||||
[style.marginLeft.px]="IMAGE_MARGIN"
|
||||
[style.marginRight.px]="IMAGE_MARGIN">
|
||||
|
||||
</gallery-photo>
|
||||
</gallery-grid-photo>
|
||||
</div>
|
@ -11,9 +11,10 @@ import {
|
||||
AfterViewInit
|
||||
} from "@angular/core";
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {GalleryPhotoComponent} from "../photo/photo.gallery.component";
|
||||
import {GridRowBuilder} from "./GridRowBuilder";
|
||||
import {GalleryLightboxComponent} from "../lightbox/lightbox.gallery.component";
|
||||
import {GridPhoto} from "./GridPhoto";
|
||||
import {GalleryPhotoComponent} from "./photo/photo.grid.gallery.component";
|
||||
|
||||
@Component({
|
||||
selector: 'gallery-grid',
|
||||
@ -49,6 +50,8 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.lightbox.gridPhotoQL = this.gridPhotoQL;
|
||||
|
||||
//TODO: implement scroll detection
|
||||
/* this.gridPhotoQL.changes.subscribe(
|
||||
(x)=> {
|
||||
console.log("changed");
|
||||
@ -121,8 +124,4 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
|
||||
}
|
||||
|
||||
|
||||
class GridPhoto {
|
||||
constructor(public photo:Photo, public renderWidth:number, public renderHeight:number) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
<img #image [src]="gridPhoto.getThumbnailPath()">
|
@ -0,0 +1,35 @@
|
||||
///<reference path="../../../../browser.d.ts"/>
|
||||
|
||||
import {Component, Input, ElementRef, ViewChild} from "@angular/core";
|
||||
import {IRenderable, Dimension} from "../../../model/IRenderable";
|
||||
import {GridPhoto} from "../GridPhoto";
|
||||
|
||||
@Component({
|
||||
selector: 'gallery-grid-photo',
|
||||
templateUrl: 'app/gallery/grid/photo/photo.grid.gallery.component.html',
|
||||
styleUrls: ['app/gallery/grid/photo/photo.grid.gallery.component.css'],
|
||||
})
|
||||
export class GalleryPhotoComponent implements IRenderable {
|
||||
@Input() gridPhoto:GridPhoto;
|
||||
@ViewChild("image") imageRef:ElementRef;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/* getPhotoPath() {
|
||||
|
||||
let renderSize = Math.sqrt(this.gridPhoto.renderWidth * this.gridPhoto.renderHeight);
|
||||
let size = Utils.findClosest(renderSize, Config.Client.thumbnailSizes);
|
||||
return Utils.concatUrls("/api/gallery/content/", this.gridPhoto.photo.directory.path, this.gridPhoto.photo.directory.name, this.gridPhoto.photo.name, "thumbnail", size.toString());
|
||||
}
|
||||
*/
|
||||
|
||||
public getDimension():Dimension {
|
||||
return new Dimension(this.imageRef.nativeElement.offsetTop,
|
||||
this.imageRef.nativeElement.offsetLeft,
|
||||
this.imageRef.nativeElement.width,
|
||||
this.imageRef.nativeElement.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import {Component, ElementRef, ViewChild, QueryList} from "@angular/core";
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {GalleryPhotoComponent} from "../photo/photo.gallery.component";
|
||||
import {GalleryPhotoComponent} from "../grid/photo/photo.grid.gallery.component.ts";
|
||||
import {AnimationBuilder} from "@angular/platform-browser/src/animate/animation_builder";
|
||||
import {BrowserDomAdapter} from "@angular/platform-browser/src/browser_common";
|
||||
import {Dimension} from "../../model/IRenderable";
|
||||
@ -46,7 +46,7 @@ export class GalleryLightboxComponent {
|
||||
|
||||
|
||||
let fromImage = {width: from.width + "px", height: from.height + "px", top: "0px", left: "0px"};
|
||||
let toImage = this.calcLightBoxPhotoDimension(this.activePhoto.photo).toStyle();
|
||||
let toImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
|
||||
|
||||
this.forceAnimateFrom(fromImage,
|
||||
toImage,
|
||||
@ -89,7 +89,7 @@ export class GalleryLightboxComponent {
|
||||
{display: "none"});
|
||||
|
||||
|
||||
let fromImage = this.calcLightBoxPhotoDimension(this.activePhoto.photo).toStyle();
|
||||
let fromImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
|
||||
let toImage = {width: to.width + "px", height: to.height + "px", top: "0px", left: "0px"};
|
||||
|
||||
this.forceAnimateTo(fromImage,
|
||||
@ -106,7 +106,7 @@ export class GalleryLightboxComponent {
|
||||
let galleryPhotoComponents = this.gridPhotoQL.toArray();
|
||||
let selectedPhoto:GalleryPhotoComponent = null;
|
||||
for (let i = 0; i < galleryPhotoComponents.length; i++) {
|
||||
if (galleryPhotoComponents[i].photo == photo) {
|
||||
if (galleryPhotoComponents[i].gridPhoto.photo == photo) {
|
||||
selectedPhoto = galleryPhotoComponents[i];
|
||||
break;
|
||||
}
|
||||
@ -150,14 +150,14 @@ export class GalleryLightboxComponent {
|
||||
if (!this.activePhoto) {
|
||||
return "";
|
||||
}
|
||||
return Photo.getPhotoPath(this.activePhoto.photo);
|
||||
return this.activePhoto.gridPhoto.getPhotoPath();
|
||||
}
|
||||
|
||||
getThumbnailPath() {
|
||||
if (!this.activePhoto) {
|
||||
return "";
|
||||
}
|
||||
return Photo.getThumbnailPath(this.activePhoto.photo);
|
||||
return this.activePhoto.gridPhoto.getThumbnailPath();
|
||||
}
|
||||
|
||||
private getBodyScrollTop() {
|
||||
|
@ -1 +0,0 @@
|
||||
<img #image [src]="getPhotoPath()">
|
@ -1,32 +0,0 @@
|
||||
///<reference path="../../../browser.d.ts"/>
|
||||
|
||||
import {Component, Input, ElementRef, ViewChild} from "@angular/core";
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {IRenderable, Dimension} from "../../model/IRenderable";
|
||||
|
||||
@Component({
|
||||
selector: 'gallery-photo',
|
||||
templateUrl: 'app/gallery/photo/photo.gallery.component.html',
|
||||
styleUrls: ['app/gallery/photo/photo.gallery.component.css'],
|
||||
})
|
||||
export class GalleryPhotoComponent implements IRenderable {
|
||||
@Input() photo:Photo;
|
||||
@ViewChild("image") imageRef:ElementRef;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getPhotoPath() {
|
||||
return Photo.getThumbnailPath(this.photo);
|
||||
}
|
||||
|
||||
|
||||
public getDimension():Dimension {
|
||||
return new Dimension(this.imageRef.nativeElement.offsetTop,
|
||||
this.imageRef.nativeElement.offsetLeft,
|
||||
this.imageRef.nativeElement.width,
|
||||
this.imageRef.nativeElement.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
15
package.json
15
package.json
@ -31,9 +31,8 @@
|
||||
"@angular/platform-server": "2.0.0-rc.1",
|
||||
"@angular/router": "2.0.0-rc.1",
|
||||
"@angular/router-deprecated": "2.0.0-rc.1",
|
||||
"body-parser": "^1.15.0",
|
||||
"compression": "^1.6.1",
|
||||
"core-js": "^2.3.0",
|
||||
"body-parser": "^1.15.1",
|
||||
"core-js": "^2.4.0",
|
||||
"debug": "^2.2.0",
|
||||
"ejs": "^2.4.1",
|
||||
"express": "^4.13.4",
|
||||
@ -41,13 +40,13 @@
|
||||
"image-size": "^0.5.0",
|
||||
"jimp": "^0.2.24",
|
||||
"mime": "^1.3.4",
|
||||
"mongoose": "^4.4.14",
|
||||
"mongoose": "^4.4.16",
|
||||
"morgan": "^1.7.0",
|
||||
"ng2-cookies": "^0.1.5",
|
||||
"optimist": "^0.6.1",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"ts-loader": "^0.8.2",
|
||||
"tslint": "^3.9.0",
|
||||
"tslint": "^3.10.1",
|
||||
"typescript": "^1.8.10",
|
||||
"typings": "^0.8.1",
|
||||
"webpack": "^1.13.0",
|
||||
@ -67,10 +66,10 @@
|
||||
"jasmine-core": "^2.4.1",
|
||||
"json-loader": "^0.5.4",
|
||||
"karma": "^0.13.21",
|
||||
"karma-coverage": "^0.5.3",
|
||||
"karma-coverage": "^1.0.0",
|
||||
"karma-coveralls": "^1.1.2",
|
||||
"karma-jasmine": "^0.3.7",
|
||||
"karma-mocha-reporter": "^2.0.0",
|
||||
"karma-jasmine": "^1.0.2",
|
||||
"karma-mocha-reporter": "^2.0.3",
|
||||
"karma-phantomjs-launcher": "^1.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "1.7.0",
|
||||
|
@ -3,7 +3,6 @@
|
||||
"version": false,
|
||||
"ambientDependencies": {
|
||||
"body-parser": "registry:dt/body-parser#0.0.0+20160317120654",
|
||||
"compression": "registry:dt/compression#0.0.0+20160501162003",
|
||||
"core-js": "registry:dt/core-js#0.0.0+20160317120654",
|
||||
"debug": "github:DefinitelyTyped/DefinitelyTyped/debug/debug.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",
|
||||
"express": "github:DefinitelyTyped/DefinitelyTyped/express/express.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",
|
||||
|
Loading…
Reference in New Issue
Block a user