@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.
package/README.md CHANGED
@@ -6,15 +6,16 @@
6
6
  <h2><a href="https://capgo.app/consulting/?ref=plugin_file-compressor"> Missing a feature? We'll build the plugin for you 💪</a></h2>
7
7
  </div>
8
8
 
9
- Capacitor plugin for efficient image compression supporting PNG, JPEG, and WebP formats across iOS, Android, and Web platforms.
9
+ Capacitor plugin for efficient image compression and **format conversion** across iOS, Android, and Web.
10
10
 
11
11
  ## Why File Compressor?
12
12
 
13
13
  A free, open-source alternative for **client-side image compression**:
14
14
 
15
- - **Multiple formats** - JPEG and WebP compression support
15
+ - **Format conversion** - Convert HEIF, PNG, WebP, GIF, and more to JPEG, PNG, WebP, or HEIF
16
+ - **Multiple formats** - Broad input support with platform-specific output formats
16
17
  - **Quality control** - Adjustable compression quality (0.0 - 1.0)
17
- - **Smart resizing** - Automatic aspect ratio preservation
18
+ - **Smart resizing** - Automatic aspect ratio preservation without upscaling
18
19
  - **Cross-platform** - Consistent API across iOS, Android, and Web
19
20
  - **Zero backend** - All compression happens on the device
20
21
 
@@ -56,13 +57,28 @@ npm install @capgo/capacitor-file-compressor
56
57
  npx cap sync
