Top Related Projects
Asynchronous image downloader with cache support as a UIImageView category
A lightweight, pure-Swift library for downloading and caching images from the web.
AlamofireImage is an image component library for Alamofire
Image loading system
Promises for Swift & ObjC.
A delightful networking framework for iOS, macOS, watchOS, and tvOS.
Quick Overview
PINRemoteImage is a powerful image downloading, processing, and caching library for iOS and macOS. It provides a simple, fast, and memory-efficient solution for handling remote images in applications, with support for progressive image loading and animated GIFs.
Pros
- High performance and memory efficiency
- Supports progressive image loading and animated GIFs
- Extensive customization options and filters
- Thread-safe and optimized for multi-core devices
Cons
- Primarily focused on Apple platforms (iOS and macOS)
- Learning curve for advanced features and customizations
- Limited documentation for some less common use cases
- Dependency on PINCache for caching functionality
Code Examples
- Basic image download and display:
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"))
- Setting a placeholder image and custom processor:
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"), placeholderImage: UIImage(named: "placeholder"), processor: { result in
return result.image.applying(someFilter)
})
- Prefetching images:
PINRemoteImageManager.shared().prefetchImages(with: [URL(string: "https://example.com/image1.jpg")!, URL(string: "https://example.com/image2.jpg")!])
- Cancelling an image download:
imageView.pin_cancelImageDownload()
Getting Started
- Install PINRemoteImage using CocoaPods by adding the following to your Podfile:
pod 'PINRemoteImage'
- Import the library in your Swift file:
import PINRemoteImage
- Use PINRemoteImage to download and display an image:
let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"))
- For more advanced usage, refer to the library's documentation and examples on GitHub.
Competitor Comparisons
Asynchronous image downloader with cache support as a UIImageView category
Pros of SDWebImage
- More mature and widely adopted project with a larger community
- Supports a broader range of image formats, including GIF and WebP
- Offers more extensive caching options and customization
Cons of SDWebImage
- Slightly larger library size, which may impact app size
- Can be more complex to set up and configure for advanced use cases
Code Comparison
SDWebImage:
let imageView = UIImageView()
imageView.sd_setImage(with: URL(string: "https://example.com/image.jpg"))
PINRemoteImage:
let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"))
Both libraries offer similar ease of use for basic image loading, with nearly identical syntax. The main differences lie in their advanced features and customization options.
SDWebImage provides more built-in functionality for complex scenarios, while PINRemoteImage focuses on simplicity and performance. SDWebImage's larger feature set comes at the cost of a slightly larger library size, which may be a consideration for projects with strict size constraints.
Ultimately, the choice between these libraries depends on the specific requirements of your project, such as supported image formats, caching needs, and desired level of customization.
A lightweight, pure-Swift library for downloading and caching images from the web.
Pros of Kingfisher
- Written in Swift, providing better performance and type safety for Swift projects
- More extensive caching options, including memory and disk caching with customizable expiration times
- Supports image processing and filtering out of the box
Cons of Kingfisher
- Limited support for older iOS versions compared to PINRemoteImage
- May have a steeper learning curve for developers new to Swift
Code Comparison
Kingfisher:
let url = URL(string: "https://example.com/image.jpg")
imageView.kf.setImage(with: url)
PINRemoteImage:
[imageView pin_setImageFromURL:[NSURL URLWithString:@"https://example.com/image.jpg"]];
Both libraries offer simple one-line methods for setting images from URLs, but Kingfisher's Swift syntax is more concise and type-safe.
Additional Considerations
- PINRemoteImage is written in Objective-C, making it more suitable for projects with legacy code or requiring Objective-C compatibility
- Kingfisher has a more active community and frequent updates
- PINRemoteImage offers better support for animated GIFs and progressive image loading
- Kingfisher provides easier integration with SwiftUI through its KFImage view
When choosing between these libraries, consider your project's language requirements, target iOS versions, and specific image loading needs.
AlamofireImage is an image component library for Alamofire
Pros of AlamofireImage
- Seamless integration with Alamofire networking library
- Built-in support for image filters and transformations
- Extensive documentation and active community support
Cons of AlamofireImage
- Limited to iOS and macOS platforms
- Requires Alamofire as a dependency, which may increase app size
- May have slightly higher memory usage for large image sets
Code Comparison
PINRemoteImage:
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"))
AlamofireImage:
imageView.af.setImage(withURL: URL(string: "https://example.com/image.jpg"))
Both libraries offer simple one-line methods for setting images from URLs. PINRemoteImage uses the pin_setImage
method, while AlamofireImage uses the af.setImage
method.
PINRemoteImage provides a more platform-agnostic solution, supporting iOS, macOS, and tvOS. It also offers features like progressive image loading and a robust caching system. On the other hand, AlamofireImage excels in its tight integration with Alamofire and provides built-in image manipulation capabilities.
Choose PINRemoteImage for a versatile, cross-platform solution with advanced features like progressive loading. Opt for AlamofireImage if you're already using Alamofire in your project and need seamless integration with powerful image processing capabilities.
Image loading system
Pros of Nuke
- Written in Swift, providing better performance and type safety for Swift projects
- Offers a more modern API with support for SwiftUI and Combine
- Smaller codebase, making it easier to maintain and integrate
Cons of Nuke
- Less mature compared to PINRemoteImage, which may result in fewer edge cases being handled
- Lacks some advanced features like progressive image loading and WebP support out of the box
Code Comparison
PINRemoteImage:
[imageView pin_setImageFromURL:url];
Nuke:
Nuke.loadImage(with: url, into: imageView)
Both libraries offer simple one-line methods for loading images, but Nuke's API is more Swift-friendly and integrates better with modern iOS development practices.
PINRemoteImage provides more granular control over the image loading process, while Nuke focuses on simplicity and ease of use. Nuke's integration with SwiftUI makes it a strong choice for newer projects, while PINRemoteImage's maturity and extensive feature set may be preferred for larger, more complex applications.
Promises for Swift & ObjC.
Pros of PromiseKit
- Provides a more general-purpose asynchronous programming solution
- Offers a cleaner and more readable syntax for handling complex asynchronous operations
- Supports a wide range of use cases beyond image loading
Cons of PromiseKit
- May have a steeper learning curve for developers unfamiliar with promises
- Potentially higher overhead for simple tasks like image loading
- Less specialized for image-specific optimizations
Code Comparison
PINRemoteImage:
imageView.pin_setImage(from: URL(string: "https://example.com/image.jpg"))
PromiseKit:
firstly {
URLSession.shared.dataTask(.promise, with: URL(string: "https://example.com/image.jpg")!)
}.map { data, _ in
UIImage(data: data)!
}.done { image in
imageView.image = image
}.catch { error in
print("Error: \(error)")
}
PINRemoteImage is more concise for simple image loading tasks, while PromiseKit offers a more flexible approach for handling complex asynchronous operations. PINRemoteImage is specifically optimized for image loading and caching, whereas PromiseKit provides a general-purpose solution for managing asynchronous code. The choice between the two depends on the specific requirements of your project and the complexity of the tasks you need to perform.
A delightful networking framework for iOS, macOS, watchOS, and tvOS.
Pros of AFNetworking
- More comprehensive networking library, offering features beyond image loading
- Well-established and widely adopted in the iOS development community
- Supports a broader range of networking tasks, including RESTful API interactions
Cons of AFNetworking
- Larger and more complex, which may lead to increased app size
- Not specifically optimized for image loading and caching
- May require more setup and configuration for image-specific tasks
Code Comparison
AFNetworking:
[imageView setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder"]];
PINRemoteImage:
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://example.com/image.jpg"]];
Summary
AFNetworking is a more comprehensive networking library suitable for various tasks, while PINRemoteImage focuses specifically on efficient image loading and caching. AFNetworking offers broader functionality but may be overkill for projects primarily concerned with image handling. PINRemoteImage provides a simpler, more targeted solution for image-related tasks, potentially offering better performance in this specific area. The choice between the two depends on the project's requirements and the developer's preference for a specialized tool versus a more general-purpose library.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
PINRemoteImage
Fast, non-deadlocking parallel image downloader and cache for iOS
PINRemoteImageManager is an image downloading, processing and caching manager. It uses the concept of download and processing tasks to ensure that even if multiple calls to download or process an image are made, it only occurs one time (unless an item is no longer in the cache). PINRemoteImageManager is backed by GCD and safe to access from multiple threads simultaneously. It ensures that images are decoded off the main thread so that animation performance isn't affected. None of its exposed methods allow for synchronous access. However, it is optimized to call completions on the calling thread if an item is in its memory cache.
PINRemoteImage supports downloading many types of files. It, of course, supports both PNGs and JPGs. It also supports decoding WebP images if Google's library is available. It even supports GIFs and Animated WebP via PINAnimatedImageView.
PINRemoteImage also has two methods to improve the experience of downloading images on slow network connections. The first is support for progressive JPGs. This isn't any old support for progressive JPGs though: PINRemoteImage adds an attractive blur to progressive scans before returning them.
PINRemoteImageCategoryManager defines a protocol which UIView subclasses can implement and provide easy access to PINRemoteImageManager's methods. There are built-in categories on UIImageView, PINAnimatedImageView and UIButton, and it's very easy to implement a new category. See [UIImageView+PINRemoteImage](/Pod/Classes/Image Categories/UIImageView+PINRemoteImage.h) of the existing categories for reference.
Download an image and set it on an image view:
Objective-C
UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/kitten.jpg"]];
Swift
let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/kitten.jpg")!)
Download a progressive jpeg and get attractive blurred updates:
Objective-C
UIImageView *imageView = [[UIImageView alloc] init];
[imageView setPin_updateWithProgress:YES];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/progressiveKitten.jpg"]];
Swift
let imageView = UIImageView()
imageView.pin_updateWithProgress = true
imageView.pin_setImage(from: URL(string: "https://pinterest.com/progressiveKitten.jpg")!)
Download a WebP file
Objective-C
UIImageView *imageView = [[UIImageView alloc] init];
[imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/googleKitten.webp"]];
Swift
let imageView = UIImageView()
imageView.pin_setImage(from: URL(string: "https://pinterest.com/googleKitten.webp")!)
Download a GIF and display with PINAnimatedImageView
Objective-C
PINAnimatedImageView *animatedImageView = [[PINAnimatedImageView alloc] init];
[animatedImageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/flyingKitten.gif"]];
Swift
let animatedImageView = PINAnimatedImageView()
animatedImageView.pin_setImage(from: URL(string: "http://pinterest.com/flyingKitten.gif")!)
Download and process an image
Objective-C
UIImageView *imageView = [[UIImageView alloc] init];
[self.imageView pin_setImageFromURL:[NSURL URLWithString:@"https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg"] processorKey:@"rounded" processor:^UIImage *(PINRemoteImageManagerResult *result, NSUInteger *cost)
{
CGSize targetSize = CGSizeMake(200, 300);
CGRect imageRect = CGRectMake(0, 0, targetSize.width, targetSize.height);
UIGraphicsBeginImageContext(imageRect.size);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:7.0];
[bezierPath addClip];
CGFloat sizeMultiplier = MAX(targetSize.width / result.image.size.width, targetSize.height / result.image.size.height);
CGRect drawRect = CGRectMake(0, 0, result.image.size.width * sizeMultiplier, result.image.size.height * sizeMultiplier);
if (CGRectGetMaxX(drawRect) > CGRectGetMaxX(imageRect)) {
drawRect.origin.x -= (CGRectGetMaxX(drawRect) - CGRectGetMaxX(imageRect)) / 2.0;
}
if (CGRectGetMaxY(drawRect) > CGRectGetMaxY(imageRect)) {
drawRect.origin.y -= (CGRectGetMaxY(drawRect) - CGRectGetMaxY(imageRect)) / 2.0;
}
[result.image drawInRect:drawRect];
UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return processedImage;
}];
Swift
let imageView = FLAnimatedImageView()
imageView.pin_setImage(from: URL(string: "https://i.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg")!, processorKey: "rounded") { (result, unsafePointer) -> UIImage? in
guard let image = result.image else { return nil }
let radius : CGFloat = 7.0
let targetSize = CGSize(width: 200, height: 300)
let imageRect = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height)
UIGraphicsBeginImageContext(imageRect.size)
let bezierPath = UIBezierPath(roundedRect: imageRect, cornerRadius: radius)
bezierPath.addClip()
let widthMultiplier : CGFloat = targetSize.width / image.size.width
let heightMultiplier : CGFloat = targetSize.height / image.size.height
let sizeMultiplier = max(widthMultiplier, heightMultiplier)
var drawRect = CGRect(x: 0, y: 0, width: image.size.width * sizeMultiplier, height: image.size.height * sizeMultiplier)
if (drawRect.maxX > imageRect.maxX) {
drawRect.origin.x -= (drawRect.maxX - imageRect.maxX) / 2
}
if (drawRect.maxY > imageRect.maxY) {
drawRect.origin.y -= (drawRect.maxY - imageRect.maxY) / 2
}
image.draw(in: drawRect)
UIColor.red.setStroke()
bezierPath.lineWidth = 5.0
bezierPath.stroke()
let ctx = UIGraphicsGetCurrentContext()
ctx?.setBlendMode(CGBlendMode.overlay)
ctx?.setAlpha(0.5)
let logo = UIImage(named: "white-pinterest-logo")
ctx?.scaleBy(x: 1.0, y: -1.0)
ctx?.translateBy(x: 0.0, y: -drawRect.size.height)
if let coreGraphicsImage = logo?.cgImage {
ctx?.draw(coreGraphicsImage, in: CGRect(x: 90, y: 10, width: logo!.size.width, height: logo!.size.height))
}
let processedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return processedImage
}
Handle Authentication
Objective-C
[[PINRemoteImageManager sharedImageManager] setAuthenticationChallenge:^(NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, PINRemoteImageManagerAuthenticationChallengeCompletionHandler aCompletion) {
aCompletion(NSURLSessionAuthChallengePerformDefaultHandling, nil)];
Swift
PINRemoteImageManager.shared().setAuthenticationChallenge { (task, challenge, completion) in
completion?(.performDefaultHandling, nil)
}
Support for high resolution images
Currently there are two ways PINRemoteImage is supporting high resolution images:
- If the URL contains an
_2x.
or an_3x.
postfix it will be automatically handled by PINRemoteImage and the resulting image will be returned at the right scale. - If it's not possible to provide an URL with an
_2x.
or_3x.
postfix, you can also handle it with a completion handler:
NSURL *url = ...;
__weak UIImageView *weakImageView = self.imageView;
[self.imageView pin_setImageFromURL:url completion:^(PINRemoteImageManagerResult * _Nonnull result) {
CGFloat scale = UIScreen.mainScreen.scale;
if (scale > 1.0) {
UIImage *image = result.image;
weakImageView.image = [UIImage imageWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
}
}];
Set some limits
// cache is an instance of PINCache as long as you haven't overridden defaultImageCache
PINCache *cache = (PINCache *)[[PINRemoteImageManager sharedImageManager] cache];
// Max memory cost is based on number of pixels, we estimate the size of one hundred 600x600 images as our max memory image cache.
[[cache memoryCache] setCostLimit:600 * [[UIScreen mainScreen] scale] * 600 * [[UIScreen mainScreen] scale] * 100];
// ~50 MB
[[cache diskCache] setByteLimit:50 * 1024 * 1024];
// 30 days
[[cache diskCache] setAgeLimit:60 * 60 * 24 * 30];
Installation
CocoaPods
Add PINRemoteImage to your Podfile
and run pod install
.
If you'd like to use WebP images, add PINRemoteImage/WebP to your Podfile
and run pod install
.
Carthage
Add github "pinterest/PINRemoteImage"
to your Cartfile . See Carthage's readme for more information on integrating Carthage-built frameworks into your project.
Manually
Download the latest tag and drag the Pod/Classes
folder into your Xcode project. You must also manually link against PINCache.
Install the docs by double clicking the .docset
file under docs/
, or view them online at cocoadocs.org
Git Submodule
You can set up PINRemoteImage as a submodule of your repo instead of cloning and copying all the files into your repo. Add the submodule using the commands below and then follow the manual instructions above.
git submodule add https://github.com/pinterest/PINRemoteImage.git
git submodule update --init
Requirements
PINRemoteImage requires iOS 12.0 or greater.
Contact
Garrett Moon @garrettmoon Pinterest
License
Copyright 2015 Pinterest, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Top Related Projects
Asynchronous image downloader with cache support as a UIImageView category
A lightweight, pure-Swift library for downloading and caching images from the web.
AlamofireImage is an image component library for Alamofire
Image loading system
Promises for Swift & ObjC.
A delightful networking framework for iOS, macOS, watchOS, and tvOS.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot