A Swift implementation of fastimage. Supports PNG, GIF, and JPEG.

Overview

Logo

ImageScout

Test GitHub release Swift 5.0 platforms

ImageScout is a Swift implementation of fastimage. It allows you to find the size and type of a remote image by downloading as little as possible.

Why?

Sometimes you need to know the size of a remote image before downloading it, such as using a custom layout in a UICollectionView.

How?

ImageScout parses the image data as it is downloaded. As soon as it finds out the size and type of image, it stops the download. The downloaded data is below 60 KB in most cases.

Install

Swift Package Manager

Add the following to your Package.switft file:

let package = Package(
    dependencies: [
    .package(url: "https://github.com/kaishin/ImageScout.git", from: "2.1.0")
    ],
)

Carthage

  • Add the following to your Cartfile: github "kaishin/ImageScout"
  • Then run carthage update
  • Follow the current instructions in Carthage's README for up to date installation instructions.

CocoaPods

  • Add the following to your Podfile: pod 'ImageScout'
  • You will also need to make sure you're opting into using frameworks: use_frameworks!
  • Then run pod install with CocoaPods 1.0 or newer.

Usage

The only method you will be using is scoutImageWithURI(), with the following full signature:

func scoutImageWithURI(URI: String, completion: (NSError?, CGSize, ScoutedImageType) -> ())

Here's an example:

let scout = ImageScout()

scout.scoutImageWithURI("http://.../image-scout-logo.png") { error, size, type in
  if let error = error {
    print(error.code)
  } else {
    print("Size: \(size)")
    print("Type: \(type.rawValue)")
  }
}

If the image is not successfully parsed, the size is going to be CGSizeZero and the type .Unsupported. The error will contain more info about the reason:

  • Error code 100: Invalid URI parameter.
  • Error code 101: Image is corrupt or malformatted.
  • Error code 102: Not an image or unsopported image format URL.

⚠️ It's important to keep a strong reference to the ImageScout instance until the callback completes. If reference is lost, your completion handler will never be executed.

Compatibility

  • Swift 5 / Xcode 11
  • iOS 8+
  • macOS 10.11

License

See LICENSE.

