valtech-components 2.0.679 → 2.0.681

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.
@@ -1,244 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { IMAGE_DEFAULTS, } from './types';
3
- import * as i0 from "@angular/core";
4
- /**
5
- * ImageService
6
- *
7
- * Service for image processing including compression, thumbnails, cropping and validation.
8
- * Uses HTML Canvas for all operations - no external dependencies.
9
- *
10
- * @example
11
- * ```typescript
12
- * const imageService = inject(ImageService);
13
- *
14
- * // Compress an image
15
- * const compressed = await imageService.compress(file, { maxWidth: 800, quality: 0.8 });
16
- *
17
- * // Generate thumbnail
18
- * const thumb = await imageService.thumbnail(file, 150);
19
- *
20
- * // Validate before processing
21
- * const validation = imageService.validate(file, { maxSize: 5 * 1024 * 1024 });
22
- * if (!validation.valid) {
23
- * console.error(validation.message);
24
- * }
25
- * ```
26
- */
27
- export class ImageService {
28
- /**
29
- * Compress an image maintaining aspect ratio
30
- * @param file - File or Blob to compress
31
- * @param options - Compression options
32
- * @returns Promise with processed image data
33
- */
34
- async compress(file, options) {
35
- const opts = {
36
- maxWidth: options?.maxWidth ?? IMAGE_DEFAULTS.maxWidth,
37
- maxHeight: options?.maxHeight ?? IMAGE_DEFAULTS.maxHeight,
38
- quality: options?.quality ?? IMAGE_DEFAULTS.quality,
39
- mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
40
- };
41
- const img = await this.loadImage(file);
42
- const { width, height } = this.calculateDimensions(img.width, img.height, opts.maxWidth, opts.maxHeight);
43
- const canvas = document.createElement('canvas');
44
- canvas.width = width;
45
- canvas.height = height;
46
- const ctx = canvas.getContext('2d');
47
- ctx.drawImage(img, 0, 0, width, height);
48
- const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
49
- const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
50
- return {
51
- blob,
52
- dataUrl,
53
- width,
54
- height,
55
- size: blob.size,
56
- };
57
- }
58
- /**
59
- * Generate a square thumbnail from an image
60
- * @param file - File or Blob to process
61
- * @param size - Thumbnail size in pixels (default: 150)
62
- * @returns Promise with processed thumbnail
63
- */
64
- async thumbnail(file, size) {
65
- const thumbSize = size ?? IMAGE_DEFAULTS.thumbnailSize;
66
- const img = await this.loadImage(file);
67
- // Calculate square crop from center
68
- const minDim = Math.min(img.width, img.height);
69
- const cropX = (img.width - minDim) / 2;
70
- const cropY = (img.height - minDim) / 2;
71
- const canvas = document.createElement('canvas');
72
- canvas.width = thumbSize;
73
- canvas.height = thumbSize;
74
- const ctx = canvas.getContext('2d');
75
- ctx.drawImage(img, cropX, cropY, minDim, minDim, 0, 0, thumbSize, thumbSize);
76
- const blob = await this.canvasToBlob(canvas, IMAGE_DEFAULTS.mimeType, 0.7 // Lower quality for thumbnails
77
- );
78
- const dataUrl = canvas.toDataURL(IMAGE_DEFAULTS.mimeType, 0.7);
79
- return {
80
- blob,
81
- dataUrl,
82
- width: thumbSize,
83
- height: thumbSize,
84
- size: blob.size,
85
- };
86
- }
87
- /**
88
- * Crop an image with specific coordinates
89
- * @param file - File or Blob to crop
90
- * @param cropData - Crop coordinates and dimensions
91
- * @param options - Optional compression options for output
92
- * @returns Promise with cropped image
93
- */
94
- async crop(file, cropData, options) {
95
- const img = await this.loadImage(file);
96
- const opts = {
97
- quality: options?.quality ?? IMAGE_DEFAULTS.quality,
98
- mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
99
- };
100
- const canvas = document.createElement('canvas');
101
- canvas.width = cropData.width;
102
- canvas.height = cropData.height;
103
- const ctx = canvas.getContext('2d');
104
- ctx.drawImage(img, cropData.x, cropData.y, cropData.width, cropData.height, 0, 0, cropData.width, cropData.height);
105
- // Apply max dimensions if specified
106
- if (options?.maxWidth || options?.maxHeight) {
107
- return this.compress(await this.canvasToBlob(canvas, opts.mimeType, 1), options);
108
- }
109
- const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
110
- const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
111
- return {
112
- blob,
113
- dataUrl,
114
- width: cropData.width,
115
- height: cropData.height,
116
- size: blob.size,
117
- };
118
- }
119
- /**
120
- * Validate an image file before processing
121
- * @param file - File to validate
122
- * @param options - Validation options
123
- * @returns Validation result with error details if invalid
124
- */
125
- validate(file, options) {
126
- const opts = {
127
- maxSize: options?.maxSize ?? IMAGE_DEFAULTS.maxSize,
128
- allowedTypes: options?.allowedTypes ?? IMAGE_DEFAULTS.allowedTypes,
129
- };
130
- // Check file type
131
- if (!opts.allowedTypes.includes(file.type)) {
132
- return {
133
- valid: false,
134
- error: 'invalidType',
135
- message: `Formato no válido. Usa: ${opts.allowedTypes.map(t => t.split('/')[1].toUpperCase()).join(', ')}`,
136
- };
137
- }
138
- // Check file size
139
- if (file.size > opts.maxSize) {
140
- const maxMB = Math.round(opts.maxSize / (1024 * 1024));
141
- return {
142
- valid: false,
143
- error: 'fileTooLarge',
144
- message: `La imagen es muy grande. Máximo ${maxMB}MB`,
145
- };
146
- }
147
- return { valid: true };
148
- }
149
- /**
150
- * Validate image dimensions (async - requires loading image)
151
- * @param file - File to validate
152
- * @param options - Validation options with minWidth/minHeight
153
- * @returns Promise with validation result
154
- */
155
- async validateDimensions(file, options) {
156
- const img = await this.loadImage(file);
157
- if (options.minWidth && img.width < options.minWidth) {
158
- return {
159
- valid: false,
160
- error: 'imageTooSmall',
161
- message: `La imagen debe tener al menos ${options.minWidth}px de ancho`,
162
- };
163
- }
164
- if (options.minHeight && img.height < options.minHeight) {
165
- return {
166
- valid: false,
167
- error: 'imageTooSmall',
168
- message: `La imagen debe tener al menos ${options.minHeight}px de alto`,
169
- };
170
- }
171
- return { valid: true };
172
- }
173
- /**
174
- * Convert a Blob/File to a data URL
175
- */
176
- async toDataUrl(file) {
177
- return new Promise((resolve, reject) => {
178
- const reader = new FileReader();
179
- reader.onload = () => resolve(reader.result);
180
- reader.onerror = reject;
181
- reader.readAsDataURL(file);
182
- });
183
- }
184
- /**
185
- * Convert a data URL to a Blob
186
- */
187
- dataUrlToBlob(dataUrl) {
188
- const arr = dataUrl.split(',');
189
- const mime = arr[0].match(/:(.*?);/)[1];
190
- const bstr = atob(arr[1]);
191
- let n = bstr.length;
192
- const u8arr = new Uint8Array(n);
193
- while (n--) {
194
- u8arr[n] = bstr.charCodeAt(n);
195
- }
196
- return new Blob([u8arr], { type: mime });
197
- }
198
- // ============== Private Helpers ==============
199
- loadImage(file) {
200
- return new Promise((resolve, reject) => {
201
- const img = new Image();
202
- img.onload = () => {
203
- URL.revokeObjectURL(img.src);
204
- resolve(img);
205
- };
206
- img.onerror = reject;
207
- img.src = URL.createObjectURL(file);
208
- });
209
- }
210
- calculateDimensions(originalWidth, originalHeight, maxWidth, maxHeight) {
211
- let width = originalWidth;
212
- let height = originalHeight;
213
- // Scale down if necessary, maintaining aspect ratio
214
- if (width > maxWidth) {
215
- height = (height * maxWidth) / width;
216
- width = maxWidth;
217
- }
218
- if (height > maxHeight) {
219
- width = (width * maxHeight) / height;
220
- height = maxHeight;
221
- }
222
- return {
223
- width: Math.round(width),
224
- height: Math.round(height),
225
- };
226
- }
227
- canvasToBlob(canvas, mimeType, quality) {
228
- return new Promise((resolve, reject) => {
229
- canvas.toBlob((blob) => {
230
- if (blob)
231
- resolve(blob);
232
- else
233
- reject(new Error('Failed to create blob from canvas'));
234
- }, mimeType, quality);
235
- });
236
- }
237
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
238
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, providedIn: 'root' }); }
239
- }
240
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, decorators: [{
241
- type: Injectable,
242
- args: [{ providedIn: 'root' }]
243
- }] });
244
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvaW1hZ2UvaW1hZ2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFFTCxjQUFjLEdBS2YsTUFBTSxTQUFTLENBQUM7O0FBRWpCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsTUFBTSxPQUFPLFlBQVk7SUFDdkI7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsUUFBUSxDQUNaLElBQWlCLEVBQ2pCLE9BQThCO1FBRTlCLE1BQU0sSUFBSSxHQUFHO1lBQ1gsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksY0FBYyxDQUFDLFFBQVE7WUFDdEQsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLElBQUksY0FBYyxDQUFDLFNBQVM7WUFDekQsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLElBQUksY0FBYyxDQUFDLE9BQU87WUFDbkQsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksY0FBYyxDQUFDLFFBQVE7U0FDdkQsQ0FBQztRQUVGLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QyxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FDaEQsR0FBRyxDQUFDLEtBQUssRUFDVCxHQUFHLENBQUMsTUFBTSxFQUNWLElBQUksQ0FBQyxRQUFRLEVBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FDZixDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRCxNQUFNLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNyQixNQUFNLENBQUMsTUFBTSxH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RCxJQUFJLEtBQUssR0FBRyxRQUFRLEVBQUUsQ0FBQztZQUNyQixNQUFNLEdBQUcsQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQ3JDLEtBQUssR0FBRyxRQUFRLENBQUM7UUFDbkIsQ0FBQztRQUVELElBQUksTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO1lBQ3ZCLEtBQUssR0FBRyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDckMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUNyQixDQUFDO1FBRUQsT0FBTztZQUNMLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7U0FDM0IsQ0FBQztJQUNKLENBQUM7SUFFTyxZQUFZLENBQ2xCLE1BQXlCLEVBQ3pCLFFBQWdCLEVBQ2hCLE9BQWU7UUFFZixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3JDLE1BQU0sQ0FBQyxNQUFNLENBQ1gsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDUCxJQUFJLElBQUk7b0JBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOztvQkFDbkIsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUMsQ0FBQztZQUM5RCxDQUFDLEVBQ0QsUUFBUSxFQUNSLE9BQU8sQ0FDUixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDOytHQXBTVSxZQUFZO21IQUFaLFlBQVksY0FEQyxNQUFNOzs0RkFDbkIsWUFBWTtrQkFEeEIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBDcm9wRGF0YSxcbiAgSU1BR0VfREVGQVVMVFMsXG4gIEltYWdlQ29tcHJlc3NPcHRpb25zLFxuICBJbWFnZVZhbGlkYXRlT3B0aW9ucyxcbiAgSW1hZ2VWYWxpZGF0aW9uUmVzdWx0LFxuICBQcm9jZXNzZWRJbWFnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogSW1hZ2VTZXJ2aWNlXG4gKlxuICogU2VydmljZSBmb3IgaW1hZ2UgcHJvY2Vzc2luZyBpbmNsdWRpbmcgY29tcHJlc3Npb24sIHRodW1ibmFpbHMsIGNyb3BwaW5nIGFuZCB2YWxpZGF0aW9uLlxuICogVXNlcyBIVE1MIENhbnZhcyBmb3IgYWxsIG9wZXJhdGlvbnMgLSBubyBleHRlcm5hbCBkZXBlbmRlbmNpZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGltYWdlU2VydmljZSA9IGluamVjdChJbWFnZVNlcnZpY2UpO1xuICpcbiAqIC8vIENvbXByZXNzIGFuIGltYWdlXG4gKiBjb25zdCBjb21wcmVzc2VkID0gYXdhaXQgaW1hZ2VTZXJ2aWNlLmNvbXByZXNzKGZpbGUsIHsgbWF4V2lkdGg6IDgwMCwgcXVhbGl0eTogMC44IH0pO1xuICpcbiAqIC8vIEdlbmVyYXRlIHRodW1ibmFpbFxuICogY29uc3QgdGh1bWIgPSBhd2FpdCBpbWFnZVNlcnZpY2UudGh1bWJuYWlsKGZpbGUsIDE1MCk7XG4gKlxuICogLy8gVmFsaWRhdGUgYmVmb3JlIHByb2Nlc3NpbmdcbiAqIGNvbnN0IHZhbGlkYXRpb24gPSBpbWFnZVNlcnZpY2UudmFsaWRhdGUoZmlsZSwgeyBtYXhTaXplOiA1ICogMTAyNCAqIDEwMjQgfSk7XG4gKiBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAqICAgY29uc29sZS5lcnJvcih2YWxpZGF0aW9uLm1lc3NhZ2UpO1xuICogfVxuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgSW1hZ2VTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIENvbXByZXNzIGFuIGltYWdlIG1haW50YWluaW5nIGFzcGVjdCByYXRpb1xuICAgKiBAcGFyYW0gZmlsZSAtIEZpbGUgb3IgQmxvYiB0byBjb21wcmVzc1xuICAgKiBAcGFyYW0gb3B0aW9ucyAtIENvbXByZXNzaW9uIG9wdGlvbnNcbiAgICogQHJldHVybnMgUHJvbWlzZSB3aXRoIHByb2Nlc3NlZCBpbWFnZSBkYXRhXG4gICAqL1xuICBhc3luYyBjb21wcmVzcyhcbiAgICBmaWxlOiBGaWxlIHwgQmxvYixcbiAgICBvcHRpb25zPzogSW1hZ2VDb21wcmVzc09wdGlvbnNcbiAgKTogUHJvbWlzZTxQcm9jZXNzZWRJbWFnZT4ge1xuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICBtYXhXaWR0aDogb3B0aW9ucz8ubWF4V2lkdGggPz8gSU1BR0VfREVGQVVMVFMubWF4V2lkdGgsXG4gICAgICBtYXhIZWlnaHQ6IG9wdGlvbnM/Lm1heEhlaWdodCA/PyBJTUFHRV9ERUZBVUxUUy5tYXhIZWlnaHQsXG4gICAgICBxdWFsaXR5OiBvcHRpb25zPy5xdWFsaXR5ID8/IElNQUdFX0RFRkFVTFRTLnF1YWxpdHksXG4gICAgICBtaW1lVHlwZTogb3B0aW9ucz8ubWltZVR5cGUgPz8gSU1BR0VfREVGQVVMVFMubWltZVR5cGUsXG4gICAgfTtcblxuICAgIGNvbnN0IGltZyA9IGF3YWl0IHRoaXMubG9hZEltYWdlKGZpbGUpO1xuICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gdGhpcy5jYWxjdWxhdGVEaW1lbnNpb25zKFxuICAgICAgaW1nLndpZHRoLFxuICAgICAgaW1nLmhlaWdodCxcbiAgICAgIG9wdHMubWF4V2lkdGgsXG4gICAgICBvcHRzLm1heEhlaWdodFxuICAgICk7XG5cbiAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG4gICAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJykhO1xuICAgIGN0eC5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgIGNvbnN0IGJsb2IgPSBhd2FpdCB0aGlzLmNhbnZhc1RvQmxvYihjYW52YXMsIG9wdHMubWltZVR5cGUsIG9wdHMucXVhbGl0eSk7XG4gICAgY29uc3QgZGF0YVVybCA9IGNhbnZhcy50b0RhdGFVUkwob3B0cy5taW1lVHlwZSwgb3B0cy5xdWFsaXR5KTtcblxuICAgIHJldHVybiB7XG4gICAgICBibG9iLFxuICAgICAgZGF0YVVybCxcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0LFxuICAgICAgc2l6ZTogYmxvYi5zaXplLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYSBzcXVhcmUgdGh1bWJuYWlsIGZyb20gYW4gaW1hZ2VcbiAgICogQHBhcmFtIGZpbGUgLSBGaWxlIG9yIEJsb2IgdG8gcHJvY2Vzc1xuICAgKiBAcGFyYW0gc2l6ZSAtIFRodW1ibmFpbCBzaXplIGluIHBpeGVscyAoZGVmYXVsdDogMTUwKVxuICAgKiBAcmV0dXJucyBQcm9taXNlIHdpdGggcHJvY2Vzc2VkIHRodW1ibmFpbFxuICAgKi9cbiAgYXN5bmMgdGh1bWJuYWlsKGZpbGU6IEZpbGUgfCBCbG9iLCBzaXplPzogbnVtYmVyKTogUHJvbWlzZTxQcm9jZXNzZWRJbWFnZT4ge1xuICAgIGNvbnN0IHRodW1iU2l6ZSA9IHNpemUgPz8gSU1BR0VfREVGQVVMVFMudGh1bWJuYWlsU2l6ZTtcbiAgICBjb25zdCBpbWcgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZShmaWxlKTtcblxuICAgIC8vIENhbGN1bGF0ZSBzcXVhcmUgY3JvcCBmcm9tIGNlbnRlclxuICAgIGNvbnN0IG1pbkRpbSA9IE1hdGgubWluKGltZy53aWR0aCwgaW1nLmhlaWdodCk7XG4gICAgY29uc3QgY3JvcFggPSAoaW1nLndpZHRoIC0gbWluRGltKSAvIDI7XG4gICAgY29uc3QgY3JvcFkgPSAoaW1nLmhlaWdodCAtIG1pbkRpbSkgLyAyO1xuXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gdGh1bWJTaXplO1xuICAgIGNhbnZhcy5oZWlnaHQgPSB0aHVtYlNpemU7XG5cbiAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKSE7XG4gICAgY3R4LmRyYXdJbWFnZShcbiAgICAgIGltZyxcbiAgICAgIGNyb3BYLFxuICAgICAgY3JvcFksXG4gICAgICBtaW5EaW0sXG4gICAgICBtaW5EaW0sXG4gICAgICAwLFxuICAgICAgMCxcbiAgICAgIHRodW1iU2l6ZSxcbiAgICAgIHRodW1iU2l6ZVxuICAgICk7XG5cbiAgICBjb25zdCBibG9iID0gYXdhaXQgdGhpcy5jYW52YXNUb0Jsb2IoXG4gICAgICBjYW52YXMsXG4gICAgICBJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSxcbiAgICAgIDAuNyAvLyBMb3dlciBxdWFsaXR5IGZvciB0aHVtYm5haWxzXG4gICAgKTtcbiAgICBjb25zdCBkYXRhVXJsID0gY2FudmFzLnRvRGF0YVVSTChJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSwgMC43KTtcblxuICAgIHJldHVybiB7XG4gICAgICBibG9iLFxuICAgICAgZGF0YVVybCxcbiAgICAgIHdpZHRoOiB0aHVtYlNpemUsXG4gICAgICBoZWlnaHQ6IHRodW1iU2l6ZSxcbiAgICAgIHNpemU6IGJsb2Iuc2l6ZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyb3AgYW4gaW1hZ2Ugd2l0aCBzcGVjaWZpYyBjb29yZGluYXRlc1xuICAgKiBAcGFyYW0gZmlsZSAtIEZpbGUgb3IgQmxvYiB0byBjcm9wXG4gICAqIEBwYXJhbSBjcm9wRGF0YSAtIENyb3AgY29vcmRpbmF0ZXMgYW5kIGRpbWVuc2lvbnNcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb21wcmVzc2lvbiBvcHRpb25zIGZvciBvdXRwdXRcbiAgICogQHJldHVybnMgUHJvbWlzZSB3aXRoIGNyb3BwZWQgaW1hZ2VcbiAgICovXG4gIGFzeW5jIGNyb3AoXG4gICAgZmlsZTogRmlsZSB8IEJsb2IsXG4gICAgY3JvcERhdGE6IENyb3BEYXRhLFxuICAgIG9wdGlvbnM/OiBJbWFnZUNvbXByZXNzT3B0aW9uc1xuICApOiBQcm9taXNlPFByb2Nlc3NlZEltYWdlPiB7XG4gICAgY29uc3QgaW1nID0gYXdhaXQgdGhpcy5sb2FkSW1hZ2UoZmlsZSk7XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHF1YWxpdHk6IG9wdGlvbnM/LnF1YWxpdHkgPz8gSU1BR0VfREVGQVVMVFMucXVhbGl0eSxcbiAgICAgIG1pbWVUeXBlOiBvcHRpb25zPy5taW1lVHlwZSA/PyBJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSxcbiAgICB9O1xuXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gY3JvcERhdGEud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3BEYXRhLmhlaWdodDtcblxuICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpITtcbiAgICBjdHguZHJhd0ltYWdlKFxuICAgICAgaW1nLFxuICAgICAgY3JvcERhdGEueCxcbiAgICAgIGNyb3BEYXRhLnksXG4gICAgICBjcm9wRGF0YS53aWR0aCxcbiAgICAgIGNyb3BEYXRhLmhlaWdodCxcbiAgICAgIDAsXG4gICAgICAwLFxuICAgICAgY3JvcERhdGEud2lkdGgsXG4gICAgICBjcm9wRGF0YS5oZWlnaHRcbiAgICApO1xuXG4gICAgLy8gQXBwbHkgbWF4IGRpbWVuc2lvbnMgaWYgc3BlY2lmaWVkXG4gICAgaWYgKG9wdGlvbnM/Lm1heFdpZHRoIHx8IG9wdGlvbnM/Lm1heEhlaWdodCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29tcHJlc3MoYXdhaXQgdGhpcy5jYW52YXNUb0Jsb2IoY2FudmFzLCBvcHRzLm1pbWVUeXBlLCAxKSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgY29uc3QgYmxvYiA9IGF3YWl0IHRoaXMuY2FudmFzVG9CbG9iKGNhbnZhcywgb3B0cy5taW1lVHlwZSwgb3B0cy5xdWFsaXR5KTtcbiAgICBjb25zdCBkYXRhVXJsID0gY2FudmFzLnRvRGF0YVVSTChvcHRzLm1pbWVUeXBlLCBvcHRzLnF1YWxpdHkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGJsb2IsXG4gICAgICBkYXRhVXJsLFxuICAgICAgd2lkdGg6IGNyb3BEYXRhLndpZHRoLFxuICAgICAgaGVpZ2h0OiBjcm9wRGF0YS5oZWlnaHQsXG4gICAgICBzaXplOiBibG9iLnNpemUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbiBpbWFnZSBmaWxlIGJlZm9yZSBwcm9jZXNzaW5nXG4gICAqIEBwYXJhbSBmaWxlIC0gRmlsZSB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFZhbGlkYXRpb24gb3B0aW9uc1xuICAgKiBAcmV0dXJucyBWYWxpZGF0aW9uIHJlc3VsdCB3aXRoIGVycm9yIGRldGFpbHMgaWYgaW52YWxpZFxuICAgKi9cbiAgdmFsaWRhdGUoZmlsZTogRmlsZSwgb3B0aW9ucz86IEltYWdlVmFsaWRhdGVPcHRpb25zKTogSW1hZ2VWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgbWF4U2l6ZTogb3B0aW9ucz8ubWF4U2l6ZSA/PyBJTUFHRV9ERUZBVUxUUy5tYXhTaXplLFxuICAgICAgYWxsb3dlZFR5cGVzOiBvcHRpb25zPy5hbGxvd2VkVHlwZXMgPz8gSU1BR0VfREVGQVVMVFMuYWxsb3dlZFR5cGVzLFxuICAgIH07XG5cbiAgICAvLyBDaGVjayBmaWxlIHR5cGVcbiAgICBpZiAoIW9wdHMuYWxsb3dlZFR5cGVzLmluY2x1ZGVzKGZpbGUudHlwZSkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbGlkOiBmYWxzZSxcbiAgICAgICAgZXJyb3I6ICdpbnZhbGlkVHlwZScsXG4gICAgICAgIG1lc3NhZ2U6IGBGb3JtYXRvIG5vIHbDoWxpZG8uIFVzYTogJHtvcHRzLmFsbG93ZWRUeXBlcy5tYXAodCA9PiB0LnNwbGl0KCcvJylbMV0udG9VcHBlckNhc2UoKSkuam9pbignLCAnKX1gLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmaWxlIHNpemVcbiAgICBpZiAoZmlsZS5zaXplID4gb3B0cy5tYXhTaXplKSB7XG4gICAgICBjb25zdCBtYXhNQiA9IE1hdGgucm91bmQob3B0cy5tYXhTaXplIC8gKDEwMjQgKiAxMDI0KSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWxpZDogZmFsc2UsXG4gICAgICAgIGVycm9yOiAnZmlsZVRvb0xhcmdlJyxcbiAgICAgICAgbWVzc2FnZTogYExhIGltYWdlbiBlcyBtdXkgZ3JhbmRlLiBNw6F4aW1vICR7bWF4TUJ9TUJgLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGltYWdlIGRpbWVuc2lvbnMgKGFzeW5jIC0gcmVxdWlyZXMgbG9hZGluZyBpbWFnZSlcbiAgICogQHBhcmFtIGZpbGUgLSBGaWxlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVmFsaWRhdGlvbiBvcHRpb25zIHdpdGggbWluV2lkdGgvbWluSGVpZ2h0XG4gICAqIEByZXR1cm5zIFByb21pc2Ugd2l0aCB2YWxpZGF0aW9uIHJlc3VsdFxuICAgKi9cbiAgYXN5bmMgdmFsaWRhdGVEaW1lbnNpb25zKFxuICAgIGZpbGU6IEZpbGUsXG4gICAgb3B0aW9uczogUGljazxJbWFnZVZhbGlkYXRlT3B0aW9ucywgJ21pbldpZHRoJyB8ICdtaW5IZWlnaHQnPlxuICApOiBQcm9taXNlPEltYWdlVmFsaWRhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IGltZyA9IGF3YWl0IHRoaXMubG9hZEltYWdlKGZpbGUpO1xuXG4gICAgaWYgKG9wdGlvbnMubWluV2lkdGggJiYgaW1nLndpZHRoIDwgb3B0aW9ucy5taW5XaWR0aCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjogJ2ltYWdlVG9vU21hbGwnLFxuICAgICAgICBtZXNzYWdlOiBgTGEgaW1hZ2VuIGRlYmUgdGVuZXIgYWwgbWVub3MgJHtvcHRpb25zLm1pbldpZHRofXB4IGRlIGFuY2hvYCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMubWluSGVpZ2h0ICYmIGltZy5oZWlnaHQgPCBvcHRpb25zLm1pbkhlaWdodCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjogJ2ltYWdlVG9vU21hbGwnLFxuICAgICAgICBtZXNzYWdlOiBgTGEgaW1hZ2VuIGRlYmUgdGVuZXIgYWwgbWVub3MgJHtvcHRpb25zLm1pbkhlaWdodH1weCBkZSBhbHRvYCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgdmFsaWQ6IHRydWUgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGEgQmxvYi9GaWxlIHRvIGEgZGF0YSBVUkxcbiAgICovXG4gIGFzeW5jIHRvRGF0YVVybChmaWxlOiBGaWxlIHwgQmxvYik6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgICByZWFkZXIub25sb2FkID0gKCkgPT4gcmVzb2x2ZShyZWFkZXIucmVzdWx0IGFzIHN0cmluZyk7XG4gICAgICByZWFkZXIub25lcnJvciA9IHJlamVjdDtcbiAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBkYXRhIFVSTCB0byBhIEJsb2JcbiAgICovXG4gIGRhdGFVcmxUb0Jsb2IoZGF0YVVybDogc3RyaW5nKTogQmxvYiB7XG4gICAgY29uc3QgYXJyID0gZGF0YVVybC5zcGxpdCgnLCcpO1xuICAgIGNvbnN0IG1pbWUgPSBhcnJbMF0ubWF0Y2goLzooLio/KTsvKSFbMV07XG4gICAgY29uc3QgYnN0ciA9IGF0b2IoYXJyWzFdKTtcbiAgICBsZXQgbiA9IGJzdHIubGVuZ3RoO1xuICAgIGNvbnN0IHU4YXJyID0gbmV3IFVpbnQ4QXJyYXkobik7XG4gICAgd2hpbGUgKG4tLSkge1xuICAgICAgdThhcnJbbl0gPSBic3RyLmNoYXJDb2RlQXQobik7XG4gICAgfVxuICAgIHJldHVybiBuZXcgQmxvYihbdThhcnJdLCB7IHR5cGU6IG1pbWUgfSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PSBQcml2YXRlIEhlbHBlcnMgPT09PT09PT09PT09PT1cblxuICBwcml2YXRlIGxvYWRJbWFnZShmaWxlOiBGaWxlIHwgQmxvYik6IFByb21pc2U8SFRNTEltYWdlRWxlbWVudD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgIGltZy5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwoaW1nLnNyYyk7XG4gICAgICAgIHJlc29sdmUoaW1nKTtcbiAgICAgIH07XG4gICAgICBpbWcub25lcnJvciA9IHJlamVjdDtcbiAgICAgIGltZy5zcmMgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGZpbGUpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjYWxjdWxhdGVEaW1lbnNpb25zKFxuICAgIG9yaWdpbmFsV2lkdGg6IG51bWJlcixcbiAgICBvcmlnaW5hbEhlaWdodDogbnVtYmVyLFxuICAgIG1heFdpZHRoOiBudW1iZXIsXG4gICAgbWF4SGVpZ2h0OiBudW1iZXJcbiAgKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHtcbiAgICBsZXQgd2lkdGggPSBvcmlnaW5hbFdpZHRoO1xuICAgIGxldCBoZWlnaHQgPSBvcmlnaW5hbEhlaWdodDtcblxuICAgIC8vIFNjYWxlIGRvd24gaWYgbmVjZXNzYXJ5LCBtYWludGFpbmluZyBhc3BlY3QgcmF0aW9cbiAgICBpZiAod2lkdGggPiBtYXhXaWR0aCkge1xuICAgICAgaGVpZ2h0ID0gKGhlaWdodCAqIG1heFdpZHRoKSAvIHdpZHRoO1xuICAgICAgd2lkdGggPSBtYXhXaWR0aDtcbiAgICB9XG5cbiAgICBpZiAoaGVpZ2h0ID4gbWF4SGVpZ2h0KSB7XG4gICAgICB3aWR0aCA9ICh3aWR0aCAqIG1heEhlaWdodCkgLyBoZWlnaHQ7XG4gICAgICBoZWlnaHQgPSBtYXhIZWlnaHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcbiAgICAgIGhlaWdodDogTWF0aC5yb3VuZChoZWlnaHQpLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGNhbnZhc1RvQmxvYihcbiAgICBjYW52YXM6IEhUTUxDYW52YXNFbGVtZW50LFxuICAgIG1pbWVUeXBlOiBzdHJpbmcsXG4gICAgcXVhbGl0eTogbnVtYmVyXG4gICk6IFByb21pc2U8QmxvYj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjYW52YXMudG9CbG9iKFxuICAgICAgICAoYmxvYikgPT4ge1xuICAgICAgICAgIGlmIChibG9iKSByZXNvbHZlKGJsb2IpO1xuICAgICAgICAgIGVsc2UgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIGNyZWF0ZSBibG9iIGZyb20gY2FudmFzJykpO1xuICAgICAgICB9LFxuICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgcXVhbGl0eVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -1,3 +0,0 @@
1
- export * from './image.service';
2
- export * from './types';
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ltYWdlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2ltYWdlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG4iXX0=
@@ -1,13 +0,0 @@
1
- /**
2
- * Default values for image processing
3
- */
4
- export const IMAGE_DEFAULTS = {
5
- maxWidth: 800,
6
- maxHeight: 800,
7
- quality: 0.8,
8
- mimeType: 'image/jpeg',
9
- maxSize: 10 * 1024 * 1024, // 10MB
10
- allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
11
- thumbnailSize: 150,
12
- };
13
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ltYWdlL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQW1FQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRztJQUM1QixRQUFRLEVBQUUsR0FBRztJQUNiLFNBQVMsRUFBRSxHQUFHO0lBQ2QsT0FBTyxFQUFFLEdBQUc7SUFDWixRQUFRLEVBQUUsWUFBcUI7SUFDL0IsT0FBTyxFQUFFLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxFQUFFLE9BQU87SUFDbEMsWUFBWSxFQUFFLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsV0FBVyxDQUFDO0lBQ3BFLGFBQWEsRUFBRSxHQUFHO0NBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE9wdGlvbnMgZm9yIGltYWdlIGNvbXByZXNzaW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW1hZ2VDb21wcmVzc09wdGlvbnMge1xuICAvKiogTWF4aW11bSB3aWR0aCBpbiBwaXhlbHMgKGRlZmF1bHQ6IDgwMCkgKi9cbiAgbWF4V2lkdGg/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIGhlaWdodCBpbiBwaXhlbHMgKGRlZmF1bHQ6IDgwMCkgKi9cbiAgbWF4SGVpZ2h0PzogbnVtYmVyO1xuICAvKiogUXVhbGl0eSAwLTEgKGRlZmF1bHQ6IDAuOCkgKi9cbiAgcXVhbGl0eT86IG51bWJlcjtcbiAgLyoqIE91dHB1dCBNSU1FIHR5cGUgKGRlZmF1bHQ6ICdpbWFnZS9qcGVnJykgKi9cbiAgbWltZVR5cGU/OiAnaW1hZ2UvanBlZycgfCAnaW1hZ2UvcG5nJyB8ICdpbWFnZS93ZWJwJztcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBpbWFnZSB2YWxpZGF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW1hZ2VWYWxpZGF0ZU9wdGlvbnMge1xuICAvKiogTWF4aW11bSBmaWxlIHNpemUgaW4gYnl0ZXMgKGRlZmF1bHQ6IDEwTUIpICovXG4gIG1heFNpemU/OiBudW1iZXI7XG4gIC8qKiBBbGxvd2VkIE1JTUUgdHlwZXMgKGRlZmF1bHQ6IFsnaW1hZ2UvanBlZycsICdpbWFnZS9wbmcnLCAnaW1hZ2Uvd2VicCcsICdpbWFnZS9naWYnXSkgKi9cbiAgYWxsb3dlZFR5cGVzPzogc3RyaW5nW107XG4gIC8qKiBNaW5pbXVtIHdpZHRoIGluIHBpeGVscyAqL1xuICBtaW5XaWR0aD86IG51bWJlcjtcbiAgLyoqIE1pbmltdW0gaGVpZ2h0IGluIHBpeGVscyAqL1xuICBtaW5IZWlnaHQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGltYWdlIHZhbGlkYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbWFnZVZhbGlkYXRpb25SZXN1bHQge1xuICB2YWxpZDogYm9vbGVhbjtcbiAgZXJyb3I/OiAnaW52YWxpZFR5cGUnIHwgJ2ZpbGVUb29MYXJnZScgfCAnaW1hZ2VUb29TbWFsbCc7XG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VkIGltYWdlIHJlc3VsdFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByb2Nlc3NlZEltYWdlIHtcbiAgLyoqIFByb2Nlc3NlZCBpbWFnZSBhcyBCbG9iICovXG4gIGJsb2I6IEJsb2I7XG4gIC8qKiBEYXRhIFVSTCBmb3IgcHJldmlldyAqL1xuICBkYXRhVXJsOiBzdHJpbmc7XG4gIC8qKiBGaW5hbCB3aWR0aCBpbiBwaXhlbHMgKi9cbiAgd2lkdGg6IG51bWJlcjtcbiAgLyoqIEZpbmFsIGhlaWdodCBpbiBwaXhlbHMgKi9cbiAgaGVpZ2h0OiBudW1iZXI7XG4gIC8qKiBGaWxlIHNpemUgaW4gYnl0ZXMgKi9cbiAgc2l6ZTogbnVtYmVyO1xufVxuXG4vKipcbiAqIENyb3AgZGF0YSBmb3IgbWFudWFsIGNyb3BwaW5nXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3JvcERhdGEge1xuICAvKiogWCBwb3NpdGlvbiBvZiBjcm9wIGFyZWEgKi9cbiAgeDogbnVtYmVyO1xuICAvKiogWSBwb3NpdGlvbiBvZiBjcm9wIGFyZWEgKi9cbiAgeTogbnVtYmVyO1xuICAvKiogV2lkdGggb2YgY3JvcCBhcmVhICovXG4gIHdpZHRoOiBudW1iZXI7XG4gIC8qKiBIZWlnaHQgb2YgY3JvcCBhcmVhICovXG4gIGhlaWdodDogbnVtYmVyO1xufVxuXG4vKipcbiAqIERlZmF1bHQgdmFsdWVzIGZvciBpbWFnZSBwcm9jZXNzaW5nXG4gKi9cbmV4cG9ydCBjb25zdCBJTUFHRV9ERUZBVUxUUyA9IHtcbiAgbWF4V2lkdGg6IDgwMCxcbiAgbWF4SGVpZ2h0OiA4MDAsXG4gIHF1YWxpdHk6IDAuOCxcbiAgbWltZVR5cGU6ICdpbWFnZS9qcGVnJyBhcyBjb25zdCxcbiAgbWF4U2l6ZTogMTAgKiAxMDI0ICogMTAyNCwgLy8gMTBNQlxuICBhbGxvd2VkVHlwZXM6IFsnaW1hZ2UvanBlZycsICdpbWFnZS9wbmcnLCAnaW1hZ2Uvd2VicCcsICdpbWFnZS9naWYnXSxcbiAgdGh1bWJuYWlsU2l6ZTogMTUwLFxufTtcbiJdfQ==
@@ -1,59 +0,0 @@
1
- import { EventEmitter } from '@angular/core';
2
- import { ImageCroppedEvent } from 'ngx-image-cropper';
3
- import * as i0 from "@angular/core";
4
- /**
5
- * ImageCropComponent
6
- *
7
- * A modal-ready component for cropping images with a specified aspect ratio.
8
- * Uses ngx-image-cropper internally and provides a simple interface.
9
- *
10
- * @example Inside an ion-modal
11
- * ```html
12
- * <ion-modal [isOpen]="showCropModal">
13
- * <ng-template>
14
- * <val-image-crop
15
- * [image]="selectedFile"
16
- * [aspectRatio]="1"
17
- * [roundCropper]="true"
18
- * (cropComplete)="onCropComplete($event)"
19
- * (cancel)="showCropModal = false"
20
- * />
21
- * </ng-template>
22
- * </ion-modal>
23
- * ```
24
- */
25
- export declare class ImageCropComponent {
26
- private i18n;
27
- /** Image file to crop */
28
- readonly image: import("@angular/core").InputSignal<File>;
29
- /** Aspect ratio (1 for square, 16/9 for widescreen, etc.) */
30
- readonly aspectRatio: import("@angular/core").InputSignal<number>;
31
- /** Use round cropper (for avatars) */
32
- readonly roundCropper: import("@angular/core").InputSignal<boolean>;
33
- /** Resize output to specific width (0 = no resize) */
34
- readonly resizeToWidth: import("@angular/core").InputSignal<number>;
35
- /** i18n namespace for labels */
36
- readonly i18nNamespace: import("@angular/core").InputSignal<string>;
37
- /** Emitted when crop is confirmed with the cropped blob */
38
- cropComplete: EventEmitter<Blob>;
39
- /** Emitted when user cancels the crop */
40
- cancel: EventEmitter<void>;
41
- /** Emitted when image fails to load */
42
- loadFailed: EventEmitter<void>;
43
- /** Internal signal for cropped blob */
44
- protected croppedBlob: import("@angular/core").WritableSignal<Blob>;
45
- /** Computed text for cancel button */
46
- protected cancelText: import("@angular/core").Signal<string>;
47
- /** Computed text for confirm button */
48
- protected confirmText: import("@angular/core").Signal<string>;
49
- /** Computed text for title */
50
- protected titleText: import("@angular/core").Signal<string>;
51
- /** Handle crop event from ngx-image-cropper */
52
- onImageCropped(event: ImageCroppedEvent): void;
53
- /** Confirm and emit the cropped blob */
54
- confirmCrop(): void;
55
- /** Handle load failure */
56
- onLoadFailed(): void;
57
- static ɵfac: i0.ɵɵFactoryDeclaration<ImageCropComponent, never>;
58
- static ɵcmp: i0.ɵɵComponentDeclaration<ImageCropComponent, "val-image-crop", never, { "image": { "alias": "image"; "required": true; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "roundCropper": { "alias": "roundCropper"; "required": false; "isSignal": true; }; "resizeToWidth": { "alias": "resizeToWidth"; "required": false; "isSignal": true; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; "isSignal": true; }; }, { "cropComplete": "cropComplete"; "cancel": "cancel"; "loadFailed": "loadFailed"; }, never, never, true, never>;
59
- }
@@ -1 +0,0 @@
1
- export * from './image-crop.component';
@@ -1,82 +0,0 @@
1
- import { ElementRef, EventEmitter } from '@angular/core';
2
- import { AvatarUploadError, AvatarUploadMetadata, AvatarUploadResult } from './types';
3
- import * as i0 from "@angular/core";
4
- /**
5
- * AvatarUploadComponent
6
- *
7
- * A complete avatar upload solution with:
8
- * - Image selection from device
9
- * - Crop modal with round preview
10
- * - Automatic compression and thumbnail generation
11
- * - Upload to Firebase Storage
12
- * - Backend sync via AuthService
13
- *
14
- * @example Basic usage
15
- * ```html
16
- * <val-avatar-upload
17
- * [props]="{
18
- * currentUrl: user()?.avatarUrl,
19
- * initials: 'JD',
20
- * size: 120
21
- * }"
22
- * (uploaded)="onAvatarUploaded($event)"
23
- * (error)="onError($event)"
24
- * />
25
- * ```
26
- */
27
- export declare class AvatarUploadComponent {
28
- private imageService;
29
- private storageService;
30
- private authService;
31
- private i18n;
32
- fileInput: ElementRef<HTMLInputElement>;
33
- /** Component configuration */
34
- readonly props: import("@angular/core").InputSignal<AvatarUploadMetadata>;
35
- /** Emitted after successful upload and backend sync */
36
- uploaded: EventEmitter<AvatarUploadResult>;
37
- /** Emitted on any error during the process */
38
- error: EventEmitter<AvatarUploadError>;
39
- /** Emitted when upload starts */
40
- uploadStart: EventEmitter<void>;
41
- protected loading: import("@angular/core").WritableSignal<boolean>;
42
- protected showCropModal: import("@angular/core").WritableSignal<boolean>;
43
- protected selectedFile: import("@angular/core").WritableSignal<File>;
44
- protected previewUrl: import("@angular/core").WritableSignal<string>;
45
- protected imageLoadError: import("@angular/core").WritableSignal<boolean>;
46
- /** Merged config with defaults */
47
- protected config: import("@angular/core").Signal<{
48
- currentUrl?: string;
49
- initials?: string;
50
- backgroundColor: string;
51
- size: number;
52
- editable: boolean;
53
- storagePath: string;
54
- i18nNamespace: string;
55
- maxFileSize: number;
56
- compressQuality: number;
57
- maxWidth: number;
58
- thumbnailSize: number;
59
- }>;
60
- /** URL to display (preview takes priority over current) */
61
- protected displayUrl: import("@angular/core").Signal<string>;
62
- /** Aria label for edit button */
63
- protected editButtonLabel: import("@angular/core").Signal<string>;
64
- /** Open file picker dialog */
65
- openFilePicker(): void;
66
- /** Handle file selection */
67
- onFileSelected(event: Event): void;
68
- /** Handle crop completion */
69
- onCropComplete(croppedBlob: Blob): Promise<void>;
70
- /** Handle crop cancel */
71
- onCropCancel(): void;
72
- /** Handle crop load failure */
73
- onCropLoadFailed(): void;
74
- /** Handle image load error */
75
- onImageError(): void;
76
- /** Process cropped image and upload */
77
- private processAndUpload;
78
- /** Emit error event */
79
- private emitError;
80
- static ɵfac: i0.ɵɵFactoryDeclaration<AvatarUploadComponent, never>;
81
- static ɵcmp: i0.ɵɵComponentDeclaration<AvatarUploadComponent, "val-avatar-upload", never, { "props": { "alias": "props"; "required": false; "isSignal": true; }; }, { "uploaded": "uploaded"; "error": "error"; "uploadStart": "uploadStart"; }, never, never, true, never>;
82
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * Configuration for AvatarUploadComponent
3
- */
4
- export interface AvatarUploadMetadata {
5
- /** Current avatar URL */
6
- currentUrl?: string;
7
- /** Initials to show when no avatar (e.g., "JD" for John Doe) */
8
- initials?: string;
9
- /** Background color for initials avatar */
10
- backgroundColor?: string;
11
- /** Avatar size in pixels (default: 100) */
12
- size?: number;
13
- /** Show edit button (default: true) */
14
- editable?: boolean;
15
- /** Storage path prefix without userId (default: 'avatars') */
16
- storagePath?: string;
17
- /** i18n namespace for labels (default: 'AvatarUpload') */
18
- i18nNamespace?: string;
19
- /** Max file size in bytes (default: 10MB) */
20
- maxFileSize?: number;
21
- /** Quality for compressed image 0-1 (default: 0.8) */
22
- compressQuality?: number;
23
- /** Max width for avatar (default: 800) */
24
- maxWidth?: number;
25
- /** Thumbnail size (default: 150) */
26
- thumbnailSize?: number;
27
- }
28
- /**
29
- * Result emitted after successful upload
30
- */
31
- export interface AvatarUploadResult {
32
- /** Full-size avatar URL */
33
- avatarUrl: string;
34
- /** Thumbnail URL */
35
- thumbnailUrl: string;
36
- }
37
- /**
38
- * Error types that can occur during upload
39
- */
40
- export type AvatarUploadErrorType = 'invalidType' | 'fileTooLarge' | 'uploadFailed' | 'backendFailed' | 'cancelled';
41
- /**
42
- * Error object emitted on failure
43
- */
44
- export interface AvatarUploadError {
45
- type: AvatarUploadErrorType;
46
- message: string;
47
- originalError?: unknown;
48
- }
49
- /**
50
- * Default values
51
- */
52
- export declare const AVATAR_UPLOAD_DEFAULTS: {
53
- size: number;
54
- editable: boolean;
55
- storagePath: string;
56
- i18nNamespace: string;
57
- maxFileSize: number;
58
- compressQuality: number;
59
- maxWidth: number;
60
- thumbnailSize: number;
61
- backgroundColor: string;
62
- };
@@ -1,76 +0,0 @@
1
- import { CropData, ImageCompressOptions, ImageValidateOptions, ImageValidationResult, ProcessedImage } from './types';
2
- import * as i0 from "@angular/core";
3
- /**
4
- * ImageService
5
- *
6
- * Service for image processing including compression, thumbnails, cropping and validation.
7
- * Uses HTML Canvas for all operations - no external dependencies.
8
- *
9
- * @example
10
- * ```typescript
11
- * const imageService = inject(ImageService);
12
- *
13
- * // Compress an image
14
- * const compressed = await imageService.compress(file, { maxWidth: 800, quality: 0.8 });
15
- *
16
- * // Generate thumbnail
17
- * const thumb = await imageService.thumbnail(file, 150);
18
- *
19
- * // Validate before processing
20
- * const validation = imageService.validate(file, { maxSize: 5 * 1024 * 1024 });
21
- * if (!validation.valid) {
22
- * console.error(validation.message);
23
- * }
24
- * ```
25
- */
26
- export declare class ImageService {
27
- /**
28
- * Compress an image maintaining aspect ratio
29
- * @param file - File or Blob to compress
30
- * @param options - Compression options
31
- * @returns Promise with processed image data
32
- */
33
- compress(file: File | Blob, options?: ImageCompressOptions): Promise<ProcessedImage>;
34
- /**
35
- * Generate a square thumbnail from an image
36
- * @param file - File or Blob to process
37
- * @param size - Thumbnail size in pixels (default: 150)
38
- * @returns Promise with processed thumbnail
39
- */
40
- thumbnail(file: File | Blob, size?: number): Promise<ProcessedImage>;
41
- /**
42
- * Crop an image with specific coordinates
43
- * @param file - File or Blob to crop
44
- * @param cropData - Crop coordinates and dimensions
45
- * @param options - Optional compression options for output
46
- * @returns Promise with cropped image
47
- */
48
- crop(file: File | Blob, cropData: CropData, options?: ImageCompressOptions): Promise<ProcessedImage>;
49
- /**
50
- * Validate an image file before processing
51
- * @param file - File to validate
52
- * @param options - Validation options
53
- * @returns Validation result with error details if invalid
54
- */
55
- validate(file: File, options?: ImageValidateOptions): ImageValidationResult;
56
- /**
57
- * Validate image dimensions (async - requires loading image)
58
- * @param file - File to validate
59
- * @param options - Validation options with minWidth/minHeight
60
- * @returns Promise with validation result
61
- */
62
- validateDimensions(file: File, options: Pick<ImageValidateOptions, 'minWidth' | 'minHeight'>): Promise<ImageValidationResult>;
63
- /**
64
- * Convert a Blob/File to a data URL
65
- */
66
- toDataUrl(file: File | Blob): Promise<string>;
67
- /**
68
- * Convert a data URL to a Blob
69
- */
70
- dataUrlToBlob(dataUrl: string): Blob;
71
- private loadImage;
72
- private calculateDimensions;
73
- private canvasToBlob;
74
- static ɵfac: i0.ɵɵFactoryDeclaration<ImageService, never>;
75
- static ɵprov: i0.ɵɵInjectableDeclaration<ImageService>;
76
- }
@@ -1,2 +0,0 @@
1
- export * from './image.service';
2
- export * from './types';