Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add preserveAspectRatio to CameraOptions while resizing an image #3309

Merged
merged 13 commits into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
iphilgood marked this conversation as resolved.
Show resolved Hide resolved
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.
Expand All @@ -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);
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions core/src/core-plugin-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions example/src/pages/camera/camera.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@
<button (click)="takePictureFile()" ion-button color="primary">File URI</button>
<button (click)="testImageSize()" ion-button color="primary">Image Size Test (#307)</button>
<button (click)="testAndroidBreak()" ion-button color="primary">Photos Orientation Test (#319)</button>
<button (click)="takePicturePreservingAspectRatio()" ion-button color="primary">Preserving Aspect Ratio</button>
</ion-content>
15 changes: 15 additions & 0 deletions example/src/pages/camera/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
40 changes: 37 additions & 3 deletions ios/Capacitor/Capacitor/Plugins/Camera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct CameraSettings {
var height: Float = 0
var resultType = "base64"
var saveToGallery = false
var preserveAspectRatio = false
}

@objc(CAPCameraPlugin)
Expand Down Expand Up @@ -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)!)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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);

Expand All @@ -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]
}
Expand Down