diff --git a/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.pbxproj b/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.pbxproj
index 44f4caf..b355c94 100644
--- a/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.pbxproj	
+++ b/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.pbxproj	
@@ -32,6 +32,7 @@
 		7FA8566719B2762F00913254 /* banecat-red.png in Resources */ = {isa = PBXBuildFile; fileRef = 7FA8566619B2762F00913254 /* banecat-red.png */; };
 		7FE0848218E7C5C600F2F6B4 /* banecat.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7FE0848118E7C5C600F2F6B4 /* banecat.jpg */; };
 		7FE95B4E18EE0E8100F18370 /* UIApplication+JTSImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FE95B4D18EE0E8100F18370 /* UIApplication+JTSImageViewController.m */; };
+		C30DCC58191007E900B8445C /* jimpam.gif in Resources */ = {isa = PBXBuildFile; fileRef = C30DCC57191007E900B8445C /* jimpam.gif */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -81,6 +82,7 @@
 		7FE0848118E7C5C600F2F6B4 /* banecat.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = banecat.jpg; sourceTree = "<group>"; };
 		7FE95B4C18EE0E8100F18370 /* UIApplication+JTSImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIApplication+JTSImageViewController.h"; path = "../../../Source/UIApplication+JTSImageViewController.h"; sourceTree = "<group>"; };
 		7FE95B4D18EE0E8100F18370 /* UIApplication+JTSImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIApplication+JTSImageViewController.m"; path = "../../../Source/UIApplication+JTSImageViewController.m"; sourceTree = "<group>"; };
+		C30DCC57191007E900B8445C /* jimpam.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = jimpam.gif; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -141,6 +143,7 @@
 		7F9A790418E754A7000CAA69 /* Sample App */ = {
 			isa = PBXGroup;
 			children = (
+				C30DCC57191007E900B8445C /* jimpam.gif */,
 				7FE0848118E7C5C600F2F6B4 /* banecat.jpg */,
 				7FA8566619B2762F00913254 /* banecat-red.png */,
 				47A333FD19D8F34A00F60031 /* Default-1334.png */,
@@ -285,6 +288,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				C30DCC58191007E900B8445C /* jimpam.gif in Resources */,
 				472FDE9A19DA4B68000C0864 /* Default-1136.png in Resources */,
 				7FE0848218E7C5C600F2F6B4 /* banecat.jpg in Resources */,
 				7FA8566719B2762F00913254 /* banecat-red.png in Resources */,
diff --git a/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.xcworkspace/xcshareddata/JTSImageVC.xccheckout b/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.xcworkspace/xcshareddata/JTSImageVC.xccheckout
new file mode 100644
index 0000000..0546713
--- /dev/null
+++ b/Sample App/JTSImageVC/JTSImageVC.xcodeproj/project.xcworkspace/xcshareddata/JTSImageVC.xccheckout	
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDESourceControlProjectFavoriteDictionaryKey</key>
+	<false/>
+	<key>IDESourceControlProjectIdentifier</key>
+	<string>A53BEEAD-1C96-4AD9-B9A4-DD2DC3EE505A</string>
+	<key>IDESourceControlProjectName</key>
+	<string>JTSImageVC</string>
+	<key>IDESourceControlProjectOriginsDictionary</key>
+	<dict>
+		<key>80DA628EAE81E418FCA5040B6FD2F14B521C07CB</key>
+		<string>https://github.com/geoffmacd/JTSImageViewController.git</string>
+	</dict>
+	<key>IDESourceControlProjectPath</key>
+	<string>Sample App/JTSImageVC/JTSImageVC.xcodeproj</string>
+	<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
+	<dict>
+		<key>80DA628EAE81E418FCA5040B6FD2F14B521C07CB</key>
+		<string>../../../..</string>
+	</dict>
+	<key>IDESourceControlProjectURL</key>
+	<string>https://github.com/geoffmacd/JTSImageViewController.git</string>
+	<key>IDESourceControlProjectVersion</key>
+	<integer>111</integer>
+	<key>IDESourceControlProjectWCCIdentifier</key>
+	<string>80DA628EAE81E418FCA5040B6FD2F14B521C07CB</string>
+	<key>IDESourceControlProjectWCConfigurations</key>
+	<array>
+		<dict>
+			<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
+			<string>public.vcs.git</string>
+			<key>IDESourceControlWCCIdentifierKey</key>
+			<string>80DA628EAE81E418FCA5040B6FD2F14B521C07CB</string>
+			<key>IDESourceControlWCCName</key>
+			<string>JTSImageViewController</string>
+		</dict>
+	</array>
+</dict>
+</plist>
diff --git a/Sample App/JTSImageVC/JTSImageVC/Base.lproj/Main.storyboard b/Sample App/JTSImageVC/JTSImageVC/Base.lproj/Main.storyboard
index f077467..35602e0 100644
--- a/Sample App/JTSImageVC/JTSImageVC/Base.lproj/Main.storyboard	
+++ b/Sample App/JTSImageVC/JTSImageVC/Base.lproj/Main.storyboard	
@@ -13,37 +13,65 @@
                         <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                         <subviews>
-                            <view contentMode="scaleToFill" id="Sny-zi-TpS">
-                                <rect key="frame" x="0.0" y="55" width="320" height="320"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
-                                <subviews>
-                                    <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleAspectFill" image="banecat.jpg" id="kZW-w6-fbC">
-                                        <rect key="frame" x="80" y="50" width="160" height="160"/>
-                                        <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
-                                    </imageView>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Banecat McGiggins" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZA6-8J-aXt">
-                                        <rect key="frame" x="46" y="220" width="227" height="21"/>
-                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="“Your precious armory: gratefully accepted!”" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="5ta-S6-J2I">
-                                        <rect key="frame" x="-10" y="245" width="339" height="21"/>
-                                        <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                        <color key="textColor" red="0.70196080207824707" green="0.70196080207824707" blue="0.70196080207824707" alpha="1" colorSpace="calibratedRGB"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                </subviews>
-                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
-                            </view>
+                            <button opaque="NO" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cYp-7P-jxw">
+                                <rect key="frame" x="55" y="49" width="202" height="124"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" backgroundImage="banecat.jpg">
+                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="bigButtonTapped:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="BnG-my-GyB"/>
+                                </connections>
+                            </button>
+                            <button opaque="NO" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gHz-XS-42X">
+                                <rect key="frame" x="21" y="400" width="274" height="140"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" backgroundImage="jimpam.gif">
+                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="customBigButtonTapped:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="vEJ-8w-L11"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Simple Image Setting" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="95U-5E-Hib">
+                                <rect key="frame" x="19" y="20" width="282" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Custom Image Downloader: SDWebImage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BMu-Rl-QK2">
+                                <rect key="frame" x="22" y="371" width="324" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5ar-Ga-hfP">
+                                <rect key="frame" x="19" y="212" width="274" height="143"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" backgroundImage="jimpam.gif">
+                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="simpleButtonTapped:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="Ffb-mO-gZj"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Simple Download: JTSSimpleImageDownloader" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m0r-QP-xHt">
+                                <rect key="frame" x="19" y="183" width="340" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
                         </subviews>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                     </view>
                     <simulatedOrientationMetrics key="simulatedOrientationMetrics"/>
                     <connections>
-                        <outlet property="bigImageButton" destination="kZW-w6-fbC" id="g54-HZ-B12"/>
+                        <outlet property="bigImageButton" destination="cYp-7P-jxw" id="zdR-f9-LfN"/>
+                        <outlet property="customBigImageButton" destination="gHz-XS-42X" id="1is-NV-CME"/>
+                        <outlet property="simpleImageButton" destination="5ar-Ga-hfP" id="mjF-ia-URQ"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
@@ -52,6 +80,7 @@
     </scenes>
     <resources>
         <image name="banecat.jpg" width="2197" height="1450"/>
+        <image name="jimpam.gif" width="500" height="290"/>
     </resources>
     <simulatedMetricsContainer key="defaultSimulatedMetrics">
         <simulatedStatusBarMetrics key="statusBar"/>
diff --git a/Sample App/JTSImageVC/JTSImageVC/JTSViewController.h b/Sample App/JTSImageVC/JTSImageVC/JTSViewController.h
index 8488746..13df2a9 100644
--- a/Sample App/JTSImageVC/JTSImageVC/JTSViewController.h	
+++ b/Sample App/JTSImageVC/JTSImageVC/JTSViewController.h	
@@ -8,8 +8,10 @@
 
 #import <UIKit/UIKit.h>
 
-@interface JTSViewController : UIViewController
+@interface JTSViewController : UIViewController <NSURLSessionDelegate,NSURLSessionDownloadDelegate>
 
-@property (weak, nonatomic) IBOutlet UIImageView *bigImageButton;
+@property (weak, nonatomic) IBOutlet UIButton *bigImageButton;
+@property (weak, nonatomic) IBOutlet UIButton *simpleImageButton;
+@property (weak, nonatomic) IBOutlet UIButton *customBigImageButton;
 
 @end
diff --git a/Sample App/JTSImageVC/JTSImageVC/JTSViewController.m b/Sample App/JTSImageVC/JTSImageVC/JTSViewController.m
index 7af0307..1cbc32d 100644
--- a/Sample App/JTSImageVC/JTSImageVC/JTSViewController.m	
+++ b/Sample App/JTSImageVC/JTSImageVC/JTSViewController.m	
@@ -10,31 +10,35 @@
 
 #import "JTSImageViewController.h"
 #import "JTSImageInfo.h"
+#import "JTSAnimatedGIFUtility.h"
 
 @interface JTSViewController ()
 
+@property NSProgress *customProgress;
+@property JTSImageViewController * imageViewerForCustomLoading;
+
 @end
 
+
 @implementation JTSViewController
 
 - (void)viewDidLoad {
     [super viewDidLoad];
-    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] init];
-    [tapRecognizer addTarget:self action:@selector(bigButtonTapped:)];
-    [self.bigImageButton addGestureRecognizer:tapRecognizer];
+    
     [self.bigImageButton setAccessibilityLabel:@"Photo of a cat wearing a Bane costume."];
-    self.bigImageButton.layer.cornerRadius = self.bigImageButton.bounds.size.width/2.0f;
+    [self.simpleImageButton setAccessibilityLabel:@"Photo of jim and pam in love"];
+    [self.customBigImageButton setAccessibilityLabel:@"Photo of jim and pam in love"];
 }
 
 - (NSUInteger)supportedInterfaceOrientations {
     return UIInterfaceOrientationMaskPortrait;
 }
 
-- (void)bigButtonTapped:(id)sender {
+- (IBAction)bigButtonTapped:(id)sender {
     
     // Create image info
     JTSImageInfo *imageInfo = [[JTSImageInfo alloc] init];
-    imageInfo.image = self.bigImageButton.image;
+    imageInfo.image = [self.bigImageButton backgroundImageForState:UIControlStateNormal];
     imageInfo.referenceRect = self.bigImageButton.frame;
     imageInfo.referenceView = self.bigImageButton.superview;
     imageInfo.referenceContentMode = self.bigImageButton.contentMode;
@@ -46,10 +50,81 @@ - (void)bigButtonTapped:(id)sender {
                                            mode:JTSImageViewControllerMode_Image
                                            backgroundStyle:JTSImageViewControllerBackgroundOption_Scaled];
     
+    
+    // Present the view controller.
+    [imageViewer showFromViewController:self transition:JTSImageViewControllerTransition_FromOriginalPosition];
+}
+
+- (IBAction)simpleButtonTapped:(id)sender {
+    // Create image info
+    JTSImageInfo *imageInfo = [[JTSImageInfo alloc] init];
+    imageInfo.imageURL = [NSURL URLWithString:@"http://i.imgur.com/iGRxQNb.gif"];
+    imageInfo.referenceRect = self.simpleImageButton.frame;
+    imageInfo.referenceView = self.simpleImageButton.superview;
+    
+    // Setup view controller
+    JTSImageViewController *imageViewer = [[JTSImageViewController alloc]
+                                           initWithImageInfo:imageInfo
+                                           mode:JTSImageViewControllerMode_Image
+                                           backgroundStyle:JTSImageViewControllerBackgroundOption_Blurred];
+    
+    
     // Present the view controller.
     [imageViewer showFromViewController:self transition:JTSImageViewControllerTransition_FromOriginalPosition];
 }
 
+- (IBAction)customBigButtonTapped:(id)sender {
+    //download image with custom progress from SDWebImage
+    
+    // Create image info
+    JTSImageInfo *imageInfo = [[JTSImageInfo alloc] init];
+    imageInfo.referenceRect = self.customBigImageButton.frame;
+    imageInfo.referenceView = self.customBigImageButton.superview;
+    imageInfo.referenceContentMode = self.bigImageButton.contentMode;
+    imageInfo.referenceCornerRadius = self.bigImageButton.layer.cornerRadius;
+    
+    NSProgress * customProgress = [NSProgress progressWithTotalUnitCount:0];
+    customProgress.kind = NSProgressKindFile;
+    self.customProgress = customProgress;
+    
+    //with custom progress
+    JTSImageViewController *imageViewer = [[JTSImageViewController alloc]
+                                           initWithImageInfo:imageInfo
+                                           mode:JTSImageViewControllerMode_Image
+                                           backgroundStyle:JTSImageViewControllerBackgroundOption_Blurred
+                                           customImageLoadingProgress:self.customProgress];
+    NSURLSessionConfiguration * sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
+    [sessionConfig setRequestCachePolicy:NSURLRequestReloadIgnoringCacheData];//no cache to allow repeatable testing
+    NSURLSession * session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];    //main thread response for delegates
+    NSURLSessionDownloadTask * task = [session downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://i.imgur.com/iGRxQNb.gif"]]];
+    
+    self.imageViewerForCustomLoading = imageViewer;
+    
+    [task resume];
+    // Present the view controller.
+    [imageViewer showFromViewController:self transition:JTSImageViewControllerTransition_FromOriginalPosition];
+    
+}
+#pragma mark - url session download delegate
+-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
+    
+    _customProgress.totalUnitCount = expectedTotalBytes;
+    _customProgress.completedUnitCount = 0;
+
+}
+
+-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
+    
+    _customProgress.totalUnitCount = totalBytesExpectedToWrite;
+    _customProgress.completedUnitCount = totalBytesWritten;
+}
+
+-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
+    
+    UIImage * image = [JTSAnimatedGIFUtility animatedImageWithAnimatedGIFURL:location];
+    [self.imageViewerForCustomLoading customImageLoadingDidFinish:image];
+}
+
 @end
 
 
