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

fix UI API called on a background thread & add gif support #298

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
1 change: 0 additions & 1 deletion Classes/IDMPhoto.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#import <Foundation/Foundation.h>
#import "IDMPhotoProtocol.h"
#import <SDWebImage/SDWebImageManager.h>

// This class models a photo/image and it's caption
// If you want to handle photos, caching, decompression
Expand Down
83 changes: 48 additions & 35 deletions Classes/IDMPhoto.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "IDMPhoto.h"
#import "IDMPhotoBrowser.h"
#import <YYWebImageManager.h>

// Private
@interface IDMPhoto () {
Expand All @@ -34,7 +35,7 @@ - (void)imageLoadingComplete;
@implementation IDMPhoto

// Properties
@synthesize underlyingImage = _underlyingImage,
@synthesize underlyingImage = _underlyingImage,
photoURL = _photoURL,
caption = _caption;

Expand All @@ -54,33 +55,33 @@ + (IDMPhoto *)photoWithURL:(NSURL *)url {

+ (NSArray *)photosWithImages:(NSArray *)imagesArray {
NSMutableArray *photos = [NSMutableArray arrayWithCapacity:imagesArray.count];

for (UIImage *image in imagesArray) {
if ([image isKindOfClass:[UIImage class]]) {
IDMPhoto *photo = [IDMPhoto photoWithImage:image];
[photos addObject:photo];
}
}

return photos;
}

+ (NSArray *)photosWithFilePaths:(NSArray *)pathsArray {
NSMutableArray *photos = [NSMutableArray arrayWithCapacity:pathsArray.count];

for (NSString *path in pathsArray) {
if ([path isKindOfClass:[NSString class]]) {
IDMPhoto *photo = [IDMPhoto photoWithFilePath:path];
[photos addObject:photo];
}
}

return photos;
}

+ (NSArray *)photosWithURLs:(NSArray *)urlsArray {
NSMutableArray *photos = [NSMutableArray arrayWithCapacity:urlsArray.count];

for (id url in urlsArray) {
if ([url isKindOfClass:[NSURL class]]) {
IDMPhoto *photo = [IDMPhoto photoWithURL:url];
Expand All @@ -91,7 +92,7 @@ + (NSArray *)photosWithURLs:(NSArray *)urlsArray {
[photos addObject:photo];
}
}

return photos;
}

Expand Down Expand Up @@ -136,20 +137,32 @@ - (void)loadUnderlyingImageAndNotify {
[self performSelectorInBackground:@selector(loadImageFromFileAsync) withObject:nil];
} else if (_photoURL) {
// Load async from web (using SDWebImageManager)

[[SDWebImageManager sharedManager] loadImageWithURL:_photoURL options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
CGFloat progress = ((CGFloat)receivedSize)/((CGFloat)expectedSize);

if (self.progressUpdateBlock) {
self.progressUpdateBlock(progress);
}
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
if (image) {
self.underlyingImage = image;
}

[self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
}];

[[YYWebImageManager sharedManager] requestImageWithURL:_photoURL options:YYWebImageOptionShowNetworkActivity progress:^(NSInteger receivedSize, NSInteger expectedSize) {
if ([NSThread isMainThread]) {
CGFloat progress = ((CGFloat)receivedSize)/((CGFloat)expectedSize);
if (self.progressUpdateBlock) {
self.progressUpdateBlock(progress);
}
} else {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat progress = ((CGFloat)receivedSize)/((CGFloat)expectedSize);
if (weakSelf.progressUpdateBlock) {
weakSelf.progressUpdateBlock(progress);
}
});
}
} transform:^UIImage * _Nullable(UIImage * _Nonnull image, NSURL * _Nonnull url) {
return image;
} completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
if (image) {
self.underlyingImage = image;
}

[self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
}];

} else {
// Failed - no source
self.underlyingImage = nil;
Expand All @@ -174,7 +187,7 @@ - (void)unloadUnderlyingImage {
// System only supports RGB, set explicitly and prevent context error
// if the downloaded image is not the supported format
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL,
CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef),
Expand All @@ -186,16 +199,16 @@ - (void)unloadUnderlyingImage {
// makes system don't need to do extra conversion when displayed.
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
CGColorSpaceRelease(colorSpace);

if ( ! context) {
return nil;
}

CGRect rect = (CGRect){CGPointZero, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)};
CGContextDrawImage(context, rect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);

UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef];
CGImageRelease(decompressedImageRef);
return decompressedImage;
Expand All @@ -206,26 +219,26 @@ - (UIImage *)decodedImageWithImage:(UIImage *)image {
// Do not decode animated images
return image;
}

CGImageRef imageRef = image.CGImage;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize};

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
infoMask == kCGImageAlphaNoneSkipFirst ||
infoMask == kCGImageAlphaNoneSkipLast);

// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1)
{
// Unset the old alpha info.
bitmapInfo &= ~kCGBitmapAlphaInfoMask;

// Set noneSkipFirst.
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
}
Expand All @@ -236,7 +249,7 @@ - (UIImage *)decodedImageWithImage:(UIImage *)image {
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
}

// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
CGContextRef context = CGBitmapContextCreate(NULL,
imageSize.width,
Expand All @@ -246,15 +259,15 @@ - (UIImage *)decodedImageWithImage:(UIImage *)image {
colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);

// If failed, return undecompressed image
if (!context) return image;

CGContextDrawImage(context, imageRect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);

CGContextRelease(context);

UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation];
CGImageRelease(decompressedImageRef);
return decompressedImage;
Expand Down
5 changes: 3 additions & 2 deletions Classes/IDMTapDetectingImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
//

#import <Foundation/Foundation.h>
#import <YYKit/YYAnimatedImageView.h>

@protocol IDMTapDetectingImageViewDelegate;

@interface IDMTapDetectingImageView : UIImageView {
@interface IDMTapDetectingImageView : YYAnimatedImageView {
id <IDMTapDetectingImageViewDelegate> __weak tapDelegate;
}
@property (nonatomic, weak) id <IDMTapDetectingImageViewDelegate> tapDelegate;
Expand All @@ -24,4 +25,4 @@
- (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch;
- (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch;
- (void)imageView:(UIImageView *)imageView tripleTapDetected:(UITouch *)touch;
@end
@end
2 changes: 1 addition & 1 deletion Demo/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ inhibit_all_warnings!

target "PhotoBrowserDemo" do

pod 'SDWebImage'
pod 'YYWebImage'
pod 'DACircularProgress'
pod 'pop'

Expand Down
2 changes: 1 addition & 1 deletion IDMPhotoBrowser.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Pod::Spec.new do |s|
s.resources = 'Classes/IDMPhotoBrowser.bundle', 'Classes/IDMPBLocalizations.bundle'
s.framework = 'MessageUI', 'QuartzCore', 'SystemConfiguration', 'MobileCoreServices', 'Security'
s.requires_arc = true
s.dependency 'SDWebImage'
s.dependency 'YYKit'
s.dependency 'DACircularProgress'
s.dependency 'pop'
end
4 changes: 2 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ We've added both user experience and technical features inspired by Facebook's a

## New features:
- Uses ARC
- Uses SDWebImage for image loading
- Uses YYWebImage for image loading
- Image progress shown
- Minimalistic Facebook-like interface, swipe up/down to dismiss
- Ability to add custom actions on the action sheet
Expand Down Expand Up @@ -181,7 +181,7 @@ Just add `pod 'IDMPhotoBrowser'` to your Podfile.

#### Opensource libraries used

- [SDWebImage](https://github.com/rs/SDWebImage)
- [YYKit](https://github.com/ibireme/YYKit)
- [DACircularProgress](https://github.com/danielamitay/DACircularProgress)
- [pop](https://github.com/facebook/pop)

Expand Down