Skip to content

Commit

Permalink
Support for getting avasset image
Browse files Browse the repository at this point in the history
  • Loading branch information
onevcat committed Aug 11, 2020
1 parent a4ddbca commit 933cc88
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 0 deletions.
56 changes: 56 additions & 0 deletions Demo/Demo/Kingfisher-Demo/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,30 @@
<segue destination="WgT-E0-jsn" kind="show" id="Sgu-eB-5JV"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="2c2-O7-4OG">
<rect key="frame" x="0.0" y="468" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2c2-O7-4OG" id="Mjl-hg-ebT">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AVAsset Image Generator" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I8e-FH-QjH">
<rect key="frame" x="20" y="11.666666666666664" width="194.66666666666666" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="I8e-FH-QjH" secondAttribute="trailing" constant="20" symbolic="YES" id="KjO-7Q-h0u"/>
<constraint firstItem="I8e-FH-QjH" firstAttribute="leading" secondItem="Mjl-hg-ebT" secondAttribute="leading" constant="20" symbolic="YES" id="Nib-u8-NUb"/>
<constraint firstItem="I8e-FH-QjH" firstAttribute="centerY" secondItem="Mjl-hg-ebT" secondAttribute="centerY" id="s3P-9n-qo8"/>
</constraints>
</tableViewCellContentView>
<connections>
<segue destination="m5P-35-yHH" kind="show" id="iY4-PO-rZO"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
Expand Down Expand Up @@ -828,6 +852,38 @@
</objects>
<point key="canvasLocation" x="2654" y="1061"/>
</scene>
<!--Asset Image Generator View Controller-->
<scene sceneID="PCw-9j-oCu">
<objects>
<viewController id="m5P-35-yHH" customClass="AVAssetImageGeneratorViewController" customModule="Kingfisher_Demo" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Hqg-bo-3DO">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="lTP-vt-DdF">
<rect key="frame" x="87" y="94" width="240" height="240"/>
<constraints>
<constraint firstAttribute="height" constant="240" id="PRd-E7-RiS"/>
<constraint firstAttribute="width" constant="240" id="sQj-Or-zGO"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="kpf-7x-2lo"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="lTP-vt-DdF" firstAttribute="centerX" secondItem="kpf-7x-2lo" secondAttribute="centerX" id="2MT-0R-oyk"/>
<constraint firstItem="lTP-vt-DdF" firstAttribute="top" secondItem="kpf-7x-2lo" secondAttribute="top" constant="50" id="mff-5v-1Z1"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="7AD-kL-ZIP"/>
<connections>
<outlet property="imageView" destination="lTP-vt-DdF" id="fk4-PV-mkj"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Idc-Kb-7jc" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1850.7246376811595" y="1735.5978260869567"/>
</scene>
</scenes>
<resources>
<systemColor name="secondaryLabelColor">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// AVAssetImageGeneratorViewController.swift
// Kingfisher
//
// Created by onevcat on 2020/08/09.
//
// Copyright (c) 2020 Wei Wang <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import UIKit
import AVKit
import Kingfisher

class AVAssetImageGeneratorViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()

