const int MaxStripPixels = 1024*1024;
@implementation MuPrintPageRenderer
{
MuDocRef *docRef;
}
-(id) initWithDocRef:(MuDocRef *)aDocRef
{
self = [super init];
if (self)
{
docRef = [aDocRef retain];
}
return self;
}
-(void) dealloc
{
[docRef release];
[super dealloc];
}
-(NSInteger) numberOfPages
{
__block NSInteger npages = 0;
dispatch_sync(queue, ^{
fz_try(ctx)
{
npages = fz_count_pages(ctx, docRef->doc);
}
fz_catch(ctx);
});
return npages;
}
static fz_page *getPage(fz_document *doc, NSInteger pageIndex)
{
__block fz_page *page = NULL;
dispatch_sync(queue, ^{
fz_try(ctx)
{
page = fz_load_page(ctx, doc, (int)pageIndex);
}
fz_catch(ctx)
{
printf("Failed to load page\n");
}
});
return page;
}
static CGSize getPageSize(fz_document *doc, fz_page *page)
{
__block CGSize size = {0.0,0.0};
dispatch_sync(queue, ^{
fz_try(ctx)
{
fz_rect bounds;
fz_bound_page(ctx, page, &bounds);
size.width = bounds.x1 - bounds.x0;
size.height = bounds.y1 - bounds.y0;
}
fz_catch(ctx)
{
printf("Failed to find page bounds\n");
}
});
return size;
}
static fz_pixmap *createPixMap(CGSize size)
{
__block fz_pixmap *pix = NULL;
dispatch_sync(queue, ^{
fz_try(ctx)
{
pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), size.width, size.height);
}
fz_catch(ctx)
{
printf("Failed to create pixmap\n");
}
});
return pix;
}
static void freePage(fz_document *doc, fz_page *page)
{
dispatch_sync(queue, ^{
fz_drop_page(ctx, page);
});
}
static void renderPage(fz_document *doc, fz_page *page, fz_pixmap *pix, fz_matrix *ctm)
{
dispatch_sync(queue, ^{
fz_device *dev = NULL;
fz_var(dev);
fz_try(ctx)
{
dev = fz_new_draw_device(ctx, pix);
fz_clear_pixmap_with_value(ctx, pix, 0xFF);
fz_run_page(ctx, page, dev, ctm, NULL);
}
fz_always(ctx)
{
fz_drop_device(ctx, dev);
}
fz_catch(ctx)
{
printf("Failed to render page\n");
}
});
}
-(void) drawPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)printableRect
{
fz_page *page = NULL;
fz_pixmap *pix = NULL;
CGDataProviderRef dataref = NULL;
CGImageRef img = NULL;
CGContextRef cgctx = UIGraphicsGetCurrentContext();
float dpi = 300.0;
float ppi = 72.0;
if (!cgctx) return;
CGSize paperSize = self.paperRect.size;
page = getPage(docRef->doc, pageIndex);
if (page == NULL) return;
CGSize pageSize = getPageSize(docRef->doc, page);
if (pageSize.width == 0.0 || pageSize.height == 0.0)
goto exit;
CGSize scale = fitPageToScreen(pageSize, paperSize);
pageSize.width *= scale.width;
pageSize.height *= scale.height;
CGSize pageSizePix = {roundf(pageSize.width * dpi / ppi), roundf(pageSize.height * dpi /ppi)};
int max_strip_height = MaxStripPixels / (int)pageSizePix.width;
if (pageSizePix.height > max_strip_height)
pageSizePix.height = max_strip_height;
CGSize stripSize = {pageSize.width, pageSizePix.height * ppi / dpi};
float cursor = 0.0;
while (cursor < pageSize.height)
{
// Overlap strips by 1 point
if (cursor > 0.0)
cursor -= 1.0;
pix = createPixMap(pageSizePix);
if (!pix)
goto exit;
dataref = CreateWrappedPixmap(pix);
if (dataref == NULL)
goto exit;
img = CreateCGImageWithPixmap(pix, dataref);
if (img == NULL)
goto exit;
fz_matrix ctm;
fz_scale(&ctm, dpi / ppi, -dpi / ppi);
fz_pre_translate(&ctm, 0, -stripSize.height-cursor);
fz_pre_scale(&ctm, scale.width, scale.height);
renderPage(docRef->doc, page, pix, &ctm);
CGRect rect = {{0.0,cursor},stripSize};
CGContextDrawImage(cgctx, rect, img);
CGImageRelease(img);
img = NULL;
CGDataProviderRelease(dataref); // releases pix
dataref = NULL;
cursor += stripSize.height;
}
exit:
freePage(docRef->doc, page);
CGImageRelease(img);
CGDataProviderRelease(dataref); //releases pix
}
@end