diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java
index 0cb7491edb..01fa8a98fb 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/Camera.java
@@ -182,6 +182,7 @@ private CameraSettings getSettings(PluginCall call) {
settings.setHeight(call.getInt("height", 0));
settings.setShouldResize(settings.getWidth() > 0 || settings.getHeight() > 0);
settings.setShouldCorrectOrientation(call.getBoolean("correctOrientation", CameraSettings.DEFAULT_CORRECT_ORIENTATION));
+ settings.setPreserveAspectRatio(call.getBoolean("preserveAspectRatio", false));
try {
settings.setSource(CameraSource.valueOf(call.getString("source", CameraSource.PROMPT.getSource())));
} catch (IllegalArgumentException ex) {
@@ -410,7 +411,12 @@ private Bitmap prepareBitmap(Bitmap bitmap, Uri imageUri) throws IOException {
}
if (settings.isShouldResize()) {
- final Bitmap newBitmap = ImageUtils.resize(bitmap, settings.getWidth(), settings.getHeight());
+ final Bitmap newBitmap = ImageUtils.resize(
+ bitmap,
+ settings.getWidth(),
+ settings.getHeight(),
+ settings.getPreserveAspectRatio()
+ );
bitmap = replaceBitmap(bitmap, newBitmap);
}
return bitmap;
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/CameraSettings.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/CameraSettings.java
index 5598ff713b..e239a454a8 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/CameraSettings.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/CameraSettings.java
@@ -15,6 +15,7 @@ public class CameraSettings {
private int width = 0;
private int height = 0;
private CameraSource source = CameraSource.PROMPT;
+ private boolean preserveAspectRatio = false;
public CameraResultType getResultType() {
return resultType;
@@ -83,4 +84,12 @@ public CameraSource getSource() {
public void setSource(CameraSource source) {
this.source = source;
}
+
+ public void setPreserveAspectRatio(boolean preserveAspectRatio) {
+ this.preserveAspectRatio = preserveAspectRatio;
+ }
+
+ public boolean getPreserveAspectRatio() {
+ return this.preserveAspectRatio;
+ }
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/ImageUtils.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/ImageUtils.java
index da121340b5..a70977b135 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/ImageUtils.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/camera/ImageUtils.java
@@ -17,6 +17,32 @@
public class ImageUtils {
+ /**
+ * Resize an image to the given width and height.
+ * @param bitmap
+ * @param width
+ * @param height
+ * @return a new, scaled Bitmap
+ */
+ public static Bitmap resize(Bitmap bitmap, final int width, final int height) {
+ return ImageUtils.resize(bitmap, width, height, false);
+ }
+
+ /**
+ * Resize an image to the given width and height considering the preserveAspectRatio flag.
+ * @param bitmap
+ * @param width
+ * @param height
+ * @param preserveAspectRatio
+ * @return a new, scaled Bitmap
+ */
+ public static Bitmap resize(Bitmap bitmap, final int width, final int height, final boolean preserveAspectRatio) {
+ if (preserveAspectRatio) {
+ return ImageUtils.resizePreservingAspectRatio(bitmap, width, height);
+ }
+ return ImageUtils.resizeImageWithoutPreservingAspectRatio(bitmap, width, height);
+ }
+
/**
* Resize an image to the given width and height. Leave one dimension 0 to
* perform an aspect-ratio scale on the provided dimension.
@@ -25,7 +51,7 @@ public class ImageUtils {
* @param height
* @return a new, scaled Bitmap
*/
- public static Bitmap resize(Bitmap bitmap, final int width, final int height) {
+ private static Bitmap resizeImageWithoutPreservingAspectRatio(Bitmap bitmap, final int width, final int height) {
float aspect = bitmap.getWidth() / (float) bitmap.getHeight();
if (width > 0 && height > 0) {
return Bitmap.createScaledBitmap(bitmap, width, height, false);
@@ -38,6 +64,33 @@ public static Bitmap resize(Bitmap bitmap, final int width, final int height) {
return bitmap;
}
+ /**
+ * Resize an image to the given max width and max height. Constraint can be put
+ * on one dimension, or both. Resize will always preserve aspect ratio.
+ * @param bitmap
+ * @param desiredMaxWidth
+ * @param desiredMaxHeight
+ * @return a new, scaled Bitmap
+ */
+ private static Bitmap resizePreservingAspectRatio(Bitmap bitmap, final int desiredMaxWidth, final int desiredMaxHeight) {
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+
+ // 0 is treated as 'no restriction'
+ int maxHeight = desiredMaxHeight == 0 ? height : desiredMaxHeight;
+ int maxWidth = desiredMaxWidth == 0 ? width : desiredMaxWidth;
+
+ // resize with preserved aspect ratio
+ float newWidth = Math.min(width, maxWidth);
+ float newHeight = (height * newWidth) / width;
+
+ if (newHeight > maxHeight) {
+ newWidth = (width * maxHeight) / height;
+ newHeight = maxHeight;
+ }
+ return Bitmap.createScaledBitmap(bitmap, Math.round(newWidth), Math.round(newHeight), false);
+ }
+
/**
* Transform an image with the given matrix
* @param bitmap
diff --git a/core/src/core-plugin-definitions.ts b/core/src/core-plugin-definitions.ts
index de8f92ced1..f8a0618538 100644
--- a/core/src/core-plugin-definitions.ts
+++ b/core/src/core-plugin-definitions.ts
@@ -321,6 +321,18 @@ export interface CameraOptions {
* The height of the saved image
*/
height?: number;
+ /**
+ * Whether to preserve the aspect ratio of the image.
+ * If this flag is true, the width and height will be used as max values
+ * and the aspect ratio will be preserved. This is only relevant when
+ * both a width and height are passed. When only width or height is provided
+ * the aspect ratio is always preserved (and this option is a no-op).
+ *
+ * A future major version will change this behavior to be default,
+ * and may also remove this option altogether.
+ * Default: false
+ */
+ preserveAspectRatio?: boolean;
/**
* Whether to automatically rotate the image "up" to correct for orientation
* in portrait mode
diff --git a/example/src/pages/camera/camera.html b/example/src/pages/camera/camera.html
index d55138ad4b..3e2fa75537 100644
--- a/example/src/pages/camera/camera.html
+++ b/example/src/pages/camera/camera.html
@@ -26,4 +26,5 @@
+
diff --git a/example/src/pages/camera/camera.ts b/example/src/pages/camera/camera.ts
index cb9b8c99eb..052e00eeec 100644
--- a/example/src/pages/camera/camera.ts
+++ b/example/src/pages/camera/camera.ts
@@ -187,4 +187,19 @@ export class CameraPage {
console.log('Got image back', image.path, image.webPath, image.format, image.exif);
this.image = this.sanitizer.bypassSecurityTrustResourceUrl(image && (image.dataUrl));
}
+
+ async takePicturePreservingAspectRatio() {
+ const image = await Plugins.Camera.getPhoto({
+ quality: 80,
+ resultType: CameraResultType.Uri,
+ source: CameraSource.Camera,
+ saveToGallery: true,
+ correctOrientation: true,
+ height: 1920,
+ width: 1920,
+ preserveAspectRatio: true,
+ });
+ console.log('Got image back', image.path, image.webPath, image.format, image.exif);
+ this.image = this.sanitizer.bypassSecurityTrustResourceUrl(image.webPath);
+ }
}
diff --git a/ios/Capacitor/Capacitor/Plugins/Camera.swift b/ios/Capacitor/Capacitor/Plugins/Camera.swift
index 35a9252810..5674f3b0f1 100644
--- a/ios/Capacitor/Capacitor/Plugins/Camera.swift
+++ b/ios/Capacitor/Capacitor/Plugins/Camera.swift
@@ -29,6 +29,7 @@ struct CameraSettings {
var height: Float = 0
var resultType = "base64"
var saveToGallery = false
+ var preserveAspectRatio = false
}
@objc(CAPCameraPlugin)
@@ -72,7 +73,8 @@ public class CAPCameraPlugin : CAPPlugin, UIImagePickerControllerDelegate, UINav
settings.direction = CameraDirection(rawValue: call.getString("direction") ?? DEFAULT_DIRECTION.rawValue) ?? DEFAULT_DIRECTION
settings.resultType = call.get("resultType", String.self, "base64")!
settings.saveToGallery = call.get("saveToGallery", Bool.self, false)!
-
+ settings.preserveAspectRatio = call.get("preserveAspectRatio", Bool.self, false)!
+
// Get the new image dimensions if provided
settings.width = Float(call.get("width", Int.self, 0)!)
settings.height = Float(call.get("height", Int.self, 0)!)
@@ -229,7 +231,7 @@ public class CAPCameraPlugin : CAPPlugin, UIImagePickerControllerDelegate, UINav
}
if settings.shouldResize {
- guard let convertedImage = resizeImage(image!) else {
+ guard let convertedImage = resizeImage(image!, settings.preserveAspectRatio) else {
self.call?.error("Error resizing image")
return
}
@@ -312,7 +314,14 @@ public class CAPCameraPlugin : CAPPlugin, UIImagePickerControllerDelegate, UINav
return meta
}
- func resizeImage(_ image: UIImage) -> UIImage? {
+ func resizeImage(_ image: UIImage, _ preserveAspectRatio: Bool) -> UIImage? {
+ if preserveAspectRatio {
+ return resizeImagePreservingAspectRatio(image)
+ }
+ return resizeImageWithoutPreservingAspectRatio(image)
+ }
+
+ func resizeImageWithoutPreservingAspectRatio(_ image: UIImage) -> UIImage? {
let isAspectScale = settings.width > 0 && settings.height == 0 || settings.height > 0 && settings.width == 0
let aspect = Float(image.size.width / image.size.height);
@@ -333,6 +342,31 @@ public class CAPCameraPlugin : CAPPlugin, UIImagePickerControllerDelegate, UINav
return scaledImage
}
+ func resizeImagePreservingAspectRatio(_ image: UIImage) -> UIImage? {
+ let imageHeight = Float(image.size.height)
+ let imageWidth = Float(image.size.width)
+
+ // 0 is treated as 'no restriction'
+ let maxHeight = settings.height == 0 ? imageHeight : settings.height
+ let maxWidth = settings.width == 0 ? imageWidth : settings.width
+
+ // resize with preserved aspect ratio
+ var newWidth = min(imageWidth, maxWidth)
+ var newHeight = (imageHeight * newWidth) / imageWidth
+ if newHeight > maxHeight {
+ newWidth = (imageWidth * maxHeight) / imageHeight
+ newHeight = maxHeight
+ }
+ let size = CGSize.init(width: Int(newWidth), height: Int(newHeight))
+
+ UIGraphicsBeginImageContextWithOptions(size, false, 1.0)
+ image.draw(in: CGRect(origin: CGPoint.zero, size: size))
+
+ let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
+ UIGraphicsEndImageContext()
+ return scaledImage
+ }
+
func makeExif(_ exif: [AnyHashable:Any]?) -> [AnyHashable:Any]? {
return exif?["{Exif}"] as? [AnyHashable:Any]
}