let url = URL(string: "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1280_10MG.mp4")!
let asset = AVAsset(url: url)
let generator = AVAssetImageGenerator(asset: asset)
let provider = AVAssetImageDataProvider(
assetImageGenerator: generator,
time: CMTime(seconds: 14, preferredTimescale: 1)
)
imageView.kf.setImage(with: provider) { r in
print(r)
}
}
}
4 changes: 4 additions & 0 deletions Demo/Kingfisher-Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
D12EB83E24DD902300329EE1 /* TextAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12EB83D24DD902300329EE1 /* TextAttachmentViewController.swift */; };
D12EB84024DDB9E100329EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D12EB83F24DDB9E000329EE1 /* LaunchScreen.storyboard */; };
D1679A461C4E78B20020FD12 /* Kingfisher-watchOS-Demo Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D1679A451C4E78B20020FD12 /* Kingfisher-watchOS-Demo Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D16CC3D824E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D16CC3D724E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift */; };
D1A1CCA321A1879600263AD8 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A1CCA221A1879600263AD8 /* MainViewController.swift */; };
D1A1CCA721A18A3200263AD8 /* UIViewController+KingfisherOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A1CCA621A18A3200263AD8 /* UIViewController+KingfisherOperation.swift */; };
D1A1CCA821A18A3200263AD8 /* UIViewController+KingfisherOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A1CCA621A18A3200263AD8 /* UIViewController+KingfisherOperation.swift */; };
Expand Down Expand Up @@ -200,6 +201,7 @@
D16218A4238EAA67004A1C6C /* Kingfisher-Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Kingfisher-Demo.entitlements"; sourceTree = "<group>"; };
D1679A391C4E78B20020FD12 /* Kingfisher-watchOS-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Kingfisher-watchOS-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D1679A451C4E78B20020FD12 /* Kingfisher-watchOS-Demo Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Kingfisher-watchOS-Demo Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
D16CC3D724E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVAssetImageGeneratorViewController.swift; sourceTree = "<group>"; };
D1A1CCA221A1879600263AD8 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
D1A1CCA621A18A3200263AD8 /* UIViewController+KingfisherOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+KingfisherOperation.swift"; sourceTree = "<group>"; };
D1CE1BCF21A1AFA300419000 /* TransitionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitionViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -389,6 +391,7 @@
D1E4CF5321BACBA6004D029D /* ImageDataProviderCollectionViewController.swift */,
C959EEE522874DC600467A10 /* ProgressiveJPEGViewController.swift */,
D12EB83D24DD902300329EE1 /* TextAttachmentViewController.swift */,
D16CC3D724E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
Expand Down Expand Up @@ -732,6 +735,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D16CC3D824E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift in Sources */,
C959EEE622874DC600467A10 /* ProgressiveJPEGViewController.swift in Sources */,
D1CE1BD321A1B45A00419000 /* ImageLoader.swift in Sources */,
D12EB83E24DD902300329EE1 /* TextAttachmentViewController.swift in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions Kingfisher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
D12E0C581C47F23500AC98AD /* UIButtonExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */; };
D12EB83C24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12EB83B24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift */; };
D13646742165A1A100A33652 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13646732165A1A100A33652 /* Result.swift */; };
D16CC3D624E02E9500F1A515 /* AVAssetImageDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D16CC3D524E02E9500F1A515 /* AVAssetImageDataProvider.swift */; };
D16FEA3A23078C63006E67D5 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = D16FE9F623078C63006E67D5 /* LICENSE */; };
D16FEA3B23078C63006E67D5 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = D16FE9F723078C63006E67D5 /* README.md */; };
D16FEA3C23078C63006E67D5 /* LSStubRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = D16FE9FA23078C63006E67D5 /* LSStubRequest.m */; };
Expand Down Expand Up @@ -187,6 +188,7 @@
D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExtensionTests.swift; sourceTree = "<group>"; };
D12EB83B24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextAttachment+Kingfisher.swift"; sourceTree = "<group>"; };
D13646732165A1A100A33652 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
D16CC3D524E02E9500F1A515 /* AVAssetImageDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVAssetImageDataProvider.swift; sourceTree = "<group>"; };
D16FE9F623078C63006E67D5 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
D16FE9F723078C63006E67D5 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
D16FE9FA23078C63006E67D5 /* LSStubRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LSStubRequest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -627,6 +629,7 @@
D1A1CC99219FAB4B00263AD8 /* Source.swift */,
D12AB69E215D2BB50013BA68 /* Resource.swift */,
D1E56444219B16330057AAE3 /* ImageDataProvider.swift */,
D16CC3D524E02E9500F1A515 /* AVAssetImageDataProvider.swift */,
);
path = ImageSource;
sourceTree = "<group>";
Expand Down Expand Up @@ -813,6 +816,7 @@
D12AB6E4215D2BB50013BA68 /* Placeholder.swift in Sources */,
4B46CC6921744AC500D90C4A /* DiskStorage.swift in Sources */,
4B46CC5F217449C600D90C4A /* MemoryStorage.swift in Sources */,
D16CC3D624E02E9500F1A515 /* AVAssetImageDataProvider.swift in Sources */,
D1839845216E333E003927D3 /* Delegate.swift in Sources */,
D12AB6D8215D2BB50013BA68 /* ImageTransition.swift in Sources */,
D1A37BE8215D365A009B39B7 /* ExtensionHelpers.swift in Sources */,
Expand Down
94 changes: 94 additions & 0 deletions Sources/General/ImageSource/AVAssetImageDataProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// AVAssetImageDataProvider.swift
// Kingfisher
//
// Created by onevcat on 2020/08/09.
//
// Copyright (c) 2020 Wei Wang <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation
import AVKit
import MobileCoreServices

public struct AVAssetImageDataProvider: ImageDataProvider {

public enum AVAssetImageDataProviderError: Error {
case userCancelled
case invalidImage(_ image: CGImage?)
}

public let assetImageGenerator: AVAssetImageGenerator
public let time: CMTime

private var internalKey: String {
return (assetImageGenerator.asset as? AVURLAsset)?.url.absoluteString ?? UUID().uuidString
}

public var cacheKey: String {
return "\(internalKey)_\(time.value)"
}

public init(assetImageGenerator: AVAssetImageGenerator, time: CMTime) {
self.assetImageGenerator = assetImageGenerator
self.time = time
}

public init(assetURL: URL, time: CMTime) {
let asset = AVAsset(url: assetURL)
let generator = AVAssetImageGenerator(asset: asset)
self.init(assetImageGenerator: generator, time: time)
}

public func data(handler: @escaping (Result<Data, Error>) -> Void) {
assetImageGenerator.generateCGImagesAsynchronously(forTimes: [NSValue(time: time)]) {
(requestedTime, image, imageTime, result, error) in
if let error = error {
handler(.failure(error))
return
}

if result == .cancelled {
handler(.failure(AVAssetImageDataProviderError.userCancelled))
return
}

guard let cgImage = image, let data = cgImage.jpegData else {
handler(.failure(AVAssetImageDataProviderError.invalidImage(image)))
return
}

handler(.success(data))
}
}
}

extension CGImage {
var jpegData: Data? {
guard let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, kUTTypeJPEG, 1, nil)
else {
return nil
}
CGImageDestinationAddImage(destination, self, nil)
guard CGImageDestinationFinalize(destination) else { return nil }
return mutableData as Data
}
}

0 comments on commit 933cc88

Please sign in to comment.