Comments
  • Didnot  have any message  in output window

    Didnot have any message in output window

    let scout = ImageScout()

        scout.scoutImageWithURI("http://f.hiphotos.baidu.com/zhidao/pic/item/5d6034a85edf8db16efebe470b23dd54574e74c5.jpg") { error, size, type in
            if let unwrappedError = error {
                print(unwrappedError.code)
            } else {
                print("Size: \(size)")
                print("Type: \(type.rawValue)")
            }
        }
    
    opened by yanglichuan 2
  • Currently tail recursion is not guaranteed in Swift

    Currently tail recursion is not guaranteed in Swift

    This is especially problematic in Debug mode, where no tail recursion exists! I found this when some JPEGs crashed my App. This could also easily be used as an attack vector with specially crafted data.

    My Solution for parsing JPEGs is to translate the parse function into a looped version:

    private typealias JPEGParseTuple = (data: NSData, offset: Int, segment: JPEGHeaderSegment)
    
    private enum JPEGParseResult {
        case Size(CGSize)
        case Tuple(JPEGParseTuple)
    }
    
    private static func parseJPEG(tuple: JPEGParseTuple) -> JPEGParseResult {
        let data = tuple.data
        let offset = tuple.offset
        let segment = tuple.segment
    
        if segment == .EOISegment
            || (data.length <= offset + 1)
            || (data.length <= offset + 2) && segment == .SkipSegment
            || (data.length <= offset + 7) && segment == .ParseSegment {
                return .Size(CGSizeZero)
        }
        switch segment {
        case .NextSegment:
            let newOffset = offset + 1
            var byte = 0x0; data.getBytes(&byte, range: NSRange(location: newOffset, length: 1))
    
            if byte == 0xFF {
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .SOFSegment))
            } else {
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .NextSegment))
            }
        case .SOFSegment:
            let newOffset = offset + 1
            var byte = 0x0; data.getBytes(&byte, range: NSRange(location: newOffset, length: 1))
    
            switch byte {
            case 0xE0...0xEF:
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .SkipSegment))
            case 0xC0...0xC3, 0xC5...0xC7, 0xC9...0xCB, 0xCD...0xCF:
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .ParseSegment))
            case 0xFF:
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .SOFSegment))
            case 0xD9:
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .EOISegment))
            default:
                return .Tuple(JPEGParseTuple(data, offset: newOffset, segment: .SkipSegment))
            }
    
        case .SkipSegment:
            var length = UInt16(0)
            data.getBytes(&length, range: NSRange(location: offset + 1, length: 2))
    
            let newOffset = offset + Int(CFSwapInt16(length)) - 1
            return .Tuple(JPEGParseTuple(data, offset: Int(newOffset), segment: .NextSegment))
    
        case .ParseSegment:
            var size = JPEGSize(); data.getBytes(&size, range: NSRange(location: offset + 4, length: 4))
            return .Size(CGSize(width: Int(CFSwapInt16(size.width)), height: Int(CFSwapInt16(size.height))))
        default:
            return .Size(CGSizeZero)
        }
    
    }
    
    private static func parseJPEGData(data: NSData, offset: Int, segment: JPEGHeaderSegment) -> CGSize {
        var tuple: JPEGParseResult = .Tuple(JPEGParseTuple(data, offset: offset, segment: segment))
        while true {
            switch tuple {
            case .Size(let size):
                return size
            case .Tuple(let newTuple):
                tuple = parseJPEG(newTuple)
            }
        }
    }
    
    opened by jazzbox 2
  • Complete Swift 3 Upgrade

    Complete Swift 3 Upgrade

    👋

    I finished the upgrade to Swift 3 with minor code changes. I let XCode change a few things regarding new compiler warnings and removing code signing for frameworks, but can undo that if it's a problem.

    opened by sidraval 1
  • Error in ios 9.3

    Error in ios 9.3

    Hi, i use IOS 9.3 and the log not print anithing

    let scout = ImageScout()

    scout.scoutImageWithURI("http://.../image-scout-logo.png") { error, size, type in if let unwrappedError = error { println(unwrappedError.code) } else { println("Size: (size)") println("Type: (type.rawValue)") } }

    opened by ghost 1
  • Build failure on  Carthage

    Build failure on Carthage

    with error code: The following build commands failed: CompileSwift normal arm64 /Users/BourneWang/Desktop/ImageScout-master/Demo/Carthage/Checkouts/ImageScout/Source/ImageScout.swift CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler (2 failures)

    opened by skywalkerlw 1
  • error to run demo on device(iPhone5S)

    error to run demo on device(iPhone5S)

    with error: dyld: Library not loaded: @rpath/ImageScout.framework/ImageScout Referenced from: /private/var/mobile/Containers/Bundle/Application/F9A9E333-019B-46B8-8DA9-CA5B4437D2C3/Demo.app/Demo Reason: image not found

    opened by skywalkerlw 1
  • Separate framework from example project

    Separate framework from example project

    Separate out the source of the ImageScout library from the tests and example code. This way someone could still copy the source code into their own project if they wanted, but now it can also support Carthage and Cocoapods.

    opened by tonyd256 0
Releases(v3.0-beta)
Owner
Reda Lemeden
Developer/Designer based in Stockholm.
Reda Lemeden
Rudimentary implementation of a uncompressed PNG encoder in Swift without any dependencies

MicroPNG This package currently offers a very minimal PNG encoder for uncompressed RGB and RGBA PNG files. It does not rely on any frameworks and shou

Robert Bruinier 2 Sep 11, 2021
IconsMaker - Create your app icon with SwiftUI and generate PNG images in all needed sizes

