Switching out from unreliable disk caching to TMCache (damn threading issues).

This commit is contained in:
Samuel Clay 2014-02-24 18:56:51 -08:00
parent 2928f63868
commit 96b5e15718
11 changed files with 62 additions and 109 deletions

View file

@ -130,7 +130,7 @@
#pragma mark - Stories #pragma mark - Stories
- (void)refreshStories { - (void)refreshStories {
[[TMCache sharedCache] removeAllObjects:^(TMCache *cache) { [appDelegate.cachedStoryImages removeAllObjects:^(TMCache *cache) {
[appDelegate loadRiverFeedDetailView:self.storiesModule withFolder:@"everything"]; [appDelegate loadRiverFeedDetailView:self.storiesModule withFolder:@"everything"];
}]; }];
} }

View file

@ -142,7 +142,7 @@ static UIFont *indicatorFont = nil;
r.size.height, r.size.height); r.size.height, r.size.height);
UIImageView *storyImageView = [[UIImageView alloc] initWithFrame:imageFrame]; UIImageView *storyImageView = [[UIImageView alloc] initWithFrame:imageFrame];
UIImage *cachedImage = (UIImage *)[[TMCache sharedCache] objectForKey:cell.storyImageUrl]; UIImage *cachedImage = (UIImage *)[appDelegate.cachedStoryImages objectForKey:cell.storyImageUrl];
if (cachedImage && ![cachedImage isKindOfClass:[NSNull class]]) { if (cachedImage && ![cachedImage isKindOfClass:[NSNull class]]) {
// NSLog(@"Found cached image: %@", cell.storyTitle); // NSLog(@"Found cached image: %@", cell.storyTitle);
storyImageView.image = cachedImage; storyImageView.image = cachedImage;

View file

@ -161,7 +161,7 @@
if (storiesCollection.isSocialView) { if (storiesCollection.isSocialView) {
spacerBarButton.width = -6; spacerBarButton.width = -6;
NSString *feedIdStr = [NSString stringWithFormat:@"%@", [storiesCollection.activeFeed objectForKey:@"id"]]; NSString *feedIdStr = [NSString stringWithFormat:@"%@", [storiesCollection.activeFeed objectForKey:@"id"]];
UIImage *titleImage = [Utilities getImage:feedIdStr isSocial:YES]; UIImage *titleImage = [appDelegate getFavicon:feedIdStr isSocial:YES];
titleImage = [Utilities roundCorneredImage:titleImage radius:6]; titleImage = [Utilities roundCorneredImage:titleImage radius:6];
[((UIButton *)titleImageBarButton.customView).imageView removeFromSuperview]; [((UIButton *)titleImageBarButton.customView).imageView removeFromSuperview];
titleImageBarButton = [UIBarButtonItem barItemWithImage:titleImage titleImageBarButton = [UIBarButtonItem barItemWithImage:titleImage
@ -360,15 +360,15 @@
UIImage *image = requestOperation.responseImage; UIImage *image = requestOperation.responseImage;
if (!image || image.size.height < 50 || image.size.width < 50) { if (!image || image.size.height < 50 || image.size.width < 50) {
[[TMCache sharedCache] setObject:[NSNull null] [appDelegate.cachedStoryImages setObject:[NSNull null]
forKey:storyImageUrl]; forKey:storyImageUrl];
continue; continue;
} }
CGSize maxImageSize = CGSizeMake(300, 300); CGSize maxImageSize = CGSizeMake(300, 300);
image = [image imageByScalingAndCroppingForSize:maxImageSize]; image = [image imageByScalingAndCroppingForSize:maxImageSize];
[[TMCache sharedCache] setObject:image [appDelegate.cachedStoryImages setObject:image
forKey:storyImageUrl]; forKey:storyImageUrl];
if (self.isDashboardModule) { if (self.isDashboardModule) {
[appDelegate.dashboardViewController.storiesModule [appDelegate.dashboardViewController.storiesModule
showStoryImage:storyImageUrl]; showStoryImage:storyImageUrl];
@ -1064,7 +1064,7 @@
cell.feedColorBarTopBorder = UIColorFromRGB(colorBorder); cell.feedColorBarTopBorder = UIColorFromRGB(colorBorder);
// favicon // favicon
cell.siteFavicon = [Utilities getImage:feedIdStr]; cell.siteFavicon = [appDelegate getFavicon:feedIdStr];
// undread indicator // undread indicator
@ -1963,10 +1963,9 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
if ((NSNull *)favicon != [NSNull null] && [favicon length] > 0) { if ((NSNull *)favicon != [NSNull null] && [favicon length] > 0) {
NSData *imageData = [NSData dataWithBase64EncodedString:favicon]; NSData *imageData = [NSData dataWithBase64EncodedString:favicon];
UIImage *faviconImage = [UIImage imageWithData:imageData]; UIImage *faviconImage = [UIImage imageWithData:imageData];
[Utilities saveImage:faviconImage feedId:feed_id]; [appDelegate saveFavicon:faviconImage feedId:feed_id];
} }
} }
[Utilities saveimagesToDisk];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.storyTitlesTable reloadData]; [self.storyTitlesTable reloadData];

View file

@ -44,6 +44,7 @@
@class IASKAppSettingsViewController; @class IASKAppSettingsViewController;
@class UnreadCounts; @class UnreadCounts;
@class StoriesCollection; @class StoriesCollection;
@class TMCache;
@interface NewsBlurAppDelegate : BaseViewController @interface NewsBlurAppDelegate : BaseViewController
<UIApplicationDelegate, UIAlertViewDelegate, UINavigationControllerDelegate, OSKActivityCustomizations> { <UIApplicationDelegate, UIAlertViewDelegate, UINavigationControllerDelegate, OSKActivityCustomizations> {
@ -134,6 +135,9 @@
NSDictionary *categoryFeeds; NSDictionary *categoryFeeds;
UIImageView *splashView; UIImageView *splashView;
NSMutableDictionary *activeCachedImages; NSMutableDictionary *activeCachedImages;
TMCache *cachedFavicons;
TMCache *cachedStoryImages;
} }
@property (nonatomic) IBOutlet UIWindow *window; @property (nonatomic) IBOutlet UIWindow *window;
@ -170,6 +174,9 @@
@property (nonatomic) IBOutlet FirstTimeUserAddNewsBlurViewController *firstTimeUserAddNewsBlurViewController; @property (nonatomic) IBOutlet FirstTimeUserAddNewsBlurViewController *firstTimeUserAddNewsBlurViewController;
@property (nonatomic, readwrite) StoriesCollection *storiesCollection; @property (nonatomic, readwrite) StoriesCollection *storiesCollection;
@property (nonatomic, readwrite) TMCache *cachedFavicons;
@property (nonatomic, readwrite) TMCache *cachedStoryImages;
@property (readwrite) NSString * activeUsername; @property (readwrite) NSString * activeUsername;
@property (readwrite) NSString * activeUserProfileId; @property (readwrite) NSString * activeUserProfileId;
@property (readwrite) NSString * activeUserProfileName; @property (readwrite) NSString * activeUserProfileName;
@ -309,6 +316,9 @@
+ (UIView *)makeGradientView:(CGRect)rect startColor:(NSString *)start endColor:(NSString *)end; + (UIView *)makeGradientView:(CGRect)rect startColor:(NSString *)start endColor:(NSString *)end;
- (UIView *)makeFeedTitleGradient:(NSDictionary *)feed withRect:(CGRect)rect; - (UIView *)makeFeedTitleGradient:(NSDictionary *)feed withRect:(CGRect)rect;
- (UIView *)makeFeedTitle:(NSDictionary *)feed; - (UIView *)makeFeedTitle:(NSDictionary *)feed;
- (void)saveFavicon:(UIImage *)image feedId:(NSString *)filename;
- (UIImage *)getFavicon:(NSString *)filename;
- (UIImage *)getFavicon:(NSString *)filename isSocial:(BOOL)isSocial;
- (void)toggleAuthorClassifier:(NSString *)author feedId:(NSString *)feedId; - (void)toggleAuthorClassifier:(NSString *)author feedId:(NSString *)feedId;
- (void)toggleTagClassifier:(NSString *)tag feedId:(NSString *)feedId; - (void)toggleTagClassifier:(NSString *)tag feedId:(NSString *)feedId;

View file

@ -94,6 +94,8 @@
@synthesize firstTimeUserAddNewsBlurViewController; @synthesize firstTimeUserAddNewsBlurViewController;
@synthesize feedDetailPortraitYCoordinate; @synthesize feedDetailPortraitYCoordinate;
@synthesize cachedFavicons;
@synthesize cachedStoryImages;
@synthesize activeUsername; @synthesize activeUsername;
@synthesize activeUserProfileId; @synthesize activeUserProfileId;
@synthesize activeUserProfileName; @synthesize activeUserProfileName;
@ -189,7 +191,7 @@
[self createDatabaseConnection]; [self createDatabaseConnection];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) { (unsigned long)NULL), ^(void) {
[[TMCache sharedCache] removeAllObjects:^(TMCache *cache) {}]; [self.cachedStoryImages removeAllObjects:^(TMCache *cache) {}];
[self.feedsViewController loadOfflineFeeds:NO]; [self.feedsViewController loadOfflineFeeds:NO];
// [self setupReachability]; // [self setupReachability];
cacheImagesOperationQueue = [NSOperationQueue new]; cacheImagesOperationQueue = [NSOperationQueue new];
@ -202,6 +204,9 @@
[[PocketAPI sharedAPI] setConsumerKey:@"16638-05adf4465390446398e53b8b"]; [[PocketAPI sharedAPI] setConsumerKey:@"16638-05adf4465390446398e53b8b"];
// [self showFirstTimeUser]; // [self showFirstTimeUser];
cachedFavicons = [[TMCache alloc] initWithName:@"NBFavicons" rootPath:@"favicons"];
cachedStoryImages = [[TMCache alloc] initWithName:@"NBStoryImages" rootPath:@"story_images"];
return YES; return YES;
} }
@ -264,7 +269,7 @@
[super didReceiveMemoryWarning]; [super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use. // Release any cached data, images, etc that aren't in use.
[[TMCache sharedCache] removeAllObjects]; [cachedStoryImages removeAllObjects];
} }
- (void)setupReachability { - (void)setupReachability {
@ -2041,7 +2046,7 @@
titleLabel.frame = CGRectMake(32, 1, rect.size.width-32, 20); titleLabel.frame = CGRectMake(32, 1, rect.size.width-32, 20);
NSString *feedIdStr = [NSString stringWithFormat:@"%@", [feed objectForKey:@"id"]]; NSString *feedIdStr = [NSString stringWithFormat:@"%@", [feed objectForKey:@"id"]];
UIImage *titleImage = [Utilities getImage:feedIdStr]; UIImage *titleImage = [self getFavicon:feedIdStr];
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage]; UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage];
titleImageView.frame = CGRectMake(8, 3, 16.0, 16.0); titleImageView.frame = CGRectMake(8, 3, 16.0, 16.0);
[titleLabel addSubview:titleImageView]; [titleLabel addSubview:titleImageView];
@ -2110,7 +2115,7 @@
} else if (storiesCollection.isRiverView) { } else if (storiesCollection.isRiverView) {
titleImage = [UIImage imageNamed:@"g_icn_folder.png"]; titleImage = [UIImage imageNamed:@"g_icn_folder.png"];
} else { } else {
titleImage = [Utilities getImage:feedIdStr]; titleImage = [self getFavicon:feedIdStr];
} }
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage]; UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage];
titleImageView.frame = CGRectMake(0.0, 2.0, 16.0, 16.0); titleImageView.frame = CGRectMake(0.0, 2.0, 16.0, 16.0);
@ -2121,6 +2126,32 @@
return titleLabel; return titleLabel;
} }
- (void)saveFavicon:(UIImage *)image feedId:(NSString *)filename {
if (image && filename && ![image isKindOfClass:[NSNull class]] &&
[filename class] != [NSNull class]) {
[self.cachedFavicons setObject:image forKey:filename];
}
}
- (UIImage *)getFavicon:(NSString *)filename {
return [self getFavicon:filename isSocial:NO];
}
- (UIImage *)getFavicon:(NSString *)filename isSocial:(BOOL)isSocial {
UIImage *image = [self.cachedFavicons objectForKey:filename];
if (image) {
return image;
} else {
if (isSocial) {
// return [UIImage imageNamed:@"user_light.png"];
return nil;
} else {
return [UIImage imageNamed:@"world.png"];
}
}
}
#pragma mark - #pragma mark -
#pragma mark Classifiers #pragma mark Classifiers

