@knora/viewer
Version:
Knora ui module: viewer
562 lines (549 loc) • 75 kB
JavaScript
import * as tslib_1 from "tslib";
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChange } from '@angular/core';
import { Constants, Point2D } from '@knora/api';
/**
* Represents a region.
* Contains a reference to the resource representing the region and its geometries.
*/
var ImageRegion = /** @class */ (function () {
/**
*
* @param regionResource a resource of type Region
*/
function ImageRegion(regionResource) {
this.regionResource = regionResource;
}
/**
* Get all geometry information belonging to this region.
*
* @returns
*/
ImageRegion.prototype.getGeometries = function () {
return this.regionResource.properties[Constants.HasGeometry];
};
return ImageRegion;
}());
export { ImageRegion };
/**
* Represents an image including its regions.
*/
var StillImageRepresentation = /** @class */ (function () {
/**
*
* @param stillImageFileValue a [[ReadStillImageFileValue]] representing an image.
* @param regions the regions belonging to the image.
*/
function StillImageRepresentation(stillImageFileValue, regions) {
this.stillImageFileValue = stillImageFileValue;
this.regions = regions;
}
return StillImageRepresentation;
}());
export { StillImageRepresentation };
/**
* Represents a geometry belonging to a specific region.
*/
var GeometryForRegion = /** @class */ (function () {
/**
*
* @param geometry the geometrical information.
* @param region the region the geometry belongs to.
*/
function GeometryForRegion(geometry, region) {
this.geometry = geometry;
this.region = region;
}
return GeometryForRegion;
}());
export { GeometryForRegion };
/**
* This component creates a OpenSeadragon viewer instance.
* Accepts an array of ReadResource containing (among other resources) ReadStillImageFileValues to be rendered.
* @member resources - resources containing (among other resources) the StillImageFileValues and incoming regions to be rendered. (Use as angular @Input data binding property.)
*/
var StillImageComponent = /** @class */ (function () {
function StillImageComponent(elementRef) {
this.elementRef = elementRef;
this.currentImageIndex = new EventEmitter();
this.regionHovered = new EventEmitter();
this.regions = {};
}
StillImageComponent_1 = StillImageComponent;
/**
* Calculates the surface of a rectangular region.
*
* @param geom the region's geometry.
* @returns the surface.
*/
StillImageComponent.surfaceOfRectangularRegion = function (geom) {
if (geom.type !== 'rectangle') {
console.log('expected rectangular region, but ' + geom.type + ' given');
return 0;
}
var w = Math.max(geom.points[0].x, geom.points[1].x) - Math.min(geom.points[0].x, geom.points[1].x);
var h = Math.max(geom.points[0].y, geom.points[1].y) - Math.min(geom.points[0].y, geom.points[1].y);
return w * h;
};
/**
* Prepare tile sources from the given sequence of [[ReadStillImageFileValue]].
*
* @param imagesToDisplay the given file values to de displayed.
* @returns the tile sources to be passed to OSD viewer.
*/
StillImageComponent.prepareTileSourcesFromFileValues = function (imagesToDisplay) {
var e_1, _a;
var imageXOffset = 0;
var imageYOffset = 0;
var tileSources = [];
try {
for (var imagesToDisplay_1 = tslib_1.__values(imagesToDisplay), imagesToDisplay_1_1 = imagesToDisplay_1.next(); !imagesToDisplay_1_1.done; imagesToDisplay_1_1 = imagesToDisplay_1.next()) {
var image = imagesToDisplay_1_1.value;
var sipiBasePath = image.iiifBaseUrl + '/' + image.filename;
var width = image.dimX;
var height = image.dimY;
// construct OpenSeadragon tileSources according to https://openseadragon.github.io/docs/OpenSeadragon.Viewer.html#open
tileSources.push({
// construct IIIF tileSource configuration according to
// http://iiif.io/api/image/2.1/#technical-properties
// see also http://iiif.io/api/image/2.0/#a-implementation-notes
'tileSource': {
'@context': 'http://iiif.io/api/image/2/context.json',
'@id': sipiBasePath,
'height': height,
'width': width,
'profile': ['http://iiif.io/api/image/2/level2.json'],
'protocol': 'http://iiif.io/api/image',
'tiles': [{
'scaleFactors': [1, 2, 4, 8, 16, 32],
'width': 1024
}]
},
'x': imageXOffset,
'y': imageYOffset
});
imageXOffset++;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (imagesToDisplay_1_1 && !imagesToDisplay_1_1.done && (_a = imagesToDisplay_1.return)) _a.call(imagesToDisplay_1);
}
finally { if (e_1) throw e_1.error; }
}
return tileSources;
};
StillImageComponent.prototype.ngOnChanges = function (changes) {
if (changes['images'] && changes['images'].isFirstChange()) {
this.setupViewer();
// this.currentImageIri.emit(this.images[this.viewer.currentPage()].stillImageFileValue.id);
}
if (changes['images']) {
this.openImages();
this.renderRegions();
this.unhighlightAllRegions();
if (this.activateRegion !== undefined) {
this.highlightRegion(this.activateRegion);
}
}
else if (changes['activateRegion']) {
this.unhighlightAllRegions();
if (this.activateRegion !== undefined) {
this.highlightRegion(this.activateRegion);
}
}
if (this.viewer) {
// console.log(this.viewer);
// this.currentImageIndex.emit(this.viewer.currentPage());
}
};
StillImageComponent.prototype.ngOnInit = function () {
// initialisation is done on first run of ngOnChanges
};
StillImageComponent.prototype.ngOnDestroy = function () {
if (this.viewer) {
this.viewer.destroy();
this.viewer = undefined;
}
};
/**
* Renders all ReadStillImageFileValues to be found in [[this.images]].
* (Although this.images is a Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays.
* Use this method if additional ReadStillImageFileValues were added to this.images after creation/assignment of the this.images array.)
*/
StillImageComponent.prototype.updateImages = function () {
if (!this.viewer) {
this.setupViewer();
}
this.openImages();
};
/**
* Renders all regions to be found in [[this.images]].
* (Although this.images is a Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays.
* Use this method if additional regions were added to the resources.images)
*/
StillImageComponent.prototype.updateRegions = function () {
if (!this.viewer) {
this.setupViewer();
}
this.renderRegions();
};
/**
* Highlights the polygon elements associated with the given region.
*
* @param regionIri the Iri of the region whose polygon elements should be highlighted..
*/
StillImageComponent.prototype.highlightRegion = function (regionIri) {
var e_2, _a;
var activeRegion = this.regions[regionIri];
if (activeRegion !== undefined) {
try {
for (var activeRegion_1 = tslib_1.__values(activeRegion), activeRegion_1_1 = activeRegion_1.next(); !activeRegion_1_1.done; activeRegion_1_1 = activeRegion_1.next()) {
var pol = activeRegion_1_1.value;
pol.setAttribute('class', 'roi-svgoverlay active');
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (activeRegion_1_1 && !activeRegion_1_1.done && (_a = activeRegion_1.return)) _a.call(activeRegion_1);
}
finally { if (e_2) throw e_2.error; }
}
}
};
/**
* Unhighlights the polygon elements of all regions.
*
*/
StillImageComponent.prototype.unhighlightAllRegions = function () {
var e_3, _a;
for (var reg in this.regions) {
if (this.regions.hasOwnProperty(reg)) {
try {
for (var _b = tslib_1.__values(this.regions[reg]), _c = _b.next(); !_c.done; _c = _b.next()) {
var pol = _c.value;
pol.setAttribute('class', 'roi-svgoverlay');
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_3) throw e_3.error; }
}
}
}
};
/**
* Initializes the OpenSeadragon viewer
*/
StillImageComponent.prototype.setupViewer = function () {
var viewerContainer = this.elementRef.nativeElement.getElementsByClassName('osd-container')[0];
var osdOptions = {
element: viewerContainer,
sequenceMode: true,
showReferenceStrip: true,
showNavigator: true,
zoomInButton: 'KUI_OSD_ZOOM_IN',
zoomOutButton: 'KUI_OSD_ZOOM_OUT',
previousButton: 'KUI_OSD_PREV_PAGE',
nextButton: 'KUI_OSD_NEXT_PAGE',
homeButton: 'KUI_OSD_HOME',
fullPageButton: 'KUI_OSD_FULL_PAGE',
rotateLeftButton: 'KUI_OSD_ROTATE_LEFT',
rotateRightButton: 'KUI_OSD_ROTATE_RIGHT' // doesn't work yet
};
this.viewer = new OpenSeadragon.Viewer(osdOptions);
this.viewer.addHandler('full-screen', function (args) {
if (args.fullScreen) {
viewerContainer.classList.add('fullscreen');
}
else {
viewerContainer.classList.remove('fullscreen');
}
});
this.viewer.addHandler('resize', function (args) {
args.eventSource.svgOverlay().resize();
});
var fileValues = this.images.map(function (img) {
return img;
});
this.viewer.addHandler('page', function (event) {
console.log('event on page', event);
console.log('Now on page', event.page);
var index = event.page;
console.log('= id', fileValues[index].id);
var id = fileValues[index].id;
// return id;
});
//
// this.currentImageIri.emit(this.viewer.getCurrentImage());
};
/**
* Adds all images in this.images to the viewer.
* Images are positioned in a horizontal row next to each other.
*/
StillImageComponent.prototype.openImages = function () {
// imageXOffset controls the x coordinate of the left side of each image in the OpenSeadragon viewport coordinate system.
// The first image has its left side at x = 0, and all images are scaled to have a width of 1 in viewport coordinates.
// see also: https://openseadragon.github.io/examples/viewport-coordinates/
var fileValues = this.images.map(function (img) {
return img;
});
// display only the defined range of this.images
var tileSources = StillImageComponent_1.prepareTileSourcesFromFileValues(fileValues);
this.removeOverlays();
this.viewer.open(tileSources);
};
/**
* Removes SVG overlays from the DOM.
*/
StillImageComponent.prototype.removeOverlays = function () {
var e_4, _a;
for (var reg in this.regions) {
if (this.regions.hasOwnProperty(reg)) {
try {
for (var _b = tslib_1.__values(this.regions[reg]), _c = _b.next(); !_c.done; _c = _b.next()) {
var pol = _c.value;
if (pol instanceof SVGPolygonElement) {
pol.remove();
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_4) throw e_4.error; }
}
}
}
this.regions = {};
// TODO: make this work by using osdviewer's addOverlay method
this.viewer.clearOverlays();
};
/**
* Adds a ROI-overlay to the viewer for every region of every image in this.images
*/
StillImageComponent.prototype.renderRegions = function () {
var e_5, _a;
this.removeOverlays();
var imageXOffset = 0; // see documentation in this.openImages() for the usage of imageXOffset
try {
for (var _b = tslib_1.__values(this.images), _c = _b.next(); !_c.done; _c = _b.next()) {
var image = _c.value;
var aspectRatio = (image.dimY / image.dimX);
// collect all geometries belonging to this page
var geometries = [];
/* TODO: knora-api-js-lib integration needs another region handling?
image.regions.map((reg) => {
this.regions[reg.regionResource.id] = [];
const geoms = reg.getGeometries();
geoms.map((geom) => {
const geomForReg = new GeometryForRegion(geom.geometry, reg.regionResource);
geometries.push(geomForReg);
});
});
// sort all geometries belonging to this page
geometries.sort((geom1, geom2) => {
if (geom1.geometry.type === 'rectangle' && geom2.geometry.type === 'rectangle') {
const surf1 = StillImageComponent.surfaceOfRectangularRegion(geom1.geometry);
const surf2 = StillImageComponent.surfaceOfRectangularRegion(geom2.geometry);
// if reg1 is smaller than reg2, return 1
// reg1 then comes after reg2 and thus is rendered later
if (surf1 < surf2) {
return 1;
} else {
return -1;
}
} else {
return 0;
}
});
// render all geometries for this page
for (const geom of geometries) {
const geometry = geom.geometry;
this.createSVGOverlay(geom.region.id, geometry, aspectRatio, imageXOffset, geom.region.label);
}
*/
imageXOffset++;
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_5) throw e_5.error; }
}
};
/**
* Creates and adds a ROI-overlay to the viewer
* @param regionIri the Iri of the region.
* @param geometry - the geometry describing the ROI
* @param aspectRatio - the aspectRatio (h/w) of the image on which the geometry should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the geometry should be placed
* @param toolTip - the tooltip which should be displayed on mousehover of the svg element
*/
StillImageComponent.prototype.createSVGOverlay = function (regionIri, geometry, aspectRatio, xOffset, toolTip) {
var _this = this;
var lineColor = geometry.lineColor;
var lineWidth = geometry.lineWidth;
var svgElement;
switch (geometry.type) {
case 'rectangle':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); // yes, we render rectangles as svg polygon elements
this.addSVGAttributesRectangle(svgElement, geometry, aspectRatio, xOffset);
break;
case 'polygon':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
this.addSVGAttributesPolygon(svgElement, geometry, aspectRatio, xOffset);
break;
case 'circle':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
this.addSVGAttributesCircle(svgElement, geometry, aspectRatio, xOffset);
break;
default:
console.log('ERROR: StillImageOSDViewerComponent.createSVGOverlay: unknown geometryType: ' + geometry.type);
return;
}
svgElement.id = 'roi-svgoverlay-' + Math.random() * 10000;
svgElement.setAttribute('class', 'roi-svgoverlay');
svgElement.setAttribute('style', 'stroke: ' + lineColor + '; stroke-width: ' + lineWidth + 'px;');
// event when a region is clicked (output)
svgElement.addEventListener('click', function () {
_this.regionHovered.emit(regionIri);
}, false);
var svgTitle = document.createElementNS('http://www.w3.org/2000/svg', 'title');
svgTitle.textContent = toolTip;
var svgGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
svgGroup.appendChild(svgTitle);
svgGroup.appendChild(svgElement);
var overlay = this.viewer.svgOverlay();
overlay.node().appendChild(svgGroup); // TODO: use method osdviewer's method addOverlay
this.regions[regionIri].push(svgElement);
};
/**
* Adds the necessary attributes to create a ROI-overlay of type 'rectangle' to a SVGElement
* @param svgElement - an SVGElement (should have type 'polygon' (sic))
* @param geometry - the geometry describing the rectangle
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
StillImageComponent.prototype.addSVGAttributesRectangle = function (svgElement, geometry, aspectRatio, xOffset) {
var pointA = geometry.points[0];
var pointB = geometry.points[1];
// geometry.points contains two diagonally opposed corners of the rectangle, but the order of the corners is arbitrary.
// We therefore construct the upperleft (UL), lowerright (LR), upperright (UR) and lowerleft (LL) positions of the corners with min and max operations.
var positionUL = new Point2D(Math.min(pointA.x, pointB.x), Math.min(pointA.y, pointB.y));
var positionLR = new Point2D(Math.max(pointA.x, pointB.x), Math.max(pointA.y, pointB.y));
var positionUR = new Point2D(Math.max(pointA.x, pointB.x), Math.min(pointA.y, pointB.y));
var positionLL = new Point2D(Math.min(pointA.x, pointB.x), Math.max(pointA.y, pointB.y));
var points = [positionUL, positionUR, positionLR, positionLL];
var viewCoordPoints = this.image2ViewPortCoords(points, aspectRatio, xOffset);
var pointsString = this.createSVGPolygonPointsAttribute(viewCoordPoints);
svgElement.setAttribute('points', pointsString);
};
/**
* Adds the necessary attributes to create a ROI-overlay of type 'polygon' to a SVGElement
* @param svgElement - an SVGElement (should have type 'polygon')
* @param geometry - the geometry describing the polygon
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
StillImageComponent.prototype.addSVGAttributesPolygon = function (svgElement, geometry, aspectRatio, xOffset) {
var viewCoordPoints = this.image2ViewPortCoords(geometry.points, aspectRatio, xOffset);
var pointsString = this.createSVGPolygonPointsAttribute(viewCoordPoints);
svgElement.setAttribute('points', pointsString);
};
/**
* Adds the necessary attributes to create a ROI-overlay of type 'circle' to a SVGElement
* @param svgElement - an SVGElement (should have type 'circle')
* @param geometry - the geometry describing the circle
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
StillImageComponent.prototype.addSVGAttributesCircle = function (svgElement, geometry, aspectRatio, xOffset) {
var viewCoordPoints = this.image2ViewPortCoords(geometry.points, aspectRatio, xOffset);
var cx = String(viewCoordPoints[0].x);
var cy = String(viewCoordPoints[0].y);
// geometry.radius contains not the radius itself, but the coordinates of a (arbitrary) point on the circle.
// We therefore have to calculate the length of the vector geometry.radius to get the actual radius. -> sqrt(x^2 + y^2)
// Since geometry.radius has its y coordinate scaled to the height of the image,
// we need to multiply it with the aspectRatio to get to the scale used by Openseadragon, analoguous to this.image2ViewPortCoords()
var radius = String(Math.sqrt(geometry.radius.x * geometry.radius.x + aspectRatio * aspectRatio * geometry.radius.y * geometry.radius.y));
svgElement.setAttribute('cx', cx);
svgElement.setAttribute('cy', cy);
svgElement.setAttribute('r', radius);
};
/**
* Maps a Point2D[] with coordinates relative to an image to a new Point2D[] with coordinates in the viewport coordinate system of Openseadragon
* see also: https://openseadragon.github.io/examples/viewport-coordinates/
* @param points - an array of points in coordinate system relative to an image
* @param aspectRatio - the aspectRatio (h/w) of the image
* @param xOffset - the x-offset in viewport coordinates of the image
* @returns - a new Point2D[] with coordinates in the viewport coordinate system of Openseadragon
*/
StillImageComponent.prototype.image2ViewPortCoords = function (points, aspectRatio, xOffset) {
return points.map(function (point) {
return new Point2D(point.x + xOffset, point.y * aspectRatio);
});
};
/**
* Returns a string in the format expected by the 'points' attribute of a SVGElement
* @param points - an array of points to be serialized to a string
* @returns - the points serialized to a string in the format expected by the 'points' attribute of a SVGElement
*/
StillImageComponent.prototype.createSVGPolygonPointsAttribute = function (points) {
var pointsString = '';
for (var i in points) {
if (points.hasOwnProperty(i)) {
pointsString += points[i].x;
pointsString += ',';
pointsString += points[i].y;
pointsString += ' ';
}
}
return pointsString;
};
StillImageComponent.prototype.getCurrentImage = function () {
};
var StillImageComponent_1;
StillImageComponent.ctorParameters = function () { return [
{ type: ElementRef }
]; };
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Array)
], StillImageComponent.prototype, "images", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", String)
], StillImageComponent.prototype, "imageCaption", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", String)
], StillImageComponent.prototype, "activateRegion", void 0);
tslib_1.__decorate([
Output(),
tslib_1.__metadata("design:type", EventEmitter)
], StillImageComponent.prototype, "currentImageIndex", void 0);
tslib_1.__decorate([
Output(),
tslib_1.__metadata("design:type", Object)
], StillImageComponent.prototype, "regionHovered", void 0);
StillImageComponent = StillImageComponent_1 = tslib_1.__decorate([
Component({
selector: 'kui-still-image',
template: "<div class=\"still-image-viewer\">\n <div class=\"navigation left\">\n <button mat-button class=\"full-size\" id=\"KUI_OSD_PREV_PAGE\">\n <mat-icon>keyboard_arrow_left</mat-icon>\n </button>\n </div>\n\n <!-- main content with navigation and osd viewer -->\n <div class=\"content\">\n\n <!-- openseadragon (osd) viewer -->\n <div class=\"osd-container\"></div>\n <!-- /openseadragon (osd) -->\n\n <!-- footer with image caption e.g. copyright information -->\n <div class=\"footer\">\n <p class=\"mat-caption\" [innerHtml]=\"imageCaption\"></p>\n </div>\n\n <!-- action panel with tools for image -->\n <mat-toolbar class=\"action\">\n <mat-toolbar-row>\n <!-- home button -->\n <span>\n <button mat-icon-button id=\"KUI_OSD_HOME\">\n <mat-icon>home</mat-icon>\n </button>\n </span>\n <!-- zoom buttons -->\n <span class=\"fill-remaining-space\"></span>\n <span>\n <button mat-icon-button id=\"KUI_OSD_ZOOM_IN\">\n <mat-icon>add</mat-icon>\n </button>\n <button mat-icon-button id=\"KUI_OSD_ZOOM_OUT\">\n <mat-icon>remove</mat-icon>\n </button>\n </span>\n <!-- window button -->\n <span class=\"fill-remaining-space\"></span>\n <span>\n <button mat-icon-button id=\"KUI_OSD_FULL_PAGE\">\n <mat-icon>fullscreen</mat-icon>\n </button>\n </span>\n </mat-toolbar-row>\n </mat-toolbar>\n\n </div>\n\n <div class=\"navigation\">\n <button mat-button class=\"full-size\" id=\"KUI_OSD_NEXT_PAGE\" (click)=\"getCurrentImage()\">\n <mat-icon>keyboard_arrow_right</mat-icon>\n </button>\n </div>\n\n</div>\n\n<!-- simple image viewer e.g. as a preview -->\n<!-- TODO: handle images array -->\n<!--<img *ngIf=\"simple && images?.length === 1; else osdViewer\" [src]=\"simpleImageExample\">-->\n\n\n<!--\n <div>\n <span *ngIf=\"images.length > 1\" (click)=\"gotoLeft()\"><<</span>\n <span *ngIf=\"images.length > 1\" (click)=\"gotoRight()\">>></span>\n </div>\n-->\n",
styles: [".still-image-viewer{display:-webkit-inline-box;display:inline-flex;height:400px;max-width:960px;width:100%}@media (max-height:636px){.still-image-viewer{height:300px}}.still-image-viewer .navigation{height:calc(400px + 64px + 24px);width:36px}.still-image-viewer .navigation .mat-button.full-size{height:100%!important;width:36px!important;padding:0!important;min-width:36px!important}.still-image-viewer .content{height:calc(400px + 64px + 24px);max-width:calc(960px - (2 * 36px));width:calc(100% - (2 * 36px))}.still-image-viewer .content .osd-container{color:#ccc;background-color:#000;height:400px}.still-image-viewer .content .osd-container.fullscreen{max-width:100vw}.still-image-viewer .content .footer p{color:#ccc;background-color:#000;height:24px;margin:0;padding:0 16px}::ng-deep .roi-svgoverlay{opacity:.4;fill:transparent;stroke:#00695c;stroke-width:2px;vector-effect:non-scaling-stroke}.roi-svgoverlay:focus,::ng-deep .roi-svgoverlay:hover{opacity:1}::ng-deep .roi-svgoverlay.active{opacity:1}"]
}),
tslib_1.__metadata("design:paramtypes", [ElementRef])
], StillImageComponent);
return StillImageComponent;
}());
export { StillImageComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RpbGwtaW1hZ2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vQGtub3JhL3ZpZXdlci8iLCJzb3VyY2VzIjpbImxpYi9yZXByZXNlbnRhdGlvbi9zdGlsbC1pbWFnZS9zdGlsbC1pbWFnZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvSCxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBd0UsTUFBTSxZQUFZLENBQUM7QUFXdEg7OztHQUdHO0FBQ0g7SUFFSTs7O09BR0c7SUFDSCxxQkFBcUIsY0FBNEI7UUFBNUIsbUJBQWMsR0FBZCxjQUFjLENBQWM7SUFFakQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxtQ0FBYSxHQUFiO1FBQ0ksT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFvQixDQUFDO0lBQ3BGLENBQUM7SUFDTCxrQkFBQztBQUFELENBQUMsQUFsQkQsSUFrQkM7O0FBRUQ7O0dBRUc7QUFDSDtJQUVJOzs7O09BSUc7SUFDSCxrQ0FBcUIsbUJBQTRDLEVBQVcsT0FBaUI7UUFBeEUsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUF5QjtRQUFXLFlBQU8sR0FBUCxPQUFPLENBQVU7SUFFN0YsQ0FBQztJQUVMLCtCQUFDO0FBQUQsQ0FBQyxBQVhELElBV0M7O0FBRUQ7O0dBRUc7QUFDSDtJQUVJOzs7O09BSUc7SUFDSCwyQkFBcUIsUUFBd0IsRUFBVyxNQUFjO1FBQWpELGFBQVEsR0FBUixRQUFRLENBQWdCO1FBQVcsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUN0RSxDQUFDO0lBRUwsd0JBQUM7QUFBRCxDQUFDLEFBVkQsSUFVQzs7QUFXRDs7OztHQUlHO0FB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ZW50LCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFNpbXBsZUNoYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RhbnRzLCBQb2ludDJELCBSZWFkR2VvbVZhbHVlLCBSZWFkUmVzb3VyY2UsIFJlYWRTdGlsbEltYWdlRmlsZVZhbHVlLCBSZWdpb25HZW9tZXRyeSB9IGZyb20gJ0Brbm9yYS9hcGknO1xuaW1wb3J0IHsgUmVnaW9uIH0gZnJvbSAnQGtub3JhL2NvcmUnO1xuXG4vLyBUaGlzIGNvbXBvbmVudCBuZWVkcyB0aGUgb3BlbnNlYWRyYWdvbiBsaWJyYXJ5IGl0c2VsZiwgYXMgd2VsbCBhcyB0aGUgb3BlbnNlYWRyYWdvbiBwbHVnaW4gb3BlbnNlYWRyYWdvbi1zdmctb3ZlcmxheVxuLy8gQm90aCBsaWJyYXJpZXMgYXJlIGluc3RhbGxlZCB2aWEgcGFja2FnZS5qc29uLCBhbmQgbG9hZGVkIGdsb2JhbGx5IHZpYSB0aGUgc2NyaXB0IHRhZyBpbiAuYW5ndWxhci1jbGkuanNvblxuXG4vLyBPcGVuU2VhZHJhZ29uIGRvZXMgbm90IGV4cG9ydCBpdHNlbGYgYXMgRVM2L0VDTUEyMDE1IG1vZHVsZSxcbi8vIGl0IGlzIGxvYWRlZCBnbG9iYWxseSBpbiBzY3JpcHRzIHRhZyBvZiBhbmd1bGFyLWNsaS5qc29uLFxuLy8gd2Ugc3RpbGwgbmVlZCB0byBkZWNsYXJlIHRoZSBuYW1lc3BhY2UgdG8gbWFrZSBUeXBlU2NyaXB0IGNvbXBpbGVyIGhhcHB5LlxuZGVjbGFyZSBsZXQgT3BlblNlYWRyYWdvbjogYW55O1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSByZWdpb24uXG4gKiBDb250YWlucyBhIHJlZmVyZW5jZSB0byB0aGUgcmVzb3VyY2UgcmVwcmVzZW50aW5nIHRoZSByZWdpb24gYW5kIGl0cyBnZW9tZXRyaWVzLlxuICovXG5leHBvcnQgY2xhc3MgSW1hZ2VSZWdpb24ge1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVnaW9uUmVzb3VyY2UgYSByZXNvdXJjZSBvZiB0eXBlIFJlZ2lvblxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHJlYWRvbmx5IHJlZ2lvblJlc291cmNlOiBSZWFkUmVzb3VyY2UpIHtcblxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgZ2VvbWV0cnkgaW5mb3JtYXRpb24gYmVsb25naW5nIHRvIHRoaXMgcmVnaW9uLlxuICAgICAqXG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBnZXRHZW9tZXRyaWVzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWdpb25SZXNvdXJjZS5wcm9wZXJ0aWVzW0NvbnN0YW50cy5IYXNHZW9tZXRyeV0gYXMgUmVhZEdlb21WYWx1ZVtdO1xuICAgIH1cbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIGFuIGltYWdlIGluY2x1ZGluZyBpdHMgcmVnaW9ucy5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0aWxsSW1hZ2VSZXByZXNlbnRhdGlvbiB7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBzdGlsbEltYWdlRmlsZVZhbHVlIGEgW1tSZWFkU3RpbGxJbWFnZUZpbGVWYWx1ZV1dIHJlcHJlc2VudGluZyBhbiBpbWFnZS5cbiAgICAgKiBAcGFyYW0gcmVnaW9ucyB0aGUgcmVnaW9ucyBiZWxvbmdpbmcgdG8gdGhlIGltYWdlLlxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHJlYWRvbmx5IHN0aWxsSW1hZ2VGaWxlVmFsdWU6IFJlYWRTdGlsbEltYWdlRmlsZVZhbHVlLCByZWFkb25seSByZWdpb25zOiBSZWdpb25bXSkge1xuXG4gICAgfVxuXG59XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIGdlb21ldHJ5IGJlbG9uZ2luZyB0byBhIHNwZWNpZmljIHJlZ2lvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIEdlb21ldHJ5Rm9yUmVnaW9uIHtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIGdlb21ldHJ5IHRoZSBnZW9tZXRyaWNhbCBpbmZvcm1hdGlvbi5cbiAgICAgKiBAcGFyYW0gcmVnaW9uIHRoZSByZWdpb24gdGhlIGdlb21ldHJ5IGJlbG9uZ3MgdG8uXG4gICAgICovXG4gICAgY29uc3RydWN0b3IocmVhZG9ubHkgZ2VvbWV0cnk6IFJlZ2lvbkdlb21ldHJ5LCByZWFkb25seSByZWdpb246IFJlZ2lvbikge1xuICAgIH1cblxufVxuXG4vKipcbiAqIENvbGxlY3Rpb24gb2YgYFNWR1BvbHlnb25FbGVtZW50YCBmb3IgaW5kaXZpZHVhbCByZWdpb25zLlxuICovXG5pbnRlcmZhY2UgUG9seWdvbnNGb3JSZWdpb24ge1xuXG4gICAgW2tleTogc3RyaW5nXTogU1ZHUG9seWdvbkVsZW1lbnRbXTtcblxufVxuXG4vKipcbiAqIFRoaXMgY29tcG9uZW50IGNyZWF0ZXMgYSBPcGVuU2VhZHJhZ29uIHZpZXdlciBpbnN0YW5jZS5cbiAqIEFjY2VwdHMgYW4gYXJyYXkgb2YgUmVhZFJlc291cmNlIGNvbnRhaW5pbmcgKGFtb25nIG90aGVyIHJlc291cmNlcykgUmVhZFN0aWxsSW1hZ2VGaWxlVmFsdWVzIHRvIGJlIHJlbmRlcmVkLlxuICogQG1lbWJlciByZXNvdXJjZXMgLSByZXNvdXJjZXMgY29udGFpbmluZyAoYW1vbmcgb3RoZXIgcmVzb3VyY2VzKSB0aGUgU3RpbGxJbWFnZUZpbGVWYWx1ZXMgYW5kIGluY29taW5nIHJlZ2lvbnMgdG8gYmUgcmVuZGVyZWQuIChVc2UgYXMgYW5ndWxhciBASW5wdXQgZGF0YSBiaW5kaW5nIHByb3BlcnR5LilcbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdrdWktc3RpbGwtaW1hZ2UnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zdGlsbC1pbWFnZS5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vc3RpbGwtaW1hZ2UuY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBTdGlsbEltYWdlQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG5cbiAgICBASW5wdXQoKSBpbWFnZXM6IFJlYWRTdGlsbEltYWdlRmlsZVZhbHVlW107XG4gICAgQElucHV0KCkgaW1hZ2VDYXB0aW9uPzogc3RyaW5nO1xuICAgIEBJbnB1dCgpIGFjdGl2YXRlUmVnaW9uOiBzdHJpbmc7IC8vIGhpZ2hsaWdodCBhIHJlZ2lvblxuXG4gICAgQE91dHB1dCgpIGN1cnJlbnRJbWFnZUluZGV4OiBFdmVudEVtaXR0ZXI8bnVtYmVyPiA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuICAgIEBPdXRwdXQoKSByZWdpb25Ib3ZlcmVkID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgICBwcml2YXRlIHZpZXdlcjtcbiAgICBwcml2YXRlIHJlZ2lvbnM6IFBvbHlnb25zRm9yUmVnaW9uID0ge307XG5cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGVzIHRoZSBzdXJmYWNlIG9mIGEgcmVjdGFuZ3VsYXIgcmVnaW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIGdlb20gdGhlIHJlZ2lvbidzIGdlb21ldHJ5LlxuICAgICAqIEByZXR1cm5zIHRoZSBzdXJmYWNlLlxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIHN1cmZhY2VPZlJlY3Rhbmd1bGFyUmVnaW9uKGdlb206IFJlZ2lvbkdlb21ldHJ5KTogbnVtYmVyIHtcblxuICAgICAgICBpZiAoZ2VvbS50eXBlICE9PSAncmVjdGFuZ2xlJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ2V4cGVjdGVkIHJlY3Rhbmd1bGFyIHJlZ2lvbiwgYnV0ICcgKyBnZW9tLnR5cGUgKyAnIGdpdmVuJyk7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHcgPSBNYXRoLm1heChnZW9tLnBvaW50c1swXS54LCBnZW9tLnBvaW50c1sxXS54KSAtIE1hdGgubWluKGdlb20ucG9pbnRzWzBdLngsIGdlb20ucG9pbnRzWzFdLngpO1xuICAgICAgICBjb25zdCBoID0gTWF0aC5tYXgoZ2VvbS5wb2ludHNbMF0ueSwgZ2VvbS5wb2ludHNbMV0ueSkgLSBNYXRoLm1pbihnZW9tLnBvaW50c1swXS55LCBnZW9tLnBvaW50c1sxXS55KTtcblxuICAgICAgICByZXR1cm4gdyAqIGg7XG5cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcmVwYXJlIHRpbGUgc291cmNlcyBmcm9tIHRoZSBnaXZlbiBzZXF1ZW5jZSBvZiBbW1JlYWRTdGlsbEltYWdlRmlsZVZhbHVlXV0uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gaW1hZ2VzVG9EaXNwbGF5IHRoZSBnaXZlbiBmaWxlIHZhbHVlcyB0byBkZSBkaXNwbGF5ZWQuXG4gICAgICogQHJldHVybnMgdGhlIHR