diff --git a/Sample App/JTSImageVC/JTSImageVC/jimpam.gif b/Sample App/JTSImageVC/JTSImageVC/jimpam.gif
new file mode 100644
index 0000000..f180a6e
Binary files /dev/null and b/Sample App/JTSImageVC/JTSImageVC/jimpam.gif differ
diff --git a/Source/JTSImageViewController.h b/Source/JTSImageViewController.h
index 40a2340..de46bf8 100644
--- a/Source/JTSImageViewController.h
+++ b/Source/JTSImageViewController.h
@@ -70,13 +70,36 @@ extern CGFloat const JTSImageViewController_DefaultBackgroundBlurRadius;
  
  @param mode The mode to be used. (JTSImageViewController has an alternate alt text mode). Required.
  
- @param backgroundStyle Currently, either scaled-and-dimmed, or scaled-dimmed-and-blurred. 
+ @param backgroundStyle Currently, either scaled-and-dimmed, or scaled-dimmed-and-blurred.
  The latter is like Tweetbot 3.0's background style.
  */
 - (instancetype)initWithImageInfo:(JTSImageInfo *)imageInfo
                              mode:(JTSImageViewControllerMode)mode
                   backgroundStyle:(JTSImageViewControllerBackgroundOptions)backgroundOptions;
 
