| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- // Copyright 2019 The Flutter Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #import "FLTImagePickerImageUtil.h"
- #import <MobileCoreServices/MobileCoreServices.h>
- @interface GIFInfo ()
- @property(strong, nonatomic, readwrite) NSArray<UIImage *> *images;
- @property(assign, nonatomic, readwrite) NSTimeInterval interval;
- @end
- @implementation GIFInfo
- - (instancetype)initWithImages:(NSArray<UIImage *> *)images interval:(NSTimeInterval)interval;
- {
- self = [super init];
- if (self) {
- self.images = images;
- self.interval = interval;
- }
- return self;
- }
- @end
- @implementation FLTImagePickerImageUtil : NSObject
- + (UIImage *)scaledImage:(UIImage *)image
- maxWidth:(NSNumber *)maxWidth
- maxHeight:(NSNumber *)maxHeight {
- double originalWidth = image.size.width;
- double originalHeight = image.size.height;
- bool hasMaxWidth = maxWidth != (id)[NSNull null];
- bool hasMaxHeight = maxHeight != (id)[NSNull null];
- double width = hasMaxWidth ? MIN([maxWidth doubleValue], originalWidth) : originalWidth;
- double height = hasMaxHeight ? MIN([maxHeight doubleValue], originalHeight) : originalHeight;
- bool shouldDownscaleWidth = hasMaxWidth && [maxWidth doubleValue] < originalWidth;
- bool shouldDownscaleHeight = hasMaxHeight && [maxHeight doubleValue] < originalHeight;
- bool shouldDownscale = shouldDownscaleWidth || shouldDownscaleHeight;
- if (shouldDownscale) {
- double downscaledWidth = floor((height / originalHeight) * originalWidth);
- double downscaledHeight = floor((width / originalWidth) * originalHeight);
- if (width < height) {
- if (!hasMaxWidth) {
- width = downscaledWidth;
- } else {
- height = downscaledHeight;
- }
- } else if (height < width) {
- if (!hasMaxHeight) {
- height = downscaledHeight;
- } else {
- width = downscaledWidth;
- }
- } else {
- if (originalWidth < originalHeight) {
- width = downscaledWidth;
- } else if (originalHeight < originalWidth) {
- height = downscaledHeight;
- }
- }
- }
- // Scaling the image always rotate itself based on the current imageOrientation of the original
- // Image. Set to orientationUp for the orignal image before scaling, so the scaled image doesn't
- // mess up with the pixels.
- UIImage *imageToScale = [UIImage imageWithCGImage:image.CGImage
- scale:1
- orientation:UIImageOrientationUp];
- // The image orientation is manually set to UIImageOrientationUp which swapped the aspect ratio in
- // some scenarios. For example, when the original image has orientation left, the horizontal
- // pixels should be scaled to `width` and the vertical pixels should be scaled to `height`. After
- // setting the orientation to up, we end up scaling the horizontal pixels to `height` and vertical
- // to `width`. Below swap will solve this issue.
- if ([image imageOrientation] == UIImageOrientationLeft ||
- [image imageOrientation] == UIImageOrientationRight ||
- [image imageOrientation] == UIImageOrientationLeftMirrored ||
- [image imageOrientation] == UIImageOrientationRightMirrored) {
- double temp = width;
- width = height;
- height = temp;
- }
- UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 1.0);
- [imageToScale drawInRect:CGRectMake(0, 0, width, height)];
- UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return scaledImage;
- }
- + (GIFInfo *)scaledGIFImage:(NSData *)data
- maxWidth:(NSNumber *)maxWidth
- maxHeight:(NSNumber *)maxHeight {
- NSMutableDictionary<NSString *, id> *options = [NSMutableDictionary dictionary];
- options[(NSString *)kCGImageSourceShouldCache] = @(YES);
- options[(NSString *)kCGImageSourceTypeIdentifierHint] = (NSString *)kUTTypeGIF;
- CGImageSourceRef imageSource =
- CGImageSourceCreateWithData((CFDataRef)data, (CFDictionaryRef)options);
- size_t numberOfFrames = CGImageSourceGetCount(imageSource);
- NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:numberOfFrames];
- NSTimeInterval interval = 0.0;
- for (size_t index = 0; index < numberOfFrames; index++) {
- CGImageRef imageRef =
- CGImageSourceCreateImageAtIndex(imageSource, index, (CFDictionaryRef)options);
- NSDictionary *properties = (NSDictionary *)CFBridgingRelease(
- CGImageSourceCopyPropertiesAtIndex(imageSource, index, NULL));
- NSDictionary *gifProperties = properties[(NSString *)kCGImagePropertyGIFDictionary];
- NSNumber *delay = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
- if (delay == nil) {
- delay = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
- }
- if (interval == 0.0) {
- interval = [delay doubleValue];
- }
- UIImage *image = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationUp];
- image = [self scaledImage:image maxWidth:maxWidth maxHeight:maxHeight];
- [images addObject:image];
- CGImageRelease(imageRef);
- }
- CFRelease(imageSource);
- GIFInfo *info = [[GIFInfo alloc] initWithImages:images interval:interval];
- return info;
- }
- @end
|