Tool for generating Core Graphics code from vector PDF files
Install:
- Compile via
swift build --product cggen --configuration release
- Add compiled binary to PATH
Usage:
cggen [--objc-header OBJC_HEADER] [--objc-impl OBJC_IMPL]
[--objc-header-import-path OBJC_HEADER_IMPORT_PATH]
[--objc-prefix OBJC_PREFIX]
[-h] [--verbose]
pdfs
positional arguments:
pdfs pdf files to process
optional arguments:
-h, --help show help message and exit
--verbose print some debug info to stdout
--objc-header OBJC_HEADER
Path to file where objc header will be generated,
intermediate dirs should exist
--objc-impl OBJC_IMPL
Path to file where objc implementanion will be generated,
intermediate dirs should exist
--objc-header-import-path OBJC_HEADER_IMPORT_PATH
Objc implementation file should import header file, so
this argument will be used in #import "..."
--objc-prefix OBJC_PREFIX
It is usally good to prefix names of function in objc
code, because of global namespace. This prefix
will be added to every function and constant name.
After generation is done, generated implementation file should be compiled and linked into your project.
You access to drawing functions by importing header file.
Names for functions are: ($PRFX)Draw($PDFNAME)ImageInContext
,
sizes in logical points: k($PRFX)($PDFNAME)ImageSize
For easy to use, add this helper to your UIImage category (I bet you have one :) )
Objc:
@interface UIImage (Additions)
+ (UIImage*)imageWithSize:(CGSize)size
drawingFunction:(void(*)(CGContextRef))drawingFunction;
@end
@implementation UIImage (YBAdditions)
+ (UIImage*)imageWithSize:(CGSize)size
drawingFunction:(void(*)(CGContextRef))drawingFunction {
static const size_t kBitsPerComponent = 8;
static const size_t kBytesPerRow = 0; // Auto
const CGFloat scale = UIScreen.mainScreen.scale;
const CGFloat w = size.width * scale;
const CGFloat h = size.height * scale;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
w,
h,
kBitsPerComponent,
kBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast);
CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
CGContextConcatCTM(context, transform);
CGColorSpaceRelease(colorSpace);
drawingFunction(context);
CGImageRef imgRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:imgRef
scale:scale
orientation:UIImageOrientationUp];
CGImageRelease(imgRef);
CGContextRelease(context);
return img;
}
@end
swift:
extension UIImage {
static func makeImage(size: CGSize, function: (CGContext) -> Void) -> UIImage {
let bitsPerComponent = 8
let bytesPerRow = 0
let scale = UIScreen.main.scale
let w = size.width * scale
let h = size.height * scale
let colorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext.init(data: nil,
width: Int(w),
height: Int(h),
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
function(context)
let cgImage = context.makeImage()!
return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}
}
So you can use it like this:
Objc:
UIImage* img = [UIImage yb_imageWithSize:kYYIconImageSize
drawingFunction:YYDrawIconImageInContext];
swift:
let img = UIImage.makeImage(size: kYYIconImageSize,
function: YYDrawIconImageInContext)
- Add generation arguments:
--generation-style=swift-friendly
--cggen-support-header-path=/path/to/generated/sources/cggen_support.h
--module-name=YourResourcesModule
- Make a protocol in your code:
public protocol ImageDescriptor {
var drawingHandler: @convention(c) (CGContext) -> Void { get }
var size: CGSize { get }
}
- Add an implementation:
extension ImageDescriptor {
public var image: Image {
return UIImage.makeImage(size: size, function: function)
}
}
- For each generated module, add drawing support with just one line of code:
extension YourResourcesModule.ImageDescriptor: ImageDescriptor {}
- Now you can use generated resources in a bit more convenient way:
let icon: UIImage = YourResourcesModule.ImageDescriptor.yourIconName.image
.
Feel free to add some typealiases and/or extensions for the code which uses resources! Example for UIImageView
:
extension UIImageView {
func setIcon(_ icon: YourResourcesModule.ImageDescriptor) {
image = icon.image
}
}
let view = UIImageView()
view.setIcon(.yourIconName)