57
58
  ```
58
59
 
59
- ## Platform Support
60
+ ## Format Conversion
60
61
 
61
- | Platform | Supported Formats | Notes |
62
- |----------|-------------------|-------|
63
- | iOS | JPEG | Only JPEG compression supported |
64
- | Android | JPEG, WebP | Both formats fully supported |
65
- | Web | JPEG, WebP | Canvas API-based compression |
62
+ The plugin accepts common image formats as input and converts them to the `mimeType` you request.
63
+
64
+ | Platform | Input formats | Output formats |
65
+ |----------|---------------|----------------|
66
+ | iOS | JPEG, PNG, WebP, GIF, BMP, TIFF, HEIF/HEIC | JPEG, PNG, HEIF/HEIC, WebP (iOS 14+) |
67
+ | Android | JPEG, PNG, WebP, GIF, BMP, HEIF/HEIC (API 28+) | JPEG, PNG, WebP |
68
+ | Web | Any format the browser can decode | JPEG, PNG, WebP |
69
+
70
+ ```typescript
71
+ import { FileCompressor } from '@capgo/capacitor-file-compressor';
72
+
73
+ // Convert an iPhone HEIF photo to JPEG before upload
74
+ const result = await FileCompressor.compressImage({
75
+ path: heifFileUri,
76
+ width: 1920,
77
+ height: 1080,
78
+ quality: 0.7,
79
+ mimeType: 'image/jpeg',
80
+ });
81
+ ```
66
82
 
67
83
  Note: EXIF metadata is removed during compression on all platforms.
68
84
 
@@ -90,12 +106,22 @@ compressImage(options: CompressImageOptions) => Promise<CompressImageResult>
90
106
  Compresses an image file with specified dimensions and quality settings.
91
107
 
92
108
  This method compresses images to reduce file size while maintaining acceptable quality.
93
- It supports resizing and format conversion (JPEG/WebP depending on platform).
109
+ It supports resizing and format conversion across common image formats.
110
+
111
+ **Supported input formats (platform decoder dependent):**
112
+ JPEG, PNG, WebP, GIF, BMP, TIFF, HEIF/HEIC
113
+
114
+ **Supported output formats:**
115
+ - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+)
116
+ - **Android:** `image/jpeg`, `image/png`, `image/webp`
117
+ - **Web:** `image/jpeg`, `image/png`, `image/webp`
94
118
 
95
119
  **Important Notes:**
96
120
  - EXIF metadata is removed during compression on all platforms
97
121
  - Aspect ratio is automatically maintained if only one dimension is provided
122
+ - When both width and height are provided, the image fits inside that box without upscaling
98
123
  - Compressed files are saved to temporary directories on native platforms
124
+ - If the encoded output would be larger than the source file, quality is reduced automatically while keeping the requested output format
99
125
 
100
126
  | Param | Type | Description |
101
127
  | ------------- | --------------------------------------------------------------------- | --------------------------------------------- |
@@ -149,13 +175,13 @@ Options for compressing an image.
149
175
  Configure the compression behavior including quality, dimensions, and output format.
150
176
  Platform-specific options are available for path (native) and blob (web).
151
177
 
152
- | Prop | Type | Description | Default | Since |
153
- | -------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ----- |
154
- | **`path`** | <code>string</code> | The file path of the image to compress. **Platform:** Android, iOS only (not supported on Web) Accepts various path formats: - iOS: `file://` URLs or absolute paths - Android: `content://` URIs, `file://` URLs, or absolute paths | | 7.0.0 |
155
- | **`blob`** | <code>Blob</code> | The file blob of the image to compress. **Platform:** Web only (not supported on iOS/Android) Use this when compressing images from file inputs, fetch responses, or any other Blob source in web applications. | | 7.0.0 |
156
- | **`quality`** | <code>number</code> | The quality of the compressed image. **Range:** 0.0 to 1.0 - `0.0` = Maximum compression (lowest quality, smallest file) - `1.0` = Minimum compression (highest quality, largest file) - `0.6` = Default balanced compression **Platform:** All platforms Higher quality values result in larger files but better visual quality. The actual compression ratio depends on the image content and format. | <code>0.6</code> | 7.0.0 |
157
- | **`width`** | <code>number</code> | The width of the compressed image in pixels. **Platform:** All platforms If only width is specified, height is calculated automatically to maintain the original aspect ratio. If both width and height are specified, the image is resized to exact dimensions (may distort if ratio differs). | | 7.0.0 |
158
- | **`height`** | <code>number</code> | The height of the compressed image in pixels. **Platform:** All platforms If only height is specified, width is calculated automatically to maintain the original aspect ratio. If both width and height are specified, the image is resized to exact dimensions (may distort if ratio differs). | | 7.0.0 |
159
- | **`mimeType`** | <code>string</code> | The MIME type of the compressed output image. **Platform Support:** - **iOS:** `image/jpeg` only - **Android:** `image/jpeg`, `image/webp` - **Web:** `image/jpeg`, `image/webp` **Format Characteristics:** - **JPEG:** Universal support, good for photos, no transparency - **WebP:** Better compression, supports transparency, not on iOS | <code>"image/jpeg"</code> | 7.0.0 |
178
+ | Prop | Type | Description | Default | Since |
179
+ | -------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ----- |
180
+ | **`path`** | <code>string</code> | The file path of the image to compress. **Platform:** Android, iOS only (not supported on Web) Accepts various path formats: - iOS: `file://` URLs or absolute paths - Android: `content://` URIs, `file://` URLs, or absolute paths Common input formats include JPEG, PNG, WebP, GIF, BMP, TIFF, and HEIF/HEIC. | | 7.0.0 |
181
+ | **`blob`** | <code>Blob</code> | The file blob of the image to compress. **Platform:** Web only (not supported on iOS/Android) Use this when compressing images from file inputs, fetch responses, or any other Blob source in web applications. | | 7.0.0 |
182
+ | **`quality`** | <code>number</code> | The quality of the compressed image. **Range:** 0.0 to 1.0 - `0.0` = Maximum compression (lowest quality, smallest file) - `1.0` = Minimum compression (highest quality, largest file) - `0.6` = Default balanced compression **Platform:** All platforms Higher quality values result in larger files but better visual quality. The actual compression ratio depends on the image content and format. PNG output ignores quality because it is lossless. | <code>0.6</code> | 7.0.0 |
183
+ | **`width`** | <code>number</code> | The width of the compressed image in pixels. **Platform:** All platforms If only width is specified, height is calculated automatically to maintain the original aspect ratio. If both width and height are specified, the image is scaled to fit inside that box while preserving aspect ratio. Images are never upscaled. | | 7.0.0 |
184
+ | **`height`** | <code>number</code> | The height of the compressed image in pixels. **Platform:** All platforms If only height is specified, width is calculated automatically to maintain the original aspect ratio. If both width and height are specified, the image is scaled to fit inside that box while preserving aspect ratio. Images are never upscaled. | | 7.0.0 |
185
+ | **`mimeType`** | <code>string</code> | The MIME type of the compressed output image. **Platform Support:** - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+) - **Android:** `image/jpeg`, `image/png`, `image/webp` - **Web:** `image/jpeg`, `image/png`, `image/webp` Use this option to convert the source image to another format while compressing. **Format Characteristics:** - **JPEG:** Universal support, good for photos, no transparency - **PNG:** Lossless, supports transparency - **WebP:** Better compression, supports transparency - **HEIF/HEIC:** Efficient photo format on iOS | <code>"image/jpeg"</code> | 7.0.0 |
160
186
 