+/**
+ Initializer for using JTSImageViewController with a custom image downloader for the purpose of easily allowing cooperation with 3rd party libraries for downloading or caching images such as SDWebImage. Caller is responsible for setting the image view via customImageLoadingDidFinish: when image download is finished.
+ 
+ @param imageInfo The source info for image and transition metadata. Required.
+ 
+ @param mode The mode to be used. (JTSImageViewController has an alternate alt text mode). Required.
+ 
+ @param backgroundStyle Currently, either scaled-and-dimmed, or scaled-dimmed-and-blurred. The latter is like Tweetbot 3.0's background style.
+ 
+ @param customImageProgress Progress object to be updated by the caller with completed and totalUnitCount to inform of download progress.
+ */
+- (instancetype)initWithImageInfo:(JTSImageInfo *)imageInfo
+                             mode:(JTSImageViewControllerMode)mode
+                  backgroundStyle:(JTSImageViewControllerBackgroundOptions)backgroundStyle
+       customImageLoadingProgress:(NSProgress*)customImageProgress;
+
+
+/**
+ Image setter intended for use only when using custom image downloader to provide the UIImage to be used upon download/retrieval completion.
+ 
+ @param image Image to be displayed
+ */
+-(void)customImageLoadingDidFinish:(UIImage*)image;
 /**
  JTSImageViewController is presented from viewController as a UIKit modal view controller.
  
@@ -120,7 +143,7 @@ extern CGFloat const JTSImageViewController_DefaultBackgroundBlurRadius;
  and dismissal animations.
  
  This may be helpful if the reference image in your presenting view controller has been
- dimmed, such as for a dark mode. JTSImageViewController otherwise presents the animated 
+ dimmed, such as for a dark mode. JTSImageViewController otherwise presents the animated
  image view at full opacity, which can look jarring.
  */
 - (BOOL)imageViewerShouldFadeThumbnailsDuringPresentationAndDismissal:(JTSImageViewController *)imageViewer;
