mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-25 02:04:15 +02:00
removing image rotation to support the now available in-browser image orientation tag https://caniuse.com/#feat=css-image-orientation
Fixes: #172
This commit is contained in:
parent
f67dc7d58f
commit
1cc95bb925
@ -119,7 +119,7 @@ apt-get install build-essential libkrb5-dev gcc g++
|
||||
|
||||
|
||||
## 2. Translate the page to your own language
|
||||
1. [Install Pigallery2](#111-b-install-from-source) from source (with the release it won't work)
|
||||
1. [Install Pigallery2](#121-b-install-from-source) from source (with the release it won't work)
|
||||
2. add your language e.g: fr
|
||||
```bash
|
||||
npm run add-translation -- --fr
|
||||
@ -214,8 +214,8 @@ apt-get install build-essential libkrb5-dev gcc g++
|
||||
|
||||
## 5. Known errors
|
||||
* EXIF orientation tag:
|
||||
* There is no nice way to handle EXIF orientation tag properly.
|
||||
The page handles these photos, but might cause same error in the user experience (e.g.: the pages loads those photos slower. See issue [#11](https://github.com/bpatrik/pigallery2/issues/11))
|
||||
* Some photos code the orientation tag and with/height in a less conventional format, like the "duck photo" in [#19](https://github.com/bpatrik/pigallery2/issues/19).
|
||||
After Browsers support orientation tag natively [#172](https://github.com/bpatrik/pigallery2/issues/172), I could not find a solution for that.
|
||||
* Video support on weak servers (like raspberry pi) with low upload rate
|
||||
* video playback may use up too much resources and the server might not response for a while. Enable video transcoding in the app, to transcode the videos to lover bitrate.
|
||||
|
||||
|
105
package-lock.json
generated
105
package-lock.json
generated
@ -3361,15 +3361,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/gm": {
|
||||
"version": "1.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/gm/-/gm-1.18.6.tgz",
|
||||
"integrity": "sha512-ghb4ZYoSovciyS/BcbGhH/3VBmTu6Hit7rIdtIZnzVjT/a2OOAp4ZrdJGyW0PtF94XXzJC5li7WgEpg8saHfPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/gulp": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-4.0.6.tgz",
|
||||
@ -4839,18 +4830,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"array-parallel": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
|
||||
"integrity": "sha1-j3hTCJJu1apHjEfmTRszS2wMlH0=",
|
||||
"optional": true
|
||||
},
|
||||
"array-series": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
|
||||
"integrity": "sha1-3103v8XC7wdV4qpPkv6ufUtaly8=",
|
||||
"optional": true
|
||||
},
|
||||
"array-slice": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
|
||||
@ -7201,16 +7180,6 @@
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
|
||||
"integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"lru-cache": "^4.0.1",
|
||||
"which": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"crypto-browserify": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
|
||||
@ -8475,19 +8444,11 @@
|
||||
"integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI="
|
||||
},
|
||||
"exifreader": {
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-2.12.0.tgz",
|
||||
"integrity": "sha512-Z0unewjtJ5uwiN5Q6qzPIC+LnM6S/oTFdM4fvbhhqZbDxaK6C4CkLOPltYwODL7Gvz1YwflewSRIqRPfBqoR9w==",
|
||||
"version": "3.12.2",
|
||||
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-3.12.2.tgz",
|
||||
"integrity": "sha512-4+WpOVVW0iVbdMq4JnsmOx7vOurKEwb6vfopVkDW/g/JSIpdflkH6Q04yEBvh4ZzAU9l0UbvsSGf9LaW/Bu14w==",
|
||||
"requires": {
|
||||
"@types/node": "^10.12.18",
|
||||
"xmldom": "^0.1.27"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "10.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz",
|
||||
"integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA=="
|
||||
}
|
||||
"xmldom": "^0.1.31"
|
||||
}
|
||||
},
|
||||
"exit": {
|
||||
@ -10138,35 +10099,6 @@
|
||||
"sparkles": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"gm": {
|
||||
"version": "1.23.1",
|
||||
"resolved": "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz",
|
||||
"integrity": "sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"array-parallel": "~0.1.3",
|
||||
"array-series": "~0.1.5",
|
||||
"cross-spawn": "^4.0.0",
|
||||
"debug": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"got": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||
@ -10985,9 +10917,9 @@
|
||||
}
|
||||
},
|
||||
"image-size": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.8.3.tgz",
|
||||
"integrity": "sha512-SMtq1AJ+aqHB45c3FsB4ERK0UCiA2d3H1uq8s+8T0Pf8A3W4teyBQyaFaktH6xvZqh+npwlKU7i4fJo0r7TYTg==",
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.9.1.tgz",
|
||||
"integrity": "sha512-yBo6xGGjiWtApYroCGR9wTvaIgande5vmAfTYIld5ss5kN4tyDG5lrW1qGomOXgB05ss7GLXLpDYXEiFqSqkzg==",
|
||||
"requires": {
|
||||
"queue": "6.0.1"
|
||||
}
|
||||
@ -13084,6 +13016,7 @@
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
|
||||
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.2",
|
||||
"yallist": "^2.1.2"
|
||||
@ -15983,7 +15916,8 @@
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.31",
|
||||
@ -18547,9 +18481,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"ts-exif-parser": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-exif-parser/-/ts-exif-parser-0.1.4.tgz",
|
||||
"integrity": "sha512-wLZowFj+25+WM5YQcdUN4YWO8FfIWMgRnDFCjDa94zUyqT3VyeISleCetDGOUWDOq1jho9XLfG8k/Lc9syMqlA=="
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-exif-parser/-/ts-exif-parser-0.2.1.tgz",
|
||||
"integrity": "sha512-Cwhzwn6rM/VtHVr/2Mie2k35lE26rocacRttN6/VlkgBmtkuNSPQT6pPiE6naExDmuXpqJiMqNuJqpKJ7d+vow==",
|
||||
"requires": {
|
||||
"sax": "1.2.4"
|
||||
}
|
||||
},
|
||||
"ts-helpers": {
|
||||
"version": "1.1.2",
|
||||
@ -21311,9 +21248,10 @@
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
|
||||
},
|
||||
"xmldom": {
|
||||
"version": "0.1.27",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
|
||||
"integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk="
|
||||
"version": "0.1.31",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
|
||||
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
|
||||
"optional": true
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
@ -21335,7 +21273,8 @@
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
|
||||
"dev": true
|
||||
},
|
||||
"yargonaut": {
|
||||
"version": "1.1.4",
|
||||
|
@ -36,17 +36,17 @@
|
||||
"cookie-session": "2.0.0-beta.3",
|
||||
"csurf": "1.10.0",
|
||||
"ejs": "3.0.1",
|
||||
"exifreader": "2.12.0",
|
||||
"exifreader": "3.12.2",
|
||||
"express": "4.17.1",
|
||||
"express-unless": "0.5.0",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"image-size": "0.8.3",
|
||||
"image-size": "0.9.1",
|
||||
"jimp": "0.9.3",
|
||||
"locale": "0.1.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.0",
|
||||
"sqlite3": "4.1.1",
|
||||
"ts-exif-parser": "0.1.4",
|
||||
"ts-exif-parser": "0.2.1",
|
||||
"ts-node-iptc": "1.0.11",
|
||||
"typeconfig": "2.0.9",
|
||||
"typeorm": "0.2.21",
|
||||
|
@ -19,7 +19,7 @@ const ffmpeg = FFmpegFactory.get();
|
||||
export class MetadataLoader {
|
||||
|
||||
public static loadVideoMetadata(fullPath: string): Promise<VideoMetadata> {
|
||||
return new Promise<VideoMetadata>((resolve, reject) => {
|
||||
return new Promise<VideoMetadata>((resolve) => {
|
||||
const metadata: VideoMetadata = {
|
||||
size: {
|
||||
width: 1,
|
||||
@ -50,10 +50,12 @@ export class MetadataLoader {
|
||||
metadata.size.width = data.streams[i].width;
|
||||
metadata.size.height = data.streams[i].height;
|
||||
|
||||
if (Utils.isInt32(parseInt(data.streams[i].rotation, 10)) &&
|
||||
if (Utils.isInt32(parseInt(data.streams[i].rotation, 10)) &&
|
||||
(Math.abs(parseInt(data.streams[i].rotation, 10)) / 90) % 2 === 1) {
|
||||
metadata.size.width = data.streams[i].height;
|
||||
metadata.size.height = data.streams[i].width;
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
metadata.size.width = data.streams[i].height;
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
metadata.size.height = data.streams[i].width;
|
||||
}
|
||||
|
||||
if (Utils.isInt32(Math.floor(parseFloat(data.streams[i].duration) * 1000))) {
|
||||
@ -246,6 +248,8 @@ export class MetadataLoader {
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return resolve(metadata);
|
||||
} catch (err) {
|
||||
return reject({file: fullPath, error: err});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {Metadata, Sharp} from 'sharp';
|
||||
import {Dimensions, State} from 'gm';
|
||||
import {Logger} from '../../Logger';
|
||||
import {FfmpegCommand, FfprobeData} from 'fluent-ffmpeg';
|
||||
import {FFmpegFactory} from '../FFmpegFactory';
|
||||
@ -215,7 +214,7 @@ export class ImageRendererFactory {
|
||||
fit: 'cover'
|
||||
});
|
||||
}
|
||||
await image.jpeg().toFile(input.outPath);
|
||||
await image.withMetadata().jpeg().toFile(input.outPath);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {DirectoryDTO} from './DirectoryDTO';
|
||||
import {PhotoDTO} from './PhotoDTO';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
import {FileDTO} from './FileDTO';
|
||||
import {SupportedFormats} from '../SupportedFormats';
|
||||
|
||||
@ -39,18 +38,6 @@ export module MediaDTO {
|
||||
(<PhotoDTO>media).metadata.positionData.GPSData.longitude));
|
||||
};
|
||||
|
||||
export const isSideWay = (media: MediaDTO): boolean => {
|
||||
if (!(<PhotoDTO>media).metadata.orientation) {
|
||||
return false;
|
||||
}
|
||||
const photo = <PhotoDTO>media;
|
||||
return photo.metadata.orientation === OrientationTypes.LEFT_TOP ||
|
||||
photo.metadata.orientation === OrientationTypes.RIGHT_TOP ||
|
||||
photo.metadata.orientation === OrientationTypes.LEFT_BOTTOM ||
|
||||
photo.metadata.orientation === OrientationTypes.RIGHT_BOTTOM;
|
||||
|
||||
};
|
||||
|
||||
export const isPhoto = (media: FileDTO): boolean => {
|
||||
return !MediaDTO.isVideo(media);
|
||||
};
|
||||
@ -86,16 +73,7 @@ export module MediaDTO {
|
||||
};
|
||||
|
||||
|
||||
export const getRotatedSize = (photo: MediaDTO): MediaDimension => {
|
||||
if (isSideWay(photo)) {
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
return {width: photo.metadata.size.height, height: photo.metadata.size.width};
|
||||
}
|
||||
return photo.metadata.size;
|
||||
};
|
||||
|
||||
export const calcRotatedAspectRatio = (photo: MediaDTO): number => {
|
||||
const size = getRotatedSize(photo);
|
||||
return size.width / size.height;
|
||||
export const calcAspectRatio = (photo: MediaDTO): number => {
|
||||
return photo.metadata.size.width / photo.metadata.size.height;
|
||||
};
|
||||
}
|
||||
|
@ -63,7 +63,6 @@ import {IconizeSortingMethod} from './pipes/IconizeSortingMethod';
|
||||
import {StringifySortingMethod} from './pipes/StringifySortingMethod';
|
||||
import {RandomQueryBuilderGalleryComponent} from './ui/gallery/random-query-builder/random-query-builder.gallery.component';
|
||||
import {RandomPhotoSettingsComponent} from './ui/settings/random-photo/random-photo.settings.component';
|
||||
import {FixOrientationPipe} from './pipes/FixOrientationPipe';
|
||||
import {VideoSettingsComponent} from './ui/settings/video/video.settings.component';
|
||||
import {DurationPipe} from './pipes/DurationPipe';
|
||||
import {MapService} from './ui/gallery/map/map.service';
|
||||
@ -211,7 +210,6 @@ export function translationsFactory(locale: string) {
|
||||
StringifyRole,
|
||||
IconizeSortingMethod,
|
||||
StringifySortingMethod,
|
||||
FixOrientationPipe,
|
||||
DurationPipe,
|
||||
FileSizePipe
|
||||
],
|
||||
|
@ -1,91 +0,0 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
|
||||
/**
|
||||
* This pipe is used to fix thumbnail and media orientation based on their exif orientation tag
|
||||
*/
|
||||
|
||||
@Pipe({name: 'fixOrientation'})
|
||||
export class FixOrientationPipe implements PipeTransform {
|
||||
|
||||
public static transform(imageSrc: string, orientation: OrientationTypes): Promise<string> {
|
||||
if (orientation === OrientationTypes.TOP_LEFT) {
|
||||
return Promise.resolve(imageSrc);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const img = new Image();
|
||||
|
||||
// noinspection SpellCheckingInspection
|
||||
img.onload = () => {
|
||||
const width = img.width,
|
||||
height = img.height,
|
||||
canvas = document.createElement('canvas'),
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// set proper canvas dimensions before transform & export
|
||||
if (OrientationTypes.BOTTOM_LEFT < orientation &&
|
||||
orientation <= OrientationTypes.LEFT_BOTTOM) {
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
canvas.width = height;
|
||||
// noinspection JSSuspiciousNameCombination
|
||||
canvas.height = width;
|
||||
} else {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
|
||||
// transform context before drawing image
|
||||
|
||||
// transform function parameters:
|
||||
// a Horizontal scaling
|
||||
// b Horizontal skewing
|
||||
// c Vertical skewing
|
||||
// d Vertical scaling
|
||||
// e Horizontal moving
|
||||
// f Vertical moving
|
||||
|
||||
switch (orientation) {
|
||||
case OrientationTypes.TOP_RIGHT: // 2
|
||||
ctx.transform(-1, 0, 0, 1, width, 0);
|
||||
break;
|
||||
case OrientationTypes.BOTTOM_RIGHT: // 3
|
||||
ctx.transform(-1, 0, 0, -1, width, height);
|
||||
break;
|
||||
case OrientationTypes.BOTTOM_LEFT: // 4
|
||||
ctx.transform(1, 0, 0, -1, 0, height);
|
||||
break;
|
||||
case OrientationTypes.LEFT_TOP: // 5
|
||||
ctx.transform(0, 1, 1, 0, 0, 0);
|
||||
break;
|
||||
case OrientationTypes.RIGHT_TOP: // 6
|
||||
ctx.transform(0, 1, -1, 0, height, 0);
|
||||
break;
|
||||
case OrientationTypes.RIGHT_BOTTOM: // 7
|
||||
ctx.transform(0, -1, -1, 0, height, width);
|
||||
break;
|
||||
case OrientationTypes.LEFT_BOTTOM: // 8
|
||||
ctx.transform(0, -1, 1, 0, 0, width);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// draw image
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
// export base64
|
||||
resolve(canvas.toDataURL());
|
||||
};
|
||||
|
||||
img.onerror = () => {
|
||||
resolve(imageSrc);
|
||||
};
|
||||
|
||||
img.src = imageSrc;
|
||||
});
|
||||
}
|
||||
|
||||
transform(imageSrc: string, orientation: OrientationTypes): Promise<string> {
|
||||
return FixOrientationPipe.transform(imageSrc, orientation);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
<ng-template #popTemplate>
|
||||
<img alt="{{media.name}}"
|
||||
class="big-icon"
|
||||
[src]="thumbnail.Src | fixOrientation:Orientation | async"
|
||||
[src]="thumbnail.Src"
|
||||
*ngIf="thumbnail.Available">
|
||||
</ng-template>
|
||||
|
||||
@ -10,6 +10,6 @@
|
||||
class="icon"
|
||||
[popover]="popTemplate"
|
||||
triggers="mouseenter:mouseleave"
|
||||
[src]="thumbnail.Src | fixOrientation:Orientation | async"
|
||||
[src]="thumbnail.Src"
|
||||
*ngIf="thumbnail.Available">
|
||||
</div>
|
||||
|
@ -1,8 +1,6 @@
|
||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {MediaDTO} from '../../../../../common/entities/MediaDTO';
|
||||
import {IconThumbnail, ThumbnailManagerService} from '../../gallery/thumbnailManager.service';
|
||||
import {PhotoDTO} from '../../../../../common/entities/PhotoDTO';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
import {MediaIcon} from '../../gallery/MediaIcon';
|
||||
|
||||
@Component({
|
||||
@ -19,12 +17,6 @@ export class DuplicatesPhotoComponent implements OnInit, OnDestroy {
|
||||
constructor(private thumbnailService: ThumbnailManagerService) {
|
||||
}
|
||||
|
||||
get Orientation() {
|
||||
if (!this.media) {
|
||||
return OrientationTypes.TOP_LEFT;
|
||||
}
|
||||
return (<PhotoDTO>this.media).metadata.orientation || OrientationTypes.TOP_LEFT;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.thumbnail = this.thumbnailService.getIcon(new MediaIcon(this.media));
|
||||
|
@ -54,28 +54,3 @@ a:hover .photo-container {
|
||||
width: 180px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* transforming media, based on exif orientation*/
|
||||
.photo-orientation-1 {
|
||||
}
|
||||
.photo-orientation-2 {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
.photo-orientation-3 {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.photo-orientation-4 {
|
||||
transform: rotate(180deg) rotateY(180deg);
|
||||
}
|
||||
.photo-orientation-5 {
|
||||
transform: rotate(270deg) rotateY(180deg);
|
||||
}
|
||||
.photo-orientation-6 {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.photo-orientation-7 {
|
||||
transform: rotate(90deg) rotateY(180deg);
|
||||
}
|
||||
.photo-orientation-8 {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="photo-container"
|
||||
[style.width.px]="size"
|
||||
[style.height.px]="size">
|
||||
<div [ngClass]="'photo photo-orientation-'+Orientation"
|
||||
<div class="photo"
|
||||
*ngIf="thumbnail && thumbnail.Available"
|
||||
[style.background-image]="getSanitizedThUrl()"></div>
|
||||
|
||||
|
@ -7,8 +7,7 @@ import {Media} from '../../Media';
|
||||
import {Thumbnail, ThumbnailManagerService} from '../../thumbnailManager.service';
|
||||
import {QueryService} from '../../../../model/query.service';
|
||||
import {MediaDTO} from '../../../../../../common/entities/MediaDTO';
|
||||
import {PhotoDTO} from '../../../../../../common/entities/PhotoDTO';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-directory',
|
||||
@ -35,11 +34,6 @@ export class GalleryDirectoryComponent implements OnInit, OnDestroy {
|
||||
return null;
|
||||
}
|
||||
|
||||
public get Orientation(): OrientationTypes {
|
||||
return (this.SamplePhoto && (this.SamplePhoto as PhotoDTO).metadata.orientation)
|
||||
|| OrientationTypes.TOP_LEFT;
|
||||
}
|
||||
|
||||
getSanitizedThUrl() {
|
||||
return this._sanitizer.bypassSecurityTrustStyle('url(' +
|
||||
encodeURI(this.thumbnail.Src)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {Media} from '../Media';
|
||||
import {MediaDTO} from '../../../../../common/entities/MediaDTO';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
import {PhotoDTO} from '../../../../../common/entities/PhotoDTO';
|
||||
import {VideoDTO} from '../../../../../common/entities/VideoDTO';
|
||||
|
||||
@ -11,10 +10,6 @@ export class GridMedia extends Media {
|
||||
super(media, renderWidth, renderHeight);
|
||||
}
|
||||
|
||||
public get Orientation(): OrientationTypes {
|
||||
return (<PhotoDTO>this.media).metadata.orientation || OrientationTypes.TOP_LEFT;
|
||||
}
|
||||
|
||||
get Video(): VideoDTO {
|
||||
return <VideoDTO>this.media;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export class GridRowBuilder {
|
||||
public calcRowHeight(): number {
|
||||
let width = 0;
|
||||
for (let i = 0; i < this.photoRow.length; i++) {
|
||||
const size = MediaDTO.getRotatedSize(this.photoRow[i]);
|
||||
const size = this.photoRow[i].metadata.size;
|
||||
width += (size.width / size.height); // summing up aspect ratios
|
||||
}
|
||||
const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1
|
||||
|
@ -182,7 +182,7 @@ export class GalleryGridComponent implements OnChanges, OnInit, AfterViewInit, O
|
||||
const imageHeight = rowHeight - (this.IMAGE_MARGIN * 2);
|
||||
|
||||
photoRowBuilder.getPhotoRow().forEach((photo) => {
|
||||
const imageWidth = imageHeight * MediaDTO.calcRotatedAspectRatio(photo);
|
||||
const imageWidth = imageHeight * MediaDTO.calcAspectRatio(photo);
|
||||
this.photosToRender.push(new GridMedia(photo, imageWidth, imageHeight, this.renderedPhotoIndex));
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div #photoContainer class="photo-container" (mouseover)="mouseOver()" (mouseout)="mouseOut()">
|
||||
|
||||
|
||||
<img alt="{{gridMedia.media.name}}" #img [src]="thumbnail.Src | fixOrientation:gridMedia.Orientation | async"
|
||||
<img alt="{{gridMedia.media.name}}" #img [src]="thumbnail.Src"
|
||||
*ngIf="thumbnail.Available">
|
||||
|
||||
<app-gallery-grid-photo-loading
|
||||
|
@ -307,7 +307,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
||||
return;
|
||||
}
|
||||
|
||||
const photoAspect = MediaDTO.calcRotatedAspectRatio(this.activePhoto.gridMedia.media);
|
||||
const photoAspect = MediaDTO.calcAspectRatio(this.activePhoto.gridMedia.media);
|
||||
const widthFilled = photoAspect > this.photoFrameDim.aspect;
|
||||
const divWidth = this.photoFrameDim.width;
|
||||
const divHeight = this.photoFrameDim.height;
|
||||
@ -368,7 +368,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
||||
}
|
||||
|
||||
|
||||
const photoAspect = MediaDTO.calcRotatedAspectRatio(this.activePhoto.gridMedia.media);
|
||||
const photoAspect = MediaDTO.calcAspectRatio(this.activePhoto.gridMedia.media);
|
||||
|
||||
if (photoAspect < this.photoFrameDim.aspect) {
|
||||
this.faceContainerDim.height = this.photoFrameDim.height;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {Component, ElementRef, EventEmitter, Input, OnChanges, Output, ViewChild} from '@angular/core';
|
||||
import {GridMedia} from '../../grid/GridMedia';
|
||||
import {FixOrientationPipe} from '../../../../pipes/FixOrientationPipe';
|
||||
import {MediaDTO} from '../../../../../../common/entities/MediaDTO';
|
||||
import {DomSanitizer, SafeStyle} from '@angular/platform-browser';
|
||||
import {SupportedFormats} from '../../../../../../common/SupportedFormats';
|
||||
@ -111,11 +110,10 @@ export class GalleryLightboxMediaComponent implements OnChanges {
|
||||
this.setImageSize();
|
||||
}
|
||||
if (this.thumbnailSrc == null && this.gridMedia && this.ThumbnailUrl !== null) {
|
||||
FixOrientationPipe.transform(this.ThumbnailUrl, this.gridMedia.Orientation)
|
||||
.then((src) => this.thumbnailSrc = src);
|
||||
this.thumbnailSrc = this.ThumbnailUrl;
|
||||
}
|
||||
|
||||
this.loadPhoto().catch(console.error);
|
||||
this.loadPhoto();
|
||||
|
||||
}
|
||||
|
||||
@ -161,7 +159,7 @@ export class GalleryLightboxMediaComponent implements OnChanges {
|
||||
this.videoSourceError.emit();
|
||||
}
|
||||
|
||||
private async loadPhoto() {
|
||||
private loadPhoto() {
|
||||
if (!this.gridMedia || !this.loadMedia || !this.gridMedia.isPhoto()) {
|
||||
return;
|
||||
}
|
||||
@ -169,16 +167,16 @@ export class GalleryLightboxMediaComponent implements OnChanges {
|
||||
if (this.zoom === 1) {
|
||||
if (this.photo.src == null) {
|
||||
if (Config.Client.Media.Photo.Converting.enabled === true) {
|
||||
this.photo.src = await FixOrientationPipe.transform(this.gridMedia.getBestFitMediaPath(), this.gridMedia.Orientation);
|
||||
this.photo.src = this.gridMedia.getBestFitMediaPath();
|
||||
this.photo.isBestFit = true;
|
||||
} else {
|
||||
this.photo.src = await FixOrientationPipe.transform(this.gridMedia.getMediaPath(), this.gridMedia.Orientation);
|
||||
this.photo.src = this.gridMedia.getMediaPath();
|
||||
this.photo.isBestFit = false;
|
||||
}
|
||||
}
|
||||
// on zoom load high res photo
|
||||
} else if ((this.photo.isBestFit === true || this.photo.src == null)) {
|
||||
this.photo.src = await FixOrientationPipe.transform(this.gridMedia.getMediaPath(), this.gridMedia.Orientation);
|
||||
this.photo.src = this.gridMedia.getMediaPath();
|
||||
this.photo.isBestFit = false;
|
||||
}
|
||||
}
|
||||
@ -194,7 +192,7 @@ export class GalleryLightboxMediaComponent implements OnChanges {
|
||||
}
|
||||
|
||||
|
||||
const photoAspect = MediaDTO.calcRotatedAspectRatio(this.gridMedia.media);
|
||||
const photoAspect = MediaDTO.calcAspectRatio(this.gridMedia.media);
|
||||
|
||||
if (photoAspect < this.windowAspect) {
|
||||
this.imageSize.height = '100';
|
||||
|
@ -46,7 +46,7 @@
|
||||
<img *ngIf="photo.preview.thumbnail.Src"
|
||||
[style.width.px]="photo.preview.width"
|
||||
[style.height.px]="photo.preview.height"
|
||||
[src]="photo.preview.thumbnail.Src | fixOrientation:photo.orientation | async">
|
||||
[src]="photo.preview.thumbnail.Src">
|
||||
<div class="preview-loading"
|
||||
*ngIf="!photo.preview.thumbnail.Src"
|
||||
[style.width.px]="photo.preview.width"
|
||||
|
@ -6,15 +6,12 @@ import {IconThumbnail, Thumbnail, ThumbnailManagerService} from '../../thumbnail
|
||||
import {MediaIcon} from '../../MediaIcon';
|
||||
import {Media} from '../../Media';
|
||||
import {PageHelper} from '../../../../model/page.helper';
|
||||
import {OrientationTypes} from 'ts-exif-parser';
|
||||
import {MediaDTO} from '../../../../../../common/entities/MediaDTO';
|
||||
import {FileDTO} from '../../../../../../common/entities/FileDTO';
|
||||
import {Utils} from '../../../../../../common/Utils';
|
||||
import {Config} from '../../../../../../common/config/public/Config';
|
||||
import {MapService} from '../map.service';
|
||||
import {LatLng, Point} from 'leaflet';
|
||||
import {MapComponent} from '@yaga/leaflet-ng2';
|
||||
import {FixOrientationPipe} from '../../../../pipes/FixOrientationPipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-map-lightbox',
|
||||
@ -144,11 +141,11 @@ export class GalleryMapLightboxComponent implements OnChanges, AfterViewInit {
|
||||
}).map(p => {
|
||||
let width = 500;
|
||||
let height = 500;
|
||||
const rotatedSize = MediaDTO.getRotatedSize(p);
|
||||
if (rotatedSize.width > rotatedSize.height) {
|
||||
height = width * (rotatedSize.height / rotatedSize.width);
|
||||
const size = p.metadata.size;
|
||||
if (size.width > size.height) {
|
||||
height = width * (size.height / size.width);
|
||||
} else {
|
||||
width = height * (rotatedSize.width / rotatedSize.height);
|
||||
width = height * (size.width / size.height);
|
||||
}
|
||||
const iconTh = this.thumbnailService.getIcon(new MediaIcon(p));
|
||||
iconTh.Visible = true;
|
||||
@ -157,7 +154,6 @@ export class GalleryMapLightboxComponent implements OnChanges, AfterViewInit {
|
||||
lat: p.metadata.positionData.GPSData.latitude,
|
||||
lng: p.metadata.positionData.GPSData.longitude,
|
||||
iconThumbnail: iconTh,
|
||||
orientation: p.metadata.orientation,
|
||||
preview: {
|
||||
width: width,
|
||||
height: height,
|
||||
@ -167,14 +163,10 @@ export class GalleryMapLightboxComponent implements OnChanges, AfterViewInit {
|
||||
};
|
||||
if (Config.Client.Map.useImageMarkers === true) {
|
||||
if (iconTh.Available === true) {
|
||||
FixOrientationPipe.transform(iconTh.Src, p.metadata.orientation).then((icon) => {
|
||||
obj.iconUrl = icon;
|
||||
});
|
||||
obj.iconUrl = iconTh.Src;
|
||||
} else {
|
||||
iconTh.OnLoad = () => {
|
||||
FixOrientationPipe.transform(iconTh.Src, p.metadata.orientation).then((icon) => {
|
||||
obj.iconUrl = icon;
|
||||
});
|
||||
obj.iconUrl = iconTh.Src;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -258,7 +250,6 @@ export interface MapPhoto {
|
||||
lng: number;
|
||||
iconUrl?: string;
|
||||
iconThumbnail: IconThumbnail;
|
||||
orientation: OrientationTypes;
|
||||
preview: {
|
||||
width: number;
|
||||
height: number;
|
||||
|
@ -100,7 +100,7 @@ export class SettingsEntryComponent implements ControlValueAccessor, Validator,
|
||||
if (this.state.type === 'array' &&
|
||||
(this.state.arrayType === 'string' || this.isNumberArray)) {
|
||||
value = value.replace(new RegExp(',', 'g'), ';');
|
||||
if(this.allowSpaces === false) {
|
||||
if (this.allowSpaces === false) {
|
||||
value = value.replace(new RegExp(' ', 'g'), ';');
|
||||
}
|
||||
this.state.value = value.split(';').filter((v: string) => v !== '');
|
||||
|
Loading…
Reference in New Issue
Block a user