161
187
  </docgen-api>
@@ -1,9 +1,9 @@
1
1
  package io.capgo.filecompressor;
2
2
 
3
+ import android.content.res.AssetFileDescriptor;
3
4
  import android.graphics.Bitmap;
4
5
  import android.graphics.BitmapFactory;
5
6
  import android.net.Uri;
6
- import android.webkit.MimeTypeMap;
7
7
  import com.getcapacitor.JSObject;
8
8
  import com.getcapacitor.Plugin;
9
9
  import com.getcapacitor.PluginCall;
@@ -13,12 +13,17 @@ import java.io.File;
13
13
  import java.io.FileOutputStream;
14
14
  import java.io.IOException;
15
15
  import java.io.InputStream;
16
+ import java.util.Arrays;
17
+ import java.util.List;
16
18
  import java.util.UUID;
17
19
 
18
20
  @CapacitorPlugin(name = "FileCompressor")
19
21
  public class FileCompressorPlugin extends Plugin {
20
22
 
21
- private final String pluginVersion = "8.0.34";
23
+ private final String pluginVersion = "8.1.1";
24
+ private static final float MIN_QUALITY = 0.1f;
25
+ private static final float QUALITY_STEP = 0.05f;
26
+ private static final List<String> SUPPORTED_OUTPUT_MIME_TYPES = Arrays.asList("image/jpeg", "image/png", "image/webp");
22
27
 
23
28
  @PluginMethod
24
29
  public void compressImage(PluginCall call) {
@@ -31,56 +36,45 @@ public class FileCompressorPlugin extends Plugin {
31
36
  float quality = call.getFloat("quality", 0.6f);
32
37
  Integer width = call.getInt("width");
33
38
  Integer height = call.getInt("height");
34
- String mimeType = call.getString("mimeType", "image/jpeg");
39
+ String mimeType = call.getString("mimeType", "image/jpeg").toLowerCase();
35
40
 
36
- // Validate mime type for Android
37
- if (!mimeType.equals("image/jpeg") && !mimeType.equals("image/webp")) {
38
- call.reject("Only image/jpeg and image/webp are supported on Android");
41
+ if (!SUPPORTED_OUTPUT_MIME_TYPES.contains(mimeType)) {
42
+ call.reject("Unsupported output mimeType: " + mimeType + ". Supported: " + String.join(", ", SUPPORTED_OUTPUT_MIME_TYPES));
39
43
  return;
40
44
  }
41
45
 
42
- // Validate quality range
43
46
  if (quality < 0.0f || quality > 1.0f) {
44
47
  call.reject("quality must be between 0.0 and 1.0");
45
48
  return;
46
49
  }
47
50
 
48
51
  try {
49
- // Load bitmap from path
52
+ long maxBytes = getOriginalFileSize(path);
53
+ OutputFormat outputFormat = OutputFormat.fromMimeType(mimeType);
54
+
50
55
  Bitmap bitmap = loadBitmapFromPath(path);
51
56
  if (bitmap == null) {
52
57
  call.reject("Failed to load image from path");
53
58
  return;
54
59
  }
55
60
 
56
- // Resize bitmap if dimensions are provided
61
+ int[] targetDimensions = calculateTargetDimensions(bitmap, width, height);
57
62
  Bitmap processedBitmap = bitmap;
58
- if (width != null && height != null) {
59
- processedBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
60
- } else if (width != null) {
61
- float aspectRatio = (float) bitmap.getHeight() / bitmap.getWidth();
62
- int targetHeight = (int) (width * aspectRatio);
63
- processedBitmap = Bitmap.createScaledBitmap(bitmap, width, targetHeight, true);
64
- } else if (height != null) {
65
- float aspectRatio = (float) bitmap.getWidth() / bitmap.getHeight();
66
- int targetWidth = (int) (height * aspectRatio);
67
- processedBitmap = Bitmap.createScaledBitmap(bitmap, targetWidth, height, true);
63
+ if (targetDimensions[0] != bitmap.getWidth() || targetDimensions[1] != bitmap.getHeight()) {
64
+ processedBitmap = Bitmap.createScaledBitmap(bitmap, targetDimensions[0], targetDimensions[1], true);
68
65
  }
69
66
 
70
- // Compress bitmap
71
- File compressedFile = compressBitmap(processedBitmap, quality, mimeType);
67
+ File compressedFile = compressBitmap(processedBitmap, quality, outputFormat, maxBytes);
72
68
  if (compressedFile == null) {
73
69
  call.reject("Failed to compress image");
74
70
  return;
75
71
  }
76
72
 
77
- // Clean up
78
73
  if (processedBitmap != bitmap) {
79
74
  processedBitmap.recycle();
80
75
  }
81
76
  bitmap.recycle();
82
77
 
83
- // Return result
84
78
  JSObject result = new JSObject();
85
79
  result.put("path", compressedFile.getAbsolutePath());
86
80
  call.resolve(result);
@@ -89,9 +83,54 @@ public class FileCompressorPlugin extends Plugin {
89
83
  }
90
84
  }
91
85
 
86
+ private int[] calculateTargetDimensions(Bitmap bitmap, Integer maxWidth, Integer maxHeight) {
87
+ int sourceWidth = bitmap.getWidth();
88
+ int sourceHeight = bitmap.getHeight();
89
+
90
+ if (maxWidth == null && maxHeight == null) {
91
+ return new int[] { sourceWidth, sourceHeight };
92
+ }
93
+
94
+ float ratio = 1f;
95
+
96
+ if (maxWidth != null && maxHeight != null) {
97
+ ratio = Math.min((float) maxWidth / sourceWidth, (float) maxHeight / sourceHeight);
98
+ } else if (maxWidth != null) {
99
+ ratio = (float) maxWidth / sourceWidth;
100
+ } else if (maxHeight != null) {
101
+ ratio = (float) maxHeight / sourceHeight;
102
+ }
103
+
104
+ ratio = Math.min(ratio, 1f);
105
+
106
+ return new int[] { Math.round(sourceWidth * ratio), Math.round(sourceHeight * ratio) };
107
+ }
108
+
109
+ private long getOriginalFileSize(String path) {
110
+ try {
111
+ if (path.startsWith("content://")) {
112
+ Uri uri = Uri.parse(path);
113
+ try (AssetFileDescriptor descriptor = getContext().getContentResolver().openAssetFileDescriptor(uri, "r")) {
114
+ if (descriptor != null) {
115
+ return descriptor.getLength();
116
+ }
117
+ }
118
+ } else {
119
+ String filePath = path.startsWith("file://") ? path.substring(7) : path;
120
+ File file = new File(filePath);
121
+ if (file.exists()) {
122
+ return file.length();
123
+ }
124
+ }
125
+ } catch (Exception e) {
126
+ e.printStackTrace();
127
+ }
128
+
129
+ return -1;
130
+ }
131
+
92
132
  private Bitmap loadBitmapFromPath(String path) {
93
133
  try {
94
- // Handle content:// URIs
95
134
  if (path.startsWith("content://")) {
96
135
  Uri uri = Uri.parse(path);
97
136
  InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
@@ -100,13 +139,10 @@ public class FileCompressorPlugin extends Plugin {
100
139
  inputStream.close();
101
140
  return bitmap;
102
141
  }
103
- }
104
- // Handle file:// URIs and absolute paths
105
- else if (path.startsWith("file://")) {
106
- path = path.substring(7); // Remove "file://" prefix
142
+ } else if (path.startsWith("file://")) {
143
+ path = path.substring(7);
107
144
  }
108
145
 
109
- // Try loading as file path
110
146
  File file = new File(path);
111
147
  if (file.exists()) {
112
148
  return BitmapFactory.decodeFile(file.getAbsolutePath());
@@ -117,29 +153,38 @@ public class FileCompressorPlugin extends Plugin {
117
153
  return null;
118
154
  }
119
155
 
120
- private File compressBitmap(Bitmap bitmap, float quality, String mimeType) {
121
- try {
122
- // Determine compression format and file extension
123
- Bitmap.CompressFormat format;
124
- String extension;
156
+ private File compressBitmap(Bitmap bitmap, float quality, OutputFormat outputFormat, long maxBytes) {
157
+ float currentQuality = quality;
158
+ File lastFile = null;
125
159
 
126
- if (mimeType.equals("image/webp")) {
127
- format = Bitmap.CompressFormat.WEBP;
128
- extension = ".webp";
129
- } else {
130
- format = Bitmap.CompressFormat.JPEG;
131
- extension = ".jpg";
160
+ while (true) {
161
+ File compressedFile = writeCompressedBitmap(bitmap, outputFormat, currentQuality);
162
+ if (compressedFile == null) {
163
+ return lastFile;
132
164
  }
133
165
 
134
- // Create temporary file
166
+ if (lastFile != null && lastFile != compressedFile) {
167
+ lastFile.delete();
168
+ }
169
+
170
+ if (maxBytes <= 0 || compressedFile.length() <= maxBytes || currentQuality <= MIN_QUALITY || !outputFormat.supportsQuality) {
171
+ return compressedFile;
172
+ }
173
+
174
+ lastFile = compressedFile;
175
+ currentQuality = Math.max(MIN_QUALITY, currentQuality - QUALITY_STEP);
176
+ }
177
+ }
178
+
179
+ private File writeCompressedBitmap(Bitmap bitmap, OutputFormat outputFormat, float quality) {
180
+ try {
135
181
  File tempDir = getContext().getCacheDir();
136
- String fileName = "compressed_" + UUID.randomUUID().toString() + extension;
182
+ String fileName = "compressed_" + UUID.randomUUID().toString() + outputFormat.extension;
137
183
  File compressedFile = new File(tempDir, fileName);
138
184
 
139
- // Compress and save
140
185
  FileOutputStream outputStream = new FileOutputStream(compressedFile);
141
- int qualityInt = (int) (quality * 100);
142
- bitmap.compress(format, qualityInt, outputStream);
186
+ int qualityInt = Math.round(quality * 100);
187
+ bitmap.compress(outputFormat.format, qualityInt, outputStream);
143
188
  outputStream.flush();
144
189
  outputStream.close();
145
190
 
@@ -160,4 +205,29 @@ public class FileCompressorPlugin extends Plugin {
160
205
  call.reject("Could not get plugin version", e);
161
206
  }
162
207
  }
208
+
209
+ private static final class OutputFormat {
210
+
211
+ private final Bitmap.CompressFormat format;
212
+ private final String extension;
213
+ private final boolean supportsQuality;
214
+
215
+ private OutputFormat(Bitmap.CompressFormat format, String extension, boolean supportsQuality) {
216
+ this.format = format;
217
+ this.extension = extension;
218
+ this.supportsQuality = supportsQuality;
219
+ }
220
+
221
+ private static OutputFormat fromMimeType(String mimeType) {
222
+ switch (mimeType) {
223
+ case "image/webp":
224
+ return new OutputFormat(Bitmap.CompressFormat.WEBP, ".webp", true);
225
+ case "image/png":
226
+ return new OutputFormat(Bitmap.CompressFormat.PNG, ".png", false);
227
+ case "image/jpeg":
228
+ default:
229
+ return new OutputFormat(Bitmap.CompressFormat.JPEG, ".jpg", true);
230
+ }
231
+ }
232
+ }
163
233
  }
package/dist/docs.json CHANGED
@@ -44,18 +44,18 @@
44
44
  },
45
45
  {
46
46
  "name": "example",
47
- "text": "```typescript\n// iOS - Compress image from file path\nconst 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});\nconsole.log('Compressed to:', result.path);\n```"
47
+ "text": "```typescript\n// iOS - Convert HEIF iPhone photo to JPEG\nconst result = await FileCompressor.compressImage({\n path: heifFileUri,\n quality: 0.7,\n width: 1920,\n height: 1080,\n mimeType: 'image/jpeg'\n});\nconsole.log('Converted to JPEG:', result.path);\n```"
48
48
  },
49
49
  {
50
50
  "name": "example",
51
- "text": "```typescript\n// Android - Compress with WebP format\nconst 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});\nconsole.log('Compressed to:', result.path);\n```"
51
+ "text": "```typescript\n// Android - Convert PNG to WebP\nconst 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});\nconsole.log('Compressed to:', result.path);\n```"
52
52
  },
53
53
  {
54
54
  "name": "example",
55
- "text": "```typescript\n// Maintain aspect ratio - only specify width\nconst result = await FileCompressor.compressImage({\n path: imagePath,\n quality: 0.75,\n width: 1920, // Height calculated automatically\n mimeType: 'image/jpeg'\n});\n```"
55
+ "text": "```typescript\n// Maintain aspect ratio - only specify width\nconst result = await FileCompressor.compressImage({\n path: imagePath,\n quality: 0.75,\n width: 1920,\n mimeType: 'image/jpeg'\n});\n```"
56
56
  }
57
57
  ],
58
- "docs": "Compresses an image file with specified dimensions and quality settings.\n\nThis method compresses images to reduce file size while maintaining acceptable quality.\nIt 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",
58
+ "docs": "Compresses an image file with specified dimensions and quality settings.\n\nThis method compresses images to reduce file size while maintaining acceptable quality.\nIt supports resizing and format conversion across common image formats.\n\n**Supported input formats (platform decoder dependent):**\nJPEG, 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",
59
59
  "complexTypes": [
60
60
  "CompressImageResult",
61
61
  "CompressImageOptions"
@@ -117,7 +117,7 @@
117
117
  "name": "example"
118
118
  },
119
119
  {
120
- "text": "\"/data/user/0/com.app/cache/compressed_xyz789.jpg\" // Android",
120
+ "text": "\"/data/user/0/com.app/cache/compressed_xyz789.webp\" // Android",
121
121
  "name": "example"
122
122
  }
123
123
  ],
@@ -169,7 +169,7 @@
169
169
  "name": "since"
170
170
  },
171
171
  {
172
- "text": "\"file:///var/mobile/Containers/Data/Application/image.jpg\" // iOS",
172
+ "text": "\"file:///var/mobile/Containers/Data/Application/photo.heic\" // iOS HEIF",
173
173
  "name": "example"
174
174
  },
175
175
  {
@@ -181,7 +181,7 @@
181
181
  "name": "example"
182
182
  }
183
183
  ],
184
- "docs": "The file path of the image to compress.\n\n**Platform:** Android, iOS only (not supported on Web)\n\nAccepts various path formats:\n- iOS: `file://` URLs or absolute paths\n- Android: `content://` URIs, `file://` URLs, or absolute paths",
184
+ "docs": "The file path of the image to compress.\n\n**Platform:** Android, iOS only (not supported on Web)\n\nAccepts various path formats:\n- iOS: `file://` URLs or absolute paths\n- Android: `content://` URIs, `file://` URLs, or absolute paths\n\nCommon input formats include JPEG, PNG, WebP, GIF, BMP, TIFF, and HEIF/HEIC.",
185
185
  "complexTypes": [],
186
186
  "type": "string | undefined"
187
187
  },
@@ -231,7 +231,7 @@
231
231
  "name": "example"
232
232
  }
233
233
  ],
234
- "docs": "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\nHigher quality values result in larger files but better visual quality.\nThe actual compression ratio depends on the image content and format.",
234
+ "docs": "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\nHigher quality values result in larger files but better visual quality.\nThe actual compression ratio depends on the image content and format.\nPNG output ignores quality because it is lossless.",
235
235
  "complexTypes": [],
236
236
  "type": "number | undefined"
237
237
  },
@@ -255,7 +255,7 @@
255
255
  "name": "example"
256
256
  }
257
257
  ],
