Twitter Image Pipeline is a robust and performant image loading and caching framework for iOS clients

Overview

Twitter Image Pipeline (a.k.a. TIP)

Background

The Twitter Image Pipeline is a streamlined framework for fetching and storing images in an application. The high level concept is that all requests to fetch or store an image go through an image pipeline which encapsulates the work of checking the in memory caches and an on disk cache before retrieving the image from over the network as well as keeping the caches both up to date and pruned.

Goals and Requirements

Twitter Image Pipeline came to fruition as numerous needs rose out of Twitter for iOS use cases. The system for image loading prior to TIP was fragile and inefficient with some severe edge cases. Designing a new framework from the ground up to holistically approach the need for loading images was the best route and led to TIP.

  • Progressive image loading support (Progressive JPEG)
    • PJPEG can render progressive scans with a fraction of the bytes needed for the full image
    • Users can see a 35% to 65% improvement in how soon an image is visible (occasionally even better)
    • PJPEG images happen to be 10% smaller (on average) than their non-progressive counterparts
    • PJPEG is hardware decodable on iOS devices, just like non-progressive JPEG images
  • Resumable download support
    • If an image load is terminated (via failure or cancellation) when an image is partially loaded, the next load of that image should resume from where it left off saving on bytes needing to be transferred
    • Has a compounding benefit with Progressive JPEG as resuming an image that is partially loaded can render to screen with a progressive scan immediately while remaining bytes can be loaded to improve the quality
  • Support programmatically/manually storing images to the cache(s)
    • By being able to store images to the underlying cache(s), cases where images are uploaded can have those images in cache at the right location without having to make a fetch. (Ex// Post a Tweet with an image, that image can be stored to the cache before it is ever seen in the timeline making the timeline's fetch of that image immediate and avoids hitting the network.)
  • Support vending a larger variant when a smaller variant is fetched
    • By maintaining the largest variant in cache, we can merely scale the image (in the background) and vend that image instead of hitting the network
  • Support vending a smaller variant when a larger variant is fetched
    • When fetching a larger variant of an image when a smaller variant is in the cache, the smaller variant should be optionally be consumable as the larger variant is loaded over the network
    • This improves the user experience by providing an image at lower quality while loading the higher quality variant instead of just having an empty/blank UI or placeholder
  • Asynchronous architecture
    • Using requests to encapsulate what to load, using an operation for executing the asynchronous work, and having a delegate for callbacks we can provide a strong and scalable pattern for image loading
  • Cancellable fetches
    • When an image fetch is no longer relevant (such as navigating away from an image that hasn't finished loading), we should be permitted to cancel fetches
    • HTTP/1.1 based fetch downloads that are cancelled will have the negative side effect of tearing down that TCP connection which is expensive to re-establish at the tradeoff of saving on bandwidth and unnecessary network contention with other network requests
    • HTTP/2 (or SPDY) based fetch downloads will have no negative side effects since the protocol supports midstream cancellation without impacting overall network performance
  • Fast access to cached images
    • Having the fetch synchronously load already scaled and cached images will keep the UI smooth by avoiding lapses when the image is immediately available
  • Background rendering/scaling/decoding of fetched images
    • Fetched images need to be decoded and often scaled and even rendered, doing so on a background thread will eliminate framerate drops from trying to do the same expensive work from the main thread
  • Segregated caches / pipelines
    • By having caches support being segregated, the Twitter app can utilize this segregation to keep caches separate per user account. On account removal, that account's cache can be cleared without affecting other account caches.
  • Image fetch hydration support
    • Certain image fetches will require the fetch to sign the request to be loaded over the network, having support for a hydration step will enable this with "pull" based pattern vs a "push" based pattern that would require applying any such request construct up front.
  • Support for custom networking to execute the downloading of images.
    • Twitter has strict requirements to have all networking go through its network layer and as such TIP has abstracted out networking so that any network layer can be plugged in via the abstraction interface for downloads.
    • An NSURLSession based download plugin is used by default, but consumers can plug in whatever network layer they desire.
  • Support any image codec desired
    • By default, all ImageIO supported image types are supported
    • A plugin architecture supports custom codecs for encoding and/or decoding images in TIP
    • Use cases include WebP support, or any custom decoding support such as JPEG decoding with a shared quantization table and/or header, or even applying some visual transform (like a blur) as a part of the rendering

Architecture

Caches

There are 3 separate caches for each image pipeline: the rendered in-memory cache, the image data in-memory cache, and the on-disk cache. Entries in the caches are keyed by an image identifier which is provided by the creator of the fetch request or automatically generated from the image fetch's URL.

  • The On-Disk Cache will maintain both the latest partial image and the largest completed image for an image identifier
  • The Image Data In-Memory Cache will maintain the largest matching image data (based on the image identifier), but is not decoded
  • The Rendered In-Memory Cache will maintain the 3 most recently sized and rendered/decoded UIImages that match (based on the image identifier)

The image will simultaneously be loaded into memory (as raw bytes) and written to the disk cache when retrieving from the Network. Partial images will be persisted as well and not replace any completed images in the cache.

Once the image is either retrieved from any of the caches or the network, the retrieved image will percolate back through the caches in its various forms.

Caches will be configurable at a global level to have maximum size. This maximum will be enforced across all image pipeline cache's of the same kind, and be maintained with the combination of time-to-live (TTL) expiration and least-recently-used (LRU) purging. (This solves the long standing issue for the Twitter iOS app of having an unbounded cache that could consume Gigabytes of disk space).

Execution

The architecture behind the fetch operation is rather straightforward and streamlined into a pipeline (hence, "image pipeline").

When the request is made, the fetch operation will perform the following:

  • Synchronously consult the Rendered In-Memory Cache for an image that will fit the target dimensions and content mode.
  • On miss, asynchronously consult the Image Data In-Memory Cache that holds the image of the largest matching image (based on identifier).
  • On miss, asynchronously consult the On-Disk Cache that maintains the image data of the largest matching image (based on identifier). As an optimization, TIP will take it a step further and also consult all other registered pipeline disk caches - thus saving on the cost of network load by pulling from disk. The cross pipeline retrieved image will be stored to the fetching pipeline's caches to maintain image pipeline siloing. Note: this cross pipeline access requires the fetching image identifier and image URL to match.
  • On miss, asynchronously consult any provided additional caches (based on URL). This is so that legacy caches can be pulled from when transitioning to TIP without having to forcibly load all assets again.
  • On miss, asynchronously retrieve the image from the Network, resuming any partially loaded data that may exist in the On-Disk Cache.

Preview Support

In addition to this simple progression, the fetch operation will offer the first matching (based on image identifier) complete image in the In-Memory Cache or On-Disk Cache (rendered and sized to the request's specified target sizing) as a preview image when the URLs don't match. At that point, the fetch delegate can choose to just use the preview image or continue with the Network loading the final image. This is particularly useful when the fetch image URL is for a smaller image than the image in cache, no need to hit the network :)

Progressive Support

A great value that the image pipeline offers is the ability to stream progressive scans of an image, if it is PJPEG, as the image is loaded from the Network. This progressive rendering is natively supported by iOS 8+, the OS minimum for TIP is now iOS 10+. Progressive support is opt-in and also configurable in how scans should load.

Resuming Image Downloads

As already mentioned, by persisting the partial load of an image to the On-Disk Cache, we are able to support resumable downloads. This requires no interface either, it's just a part of how the image pipeline works.

Rendering to Target Sizing

As of 2.20, the image pipeline will load the image from data to the specified target sizing of the fetch request, which avoids the overhead of loading the entire image into a large bitmap just to scale it down to the correct size. If the target sizing is larger than the image data, it will load that image bitmap and scale it up to the target sizing specified by the fetch request. If a request does not provide target sizing (or the sizing indicates to not resize), it will yield the full size image, as one would expect.

Twitter Image Pipeline features

  • Fetching
    • Progress reporting
    • Customizable progressive loading policies
    • Preview loading with option to avoid continuing to load
    • Placeholder support (for non-canonical images that get purged)
    • Automatic scaling to target view's size
    • Custom caching uptions
    • Customizable set of loading sources (caches and network)
    • NSOperation based
      • Cancellable
      • Priority support
      • Dependency chain support
    • Delegate pattern (for robust support)
    • Block callback pattern (for simple use cases)
  • Storing
    • Manual storage support (UIImage, NSData or file on disk)
    • Manual purging support
    • Dependency chain support (like NSOperation)
  • Caching
    • Synchronous/fast cache for rendered images
    • Async memory cache for image data
    • Async disk cache for image data
    • Automatic LRU purging
    • Automatic TTL purging
    • Siloed caches (via multiple TIPImagePipeline instances)
    • Support for loading from additional non-TIP caches (helps with migration)
    • Expose method to copy disk cache images directly
  • Downloads
    • Coalescing image downloads
    • Image download resumption support built in
      • Image response "Accept-Ranges" must be "bytes" and have "Last-Modified" header
      • Uses "Range" and "If-Range" headers to specify continuation
    • Pluggable networking (use your own network layer)
    • Custom hydration (useful for authenticated fetches)
  • Detailed insights
    • Global pipeline observability
    • Individual pipeline observability
    • Global problem observability (non-fatal problems for monitoring)
    • Asserts can be enabled/disabled
    • Pluggable logging
    • Inspectable (can inspect each pipeline's entries)
    • Robust errors
    • Detailed metrics on fetch operation completion
  • Robust image support
    • Pluggable codecs (can add WebP or other image codecs)
    • Can serialize access to CGContext
    • UIImage convenience methods
    • Animated image support (GIFs, by default)
  • UIKit integration
    • Dedicated helper object decoupling logic from views w/ TIPImageViewFetchHelper
    • Fetch helper offers useful fetch behavior encapsulation
    • Debug overlay feature to see debug details of the image view
    • UIImageView category for convenient pairing with a TIPImageViewFetchHelper
  • Configurable
    • caches sizes (both in bytes and image count)
    • max cache entry size
    • max time for detached download
    • max concurrent downloads

Components of the Twitter Image Pipeline

  • TIPGlobalConfiguration
    • The global configuration for TIP
    • Configure/modify this configuration to adjust TIP behavior for your needs
  • TIPImagePipeline
    • the pipeline for fetching images from and storing images to
    • multiple pipelines can exist providing segregation by use case
    • a fetch operation is constructed by providing a request (TIPImageFetchRequest) with a delegate (TIPImageFetchDelegate) or completion block (TIPImagePipelineFetchCompletionBlock) to a desired pipeline. The operation can then be provided to that same pipeline to start the fetching. This two step approach is necessary to support both synchronous and asynchronous loading while incurring minimal burden on the developer.
  • TIPImageFetchRequest
    • the protocol that encapsulates the information necessary for retrieving an image
  • TIPImageFetchDelegate
    • the delegate for dealing with dynamic decisions and event callbacks
  • TIPImageFetchOperation
    • the NSOperation that executes the request and provides a handle to the operation
    • the operation maintains the state of the fetch's progress as it executes
    • the operation offers several features:
      • cancelability
      • dependency support
      • prioritization (can be mutated at any time)
      • a unique reference for distinguishing between operations
  • TIPImageStoreRequest
    • the protocol that encapsulates the information necessary for programmatically storing an image
  • TIPImageContainer
    • object to encapsulate the relevant info for a fetched image
    • the TIPImageFetchDelegate will use TIPImageContainer instances for callbacks, and the TIPImageFetchOperation will maintain TIPImageFetchOperation properties as it progresses.
  • TIPImageViewFetchHelper
    • powerful class that can encapsulate the majority of use cases for loading an image and displaying it in a UIImageView
    • 99% of image loading and displaying use cases can be solved by using this class, configuring it and providing a delegate and/or data source
    • having the logic in this class avoid coupling controller code with view code in the MVC practice
  • UIView(TIPImageFetchable) and UIImageView(TIPImageFetchable)
    • convenience categories on UIImageView and UIView for associating a TIPImageViewFetchHelper

Usage

The simplest way to use TIP is with the TIPImageViewHelper counterpart.

For concrete coding samples, look at the TIP Sample App and TIP Swift Sample App (in Objective-C and Swift, respectively).

Here's a simple example of using TIP with a UIViewController that has an array of image views to populate with images.


    /* category on TIPImagePipeline */

    + (TIPImagePipeline *)my_imagePipeline
    {
        static TIPImagePipeline *sPipeline;
        static dispatch_once_t sOnceToken;
        dispatch_once(&sOnceToken, ^{
            sPipeline = [[TIPImagePipeline alloc] initWithIdentifier:@"com.my.app.image.pipeline"];

            // support looking in legacy cache before hitting the network
            sPipeline.additionalCaches = @[ [MyLegacyCache sharedInstance] ];
        });
        return sPipeline;
    }

    // ...

    /* in a UIViewController */

    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];

        if (nil == self.view.window) {
            // not visible
            return;
        }

        [_imageFetchOperations makeAllObjectsPerformSelector:@selector(cancelAndDiscardDelegate)];
        [_imageFetchOperations removeAllObjects];

        TIPImagePipeline *pipeline = [TIPImagePipeline my_imagePipeline];
        for (NSInteger imageIndex = 0; imageIndex < self.imageViewCount; imageIndex++) {
            UIImageView *imageView = _imageView[imageIndex];
            imageView.image = nil;
            id<TIPImageFetchRequest> request = [self _my_imageFetchRequestForIndex:imageIndex];

            TIPImageFetchOperation *op = [pipeline operationWithRequest:request context:@(imageIndex) delegate:self];

            // fetch can complete sync or async, so we need to hold the reference BEFORE
            // triggering the fetch (in case it completes sync and will clear the ref)
            [_imageFetchOperations addObject:op];
            [[TIPImagePipeline my_imagePipeline] fetchImageWithOperation:op];
        }
    }

    - (id<TIPImageFetchRequest>)_my_imageFetchRequestForIndex:(NSInteger)index
    {
        NSAssert(index < self.imageViewCount);

        UIImageView *imageView = _imageViews[index];
        MyImageModel *model = _imageModels[index];

        MyImageFetchRequest *request = [[MyImageFetchRequest alloc] init];
        request.imageURL = model.thumbnailImageURL;
        request.imageIdentifier = model.imageURL.absoluteString; // shared identifier between image and thumbnail
        request.targetDimensions = TIPDimensionsFromView(imageViews);
        request.targetContentMode = imageView.contentMode;

        return request;
    }

    /* delegate methods */

    - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op
                didLoadPreviewImage:(id<TIPImageFetchResult>)previewResult
                         completion:(TIPImageFetchDidLoadPreviewCallback)completion
    {
        TIPImageContainer *imageContainer = previewResult.imageContainer;
        NSInteger idx = [op.context integerValue];
        UIImageView *imageView = _imageViews[idx];
        imageView.image = imageContainer.image;

        if ((imageContainer.dimension.width * imageContainer.dimensions.height) >= (originalDimensions.width * originalDimensions.height)) {
            // scaled down, preview is plenty
            completion(TIPImageFetchPreviewLoadedBehaviorStopLoading);
        } else {
            completion(TIPImageFetchPreviewLoadedBehaviorContinueLoading);
        }
    }

    - (BOOL)tip_imageFetchOperation:(TIPImageFetchOperation *)op
    shouldLoadProgressivelyWithIdentifier:(NSString *)identifier
                                URL:(NSURL *)URL
                          imageType:(NSString *)imageType
                 originalDimensions:(CGSize)originalDimensions
    {
        // only load progressively if we didn't load a "preview"
        return (nil == op.previewImageContainer);
    }

    - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op
          didUpdateProgressiveImage:(id<TIPImageFetchResult>)progressiveResult
                           progress:(float)progress
    {
        NSInteger idx = [op.context integerValue];
        UIImageView *imageView = _imageViews[idx];
        imageView.image = progressiveResult.imageContainer.image;
    }

    - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op
                  didLoadFinalImage:(id<TIPImageFetchResult>)finalResult
    {
        NSInteger idx = [op.context integerValue];
        UIImageView *imageView = _imageViews[idx];
        imageView.image = finalResult.imageContainer.image;

        [_imageFetchOperations removeObject:op];
    }

    - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op
            didFailToLoadFinalImage:(NSError *)error
    {
        NSInteger idx = [op.context integerValue];
        UIImageView *imageView = _imageViews[idx];
        if (!imageView.image) {
            imageView.image = MyAppImageLoadFailedPlaceholderImage();
        }

        NSLog(@"-[%@ %@]: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error);
        [_imageFetchOperations removeObject:op];
    }

Inspecting Image Pipelines

Twitter Image Pipeline has built in support for inspecting the caches via convenience categories. TIPGlobalConfiguration has an inspect: method that will inspect all registered TIPImagePipeline instances (even if they have not been explicitely loaded) and will provide detailed results for those caches and the images there-in. You can also call inspect: on a specific TIPImagePipeline instance to be provided detailed info for that specific pipeline. Inspecting pipelines is asynchronously done on background threads before the inspection callback is called on the main thread. This can provide very useful debugging info. As an example, Twitter has built in UI and tools that use the inspection support of TIP for internal builds.

License

Copyright 2015-2020 Twitter, Inc.

Licensed under the Apache License, Version 2.0: https://www.apache.org/licenses/LICENSE-2.0

Security Issues?

Please report sensitive security issues via Twitter's bug-bounty program (https://hackerone.com/twitter) rather than GitHub.

Comments
  • Image decoding/decompression still happening on the main thread

    Image decoding/decompression still happening on the main thread

    Describe the bug Even though there exists code in TIP to decode the image on the background thread, apple is still decoding the image again on the main thread. Seems some recent change caused the decoding in TIP to not function.

    To Reproduce Load remote images under profiler and do a filter for jpeg.

    Expected behavior Images are decompressed only on background thread.

    Screenshots If applicable, add screenshots to help explain your problem.

    Environment iOS 14 (coworker claims it happens on iOS 13 as well)

    Additional context So there are 2 weird things:

    1. As a part of decoding the image that is returned from the background render is never used, only the original UIImage instance is used. Also this does result in 2 different UIImage instances. Seems the original maintains unmodified, it's possible this was a more recent iOS change.
    2. The image is rendered to 1x1. I assume this was a memory optimization, but it means the rendered image can't just be swapped in place of the original one.

    I'll create a PR soon, need to get more familiar with the code and what is best practice for decoding images off the main thread. Wanted to create the issue now to increase awareness for those that are more familiar with this code.

    opened by cltnschlosser 5
  • Can't link to app

    Can't link to app

    ld: '/Users/cc/Library/.../TwitterImagePipeline.framework/TwitterImagePipeline' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. file '/Users/cc/Library/.../TwitterImagePipeline.framework/TwitterImagePipeline' for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

    This framework was built by carthage and embedded manually.

    Xcode 9.1 beta 2. iOS 11.1 beta 5. macOS High Sierra 10.13.1 beta

    opened by lastcc 5
  • Add COCOAPODS.md with installation instructions

    Add COCOAPODS.md with installation instructions

    Following #56, this change adds a COCOAPODS.md document describing ways to configure the TwitterImagePipeline pod for use with the extended subspecs.

    I was thinking about adding a section to the bottom of README.md but wasn't sure if it was best to do that since there are no manual usage instructions to go with it.. Let me know if you want me to add something though.

    Once merged, will it be possible to get a 2.24.1 release to push up the new Podspec? I can bump versions or update CHANGELOG.md here if it would help?

    Thanks!

    opened by liamnichols 4
  • [Idea] Supporting WebP via CocoaPod's subspec

    [Idea] Supporting WebP via CocoaPod's subspec

    Hey! First off, I only recently discovered this library and wow it's impressive! As our project has evolved we've outgrown our existing tool used for managing remotely served images and when I came across TIP it seemed to check all of the boxes for what I was looking for!

    We currently also depend on WebP support and I understand why you didn't include it built into TIP however I was wondering if there is any reason not to provide the Codec via an opt-in subspec using CocaPods?

    I see that there is a bit of trickery around getting libwebp building for Mac Catalyst however I stubbed across SDWebImage/libwebp-Xcode and it appears to handle all platforms correctly (although I need to double check that). In the sample PR here, I've added a simple subspec that includes the TIPXWebPCodec as well as a dependency on the libwebp pod provided by the linked repo and can confirm that this works for my iOS project... Is this approach something that interests you?

    I guess that there are still a few unresolved questions though but I wanted to get opinions before I dig deeper:

    1. Does this work for everything (macCatalyst and so on)?
    2. How much work does it take to get TIPXWebPCodec up to scratch to release alongside (I noticed a couple of TODO's)
    3. Should we somehow auto-register the codec with TIPImageCodecCatalogue or leave that up to the user?

    No worries if this isn't something that you want to support in TIP, I just thought that it's better to check here as I'd much rather help give back a little than just integrate something directly into our project 🙏

    opened by liamnichols 4
  • Allow `tip_fetchedImage` to know about how it was set

    Allow `tip_fetchedImage` to know about how it was set

    By setting tip_fetchedImage after setting fetchSource and _flags, an implementation of tip_fetchedImage can ask the TIPImageViewFetchHelper about where it came from, it's progress, etc. One use of this is being able to animate the setting of the image if the source was from the network.

    opened by brentleyjones 4
  • Controlling Animation on TIPImageView

    Controlling Animation on TIPImageView

    Can you point me in the right direction regarding how to control the animations on a TIPImageView that encapsulates an animated GIF? UIImageView property isAnimating, and methods startAnimating, stopAnimating don't seem to function out of the box. Ideally, I need to be able to pause / resume the animation.

    Thanks for sharing the awesome library!

    enhancement 
    opened by ken-jen 3
  • Add Subspecs for Extended code (WebP and MP4 Codecs)

    Add Subspecs for Extended code (WebP and MP4 Codecs)

    Hello again @NSProgrammer 👋 This PR is a followup to #53 that I hope addresses some initial concerns 🙏

    Now that I'm back to migrating our project over to TwitterImagePipeline i'm back to the drawing board trying to work out how best to integrate TIP along with the WebP codec that you already provide and test in this repo.

    Like WEBP_README.md rightly explains, compiling/integrating libwebp into a project isn't as simple as we'd like and I've not been able to come up with an approach to integrate the TIPXWebPCodec into our project in a way that I'm happy with.

    When managing the TwitterImagePipeline dependency via something like Git submodules then I understand how including the WebP codec might not be such a big problem however when using CocoaPods to manage the main dependency then configuring the WebP.framework and copying source files over manually seems fragile and a lot of work that can be avoided.

    After looking back at your original feedback and the configuration of the project, I realised that there might have been a slight misunderstanding how subspecs work and also I discovered a way to avoid external dependencies that this change demonstrates.

    Firstly...

    It is important that the WebP extended code be committed to the repo but also unnecessary for using TIP, only Apple provided decoders/encoders will be automatically supported. This will avoid any binary bloating for consumers that do not need codecs that are not included by Apple.

    I agree with the statement above but when using CocoaPods, the entire git repository will be cloned regardless to if source files are included in the Default subspec's source_files or not. Prior to this change, you don't include the ./Extended directory in the Podspec so the code will never be compiled and won't bloat the resulting project.

    In this change, I add additional subspecs but I don't include them in the default_subspec configuration. This means that out the box, users who declare the TwitterImagePipeline pod will by default only use the Default subspec.

    So in a pod file configuration:

    pod 'TwitterImagePipeline'
    # is the same as 
    pod 'TwitterImagePipeline', :subspecs => ['Default']
    

    I've added extra Subspecs in this PR that aren't' included as the default, so by default they are ignored (thus avoiding any binary bloating) however they can be opted into using configurations such as the following:

    pod 'TwitterImagePipeline', :subspecs => ['WebPCodec/Default']
    pod 'TwitterImagePipeline', :subspecs => ['WebPCodec/Default', 'MP4Codec']
    pod 'TwitterImagePipeline', :subspecs => ['WebPCodec/Animated']
    pod 'TwitterImagePipeline', :subspecs => ['MP4Codec']
    

    Only when one of the configurations like the above are used would the extended code be included in the binary output and this would only ever be the code that the consumer intentionally wanted.

    If it helps, you can see the output Xcode Project that CocoaPods produces for somebody opting into WebPCodec/Animated and MP4Codec subspecs below:

    Screenshot 2020-08-20 at 09 48 34

    We are committed to having Twitter Image Pipeline be a zero dependency project

    This is a great thing to be doing, and in my original proposal I suggested using the libwebp pod however now I've realised that wasn't necessary..

    In this proposed solution, I use vendored_frameworks to reference the precompiled WebP and WebPDemux frameworks instead. This is possible since the Podspec currently is only configured for iOS and from what I understand CocoaPods doesn't actually support Catalyst (CocoaPods/CocoaPods#8877) so for the time being this solution works fine.

    If you do also want to support Mac via CocoaPods then it isn't impossible either.. Since you already include the source in the repo, we'd just need to add another subspec with a configuration similar to this: https://github.com/SDWebImage/libwebp-Xcode/blob/master/libwebp.podspec and use that instead (although in the long run, I think we'll want to push to work on an .xcframework version of libwebp (I think)).


    Anyway, please take a look at this change and the above and let me know what you think.. Since it's zero dependencies and requires no code changes I hope it resolves some of your prior concerns but let me know if there is more 🙏

    I was also thinking of adding some info the readme but seeing as there is already no mention of CocoaPods I didn't know if it was worth it or not.. Let me know if you do want me to document anything though.

    Lastly, here is the pod spec lint output (all is good):

    Output
     -> TwitterImagePipeline (2.24.0)
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  note: Using new build system
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  note: Building targets in parallel
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  note: Planning build
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  note: Constructing build description
        - NOTE  | [iOS] xcodebuild:  note: Build description constructed in 0.209491149s
        - NOTE  | [iOS] xcodebuild:  note: Using build description 'ad760b0efabd4862f1636d529a9228aa'
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  note: Using eager compilation
        - NOTE  | [TwitterImagePipeline/Default, TwitterImagePipeline/WebPCodec, TwitterImagePipeline/WebPCodec/Default, and more...] xcodebuild:  warning: Skipping code signing because the target does not have an Info.plist file and one is not being generated automatically. (in target 'App' from project 'App')
        - NOTE  | [iOS] [TwitterImagePipeline/Default] xcodebuild:  note: Build description constructed in 0.179841603s
        - NOTE  | [iOS] [TwitterImagePipeline/Default] xcodebuild:  note: Using build description 'd884f8e2d5f66a1cf8dd2b6065860e9d'
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec] xcodebuild:  note: Build description constructed in 0.177936516s
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec] xcodebuild:  note: Using build description '9d59a6ab73ce4416f340a9a979c3aa4c'
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec/Default] xcodebuild:  note: Build description constructed in 0.177591027s
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec/Default] xcodebuild:  note: Using build description '046535f7d04f66a39129b59a714a5d4d'
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec/Animated] xcodebuild:  note: Build description constructed in 0.176152623s
        - NOTE  | [iOS] [TwitterImagePipeline/WebPCodec/Animated] xcodebuild:  note: Using build description '161247a73b43f2db73d7b5a7fc0b87f8'
        - NOTE  | [iOS] [TwitterImagePipeline/MP4Codec] xcodebuild:  note: Build description constructed in 0.179207421s
        - NOTE  | [iOS] [TwitterImagePipeline/MP4Codec] xcodebuild:  note: Using build description '3fb25302f4156ee441f260649ea287af'
    
    Analyzed 1 podspec.
    
    TwitterImagePipeline.podspec passed validation.
    
    opened by liamnichols 2
  • ITMS-90338: Non-public API usage - imageDimensions, imageFilePath

    ITMS-90338: Non-public API usage - imageDimensions, imageFilePath

    We just submitted our app to the App Store, but they rejected our package due to they think we used Apple private APIs: ITMS-90338: Non-public API usage - imageDimensions, imageFilePath. Maybe the names match the private Apple APIs listed above. I have send email to Apple, that they flagged in error, and they approved our app later. But i think maybe alter the names will help prevent app being flagged in future?

    opened by lilei2100 2
  • Setting maxBytes = 0 does not work

    Setting maxBytes = 0 does not work

    In our project, we don't want a disk cache so we set [TIPGlobalConfiguration sharedInstance].maxBytesForAllDiskCaches = 0. However, that doesn't seem to be working. I DM'd with @NSProgrammer and he confirmed there are some places where 0 == off and others where 0 == unlimited (ex: https://github.com/twitter/ios-twitter-image-pipeline/blob/8b3eff1b4c44f258d66f2041d350c7a1d5b616dd/TwitterImagePipeline/TIPGlobalConfiguration.m#L542).

    opened by gitdump1 2
  • Duplicate info.plist file in 2.11 Pods

    Duplicate info.plist file in 2.11 Pods

    There seems to be an issue when using the unpublished 2.11 tag with CocoaPods:

    pod 'TwitterImagePipeline', :git => 'https://github.com/twitter/ios-twitter-image-pipeline.git', :tag => '2.11.0'

    Produces:

    warning: duplicate output file '/Users/test/Library/Developer/Xcode/DerivedData/testapp-ewynxhezdlpikvcpvyepzrthcgds/Build/Products/Debug-iphonesimulator/TwitterImagePipeline/TwitterImagePipeline.framework/Info.plist' on task: ProcessInfoPlistFile /Users/test/Library/Developer/Xcode/DerivedData/testapp-ewynxhezdlpikvcpvyepzrthcgds/Build/Products/Debug-iphonesimulator/TwitterImagePipeline/TwitterImagePipeline.framework/Info.plist /Users/test/Documents/testapp_ios/Pods/Target Support Files/TwitterImagePipeline/Info.plist (in target 'TwitterImagePipeline')

    info.plist is included in the compiled sources list for the TwitterImagePipeline. Was this intentional?

    opened by klische 2
  • tvOS Platform Support

    tvOS Platform Support

    Hi all, I've successfully integrated the current pod into a tvOS project by manually overriding the supported platforms in my local master repo. Is there any reason the podspec couldn't be updated to include s.tvos.deployment_target = '9.0'?

    opened by clstroudtm 2
  • changes to continuous integration

    changes to continuous integration

    We will be dropping our paid Travis CI plan at the end of 2021. We do not expect there to be any visible changes to this repo, but wanted to give some notice just in case. We recommend migrating CI jobs to GitHub Actions.

    Travis CI provides free testing for open source projects. In addition, Twitter has paid for a small number of additional concurrent builds which were available for open source as well as private repositories. Many Twitter projects have already moved to GitHub Actions for CI, and we have no private repos left using Travis, so we will be discontinuing our plan at the end of 2021.

    Since this repo is open source, we do not expect this change to impact Travis CI builds for this project. However, we still recommend most Twitter projects to migrate to GitHub Actions for CI at your convenience.

    opened by willnorris 0
  • Leverage iOS 15 image decoding

    Leverage iOS 15 image decoding

    iOS 15's new first party image decoding APIs appear to be faster and more memory efficient that the classic "draw image in context" method of image decoding. Would be nice to leverage this in TIP.

    https://twitter.com/timonus/status/1450866353137618949

    I plan to put up a PR for this at some point, haven't had time yet. I chatted with @NSProgrammer about this earlier today and he recommended opening a task tracking it!

    opened by timonus 0
  • Use xcframework distribution of WebP

    Use xcframework distribution of WebP

    Hello Twitter 👋

    As I am sure that you are aware, TIP had to make some compromises for WebP support and Mac Catalyst since no xcframework distribution of WebP existed. I'm happy to announce however that starting with 1.2.0, this is no longer the case!

    https://groups.google.com/a/webmproject.org/g/webp-discuss/c/LwWaVfKbJGc/m/IjpeggKnAAAJ https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html

    With xcframeworks, we no longer need to both support both compiling webp as well as using precompiled frameworks. In this pull-request I take a first attempt at getting it up and running.

    Why

    1. Simplify repo by removing the webp source code in favour of just managing the xcframework from Google
    2. Modernise the project by using the latest and (kind of) greatest tech (xcframeworks)
    3. Support building TIP on iOS Simulators when using Apple silicon

    How

    I'm able to achieve this by doing the following:

    1. Downloading the ~1.2.1~ 1.2.2 release of WebP direct from the source
    2. ~'Patch'/'Modify' the headers in the .xcframeworks file (more info here)~
    3. Remove the webp target and old .framework files
    4. Add the replacement .xcframeworks
    5. Remove the workaround in TIPXWebPCodec.m for importing the libraries
    6. Made a minor fix in the Swift Example App (related to some code that wasn't updated from #62 i think)
    7. Update the podspec and validate using pod spec lint

    What Next?

    Firstly, i'm not sure if you are happy just using the binaries that I have pushed in this PR.. Please feel free to download again from the link above and apply the modifications in step 2 yourself.

    Secondly, I from what I gather, Twitter might not use this repository directly internally so you might want to land this change in some other way? I've verified that all of the targets in the TwitterImagePipeline Xcode Project compile and run the tests as expected. I've also verified in my own project which uses both TIP and the WebP Codec via the CocoaPods integration that things work as expected!

    Thanks again! Please let me know if there is anything else that I can do to help

    opened by liamnichols 3
  • Please release 2.25.0 via CocoaPods

    Please release 2.25.0 via CocoaPods

    👋

    It looks like #62 introduced version 2.25.0 (the PR is titled incorrectly as 2.50.0) but this was never pushed to CocoaPods. Please could you tag master and push the release to CocoaPods 🙏

    opened by liamnichols 2
  • Detecting WebP via TIPDetectImageType and TIPDetectImageTypeFromFile?

    Detecting WebP via TIPDetectImageType and TIPDetectImageTypeFromFile?

    Hey! Hope you don't mind me bugging you about WebP related stuff even more? 😬

    I was looking at using TIPDetectImageTypeFromFile for convenience in my project (usage not directly related to the rest of TIP) and I noticed that prior to iOS 14, these methods aren't able to detect when a file or data is WebP.

    It's because these methods first attempt to use CGImageSourceRef to detect the type before falling back to magic number checks of the data however CoreGraphics in the iOS 13SDK doesn't recognise WebP as it wasn't added until the iOS 14 SDK (I've verified that it works when building with the 14SDK) and the TIPDetectImageTypeViaMagicNumbers magic number fallback only detects BPM, JPEG, GIF and PNG.

    Do you think it's worth updating this check to look for the WebP header/signature/magic numbers?

    I can relatively easily wrap and extend in my own code but I wasn't sure if other parts of the TIP project were expecting these methods to detect WebP or not?

    It's a little trickier to add support since the header also includes the file size (https://developers.google.com/speed/webp/docs/riff_container) so I'm not sure of the best way to adjust the existing code to support this but am happy to help and dig into it a little more if you think it's worth it?

    Let me know your thoughts, thanks!

    opened by liamnichols 1
  • Question: TIP vs PINRemoteImage

    Question: TIP vs PINRemoteImage

    Thanks for sharing TIP! Looks very very impressive!

    Currently, I use PINRemoteImage in my app (and enjoy it very much!). If I may, I wanted to ask the following:

    1. What were the reasons you felt that PINRemoteImage would not be good for the Twitter iOS app?
    2. What are the key differences to consider when choosing between both?

    Thanks again for sharing this library!

    question 
    opened by oferRounds 4