@@ -141,9 +164,9 @@ extern CGFloat const JTSImageViewController_DefaultBackgroundBlurRadius;
 
 /**
  The background color of the image view itself, not to be confused with the background
- color for the view controller's view. 
+ color for the view controller's view.
  
- You may wish to override this method if displaying an image with dark content on an 
+ You may wish to override this method if displaying an image with dark content on an
  otherwise clear background color (such as images from the XKCD What If? site).
  
  The default color is `[UIColor clearColor]`.
@@ -182,7 +205,7 @@ extern CGFloat const JTSImageViewController_DefaultBackgroundBlurRadius;
 /**
  Called when the image viewer is deciding whether to respond to user interactions.
  
- You may need to return NO if you are presenting custom, temporary UI on top of the image viewer. 
+ You may need to return NO if you are presenting custom, temporary UI on top of the image viewer.
  This method is called more than once. Returning NO does not "lock" the image viewer.
  */
 - (BOOL)imageViewerShouldTemporarilyIgnoreTouches:(JTSImageViewController *)imageViewer;
@@ -235,4 +258,3 @@ extern CGFloat const JTSImageViewController_DefaultBackgroundBlurRadius;
 
 
 
-
diff --git a/Source/JTSImageViewController.m b/Source/JTSImageViewController.m
index d1e1dbb..fb9ce7e 100644
--- a/Source/JTSImageViewController.m
+++ b/Source/JTSImageViewController.m
@@ -61,10 +61,10 @@
 
 @interface JTSImageViewController ()
 <