258
- "docs": "The width of the compressed image in pixels.\n\n**Platform:** All platforms\n\nIf only width is specified, height is calculated automatically\nto maintain the original aspect ratio.\n\nIf both width and height are specified, the image is resized\nto exact dimensions (may distort if ratio differs).",
258
+ "docs": "The width of the compressed image in pixels.\n\n**Platform:** All platforms\n\nIf only width is specified, height is calculated automatically\nto maintain the original aspect ratio.\n\nIf both width and height are specified, the image is scaled to fit inside\nthat box while preserving aspect ratio. Images are never upscaled.",
259
259
  "complexTypes": [],
260
260
  "type": "number | undefined"
261
261
  },
@@ -279,7 +279,7 @@
279
279
  "name": "example"
280
280
  }
281
281
  ],
282
- "docs": "The height of the compressed image in pixels.\n\n**Platform:** All platforms\n\nIf only height is specified, width is calculated automatically\nto maintain the original aspect ratio.\n\nIf both width and height are specified, the image is resized\nto exact dimensions (may distort if ratio differs).",
282
+ "docs": "The height of the compressed image in pixels.\n\n**Platform:** All platforms\n\nIf only height is specified, width is calculated automatically\nto maintain the original aspect ratio.\n\nIf both width and height are specified, the image is scaled to fit inside\nthat box while preserving aspect ratio. Images are never upscaled.",
283
283
  "complexTypes": [],
