Merge branch 'charlesmchen/saeLiveImageCrash'

pull/1/head
Matthew Chen 7 years ago
commit b9c852378a

@ -136,6 +136,9 @@
/* Attachment error message for image attachments in which metadata could not be removed */ /* Attachment error message for image attachments in which metadata could not be removed */
"ATTACHMENT_ERROR_COULD_NOT_REMOVE_METADATA" = "Unable to remove metadata from image."; "ATTACHMENT_ERROR_COULD_NOT_REMOVE_METADATA" = "Unable to remove metadata from image.";
/* Attachment error message for image attachments which could not be resized */
"ATTACHMENT_ERROR_COULD_NOT_RESIZE_IMAGE" = "Could not resize image.";
/* Attachment error message for attachments whose data exceed file size limits */ /* Attachment error message for attachments whose data exceed file size limits */
"ATTACHMENT_ERROR_FILE_SIZE_TOO_LARGE" = "Attachment is too large."; "ATTACHMENT_ERROR_FILE_SIZE_TOO_LARGE" = "Attachment is too large.";

@ -17,6 +17,7 @@ enum SignalAttachmentError: Error {
case couldNotConvertToMpeg4 case couldNotConvertToMpeg4
case couldNotRemoveMetadata case couldNotRemoveMetadata
case invalidFileFormat case invalidFileFormat
case couldNotResizeImage
} }
extension String { extension String {
@ -56,6 +57,8 @@ extension SignalAttachmentError: LocalizedError {
return NSLocalizedString("ATTACHMENT_ERROR_COULD_NOT_CONVERT_TO_MP4", comment: "Attachment error message for video attachments which could not be converted to MP4") return NSLocalizedString("ATTACHMENT_ERROR_COULD_NOT_CONVERT_TO_MP4", comment: "Attachment error message for video attachments which could not be converted to MP4")
case .couldNotRemoveMetadata: case .couldNotRemoveMetadata:
return NSLocalizedString("ATTACHMENT_ERROR_COULD_NOT_REMOVE_METADATA", comment: "Attachment error message for image attachments in which metadata could not be removed") return NSLocalizedString("ATTACHMENT_ERROR_COULD_NOT_REMOVE_METADATA", comment: "Attachment error message for image attachments in which metadata could not be removed")
case .couldNotResizeImage:
return NSLocalizedString("ATTACHMENT_ERROR_COULD_NOT_RESIZE_IMAGE", comment: "Attachment error message for image attachments which could not be resized")
} }
} }
} }
@ -700,7 +703,11 @@ public class SignalAttachment: NSObject {
var dstImage: UIImage! = image var dstImage: UIImage! = image
if image.size.width > maxSize || if image.size.width > maxSize ||
image.size.height > maxSize { image.size.height > maxSize {
dstImage = imageScaled(image, toMaxSize: maxSize) guard let resizedImage = imageScaled(image, toMaxSize: maxSize) else {
attachment.error = .couldNotResizeImage
return attachment
}
dstImage = resizedImage
} }
guard let jpgImageData = UIImageJPEGRepresentation(dstImage, guard let jpgImageData = UIImageJPEGRepresentation(dstImage,
jpegCompressionQuality(imageUploadQuality: imageUploadQuality)) else { jpegCompressionQuality(imageUploadQuality: imageUploadQuality)) else {
@ -746,20 +753,56 @@ public class SignalAttachment: NSObject {
} }
} }
private class func imageScaled(_ image: UIImage, toMaxSize size: CGFloat) -> UIImage { // NOTE: For unknown reasons, resizing images with UIGraphicsBeginImageContext()
var scaleFactor: CGFloat // crashes reliably in the share extension after screen lock's auth UI has been presented.
let aspectRatio: CGFloat = image.size.height / image.size.width // Resizing using a CGContext seems to work fine.
if aspectRatio > 1 { private class func imageScaled(_ uiImage: UIImage, toMaxSize maxSize: CGFloat) -> UIImage? {
scaleFactor = size / image.size.width guard let cgImage = uiImage.cgImage else {
} else { owsFail("\(logTag) UIImage missing cgImage.")
scaleFactor = size / image.size.height return nil
} }
let newSize = CGSize(width: CGFloat(image.size.width * scaleFactor), height: CGFloat(image.size.height * scaleFactor))
UIGraphicsBeginImageContext(newSize) // It's essential that we work consistently in "CG" coordinates (which are
image.draw(in: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(newSize.width), height: CGFloat(newSize.height))) // pixels and don't reflect orientation), not "UI" coordinates (which
let updatedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext() // are points and do reflect orientation).
UIGraphicsEndImageContext() let scrSize = CGSize(width: cgImage.width, height: cgImage.height)
return updatedImage! var maxSizeRect = CGRect.zero
maxSizeRect.size = CGSize(width: maxSize, height: maxSize)
let newSize = AVMakeRect(aspectRatio: scrSize, insideRect: maxSizeRect).size
assert(newSize.width <= maxSize)
assert(newSize.height <= maxSize)
let bitsPerComponent = cgImage.bitsPerComponent
let bytesPerRow = cgImage.bytesPerRow
guard let colorSpace = cgImage.colorSpace else {
owsFail("\(logTag) cgImage missing colorSpace.")
return nil
}
let bitmapInfo = cgImage.bitmapInfo
guard let context = CGContext.init(data: nil,
width: Int(newSize.width),
height: Int(newSize.height),
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue) else {
owsFail("\(logTag) could not create CGContext.")
return nil
}
context.interpolationQuality = .high
var drawRect = CGRect.zero
drawRect.size = newSize
context.draw(cgImage, in: drawRect)
guard let newCGImage = context.makeImage() else {
owsFail("\(logTag) could not create new CGImage.")
return nil
}
return UIImage(cgImage: newCGImage,
scale: uiImage.scale,
orientation: uiImage.imageOrientation)
} }
private class func doesImageHaveAcceptableFileSize(dataSource: DataSource, imageQuality: TSImageQuality) -> Bool { private class func doesImageHaveAcceptableFileSize(dataSource: DataSource, imageQuality: TSImageQuality) -> Bool {

Loading…
Cancel
Save