View file

@ -1011,7 +1011,7 @@ static UIFont *userLabelFont;
[appDelegate.dictSocialFeeds objectForKey:feedIdStr] : [appDelegate.dictSocialFeeds objectForKey:feedIdStr] :
[appDelegate.dictFeeds objectForKey:feedIdStr]; [appDelegate.dictFeeds objectForKey:feedIdStr];
NSDictionary *unreadCounts = [appDelegate.dictUnreadCounts objectForKey:feedIdStr]; NSDictionary *unreadCounts = [appDelegate.dictUnreadCounts objectForKey:feedIdStr];
cell.feedFavicon = [Utilities getImage:feedIdStr isSocial:isSocial]; cell.feedFavicon = [appDelegate getFavicon:feedIdStr isSocial:isSocial];
cell.feedTitle = [feed objectForKey:@"feed_title"]; cell.feedTitle = [feed objectForKey:@"feed_title"];
cell.positiveCount = [[unreadCounts objectForKey:@"ps"] intValue]; cell.positiveCount = [[unreadCounts objectForKey:@"ps"] intValue];
cell.neutralCount = [[unreadCounts objectForKey:@"nt"] intValue]; cell.neutralCount = [[unreadCounts objectForKey:@"nt"] intValue];
@ -1520,11 +1520,9 @@ heightForHeaderInSection:(NSInteger)section {
if (!faviconImage) continue; if (!faviconImage) continue;
faviconImage = [Utilities roundCorneredImage:faviconImage radius:6]; faviconImage = [Utilities roundCorneredImage:faviconImage radius:6];
[Utilities saveImage:faviconImage feedId:feed_id]; [appDelegate saveFavicon:faviconImage feedId:feed_id];
} }
[Utilities saveimagesToDisk];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.feedTitlesTable reloadData]; [self.feedTitlesTable reloadData];
}); });
@ -1553,10 +1551,9 @@ heightForHeaderInSection:(NSInteger)section {
if ((NSNull *)favicon != [NSNull null] && [favicon length] > 0) { if ((NSNull *)favicon != [NSNull null] && [favicon length] > 0) {
NSData *imageData = [NSData dataWithBase64EncodedString:favicon]; NSData *imageData = [NSData dataWithBase64EncodedString:favicon];
UIImage *faviconImage = [UIImage imageWithData:imageData]; UIImage *faviconImage = [UIImage imageWithData:imageData];
[Utilities saveImage:faviconImage feedId:feed_id]; [appDelegate saveFavicon:faviconImage feedId:feed_id];
} }
} }
[Utilities saveimagesToDisk];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.feedTitlesTable reloadData]; [self.feedTitlesTable reloadData];