284
284
  "type": "number | undefined"
285
285
  },
@@ -295,15 +295,23 @@
295
295
  "name": "default"
296
296
  },
297
297
  {
298
- "text": "\"image/jpeg\" // JPEG format (all platforms)",
298
+ "text": "\"image/jpeg\" // JPEG format",
299
299
  "name": "example"
300
300
  },
301
301
  {
302
- "text": "\"image/webp\" // WebP format (Android/Web only)",
302
+ "text": "\"image/png\" // PNG format",
303
+ "name": "example"
304
+ },
305
+ {
306
+ "text": "\"image/webp\" // WebP format",
307
+ "name": "example"
308
+ },
309
+ {
310
+ "text": "\"image/heif\" // HEIF format (iOS output)",
303
311
  "name": "example"
304
312
  }
305
313
  ],
306
- "docs": "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",
314
+ "docs": "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\nUse 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",
307
315
  "complexTypes": [],
308
316
  "type": "string | undefined"
309
317
  }
@@ -8,12 +8,22 @@ export interface FileCompressorPlugin {
8
8
  * Compresses an image file with specified dimensions and quality settings.
9
9
  *
10
10
  * This method compresses images to reduce file size while maintaining acceptable quality.
11
- * It supports resizing and format conversion (JPEG/WebP depending on platform).
11
+ * It supports resizing and format conversion across common image formats.
12
+ *
13
+ * **Supported input formats (platform decoder dependent):**
14
+ * JPEG, PNG, WebP, GIF, BMP, TIFF, HEIF/HEIC
15
+ *
16
+ * **Supported output formats:**
17
+ * - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+)
18
+ * - **Android:** `image/jpeg`, `image/png`, `image/webp`
19
+ * - **Web:** `image/jpeg`, `image/png`, `image/webp`
12
20
  *