Releases(2.24.2)
  • 2.24.2(Oct 26, 2020)

  • 2.24.1(Oct 20, 2020)

  • 2.24.0(Aug 10, 2020)

    2.24.0

    • Drop iOS 8 and iOS 9 support

    2.23.5

    • Refactor WebP decoder to support animation decoding and improve efficiency
      • Requires WebPDemux.framework for iOS (the Catalyst lib already has the necessary bits)
      • The TIPXWebPCodec also supports progressive loading (rendering the first frame while more data is loading)
        • This makes it potentially a better choice as a decoder than the iOS 14+ built in decoder, depending on your use case
      • Improve decoder to support having static WebP images decode into the provided target sizing for better efficiency

    2.23.2

    • Update to WebP v1.1.0
      • Also fixes building WebP for Apple Silicon Catalyst builds

    2.23.1

    • Optimize the rendered cache unloading when clearMemoryCachesOnApplicationBackgroundEnabled is YES
      • When the app goes into the background, the rendered cache used to clear the oldest rendered images and just keep a max of 50% of the rendered cache capacity for when the app resumes
        • This was mostly effective for keeping the on screen images in cache avoiding any flashing UI, but had edge cases that could lead flashing or holding onto too much in memory that isn't needed for app resumes
      • Now, the rendered cache will turn each cache entry as weak and on app resume, these weak entries will be made strong again.
        • This will have the effect of all rendered cache images with no references being purged, but all those references being retained
        • Effectively, any UI that is holding the rendered images will keep those around for when the app resumes, making it seemless
        • For any UI that has unloaded its images when not visible, those images will be purged and will reload when the view becomes visible again
        • This works especially well with TIPImageViewFetchHelper when disappearanceBehavior is TIPImageViewDisappearanceBehaviorUnload or TIPImageViewDisappearanceBehaviorReplaceWithPlaceholder

    2.23.0

    • Replace TIPImageFetchProgressiveLoadingPolicy class methods with C functions
      • Swift does not like having an @interface have the same name as an @protocol
      • It can work, but gets very messy
      • Best to avoid it and replace the convenient class method interfaces in Objective-C with C functions
      • Though this is a minor version bump, it is API breaking
        • There isn't a way to deprecated the old APIs and introduce new ones, we just have to remove the old ones to fix usages in Swift
        • Apologies for the inconvenience!

    2.22.0

    • Add TIPImageFetchSkipStoringToRenderedCache to TIPImageFetchOptions
      • This permits a fetch to skip storing to the synchronous rendered cache altogether after a fetch
      • This is useful for UI that displays a large image but is not frequented regularly, such as a full screen image view
      • By avoiding infrequent images going to rendered cache, the rendered cache can keep more relevent images in cache (or can be configured to be smaller)
    • Add TIPImageViewDisappearanceBehaviorUnload to TIPImageViewDisappearanceBehavior
      • This new behavior will set the fetchView image to nil on disappearance
      • This new feature can really level up an app at keeping a memory footprint down automatically, no extra work is needed when using TIPImageViewFetchHelper for displaying images!
    • Add TIPImageViewDisappearanceBehaviorReplaceWithPlaceholder to TIPImageViewDisappearanceBehavior
      • This new behavior will set the fetchView image to a placeholder (low resolution) version on disappearance, which will be replace with the full image on visible return
      • Similar benefits to TIPImageViewDisappearanceBehaviorUnload but with the compromise of keeping a little more RAM for a placeholder to avoid UI situations that could yield an empty image view temporarily as the full image is decoded (notably for large images or slow devices)
    • Rename TIPImageViewFetchHelper class' fetchDisappearanceBehavior to disappearanceBehavior
    • Add shouldTreatApplicationBackgroundAsViewDisappearance property to TIPImageViewFetchHelper
      • This BOOL property will opt the fetch helper into using the disappearance behavior when the app backgrounds
      • Another big improvement for app memory footprint as the large amount of RAM used for images can be unloaded on app background, reducing the risk of the app being jettisoned!
      • Impact is really great for large images on screen when backgrounded, be sure to set to YES for your large image views!

    2.21.5

    • Adopt direct support for Objective-C code and eliminate PRIVATE_SELF C function pattern
      • Preserves Objective-C calling syntax for better code legibility (less C-style calls interleaving ObjC)
      • Safer than PRIVATE_SELF C functions (don't need to check self != nil)
      • Avoids awkward self->_ivar access in the direct methods (can stick with just using _ivar)
      • Same low binary overhead as private C functions

    2.21.0

    • Revise TIPError.h to be much more Swift compatible

    2.20.5

    • Revise WebP support by adding iOS 14 decoder and integrating that with existing TIPXWebPCodec
      • Also means Animated WebP are supported (decode only) on iOS 14+ now

    2.20.0

    • Fundamentally apply a rearchitecture to Twitter Image Pipeline
      • First: when loading images from data or files, the target sizing (dimensions & content mode) can now be used by codecs for more efficient decoding
        • This means that decoding a large image into a view port that is smaller can now decode directly into the appropriate size, reducing RAM and CPU of the decode AND avoiding needing to scale the image down before delivering the image as a result (more CPU savings)
        • This is implemented with the ImageIO based codecs, but not the extended codecs (WebP and MP4)...yet
      • Second: there are 3 caches in TIP: Rendered image cache, In Memory image cache, and On Disk image data cache.
        • The In Memory cache has been been restructured to cache the compressed image data instead of the image itself
        • This means:
          • Less RAM is needed for this middle cache
          • Less RAM is used when decoding the image to serve as a response
          • No more scaling the image from full size to the size to serve as a response (for core image codecs)
    • Given how substantial this change is, we are bumping from version 2.13 to 2.20
      • In particular, custom codecs will need to be updated to support the new targetDimensions and targetContentMode arguments
    Source code(tar.gz)
    Source code(zip)
  • 2.13.5(May 31, 2020)

    2.13.5

    • Add WebP support to Catalyst builds
      • See WEBP_README.md
    • Miscellaneous performance improvements
      • Async load the default codes to avoid main thread blockage on app launch
      • Tighter memory management with autorelease pools
      • TIPImageFetchHelper will now register for all image cache updates and filter on observation vs registering against specific pipelines, which avoids register/unregister locking performance impact
      • Add TIPDetectImageTypeFromFile(...) for efficient and effective image type detection from a file
    • Add replacements for UIImagePNGRepresentation and UIImageJPEGRepresentation
      • Unifies to the TIP codec based encoding rather than the UIKit implementation which can be unreliable for consistency.
      • Provides progressive support for JPEG variant of functionality.
      • See -[UIImage tip_PNGRepresentation] and -[UIImage tip_JPEGRepresentationWithQuality:progressive:]
    • Add some palette based image utilities
      • -[UIImage tip_canLosslesslyEncodeUsingIndexedPaletteWithOptions:]
    • Fix bug where a GIF load may be incomplete in response but complete in data loaded failing to load in TIP
      • Mostly an issue with some CDN vendors terminating the HTTP response incorrectly

    2.13.2

    • Add [TIPGlobalConfiguration defaultInterpolationQuality]
      • By default, will use CGInterpolationQualityDefault which is same behavior as before
      • Add quality arg to image scaling with [UIImage tip_scaledImageWithTargetDimensions:contentMode:interpolationQuality:decode:]

    2.13.1

    • Add [TIPImageFetchDelegate tip_imageFetchOperation:didLoadDirtyPreviewImage:] support
      • This allows for the rendered cache to mark a specific entry dirty (by identifier)
      • On fetch operation load, the dirty preview can be synchronously loaded while the op continues on async
      • This helps systems where a larger version of an image with a shared identifier loads and matching fetch helpers that are not visible in the UI take note in order to refresh with the better resolution image, but without the risk of clearing that image's render cache which can lead to a 1 or 2 frame "flash" of the image loading async from cache
    Source code(tar.gz)
    Source code(zip)
  • 2.12.2(Jun 4, 2019)

    2.12.2

    • Add automatic handling of unnecessary image download errors when the download has finished loading
      • It is not uncommon for a service/CDN to yield an error after the final byte of the response has been loaded by the client
      • The consequence of treating a successful load as a failure is that upon next fetch for that image an unnessecary network request will trigger:
        • For image resumption supported loads, resumes the load beyond the available byte range
        • For full image loads, a redundant download
      • When TIP sees an error on image download but has all the bytes (looking at Content-Length header), TIP now posts TIPProblemImageDownloadedWithUnnecessaryError problem

    Also

    • Fix a number of bugs
    • Add more util methods to UIImage category
    Source code(tar.gz)
    Source code(zip)
  • 2.12.1(Feb 21, 2019)

    • Fix bugs related to capping the sizes of caches
      • Capping a cache to 0 bytes would not completely disable it as documented, fixed
      • Setting the max ratio value to a negative value would not use the default value as documented, fixed
      • Thanks to @jml5qh for filing this issue (#41)
    • Analyzer warning fixes too (not actual bugs)
    Source code(tar.gz)
    Source code(zip)
  • 2.12.0(Jan 3, 2019)

  • 2.11.0(Oct 28, 2018)

    • add support for animated images with TIPImageViewFetchHelper by supporting TIPImageContainer as well as UIImage
      • to support animated images, implement a UIView that adopts TIPImageFetchable with tip_fetchedImageContainer that can animate the provided TIPImageContainer
      • update TIPImageFetchable
        • add tip_fetchedImageContainer as optional property
        • mark tip_fetchedImage as optional
        • require at least one of the two methods be implemented to conform to TIPImageFetchable
      • add helper functions:
        • TIPImageFetchableHasImage
        • TIPImageFetchableGetImage and TIPImageFetchableGetImageContainer
        • TIPImageFetchableSetImage and TIPImageFetchableSetImageContainer
      • update TIPImageViewFetchHelper
        • add setImageContainerAsIfLoaded:
        • add setImageContainerAsIfPlaceholder:
      • update TIPImageViewFetchHelperDataSource
        • add tip_imageContainerForFetchHelper:
      • update TIPImageViewFetchHelperDelegate
        • add tip_fetchHelper:didUpdateDisplayedImageContainer:fromSourceDimensions:isFinal:
        • deprecate tip_fetchHelper:didUpdateDisplayedImage:fromSourceDimensions:isFinal:
        • add tip_fetchHelper:shouldReloadAfterDifferentFetchCompletedWithImageContainer:dimensions:identifier:URL:treatedAsPlaceholder:manuallyStored:
        • deprecate tip_fetchHelper:shouldReloadAfterDifferentFetchCompletedWithImage:dimensions:identifier:URL:treatedAsPlaceholder:manuallyStored:
    • Move to Xcode 10
      • split unit tests up for parallelize builds (so much faster!!)
      • parallelize builds don't work with Travis CI, so they are disabled by default :(
    Source code(tar.gz)
    Source code(zip)
    TwitterImagePipeline_BuiltFrameworks_2.11.0.zip(10.47 MB)
  • 2.10.0(Aug 29, 2018)

  • 2.9.2(May 14, 2018)

    • Style updates
      • colon ':' align code
      • split code up more to fit on less horizontal space for easier code reviews
    • Replace private methods with static C functions
      • methods have runtime load overhead and binary size overhead
      • using methods for private code is wasteful to the framework consumer
      • replace all private methods with static C functions to reduce binary size and improve consuming app launch time perf (slightly)
      • Twitter Image Pipeline is being a good citizen for consuming apps, every little bit helps
    • Remove sample app xcscheme dependency of TIP framework for better Carthage support
      • Credit to: @brentleyjones
    • Move update to tip_fetchedImage in fetch helper so that the implementer of tip_fetchedImage can query the current state of the fetch helper at the time the update happens. Can help with animations.
      • Credit to: @brentleyjones
    • Optimize image scaling on iOS 10+ to use UIGraphicsImageRenderer
      • GraphicsRendererSpeed sample app added to validate perf
    • Added TIPRenderImage to TIPImageUtils
    • Added tip_imageWithRenderFormattings:render: to UIImage+TIPAdditions
    Source code(tar.gz)
    Source code(zip)
  • 2.9.0(Apr 6, 2018)

    • Fix race condition bug in downloader code
    • Move TIPImageViewFetchHelper to supporting UIView
    • Improve rendered cache
    • Wide gamut color support
    Source code(tar.gz)
    Source code(zip)
  • 2.7.2(Nov 20, 2017)

    2.7.2

    • improve TIPImageFetchTransformer support with optional identifier
      • was easy to get the rendered cache images mixed up between transformed and non-transformed fetches
      • now, transform requests can only fetch images from the rendered cache if there is a match with the tip_tranformerIdentifier
      • transformers that don't provide an identifier cannot be cached nor retrieved from the rendered cache
    • removed transformer from TIPGlobalConfiguration (would interfere with above improvement)

    2.7.1

    • add generic concrete class for TIPImageFetchRequest as convenience
      • generic fetch request is mutable/immutable pair: TIPGenericImageFetchRequest and TIPMutableGenericImageFetchRequest

    2.7.0

    • add decoder config support
      • enables custom TIPImageDecoder implementations to have configurable ways of being decoded
    • add memory map loading option for images
      • default continues to not use memory map loading, but it's now exposed on TIPImageContainer
    • add MP4 decoder to TIP (as an extended decoder, not bundled by default)
      • decodes MP4s as animated images

    2.6.0

    • Remove TIPImageView, just use UIImageView category instead
      • Add hidden property support to UIImageView fetch helper category
    • Remove TIPImageViewFetchHelper subclassing event methods
      • Use delegate pattern for eventing instead of polymorphism #Simplify
    • Remove setViewHidden: method for TIPImageViewFetchHelper
      • It never did what it was advertised to do and muddied the control flow
    • Add fetchResultDimensions to TIPImageViewFetchHelper for more insight into results

    (Also, lots of bug fixes and performance improvements)

    Source code(tar.gz)
    Source code(zip)
  • 2.5.0(Aug 9, 2017)

    • reduce thread count for TIP by unifying all disk caches to using 1 manifest queue
      • make disk cache manifest load async instead of sync now that it is shared
      • no real speed improvements, just fewer threads need to be used in multi-pipeline apps
    • clean up some large inline functions to be regular functions
    • Remove detached downloads support for TIP image fetches
      • using HTTP/2 is the ideal solution, removing the complexity to remove the crutch
    • other miscellaneous minor improvements
    Source code(tar.gz)
    Source code(zip)
  • 2.4.4(Jun 27, 2017)

    • update ImageSpeedComparison sample
    • clean up nullability all over
    • image transform support
    • image view fetch helper category for UIImageView
      • added by Brandon Carpenter
    • add support to change cached image's identifier
    • update WebP codec (0.6.0)
    • fixe WebP codec
      • added by protosphere
    • other misc bug fixes
    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Apr 27, 2017)

    • Reduce memory pressure w/ @autoreleasepool blocks on GCD queues in TIP
    • Add "problem" for images not caching because they are too large
    • Add "problem" when downloaded image cannot be decoded
    • Add Animated PNG support (iOS 8+)
    • Add the store operation as an argument to TIPImagePipelineStoreCompletionBlock
    • Tightened up some threading race conditions that cropped up with the thread sanitizer
    • Fix edge case where memory cache can exceed max cache size
    • Other miscellaneous fixes
    • update to Xcode 8.3
    Source code(tar.gz)
    Source code(zip)
Owner
Twitter
Twitter 💙 #opensource
Twitter
Advanced framework for loading, caching, processing, displaying and preheating images.

Advanced framework for loading, caching, processing, displaying and preheating images. This framework is no longer maintained. Programming in Swift? C

Alexander Grebenyuk 1.2k Dec 23, 2022
🚀SwiftUI Image downloader with performant LRU mem/disk cache.

Progressive concurrent image downloader for SwiftUI, with neat API and performant LRU mem/disk cache.

Cheng Zhang 42 Sep 24, 2022
A thread safe, performant, feature rich image fetcher

PINRemoteImage Fast, non-deadlocking parallel image downloader and cache for iOS PINRemoteImageManager is an image downloading, processing and caching

Pinterest 4k Jan 9, 2023
An extremely high-performance, lightweight, and energy-efficient pure Swift async web image loader with memory and disk caching for iOS and  Watch.

KFSwiftImageLoader KFSwiftImageLoader is an extremely high-performance, lightweight, and energy-efficient pure Swift async web image loader with memor

Kiavash Faisali 343 Oct 29, 2022
🍁🥓 Lightweight and fast Swift library for image downloading, caching and transformations

MapleBacon Introduction MapleBacon is a lightweight and fast Swift library for downloading and caching images. Example The folder Example contains a s

Jan Gorman 335 Nov 1, 2022
A high-performance image library for downloading, caching, and processing images in Swift.

Features Asynchronous image downloader with priority queuing Advanced memory and database caching using YapDatabase (SQLite) Guarantee of only one ima

Yap Studios 72 Sep 19, 2022
XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage

XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage. An illustration is shown below: Features Plays m

Khaled Taha 561 Sep 9, 2022
A simple, performant, and lightweight SVG parser

Key Features Parsing performance that meets or beats other popular SVG Frameworks A simple architecture, optimized for extension, flexibility and deve

Michael Choe 1.8k Dec 29, 2022
SwiftUI Image loading and Animation framework powered by SDWebImage

SDWebImageSwiftUI What's for SDWebImageSwiftUI is a SwiftUI image loading framework, which based on SDWebImage. It brings all your favorite features f

null 1.6k Jan 6, 2023
A pure Swift high-performance asynchronous image loading framework. SwiftUI supported.

Longinus Longinus is a pure-Swift high-performance asynchronous web image loading,caching,editing framework. It was learned from Objective-C web image

Qitao Yang 290 Dec 17, 2022
Asynchronous image loading framework.

YYWebImage YYWebImage is an asynchronous image loading framework (a component of YYKit). It was created as an improved replacement for SDWebImage, PIN

null 3.5k Dec 27, 2022
EbImagesSwiftUI - SDWebImageSwiftUI - a SwiftUI image loading framework, which based on SDWebImage

SDWebImageSwiftUI What's for SDWebImageSwiftUI is a SwiftUI image loading framew

An Tran 1 Jan 6, 2022
LCWebImage - An asynchronous image loading framework based on AFNetworking.

LCWebImage is an asynchronous image loading framework based on AFNetworking, which supports memory and disk caching, and provides functions such as custom caching, custom image decoding, and custom network configuration.

LiuChang 27 Jul 23, 2022
Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web

Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web. It provides you a chance to use a pure-Swift way to work

Wei Wang 20.9k Dec 30, 2022
A Swift/SwiftUI utility for caching and displaying images in SwiftUI Views

A Swift/SwiftUI utility for caching and displaying images asynchronously. Built with Swift 5.5 and works with async/await.

王雪铮 Xuezheng Wang 1 May 5, 2022
Focus on avatar caching.

Navi Navi is designed for avatar caching, with style. The name of Navi from movie Avatar. Requirements Swift 3.1, iOS 8.0 Swift 2.3, use version 0.5.0

null 114 Jun 30, 2022
Slide image viewer library similar to Twitter and LINE.

Overview You can use it simply by passing the necessary information! Serrata is a UI library that allows you to intuitively view images. Features King

Takuma Horiuchi 324 Dec 9, 2022
An image viewer à la Twitter

For the latest changes see the CHANGELOG Install CocoaPods pod 'ImageViewer' Carthage github "Krisiacik/ImageViewer" Sample Usage For a detailed examp

Kristian Angyal 2.4k Dec 29, 2022
Lightweight and customisable async image loading in SwiftUI. Supports on-disk storage, placeholders and more!

Asyncrounously download and display images in Swift UI. Supports progress indicators, placeholders and image transitions. RemoteImageView Asyncrounous

Callum Trounce 192 Dec 7, 2022