View file

@ -113,7 +113,7 @@
NSString *feedIdStr = [NSString stringWithFormat:@"%@", NSString *feedIdStr = [NSString stringWithFormat:@"%@",
[appDelegate.activeStory objectForKey:@"story_feed_id"]]; [appDelegate.activeStory objectForKey:@"story_feed_id"]];
UIImage *titleImage = [Utilities getImage:feedIdStr]; UIImage *titleImage = [appDelegate getFavicon:feedIdStr];
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage]; UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage];
titleImageView.frame = CGRectMake(0.0, 2.0, 16.0, 16.0); titleImageView.frame = CGRectMake(0.0, 2.0, 16.0, 16.0);
titleImageView.hidden = YES; titleImageView.hidden = YES;

View file

@ -212,7 +212,7 @@
} else { } else {
NSString *feedIdStr = [NSString stringWithFormat:@"%@", NSString *feedIdStr = [NSString stringWithFormat:@"%@",
[appDelegate.activeStory objectForKey:@"story_feed_id"]]; [appDelegate.activeStory objectForKey:@"story_feed_id"]];
titleImage = [Utilities getImage:feedIdStr]; titleImage = [appDelegate getFavicon:feedIdStr];
} }
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage]; UIImageView *titleImageView = [[UIImageView alloc] initWithImage:titleImage];
@ -230,7 +230,7 @@
} else { } else {
NSString *feedIdStr = [NSString stringWithFormat:@"%@", NSString *feedIdStr = [NSString stringWithFormat:@"%@",
[appDelegate.storiesCollection.activeFeed objectForKey:@"id"]]; [appDelegate.storiesCollection.activeFeed objectForKey:@"id"]];
UIImage *titleImage = [Utilities getImage:feedIdStr]; UIImage *titleImage = [appDelegate getFavicon:feedIdStr];
titleImage = [Utilities roundCorneredImage:titleImage radius:6]; titleImage = [Utilities roundCorneredImage:titleImage radius:6];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];

