UNPKG

@autonomdev/ngx-document-scanner

Version:

Angular 2+ component for cropping and enhancing images of documents

1,511 lines (1,505 loc) 93.5 kB
import { Injectable, ɵɵdefineInjectable, Component, Input, EventEmitter, Inject, Output, ViewChild, ElementRef, NgModule } from '@angular/core'; import { __spread, __awaiter, __generator } from 'tslib'; import { BehaviorSubject } from 'rxjs'; import { MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA, MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet'; import { NgxOpenCVService, OpenCvConfigToken, NgxOpenCVModule } from 'ngx-opencv'; import { FlexLayoutModule } from '@angular/flex-layout'; import { AngularDraggableModule } from 'angular2-draggable'; import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; /** * @fileoverview added by tsickle * Generated from: lib/services/limits.service.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var LimitsService = /** @class */ (function () { function LimitsService() { this.limitDirections = ['left', 'right', 'top', 'bottom']; /** * stores the crop limits limits */ this._limits = { top: 0, bottom: 0, right: 0, left: 0 }; /** * stores the array of the draggable points displayed on the crop area */ this._points = []; // *********** // // Observables // // *********** // this.positions = new BehaviorSubject(Array.from(this._points)); this.repositionEvent = new BehaviorSubject([]); this.limits = new BehaviorSubject(this._limits); this.paneDimensions = new BehaviorSubject({ width: 0, height: 0 }); } /** * set privew pane dimensions */ /** * set privew pane dimensions * @param {?} dimensions * @return {?} */ LimitsService.prototype.setPaneDimensions = /** * set privew pane dimensions * @param {?} dimensions * @return {?} */ function (dimensions) { var _this = this; return new Promise((/** * @param {?} resolve * @param {?} reject * @return {?} */ function (resolve, reject) { _this._paneDimensions = dimensions; _this.paneDimensions.next(dimensions); resolve(); })); }; /** * repositions points externally */ /** * repositions points externally * @param {?} positions * @return {?} */ LimitsService.prototype.repositionPoints = /** * repositions points externally * @param {?} positions * @return {?} */ function (positions) { var _this = this; this._points = positions; positions.forEach((/** * @param {?} position * @return {?} */ function (position) { _this.positionChange(position); })); this.repositionEvent.next(positions); }; /** * updates limits and point positions and calls next on the observables * @param positionChangeData - position change event data */ /** * updates limits and point positions and calls next on the observables * @param {?} positionChangeData - position change event data * @return {?} */ LimitsService.prototype.positionChange = /** * updates limits and point positions and calls next on the observables * @param {?} positionChangeData - position change event data * @return {?} */ function (positionChangeData) { var _this = this; // update positions according to current position change this.updatePosition(positionChangeData); // for each direction: // 1. filter the _points that have a role as the direction's limit // 2. for top and left find max x | y values, and min for right and bottom this.limitDirections.forEach((/** * @param {?} direction * @return {?} */ function (direction) { /** @type {?} */ var relevantPoints = _this._points.filter((/** * @param {?} point * @return {?} */ function (point) { return point.roles.includes(direction); })) .map((/** * @param {?} point * @return {?} */ function (point) { return point[_this.getDirectionAxis(direction)]; })); /** @type {?} */ var limit; if (direction === 'top' || direction === 'left') { limit = Math.max.apply(Math, __spread(relevantPoints)); } if (direction === 'right' || direction === 'bottom') { limit = Math.min.apply(Math, __spread(relevantPoints)); } _this._limits[direction] = limit; })); this.limits.next(this._limits); this.positions.next(Array.from(this._points)); }; /** * updates the position of the point * @param positionChange - position change event data */ /** * updates the position of the point * @param {?} positionChange - position change event data * @return {?} */ LimitsService.prototype.updatePosition = /** * updates the position of the point * @param {?} positionChange - position change event data * @return {?} */ function (positionChange) { var _this = this; // finds the current position of the point by it's roles, than splices it for the new position or pushes it if it's not yet in the array /** @type {?} */ var index = this._points.findIndex((/** * @param {?} point * @return {?} */ function (point) { return _this.compareArray(positionChange.roles, point.roles); })); if (index === -1) { this._points.push(positionChange); } else { this._points.splice(index, 1, positionChange); } }; /** * check if a position change event exceeds the limits * @param positionChange - position change event data * @returns LimitException0 */ /** * check if a position change event exceeds the limits * @param {?} positionChange - position change event data * @return {?} LimitException0 */ LimitsService.prototype.exceedsLimit = /** * check if a position change event exceeds the limits * @param {?} positionChange - position change event data * @return {?} LimitException0 */ function (positionChange) { var _this = this; /** @type {?} */ var pointLimits = this.limitDirections.filter((/** * @param {?} direction * @return {?} */ function (direction) { return !positionChange.roles.includes(direction); })); /** @type {?} */ var limitException = { exceeds: false, resetCoefficients: { x: 0, y: 0 }, resetCoordinates: { x: positionChange.x, y: positionChange.y } }; // limit directions are the opposite sides of the point's roles pointLimits.forEach((/** * @param {?} direction * @return {?} */ function (direction) { /** @type {?} */ var directionAxis = _this.getDirectionAxis(direction); if (direction === 'top' || direction === 'left') { if (positionChange[directionAxis] < _this._limits[direction]) { limitException.resetCoefficients[directionAxis] = 1; limitException.resetCoordinates[directionAxis] = _this._limits[direction]; } } else if (direction === 'right' || direction === 'bottom') { if (positionChange[directionAxis] > _this._limits[direction]) { limitException.resetCoefficients[directionAxis] = -1; limitException.resetCoordinates[directionAxis] = _this._limits[direction]; } } })); if (limitException.resetCoefficients.x !== 0 || limitException.resetCoefficients.y !== 0) { limitException.exceeds = true; } return limitException; }; /** * rotate crop tool points clockwise * @param resizeRatios - ratio between the new dimensions and the previous * @param initialPreviewDimensions - preview pane dimensions before rotation * @param initialPositions - current positions before rotation */ /** * rotate crop tool points clockwise * @param {?} resizeRatios - ratio between the new dimensions and the previous * @param {?} initialPreviewDimensions - preview pane dimensions before rotation * @param {?} initialPositions - current positions before rotation * @return {?} */ LimitsService.prototype.rotateClockwise = /** * rotate crop tool points clockwise * @param {?} resizeRatios - ratio between the new dimensions and the previous * @param {?} initialPreviewDimensions - preview pane dimensions before rotation * @param {?} initialPositions - current positions before rotation * @return {?} */ function (resizeRatios, initialPreviewDimensions, initialPositions) { var _this = this; // convert positions to ratio between position to initial pane dimension initialPositions = initialPositions.map((/** * @param {?} point * @return {?} */ function (point) { return new PositionChangeData({ x: point.x / initialPreviewDimensions.width, y: point.y / initialPreviewDimensions.height, }, point.roles); })); this.repositionPoints(initialPositions.map((/** * @param {?} point * @return {?} */ function (point) { return _this.rotateCornerClockwise(point); }))); }; /** * returns the corner positions after a 90 degrees clockwise rotation */ /** * returns the corner positions after a 90 degrees clockwise rotation * @private * @param {?} corner * @return {?} */ LimitsService.prototype.rotateCornerClockwise = /** * returns the corner positions after a 90 degrees clockwise rotation * @private * @param {?} corner * @return {?} */ function (corner) { var _this = this; /** @type {?} */ var rotated = { x: this._paneDimensions.width * (1 - corner.y), y: this._paneDimensions.height * corner.x, roles: [] }; // rotates corner according to order /** @type {?} */ var order = [ ['bottom', 'left'], ['top', 'left'], ['top', 'right'], ['bottom', 'right'], ['bottom', 'left'] ]; rotated.roles = order[order.findIndex((/** * @param {?} roles * @return {?} */ function (roles) { return _this.compareArray(roles, corner.roles); })) + 1]; return rotated; }; /** * checks if two array contain the same values * @param array1 - array 1 * @param array2 - array 2 * @returns boolean */ /** * checks if two array contain the same values * @param {?} array1 - array 1 * @param {?} array2 - array 2 * @return {?} boolean */ LimitsService.prototype.compareArray = /** * checks if two array contain the same values * @param {?} array1 - array 1 * @param {?} array2 - array 2 * @return {?} boolean */ function (array1, array2) { return array1.every((/** * @param {?} element * @return {?} */ function (element) { return array2.includes(element); })) && array1.length === array2.length; }; /** * @private * @param {?} direction * @return {?} */ LimitsService.prototype.getDirectionAxis = /** * @private * @param {?} direction * @return {?} */ function (direction) { return { left: 'x', right: 'x', top: 'y', bottom: 'y' }[direction]; }; LimitsService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ LimitsService.ctorParameters = function () { return []; }; /** @nocollapse */ LimitsService.ɵprov = ɵɵdefineInjectable({ factory: function LimitsService_Factory() { return new LimitsService(); }, token: LimitsService, providedIn: "root" }); return LimitsService; }()); if (false) { /** * @type {?} * @private */ LimitsService.prototype.limitDirections; /** * stores the crop limits limits * @type {?} * @private */ LimitsService.prototype._limits; /** * stores the array of the draggable points displayed on the crop area * @type {?} * @private */ LimitsService.prototype._points; /** * stores the pane dimensions * @type {?} * @private */ LimitsService.prototype._paneDimensions; /** @type {?} */ LimitsService.prototype.positions; /** @type {?} */ LimitsService.prototype.repositionEvent; /** @type {?} */ LimitsService.prototype.limits; /** @type {?} */ LimitsService.prototype.paneDimensions; } /** * @record */ function PointPositionChange() { } if (false) { /** @type {?} */ PointPositionChange.prototype.x; /** @type {?} */ PointPositionChange.prototype.y; /** @type {?} */ PointPositionChange.prototype.roles; } /** * @record */ function AreaLimits() { } if (false) { /** @type {?} */ AreaLimits.prototype.top; /** @type {?} */ AreaLimits.prototype.bottom; /** @type {?} */ AreaLimits.prototype.right; /** @type {?} */ AreaLimits.prototype.left; } var PositionChangeData = /** @class */ (function () { function PositionChangeData(position, roles) { this.x = position.x; this.y = position.y; this.roles = roles; } return PositionChangeData; }()); if (false) { /** @type {?} */ PositionChangeData.prototype.x; /** @type {?} */ PositionChangeData.prototype.y; /** @type {?} */ PositionChangeData.prototype.roles; } /** * @fileoverview added by tsickle * Generated from: lib/components/draggable-point/ngx-draggable-point.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var NgxDraggablePointComponent = /** @class */ (function () { function NgxDraggablePointComponent(limitsService) { this.limitsService = limitsService; this.width = 10; this.height = 10; this.color = '#3cabe2'; this.shape = 'rect'; this.pointOptions = 'rect'; this.position = { x: 0, y: 0 }; } /** * @return {?} */ NgxDraggablePointComponent.prototype.ngAfterViewInit = /** * @return {?} */ function () { var _this = this; Object.keys(this.pointOptions).forEach((/** * @param {?} key * @return {?} */ function (key) { _this[key] = _this.pointOptions[key]; })); // subscribe to pane dimensions changes this.limitsService.paneDimensions.subscribe((/** * @param {?} dimensions * @return {?} */ function (dimensions) { if (dimensions.width > 0 && dimensions.width > 0) { _this._paneDimensions = { width: dimensions.width, height: dimensions.height }; _this.position = _this.getInitialPosition(dimensions); _this.limitsService.positionChange(new PositionChangeData(_this.position, _this.limitRoles)); } })); // subscribe to external reposition events this.limitsService.repositionEvent.subscribe((/** * @param {?} positions * @return {?} */ function (positions) { if (positions.length > 0) { _this.externalReposition(positions); } })); }; /** * returns a css style object for the point */ /** * returns a css style object for the point * @return {?} */ NgxDraggablePointComponent.prototype.pointStyle = /** * returns a css style object for the point * @return {?} */ function () { return { width: this.width + 'px', height: this.height + 'px', 'background-color': this.color, 'border-radius': this.shape === 'circle' ? '100%' : 0, position: 'absolute' }; }; /** * registers a position change on the limits service, and adjusts position if necessary * @param position - the current position of the point */ /** * registers a position change on the limits service, and adjusts position if necessary * @param {?} position - the current position of the point * @return {?} */ NgxDraggablePointComponent.prototype.positionChange = /** * registers a position change on the limits service, and adjusts position if necessary * @param {?} position - the current position of the point * @return {?} */ function (position) { /** @type {?} */ var positionChangeData = new PositionChangeData(position, this.limitRoles); /** @type {?} */ var limitException = this.limitsService.exceedsLimit(positionChangeData); if (limitException.exceeds) { // if exceeds limits, reposition this.resetPosition = limitException.resetCoordinates; } else { this.limitsService.positionChange(positionChangeData); this._currentPosition = position; } }; /** * adjusts the position of the point after a limit exception */ /** * adjusts the position of the point after a limit exception * @private * @param {?} limitException * @return {?} */ NgxDraggablePointComponent.prototype.adjustPosition = /** * adjusts the position of the point after a limit exception * @private * @param {?} limitException * @return {?} */ function (limitException) { /** @type {?} */ var newPosition = { x: 0, y: 0 }; Object.keys(this.startPosition).forEach((/** * @param {?} axis * @return {?} */ function (axis) { newPosition[axis] = limitException.resetCoordinates[axis] + limitException.resetCoefficients[axis]; })); this.position = newPosition; this.limitsService.positionChange(new PositionChangeData(this.position, this.limitRoles)); }; /** * called on movement end, checks if last position exceeded the limits ad adjusts */ /** * called on movement end, checks if last position exceeded the limits ad adjusts * @param {?} position * @return {?} */ NgxDraggablePointComponent.prototype.movementEnd = /** * called on movement end, checks if last position exceeded the limits ad adjusts * @param {?} position * @return {?} */ function (position) { /** @type {?} */ var positionChangeData = new PositionChangeData(position, this.limitRoles); /** @type {?} */ var limitException = this.limitsService.exceedsLimit(positionChangeData); if (limitException.exceeds) { this.resetPosition = limitException.resetCoordinates; if (limitException.exceeds) { this.adjustPosition(limitException); positionChangeData = new PositionChangeData(this.position, this.limitRoles); this.limitsService.updatePosition(positionChangeData); } } }; /** * calculates the initial positions of the point by it's roles * @param dimensions - dimensions of the pane in which the point is located */ /** * calculates the initial positions of the point by it's roles * @private * @param {?} dimensions - dimensions of the pane in which the point is located * @return {?} */ NgxDraggablePointComponent.prototype.getInitialPosition = /** * calculates the initial positions of the point by it's roles * @private * @param {?} dimensions - dimensions of the pane in which the point is located * @return {?} */ function (dimensions) { return { x: this.limitRoles.includes('left') ? 0 : dimensions.width - this.width / 2, y: this.limitRoles.includes('top') ? 0 : dimensions.height - this.height / 2 }; }; /** * repositions the point after an external reposition event * @param positions - an array of all points on the pane */ /** * repositions the point after an external reposition event * @private * @param {?} positions - an array of all points on the pane * @return {?} */ NgxDraggablePointComponent.prototype.externalReposition = /** * repositions the point after an external reposition event * @private * @param {?} positions - an array of all points on the pane * @return {?} */ function (positions) { var _this = this; positions.forEach((/** * @param {?} position * @return {?} */ function (position) { if (_this.limitsService.compareArray(_this.limitRoles, position.roles)) { position = _this.enforcePaneLimits(position); _this.position = { x: position.x, y: position.y }; } })); }; /** * returns a new point position if the movement exceeded the pane limit */ /** * returns a new point position if the movement exceeded the pane limit * @private * @param {?} position * @return {?} */ NgxDraggablePointComponent.prototype.enforcePaneLimits = /** * returns a new point position if the movement exceeded the pane limit * @private * @param {?} position * @return {?} */ function (position) { if (this._paneDimensions.width === 0 || this._paneDimensions.height === 0) { return position; } else { if (position.x > this._paneDimensions.width) { position.x = this._paneDimensions.width; } if (position.x < 0) { position.x = 1; } if (position.y > this._paneDimensions.height) { position.y = this._paneDimensions.height; } if (position.y < 0) { position.y = 1; } } return position; }; NgxDraggablePointComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-draggable-point', template: "<div #point ngDraggable=\"draggable\"\n (movingOffset)=\"positionChange($event)\"\n [ngStyle]=\"pointStyle()\"\n [position]=\"position\"\n [bounds]=\"container\"\n [inBounds]=\"true\"\n (endOffset)=\"movementEnd($event)\"\n style=\"z-index: 1000\">\n</div>\n" }] } ]; /** @nocollapse */ NgxDraggablePointComponent.ctorParameters = function () { return [ { type: LimitsService } ]; }; NgxDraggablePointComponent.propDecorators = { width: [{ type: Input }], height: [{ type: Input }], color: [{ type: Input }], shape: [{ type: Input }], pointOptions: [{ type: Input }], limitRoles: [{ type: Input }], startPosition: [{ type: Input }], container: [{ type: Input }], _currentPosition: [{ type: Input }] }; return NgxDraggablePointComponent; }()); if (false) { /** @type {?} */ NgxDraggablePointComponent.prototype.width; /** @type {?} */ NgxDraggablePointComponent.prototype.height; /** @type {?} */ NgxDraggablePointComponent.prototype.color; /** @type {?} */ NgxDraggablePointComponent.prototype.shape; /** @type {?} */ NgxDraggablePointComponent.prototype.pointOptions; /** @type {?} */ NgxDraggablePointComponent.prototype.limitRoles; /** @type {?} */ NgxDraggablePointComponent.prototype.startPosition; /** @type {?} */ NgxDraggablePointComponent.prototype.container; /** * @type {?} * @private */ NgxDraggablePointComponent.prototype._currentPosition; /** @type {?} */ NgxDraggablePointComponent.prototype.position; /** * @type {?} * @private */ NgxDraggablePointComponent.prototype._paneDimensions; /** @type {?} */ NgxDraggablePointComponent.prototype.resetPosition; /** * @type {?} * @private */ NgxDraggablePointComponent.prototype.limitsService; } /** * @fileoverview added by tsickle * Generated from: lib/components/filter-menu/ngx-filter-menu.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var NgxFilterMenuComponent = /** @class */ (function () { function NgxFilterMenuComponent(bottomSheetRef, data) { var _this = this; this.bottomSheetRef = bottomSheetRef; this.data = data; this.filterOptions = [ { name: 'bw2', icon: 'filter_b_and_w', action: (/** * @param {?} filter * @return {?} */ function (filter) { _this.filterSelected.emit(filter); }), text: 'B&W 2' }, { name: 'bw3', icon: 'blur_on', action: (/** * @param {?} filter * @return {?} */ function (filter) { _this.filterSelected.emit(filter); }), text: 'B&W 3' }, { name: 'magic_color', icon: 'filter_vintage', action: (/** * @param {?} filter * @return {?} */ function (filter) { _this.filterSelected.emit(filter); }), text: 'Magic Color' }, { name: 'default', icon: 'crop_original', action: (/** * @param {?} filter * @return {?} */ function (filter) { _this.filterSelected.emit(filter); }), text: 'Original' }, ]; this.filterSelected = new EventEmitter(); } /** * @param {?} optionName * @return {?} */ NgxFilterMenuComponent.prototype.selectOption = /** * @param {?} optionName * @return {?} */ function (optionName) { this.data.filter = optionName; this.bottomSheetRef.dismiss(); }; NgxFilterMenuComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-filter-menu', template: "<mat-action-list>\n <button mat-list-item *ngFor=\"let option of filterOptions\" (click)=\"selectOption(option.name)\">\n <mat-icon>{{option.icon}}</mat-icon>\n <span fxFlex=\"100\" style=\"text-align: start; margin: 5px\">{{option.text}}</span>\n <span fxFlex=\"100\"></span>\n <mat-icon *ngIf=\"option.name === data.filter\">done</mat-icon>\n </button>\n</mat-action-list>\n" }] } ]; /** @nocollapse */ NgxFilterMenuComponent.ctorParameters = function () { return [ { type: MatBottomSheetRef }, { type: undefined, decorators: [{ type: Inject, args: [MAT_BOTTOM_SHEET_DATA,] }] } ]; }; NgxFilterMenuComponent.propDecorators = { filterSelected: [{ type: Output }] }; return NgxFilterMenuComponent; }()); if (false) { /** @type {?} */ NgxFilterMenuComponent.prototype.filterOptions; /** @type {?} */ NgxFilterMenuComponent.prototype.filterSelected; /** * @type {?} * @private */ NgxFilterMenuComponent.prototype.bottomSheetRef; /** @type {?} */ NgxFilterMenuComponent.prototype.data; } /** * @fileoverview added by tsickle * Generated from: lib/components/shape-outline/ngx-shape-outline.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var NgxShapeOutlineComponent = /** @class */ (function () { function NgxShapeOutlineComponent(limitsService) { this.limitsService = limitsService; this.color = '#3cabe2'; } /** * @return {?} */ NgxShapeOutlineComponent.prototype.ngAfterViewInit = /** * @return {?} */ function () { var _this = this; // init drawing canvas dimensions this.canvas.nativeElement.width = this.dimensions.width; this.canvas.nativeElement.height = this.dimensions.height; this.limitsService.positions.subscribe((/** * @param {?} positions * @return {?} */ function (positions) { if (positions.length === 4) { _this._points = positions; _this.sortPoints(); _this.clearCanvas(); _this.drawShape(); } })); // subscribe to changes in the pane's dimensions this.limitsService.paneDimensions.subscribe((/** * @param {?} dimensions * @return {?} */ function (dimensions) { _this.clearCanvas(); _this.canvas.nativeElement.width = dimensions.width; _this.canvas.nativeElement.height = dimensions.height; })); // subscribe to reposition events this.limitsService.repositionEvent.subscribe((/** * @param {?} positions * @return {?} */ function (positions) { if (positions.length === 4) { setTimeout((/** * @return {?} */ function () { _this.clearCanvas(); _this.sortPoints(); _this.drawShape(); }), 10); } })); }; /** * clears the shape canvas */ /** * clears the shape canvas * @private * @return {?} */ NgxShapeOutlineComponent.prototype.clearCanvas = /** * clears the shape canvas * @private * @return {?} */ function () { /** @type {?} */ var canvas = this.canvas.nativeElement; /** @type {?} */ var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, this.dimensions.width, this.dimensions.height); }; /** * sorts the array of points according to their clockwise alignment */ /** * sorts the array of points according to their clockwise alignment * @private * @return {?} */ NgxShapeOutlineComponent.prototype.sortPoints = /** * sorts the array of points according to their clockwise alignment * @private * @return {?} */ function () { var _this = this; /** @type {?} */ var _points = Array.from(this._points); /** @type {?} */ var sortedPoints = []; /** @type {?} */ var sortOrder = { vertical: ['top', 'top', 'bottom', 'bottom'], horizontal: ['left', 'right', 'right', 'left'] }; var _loop_1 = function (i) { /** @type {?} */ var roles = Array.from([sortOrder.vertical[i], sortOrder.horizontal[i]]); sortedPoints.push(_points.filter((/** * @param {?} point * @return {?} */ function (point) { return _this.limitsService.compareArray(point.roles, roles); }))[0]); }; for (var i = 0; i < 4; i++) { _loop_1(i); } this._sortedPoints = sortedPoints; }; /** * draws a line between the points according to their order */ /** * draws a line between the points according to their order * @private * @return {?} */ NgxShapeOutlineComponent.prototype.drawShape = /** * draws a line between the points according to their order * @private * @return {?} */ function () { var _this = this; /** @type {?} */ var canvas = this.canvas.nativeElement; /** @type {?} */ var ctx = canvas.getContext('2d'); ctx.lineWidth = this.weight; ctx.strokeStyle = this.color; ctx.beginPath(); this._sortedPoints.forEach((/** * @param {?} point * @param {?} index * @return {?} */ function (point, index) { if (index === 0) { ctx.moveTo(point.x, point.y); } if (index !== _this._sortedPoints.length - 1) { /** @type {?} */ var nextPoint = _this._sortedPoints[index + 1]; ctx.lineTo(nextPoint.x, nextPoint.y); } else { ctx.closePath(); } })); ctx.stroke(); }; NgxShapeOutlineComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-shape-outine', template: "<canvas #outline\n style=\"position: absolute; z-index: 1000\"\n [ngStyle]=\"{width: dimensions.width + 'px', height: dimensions.height + 'px'}\"\n *ngIf=\"dimensions\">\n</canvas>\n" }] } ]; /** @nocollapse */ NgxShapeOutlineComponent.ctorParameters = function () { return [ { type: LimitsService } ]; }; NgxShapeOutlineComponent.propDecorators = { color: [{ type: Input }], weight: [{ type: Input }], dimensions: [{ type: Input }], canvas: [{ type: ViewChild, args: ['outline',] }] }; return NgxShapeOutlineComponent; }()); if (false) { /** @type {?} */ NgxShapeOutlineComponent.prototype.color; /** @type {?} */ NgxShapeOutlineComponent.prototype.weight; /** @type {?} */ NgxShapeOutlineComponent.prototype.dimensions; /** @type {?} */ NgxShapeOutlineComponent.prototype.canvas; /** * @type {?} * @private */ NgxShapeOutlineComponent.prototype._points; /** * @type {?} * @private */ NgxShapeOutlineComponent.prototype._sortedPoints; /** * @type {?} * @private */ NgxShapeOutlineComponent.prototype.limitsService; } /** * @fileoverview added by tsickle * Generated from: lib/components/image-editor/ngx-doc-scanner.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var NgxDocScannerComponent = /** @class */ (function () { function NgxDocScannerComponent(ngxOpenCv, limitsService, bottomSheet) { var _this = this; this.ngxOpenCv = ngxOpenCv; this.limitsService = limitsService; this.bottomSheet = bottomSheet; // ************* // // EDITOR CONFIG // // ************* // /** * an array of action buttons displayed on the editor screen */ this.editorButtons = [ { name: 'exit', action: (/** * @return {?} */ function () { _this.exitEditor.emit('canceled'); }), icon: 'arrow_back', type: 'fab', mode: 'crop' }, { name: 'rotate', action: this.rotateImage.bind(this), icon: 'rotate_right', type: 'fab', mode: 'crop' }, { name: 'done_crop', action: (/** * @return {?} */ function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: this.mode = 'color'; return [4 /*yield*/, this.transform()]; case 1: _a.sent(); return [4 /*yield*/, this.applyFilter(true)]; case 2: _a.sent(); return [2 /*return*/]; } }); }); }), icon: 'done', type: 'fab', mode: 'crop' }, { name: 'back', action: (/** * @return {?} */ function () { _this.mode = 'crop'; _this.loadFile(_this.originalImage); }), icon: 'arrow_back', type: 'fab', mode: 'color' }, { name: 'filter', action: (/** * @return {?} */ function () { return _this.chooseFilters(); }), icon: 'photo_filter', type: 'fab', mode: 'color' }, { name: 'upload', action: this.exportImage.bind(this), icon: 'cloud_upload', type: 'fab', mode: 'color' }, ]; /** * true after the image is loaded and preview is displayed */ this.imageLoaded = false; /** * editor mode */ this.mode = 'crop'; /** * filter selected by the user, returned by the filter selector bottom sheet */ this.selectedFilter = 'default'; /** * image dimensions */ this.imageDimensions = { width: 0, height: 0 }; // ************** // // EVENT EMITTERS // // ************** // /** * optional binding to the exit button of the editor */ this.exitEditor = new EventEmitter(); /** * fires on edit completion */ this.editResult = new EventEmitter(); /** * emits errors, can be linked to an error handler of choice */ this.error = new EventEmitter(); /** * emits the loading status of the cv module. */ this.ready = new EventEmitter(); /** * emits true when processing is done, false when completed */ this.processing = new EventEmitter(); this.screenDimensions = { width: window.innerWidth, height: window.innerHeight }; // subscribe to status of cv module this.ngxOpenCv.cvState.subscribe((/** * @param {?} cvState * @return {?} */ function (cvState) { _this.cvState = cvState.state; _this.ready.emit(cvState.ready); if (cvState.error) { _this.error.emit(new Error('error loading cv')); } else if (cvState.loading) { _this.processing.emit(true); } else if (cvState.ready) { _this.processing.emit(false); } })); // subscribe to positions of crop tool this.limitsService.positions.subscribe((/** * @param {?} points * @return {?} */ function (points) { _this.points = points; })); } Object.defineProperty(NgxDocScannerComponent.prototype, "displayedButtons", { /** * returns an array of buttons according to the editor mode */ get: /** * returns an array of buttons according to the editor mode * @return {?} */ function () { var _this = this; return this.editorButtons.filter((/** * @param {?} button * @return {?} */ function (button) { return button.mode === _this.mode; })); }, enumerable: true, configurable: true }); Object.defineProperty(NgxDocScannerComponent.prototype, "file", { // ****** // // INPUTS // // ****** // /** * set image for editing * @param file - file from form input */ set: // ****** // // INPUTS // // ****** // /** * set image for editing * @param {?} file - file from form input * @return {?} */ function (file) { var _this = this; if (file) { setTimeout((/** * @return {?} */ function () { _this.processing.emit(true); }), 5); this.imageLoaded = false; this.originalImage = file; this.ngxOpenCv.cvState.subscribe((/** * @param {?} cvState * @return {?} */ function (cvState) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!cvState.ready) return [3 /*break*/, 2]; // read file to image & canvas return [4 /*yield*/, this.loadFile(file)]; case 1: // read file to image & canvas _a.sent(); this.processing.emit(false); _a.label = 2; case 2: return [2 /*return*/]; } }); }); })); } }, enumerable: true, configurable: true }); /** * @return {?} */ NgxDocScannerComponent.prototype.ngOnInit = /** * @return {?} */ function () { var _this = this; // set options from config object this.options = new ImageEditorConfig(this.config); // set export image icon this.editorButtons.forEach((/** * @param {?} button * @return {?} */ function (button) { if (button.name === 'upload') { button.icon = _this.options.exportImageIcon; } })); this.maxPreviewWidth = this.options.maxPreviewWidth; this.editorStyle = this.options.editorStyle; }; // ***************************** // // editor action buttons methods // // ***************************** // /** * emits the exitEditor event */ // ***************************** // // editor action buttons methods // // ***************************** // /** * emits the exitEditor event * @return {?} */ NgxDocScannerComponent.prototype.exit = // ***************************** // // editor action buttons methods // // ***************************** // /** * emits the exitEditor event * @return {?} */ function () { this.exitEditor.emit('canceled'); }; /** * applies the selected filter, and when done emits the resulted image */ /** * applies the selected filter, and when done emits the resulted image * @private * @return {?} */ NgxDocScannerComponent.prototype.exportImage = /** * applies the selected filter, and when done emits the resulted image * @private * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.applyFilter(false)]; case 1: _a.sent(); if (this.options.maxImageDimensions) { this.resize(this.editedImage) .then((/** * @param {?} resizeResult * @return {?} */ function (resizeResult) { resizeResult.toBlob((/** * @param {?} blob * @return {?} */ function (blob) { _this.editResult.emit(blob); _this.processing.emit(false); }), _this.originalImage.type); })); } else { this.editedImage.toBlob((/** * @param {?} blob * @return {?} */ function (blob) { _this.editResult.emit(blob); _this.processing.emit(false); }), this.originalImage.type); } return [2 /*return*/]; } }); }); }; /** * open the bottom sheet for selecting filters, and applies the selected filter in preview mode */ /** * open the bottom sheet for selecting filters, and applies the selected filter in preview mode * @private * @return {?} */ NgxDocScannerComponent.prototype.chooseFilters = /** * open the bottom sheet for selecting filters, and applies the selected filter in preview mode * @private * @return {?} */ function () { var _this = this; /** @type {?} */ var data = { filter: this.selectedFilter }; /** @type {?} */ var bottomSheetRef = this.bottomSheet.open(NgxFilterMenuComponent, { data: data }); bottomSheetRef.afterDismissed().subscribe((/** * @return {?} */ function () { _this.selectedFilter = data.filter; _this.applyFilter(true); })); }; // *************************** // // File Input & Output Methods // // *************************** // /** * load image from input field */ // *************************** // // File Input & Output Methods // // *************************** // /** * load image from input field * @private * @param {?} file * @return {?} */ NgxDocScannerComponent.prototype.loadFile = // *************************** // // File Input & Output Methods // // *************************** // /** * load image from input field * @private * @param {?} file * @return {?} */ function (file) { var _this = this; return new Promise((/** * @param {?} resolve * @param {?} reject * @return {?} */ function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { var err_1, err_2; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: this.processing.emit(true); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.readImage(file)]; case 2: _a.sent(); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); console.error(err_1); this.error.emit(new Error(err_1)); return [3 /*break*/, 4]; case 4: _a.trys.push([4, 6, , 7]); return [4 /*yield*/, this.showPreview()]; case 5: _a.sent(); return [3 /*break*/, 7]; case 6: err_2 = _a.sent(); console.error(err_2);