@capgo/capacitor-file-compressor 8.0.34 → 8.1.1

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 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Capacitor File Compressor Plugin interface for image compression.\n *\n * @since 7.0.0\n */\nexport interface FileCompressorPlugin {\n /**\n * Compresses an image file with specified dimensions and quality settings.\n *\n * This method compresses images to reduce file size while maintaining acceptable quality.\n * It supports resizing and format conversion (JPEG/WebP depending on platform).\n *\n * **Important Notes:**\n * - EXIF metadata is removed during compression on all platforms\n * - Aspect ratio is automatically maintained if only one dimension is provided\n * - Compressed files are saved to temporary directories on native platforms\n *\n * @param options - Configuration options for image compression\n * @returns Promise that resolves with the compressed image path or blob\n * @throws Error if compression fails, invalid parameters, or unsupported format\n * @since 7.0.0\n * @example\n * ```typescript\n * // Web - Compress from file input\n * const fileInput = document.getElementById('file') as HTMLInputElement;\n * const file = fileInput.files[0];\n * const result = await FileCompressor.compressImage({\n * blob: file,\n * quality: 0.8,\n * width: 1200,\n * mimeType: 'image/jpeg'\n * });\n * const url = URL.createObjectURL(result.blob);\n * ```\n * @example\n * ```typescript\n * // iOS - Compress image from file path\n * const result = await FileCompressor.compressImage({\n * path: 'file:///var/mobile/Containers/Data/image.jpg',\n * quality: 0.7,\n * width: 1000,\n * mimeType: 'image/jpeg' // Only JPEG supported on iOS\n * });\n * console.log('Compressed to:', result.path);\n * ```\n * @example\n * ```typescript\n * // Android - Compress with WebP format\n * const result = await FileCompressor.compressImage({\n * path: 'content://downloads/document/123',\n * quality: 0.6,\n * width: 800,\n * height: 600,\n * mimeType: 'image/webp'\n * });\n * console.log('Compressed to:', result.path);\n * ```\n * @example\n * ```typescript\n * // Maintain aspect ratio - only specify width\n * const result = await FileCompressor.compressImage({\n * path: imagePath,\n * quality: 0.75,\n * width: 1920, // Height calculated automatically\n * mimeType: 'image/jpeg'\n * });\n * ```\n */\n compressImage(options: CompressImageOptions): Promise<CompressImageResult>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * Returns the version of the native plugin implementation.\n * Useful for debugging and ensuring compatibility.\n *\n * @returns Promise that resolves with the plugin version string\n * @throws Error if getting the version fails\n * @since 7.0.0\n * @example\n * ```typescript\n * const { version } = await FileCompressor.getPluginVersion();\n * console.log('Plugin version:', version); // \"7.0.0\"\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n\n/**\n * Options for compressing an image.\n *\n * Configure the compression behavior including quality, dimensions, and output format.\n * Platform-specific options are available for path (native) and blob (web).\n *\n * @since 7.0.0\n */\nexport interface CompressImageOptions {\n /**\n * The file path of the image to compress.\n *\n * **Platform:** Android, iOS only (not supported on Web)\n *\n * Accepts various path formats:\n * - iOS: `file://` URLs or absolute paths\n * - Android: `content://` URIs, `file://` URLs, or absolute paths\n *\n * @since 7.0.0\n * @example \"file:///var/mobile/Containers/Data/Application/image.jpg\" // iOS\n * @example \"content://com.android.providers.downloads.documents/document/msf%3A1000000485\" // Android\n * @example \"/storage/emulated/0/Download/photo.png\" // Android absolute path\n */\n path?: string;\n\n /**\n * The file blob of the image to compress.\n *\n * **Platform:** Web only (not supported on iOS/Android)\n *\n * Use this when compressing images from file inputs, fetch responses,\n * or any other Blob source in web applications.\n *\n * @since 7.0.0\n * @example\n * ```typescript\n * // From file input\n * const fileInput = document.getElementById('file') as HTMLInputElement;\n * const blob = fileInput.files[0];\n * ```\n * @example\n * ```typescript\n * // From fetch\n * const response = await fetch('https://example.com/image.jpg');\n * const blob = await response.blob();\n * ```\n */\n blob?: Blob;\n\n /**\n * The quality of the compressed image.\n *\n * **Range:** 0.0 to 1.0\n * - `0.0` = Maximum compression (lowest quality, smallest file)\n * - `1.0` = Minimum compression (highest quality, largest file)\n * - `0.6` = Default balanced compression\n *\n * **Platform:** All platforms\n *\n * Higher quality values result in larger files but better visual quality.\n * The actual compression ratio depends on the image content and format.\n *\n * @since 7.0.0\n * @default 0.6\n * @example 0.8 // High quality\n * @example 0.5 // Medium quality, smaller file\n * @example 0.3 // Low quality, very small file\n */\n quality?: number;\n\n /**\n * The width of the compressed image in pixels.\n *\n * **Platform:** All platforms\n *\n * If only width is specified, height is calculated automatically\n * to maintain the original aspect ratio.\n *\n * If both width and height are specified, the image is resized\n * to exact dimensions (may distort if ratio differs).\n *\n * @since 7.0.0\n * @example 1920 // Full HD width\n * @example 1200 // Common web image width\n * @example 800 // Mobile-optimized width\n */\n width?: number;\n\n /**\n * The height of the compressed image in pixels.\n *\n * **Platform:** All platforms\n *\n * If only height is specified, width is calculated automatically\n * to maintain the original aspect ratio.\n *\n * If both width and height are specified, the image is resized\n * to exact dimensions (may distort if ratio differs).\n *\n * @since 7.0.0\n * @example 1080 // Full HD height\n * @example 800 // Common web image height\n * @example 600 // Mobile-optimized height\n */\n height?: number;\n\n /**\n * The MIME type of the compressed output image.\n *\n * **Platform Support:**\n * - **iOS:** `image/jpeg` only\n * - **Android:** `image/jpeg`, `image/webp`\n * - **Web:** `image/jpeg`, `image/webp`\n *\n * **Format Characteristics:**\n * - **JPEG:** Universal support, good for photos, no transparency\n * - **WebP:** Better compression, supports transparency, not on iOS\n *\n * @since 7.0.0\n * @default \"image/jpeg\"\n * @example \"image/jpeg\" // JPEG format (all platforms)\n * @example \"image/webp\" // WebP format (Android/Web only)\n */\n mimeType?: string;\n}\n\n/**\n * The result of compressing an image.\n *\n * Contains either a file path (native platforms) or a Blob (web platform)\n * depending on where the compression was performed.\n *\n * @since 7.0.0\n */\nexport interface CompressImageResult {\n /**\n * The file path of the compressed image.\n *\n * **Platform:** Android, iOS only (undefined on Web)\n *\n * Points to a temporary file containing the compressed image.\n * On iOS, typically in `NSTemporaryDirectory()`.\n * On Android, typically in app cache directory.\n *\n * **Important:** These files may be cleaned up by the OS.\n * Copy to permanent storage if needed for long-term use.\n *\n * @since 7.0.0\n * @example \"/var/mobile/Containers/Data/tmp/compressed_abc123.jpg\" // iOS\n * @example \"/data/user/0/com.app/cache/compressed_xyz789.jpg\" // Android\n */\n path?: string;\n\n /**\n * The blob of the compressed image.\n *\n * **Platform:** Web only (undefined on iOS/Android)\n *\n * A Blob object containing the compressed image data.\n * Can be used to:\n * - Create object URLs for preview: `URL.createObjectURL(blob)`\n * - Upload to server via FormData\n * - Save to IndexedDB or other storage\n * - Convert to base64 with FileReader\n *\n * @since 7.0.0\n * @example\n * ```typescript\n * // Create preview URL\n * const url = URL.createObjectURL(result.blob);\n * imageElement.src = url;\n * ```\n * @example\n * ```typescript\n * // Upload to server\n * const formData = new FormData();\n * formData.append('image', result.blob, 'compressed.jpg');\n * await fetch('/upload', { method: 'POST', body: formData });\n * ```\n */\n blob?: Blob;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Capacitor File Compressor Plugin interface for image compression.\n *\n * @since 7.0.0\n */\nexport interface FileCompressorPlugin {\n /**\n * Compresses an image file with specified dimensions and quality settings.\n *\n * This method compresses images to reduce file size while maintaining acceptable quality.\n * It supports resizing and format conversion across common image formats.\n *\n * **Supported input formats (platform decoder dependent):**\n * JPEG, PNG, WebP, GIF, BMP, TIFF, HEIF/HEIC\n *\n * **Supported output formats:**\n * - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+)\n * - **Android:** `image/jpeg`, `image/png`, `image/webp`\n * - **Web:** `image/jpeg`, `image/png`, `image/webp`\n *\n * **Important Notes:**\n * - EXIF metadata is removed during compression on all platforms\n * - Aspect ratio is automatically maintained if only one dimension is provided\n * - When both width and height are provided, the image fits inside that box without upscaling\n * - Compressed files are saved to temporary directories on native platforms\n * - If the encoded output would be larger than the source file, quality is reduced automatically while keeping the requested output format\n *\n * @param options - Configuration options for image compression\n * @returns Promise that resolves with the compressed image path or blob\n * @throws Error if compression fails, invalid parameters, or unsupported format\n * @since 7.0.0\n * @example\n * ```typescript\n * // Web - Compress from file input\n * const fileInput = document.getElementById('file') as HTMLInputElement;\n * const file = fileInput.files[0];\n * const result = await FileCompressor.compressImage({\n * blob: file,\n * quality: 0.8,\n * width: 1200,\n * mimeType: 'image/jpeg'\n * });\n * const url = URL.createObjectURL(result.blob);\n * ```\n * @example\n * ```typescript\n * // iOS - Convert HEIF iPhone photo to JPEG\n * const result = await FileCompressor.compressImage({\n * path: heifFileUri,\n * quality: 0.7,\n * width: 1920,\n * height: 1080,\n * mimeType: 'image/jpeg'\n * });\n * console.log('Converted to JPEG:', result.path);\n * ```\n * @example\n * ```typescript\n * // Android - Convert PNG to WebP\n * const result = await FileCompressor.compressImage({\n * path: 'content://downloads/document/123',\n * quality: 0.6,\n * width: 800,\n * height: 600,\n * mimeType: 'image/webp'\n * });\n * console.log('Compressed to:', result.path);\n * ```\n * @example\n * ```typescript\n * // Maintain aspect ratio - only specify width\n * const result = await FileCompressor.compressImage({\n * path: imagePath,\n * quality: 0.75,\n * width: 1920,\n * mimeType: 'image/jpeg'\n * });\n * ```\n */\n compressImage(options: CompressImageOptions): Promise<CompressImageResult>;\n\n /**\n * Get the native Capacitor plugin version.\n *\n * Returns the version of the native plugin implementation.\n * Useful for debugging and ensuring compatibility.\n *\n * @returns Promise that resolves with the plugin version string\n * @throws Error if getting the version fails\n * @since 7.0.0\n * @example\n * ```typescript\n * const { version } = await FileCompressor.getPluginVersion();\n * console.log('Plugin version:', version); // \"7.0.0\"\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n\n/**\n * Options for compressing an image.\n *\n * Configure the compression behavior including quality, dimensions, and output format.\n * Platform-specific options are available for path (native) and blob (web).\n *\n * @since 7.0.0\n */\nexport interface CompressImageOptions {\n /**\n * The file path of the image to compress.\n *\n * **Platform:** Android, iOS only (not supported on Web)\n *\n * Accepts various path formats:\n * - iOS: `file://` URLs or absolute paths\n * - Android: `content://` URIs, `file://` URLs, or absolute paths\n *\n * Common input formats include JPEG, PNG, WebP, GIF, BMP, TIFF, and HEIF/HEIC.\n *\n * @since 7.0.0\n * @example \"file:///var/mobile/Containers/Data/Application/photo.heic\" // iOS HEIF\n * @example \"content://com.android.providers.downloads.documents/document/msf%3A1000000485\" // Android\n * @example \"/storage/emulated/0/Download/photo.png\" // Android absolute path\n */\n path?: string;\n\n /**\n * The file blob of the image to compress.\n *\n * **Platform:** Web only (not supported on iOS/Android)\n *\n * Use this when compressing images from file inputs, fetch responses,\n * or any other Blob source in web applications.\n *\n * @since 7.0.0\n * @example\n * ```typescript\n * // From file input\n * const fileInput = document.getElementById('file') as HTMLInputElement;\n * const blob = fileInput.files[0];\n * ```\n * @example\n * ```typescript\n * // From fetch\n * const response = await fetch('https://example.com/image.jpg');\n * const blob = await response.blob();\n * ```\n */\n blob?: Blob;\n\n /**\n * The quality of the compressed image.\n *\n * **Range:** 0.0 to 1.0\n * - `0.0` = Maximum compression (lowest quality, smallest file)\n * - `1.0` = Minimum compression (highest quality, largest file)\n * - `0.6` = Default balanced compression\n *\n * **Platform:** All platforms\n *\n * Higher quality values result in larger files but better visual quality.\n * The actual compression ratio depends on the image content and format.\n * PNG output ignores quality because it is lossless.\n *\n * @since 7.0.0\n * @default 0.6\n * @example 0.8 // High quality\n * @example 0.5 // Medium quality, smaller file\n * @example 0.3 // Low quality, very small file\n */\n quality?: number;\n\n /**\n * The width of the compressed image in pixels.\n *\n * **Platform:** All platforms\n *\n * If only width is specified, height is calculated automatically\n * to maintain the original aspect ratio.\n *\n * If both width and height are specified, the image is scaled to fit inside\n * that box while preserving aspect ratio. Images are never upscaled.\n *\n * @since 7.0.0\n * @example 1920 // Full HD width\n * @example 1200 // Common web image width\n * @example 800 // Mobile-optimized width\n */\n width?: number;\n\n /**\n * The height of the compressed image in pixels.\n *\n * **Platform:** All platforms\n *\n * If only height is specified, width is calculated automatically\n * to maintain the original aspect ratio.\n *\n * If both width and height are specified, the image is scaled to fit inside\n * that box while preserving aspect ratio. Images are never upscaled.\n *\n * @since 7.0.0\n * @example 1080 // Full HD height\n * @example 800 // Common web image height\n * @example 600 // Mobile-optimized height\n */\n height?: number;\n\n /**\n * The MIME type of the compressed output image.\n *\n * **Platform Support:**\n * - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+)\n * - **Android:** `image/jpeg`, `image/png`, `image/webp`\n * - **Web:** `image/jpeg`, `image/png`, `image/webp`\n *\n * Use this option to convert the source image to another format while compressing.\n *\n * **Format Characteristics:**\n * - **JPEG:** Universal support, good for photos, no transparency\n * - **PNG:** Lossless, supports transparency\n * - **WebP:** Better compression, supports transparency\n * - **HEIF/HEIC:** Efficient photo format on iOS\n *\n * @since 7.0.0\n * @default \"image/jpeg\"\n * @example \"image/jpeg\" // JPEG format\n * @example \"image/png\" // PNG format\n * @example \"image/webp\" // WebP format\n * @example \"image/heif\" // HEIF format (iOS output)\n */\n mimeType?: string;\n}\n\n/**\n * The result of compressing an image.\n *\n * Contains either a file path (native platforms) or a Blob (web platform)\n * depending on where the compression was performed.\n *\n * @since 7.0.0\n */\nexport interface CompressImageResult {\n /**\n * The file path of the compressed image.\n *\n * **Platform:** Android, iOS only (undefined on Web)\n *\n * Points to a temporary file containing the compressed image.\n * On iOS, typically in `NSTemporaryDirectory()`.\n * On Android, typically in app cache directory.\n *\n * **Important:** These files may be cleaned up by the OS.\n * Copy to permanent storage if needed for long-term use.\n *\n * @since 7.0.0\n * @example \"/var/mobile/Containers/Data/tmp/compressed_abc123.jpg\" // iOS\n * @example \"/data/user/0/com.app/cache/compressed_xyz789.webp\" // Android\n */\n path?: string;\n\n /**\n * The blob of the compressed image.\n *\n * **Platform:** Web only (undefined on iOS/Android)\n *\n * A Blob object containing the compressed image data.\n * Can be used to:\n * - Create object URLs for preview: `URL.createObjectURL(blob)`\n * - Upload to server via FormData\n * - Save to IndexedDB or other storage\n * - Convert to base64 with FileReader\n *\n * @since 7.0.0\n * @example\n * ```typescript\n * // Create preview URL\n * const url = URL.createObjectURL(result.blob);\n * imageElement.src = url;\n * ```\n * @example\n * ```typescript\n * // Upload to server\n * const formData = new FormData();\n * formData.append('image', result.blob, 'compressed.jpg');\n * await fetch('/upload', { method: 'POST', body: formData });\n * ```\n */\n blob?: Blob;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
2
  import type { CompressImageOptions, CompressImageResult, FileCompressorPlugin } from './definitions';
3
3
  export declare class FileCompressorWeb extends WebPlugin implements FileCompressorPlugin {
4
+ private readonly minimumQuality;
5
+ private readonly qualityStep;
4
6
  compressImage(options: CompressImageOptions): Promise<CompressImageResult>;
5
7
  getPluginVersion(): Promise<{
6
8
  version: string;
7
9
  }>;
10
+ private calculateDimensions;
11
+ private canvasToBlobWithinSize;
12
+ private canvasToBlob;
8
13
  private createImageFromBlob;
9
14
  }
package/dist/esm/web.js CHANGED
@@ -1,29 +1,23 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
+ const SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
2
3
  export class FileCompressorWeb extends WebPlugin {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.minimumQuality = 0.1;
7
+ this.qualityStep = 0.05;
8
+ }
3
9
  async compressImage(options) {
4
- var _a, _b, _c, _d;
10
+ var _a, _b;
5
11
  if (!options.blob) {
6
12
  throw new Error('blob is required on web platform');
7
13
  }
8
14
  const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;
9
- const mimeType = (_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg';
10
- // Validate mime type for web
11
- if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {
12
- throw new Error('Only image/jpeg and image/webp are supported on web platform');
15
+ const mimeType = ((_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg').toLowerCase();
16
+ if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType)) {
17
+ throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);
13
18
  }
14
- // Create image element to load the blob
15
19
  const img = await this.createImageFromBlob(options.blob);
16
- // Calculate dimensions
17
- let width = (_c = options.width) !== null && _c !== void 0 ? _c : img.width;
18
- let height = (_d = options.height) !== null && _d !== void 0 ? _d : img.height;
19
- // Maintain aspect ratio if only one dimension is provided
20
- if (options.width && !options.height) {
21
- height = (img.height / img.width) * width;
22
- }
23
- else if (options.height && !options.width) {
24
- width = (img.width / img.height) * height;
25
- }
26
- // Create canvas and draw image
20
+ const { width, height } = this.calculateDimensions(img, options.width, options.height);
27
21
  const canvas = document.createElement('canvas');
28
22
  canvas.width = width;
29
23
  canvas.height = height;
@@ -32,8 +26,45 @@ export class FileCompressorWeb extends WebPlugin {
32
26
  throw new Error('Failed to get canvas context');
33
27
  }
34
28
  ctx.drawImage(img, 0, 0, width, height);
35
- // Convert canvas to blob
36
- const blob = await new Promise((resolve, reject) => {
29
+ const blob = await this.canvasToBlobWithinSize(canvas, mimeType, quality, options.blob.size);
30
+ return { blob };
31
+ }
32
+ async getPluginVersion() {
33
+ return { version: '7.0.0' };
34
+ }
35
+ calculateDimensions(img, maxWidth, maxHeight) {
36
+ let width = img.width;
37
+ let height = img.height;
38
+ if (maxWidth != null && maxHeight != null) {
39
+ const ratio = Math.min(maxWidth / width, maxHeight / height, 1);
40
+ width = Math.round(width * ratio);
41
+ height = Math.round(height * ratio);
42
+ }
43
+ else if (maxWidth != null) {
44
+ const ratio = Math.min(maxWidth / width, 1);
45
+ width = Math.round(width * ratio);
46
+ height = Math.round(height * ratio);
47
+ }
48
+ else if (maxHeight != null) {
49
+ const ratio = Math.min(maxHeight / height, 1);
50
+ width = Math.round(width * ratio);
51
+ height = Math.round(height * ratio);
52
+ }
53
+ return { width, height };
54
+ }
55
+ async canvasToBlobWithinSize(canvas, mimeType, quality, maxBytes) {
56
+ let currentQuality = quality;
57
+ const supportsQuality = mimeType !== 'image/png';
58
+ while (true) {
59
+ const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);
60
+ if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {
61
+ return blob;
62
+ }
63
+ currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);
64
+ }
65
+ }
66
+ canvasToBlob(canvas, mimeType, quality) {
67
+ return new Promise((resolve, reject) => {
37
68
  canvas.toBlob((blob) => {
38
69
  if (blob) {
39
70
  resolve(blob);
@@ -43,10 +74,6 @@ export class FileCompressorWeb extends WebPlugin {
43
74
  }
44
75
  }, mimeType, quality);
45
76
  });
46
- return { blob };
47
- }
48
- async getPluginVersion() {
49
- return { version: '7.0.0' };
50
77
  }
51
78
  createImageFromBlob(blob) {
52
79
  return new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC9C,KAAK,CAAC,aAAa,CAAC,OAA6B;;QAC/C,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,OAAO,mCAAI,GAAG,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAA,OAAO,CAAC,QAAQ,mCAAI,YAAY,CAAC;QAElD,6BAA6B;QAC7B,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAClF,CAAC;QAED,wCAAwC;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEzD,uBAAuB;QACvB,IAAI,KAAK,GAAG,MAAA,OAAO,CAAC,KAAK,mCAAI,GAAG,CAAC,KAAK,CAAC;QACvC,IAAI,MAAM,GAAG,MAAA,OAAO,CAAC,MAAM,mCAAI,GAAG,CAAC,MAAM,CAAC;QAE1C,0DAA0D;QAC1D,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QAC5C,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5C,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;QAC5C,CAAC;QAED,+BAA+B;QAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAExC,yBAAyB;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACvD,MAAM,CAAC,MAAM,CACX,CAAC,IAAI,EAAE,EAAE;gBACP,IAAI,IAAI,EAAE,CAAC;oBACT,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC,EACD,QAAQ,EACR,OAAO,CACR,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAEO,mBAAmB,CAAC,IAAU;QACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEtC,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;gBAChB,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,CAAC;YAEF,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE;gBACjB,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBACzB,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;YACtD,CAAC,CAAC;YAEF,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { CompressImageOptions, CompressImageResult, FileCompressorPlugin } from './definitions';\n\nexport class FileCompressorWeb extends WebPlugin implements FileCompressorPlugin {\n async compressImage(options: CompressImageOptions): Promise<CompressImageResult> {\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n\n const quality = options.quality ?? 0.6;\n const mimeType = options.mimeType ?? 'image/jpeg';\n\n // Validate mime type for web\n if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {\n throw new Error('Only image/jpeg and image/webp are supported on web platform');\n }\n\n // Create image element to load the blob\n const img = await this.createImageFromBlob(options.blob);\n\n // Calculate dimensions\n let width = options.width ?? img.width;\n let height = options.height ?? img.height;\n\n // Maintain aspect ratio if only one dimension is provided\n if (options.width && !options.height) {\n height = (img.height / img.width) * width;\n } else if (options.height && !options.width) {\n width = (img.width / img.height) * height;\n }\n\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // Convert canvas to blob\n const blob = await new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error('Failed to create blob from canvas'));\n }\n },\n mimeType,\n quality,\n );\n });\n\n return { blob };\n }\n\n async getPluginVersion(): Promise<{ version: string }> {\n return { version: '7.0.0' };\n }\n\n private createImageFromBlob(blob: Blob): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n\n img.src = url;\n });\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { CompressImageOptions, CompressImageResult, FileCompressorPlugin } from './definitions';\n\nconst SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'] as const;\n\ntype SupportedOutputMimeType = (typeof SUPPORTED_OUTPUT_MIME_TYPES)[number];\n\nexport class FileCompressorWeb extends WebPlugin implements FileCompressorPlugin {\n private readonly minimumQuality = 0.1;\n private readonly qualityStep = 0.05;\n\n async compressImage(options: CompressImageOptions): Promise<CompressImageResult> {\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n\n const quality = options.quality ?? 0.6;\n const mimeType = (options.mimeType ?? 'image/jpeg').toLowerCase();\n\n if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType as SupportedOutputMimeType)) {\n throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);\n }\n\n const img = await this.createImageFromBlob(options.blob);\n const { width, height } = this.calculateDimensions(img, options.width, options.height);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n const blob = await this.canvasToBlobWithinSize(\n canvas,\n mimeType as SupportedOutputMimeType,\n quality,\n options.blob.size,\n );\n\n return { blob };\n }\n\n async getPluginVersion(): Promise<{ version: string }> {\n return { version: '7.0.0' };\n }\n\n private calculateDimensions(\n img: HTMLImageElement,\n maxWidth?: number,\n maxHeight?: number,\n ): { width: number; height: number } {\n let width = img.width;\n let height = img.height;\n\n if (maxWidth != null && maxHeight != null) {\n const ratio = Math.min(maxWidth / width, maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n } else if (maxWidth != null) {\n const ratio = Math.min(maxWidth / width, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n } else if (maxHeight != null) {\n const ratio = Math.min(maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n\n return { width, height };\n }\n\n private async canvasToBlobWithinSize(\n canvas: HTMLCanvasElement,\n mimeType: SupportedOutputMimeType,\n quality: number,\n maxBytes: number,\n ): Promise<Blob> {\n let currentQuality = quality;\n const supportsQuality = mimeType !== 'image/png';\n\n while (true) {\n const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);\n if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {\n return blob;\n }\n\n currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);\n }\n }\n\n private canvasToBlob(canvas: HTMLCanvasElement, mimeType: SupportedOutputMimeType, quality: number): Promise<Blob> {\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error('Failed to create blob from canvas'));\n }\n },\n mimeType,\n quality,\n );\n });\n }\n\n private createImageFromBlob(blob: Blob): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n\n img.src = url;\n });\n }\n}\n"]}
@@ -6,31 +6,25 @@ const FileCompressor = core.registerPlugin('FileCompressor', {
6
6
  web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.FileCompressorWeb()),
7
7
  });
8
8
 
9
+ const SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
9
10
  class FileCompressorWeb extends core.WebPlugin {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.minimumQuality = 0.1;
14
+ this.qualityStep = 0.05;
15
+ }
10
16
  async compressImage(options) {
11
- var _a, _b, _c, _d;
17
+ var _a, _b;
12
18
  if (!options.blob) {
13
19
  throw new Error('blob is required on web platform');
14
20
  }
15
21
  const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;
16
- const mimeType = (_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg';
17
- // Validate mime type for web
18
- if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {
19
- throw new Error('Only image/jpeg and image/webp are supported on web platform');
22
+ const mimeType = ((_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg').toLowerCase();
23
+ if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType)) {
24
+ throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);
20
25
  }
21
- // Create image element to load the blob
22
26
  const img = await this.createImageFromBlob(options.blob);
23
- // Calculate dimensions
24
- let width = (_c = options.width) !== null && _c !== void 0 ? _c : img.width;
25
- let height = (_d = options.height) !== null && _d !== void 0 ? _d : img.height;
26
- // Maintain aspect ratio if only one dimension is provided
27
- if (options.width && !options.height) {
28
- height = (img.height / img.width) * width;
29
- }
30
- else if (options.height && !options.width) {
31
- width = (img.width / img.height) * height;
32
- }
33
- // Create canvas and draw image
27
+ const { width, height } = this.calculateDimensions(img, options.width, options.height);
34
28
  const canvas = document.createElement('canvas');
35
29
  canvas.width = width;
36
30
  canvas.height = height;
@@ -39,8 +33,45 @@ class FileCompressorWeb extends core.WebPlugin {
39
33
  throw new Error('Failed to get canvas context');
40
34
  }
41
35
  ctx.drawImage(img, 0, 0, width, height);
42
- // Convert canvas to blob
43
- const blob = await new Promise((resolve, reject) => {
36
+ const blob = await this.canvasToBlobWithinSize(canvas, mimeType, quality, options.blob.size);
37
+ return { blob };
38
+ }
39
+ async getPluginVersion() {
40
+ return { version: '7.0.0' };
41
+ }
42
+ calculateDimensions(img, maxWidth, maxHeight) {
43
+ let width = img.width;
44
+ let height = img.height;
45
+ if (maxWidth != null && maxHeight != null) {
46
+ const ratio = Math.min(maxWidth / width, maxHeight / height, 1);
47
+ width = Math.round(width * ratio);
48
+ height = Math.round(height * ratio);
49
+ }
50
+ else if (maxWidth != null) {
51
+ const ratio = Math.min(maxWidth / width, 1);
52
+ width = Math.round(width * ratio);
53
+ height = Math.round(height * ratio);
54
+ }
55
+ else if (maxHeight != null) {
56
+ const ratio = Math.min(maxHeight / height, 1);
57
+ width = Math.round(width * ratio);
58
+ height = Math.round(height * ratio);
59
+ }
60
+ return { width, height };
61
+ }
62
+ async canvasToBlobWithinSize(canvas, mimeType, quality, maxBytes) {
63
+ let currentQuality = quality;
64
+ const supportsQuality = mimeType !== 'image/png';
65
+ while (true) {
66
+ const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);
67
+ if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {
68
+ return blob;
69
+ }
70
+ currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);
71
+ }
72
+ }
73
+ canvasToBlob(canvas, mimeType, quality) {
74
+ return new Promise((resolve, reject) => {
44
75
  canvas.toBlob((blob) => {
45
76
  if (blob) {
46
77
  resolve(blob);
@@ -50,10 +81,6 @@ class FileCompressorWeb extends core.WebPlugin {
50
81
  }
51
82
  }, mimeType, quality);
52
83
  });
53
- return { blob };
54
- }
55
- async getPluginVersion() {
56
- return { version: '7.0.0' };
57
84
  }
58
85
  createImageFromBlob(blob) {
59
86
  return new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst FileCompressor = registerPlugin('FileCompressor', {\n web: () => import('./web').then((m) => new m.FileCompressorWeb()),\n});\nexport * from './definitions';\nexport { FileCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class FileCompressorWeb extends WebPlugin {\n async compressImage(options) {\n var _a, _b, _c, _d;\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;\n const mimeType = (_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg';\n // Validate mime type for web\n if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {\n throw new Error('Only image/jpeg and image/webp are supported on web platform');\n }\n // Create image element to load the blob\n const img = await this.createImageFromBlob(options.blob);\n // Calculate dimensions\n let width = (_c = options.width) !== null && _c !== void 0 ? _c : img.width;\n let height = (_d = options.height) !== null && _d !== void 0 ? _d : img.height;\n // Maintain aspect ratio if only one dimension is provided\n if (options.width && !options.height) {\n height = (img.height / img.width) * width;\n }\n else if (options.height && !options.width) {\n width = (img.width / img.height) * height;\n }\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n ctx.drawImage(img, 0, 0, width, height);\n // Convert canvas to blob\n const blob = await new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n }\n else {\n reject(new Error('Failed to create blob from canvas'));\n }\n }, mimeType, quality);\n });\n return { blob };\n }\n async getPluginVersion() {\n return { version: '7.0.0' };\n }\n createImageFromBlob(blob) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n img.src = url;\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst FileCompressor = registerPlugin('FileCompressor', {\n web: () => import('./web').then((m) => new m.FileCompressorWeb()),\n});\nexport * from './definitions';\nexport { FileCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];\nexport class FileCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.minimumQuality = 0.1;\n this.qualityStep = 0.05;\n }\n async compressImage(options) {\n var _a, _b;\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;\n const mimeType = ((_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg').toLowerCase();\n if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType)) {\n throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);\n }\n const img = await this.createImageFromBlob(options.blob);\n const { width, height } = this.calculateDimensions(img, options.width, options.height);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n ctx.drawImage(img, 0, 0, width, height);\n const blob = await this.canvasToBlobWithinSize(canvas, mimeType, quality, options.blob.size);\n return { blob };\n }\n async getPluginVersion() {\n return { version: '7.0.0' };\n }\n calculateDimensions(img, maxWidth, maxHeight) {\n let width = img.width;\n let height = img.height;\n if (maxWidth != null && maxHeight != null) {\n const ratio = Math.min(maxWidth / width, maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n else if (maxWidth != null) {\n const ratio = Math.min(maxWidth / width, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n else if (maxHeight != null) {\n const ratio = Math.min(maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n return { width, height };\n }\n async canvasToBlobWithinSize(canvas, mimeType, quality, maxBytes) {\n let currentQuality = quality;\n const supportsQuality = mimeType !== 'image/png';\n while (true) {\n const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);\n if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {\n return blob;\n }\n currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);\n }\n }\n canvasToBlob(canvas, mimeType, quality) {\n return new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n }\n else {\n reject(new Error('Failed to create blob from canvas'));\n }\n }, mimeType, quality);\n });\n }\n createImageFromBlob(blob) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n img.src = url;\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
package/dist/plugin.js CHANGED
@@ -5,31 +5,25 @@ var capacitorFileCompressor = (function (exports, core) {
5
5
  web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.FileCompressorWeb()),
6
6
  });
7
7
 
8
+ const SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
8
9
  class FileCompressorWeb extends core.WebPlugin {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.minimumQuality = 0.1;
13
+ this.qualityStep = 0.05;
14
+ }
9
15
  async compressImage(options) {
10
- var _a, _b, _c, _d;
16
+ var _a, _b;
11
17
  if (!options.blob) {
12
18
  throw new Error('blob is required on web platform');
13
19
  }
14
20
  const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;
15
- const mimeType = (_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg';
16
- // Validate mime type for web
17
- if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {
18
- throw new Error('Only image/jpeg and image/webp are supported on web platform');
21
+ const mimeType = ((_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg').toLowerCase();
22
+ if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType)) {
23
+ throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);
19
24
  }
20
- // Create image element to load the blob
21
25
  const img = await this.createImageFromBlob(options.blob);
22
- // Calculate dimensions
23
- let width = (_c = options.width) !== null && _c !== void 0 ? _c : img.width;
24
- let height = (_d = options.height) !== null && _d !== void 0 ? _d : img.height;
25
- // Maintain aspect ratio if only one dimension is provided
26
- if (options.width && !options.height) {
27
- height = (img.height / img.width) * width;
28
- }
29
- else if (options.height && !options.width) {
30
- width = (img.width / img.height) * height;
31
- }
32
- // Create canvas and draw image
26
+ const { width, height } = this.calculateDimensions(img, options.width, options.height);
33
27
  const canvas = document.createElement('canvas');
34
28
  canvas.width = width;
35
29
  canvas.height = height;
@@ -38,8 +32,45 @@ var capacitorFileCompressor = (function (exports, core) {
38
32
  throw new Error('Failed to get canvas context');
39
33
  }
40
34
  ctx.drawImage(img, 0, 0, width, height);
41
- // Convert canvas to blob
42
- const blob = await new Promise((resolve, reject) => {
35
+ const blob = await this.canvasToBlobWithinSize(canvas, mimeType, quality, options.blob.size);
36
+ return { blob };
37
+ }
38
+ async getPluginVersion() {
39
+ return { version: '7.0.0' };
40
+ }
41
+ calculateDimensions(img, maxWidth, maxHeight) {
42
+ let width = img.width;
43
+ let height = img.height;
44
+ if (maxWidth != null && maxHeight != null) {
45
+ const ratio = Math.min(maxWidth / width, maxHeight / height, 1);
46
+ width = Math.round(width * ratio);
47
+ height = Math.round(height * ratio);
48
+ }
49
+ else if (maxWidth != null) {
50
+ const ratio = Math.min(maxWidth / width, 1);
51
+ width = Math.round(width * ratio);
52
+ height = Math.round(height * ratio);
53
+ }
54
+ else if (maxHeight != null) {
55
+ const ratio = Math.min(maxHeight / height, 1);
56
+ width = Math.round(width * ratio);
57
+ height = Math.round(height * ratio);
58
+ }
59
+ return { width, height };
60
+ }
61
+ async canvasToBlobWithinSize(canvas, mimeType, quality, maxBytes) {
62
+ let currentQuality = quality;
63
+ const supportsQuality = mimeType !== 'image/png';
64
+ while (true) {
65
+ const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);
66
+ if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {
67
+ return blob;
68
+ }
69
+ currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);
70
+ }
71
+ }
72
+ canvasToBlob(canvas, mimeType, quality) {
73
+ return new Promise((resolve, reject) => {
43
74
  canvas.toBlob((blob) => {
44
75
  if (blob) {
45
76
  resolve(blob);
@@ -49,10 +80,6 @@ var capacitorFileCompressor = (function (exports, core) {
49
80
  }
50
81
  }, mimeType, quality);
51
82
  });
52
- return { blob };
53
- }
54
- async getPluginVersion() {
55
- return { version: '7.0.0' };
56
83
  }
57
84
  createImageFromBlob(blob) {
58
85
  return new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst FileCompressor = registerPlugin('FileCompressor', {\n web: () => import('./web').then((m) => new m.FileCompressorWeb()),\n});\nexport * from './definitions';\nexport { FileCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class FileCompressorWeb extends WebPlugin {\n async compressImage(options) {\n var _a, _b, _c, _d;\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;\n const mimeType = (_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg';\n // Validate mime type for web\n if (mimeType !== 'image/jpeg' && mimeType !== 'image/webp') {\n throw new Error('Only image/jpeg and image/webp are supported on web platform');\n }\n // Create image element to load the blob\n const img = await this.createImageFromBlob(options.blob);\n // Calculate dimensions\n let width = (_c = options.width) !== null && _c !== void 0 ? _c : img.width;\n let height = (_d = options.height) !== null && _d !== void 0 ? _d : img.height;\n // Maintain aspect ratio if only one dimension is provided\n if (options.width && !options.height) {\n height = (img.height / img.width) * width;\n }\n else if (options.height && !options.width) {\n width = (img.width / img.height) * height;\n }\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n ctx.drawImage(img, 0, 0, width, height);\n // Convert canvas to blob\n const blob = await new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n }\n else {\n reject(new Error('Failed to create blob from canvas'));\n }\n }, mimeType, quality);\n });\n return { blob };\n }\n async getPluginVersion() {\n return { version: '7.0.0' };\n }\n createImageFromBlob(blob) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n img.src = url;\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst FileCompressor = registerPlugin('FileCompressor', {\n web: () => import('./web').then((m) => new m.FileCompressorWeb()),\n});\nexport * from './definitions';\nexport { FileCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst SUPPORTED_OUTPUT_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];\nexport class FileCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.minimumQuality = 0.1;\n this.qualityStep = 0.05;\n }\n async compressImage(options) {\n var _a, _b;\n if (!options.blob) {\n throw new Error('blob is required on web platform');\n }\n const quality = (_a = options.quality) !== null && _a !== void 0 ? _a : 0.6;\n const mimeType = ((_b = options.mimeType) !== null && _b !== void 0 ? _b : 'image/jpeg').toLowerCase();\n if (!SUPPORTED_OUTPUT_MIME_TYPES.includes(mimeType)) {\n throw new Error(`Unsupported output mimeType: ${mimeType}. Supported: ${SUPPORTED_OUTPUT_MIME_TYPES.join(', ')}`);\n }\n const img = await this.createImageFromBlob(options.blob);\n const { width, height } = this.calculateDimensions(img, options.width, options.height);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas context');\n }\n ctx.drawImage(img, 0, 0, width, height);\n const blob = await this.canvasToBlobWithinSize(canvas, mimeType, quality, options.blob.size);\n return { blob };\n }\n async getPluginVersion() {\n return { version: '7.0.0' };\n }\n calculateDimensions(img, maxWidth, maxHeight) {\n let width = img.width;\n let height = img.height;\n if (maxWidth != null && maxHeight != null) {\n const ratio = Math.min(maxWidth / width, maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n else if (maxWidth != null) {\n const ratio = Math.min(maxWidth / width, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n else if (maxHeight != null) {\n const ratio = Math.min(maxHeight / height, 1);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n return { width, height };\n }\n async canvasToBlobWithinSize(canvas, mimeType, quality, maxBytes) {\n let currentQuality = quality;\n const supportsQuality = mimeType !== 'image/png';\n while (true) {\n const blob = await this.canvasToBlob(canvas, mimeType, currentQuality);\n if (blob.size <= maxBytes || currentQuality <= this.minimumQuality || !supportsQuality) {\n return blob;\n }\n currentQuality = Math.max(this.minimumQuality, currentQuality - this.qualityStep);\n }\n }\n canvasToBlob(canvas, mimeType, quality) {\n return new Promise((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n }\n else {\n reject(new Error('Failed to create blob from canvas'));\n }\n }, mimeType, quality);\n });\n }\n createImageFromBlob(blob) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(blob);\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image from blob'));\n };\n img.src = url;\n });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}