├── UIImage+PDF.zip
├── Swift Image+PDF
├── animalsCat.pdf
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── UIImage+PDF
│ ├── UIView+Image.swift
│ ├── UIPDFView.swift
│ ├── PDFResourceHelper.swift
│ └── UIImage+PDF.swift
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── AppDelegate.swift
└── ViewController.swift
├── Swift Image+PDF.xcodeproj
├── xcuserdata
│ └── rb.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── Swift Image+PDF.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── rb.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── Swift Image+PDF.xcscmblueprint
└── project.pbxproj
└── README.md
/UIImage+PDF.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RomanBambura/Swift-UIImage-PDF/HEAD/UIImage+PDF.zip
--------------------------------------------------------------------------------
/Swift Image+PDF/animalsCat.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RomanBambura/Swift-UIImage-PDF/HEAD/Swift Image+PDF/animalsCat.pdf
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/xcuserdata/rb.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/project.xcworkspace/xcuserdata/rb.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RomanBambura/Swift-UIImage-PDF/HEAD/Swift Image+PDF.xcodeproj/project.xcworkspace/xcuserdata/rb.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/xcuserdata/rb.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Swift Image+PDF.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 319AD2AF1C802CBC003845A4
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Swift Image+PDF/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/Swift Image+PDF/UIImage+PDF/UIView+Image.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Image.swift
3 | // WAPersonal
4 | //
5 | // Created by Roman Bambura on 2/25/16.
6 | // Copyright © 2016 Roman Bambura. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 |
13 | var imageShot: UIImage{
14 |
15 | get{
16 | //self.layer.shouldRasterize = true
17 |
18 | //print(self.contentScaleFactor)
19 | //UIGraphicsBeginImageContextWithOptions( self.bounds.size, false, self.contentScaleFactor)
20 |
21 | UIGraphicsBeginImageContextWithOptions( self.bounds.size, false, 3)
22 | self.layer.render(in: UIGraphicsGetCurrentContext()!)
23 | let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!;
24 | UIGraphicsEndImageContext();
25 | return image;
26 | }
27 | }
28 |
29 |
30 |
31 | func savePNG(_ filePath: String){
32 | if let data = UIImagePNGRepresentation(self.imageShot){
33 | try? data.write(to: URL(fileURLWithPath: filePath), options: [.atomic])
34 | }
35 | }
36 |
37 |
38 | func saveJPEG(_ filePath: String, quality:CGFloat){
39 | if let data = UIImageJPEGRepresentation(self.imageShot, quality){
40 | try? data.write(to: URL(fileURLWithPath: filePath), options: [])
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Swift Image+PDF/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Swift Image+PDF/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Swift Image+PDF/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/project.xcworkspace/xcshareddata/Swift Image+PDF.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "A066FFF00290EBA4EC1E72C6FF51C9DEBB1D46B0",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "A066FFF00290EBA4EC1E72C6FF51C9DEBB1D46B0" : 0,
8 | "F0F16AFC1EEA4EE9481A6656D286995C37BA90C6" : 0
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "A5A39272-10E8-494C-9708-4A6B438AF1EF",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "A066FFF00290EBA4EC1E72C6FF51C9DEBB1D46B0" : "Swift-UIImage-PDF\/",
13 | "F0F16AFC1EEA4EE9481A6656D286995C37BA90C6" : ""
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "Swift Image+PDF",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Swift Image+PDF.xcodeproj",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/RomanBambura\/Swift-UIImage-PDF.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A066FFF00290EBA4EC1E72C6FF51C9DEBB1D46B0"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/RomanBambura\/Swift-Image-PDF.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F0F16AFC1EEA4EE9481A6656D286995C37BA90C6"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/Swift Image+PDF/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Swift Image+PDF
4 | //
5 | // Created by Roman Bambura on 2/26/16.
6 | // Copyright © 2016 Roman Bambura. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Swift Image+PDF/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Swift Image+PDF
4 | //
5 | // Created by Roman Bambura on 2/26/16.
6 | // Copyright © 2016 Roman Bambura. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view, typically from a nib.
16 |
17 | // UIView From PDF Use UIPDFView For perfect image sharpness animation
18 | let pdfView = UIPDFView(withName: "animalsCat", frame: CGRect(x: 10, y: 20, width: 100, height: 100) )
19 | pdfView.backgroundColor = UIColor.clear
20 | view.addSubview(pdfView)
21 |
22 |
23 | // UIImages From PDF With Disc Cache user/Documents/CachedAssets/
24 | // file will be cached with name animalsCat_100X100@2x // scale 2
25 | // animalsCat_100X100@1x // scale 1
26 |
27 | // Size To Fit
28 | if let pdfImage: UIImage = UIImage.imageWithPDFNamed("animalsCat", fitSize: CGSize(width:100, height:100)){
29 |
30 | let pdfImageView: UIImageView = UIImageView(image: pdfImage)
31 | pdfImageView.center = CGPoint(x:200, y:200)
32 |
33 | view.addSubview(pdfImageView)
34 | }
35 |
36 |
37 | if let pdfImage2: UIImage = UIImage.imageWithPDFNamed("animalsCat", size: CGSize(width:80, height:80)){
38 |
39 | let pdfImageView2: UIImageView = UIImageView(image: pdfImage2)
40 | pdfImageView2.center = CGPoint(x:200, y:290)
41 |
42 | view.addSubview(pdfImageView2)
43 | }
44 |
45 | // With Width
46 | if let pdfImage3: UIImage = UIImage.imageWithPDFNamed("animalsCat", width: 70){
47 |
48 | let pdfImageView3: UIImageView = UIImageView(image: pdfImage3)
49 | pdfImageView3.center = CGPoint(x:200, y:380)
50 |
51 | view.addSubview(pdfImageView3)
52 | }
53 |
54 | // With Height
55 | if let pdfImage4: UIImage = UIImage.imageWithPDFNamed("animalsCat", height: 40){
56 |
57 | let pdfImageView4: UIImageView = UIImageView(image: pdfImage4)
58 | pdfImageView4.center = CGPoint(x:200, y:440)
59 |
60 | view.addSubview(pdfImageView4)
61 | }
62 | }
63 |
64 | override func didReceiveMemoryWarning() {
65 | super.didReceiveMemoryWarning()
66 | // Dispose of any resources that can be recreated.
67 | }
68 |
69 |
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UIImage+PDF Swift
2 | UIImage+PDF provides a UIImage class category method to render a UIImage from any PDF stored in the application bundle. The motivation for this was to enable the easy use of scaleable vector assets in Swift iOS apps.
3 |
4 | #Usage
5 | Add the sources files in the UIImage+PDF sub folder to your project.
6 |
7 | # UIPDFView
8 | Use UIPDFView for animation
9 | ```swift
10 | UIPDFView(name: String, frame: CGRect)
11 |
12 | Sample:
13 | let pdfView = UIPDFView(name: "animalsCat", frame: CGRectMake(10, 20, 100, 100))
14 | pdfView.backgroundColor = UIColor.clearColor()
15 | view.addSubview(pdfView)
16 | ```
17 |
18 | # UIImage
19 | PDF asset name used without extension
20 |
21 | Sample:
22 | ```swift
23 | if let pdfImage: UIImage = UIImage.imageWithPDFNamed("animalsCat", fitSize: CGSizeMake(100, 100)){
24 |
25 | let pdfImageView: UIImageView = UIImageView(image: pdfImage)
26 | pdfImageView.center = CGPointMake(200, 200)
27 |
28 | view.addSubview(pdfImageView)
29 | }
30 | ```
31 | PDF Asset with size to fit
32 | ```swift
33 | UIImage.imageWithPDFNamed(name: String, fitSize: CGSize)
34 | ```
35 |
36 |
37 | PDF Asset with Size
38 | ```swift
39 | UIImage.imageWithPDFNamed(name: String, size: CGSize)
40 | ```
41 |
42 | PDF Asset with Width
43 | ```swift
44 | UIImage.imageWithPDFNamed(name: String, width: CGFloat)
45 | ```
46 |
47 | PDF Asset with Height
48 | ```swift
49 | UIImage.imageWithPDFNamed(name: String, height: CGFloat)
50 | ```
51 |
52 | # Disk Cacheing
53 | Cached PDF assets to PNG images with readable names and scale factor ready to reuse.
54 | UIImage+PDF now transparently caches all rendered PDFs in Application_Home/Documents/CachedAssets. This substantially improves application latency with large PDFs, especially on larger devices. To disable disk cacheing, call:
55 | ```swift
56 | UIImage.shouldCacheOnDisk = false
57 | ```
58 |
59 | # Memory Cacheing
60 | UIImage+PDF can now use NSCache to cache rendered PDFs in memory. This feature is disabled by default. To enable it call:
61 | ```swift
62 | UIImage.shouldCacheInMemory = true
63 | ```
64 |
65 | # PDF file size
66 | By default Adobe Illustrator saves exported PDFs very inefficiently. For best results, select File -> Save a Copy, select PDF format and then uncheck all the general options. Once you are ready to ship your app, run all your PDF assets through ShrinkIt (see below).
67 |
68 | Other vector graphics editors which natively use the OSX Quartz renderer, such as Sketch, will create much more compact PDFs.
69 |
70 | The amazing devs at Panic have now released a PDF shrinking utility, ShrinkIt, which should take a lot of the pain out of a vector asset workflow.
71 |
72 | #Licence
73 | Copyright 2016 Roman Bambura - @RomanBambura. All rights reserved.
74 |
75 | Permission is given to use this source code file without charge in any project, commercial or otherwise, entirely at your risk, with the condition that any redistribution (in part or whole) of source code must retain this copyright and permission notice. Attribution in compiled projects is appreciated but not required.
76 |
77 | #Further Reading
78 | Matt Gemmell has an excellent article on his blog explaining how to use PDF images in iOS apps.
79 |
80 | #UIImage+PDF Objective-C
81 | Nigel Timothy Barber UIImage-PDF
82 |
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/xcuserdata/rb.xcuserdatad/xcschemes/Swift Image+PDF.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Swift Image+PDF/UIImage+PDF/UIPDFView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIPDFView.swift
3 | //
4 | //
5 | // Created by Roman Bambura on 2/23/16.
6 | // Copyright © 2016 Roman Bambura. All rights reserved.
7 | // http://www.sonettic.com
8 | //
9 |
10 | import UIKit
11 |
12 | class UIPDFView: UIView {
13 |
14 | let page = 1
15 | var m_resourceName:String?
16 | var m_resourceURL:URL?
17 | var m_resourceData:Data?
18 |
19 | required init?(coder aDecoder: NSCoder) {
20 | super.init(coder: aDecoder)
21 | }
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: frame)
25 | }
26 |
27 | init(withName name: String, frame: CGRect) {
28 | super.init(frame: frame)
29 |
30 | m_resourceName = name + ".pdf"
31 |
32 | m_resourceURL = PDFResourceHelper.resourceURLForName(m_resourceName!)
33 |
34 | }
35 |
36 | // Resource Name
37 | var resourceName:String?{
38 |
39 | set{
40 | m_resourceName = newValue
41 |
42 | self.setNeedsDisplay()
43 | }
44 | get{
45 | return m_resourceName
46 | }
47 | }
48 |
49 | // Resource URL
50 | var resourceURL:URL?{
51 |
52 | set{
53 | m_resourceURL = newValue
54 |
55 | self.setNeedsDisplay()
56 | }
57 | get{
58 | return m_resourceURL
59 | }
60 | }
61 |
62 | // Resource Data
63 | var resourceData:Data?{
64 | set{
65 | m_resourceData = newValue;
66 |
67 | self.setNeedsDisplay()
68 | }
69 | get{
70 | return m_resourceData
71 | }
72 | }
73 |
74 |
75 | static func pageCountForURL(_ resourceURL: URL?) -> Int{
76 |
77 | var pageCount = 1;
78 |
79 | if resourceURL != nil
80 | {
81 | if let document: CGPDFDocument = CGPDFDocument( resourceURL as! CFURL){
82 |
83 | pageCount = document.numberOfPages;
84 | }
85 | }
86 |
87 | return pageCount;
88 | }
89 |
90 |
91 | func renderIntoContext(_ ctx: CGContext, url resourceURL: URL?, data resourceData:Data?, size: CGSize, page:Int, preserveAspectRatio:Bool){
92 |
93 | var document: CGPDFDocument?
94 |
95 | if resourceURL != nil
96 | {
97 | document = CGPDFDocument( resourceURL as! CFURL )!
98 | }
99 | else if resourceData != nil
100 | {
101 | if let provider: CGDataProvider = CGDataProvider( data: resourceData as! CFData )
102 | {
103 | document = CGPDFDocument( provider )!
104 | }
105 | }
106 |
107 | if let page1: CGPDFPage = document?.page(at: page ){
108 |
109 | let destRect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
110 |
111 | ctx.fill(destRect);
112 | ctx.translateBy(x: 0.0, y: destRect.size.height);
113 | ctx.scaleBy(x: 1.0, y: -1.0);
114 | ctx.concatenate(page1.getDrawingTransform(CGPDFBox.cropBox, rect: destRect, rotate: 0, preserveAspectRatio: preserveAspectRatio));
115 | ctx.drawPDFPage(page1);
116 | }
117 | }
118 |
119 | // Only override drawRect: if you perform custom drawing.
120 | // An empty implementation adversely affects performance during animation.
121 | override func draw(_ rect: CGRect){
122 |
123 | if let ctx: CGContext = UIGraphicsGetCurrentContext()
124 | {
125 | self.backgroundColor?.set()
126 | ctx.fill(rect )
127 | layer.render(in: ctx)
128 | renderIntoContext(ctx, url:resourceURL, data:resourceData, size:rect.size, page:page, preserveAspectRatio:true)
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/Swift Image+PDF/UIImage+PDF/PDFResourceHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PDFResourceHelper.swift
3 | // WAPersonal
4 | //
5 | // Created by Roman Bambura on 2/25/16.
6 | // Copyright © 2016 Roman Bambura. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PDFResourceHelper {
12 |
13 | static func resourceURLForName(_ resourceName:String?) -> URL?{
14 |
15 | if let path = Bundle.main.path(forResource: resourceName , ofType: nil){
16 | return URL(fileURLWithPath:path)
17 | }
18 | return nil
19 | }
20 |
21 | static func mediaRect(_ resourceName: String?) -> CGRect
22 | {
23 | return self.mediaRectForURL(self.resourceURLForName(resourceName)!)
24 | }
25 |
26 | static func mediaRectForURL(_ resourceURL: URL) -> CGRect
27 | {
28 | return mediaRectForURL(resourceURL, page:1)
29 | }
30 |
31 |
32 |
33 |
34 | static func mediaRectForURL(_ resourceURL: URL?, page: Int)-> CGRect{
35 |
36 | var rect:CGRect = CGRect.null
37 |
38 | if resourceURL != nil
39 | {
40 | if let pdf:CGPDFDocument = CGPDFDocument(resourceURL as! CFURL)
41 | {
42 |
43 | if let page1:CGPDFPage = pdf.page(at: page)
44 | {
45 |
46 | rect = page1.getBoxRect(CGPDFBox.cropBox)
47 |
48 | let rotationAngle = page1.rotationAngle
49 |
50 | if (rotationAngle == 90 || rotationAngle == 270)
51 | {
52 | let temp = rect.size.width
53 | rect.size.width = rect.size.height
54 | rect.size.height = temp
55 | }
56 | }
57 | }
58 | }
59 |
60 | return rect;
61 | }
62 |
63 | static func renderIntoContext(_ ctx: CGContext, url resourceURL: URL?, data resourceData:Data?, size: CGSize, page:Int, preserveAspectRatio:Bool){
64 |
65 | var document: CGPDFDocument?
66 |
67 | if resourceURL != nil
68 | {
69 | document = CGPDFDocument( resourceURL as! CFURL )!
70 | }
71 | else if resourceData != nil
72 | {
73 | if let provider: CGDataProvider = CGDataProvider( data: resourceData as! CFData )
74 | {
75 | document = CGPDFDocument( provider )!
76 | }
77 | }
78 |
79 | if let page1: CGPDFPage = document?.page(at: page ){
80 |
81 | let destRect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
82 |
83 | let drawingTransform: CGAffineTransform = page1.getDrawingTransform(CGPDFBox.cropBox, rect: destRect, rotate: 0, preserveAspectRatio: preserveAspectRatio);
84 | ctx.concatenate(drawingTransform)
85 | ctx.drawPDFPage(page1 )
86 | }
87 | }
88 |
89 | static func mediaRectForData(_ data: Data?, page: Int) -> CGRect{
90 |
91 | var rect:CGRect = CGRect.null
92 |
93 | if data != nil
94 | {
95 | if let provider:CGDataProvider = CGDataProvider( data: data as! CFData )
96 | {
97 |
98 | if let document:CGPDFDocument = CGPDFDocument( provider ){
99 |
100 | if let page1:CGPDFPage = document.page(at: page )
101 | {
102 |
103 | rect = page1.getBoxRect(CGPDFBox.cropBox )
104 |
105 | let rotationAngle = page1.rotationAngle
106 |
107 | if (rotationAngle == 90 || rotationAngle == 270)
108 | {
109 | let temp = rect.size.width
110 | rect.size.width = rect.size.height
111 | rect.size.height = temp
112 | }
113 | }
114 | }
115 | }
116 | }
117 |
118 | return rect;
119 | }
120 |
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/Swift Image+PDF.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 319AD2B41C802CBC003845A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2B31C802CBC003845A4 /* AppDelegate.swift */; };
11 | 319AD2B61C802CBC003845A4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2B51C802CBC003845A4 /* ViewController.swift */; };
12 | 319AD2B91C802CBC003845A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 319AD2B71C802CBC003845A4 /* Main.storyboard */; };
13 | 319AD2BB1C802CBC003845A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 319AD2BA1C802CBC003845A4 /* Assets.xcassets */; };
14 | 319AD2BE1C802CBC003845A4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 319AD2BC1C802CBC003845A4 /* LaunchScreen.storyboard */; };
15 | 319AD2CE1C802D74003845A4 /* PDFResourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2CA1C802D74003845A4 /* PDFResourceHelper.swift */; };
16 | 319AD2CF1C802D74003845A4 /* UIImage+PDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2CB1C802D74003845A4 /* UIImage+PDF.swift */; };
17 | 319AD2D01C802D74003845A4 /* UIPDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2CC1C802D74003845A4 /* UIPDFView.swift */; };
18 | 319AD2D11C802D74003845A4 /* UIView+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319AD2CD1C802D74003845A4 /* UIView+Image.swift */; };
19 | 319AD2D31C80395C003845A4 /* animalsCat.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 319AD2D21C80395C003845A4 /* animalsCat.pdf */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 319AD2B01C802CBC003845A4 /* Swift Image+PDF.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swift Image+PDF.app"; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 319AD2B31C802CBC003845A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | 319AD2B51C802CBC003845A4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
26 | 319AD2B81C802CBC003845A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
27 | 319AD2BA1C802CBC003845A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
28 | 319AD2BD1C802CBC003845A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | 319AD2BF1C802CBC003845A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | 319AD2CA1C802D74003845A4 /* PDFResourceHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFResourceHelper.swift; sourceTree = ""; };
31 | 319AD2CB1C802D74003845A4 /* UIImage+PDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+PDF.swift"; sourceTree = ""; };
32 | 319AD2CC1C802D74003845A4 /* UIPDFView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIPDFView.swift; sourceTree = ""; };
33 | 319AD2CD1C802D74003845A4 /* UIView+Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Image.swift"; sourceTree = ""; };
34 | 319AD2D21C80395C003845A4 /* animalsCat.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = animalsCat.pdf; path = "Swift Image+PDF/animalsCat.pdf"; sourceTree = SOURCE_ROOT; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | 319AD2AD1C802CBC003845A4 /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | 319AD2A71C802CBC003845A4 = {
49 | isa = PBXGroup;
50 | children = (
51 | 319AD2B21C802CBC003845A4 /* Swift Image+PDF */,
52 | 319AD2B11C802CBC003845A4 /* Products */,
53 | );
54 | sourceTree = "";
55 | };
56 | 319AD2B11C802CBC003845A4 /* Products */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 319AD2B01C802CBC003845A4 /* Swift Image+PDF.app */,
60 | );
61 | name = Products;
62 | sourceTree = "";
63 | };
64 | 319AD2B21C802CBC003845A4 /* Swift Image+PDF */ = {
65 | isa = PBXGroup;
66 | children = (
67 | 319AD2B31C802CBC003845A4 /* AppDelegate.swift */,
68 | 319AD2B51C802CBC003845A4 /* ViewController.swift */,
69 | 319AD2C91C802D74003845A4 /* UIImage+PDF */,
70 | 319AD2BA1C802CBC003845A4 /* Assets.xcassets */,
71 | 319AD2B71C802CBC003845A4 /* Main.storyboard */,
72 | 319AD2BC1C802CBC003845A4 /* LaunchScreen.storyboard */,
73 | 319AD2BF1C802CBC003845A4 /* Info.plist */,
74 | );
75 | path = "Swift Image+PDF";
76 | sourceTree = "";
77 | };
78 | 319AD2C91C802D74003845A4 /* UIImage+PDF */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 319AD2CA1C802D74003845A4 /* PDFResourceHelper.swift */,
82 | 319AD2CD1C802D74003845A4 /* UIView+Image.swift */,
83 | 319AD2CC1C802D74003845A4 /* UIPDFView.swift */,
84 | 319AD2CB1C802D74003845A4 /* UIImage+PDF.swift */,
85 | 319AD2D21C80395C003845A4 /* animalsCat.pdf */,
86 | );
87 | path = "UIImage+PDF";
88 | sourceTree = "";
89 | };
90 | /* End PBXGroup section */
91 |
92 | /* Begin PBXNativeTarget section */
93 | 319AD2AF1C802CBC003845A4 /* Swift Image+PDF */ = {
94 | isa = PBXNativeTarget;
95 | buildConfigurationList = 319AD2C21C802CBC003845A4 /* Build configuration list for PBXNativeTarget "Swift Image+PDF" */;
96 | buildPhases = (
97 | 319AD2AC1C802CBC003845A4 /* Sources */,
98 | 319AD2AD1C802CBC003845A4 /* Frameworks */,
99 | 319AD2AE1C802CBC003845A4 /* Resources */,
100 | );
101 | buildRules = (
102 | );
103 | dependencies = (
104 | );
105 | name = "Swift Image+PDF";
106 | productName = "Swift Image+PDF";
107 | productReference = 319AD2B01C802CBC003845A4 /* Swift Image+PDF.app */;
108 | productType = "com.apple.product-type.application";
109 | };
110 | /* End PBXNativeTarget section */
111 |
112 | /* Begin PBXProject section */
113 | 319AD2A81C802CBC003845A4 /* Project object */ = {
114 | isa = PBXProject;
115 | attributes = {
116 | LastSwiftUpdateCheck = 0730;
117 | LastUpgradeCheck = 0820;
118 | ORGANIZATIONNAME = "Roman Bambura";
119 | TargetAttributes = {
120 | 319AD2AF1C802CBC003845A4 = {
121 | CreatedOnToolsVersion = 7.3;
122 | LastSwiftMigration = 0820;
123 | };
124 | };
125 | };
126 | buildConfigurationList = 319AD2AB1C802CBC003845A4 /* Build configuration list for PBXProject "Swift Image+PDF" */;
127 | compatibilityVersion = "Xcode 3.2";
128 | developmentRegion = English;
129 | hasScannedForEncodings = 0;
130 | knownRegions = (
131 | en,
132 | Base,
133 | );
134 | mainGroup = 319AD2A71C802CBC003845A4;
135 | productRefGroup = 319AD2B11C802CBC003845A4 /* Products */;
136 | projectDirPath = "";
137 | projectRoot = "";
138 | targets = (
139 | 319AD2AF1C802CBC003845A4 /* Swift Image+PDF */,
140 | );
141 | };
142 | /* End PBXProject section */
143 |
144 | /* Begin PBXResourcesBuildPhase section */
145 | 319AD2AE1C802CBC003845A4 /* Resources */ = {
146 | isa = PBXResourcesBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | 319AD2BE1C802CBC003845A4 /* LaunchScreen.storyboard in Resources */,
150 | 319AD2BB1C802CBC003845A4 /* Assets.xcassets in Resources */,
151 | 319AD2B91C802CBC003845A4 /* Main.storyboard in Resources */,
152 | 319AD2D31C80395C003845A4 /* animalsCat.pdf in Resources */,
153 | );
154 | runOnlyForDeploymentPostprocessing = 0;
155 | };
156 | /* End PBXResourcesBuildPhase section */
157 |
158 | /* Begin PBXSourcesBuildPhase section */
159 | 319AD2AC1C802CBC003845A4 /* Sources */ = {
160 | isa = PBXSourcesBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | 319AD2B61C802CBC003845A4 /* ViewController.swift in Sources */,
164 | 319AD2D01C802D74003845A4 /* UIPDFView.swift in Sources */,
165 | 319AD2B41C802CBC003845A4 /* AppDelegate.swift in Sources */,
166 | 319AD2CF1C802D74003845A4 /* UIImage+PDF.swift in Sources */,
167 | 319AD2D11C802D74003845A4 /* UIView+Image.swift in Sources */,
168 | 319AD2CE1C802D74003845A4 /* PDFResourceHelper.swift in Sources */,
169 | );
170 | runOnlyForDeploymentPostprocessing = 0;
171 | };
172 | /* End PBXSourcesBuildPhase section */
173 |
174 | /* Begin PBXVariantGroup section */
175 | 319AD2B71C802CBC003845A4 /* Main.storyboard */ = {
176 | isa = PBXVariantGroup;
177 | children = (
178 | 319AD2B81C802CBC003845A4 /* Base */,
179 | );
180 | name = Main.storyboard;
181 | sourceTree = "";
182 | };
183 | 319AD2BC1C802CBC003845A4 /* LaunchScreen.storyboard */ = {
184 | isa = PBXVariantGroup;
185 | children = (
186 | 319AD2BD1C802CBC003845A4 /* Base */,
187 | );
188 | name = LaunchScreen.storyboard;
189 | sourceTree = "";
190 | };
191 | /* End PBXVariantGroup section */
192 |
193 | /* Begin XCBuildConfiguration section */
194 | 319AD2C01C802CBC003845A4 /* Debug */ = {
195 | isa = XCBuildConfiguration;
196 | buildSettings = {
197 | ALWAYS_SEARCH_USER_PATHS = NO;
198 | CLANG_ANALYZER_NONNULL = YES;
199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
200 | CLANG_CXX_LIBRARY = "libc++";
201 | CLANG_ENABLE_MODULES = YES;
202 | CLANG_ENABLE_OBJC_ARC = YES;
203 | CLANG_WARN_BOOL_CONVERSION = YES;
204 | CLANG_WARN_CONSTANT_CONVERSION = YES;
205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
206 | CLANG_WARN_EMPTY_BODY = YES;
207 | CLANG_WARN_ENUM_CONVERSION = YES;
208 | CLANG_WARN_INFINITE_RECURSION = YES;
209 | CLANG_WARN_INT_CONVERSION = YES;
210 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
211 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
212 | CLANG_WARN_UNREACHABLE_CODE = YES;
213 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
214 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
215 | COPY_PHASE_STRIP = NO;
216 | DEBUG_INFORMATION_FORMAT = dwarf;
217 | ENABLE_STRICT_OBJC_MSGSEND = YES;
218 | ENABLE_TESTABILITY = YES;
219 | GCC_C_LANGUAGE_STANDARD = gnu99;
220 | GCC_DYNAMIC_NO_PIC = NO;
221 | GCC_NO_COMMON_BLOCKS = YES;
222 | GCC_OPTIMIZATION_LEVEL = 0;
223 | GCC_PREPROCESSOR_DEFINITIONS = (
224 | "DEBUG=1",
225 | "$(inherited)",
226 | );
227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
229 | GCC_WARN_UNDECLARED_SELECTOR = YES;
230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
231 | GCC_WARN_UNUSED_FUNCTION = YES;
232 | GCC_WARN_UNUSED_VARIABLE = YES;
233 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
234 | MTL_ENABLE_DEBUG_INFO = YES;
235 | ONLY_ACTIVE_ARCH = YES;
236 | SDKROOT = iphoneos;
237 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
238 | TARGETED_DEVICE_FAMILY = "1,2";
239 | };
240 | name = Debug;
241 | };
242 | 319AD2C11C802CBC003845A4 /* Release */ = {
243 | isa = XCBuildConfiguration;
244 | buildSettings = {
245 | ALWAYS_SEARCH_USER_PATHS = NO;
246 | CLANG_ANALYZER_NONNULL = YES;
247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
248 | CLANG_CXX_LIBRARY = "libc++";
249 | CLANG_ENABLE_MODULES = YES;
250 | CLANG_ENABLE_OBJC_ARC = YES;
251 | CLANG_WARN_BOOL_CONVERSION = YES;
252 | CLANG_WARN_CONSTANT_CONVERSION = YES;
253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
254 | CLANG_WARN_EMPTY_BODY = YES;
255 | CLANG_WARN_ENUM_CONVERSION = YES;
256 | CLANG_WARN_INFINITE_RECURSION = YES;
257 | CLANG_WARN_INT_CONVERSION = YES;
258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNREACHABLE_CODE = YES;
261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu99;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | SDKROOT = iphoneos;
278 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
279 | TARGETED_DEVICE_FAMILY = "1,2";
280 | VALIDATE_PRODUCT = YES;
281 | };
282 | name = Release;
283 | };
284 | 319AD2C31C802CBC003845A4 /* Debug */ = {
285 | isa = XCBuildConfiguration;
286 | buildSettings = {
287 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
288 | INFOPLIST_FILE = "Swift Image+PDF/Info.plist";
289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
290 | PRODUCT_BUNDLE_IDENTIFIER = "sonettic.Swift-Image-PDF";
291 | PRODUCT_NAME = "$(TARGET_NAME)";
292 | SWIFT_VERSION = 3.0;
293 | };
294 | name = Debug;
295 | };
296 | 319AD2C41C802CBC003845A4 /* Release */ = {
297 | isa = XCBuildConfiguration;
298 | buildSettings = {
299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
300 | INFOPLIST_FILE = "Swift Image+PDF/Info.plist";
301 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
302 | PRODUCT_BUNDLE_IDENTIFIER = "sonettic.Swift-Image-PDF";
303 | PRODUCT_NAME = "$(TARGET_NAME)";
304 | SWIFT_VERSION = 3.0;
305 | };
306 | name = Release;
307 | };
308 | /* End XCBuildConfiguration section */
309 |
310 | /* Begin XCConfigurationList section */
311 | 319AD2AB1C802CBC003845A4 /* Build configuration list for PBXProject "Swift Image+PDF" */ = {
312 | isa = XCConfigurationList;
313 | buildConfigurations = (
314 | 319AD2C01C802CBC003845A4 /* Debug */,
315 | 319AD2C11C802CBC003845A4 /* Release */,
316 | );
317 | defaultConfigurationIsVisible = 0;
318 | defaultConfigurationName = Release;
319 | };
320 | 319AD2C21C802CBC003845A4 /* Build configuration list for PBXNativeTarget "Swift Image+PDF" */ = {
321 | isa = XCConfigurationList;
322 | buildConfigurations = (
323 | 319AD2C31C802CBC003845A4 /* Debug */,
324 | 319AD2C41C802CBC003845A4 /* Release */,
325 | );
326 | defaultConfigurationIsVisible = 0;
327 | defaultConfigurationName = Release;
328 | };
329 | /* End XCConfigurationList section */
330 | };
331 | rootObject = 319AD2A81C802CBC003845A4 /* Project object */;
332 | }
333 |
--------------------------------------------------------------------------------
/Swift Image+PDF/UIImage+PDF/UIImage+PDF.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+PDF.swift
3 | //
4 | // Created by Roman Bambura on 2/23/16.
5 | // Copyright © 2016 Roman Bambura. All rights reserved.
6 | // http://www.sonettic.com
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIImage {
12 |
13 | // MARK: Control cache
14 | fileprivate static var _imagesCache: NSCache?
15 | fileprivate static var _shouldCache: Bool = false
16 | fileprivate static var _shouldCacheOnDisk: Bool = true
17 | fileprivate static var _assetName: String?
18 | fileprivate static var _resourceName: String?
19 |
20 |
21 | static var cachedAssetsDirectory: String{
22 | get{
23 | return "CachedAssets"
24 | }
25 | }
26 |
27 | static var resourceName: String?{
28 |
29 | set{
30 | _resourceName = newValue
31 | _assetName = newValue!.components(separatedBy: ".")[0]
32 | }
33 | get{
34 | return _resourceName
35 | }
36 | }
37 |
38 | static var assetName: String? {
39 | set{
40 | _assetName = newValue
41 | _resourceName = _assetName! + ".pdf"
42 | }
43 | get{
44 | return _assetName
45 | }
46 | }
47 |
48 |
49 | static var shouldCacheInMemory:Bool{
50 |
51 | set{
52 | _shouldCache = newValue
53 |
54 | if( _shouldCache && _imagesCache == nil)
55 | {
56 | _imagesCache = NSCache()
57 | }
58 | }
59 | get{
60 | return _shouldCache
61 | }
62 | }
63 |
64 | static var shouldCacheOnDisk: Bool {
65 |
66 | set{
67 | _shouldCacheOnDisk = newValue;
68 | }
69 | get{
70 | return _shouldCacheOnDisk
71 | }
72 |
73 | }
74 |
75 |
76 | // Mark: Public Func
77 |
78 | // Mark: Convenience methods
79 | class func pdfAssetNamed(_ name: String) -> UIImage?{
80 |
81 | assetName = name
82 |
83 | return self.originalSizeImageWithPDFNamed(resourceName!)
84 | }
85 |
86 | class func pdfAssetWithContentsOfFile(_ path: String) -> UIImage?{
87 | return self.originalSizeImageWithPDFURL( URL(fileURLWithPath: path))
88 | }
89 |
90 | class func screenScale() -> CGFloat{
91 | return UIScreen.main.scale
92 | }
93 |
94 |
95 | // Mark: Get UIImage With PDF Name Without Extension
96 |
97 | // Mark: UIImage With Size
98 | class func imageWithPDFNamed(_ name: String, size:CGSize) -> UIImage? {
99 |
100 | assetName = name
101 |
102 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName)!, size:size)
103 | }
104 |
105 | // Mark: UIImage With Width
106 | class func imageWithPDFNamed(_ name: String, width:CGFloat) -> UIImage?{
107 |
108 | assetName = name
109 |
110 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName), width: width)
111 | }
112 |
113 | // Mark: UIImage With Height
114 | class func imageWithPDFNamed(_ name: String, height:CGFloat) -> UIImage?{
115 |
116 | assetName = name
117 |
118 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName), height: height)
119 | }
120 |
121 | // Mark: UIImage Size To Fit
122 | class func imageWithPDFNamed(_ name: String, fitSize size: CGSize) -> UIImage? {
123 |
124 | assetName = name
125 |
126 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(_resourceName), fitSize:size)
127 | }
128 |
129 |
130 |
131 | // Mark: Resource name
132 | // Size
133 | fileprivate class func imageWithPDFNamed(_ name: String, size: CGSize, page: Int) -> UIImage? {
134 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName!), size:size, page:page)
135 | }
136 |
137 | // Width
138 | fileprivate class func imageWithPDFNamed(_ name: String, width:CGFloat, page: Int) -> UIImage?{
139 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName), width: width, page: page)
140 | }
141 |
142 | // Height
143 | fileprivate class func imageWithPDFNamed( _ name: String, height:CGFloat, page: Int) -> UIImage?{
144 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(resourceName), height : height, page: page)
145 | }
146 |
147 | // Fit
148 | fileprivate class func imageWithPDFNamed(_ name: String, fitSize size: CGSize, page: Int) -> UIImage? {
149 | return self.imageWithPDFURL( PDFResourceHelper.resourceURLForName(name), fitSize:size, page:page)
150 | }
151 |
152 | // Original Size
153 | fileprivate class func originalSizeImageWithPDFNamed(_ resourceName: String, page: Int) -> UIImage?{
154 | return self.originalSizeImageWithPDFURL( PDFResourceHelper.resourceURLForName( resourceName ), page:page)
155 | }
156 |
157 | fileprivate class func originalSizeImageWithPDFNamed(_ resourceName: String) -> UIImage?{
158 | return self.originalSizeImageWithPDFURL( PDFResourceHelper.resourceURLForName( resourceName) )
159 | }
160 |
161 |
162 | // Mark: Resource Data
163 | class func originalSizeImageWithPDFData( _ data: Data ) -> UIImage? {
164 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForData(data, page:1)
165 | return self.imageWithPDFData(data, size:mediaRect.size, page:1 )
166 | }
167 |
168 | class func imageWithPDFData(_ data: Data, width:CGFloat) -> UIImage?{
169 | return self.imageWithPDFData(data, width:width, page:1)
170 | }
171 |
172 | class func imageWithPDFData(_ data: Data?, width:CGFloat, page:Int) -> UIImage?{
173 |
174 | if ( data == nil ){
175 | return UIImage()
176 | }
177 |
178 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForData(data, page:page)
179 | let aspectRatio: CGFloat = mediaRect.size.width / mediaRect.size.height
180 | let size: CGSize = CGSize( width: width, height: ceil( width / aspectRatio ))
181 |
182 | return self.imageWithPDFData(data, size:size, page:page)
183 | }
184 |
185 |
186 | class func imageWithPDFData(_ data: Data?, height:CGFloat) -> UIImage? {
187 | return self.imageWithPDFData(data, height:height, page:1)
188 | }
189 |
190 | class func imageWithPDFData(_ data: Data?, height:CGFloat, page:Int) -> UIImage?{
191 |
192 | if ( data == nil ){
193 | return UIImage()
194 | }
195 |
196 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForData(data, page:page)
197 | let aspectRatio: CGFloat = mediaRect.size.width / mediaRect.size.height
198 | let size: CGSize = CGSize( width: ceil( height / aspectRatio ), height: height)
199 |
200 | return self.imageWithPDFData(data, size:size, page:page)
201 | }
202 |
203 | class func imageWithPDFData( _ data: Data?, fitSize size:CGSize) -> UIImage? {
204 | return self.imageWithPDFData(data, fitSize:size, page:1)
205 | }
206 |
207 | class func imageWithPDFData(_ data: Data?, fitSize size: CGSize, page: Int) -> UIImage? {
208 | return self.imageWithPDFData(data, size:size, page:page, preserveAspectRatio:true)
209 | }
210 |
211 | class func imageWithPDFData(_ data: Data?, size: CGSize ) -> UIImage? {
212 | return self.imageWithPDFData(data, size:size, page:1)
213 | }
214 |
215 | class func imageWithPDFData( _ data: Data?, size: CGSize, page: Int) -> UIImage? {
216 | return self.imageWithPDFData(data, size:size, page:page, preserveAspectRatio:false)
217 | }
218 |
219 | class func imageWithPDFData( _ data: Data?, size: CGSize, page: Int, preserveAspectRatio: Bool) -> UIImage?{
220 |
221 | if(data == nil || size.equalTo(CGSize.zero) || page == 0){
222 | return UIImage();
223 | }
224 |
225 | var pdfImage: UIImage?
226 |
227 | let cacheFilename: String = self.cacheFileNameForResourceNamed(self.assetName!, size: size)
228 | let cacheFilePath: String = self.cacheFilePathForResourceNamed(cacheFilename)
229 |
230 | if(_shouldCacheOnDisk && FileManager.default.fileExists(atPath: cacheFilePath))
231 | {
232 | pdfImage = UIImage(contentsOfFile: cacheFilePath)
233 | }
234 | else
235 | {
236 |
237 | let screenScale: CGFloat = UIScreen.main.scale
238 | let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
239 | let ctx: CGContext = CGContext(data: nil, width: Int(size.width * screenScale), height: Int(size.height * screenScale), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo().rawValue)!
240 | ctx.scaleBy(x: screenScale, y: screenScale);
241 |
242 | PDFResourceHelper.renderIntoContext(ctx, url:nil, data:data, size:size, page:page, preserveAspectRatio:preserveAspectRatio)
243 | if let image: CGImage = ctx.makeImage(){
244 | pdfImage = UIImage(cgImage: image, scale: screenScale, orientation: UIImageOrientation.up)
245 | }
246 |
247 | if(_shouldCacheOnDisk)
248 | {
249 | if let data = UIImagePNGRepresentation( pdfImage! ) {
250 | try? data.write(to: URL(fileURLWithPath: cacheFilePath), options: [])
251 | }
252 | }
253 | }
254 |
255 | /**
256 | * Cache image to in memory if active
257 | */
258 | if (pdfImage != nil && _shouldCache)
259 | {
260 | _imagesCache?.setObject(pdfImage!, forKey: cacheFilename as AnyObject)
261 | }
262 |
263 | return pdfImage;
264 | }
265 |
266 | // Mark: Resource URLs
267 |
268 | class func imageWithPDFURL(_ URL: Foundation.URL?, size: CGSize, page:Int) -> UIImage?{
269 | return self.imageWithPDFURL(URL, size:size, page:page, preserveAspectRatio:false)
270 | }
271 |
272 | class func imageWithPDFURL(_ URL: Foundation.URL?, size:CGSize, page: Int, preserveAspectRatio:Bool) -> UIImage? {
273 |
274 | if(URL == nil || size.equalTo(CGSize.zero) || page == 0){
275 | return nil
276 | }
277 |
278 | var pdfImage: UIImage?
279 |
280 | let cacheFilename: String = self.cacheFileNameForResourceNamed(self.assetName!, size: size)
281 | let cacheFilePath: String = self.cacheFilePathForResourceNamed(cacheFilename)
282 |
283 | /**
284 | * Check in Memory cached image before checking file system
285 | */
286 | if (_shouldCache)
287 | {
288 | pdfImage = _imagesCache!.object(forKey: cacheFilename as AnyObject) as? UIImage
289 |
290 | if (pdfImage != nil) {
291 | return pdfImage
292 | }
293 | }
294 |
295 | if(_shouldCacheOnDisk && FileManager.default.fileExists(atPath: cacheFilePath))
296 | {
297 | pdfImage = UIImage(contentsOfFile: cacheFilePath)
298 |
299 | }
300 | else
301 | {
302 |
303 | let screenScale: CGFloat = UIScreen.main.scale
304 | let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
305 | let ctx: CGContext = CGContext(data: nil, width: Int(size.width * screenScale), height: Int(size.height * screenScale), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo().rawValue)!
306 | ctx.scaleBy(x: screenScale, y: screenScale);
307 |
308 | PDFResourceHelper.renderIntoContext(ctx, url:URL, data:nil, size:size, page:page, preserveAspectRatio:preserveAspectRatio)
309 | if let image: CGImage = ctx.makeImage(){
310 | pdfImage = UIImage(cgImage: image, scale: screenScale, orientation: UIImageOrientation.up)
311 | }
312 |
313 | if(_shouldCacheOnDisk)
314 | {
315 | if let data = UIImagePNGRepresentation( pdfImage! ) {
316 | try? data.write(to: Foundation.URL(fileURLWithPath: cacheFilePath), options: [])
317 | }
318 | }
319 | }
320 |
321 | /**
322 | * Cache image to in memory if active
323 | */
324 | if (pdfImage != nil && _shouldCache)
325 | {
326 | _imagesCache?.setObject(pdfImage!, forKey: cacheFilename as AnyObject)
327 | }
328 |
329 | return pdfImage;
330 | }
331 |
332 | class func imageWithPDFURL(_ URL: Foundation.URL?, size: CGSize) -> UIImage?{
333 | return self.imageWithPDFURL(URL, size:size, page:1, preserveAspectRatio:false)
334 | }
335 |
336 | fileprivate class func imageWithPDFURL(_ URL: Foundation.URL?, fitSize size: CGSize, page: Int) -> UIImage?{
337 | return self.imageWithPDFURL(URL, size:size, page:page, preserveAspectRatio:true)
338 | }
339 |
340 | class func imageWithPDFURL(_ URL: Foundation.URL?, fitSize size: CGSize) -> UIImage?{
341 | return self.imageWithPDFURL(URL, fitSize:size, page:1)
342 | }
343 |
344 | class func imageWithPDFURL(_ URL: Foundation.URL?, width: CGFloat, page: Int) -> UIImage?{
345 |
346 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForURL(URL, page:page)
347 | let aspectRatio: CGFloat = mediaRect.size.width / mediaRect.size.height;
348 |
349 | let size: CGSize = CGSize( width: width, height: ceil( width / aspectRatio ));
350 |
351 | return self.imageWithPDFURL(URL, size:size, page:page)
352 | }
353 |
354 | class func imageWithPDFURL(_ URL: Foundation.URL?, width: CGFloat) -> UIImage? {
355 | return self.imageWithPDFURL(URL, width:width, page:1)
356 | }
357 |
358 | class func imageWithPDFURL(_ URL: Foundation.URL?, height: CGFloat, page: Int) -> UIImage? {
359 |
360 | if ( URL == nil ){
361 | return nil
362 | }
363 |
364 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForURL(URL, page:page)
365 | let aspectRatio: CGFloat = mediaRect.size.width / mediaRect.size.height;
366 | let size: CGSize = CGSize( width: ceil( height * aspectRatio ), height: height );
367 |
368 | return self.imageWithPDFURL(URL, size:size, page:page)
369 | }
370 |
371 | class func imageWithPDFURL(_ URL: Foundation.URL?, height: CGFloat) -> UIImage? {
372 | return self.imageWithPDFURL(URL, height:height, page:1)
373 | }
374 |
375 | class func originalSizeImageWithPDFURL( _ URL: Foundation.URL?, page: Int) -> UIImage? {
376 |
377 | if ( URL == nil ){
378 | return nil
379 | }
380 |
381 | let mediaRect: CGRect = PDFResourceHelper.mediaRectForURL(URL, page:page)
382 |
383 | return self.imageWithPDFURL(URL, size:mediaRect.size, page:page, preserveAspectRatio:true)
384 | }
385 |
386 | class func originalSizeImageWithPDFURL(_ URL: Foundation.URL?) -> UIImage? {
387 | return self.originalSizeImageWithPDFURL(URL, page:1)
388 | }
389 |
390 | // Mark: Cacheing
391 | fileprivate class func cacheFileNameForResourceNamed(_ resourceName: String, size: CGSize) -> String{
392 | return String(format: "%@_%dX%d@%dx",resourceName, Int(size.width), Int(size.height), Int(self.screenScale()) )
393 | }
394 |
395 | fileprivate class func cacheFilePathForResourceNamed(_ resourceName: String, size: CGSize) -> String{
396 | let fileName: String = self.cacheFileNameForResourceNamed(resourceName, size: size)
397 | return self.cacheFilePathForResourceNamed(fileName)
398 | }
399 |
400 | fileprivate class func cacheFilePathForResourceNamed(_ cacheResourseName: String) -> String{
401 |
402 | let fileManager: FileManager = FileManager.default
403 | let documentsDirectoryPath: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
404 | let cacheDirectory = String(format: "%@/%@", documentsDirectoryPath, cachedAssetsDirectory)
405 | do{
406 | try fileManager.createDirectory(atPath: cacheDirectory, withIntermediateDirectories: true, attributes: nil)
407 | }catch{
408 | print ("CACHES DIRECTORY IMAGE+PDF CAN'T BE CREATED!")
409 | }
410 |
411 | return String(format:"%@/%@.png", cacheDirectory, cacheResourseName)
412 | }
413 |
414 | }
415 |
416 |
--------------------------------------------------------------------------------