Skip to content
This repository has been archived by the owner on Jul 24, 2019. It is now read-only.

Add PDF extraction support #24

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 66 additions & 22 deletions cartool/main.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>

typedef enum _kCoreThemeIdiom {
kCoreThemeIdiomUniversal,
Expand Down Expand Up @@ -50,22 +51,18 @@ -(CGImageRef)image;
@interface CUIRenditionKey : NSObject
@end

@interface CUIThemeFacet : NSObject

+(CUIThemeFacet *)themeWithContentsOfURL:(NSURL *)u error:(NSError **)e;

@end

@interface CUICatalog : NSObject

@property(readonly) bool isVectorBased;

-(id)initWithURL:(id)arg1 error:(id*)arg2;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This initializer replaces the need to use the CUIThemeFacet (in my limited testing)

-(id)initWithName:(NSString *)n fromBundle:(NSBundle *)b;
-(id)allKeys;
-(id)allImageNames;
-(CUINamedImage *)imageWithName:(NSString *)n scaleFactor:(CGFloat)s;
-(CUINamedImage *)imageWithName:(NSString *)n scaleFactor:(CGFloat)s deviceIdiom:(int)idiom;
-(NSArray *)imagesWithName:(NSString *)n;
- (struct CGPDFDocument { }*)pdfDocumentWithName:(id)arg1;

@end

Expand Down Expand Up @@ -134,32 +131,65 @@ void CGImageWriteToFile(CGImageRef image, NSString *path)
{
NSMutableArray *images = [[NSMutableArray alloc] initWithCapacity:5];

for (NSNumber *scaleFactor in @[@1, @2, @3])
{
CUINamedImage *image = [catalog imageWithName:key scaleFactor:scaleFactor.doubleValue];

struct CGPDFDocument *pdfDocument = [catalog pdfDocumentWithName:key];

if (pdfDocument) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a PDF document, I'm skipping the extraction of the generated raster images and only extracting the PDF

[images addObject:(__bridge id _Nonnull)(pdfDocument)];
} else {
for (NSNumber *scaleFactor in @[@1, @2, @3])
{
CUINamedImage *image = [catalog imageWithName:key scaleFactor:scaleFactor.doubleValue];

if (image && image.scale == scaleFactor.floatValue) [images addObject:image];
if (image && image.scale == scaleFactor.floatValue) [images addObject:image];
}
}

return images;
}

void writePDFtoFile(struct CGPDFDocument *pdfDocument, NSString *path, NSString *key) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with CGPDFDocument, but I cobbled this together from a few answers on Stack Overflow and pastern and it hasn't failed me yet

unsigned long pageCount = CGPDFDocumentGetNumberOfPages(pdfDocument);
CGPDFPageRef pageRef = CGPDFDocumentGetPage(pdfDocument, 1);
CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFMediaBox);
float pageHeight = pageRect.size.height;
pageRect.size.height = pageRect.size.height * pageCount;

NSMutableData* pdfData = [[NSMutableData alloc] init];
CGDataConsumerRef pdfConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfData);
CGContextRef pdfContext = CGPDFContextCreate(pdfConsumer, &pageRect, NULL);

CGPDFContextBeginPage(pdfContext, NULL);
CGContextTranslateCTM(pdfContext, 0, pageRect.size.height);
for (int i = 1; i <= pageCount; i++) {
@autoreleasepool {
pageRef = CGPDFDocumentGetPage(pdfDocument, i);
CGContextTranslateCTM(pdfContext, 0, -pageHeight);
CGContextDrawPDFPage(pdfContext, pageRef);
}
}
CGPDFContextEndPage(pdfContext);
CGPDFContextClose(pdfContext);

NSString *filename = [NSString stringWithFormat:@"%@.pdf", key];
NSString *pdfFile = [path stringByAppendingPathComponent:filename];

[pdfData writeToFile: pdfFile atomically: NO];
printf("\t%s\n", [filename UTF8String]);
}

void exportCarFileAtPath(NSString * carPath, NSString *outputDirectoryPath)
{
NSError *error = nil;

outputDirectoryPath = [outputDirectoryPath stringByExpandingTildeInPath];

CUIThemeFacet *facet = [CUIThemeFacet themeWithContentsOfURL:[NSURL fileURLWithPath:carPath] error:&error];

CUICatalog *catalog = [[CUICatalog alloc] init];

/* Override CUICatalog to point to a file rather than a bundle */
[catalog setValue:facet forKey:@"_storageRef"];

carPath = [carPath stringByExpandingTildeInPath];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well expand this path too


NSURL *carPathURL = [NSURL fileURLWithPath:carPath.stringByExpandingTildeInPath];
CUICatalog *catalog = [[CUICatalog alloc] initWithURL:carPathURL error:&error];

/* CUICommonAssetStorage won't link */
CUICommonAssetStorage *storage = [[NSClassFromString(@"CUICommonAssetStorage") alloc] initWithPath:carPath];

for (NSString *key in [storage allRenditionNames])
{
printf("%s\n", [key UTF8String]);
Expand All @@ -185,8 +215,19 @@ void exportCarFileAtPath(NSString * carPath, NSString *outputDirectoryPath)
NSMutableArray *images = getImagesArray(catalog, key);
for( CUINamedImage *image in images )
{
if( CGSizeEqualToSize(image.size, CGSizeZero) )
if ( ![image respondsToSelector:@selector(size)]) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement is kinda sloppy — I wish I could do something like if ( ![image isKindOfClass:[CGPDFDocument class]]), but of course CGPDFDocument isn't a class and I don't think there's any way to check the struct type at runtime. Wonder if you know of anything better.

// image is really a CGPDFDocument
struct CGPDFDocument *pdfDocument = (__bridge struct CGPDFDocument *)(image);
printf("\t looks like a PDF!!\n");
if (outputDirectoryPath) {
writePDFtoFile(pdfDocument, outputDirectoryPath, key);
} else {
printf("\t not saving since an output path wasn't provided\n");
}
}
else if( CGSizeEqualToSize(image.size, CGSizeZero) ) {
printf("\tnil image?\n");
}
else
{
CGImageRef cgImage = [image image];
Expand All @@ -202,8 +243,11 @@ void exportCarFileAtPath(NSString * carPath, NSString *outputDirectoryPath)
NSString *scale = image.scale > 1.0 ? [NSString stringWithFormat:@"@%dx", (int)floor(image.scale)] : @"";
NSString *name = [NSString stringWithFormat:@"%@%@%@%@.png", key, idiomSuffix, sizeClassSuffix, scale];
printf("\t%s\n", [name UTF8String]);
if( outputDirectoryPath )
if( outputDirectoryPath ) {
CGImageWriteToFile(cgImage, [outputDirectoryPath stringByAppendingPathComponent:name]);
} else {
printf("\t not saving since an output path wasn't provided\n");
}
}
}
}
Expand Down