-    UIScrollViewDelegate,
-    UITextViewDelegate,
-    UIViewControllerTransitioningDelegate,
-    UIGestureRecognizerDelegate
+UIScrollViewDelegate,
+UITextViewDelegate,
+UIViewControllerTransitioningDelegate,
+UIGestureRecognizerDelegate
 >
 
 // General Info
@@ -109,6 +109,8 @@ @interface JTSImageViewController ()
 // Image Downloading
 @property (strong, nonatomic) NSURLSessionDataTask *imageDownloadDataTask;
 @property (strong, nonatomic) NSTimer *downloadProgressTimer;
+@property (assign, nonatomic) BOOL imageDownloadUsingCustom;
+@property (strong, nonatomic) NSProgress * customImageProgress;
 
 @end
 
@@ -138,6 +140,47 @@ - (instancetype)initWithImageInfo:(JTSImageInfo *)imageInfo
     return self;
 }
 
+- (instancetype)initWithImageInfo:(JTSImageInfo *)imageInfo
+                             mode:(JTSImageViewControllerMode)mode
+                  backgroundStyle:(JTSImageViewControllerBackgroundOptions)backgroundStyle
+       customImageLoadingProgress:(NSProgress*)customImageProgress{
+    
+    self = [super initWithNibName:nil bundle:nil];
+    if (self) {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
+        _imageInfo = imageInfo;
+        _currentSnapshotRotationTransform = CGAffineTransformIdentity;
+        _mode = mode;
+        _backgroundOptions = backgroundStyle;
+        if (_mode == JTSImageViewControllerMode_Image) {
+            _imageDownloadUsingCustom = YES;
+            //set placeholder
+            [self setImage:imageInfo.placeholderImage];
+            //retain NSProgress to be used in place of imageDownloadDataTask
+            _customImageProgress = customImageProgress;
+            [self startProgressTimer];
+        }
+    }
+    return self;
+}
+
+-(void)customImageLoadingDidFinish:(UIImage*)image{
+    
+    if (image) {
+        if (self.isViewLoaded) {
+            [self updateInterfaceWithImage:image];
+        } else {
+            [self setImage:image];
+        }
+    } else if (self.image == nil) {
+        _flags.imageDownloadFailed = YES;
+        if (_flags.isPresented && _flags.isAnimatingAPresentationOrDismissal == NO) {
+            [self dismiss:YES];
+        }
+        // If we're still presenting, at the end of presentation we'll auto dismiss.
+    }
+}
+
 - (void)showFromViewController:(UIViewController *)viewController
                     transition:(JTSImageViewControllerTransition)transition {
     
@@ -676,7 +719,7 @@ - (void)showImageViewerByExpandingFromOriginalPositionFromViewController:(UIView
                      } else {
                          [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
                      }
-                     
+                    
                      CGFloat scaling;
                      if (!(weakSelf.backgroundOptions & JTSImageViewControllerBackgroundOption_Scaled)) {
                          scaling = 1.0;
@@ -1039,7 +1082,7 @@ - (void)dismissByCollapsingImageBackToOriginalPosition {
             [weakSelf.imageView.layer addAnimation:cornerRadiusAnimation forKey:@"cornerRadius"];
             weakSelf.imageView.layer.cornerRadius = weakSelf.imageInfo.referenceCornerRadius;
             
-            [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
+            [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState| UIViewAnimationOptionCurveEaseInOut animations:^{
                 
                 if ([weakSelf.animationDelegate respondsToSelector:@selector(imageViewerWillAnimateDismissal:withContainerView:duration:)]) {
                     [weakSelf.animationDelegate imageViewerWillAnimateDismissal:weakSelf withContainerView:weakSelf.view duration:duration];
@@ -1872,13 +1915,25 @@ - (void)cancelProgressTimer {
 
 - (void)progressTimerFired:(NSTimer *)timer {
     CGFloat progress = 0;
-    CGFloat bytesExpected = self.imageDownloadDataTask.countOfBytesExpectedToReceive;
-    if (bytesExpected > 0 && _flags.imageIsBeingReadFromDisk == NO) {
-        [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear animations:^{
-            self.spinner.alpha = 0;
-            self.progressView.alpha = 1;
-        } completion:nil];
-        progress = self.imageDownloadDataTask.countOfBytesReceived / bytesExpected;
+    if(self.imageDownloadUsingCustom){
+        if(self.customImageProgress){
+            //use progress object to determine completion
+            progress = _customImageProgress.fractionCompleted;
+            if(_customImageProgress.totalUnitCount){
+                self.spinner.alpha = 0;
+                self.progressView.alpha = 1;
+            }
+        }
+    } else {
+        //JTSSimpleImageDownloader
+        CGFloat bytesExpected = self.imageDownloadDataTask.countOfBytesExpectedToReceive;
+        if (bytesExpected > 0 && _flags.imageIsBeingReadFromDisk == NO) {
+            [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear animations:^{
+                self.spinner.alpha = 0;
+                self.progressView.alpha = 1;
+            } completion:nil];
+            progress = self.imageDownloadDataTask.countOfBytesReceived / bytesExpected;
+        }
     }
     self.progressView.progress = progress;
 }
@@ -1963,4 +2018,3 @@ - (NSString *)defaultAccessibilityHintForScrollView:(BOOL)zoomedIn {
 @end
 
 
-
