@rdlabo/ionic-angular-photo-editor 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/dictionaries.mjs +27 -0
- package/esm2022/lib/filter-preset.mjs +1 -1
- package/esm2022/lib/pages/photo-editor.page.mjs +187 -0
- package/esm2022/lib/pages/photo-viewer.page.mjs +96 -0
- package/esm2022/lib/photoEditorErrors.mjs +7 -0
- package/esm2022/lib/service/helper.service.mjs +44 -0
- package/esm2022/lib/service/photo-file.service.mjs +137 -0
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/public-api.mjs +4 -2
- package/fesm2022/rdlabo-ionic-angular-photo-editor.mjs +263 -24
- package/fesm2022/rdlabo-ionic-angular-photo-editor.mjs.map +1 -1
- package/lib/dictionaries.d.ts +4 -0
- package/lib/filter-preset.d.ts +2 -2
- package/lib/{page → pages}/photo-editor.page.d.ts +4 -4
- package/lib/pages/photo-viewer.page.d.ts +26 -0
- package/lib/photoEditorErrors.d.ts +5 -0
- package/lib/service/helper.service.d.ts +9 -0
- package/lib/service/photo-file.service.d.ts +16 -0
- package/lib/types.d.ts +12 -1
- package/package.json +4 -1
- package/public-api.d.ts +3 -1
- package/esm2022/lib/dictionary.mjs +0 -17
- package/esm2022/lib/page/photo-editor.page.mjs +0 -187
- package/esm2022/lib/service/photo-editor.service.mjs +0 -41
- package/lib/dictionary.d.ts +0 -2
- package/lib/service/photo-editor.service.d.ts +0 -8
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { inject, Injectable, signal } from '@angular/core';
|
|
2
|
+
import { ActionSheetController, Platform } from '@ionic/angular/standalone';
|
|
3
|
+
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
|
4
|
+
import ImageEditor from 'tui-image-editor';
|
|
5
|
+
import { PhotoEditorErrors } from '../photoEditorErrors';
|
|
6
|
+
import { dictionaryForService } from '../dictionaries';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
export class PhotoFileService {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.$photoMaxSize = signal(1000);
|
|
11
|
+
this.actionSheetCtrl = inject(ActionSheetController);
|
|
12
|
+
this.platform = inject(Platform);
|
|
13
|
+
this.dictionary = dictionaryForService();
|
|
14
|
+
}
|
|
15
|
+
set photoMaxSize(value) {
|
|
16
|
+
this.$photoMaxSize.set(value);
|
|
17
|
+
}
|
|
18
|
+
set labels(d) {
|
|
19
|
+
this.dictionary = Object.assign(this.dictionary, d);
|
|
20
|
+
}
|
|
21
|
+
async loadPhoto(limit) {
|
|
22
|
+
/**
|
|
23
|
+
* Using Input for browser
|
|
24
|
+
*/
|
|
25
|
+
if (!this.platform.is('capacitor')) {
|
|
26
|
+
return this.getPictureFromBrowser();
|
|
27
|
+
}
|
|
28
|
+
const actionSheet = await this.actionSheetCtrl.create({
|
|
29
|
+
buttons: [
|
|
30
|
+
{
|
|
31
|
+
text: this.dictionary.camera,
|
|
32
|
+
handler: () => {
|
|
33
|
+
actionSheet.dismiss('camera');
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
text: this.dictionary.album,
|
|
38
|
+
handler: () => {
|
|
39
|
+
actionSheet.dismiss('album');
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
text: this.dictionary.cancel,
|
|
44
|
+
role: 'cancel',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
await actionSheet.present();
|
|
49
|
+
const { data } = await actionSheet.onDidDismiss();
|
|
50
|
+
if (!data) {
|
|
51
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
52
|
+
}
|
|
53
|
+
if (data === 'camera') {
|
|
54
|
+
const defaultCamera = {
|
|
55
|
+
quality: 100,
|
|
56
|
+
width: this.$photoMaxSize(),
|
|
57
|
+
allowEditing: false,
|
|
58
|
+
resultType: CameraResultType.DataUrl,
|
|
59
|
+
source: CameraSource.Camera,
|
|
60
|
+
presentationStyle: 'popover',
|
|
61
|
+
};
|
|
62
|
+
const image = await Camera.getPhoto(defaultCamera).catch(() => undefined);
|
|
63
|
+
if (!image?.dataUrl) {
|
|
64
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
65
|
+
}
|
|
66
|
+
if (!image.dataUrl.includes('capacitor://localhost')) {
|
|
67
|
+
return [image.dataUrl];
|
|
68
|
+
}
|
|
69
|
+
return Promise.all([image.dataUrl].map(async (image) => await this.loadPhotoFromFilePath(image)));
|
|
70
|
+
}
|
|
71
|
+
if (data === 'album') {
|
|
72
|
+
const images = await Camera.pickImages({
|
|
73
|
+
quality: 100,
|
|
74
|
+
width: this.$photoMaxSize(),
|
|
75
|
+
limit,
|
|
76
|
+
presentationStyle: 'popover',
|
|
77
|
+
}).catch(() => undefined);
|
|
78
|
+
if (!images) {
|
|
79
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
80
|
+
}
|
|
81
|
+
return Promise.all(images.photos.map(async (image) => await this.loadPhotoFromFilePath(image.webPath)));
|
|
82
|
+
}
|
|
83
|
+
// Not run on this line. This is for lint
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
getPictureFromBrowser() {
|
|
87
|
+
const inputFile = document.querySelector('input#browserPhotoUploader');
|
|
88
|
+
if (!inputFile) {
|
|
89
|
+
return Promise.reject(PhotoEditorErrors.initialize);
|
|
90
|
+
}
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
inputFile.addEventListener('change', (e) => {
|
|
93
|
+
if (!e.target.files || !e.target.files[0]) {
|
|
94
|
+
reject(PhotoEditorErrors.cancel);
|
|
95
|
+
}
|
|
96
|
+
const file = e.target.files[0];
|
|
97
|
+
const reader = new FileReader();
|
|
98
|
+
reader.onload = (() => {
|
|
99
|
+
if (file.type.indexOf('image') < 0) {
|
|
100
|
+
reject(PhotoEditorErrors.type);
|
|
101
|
+
}
|
|
102
|
+
return async (event) => {
|
|
103
|
+
inputFile.value = '';
|
|
104
|
+
const result = event.target.result;
|
|
105
|
+
const data = await this.loadPhotoFromFilePath(result);
|
|
106
|
+
resolve([data]);
|
|
107
|
+
};
|
|
108
|
+
})();
|
|
109
|
+
reader.readAsDataURL(file);
|
|
110
|
+
}, false);
|
|
111
|
+
inputFile.click();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async loadPhotoFromFilePath(filePath) {
|
|
115
|
+
const defaultInstance = new ImageEditor(document.createElement('div'), {
|
|
116
|
+
cssMaxWidth: this.$photoMaxSize(),
|
|
117
|
+
cssMaxHeight: this.$photoMaxSize(),
|
|
118
|
+
});
|
|
119
|
+
const blob = await fetch(filePath).then((res) => res.blob());
|
|
120
|
+
const loaded = await defaultInstance.loadImageFromFile(new File([blob], 'data.png', { type: blob.type }));
|
|
121
|
+
const maxSize = Math.max(loaded.newWidth, loaded.newHeight);
|
|
122
|
+
const dataUrl = defaultInstance.toDataURL({
|
|
123
|
+
multiplier: this.$photoMaxSize() / maxSize,
|
|
124
|
+
});
|
|
125
|
+
defaultInstance.destroy();
|
|
126
|
+
return dataUrl;
|
|
127
|
+
}
|
|
128
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
129
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, providedIn: 'root' }); }
|
|
130
|
+
}
|
|
131
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, decorators: [{
|
|
132
|
+
type: Injectable,
|
|
133
|
+
args: [{
|
|
134
|
+
providedIn: 'root',
|
|
135
|
+
}]
|
|
136
|
+
}], ctorParameters: () => [] });
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGhvdG8tZmlsZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcGhvdG8tZWRpdG9yL3NyYy9saWIvc2VydmljZS9waG90by1maWxlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxRQUFRLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsTUFBTSxFQUFFLGdCQUFnQixFQUFFLFlBQVksRUFBZ0IsTUFBTSxtQkFBbUIsQ0FBQztBQUV6RixPQUFPLFdBQVcsTUFBTSxrQkFBa0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7QUFNdkQsTUFBTSxPQUFPLGdCQUFnQjtJQU0zQjtRQUxpQixrQkFBYSxHQUFHLE1BQU0sQ0FBUyxJQUFJLENBQUMsQ0FBQztRQUNyQyxvQkFBZSxHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQ2hELGFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckMsZUFBVSxHQUEwQixvQkFBb0IsRUFBRSxDQUFDO0lBRXBELENBQUM7SUFFaEIsSUFBSSxZQUFZLENBQUMsS0FBYTtRQUM1QixJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsSUFBSSxNQUFNLENBQUMsQ0FBd0I7UUFDakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELEtBQUssQ0FBQyxT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QztRQUM1RCxNQUFNLE9BQU8sR0FBRyxlQUFlLENBQUMsU0FBUyxDQUFDO1lBQ3hDLFVBQVUsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLEdBQUcsT0FBTztTQUMzQyxDQUFDLENBQUM7UUFDSCxlQUFlLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFMUIsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQzs4R0E5SVUsZ0JBQWdCO2tIQUFoQixnQkFBZ0IsY0FGZixNQUFNOzsyRkFFUCxnQkFBZ0I7a0JBSDVCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBJbmplY3RhYmxlLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFjdGlvblNoZWV0Q29udHJvbGxlciwgUGxhdGZvcm0gfSBmcm9tICdAaW9uaWMvYW5ndWxhci9zdGFuZGFsb25lJztcbmltcG9ydCB7IENhbWVyYSwgQ2FtZXJhUmVzdWx0VHlwZSwgQ2FtZXJhU291cmNlLCBJbWFnZU9wdGlvbnMgfSBmcm9tICdAY2FwYWNpdG9yL2NhbWVyYSc7XG5pbXBvcnQgeyBHYWxsZXJ5UGhvdG9zIH0gZnJvbSAnQGNhcGFjaXRvci9jYW1lcmEvZGlzdC9lc20vZGVmaW5pdGlvbnMnO1xuaW1wb3J0IEltYWdlRWRpdG9yIGZyb20gJ3R1aS1pbWFnZS1lZGl0b3InO1xuaW1wb3J0IHsgUGhvdG9FZGl0b3JFcnJvcnMgfSBmcm9tICcuLi9waG90b0VkaXRvckVycm9ycyc7XG5pbXBvcnQgeyBkaWN0aW9uYXJ5Rm9yU2VydmljZSB9IGZyb20gJy4uL2RpY3Rpb25hcmllcyc7XG5pbXBvcnQgeyBJRGljdGlvbmFyeUZvclNlcnZpY2UgfSBmcm9tICcuLi90eXBlcyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBQaG90b0ZpbGVTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSAkcGhvdG9NYXhTaXplID0gc2lnbmFsPG51bWJlcj4oMTAwMCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWN0aW9uU2hlZXRDdHJsID0gaW5qZWN0KEFjdGlvblNoZWV0Q29udHJvbGxlcik7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGxhdGZvcm0gPSBpbmplY3QoUGxhdGZvcm0pO1xuICBwcml2YXRlIGRpY3Rpb25hcnk6IElEaWN0aW9uYXJ5Rm9yU2VydmljZSA9IGRpY3Rpb25hcnlGb3JTZXJ2aWNlKCk7XG5cbiAgY29uc3RydWN0b3IoKSB7fVxuXG4gIHNldCBwaG90b01heFNpemUodmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuJHBob3RvTWF4U2l6ZS5zZXQodmFsdWUpO1xuICB9XG5cbiAgc2V0IGxhYmVscyhkOiBJRGljdGlvbmFyeUZvclNlcnZpY2UpIHtcbiAgICB0aGlzLmRpY3Rpb25hcnkgPSBPYmplY3QuYXNzaWduKHRoaXMuZGljdGlvbmFyeSwgZCk7XG4gIH1cblxuICBhc3luYyBsb2FkUGhvdG8obGltaXQ6IG51bWJlcik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAvKipcbiAgICAgKiBVc2luZyBJbnB1dCBmb3IgYnJvd3NlclxuICAgICAqL1xuICAgIGlmICghdGhpcy5wbGF0Zm9ybS5pcygnY2FwYWNpdG9yJykpIHtcbiAgICAgIHJldHVybiB0aGlzLmdldFBpY3R1cmVGcm9tQnJvd3NlcigpO1xuICAgIH1cblxuICAgIGNvbnN0IGFjdGlvblNoZWV0ID0gYXdhaXQgdGhpcy5hY3Rpb25TaGVldEN0cmwuY3JlYXRlKHtcbiAgICAgIGJ1dHRvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHRleHQ6IHRoaXMuZGljdGlvbmFyeS5jYW1lcmEsXG4gICAgICAgICAgaGFuZGxlcjogKCkgPT4ge1xuICAgICAgICAgICAgYWN0aW9uU2hlZXQuZGlzbWlzcygnY2FtZXJhJyk7XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHRleHQ6IHRoaXMuZGljdGlvbmFyeS5hbGJ1bSxcbiAgICAgICAgICBoYW5kbGVyOiAoKSA9PiB7XG4gICAgICAgICAgICBhY3Rpb25TaGVldC5kaXNtaXNzKCdhbGJ1bScpO1xuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICB0ZXh0OiB0aGlzLmRpY3Rpb25hcnkuY2FuY2VsLFxuICAgICAgICAgIHJvbGU6ICdjYW5jZWwnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBhd2FpdCBhY3Rpb25TaGVldC5wcmVzZW50KCk7XG4gICAgY29uc3QgeyBkYXRhIH0gPSBhd2FpdCBhY3Rpb25TaGVldC5vbkRpZERpc21pc3M8J2NhbWVyYScgfCAnYWxidW0nPigpO1xuICAgIGlmICghZGF0YSkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KFBob3RvRWRpdG9yRXJyb3JzLmNhbmNlbCk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGEgPT09ICdjYW1lcmEnKSB7XG4gICAgICBjb25zdCBkZWZhdWx0Q2FtZXJhOiBJbWFnZU9wdGlvbnMgPSB7XG4gICAgICAgIHF1YWxpdHk6IDEwMCxcbiAgICAgICAgd2lkdGg6IHRoaXMuJHBob3RvTWF4U2l6ZSgpLFxuICAgICAgICBhbGxvd0VkaXRpbmc6IGZhbHNlLFxuICAgICAgICByZXN1bHRUeXBlOiBDYW1lcmFSZXN1bHRUeXBlLkRhdGFVcmwsXG4gICAgICAgIHNvdXJjZTogQ2FtZXJhU291cmNlLkNhbWVyYSxcbiAgICAgICAgcHJlc2VudGF0aW9uU3R5bGU6ICdwb3BvdmVyJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBpbWFnZSA9IGF3YWl0IENhbWVyYS5nZXRQaG90byhkZWZhdWx0Q2FtZXJhKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgICAgaWYgKCFpbWFnZT8uZGF0YVVybCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoUGhvdG9FZGl0b3JFcnJvcnMuY2FuY2VsKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpbWFnZS5kYXRhVXJsLmluY2x1ZGVzKCdjYXBhY2l0b3I6Ly9sb2NhbGhvc3QnKSkge1xuICAgICAgICByZXR1cm4gW2ltYWdlLmRhdGFVcmxdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtpbWFnZS5kYXRhVXJsXS5tYXAoYXN5bmMgKGltYWdlKSA9PiBhd2FpdCB0aGlzLmxvYWRQaG90b0Zyb21GaWxlUGF0aChpbWFnZSkpKTtcbiAgICB9XG5cbiAgICBpZiAoZGF0YSA9PT0gJ2FsYnVtJykge1xuICAgICAgY29uc3QgaW1hZ2VzID0gYXdhaXQgQ2FtZXJhLnBpY2tJbWFnZXMoe1xuICAgICAgICBxdWFsaXR5OiAxMDAsXG4gICAgICAgIHdpZHRoOiB0aGlzLiRwaG90b01heFNpemUoKSxcbiAgICAgICAgbGltaXQsXG4gICAgICAgIHByZXNlbnRhdGlvblN0eWxlOiAncG9wb3ZlcicsXG4gICAgICB9KS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuXG4gICAgICBpZiAoIWltYWdlcykge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoUGhvdG9FZGl0b3JFcnJvcnMuY2FuY2VsKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFByb21pc2UuYWxsKGltYWdlcy5waG90b3MubWFwKGFzeW5jIChpbWFnZSkgPT4gYXdhaXQgdGhpcy5sb2FkUGhvdG9Gcm9tRmlsZVBhdGgoaW1hZ2Uud2ViUGF0aCkpKTtcbiAgICB9XG5cbiAgICAvLyBOb3QgcnVuIG9uIHRoaXMgbGluZS4gVGhpcyBpcyBmb3IgbGludFxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0UGljdHVyZUZyb21Ccm93c2VyKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBjb25zdCBpbnB1dEZpbGU6IEhUTUxJbnB1dEVsZW1lbnQgfCBudWxsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignaW5wdXQjYnJvd3NlclBob3RvVXBsb2FkZXInKTtcblxuICAgIGlmICghaW5wdXRGaWxlKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoUGhvdG9FZGl0b3JFcnJvcnMuaW5pdGlhbGl6ZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGlucHV0RmlsZSEuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgJ2NoYW5nZScsXG4gICAgICAgIChlOiBFdmVudCkgPT4ge1xuICAgICAgICAgIGlmICghKGUudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQpLmZpbGVzIHx8ICEoZS50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkuZmlsZXMhWzBdKSB7XG4gICAgICAgICAgICByZWplY3QoUGhvdG9FZGl0b3JFcnJvcnMuY2FuY2VsKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgZmlsZSA9IChlLnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS5maWxlcyFbMF07XG4gICAgICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcblxuICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSAoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGZpbGUudHlwZS5pbmRleE9mKCdpbWFnZScpIDwgMCkge1xuICAgICAgICAgICAgICByZWplY3QoUGhvdG9FZGl0b3JFcnJvcnMudHlwZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgaW5wdXRGaWxlLnZhbHVlID0gJyc7XG4gICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGV2ZW50LnRhcmdldCEucmVzdWx0IGFzIHN0cmluZztcbiAgICAgICAgICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMubG9hZFBob3RvRnJvbUZpbGVQYXRoKHJlc3VsdCk7XG4gICAgICAgICAgICAgIHJlc29sdmUoW2RhdGFdKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSkoKTtcblxuICAgICAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xuICAgICAgICB9LFxuICAgICAgICBmYWxzZSxcbiAgICAgICk7XG4gICAgICBpbnB1dEZpbGUuY2xpY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFBob3RvRnJvbUZpbGVQYXRoKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGRlZmF1bHRJbnN0YW5jZSA9IG5ldyBJbWFnZUVkaXRvcihkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSwge1xuICAgICAgY3NzTWF4V2lkdGg6IHRoaXMuJHBob3RvTWF4U2l6ZSgpLFxuICAgICAgY3NzTWF4SGVpZ2h0OiB0aGlzLiRwaG90b01heFNpemUoKSxcbiAgICB9KTtcbiAgICBjb25zdCBibG9iID0gYXdhaXQgZmV0Y2goZmlsZVBhdGgpLnRoZW4oKHJlcykgPT4gcmVzLmJsb2IoKSk7XG4gICAgY29uc3QgbG9hZGVkID0gYXdhaXQgZGVmYXVsdEluc3RhbmNlLmxvYWRJbWFnZUZyb21GaWxlKG5ldyBGaWxlKFtibG9iXSwgJ2RhdGEucG5nJywgeyB0eXBlOiBibG9iLnR5cGUgfSkpO1xuXG4gICAgY29uc3QgbWF4U2l6ZSA9IE1hdGgubWF4KGxvYWRlZC5uZXdXaWR0aCwgbG9hZGVkLm5ld0hlaWdodCk7XG4gICAgY29uc3QgZGF0YVVybCA9IGRlZmF1bHRJbnN0YW5jZS50b0RhdGFVUkwoe1xuICAgICAgbXVsdGlwbGllcjogdGhpcy4kcGhvdG9NYXhTaXplKCkgLyBtYXhTaXplLFxuICAgIH0pO1xuICAgIGRlZmF1bHRJbnN0YW5jZS5kZXN0cm95KCk7XG5cbiAgICByZXR1cm4gZGF0YVVybDtcbiAgfVxufVxuIl19
|
package/esm2022/lib/types.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export {};
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9waG90by1lZGl0b3Ivc3JjL2xpYi90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGludGVyZmFjZSBJRmlsdGVyIHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBzdHJpbmc7XG4gIG9wdGlvbjogYW55O1xuICBkYXRhOiBzdHJpbmc7XG4gIHdpZHRoOiBudW1iZXI7XG4gIGhlaWdodDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElTaXplIHtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSURpY3Rpb25hcnlGb3JFZGl0b3Ige1xuICBzYXZlOiBzdHJpbmc7XG4gIGNyb3A6IHN0cmluZztcbiAgZmlsdGVyOiBzdHJpbmc7XG4gIGJyaWdodG5lc3M6IHN0cmluZztcbiAgb3JpZ2luYWw6IHN0cmluZztcbiAgaW52ZXJ0OiBzdHJpbmc7XG4gIHNlcGlhOiBzdHJpbmc7XG4gIHZpbnRhZ2U6IHN0cmluZztcbiAgYmx1cjogc3RyaW5nO1xuICBncmF5c2NhbGU6IHN0cmluZztcbiAgc2hhcnBlbjogc3RyaW5nO1xuICBlbWJvc3M6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJRmlsdGVyUHJlc2V0IHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBzdHJpbmc7XG4gIG9wdGlvbjogYW55O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQaG90b0VkaXRvckRpc21pc3Mge1xuICB2YWx1ZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElQaG90b1ZpZXdlckRpc21pc3Mge1xuICBkZWxldGU6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSURpY3Rpb25hcnlGb3JWaWV3ZXIge1xuICBkZWxldGU6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJRGljdGlvbmFyeUZvclNlcnZpY2Uge1xuICBjYW1lcmE6IHN0cmluZztcbiAgYWxidW06IHN0cmluZztcbiAgY2FuY2VsOiBzdHJpbmc7XG59XG4iXX0=
|
package/esm2022/public-api.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Public API Surface of photo-editor
|
|
3
3
|
*/
|
|
4
|
-
export * from './lib/
|
|
4
|
+
export * from './lib/pages/photo-editor.page';
|
|
5
|
+
export * from './lib/pages/photo-viewer.page';
|
|
6
|
+
export * from './lib/service/photo-file.service';
|
|
5
7
|
export * from './lib/types';
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3Bob3RvLWVkaXRvci9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsK0JBQStCLENBQUM7QUFDOUMsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLGtDQUFrQyxDQUFDO0FBQ2pELGNBQWMsYUFBYSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBwaG90by1lZGl0b3JcbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9wYWdlcy9waG90by1lZGl0b3IucGFnZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9wYWdlcy9waG90by12aWV3ZXIucGFnZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zZXJ2aWNlL3Bob3RvLWZpbGUuc2VydmljZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90eXBlcyc7XG4iXX0=
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, signal, inject, Component, Input, ViewChild } from '@angular/core';
|
|
3
|
-
import { CommonModule, NgOptimizedImage } from '@angular/common';
|
|
2
|
+
import { Injectable, signal, inject, Component, Input, ViewChild, ElementRef, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
3
|
+
import { CommonModule, NgOptimizedImage, NgFor, NgIf } from '@angular/common';
|
|
4
4
|
import { FormsModule } from '@angular/forms';
|
|
5
5
|
import * as i1 from '@ionic/angular/standalone';
|
|
6
|
-
import { IonHeader, IonToolbar, IonButtons, IonButton, IonIcon, IonContent, IonFooter, IonText, IonRange, ModalController } from '@ionic/angular/standalone';
|
|
6
|
+
import { IonHeader, IonToolbar, IonButtons, IonButton, IonIcon, IonContent, IonFooter, IonText, IonRange, ModalController, IonicSlides, ActionSheetController, Platform } from '@ionic/angular/standalone';
|
|
7
7
|
import ImageEditor from 'tui-image-editor';
|
|
8
8
|
import { toObservable } from '@angular/core/rxjs-interop';
|
|
9
9
|
import { addIcons } from 'ionicons';
|
|
10
|
-
import { closeOutline, send, cropOutline, colorFilterOutline, sunnyOutline, expandOutline, tabletLandscapeOutline, squareOutline, refreshOutline, checkmarkOutline } from 'ionicons/icons';
|
|
10
|
+
import { closeOutline, removeOutline, send, cropOutline, colorFilterOutline, sunnyOutline, expandOutline, tabletLandscapeOutline, squareOutline, refreshOutline, checkmarkOutline } from 'ionicons/icons';
|
|
11
|
+
import { Navigation, Zoom } from 'swiper/modules';
|
|
12
|
+
import { fromEvent, withLatestFrom, zipWith, throttleTime } from 'rxjs';
|
|
13
|
+
import { register } from 'swiper/element/bundle';
|
|
14
|
+
import { CameraResultType, CameraSource, Camera } from '@capacitor/camera';
|
|
11
15
|
|
|
12
16
|
const filterPreset = (dictionary) => [
|
|
13
17
|
{
|
|
@@ -52,9 +56,15 @@ const filterPreset = (dictionary) => [
|
|
|
52
56
|
// },
|
|
53
57
|
];
|
|
54
58
|
|
|
55
|
-
class
|
|
59
|
+
class HelperService {
|
|
56
60
|
constructor() { }
|
|
57
|
-
|
|
61
|
+
initializeViewerIcons() {
|
|
62
|
+
addIcons({
|
|
63
|
+
closeOutline,
|
|
64
|
+
removeOutline,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
initializeEditorIcons() {
|
|
58
68
|
addIcons({
|
|
59
69
|
closeOutline,
|
|
60
70
|
send,
|
|
@@ -79,19 +89,16 @@ class PhotoEditorService {
|
|
|
79
89
|
});
|
|
80
90
|
});
|
|
81
91
|
}
|
|
82
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.
|
|
83
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.
|
|
92
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: HelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
93
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: HelperService }); }
|
|
84
94
|
}
|
|
85
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.
|
|
86
|
-
type: Injectable
|
|
87
|
-
args: [{
|
|
88
|
-
providedIn: 'root',
|
|
89
|
-
}]
|
|
95
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: HelperService, decorators: [{
|
|
96
|
+
type: Injectable
|
|
90
97
|
}], ctorParameters: () => [] });
|
|
91
98
|
|
|
92
99
|
const ionComponents = [IonHeader, IonToolbar, IonButtons, IonButton, IonIcon, IonContent, IonFooter, IonText, IonRange];
|
|
93
100
|
|
|
94
|
-
const
|
|
101
|
+
const dictionaryForEditor = () => ({
|
|
95
102
|
// UI labels
|
|
96
103
|
save: '保存',
|
|
97
104
|
crop: '切り抜き・回転',
|
|
@@ -107,14 +114,24 @@ const dictionary = () => ({
|
|
|
107
114
|
sharpen: '輪郭',
|
|
108
115
|
emboss: 'エンボス',
|
|
109
116
|
});
|
|
117
|
+
const dictionaryForViewer = () => ({
|
|
118
|
+
// UI labels
|
|
119
|
+
delete: '削除',
|
|
120
|
+
});
|
|
121
|
+
const dictionaryForService = () => ({
|
|
122
|
+
// UI labels
|
|
123
|
+
camera: 'カメラ撮影',
|
|
124
|
+
album: 'アルバムから選択',
|
|
125
|
+
cancel: 'キャンセル',
|
|
126
|
+
});
|
|
110
127
|
|
|
111
128
|
class PhotoEditorPage {
|
|
112
|
-
set
|
|
129
|
+
set labels(d) {
|
|
113
130
|
this.dictionary = Object.assign(this.dictionary, d);
|
|
114
131
|
this.filterPreset = filterPreset(this.dictionary);
|
|
115
132
|
}
|
|
116
133
|
constructor() {
|
|
117
|
-
this.dictionary =
|
|
134
|
+
this.dictionary = dictionaryForEditor();
|
|
118
135
|
this.filterPreset = filterPreset(this.dictionary);
|
|
119
136
|
this.requireSquare = false;
|
|
120
137
|
this.$filters = signal([]);
|
|
@@ -130,7 +147,7 @@ class PhotoEditorPage {
|
|
|
130
147
|
this.$adoptFilter = signal(undefined);
|
|
131
148
|
this.initSubscription$ = [];
|
|
132
149
|
this.filterImageSize = 240;
|
|
133
|
-
this.service = inject(
|
|
150
|
+
this.service = inject(HelperService);
|
|
134
151
|
this.modalCtrl = inject(ModalController);
|
|
135
152
|
this.canvasContainerObserver = new MutationObserver((mutationsList) => {
|
|
136
153
|
if (mutationsList.find((mutation) => mutation.type === 'attributes' && mutation.attributeName === 'style')) {
|
|
@@ -143,7 +160,7 @@ class PhotoEditorPage {
|
|
|
143
160
|
});
|
|
144
161
|
}
|
|
145
162
|
});
|
|
146
|
-
this.service.
|
|
163
|
+
this.service.initializeEditorIcons();
|
|
147
164
|
}
|
|
148
165
|
ngOnInit() {
|
|
149
166
|
this.initSubscription$.push(this.footerMenu$.subscribe((value) => {
|
|
@@ -263,17 +280,17 @@ class PhotoEditorPage {
|
|
|
263
280
|
await this.editorInstance.applyFilter(filter.type, filter.option);
|
|
264
281
|
this.$adoptFilter.set(filter);
|
|
265
282
|
}
|
|
266
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.
|
|
267
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.0.
|
|
283
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoEditorPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
284
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.0.7", type: PhotoEditorPage, isStandalone: true, selector: "app-editor-image", inputs: { requireSquare: "requireSquare", value: "value", labels: "labels" }, providers: [HelperService], viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["imageEditor"], descendants: true, static: true }, { propertyName: "ionContent", first: true, predicate: IonContent, descendants: true }], ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\"\n ><ion-button (click)=\"modalCtrl.dismiss()\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button\n ></ion-buttons>\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"outline\" [disabled]=\"!['menu', 'filter'].includes($footerMenu())\" (click)=\"imageSave()\">\n {{ dictionary.save }}\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\" [scrollY]=\"false\">\n <div #imageEditor></div>\n</ion-content>\n<ion-footer>\n <ion-toolbar>\n @if (this.$footerMenu() === 'menu') {\n <aside class=\"ion-justify-content-center\">\n <button (click)=\"$footerMenu.set('crop')\">\n <ion-text>{{ dictionary.crop }}</ion-text>\n <ion-icon name=\"crop-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('filter')\">\n <ion-text>{{ dictionary.filter }}</ion-text>\n <ion-icon name=\"color-filter-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('brightness')\">\n <ion-text>{{ dictionary.brightness }}</ion-text>\n <ion-icon name=\"sunny-outline\" size=\"large\"></ion-icon>\n </button>\n </aside>\n }\n\n @if (this.$footerMenu() === 'filter') {\n <aside>\n @for (item of $filters(); track item) {\n <button (click)=\"filterImage(item)\">\n <ion-text>{{ item.name }}</ion-text>\n <span class=\"image-filter-box\" [style.background-image]=\"'url(' + item.data + ')'\"></span>\n </button>\n }\n </aside>\n }\n\n @if (this.$footerMenu() === 'crop' && !requireSquare) {\n <ion-buttons class=\"ion-justify-content-center submenu-icon-buttons\">\n <ion-button (click)=\"changeCrop('cover')\" [color]=\"$currentCrop() === 'cover' ? 'success' : undefined\">\n <ion-icon name=\"expand-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('16/9')\" [color]=\"$currentCrop() === '16/9' ? 'success' : undefined\">\n <ion-icon name=\"tablet-landscape-outline\" slot=\"icon-only\" style=\"transform: scale(1, 0.8)\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('1')\" [color]=\"$currentCrop() === '1' ? 'success' : undefined\">\n <ion-icon name=\"square-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('auto')\" [color]=\"$currentCrop() === 'auto' ? 'success' : undefined\">\n <ion-icon name=\"crop-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"rotate()\"><ion-icon name=\"refresh-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n </ion-buttons>\n }\n\n @if (['brightness'].includes(this.$footerMenu())) {\n <div class=\"ion-padding ion-margin\">\n <ion-range [pin]=\"true\" [min]=\"-100\" [max]=\"100\" (ionChange)=\"changeRange($any($event))\"></ion-range>\n </div>\n }\n </ion-toolbar>\n @if (this.$footerMenu() !== 'menu') {\n <ion-toolbar mode=\"md\">\n @if (this.$footerMenu() === 'filter') {\n <ion-buttons class=\"ion-justify-content-center\" style=\"margin: 0 8px\">\n <ion-button fill=\"outline\" shape=\"round\" (click)=\"this.$footerMenu.set('menu')\">\u623B\u308B</ion-button>\n </ion-buttons>\n } @else {\n <ion-buttons slot=\"start\" style=\"min-width: 60px\">\n @if (!requireSquare || $isCropped()) {\n <ion-button (click)=\"closeCrop('cancel')\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n }</ion-buttons\n ><ion-text class=\"footer-title\">\n @if ($footerMenu() === 'crop') {\n {{ dictionary.crop }}\n } @else if ($footerMenu() === 'brightness') {\n {{ dictionary.brightness }}\n }</ion-text\n ><ion-buttons slot=\"end\"\n ><ion-button (click)=\"closeCrop('apply')\"\n ><ion-icon name=\"checkmark-outline\" slot=\"icon-only\" color=\"success\"></ion-icon></ion-button\n ></ion-buttons>\n }\n </ion-toolbar>\n }\n</ion-footer>\n", styles: ["@charset \"UTF-8\";:host{--alway-dark: var(--ion-color-step-100, #2a2a2a);--alway-dark-tint: var(--ion-color-step-200, #414141);--alway-white: var(--ion-color-step-950, #f0f0f0);--alway-white-tint: var(--ion-color-step-850, #dbdbdb)}ion-content,ion-toolbar,ion-header,ion-footer{background:var(--alway-dark);--background: var(--alway-dark)}\n", "ion-content{--background: var(--alway-dark)}ion-content>div{width:100%;height:100%;max-width:100%;max-height:100%;display:grid;align-items:center;justify-items:center}aside{display:flex;overflow-x:scroll;margin-top:16px;min-height:120px}aside ion-icon{color:var(--alway-white);border:1px solid var(--alway-dark-tint);border-radius:50%;padding:16px}aside button{width:120px;display:block;flex:1;background:transparent;margin:0 8px 16px}aside button ion-text{display:block;color:var(--alway-white);margin-bottom:8px;font-size:.8rem}aside button span.image-filter-box{width:96px;height:64px;border-radius:8px;overflow:hidden;display:block;background-position:center,center;background-size:cover}ion-header ion-button,ion-footer ion-button{--color: var(--alway-white) !important}ion-footer ion-toolbar ion-text.footer-title{color:var(--alway-white)!important;display:block;text-align:center}ion-footer ion-toolbar ion-range{--bar-background: var(--alway-white);--bar-background-active: var(--alway-white);--bar-height: 2px;--bar-border-radius: 8px;--knob-background: var(--alway-white);--knob-size: 20px;--pin-background: none;--pin-color: var(--alway-white)}ion-footer ion-toolbar ion-buttons[slot=start] ion-button,ion-footer ion-toolbar ion-buttons[slot=end] ion-button{--background: var(--alway-dark-tint) !important;--border-radius: 50%;margin:0 8px;min-width:32px;min-height:32px}ion-footer ion-toolbar ion-buttons.submenu-icon-buttons ion-button{margin:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i1.IonRange, selector: "ion-range", inputs: ["activeBarStart", "color", "debounce", "disabled", "dualKnobs", "label", "labelPlacement", "legacy", "max", "min", "mode", "name", "pin", "pinFormatter", "snaps", "step", "ticks", "value"] }] }); }
|
|
268
285
|
}
|
|
269
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.
|
|
286
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoEditorPage, decorators: [{
|
|
270
287
|
type: Component,
|
|
271
|
-
args: [{ selector: 'app-editor-image', standalone: true, imports: [CommonModule, FormsModule, NgOptimizedImage, ...ionComponents], template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\"\n ><ion-button (click)=\"modalCtrl.dismiss()\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button\n ></ion-buttons>\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"outline\" [disabled]=\"!['menu', 'filter'].includes($footerMenu())\" (click)=\"imageSave()\">\n {{ dictionary.save }}\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\" [scrollY]=\"false\">\n <div #imageEditor></div>\n</ion-content>\n<ion-footer>\n <ion-toolbar>\n @if (this.$footerMenu() === 'menu') {\n <aside class=\"ion-justify-content-center\">\n <button (click)=\"$footerMenu.set('crop')\">\n <ion-text>{{ dictionary.crop }}</ion-text>\n <ion-icon name=\"crop-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('filter')\">\n <ion-text>{{ dictionary.filter }}</ion-text>\n <ion-icon name=\"color-filter-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('brightness')\">\n <ion-text>{{ dictionary.brightness }}</ion-text>\n <ion-icon name=\"sunny-outline\" size=\"large\"></ion-icon>\n </button>\n </aside>\n }\n\n @if (this.$footerMenu() === 'filter') {\n <aside>\n @for (item of $filters(); track item) {\n <button (click)=\"filterImage(item)\">\n <ion-text>{{ item.name }}</ion-text>\n <span class=\"image-filter-box\" [style.background-image]=\"'url(' + item.data + ')'\"></span>\n </button>\n }\n </aside>\n }\n\n @if (this.$footerMenu() === 'crop' && !requireSquare) {\n <ion-buttons class=\"ion-justify-content-center submenu-icon-buttons\">\n <ion-button (click)=\"changeCrop('cover')\" [color]=\"$currentCrop() === 'cover' ? 'success' : undefined\">\n <ion-icon name=\"expand-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('16/9')\" [color]=\"$currentCrop() === '16/9' ? 'success' : undefined\">\n <ion-icon name=\"tablet-landscape-outline\" slot=\"icon-only\" style=\"transform: scale(1, 0.8)\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('1')\" [color]=\"$currentCrop() === '1' ? 'success' : undefined\">\n <ion-icon name=\"square-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('auto')\" [color]=\"$currentCrop() === 'auto' ? 'success' : undefined\">\n <ion-icon name=\"crop-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"rotate()\"><ion-icon name=\"refresh-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n </ion-buttons>\n }\n\n @if (['brightness'].includes(this.$footerMenu())) {\n <div class=\"ion-padding ion-margin\">\n <ion-range [pin]=\"true\" [min]=\"-100\" [max]=\"100\" (ionChange)=\"changeRange($any($event))\"></ion-range>\n </div>\n }\n </ion-toolbar>\n @if (this.$footerMenu() !== 'menu') {\n <ion-toolbar mode=\"md\">\n @if (this.$footerMenu() === 'filter') {\n <ion-buttons class=\"ion-justify-content-center\" style=\"margin: 0 8px\">\n <ion-button fill=\"outline\" shape=\"round\" (click)=\"this.$footerMenu.set('menu')\">\u623B\u308B</ion-button>\n </ion-buttons>\n } @else {\n <ion-buttons slot=\"start\" style=\"min-width: 60px\">\n @if (!requireSquare || $isCropped()) {\n <ion-button (click)=\"closeCrop('cancel')\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n }</ion-buttons\n ><ion-text class=\"footer-title\">\n @if ($footerMenu() === 'crop') {\n {{ dictionary.crop }}\n } @else if ($footerMenu() === 'brightness') {\n {{ dictionary.brightness }}\n }</ion-text\n ><ion-buttons slot=\"end\"\n ><ion-button (click)=\"closeCrop('apply')\"\n ><ion-icon name=\"checkmark-outline\" slot=\"icon-only\" color=\"success\"></ion-icon></ion-button\n ></ion-buttons>\n }\n </ion-toolbar>\n }\n</ion-footer>\n", styles: ["@charset \"UTF-8\";:host{--alway-dark: var(--ion-color-step-100, #2a2a2a);--alway-dark-tint: var(--ion-color-step-200, #414141);--alway-white: var(--ion-color-step-950, #f0f0f0);--alway-white-tint: var(--ion-color-step-850, #dbdbdb)}ion-content,ion-toolbar,ion-header,ion-footer{background:var(--alway-dark);--background: var(--alway-dark)}ion-content{--background: var(--alway-dark)}ion-content>div{width:100%;height:100%;max-width:100%;max-height:100%;display:grid;align-items:center;justify-items:center}aside{display:flex;overflow-x:scroll;margin-top:16px;min-height:120px}aside ion-icon{color:var(--alway-white);border:1px solid var(--alway-dark-tint);border-radius:50%;padding:16px}aside button{width:120px;display:block;flex:1;background:transparent;margin:0 8px 16px}aside button ion-text{display:block;color:var(--alway-white);margin-bottom:8px;font-size:.8rem}aside button span.image-filter-box{width:96px;height:64px;border-radius:8px;overflow:hidden;display:block;background-position:center,center;background-size:cover}ion-header ion-button,ion-footer ion-button{--color: var(--alway-white) !important}ion-footer ion-toolbar ion-text.footer-title{color:var(--alway-white)!important;display:block;text-align:center}ion-footer ion-toolbar ion-range{--bar-background: var(--alway-white);--bar-background-active: var(--alway-white);--bar-height: 2px;--bar-border-radius: 8px;--knob-background: var(--alway-white);--knob-size: 20px;--pin-background: none;--pin-color: var(--alway-white)}ion-footer ion-toolbar ion-buttons[slot=start] ion-button,ion-footer ion-toolbar ion-buttons[slot=end] ion-button{--background: var(--alway-dark-tint) !important;--border-radius: 50%;margin:0 8px;min-width:32px;min-height:32px}ion-footer ion-toolbar ion-buttons.submenu-icon-buttons ion-button{margin:16px}\n"] }]
|
|
288
|
+
args: [{ selector: 'app-editor-image', standalone: true, imports: [CommonModule, FormsModule, NgOptimizedImage, ...ionComponents], providers: [HelperService], template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\"\n ><ion-button (click)=\"modalCtrl.dismiss()\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button\n ></ion-buttons>\n <ion-buttons slot=\"end\">\n <ion-button color=\"primary\" fill=\"outline\" [disabled]=\"!['menu', 'filter'].includes($footerMenu())\" (click)=\"imageSave()\">\n {{ dictionary.save }}\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\" [scrollY]=\"false\">\n <div #imageEditor></div>\n</ion-content>\n<ion-footer>\n <ion-toolbar>\n @if (this.$footerMenu() === 'menu') {\n <aside class=\"ion-justify-content-center\">\n <button (click)=\"$footerMenu.set('crop')\">\n <ion-text>{{ dictionary.crop }}</ion-text>\n <ion-icon name=\"crop-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('filter')\">\n <ion-text>{{ dictionary.filter }}</ion-text>\n <ion-icon name=\"color-filter-outline\" size=\"large\"></ion-icon>\n </button>\n <button (click)=\"$footerMenu.set('brightness')\">\n <ion-text>{{ dictionary.brightness }}</ion-text>\n <ion-icon name=\"sunny-outline\" size=\"large\"></ion-icon>\n </button>\n </aside>\n }\n\n @if (this.$footerMenu() === 'filter') {\n <aside>\n @for (item of $filters(); track item) {\n <button (click)=\"filterImage(item)\">\n <ion-text>{{ item.name }}</ion-text>\n <span class=\"image-filter-box\" [style.background-image]=\"'url(' + item.data + ')'\"></span>\n </button>\n }\n </aside>\n }\n\n @if (this.$footerMenu() === 'crop' && !requireSquare) {\n <ion-buttons class=\"ion-justify-content-center submenu-icon-buttons\">\n <ion-button (click)=\"changeCrop('cover')\" [color]=\"$currentCrop() === 'cover' ? 'success' : undefined\">\n <ion-icon name=\"expand-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('16/9')\" [color]=\"$currentCrop() === '16/9' ? 'success' : undefined\">\n <ion-icon name=\"tablet-landscape-outline\" slot=\"icon-only\" style=\"transform: scale(1, 0.8)\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('1')\" [color]=\"$currentCrop() === '1' ? 'success' : undefined\">\n <ion-icon name=\"square-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"changeCrop('auto')\" [color]=\"$currentCrop() === 'auto' ? 'success' : undefined\">\n <ion-icon name=\"crop-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n <ion-button (click)=\"rotate()\"><ion-icon name=\"refresh-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n </ion-buttons>\n }\n\n @if (['brightness'].includes(this.$footerMenu())) {\n <div class=\"ion-padding ion-margin\">\n <ion-range [pin]=\"true\" [min]=\"-100\" [max]=\"100\" (ionChange)=\"changeRange($any($event))\"></ion-range>\n </div>\n }\n </ion-toolbar>\n @if (this.$footerMenu() !== 'menu') {\n <ion-toolbar mode=\"md\">\n @if (this.$footerMenu() === 'filter') {\n <ion-buttons class=\"ion-justify-content-center\" style=\"margin: 0 8px\">\n <ion-button fill=\"outline\" shape=\"round\" (click)=\"this.$footerMenu.set('menu')\">\u623B\u308B</ion-button>\n </ion-buttons>\n } @else {\n <ion-buttons slot=\"start\" style=\"min-width: 60px\">\n @if (!requireSquare || $isCropped()) {\n <ion-button (click)=\"closeCrop('cancel')\"><ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon></ion-button>\n }</ion-buttons\n ><ion-text class=\"footer-title\">\n @if ($footerMenu() === 'crop') {\n {{ dictionary.crop }}\n } @else if ($footerMenu() === 'brightness') {\n {{ dictionary.brightness }}\n }</ion-text\n ><ion-buttons slot=\"end\"\n ><ion-button (click)=\"closeCrop('apply')\"\n ><ion-icon name=\"checkmark-outline\" slot=\"icon-only\" color=\"success\"></ion-icon></ion-button\n ></ion-buttons>\n }\n </ion-toolbar>\n }\n</ion-footer>\n", styles: ["@charset \"UTF-8\";:host{--alway-dark: var(--ion-color-step-100, #2a2a2a);--alway-dark-tint: var(--ion-color-step-200, #414141);--alway-white: var(--ion-color-step-950, #f0f0f0);--alway-white-tint: var(--ion-color-step-850, #dbdbdb)}ion-content,ion-toolbar,ion-header,ion-footer{background:var(--alway-dark);--background: var(--alway-dark)}\n", "ion-content{--background: var(--alway-dark)}ion-content>div{width:100%;height:100%;max-width:100%;max-height:100%;display:grid;align-items:center;justify-items:center}aside{display:flex;overflow-x:scroll;margin-top:16px;min-height:120px}aside ion-icon{color:var(--alway-white);border:1px solid var(--alway-dark-tint);border-radius:50%;padding:16px}aside button{width:120px;display:block;flex:1;background:transparent;margin:0 8px 16px}aside button ion-text{display:block;color:var(--alway-white);margin-bottom:8px;font-size:.8rem}aside button span.image-filter-box{width:96px;height:64px;border-radius:8px;overflow:hidden;display:block;background-position:center,center;background-size:cover}ion-header ion-button,ion-footer ion-button{--color: var(--alway-white) !important}ion-footer ion-toolbar ion-text.footer-title{color:var(--alway-white)!important;display:block;text-align:center}ion-footer ion-toolbar ion-range{--bar-background: var(--alway-white);--bar-background-active: var(--alway-white);--bar-height: 2px;--bar-border-radius: 8px;--knob-background: var(--alway-white);--knob-size: 20px;--pin-background: none;--pin-color: var(--alway-white)}ion-footer ion-toolbar ion-buttons[slot=start] ion-button,ion-footer ion-toolbar ion-buttons[slot=end] ion-button{--background: var(--alway-dark-tint) !important;--border-radius: 50%;margin:0 8px;min-width:32px;min-height:32px}ion-footer ion-toolbar ion-buttons.submenu-icon-buttons ion-button{margin:16px}\n"] }]
|
|
272
289
|
}], ctorParameters: () => [], propDecorators: { requireSquare: [{
|
|
273
290
|
type: Input
|
|
274
291
|
}], value: [{
|
|
275
292
|
type: Input
|
|
276
|
-
}],
|
|
293
|
+
}], labels: [{
|
|
277
294
|
type: Input
|
|
278
295
|
}], editorRef: [{
|
|
279
296
|
type: ViewChild,
|
|
@@ -283,6 +300,228 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.6", ngImpor
|
|
|
283
300
|
args: [IonContent]
|
|
284
301
|
}] } });
|
|
285
302
|
|
|
303
|
+
class PhotoViewerPage {
|
|
304
|
+
set labels(d) {
|
|
305
|
+
this.dictionary = Object.assign(this.dictionary, d);
|
|
306
|
+
}
|
|
307
|
+
constructor() {
|
|
308
|
+
this.dictionary = dictionaryForViewer();
|
|
309
|
+
this.imageUrls = [];
|
|
310
|
+
this.index = 0;
|
|
311
|
+
this.isCircle = false;
|
|
312
|
+
this.enableDelete = false;
|
|
313
|
+
this.enableFooterSafeArea = false;
|
|
314
|
+
this.modalCtrl = inject(ModalController);
|
|
315
|
+
this.el = inject(ElementRef);
|
|
316
|
+
this.service = inject(HelperService);
|
|
317
|
+
register();
|
|
318
|
+
this.service.initializeViewerIcons();
|
|
319
|
+
}
|
|
320
|
+
async ngOnInit() {
|
|
321
|
+
this.service.waitToFindDom(this.el.nativeElement, 'swiper-container').then(() => {
|
|
322
|
+
Object.assign(this.swiper.nativeElement, {
|
|
323
|
+
modules: [Navigation, Zoom, IonicSlides],
|
|
324
|
+
initialSlide: this.index,
|
|
325
|
+
slidesPerView: 1,
|
|
326
|
+
pagination: {
|
|
327
|
+
enabled: true,
|
|
328
|
+
clickable: true,
|
|
329
|
+
},
|
|
330
|
+
zoom: true,
|
|
331
|
+
});
|
|
332
|
+
this.swiper.nativeElement.initialize();
|
|
333
|
+
this.swiper.nativeElement.swiper.zoom.enable();
|
|
334
|
+
this.swiper.nativeElement.swiper.activeIndex = this.index;
|
|
335
|
+
this.swiper.nativeElement.swiper.update();
|
|
336
|
+
});
|
|
337
|
+
this.watchSwipe$ = fromEvent(this.el.nativeElement, 'touchstart')
|
|
338
|
+
.pipe(zipWith(fromEvent(this.el.nativeElement, 'touchend').pipe(withLatestFrom(fromEvent(this.el.nativeElement, 'touchmove')))), throttleTime(1))
|
|
339
|
+
.subscribe(([touchstart, [_, touchmove]]) => {
|
|
340
|
+
const touchstartClientX = touchstart.touches ? touchstart.touches[0].clientX : touchstart.detail[1].clientX;
|
|
341
|
+
const touchmoveClientX = touchmove.touches ? touchmove.touches[0].clientX : touchmove.detail[1].clientX;
|
|
342
|
+
const touchstartClientY = touchstart.touches ? touchstart.touches[0].clientY : touchstart.detail[1].clientY;
|
|
343
|
+
const touchmoveClientY = touchmove.touches ? touchmove.touches[0].clientY : touchmove.detail[1].clientY;
|
|
344
|
+
const xDiff = touchstartClientX - touchmoveClientX;
|
|
345
|
+
const yDiff = touchstartClientY - touchmoveClientY;
|
|
346
|
+
const slides = this.swiper.nativeElement.querySelectorAll('swiper-slide');
|
|
347
|
+
const isZoomed = Array.from(slides).find((slide) => {
|
|
348
|
+
return ['swiper-slide-zoomed', 'swiper-slide-active'].every((c) => slide.classList.contains(c));
|
|
349
|
+
});
|
|
350
|
+
const threshold = touchmove.touches ? -50 : -5;
|
|
351
|
+
if (!isZoomed && Math.abs(xDiff) < Math.abs(threshold) && yDiff < threshold && touchstart.timeStamp <= touchmove.timeStamp) {
|
|
352
|
+
this.watchSwipe$.unsubscribe();
|
|
353
|
+
this.modalCtrl.dismiss();
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
ngOnDestroy() {
|
|
358
|
+
if (this.watchSwipe$ && !this.watchSwipe$.closed) {
|
|
359
|
+
this.watchSwipe$.unsubscribe();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
remove() {
|
|
363
|
+
this.modalCtrl.dismiss({ delete: true });
|
|
364
|
+
}
|
|
365
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoViewerPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
366
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.0.7", type: PhotoViewerPage, isStandalone: true, selector: "app-photo-image", inputs: { imageUrls: "imageUrls", index: "index", isCircle: "isCircle", enableDelete: "enableDelete", enableFooterSafeArea: "enableFooterSafeArea", labels: "labels" }, providers: [HelperService], viewQueries: [{ propertyName: "swiper", first: true, predicate: ["swiper"], descendants: true }], ngImport: i0, template: "<ion-header [translucent]=\"true\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"modalCtrl.dismiss()\" class=\"viewer-close-button\">\n <ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </ion-buttons>\n @if (enableDelete) {\n <ion-buttons slot=\"end\">\n <ion-button color=\"danger\" fill=\"outline\" (click)=\"remove()\">{{ dictionary.delete }}</ion-button>\n </ion-buttons>\n }\n </ion-toolbar>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n <swiper-container #swiper>\n @for (url of imageUrls; track url) {\n <swiper-slide>\n <div class=\"swiper-zoom-container\"><img [src]=\"url\" alt=\"\" [class.circle]=\"isCircle\" /></div>\n </swiper-slide>\n }\n </swiper-container>\n</ion-content>\n\n@if (enableFooterSafeArea) {\n <!-- use for safe area-->\n <ion-footer>\n <ion-toolbar style=\"--border-width: 0; --min-height: 0\"></ion-toolbar>\n </ion-footer>\n}\n", styles: ["@charset \"UTF-8\";:host{--alway-dark: var(--ion-color-step-100, #2a2a2a);--alway-dark-tint: var(--ion-color-step-200, #414141);--alway-white: var(--ion-color-step-950, #f0f0f0);--alway-white-tint: var(--ion-color-step-850, #dbdbdb)}ion-content,ion-toolbar,ion-header,ion-footer{background:var(--alway-dark);--background: var(--alway-dark)}\n", "ion-button.viewer-close-button{--color: var(--alway-white) !important}img.circle{border-radius:50%;display:block;padding:16px}swiper-container{height:100%;max-height:100%}swiper-slide{height:100%;max-height:100%;display:flex;justify-content:center;align-items:center}swiper-slide img{display:block;object-fit:contain;max-width:100%;max-height:100%}\n"], dependencies: [{ kind: "component", type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }] }); }
|
|
367
|
+
}
|
|
368
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoViewerPage, decorators: [{
|
|
369
|
+
type: Component,
|
|
370
|
+
args: [{ selector: 'app-photo-image', standalone: true, imports: [NgFor, NgIf, ...ionComponents], schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [HelperService], template: "<ion-header [translucent]=\"true\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"modalCtrl.dismiss()\" class=\"viewer-close-button\">\n <ion-icon name=\"close-outline\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </ion-buttons>\n @if (enableDelete) {\n <ion-buttons slot=\"end\">\n <ion-button color=\"danger\" fill=\"outline\" (click)=\"remove()\">{{ dictionary.delete }}</ion-button>\n </ion-buttons>\n }\n </ion-toolbar>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n <swiper-container #swiper>\n @for (url of imageUrls; track url) {\n <swiper-slide>\n <div class=\"swiper-zoom-container\"><img [src]=\"url\" alt=\"\" [class.circle]=\"isCircle\" /></div>\n </swiper-slide>\n }\n </swiper-container>\n</ion-content>\n\n@if (enableFooterSafeArea) {\n <!-- use for safe area-->\n <ion-footer>\n <ion-toolbar style=\"--border-width: 0; --min-height: 0\"></ion-toolbar>\n </ion-footer>\n}\n", styles: ["@charset \"UTF-8\";:host{--alway-dark: var(--ion-color-step-100, #2a2a2a);--alway-dark-tint: var(--ion-color-step-200, #414141);--alway-white: var(--ion-color-step-950, #f0f0f0);--alway-white-tint: var(--ion-color-step-850, #dbdbdb)}ion-content,ion-toolbar,ion-header,ion-footer{background:var(--alway-dark);--background: var(--alway-dark)}\n", "ion-button.viewer-close-button{--color: var(--alway-white) !important}img.circle{border-radius:50%;display:block;padding:16px}swiper-container{height:100%;max-height:100%}swiper-slide{height:100%;max-height:100%;display:flex;justify-content:center;align-items:center}swiper-slide img{display:block;object-fit:contain;max-width:100%;max-height:100%}\n"] }]
|
|
371
|
+
}], ctorParameters: () => [], propDecorators: { imageUrls: [{
|
|
372
|
+
type: Input
|
|
373
|
+
}], index: [{
|
|
374
|
+
type: Input
|
|
375
|
+
}], isCircle: [{
|
|
376
|
+
type: Input
|
|
377
|
+
}], enableDelete: [{
|
|
378
|
+
type: Input
|
|
379
|
+
}], enableFooterSafeArea: [{
|
|
380
|
+
type: Input
|
|
381
|
+
}], labels: [{
|
|
382
|
+
type: Input
|
|
383
|
+
}], swiper: [{
|
|
384
|
+
type: ViewChild,
|
|
385
|
+
args: ['swiper']
|
|
386
|
+
}] } });
|
|
387
|
+
|
|
388
|
+
var PhotoEditorErrors;
|
|
389
|
+
(function (PhotoEditorErrors) {
|
|
390
|
+
PhotoEditorErrors["initialize"] = "input dom is not found";
|
|
391
|
+
PhotoEditorErrors["cancel"] = "user canceled";
|
|
392
|
+
PhotoEditorErrors["type"] = "upload file is not image.";
|
|
393
|
+
})(PhotoEditorErrors || (PhotoEditorErrors = {}));
|
|
394
|
+
|
|
395
|
+
class PhotoFileService {
|
|
396
|
+
constructor() {
|
|
397
|
+
this.$photoMaxSize = signal(1000);
|
|
398
|
+
this.actionSheetCtrl = inject(ActionSheetController);
|
|
399
|
+
this.platform = inject(Platform);
|
|
400
|
+
this.dictionary = dictionaryForService();
|
|
401
|
+
}
|
|
402
|
+
set photoMaxSize(value) {
|
|
403
|
+
this.$photoMaxSize.set(value);
|
|
404
|
+
}
|
|
405
|
+
set labels(d) {
|
|
406
|
+
this.dictionary = Object.assign(this.dictionary, d);
|
|
407
|
+
}
|
|
408
|
+
async loadPhoto(limit) {
|
|
409
|
+
/**
|
|
410
|
+
* Using Input for browser
|
|
411
|
+
*/
|
|
412
|
+
if (!this.platform.is('capacitor')) {
|
|
413
|
+
return this.getPictureFromBrowser();
|
|
414
|
+
}
|
|
415
|
+
const actionSheet = await this.actionSheetCtrl.create({
|
|
416
|
+
buttons: [
|
|
417
|
+
{
|
|
418
|
+
text: this.dictionary.camera,
|
|
419
|
+
handler: () => {
|
|
420
|
+
actionSheet.dismiss('camera');
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
text: this.dictionary.album,
|
|
425
|
+
handler: () => {
|
|
426
|
+
actionSheet.dismiss('album');
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
text: this.dictionary.cancel,
|
|
431
|
+
role: 'cancel',
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
});
|
|
435
|
+
await actionSheet.present();
|
|
436
|
+
const { data } = await actionSheet.onDidDismiss();
|
|
437
|
+
if (!data) {
|
|
438
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
439
|
+
}
|
|
440
|
+
if (data === 'camera') {
|
|
441
|
+
const defaultCamera = {
|
|
442
|
+
quality: 100,
|
|
443
|
+
width: this.$photoMaxSize(),
|
|
444
|
+
allowEditing: false,
|
|
445
|
+
resultType: CameraResultType.DataUrl,
|
|
446
|
+
source: CameraSource.Camera,
|
|
447
|
+
presentationStyle: 'popover',
|
|
448
|
+
};
|
|
449
|
+
const image = await Camera.getPhoto(defaultCamera).catch(() => undefined);
|
|
450
|
+
if (!image?.dataUrl) {
|
|
451
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
452
|
+
}
|
|
453
|
+
if (!image.dataUrl.includes('capacitor://localhost')) {
|
|
454
|
+
return [image.dataUrl];
|
|
455
|
+
}
|
|
456
|
+
return Promise.all([image.dataUrl].map(async (image) => await this.loadPhotoFromFilePath(image)));
|
|
457
|
+
}
|
|
458
|
+
if (data === 'album') {
|
|
459
|
+
const images = await Camera.pickImages({
|
|
460
|
+
quality: 100,
|
|
461
|
+
width: this.$photoMaxSize(),
|
|
462
|
+
limit,
|
|
463
|
+
presentationStyle: 'popover',
|
|
464
|
+
}).catch(() => undefined);
|
|
465
|
+
if (!images) {
|
|
466
|
+
return Promise.reject(PhotoEditorErrors.cancel);
|
|
467
|
+
}
|
|
468
|
+
return Promise.all(images.photos.map(async (image) => await this.loadPhotoFromFilePath(image.webPath)));
|
|
469
|
+
}
|
|
470
|
+
// Not run on this line. This is for lint
|
|
471
|
+
return [];
|
|
472
|
+
}
|
|
473
|
+
getPictureFromBrowser() {
|
|
474
|
+
const inputFile = document.querySelector('input#browserPhotoUploader');
|
|
475
|
+
if (!inputFile) {
|
|
476
|
+
return Promise.reject(PhotoEditorErrors.initialize);
|
|
477
|
+
}
|
|
478
|
+
return new Promise((resolve, reject) => {
|
|
479
|
+
inputFile.addEventListener('change', (e) => {
|
|
480
|
+
if (!e.target.files || !e.target.files[0]) {
|
|
481
|
+
reject(PhotoEditorErrors.cancel);
|
|
482
|
+
}
|
|
483
|
+
const file = e.target.files[0];
|
|
484
|
+
const reader = new FileReader();
|
|
485
|
+
reader.onload = (() => {
|
|
486
|
+
if (file.type.indexOf('image') < 0) {
|
|
487
|
+
reject(PhotoEditorErrors.type);
|
|
488
|
+
}
|
|
489
|
+
return async (event) => {
|
|
490
|
+
inputFile.value = '';
|
|
491
|
+
const result = event.target.result;
|
|
492
|
+
const data = await this.loadPhotoFromFilePath(result);
|
|
493
|
+
resolve([data]);
|
|
494
|
+
};
|
|
495
|
+
})();
|
|
496
|
+
reader.readAsDataURL(file);
|
|
497
|
+
}, false);
|
|
498
|
+
inputFile.click();
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
async loadPhotoFromFilePath(filePath) {
|
|
502
|
+
const defaultInstance = new ImageEditor(document.createElement('div'), {
|
|
503
|
+
cssMaxWidth: this.$photoMaxSize(),
|
|
504
|
+
cssMaxHeight: this.$photoMaxSize(),
|
|
505
|
+
});
|
|
506
|
+
const blob = await fetch(filePath).then((res) => res.blob());
|
|
507
|
+
const loaded = await defaultInstance.loadImageFromFile(new File([blob], 'data.png', { type: blob.type }));
|
|
508
|
+
const maxSize = Math.max(loaded.newWidth, loaded.newHeight);
|
|
509
|
+
const dataUrl = defaultInstance.toDataURL({
|
|
510
|
+
multiplier: this.$photoMaxSize() / maxSize,
|
|
511
|
+
});
|
|
512
|
+
defaultInstance.destroy();
|
|
513
|
+
return dataUrl;
|
|
514
|
+
}
|
|
515
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
516
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, providedIn: 'root' }); }
|
|
517
|
+
}
|
|
518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: PhotoFileService, decorators: [{
|
|
519
|
+
type: Injectable,
|
|
520
|
+
args: [{
|
|
521
|
+
providedIn: 'root',
|
|
522
|
+
}]
|
|
523
|
+
}], ctorParameters: () => [] });
|
|
524
|
+
|
|
286
525
|
/*
|
|
287
526
|
* Public API Surface of photo-editor
|
|
288
527
|
*/
|
|
@@ -291,5 +530,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.6", ngImpor
|
|
|
291
530
|
* Generated bundle index. Do not edit.
|
|
292
531
|
*/
|
|
293
532
|
|
|
294
|
-
export { PhotoEditorPage };
|
|
533
|
+
export { PhotoEditorPage, PhotoFileService, PhotoViewerPage };
|
|
295
534
|
//# sourceMappingURL=rdlabo-ionic-angular-photo-editor.mjs.map
|