View file

@ -366,7 +366,7 @@
int publisherScore = [[[[appDelegate.storiesCollection.activeClassifiers objectForKey:feedId] int publisherScore = [[[[appDelegate.storiesCollection.activeClassifiers objectForKey:feedId]
objectForKey:@"feeds"] objectForKey:feedId] intValue]; objectForKey:@"feeds"] objectForKey:feedId] intValue];
UIImage *favicon = [Utilities getImage:feedId]; UIImage *favicon = [appDelegate getFavicon:feedId];
NSData *faviconData = UIImagePNGRepresentation(favicon); NSData *faviconData = UIImagePNGRepresentation(favicon);
NSString *feedImageUrl = [NSString stringWithFormat:@"data:image/png;charset=utf-8;base64,%@", NSString *feedImageUrl = [NSString stringWithFormat:@"data:image/png;charset=utf-8;base64,%@",
[faviconData base64Encoding]]; [faviconData base64Encoding]];

View file

@ -15,11 +15,7 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
NSCache *imageCache; NSCache *imageCache;
} }
+ (void)saveImage:(UIImage *)image feedId:(NSString *)filename;
+ (UIImage *)getImage:(NSString *)filename;
+ (UIImage *)getImage:(NSString *)filename isSocial:(BOOL)isSocial;
+ (void)drawLinearGradientWithRect:(CGRect)rect startColor:(CGColorRef)startColor endColor:(CGColorRef)endColor; + (void)drawLinearGradientWithRect:(CGRect)rect startColor:(CGColorRef)startColor endColor:(CGColorRef)endColor;
+ (void)saveimagesToDisk;
+ (UIImage *)roundCorneredImage:(UIImage *)orig radius:(CGFloat)r; + (UIImage *)roundCorneredImage:(UIImage *)orig radius:(CGFloat)r;
+ (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size; + (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size;
+ (NSString *)md5:(NSString *)string; + (NSString *)md5:(NSString *)string;

View file

@ -8,6 +8,7 @@
#import "Utilities.h" #import "Utilities.h"
#import <CommonCrypto/CommonCrypto.h> #import <CommonCrypto/CommonCrypto.h>
#import "TMCache.h"
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor,
CGColorRef endColor) { CGColorRef endColor) {
@ -34,59 +35,6 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
@implementation Utilities @implementation Utilities
static NSMutableDictionary *imageCache;
+ (void)saveImage:(UIImage *)image feedId:(NSString *)filename {
if (!imageCache) {
imageCache = [NSMutableDictionary dictionary];
}
// Save image to memory-based cache, for performance when reading.
// NSLog(@"Saving %@", [imageCache allKeys]);
if (image && filename && ![image isKindOfClass:[NSNull class]] &&
[filename class] != [NSNull class]) {
[imageCache setObject:image forKey:filename];
} else {
// NSLog(@"%@ has no image!!!", filename);
}
}
+ (UIImage *)getImage:(NSString *)filename {
return [self getImage:filename isSocial:NO];
}
+ (UIImage *)getImage:(NSString *)filename isSocial:(BOOL)isSocial {
UIImage *image;
if (filename && [imageCache objectForKey:filename]) {
image = [imageCache objectForKey:filename];
}
if (!image || [image class] == [NSNull class]) {
// Image not in cache, search on disk.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
if (isSocial) {
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:@"avatars"];
} else {
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:@"favicons"];
}
NSString *path = [cacheDirectory stringByAppendingPathComponent:filename];
image = [UIImage imageWithContentsOfFile:path];
}
if (image) {
return image;
} else {
if (isSocial) {
// return [UIImage imageNamed:@"user_light.png"];
return nil;
} else {
return [UIImage imageNamed:@"world.png"];
}
}
}
+ (void)drawLinearGradientWithRect:(CGRect)rect startColor:(CGColorRef)startColor endColor:(CGColorRef)endColor { + (void)drawLinearGradientWithRect:(CGRect)rect startColor:(CGColorRef)startColor endColor:(CGColorRef)endColor {
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
@ -111,34 +59,6 @@ static NSMutableDictionary *imageCache;
CGColorSpaceRelease(colorSpace); CGColorSpaceRelease(colorSpace);
} }
+ (void)saveimagesToDisk {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);
dispatch_async(queue, ^{
for (NSString *filename in [imageCache allKeys]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
if ([filename hasPrefix:@"social"]) {
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:@"avatars"];
} else {
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:@"favicons"];
}
NSString *path = [cacheDirectory stringByAppendingPathComponent:filename];
// Save image to disk
UIImage *image;
@try {
image = [imageCache objectForKey:filename];
}
@catch (NSException *exception) {
NSLog(@"Warning: imageCache EXC_BAD_ACCESS!!! %@", imageCache);
return;
}
[UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
}
});
}
+ (UIImage *)roundCorneredImage: (UIImage*) orig radius:(CGFloat) r { + (UIImage *)roundCorneredImage: (UIImage*) orig radius:(CGFloat) r {
if (!orig) return nil; if (!orig) return nil;
UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0); UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0);