13
21
  * **Important Notes:**
14
22
  * - EXIF metadata is removed during compression on all platforms
15
23
  * - Aspect ratio is automatically maintained if only one dimension is provided
24
+ * - When both width and height are provided, the image fits inside that box without upscaling
16
25
  * - Compressed files are saved to temporary directories on native platforms
26
+ * - If the encoded output would be larger than the source file, quality is reduced automatically while keeping the requested output format
17
27
  *
18
28
  * @param options - Configuration options for image compression
19
29
  * @returns Promise that resolves with the compressed image path or blob
@@ -34,18 +44,19 @@ export interface FileCompressorPlugin {
34
44
  * ```
35
45
  * @example
36
46
  * ```typescript
37
- * // iOS - Compress image from file path
47
+ * // iOS - Convert HEIF iPhone photo to JPEG
38
48
  * const result = await FileCompressor.compressImage({
39
- * path: 'file:///var/mobile/Containers/Data/image.jpg',
49
+ * path: heifFileUri,
40
50
  * quality: 0.7,
41
- * width: 1000,
42
- * mimeType: 'image/jpeg' // Only JPEG supported on iOS
51
+ * width: 1920,
52
+ * height: 1080,
53
+ * mimeType: 'image/jpeg'
43
54
  * });
44
- * console.log('Compressed to:', result.path);
55
+ * console.log('Converted to JPEG:', result.path);
45
56
  * ```
46
57
  * @example
47
58
  * ```typescript
48
- * // Android - Compress with WebP format
59
+ * // Android - Convert PNG to WebP
49
60
  * const result = await FileCompressor.compressImage({
50
61
  * path: 'content://downloads/document/123',
51
62
  * quality: 0.6,
@@ -61,7 +72,7 @@ export interface FileCompressorPlugin {
61
72
  * const result = await FileCompressor.compressImage({
62
73
  * path: imagePath,
63
74
  * quality: 0.75,
64
- * width: 1920, // Height calculated automatically
75
+ * width: 1920,
65
76
  * mimeType: 'image/jpeg'
66
77
  * });
67
78
  * ```
@@ -104,8 +115,10 @@ export interface CompressImageOptions {
104
115
  * - iOS: `file://` URLs or absolute paths
105
116
  * - Android: `content://` URIs, `file://` URLs, or absolute paths
106
117
  *
118
+ * Common input formats include JPEG, PNG, WebP, GIF, BMP, TIFF, and HEIF/HEIC.
119
+ *
107
120
  * @since 7.0.0
108
- * @example "file:///var/mobile/Containers/Data/Application/image.jpg" // iOS
121
+ * @example "file:///var/mobile/Containers/Data/Application/photo.heic" // iOS HEIF
109
122
  * @example "content://com.android.providers.downloads.documents/document/msf%3A1000000485" // Android
110
123
  * @example "/storage/emulated/0/Download/photo.png" // Android absolute path
111
124
  */
@@ -145,6 +158,7 @@ export interface CompressImageOptions {
145
158
  *
146
159
  * Higher quality values result in larger files but better visual quality.
147
160
  * The actual compression ratio depends on the image content and format.
161
+ * PNG output ignores quality because it is lossless.
148
162
  *
149
163
  * @since 7.0.0
150
164
  * @default 0.6
@@ -161,8 +175,8 @@ export interface CompressImageOptions {
161
175
  * If only width is specified, height is calculated automatically
162
176
  * to maintain the original aspect ratio.
163
177
  *
164
- * If both width and height are specified, the image is resized
165
- * to exact dimensions (may distort if ratio differs).
178
+ * If both width and height are specified, the image is scaled to fit inside
179
+ * that box while preserving aspect ratio. Images are never upscaled.
166
180
  *
167
181
  * @since 7.0.0
168
182
  * @example 1920 // Full HD width
@@ -178,8 +192,8 @@ export interface CompressImageOptions {
178
192
  * If only height is specified, width is calculated automatically
179
193
  * to maintain the original aspect ratio.
180
194
  *
181
- * If both width and height are specified, the image is resized
182
- * to exact dimensions (may distort if ratio differs).
195
+ * If both width and height are specified, the image is scaled to fit inside
196
+ * that box while preserving aspect ratio. Images are never upscaled.
183
197
  *
184
198
  * @since 7.0.0
185
199
  * @example 1080 // Full HD height
@@ -191,18 +205,24 @@ export interface CompressImageOptions {
191
205
  * The MIME type of the compressed output image.
192
206
  *
193
207
  * **Platform Support:**
194
- * - **iOS:** `image/jpeg` only
195
- * - **Android:** `image/jpeg`, `image/webp`
196
- * - **Web:** `image/jpeg`, `image/webp`
208
+ * - **iOS:** `image/jpeg`, `image/png`, `image/heif`, `image/heic`, `image/webp` (iOS 14+)
209
+ * - **Android:** `image/jpeg`, `image/png`, `image/webp`
210
+ * - **Web:** `image/jpeg`, `image/png`, `image/webp`
211
+ *
212
+ * Use this option to convert the source image to another format while compressing.
197
213
  *
198
214
  * **Format Characteristics:**
199
215
  * - **JPEG:** Universal support, good for photos, no transparency
200
- * - **WebP:** Better compression, supports transparency, not on iOS
216
+ * - **PNG:** Lossless, supports transparency
217
+ * - **WebP:** Better compression, supports transparency
218
+ * - **HEIF/HEIC:** Efficient photo format on iOS
201
219
  *
202
220
  * @since 7.0.0
203
221
  * @default "image/jpeg"
204
- * @example "image/jpeg" // JPEG format (all platforms)
205
- * @example "image/webp" // WebP format (Android/Web only)
222
+ * @example "image/jpeg" // JPEG format
223
+ * @example "image/png" // PNG format
224
+ * @example "image/webp" // WebP format
225
+ * @example "image/heif" // HEIF format (iOS output)
206
226
  */
207
227
  mimeType?: string;
208
228
  }
@@ -229,7 +249,7 @@ export interface CompressImageResult {
229
249
  *
230
250
  * @since 7.0.0
231
251
  * @example "/var/mobile/Containers/Data/tmp/compressed_abc123.jpg" // iOS
232
- * @example "/data/user/0/com.app/cache/compressed_xyz789.jpg" // Android
252
+ * @example "/data/user/0/com.app/cache/compressed_xyz789.webp" // Android
233
253
  */
234
254
  path?: string;
235
255
  /**