IconsMaker - Create your app icon with SwiftUI and generate PNG images in all needed sizes

Jonathan Gander 14 Oct 20, 2022
Convert HEIC images to JPEG format on the Mac

heic2jpeg Convert HEIC images to JPEG format on the Mac A basic tool to convert Apple's obnoxious HEIC format images (as the default photo format for

Fazal Majid 2 Mar 1, 2022
iOS SDK to share JPEG images with an expiration date

Ebblink iOS SDK A library to integrate Ebblink private image sharing capabilities into your iOS app. Table of Contents Getting Started Requirements Se

null 4 Apr 6, 2018
DGImageView - Asynchronous image downloader with cache. Supports gif too

DGImageView Installation Usage DGImageView Asynchronous image downloader with cache. Supports gif, memory cache, disk cache features. Installation Xco

donggyu 1 Jan 1, 2022
Media view which subclasses UIImageView, and can display & load images, videos, GIFs, and audio and from the web, and has functionality to minimize from fullscreen, as well as show GIF previews for videos.

I've built out the Swift version of this library! Screenshots Description ABMediaView can display images, videos, as well as now GIFs and Audio! It su

Andrew Boryk 80 Dec 20, 2022
An app show your Live Photo and export as GIF.

LivelyGIFs Show your Live Photo and export as GIF. Demo HighLights Do not use Pod or Cathage to install 3rd party library Simple logic, new learner fr

Xue Yu 95 Jun 24, 2022
High-performance animated GIF support for iOS in Swift

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan). Install Swift Package Manager Add the fo

Reda Lemeden 2.6k Jun 21, 2021
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
Gifu adds protocol-based, performance-aware animated GIF support to UIKit.

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan). Install Swift Package Manager Add the fo

Reda Lemeden 2.8k Jan 7, 2023
SwiftGif - A small UIImage extension with gif support.

SwiftGif - A small UIImage extension with gif support.

SwiftGif 1.3k Dec 20, 2022
High performance GIF engine

SwiftyGif High performance & easy to use Gif engine Features UIImage and UIImageView extension based Remote GIFs with customizable loader Great CPU/Me

Alexis Creuzot 1.7k Jan 3, 2023
Drop in GIF Collection View. Uses Tenor as default GIFs provider.

Drop in GIF Collection View. Uses Tenor as default GIFs provider. This will allow you to easily integrate GIF image search into your app or you can use this as a GIF keyboard for your messaging needs.

null 5 May 7, 2022
A tool support convert image gif to gif3d

Trick convert gif to gif3d using Swift Features Simple way to convert gif to gif3d Change background Change size eraser tool How to work Add a layer w

Chuong Tran 16 Jan 4, 2023
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
A simple and flexible way to add source of overlapping circular pictures, currently supports horizontal overlapping or distant pictures with great layout flexibility.

THIS PROJECT IS NO LONGER MAINTAINED. STILL ONE ONLY BEST UI SOLUTION FOR UIKIT DEVELOPERS. SOON WILL COME UP WITH SWIFTUI STILL CONTRIBUTORS ARE WELC

Kiran Jasvanee 673 Dec 19, 2022
A beautiful and flexible text field control implementation of "Float Label Pattern". Written in Swift.

SkyFloatingLabelTextField SkyFloatingLabelTextField is a beautiful, flexible and customizable implementation of the space saving "Float Label Pattern"

Skyscanner 4k Jan 3, 2023
BeatboxiOS - A sample implementation for merging multiple video files and/or image files using AVFoundation

MergeVideos This is a sample implementation for merging multiple video files and

null 3 Oct 24, 2022
An implementation of High Pass Skin Smoothing using Apple's Core Image Framework

YUCIHighPassSkinSmoothing An implementation of High Pass Skin Smoothing using CoreImage.framework Available on both OS X and iOS. Ports A MetalPetal b

Yu Ao 1.2k Dec 17, 2022