GenerallyHelpfulSoftware / SVGgh

A framework for using SVG artwork in iOS Apps. Includes a UIView and a button class, printing and PDF export.
MIT License
141 stars 37 forks source link

Would Like to Take several SVGs and Tile or otherwise Lay them out into a PDF. #18

Closed grhowes closed 8 years ago

grhowes commented 8 years ago

@allen8300 requested in an unrelated issue for the following (as I understand the request)

If you look at the source for the SVGtoPDFConverter you can see it is limited to one svgs and one page.

@implementation SVGtoPDFConverter
+(void) createPDFFromRenderer:(SVGRenderer*)aRenderer intoCallback:(renderPDFCallback_t)callback
{
    [[SVGRenderer rendererQueue] addOperationWithBlock:^{
        CGRect boundingBox = aRenderer.viewRect;
        NSData* theResult = nil;
        CFMutableDataRef pdfData = CFDataCreateMutable(NULL, 0);
        if(pdfData != 0)
        {
            CGContextRef quartzContext = CreatePDFContext(boundingBox, pdfData);
            CGContextBeginPage(quartzContext, &boundingBox);
            CGContextSaveGState(quartzContext);

            CGContextTranslateCTM(quartzContext, 0, boundingBox.size.height);
            CGContextScaleCTM(quartzContext, 1.0, -1.0);
            [aRenderer renderIntoContext:quartzContext];

            CGContextEndPage(quartzContext);
            CGContextRestoreGState(quartzContext);
            CGContextFlush(quartzContext);

            CGContextRelease(quartzContext);
            theResult = [(__bridge NSMutableData*)pdfData copy];
            CFRelease(pdfData);
        }
        callback(theResult);
    }];
}
@end

A user has requested a method to generate a tiling version of a PDF. Demo-2.pdf

grhowes commented 8 years ago

@allen8300 Well, I think what you'll have to do is take the above code as a template, and generate however many SVGRenderers as you have different SVGs, and loop over them inside the calls above to CGContextBeginPage and CGContextEndPage, translating and scaling as appropriate. You should probably also take care to clip to the bounding rectangle for each SVG. This isn't something general purpose I'm inclined to add to this library, but it should be easily doable.

grhowes commented 8 years ago

The following appears to work after I cleaned it up a bit. Some things you weren't taking into account:

+(void) createPDFFromRenderer:(SVGRenderer*)aRenderer intoCallback:(renderPDFCallback_t)callback { [[SVGRenderer rendererQueue] addOperationWithBlock:^{

    const CGFloat   maxDimension = 1000.0;
    const CGFloat cellWidth = 50.0f;
    const CGFloat cellHeight = 50.0f;
    CGRect nativeRect = aRenderer.viewRect;
    CGRect boundingBox =CGRectMake(0, 0, maxDimension, maxDimension);

    NSData* theResult = nil;
    CFMutableDataRef pdfData = CFDataCreateMutable(NULL, 0);
    if(pdfData != 0)
    {
        CGContextRef quartzContext = CreatePDFContext(boundingBox, pdfData);
        CGContextBeginPage(quartzContext, &boundingBox);
        CGContextSaveGState(quartzContext);
        CGContextTranslateCTM(quartzContext, 0, maxDimension);
        CGContextScaleCTM(quartzContext, 1.0, -1.0);
        CGFloat originX = 0.0;
        CGFloat originY = 0.0;
        while(originY < maxDimension)
        {
            while(originX < maxDimension) {
                CGRect newboundingBox = CGRectMake(originX, originY, cellWidth, cellHeight);
                CGContextSaveGState(quartzContext);
                //CGContextClipToRect(quartzContext, newboundingBox);

                CGContextTranslateCTM(quartzContext, newboundingBox.origin.x, originY);

                CGContextScaleCTM(quartzContext, cellWidth/nativeRect.size.width,cellHeight/ nativeRect.size.height);

                [aRenderer renderIntoContext:quartzContext];
                CGContextRestoreGState(quartzContext);
                originX += cellWidth;
            }
            originX = 0.0;
            originY += cellHeight;
        }
        CGContextEndPage(quartzContext);
        CGContextRestoreGState(quartzContext);
        CGContextFlush(quartzContext);
        CGContextRelease(quartzContext);
        theResult = [(__bridge NSMutableData*)pdfData copy];
        CFRelease(pdfData);
    }
    callback(theResult);
}];

}

+(void) drawHeartMatrixIntoCallback:(renderPDFCallback_t)callback { NSURL* myNewArtwork = [GHControlFactory locateArtworkForBundle:nil atSubpath:@"Artwork/heart"]; SVGRenderer* aRenderer = [[SVGRenderer alloc] initWithContentsOfURL:myNewArtwork]; [self createPDFFromRenderer:aRenderer intoCallback:callback]; }