summaryrefslogtreecommitdiff
path: root/platform/ios/Classes/MuPageViewNormal.m
diff options
context:
space:
mode:
authorPaul Gardiner <paul.gardiner@artifex.com>2013-11-14 15:24:53 +0000
committerPaul Gardiner <paul.gardiner@artifex.com>2013-11-19 10:18:28 +0000
commit6f532f78076d2bb24a8c6cf47c0f45994fa5b707 (patch)
tree870193262147eba8f35d06f3fd72ffba8369ebee /platform/ios/Classes/MuPageViewNormal.m
parente4c8dcc641b9cd3c7645b034b6f632e0965a059b (diff)
downloadmupdf-6f532f78076d2bb24a8c6cf47c0f45994fa5b707.tar.xz
iOS: add support for creating markup annotations
Diffstat (limited to 'platform/ios/Classes/MuPageViewNormal.m')
-rw-r--r--platform/ios/Classes/MuPageViewNormal.m243
1 files changed, 240 insertions, 3 deletions
diff --git a/platform/ios/Classes/MuPageViewNormal.m b/platform/ios/Classes/MuPageViewNormal.m
index 8c247297..6262a7b1 100644
--- a/platform/ios/Classes/MuPageViewNormal.m
+++ b/platform/ios/Classes/MuPageViewNormal.m
@@ -7,7 +7,15 @@
#include "common.h"
#include "mupdf/pdf.h"
+#import "MuWord.h"
#import "MuTextFieldController.h"
+#import "MuTextSelectView.h"
+
+#import "MuPageViewNormal.h"
+
+#define STRIKE_HEIGHT (0.375f)
+#define UNDERLINE_HEIGHT (0.075f)
+#define LINE_THICKNESS (0.07f)
static void releasePixmap(void *info, const void *data, size_t size)
{
@@ -71,6 +79,181 @@ static NSArray *enumerateWidgetRects(fz_document *doc, fz_page *page, CGSize pag
return [arr retain];
}
+static NSArray *enumerateWords(fz_document *doc, fz_page *page)
+{
+ fz_text_sheet *sheet = NULL;
+ fz_text_page *text = NULL;
+ fz_device *dev = NULL;
+ NSMutableArray *lns = [NSMutableArray array];
+ NSMutableArray *wds;
+ MuWord *word;
+
+ if (!lns)
+ return NULL;
+
+ fz_var(sheet);
+ fz_var(text);
+ fz_var(dev);
+
+ fz_try(ctx);
+ {
+ int b, l, c;
+
+ sheet = fz_new_text_sheet(ctx);
+ text = fz_new_text_page(ctx);
+ dev = fz_new_text_device(ctx, sheet, text);
+ fz_run_page(doc, page, dev, &fz_identity, NULL);
+ fz_free_device(dev);
+ dev = NULL;
+
+ for (b = 0; b < text->len; b++)
+ {
+ fz_text_block *block;
+
+ if (text->blocks[b].type != FZ_PAGE_BLOCK_TEXT)
+ continue;
+
+ block = text->blocks[b].u.text;
+
+ for (l = 0; l < block->len; l++)
+ {
+ fz_text_line *line = &block->lines[l];
+ fz_text_span *span;
+
+ wds = [NSMutableArray array];
+ if (!wds)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create word array");
+
+ word = [MuWord word];
+ if (!word)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create word");
+
+ for (span = line->first_span; span; span = span->next)
+ {
+ for (c = 0; c < span->len; c++)
+ {
+ fz_text_char *ch = &span->text[c];
+ fz_rect bbox;
+ CGRect rect;
+
+ fz_text_char_bbox(&bbox, span, c);
+ rect = CGRectMake(bbox.x0, bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);
+
+ if (ch->c != ' ')
+ {
+ [word appendChar:ch->c withRect:rect];
+ }
+ else if (word.string.length > 0)
+ {
+ [wds addObject:word];
+ word = [MuWord word];
+ if (!word)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create word");
+ }
+ }
+ }
+
+ if (word.string.length > 0)
+ [wds addObject:word];
+
+ if ([wds count] > 0)
+ [lns addObject:wds];
+ }
+ }
+ }
+ fz_always(ctx);
+ {
+ fz_free_text_page(ctx, text);
+ fz_free_text_sheet(ctx, sheet);
+ fz_free_device(dev);
+ }
+ fz_catch(ctx)
+ {
+ lns = NULL;
+ }
+
+ return [lns retain];
+}
+
+static void addMarkupAnnot(fz_document *doc, fz_page *page, int type, NSArray *rects)
+{
+ pdf_document *idoc;
+ fz_point *quadpts = NULL;
+ float color[3];
+ float alpha;
+ float line_height;
+ float line_thickness;
+
+ idoc = pdf_specifics(doc);
+ if (!idoc)
+ return;
+
+ switch (type)
+ {
+ case FZ_ANNOT_HIGHLIGHT:
+ color[0] = 1.0;
+ color[1] = 1.0;
+ color[2] = 0.0;
+ alpha = 0.5;
+ line_thickness = 1.0;
+ line_height = 0.5;
+ break;
+ case FZ_ANNOT_UNDERLINE:
+ color[0] = 0.0;
+ color[1] = 0.0;
+ color[2] = 1.0;
+ alpha = 1.0;
+ line_thickness = LINE_THICKNESS;
+ line_height = UNDERLINE_HEIGHT;
+ break;
+ case FZ_ANNOT_STRIKEOUT:
+ color[0] = 1.0;
+ color[1] = 0.0;
+ color[2] = 0.0;
+ alpha = 1.0;
+ line_thickness = LINE_THICKNESS;
+ line_height = STRIKE_HEIGHT;
+ break;
+ }
+
+ fz_var(quadpts);
+ fz_try(ctx)
+ {
+ int i;
+ pdf_annot *annot;
+
+ quadpts = fz_malloc_array(ctx, rects.count * 4, sizeof(fz_point));
+ for (i = 0; i < rects.count; i++)
+ {
+ CGRect rect = [[rects objectAtIndex:i] CGRectValue];
+ float top = rect.origin.y;
+ float bot = top + rect.size.height;
+ float left = rect.origin.x;
+ float right = left + rect.size.width;
+ quadpts[i*4].x = left;
+ quadpts[i*4].y = bot;
+ quadpts[i*4+1].x = right;
+ quadpts[i*4+1].y = bot;
+ quadpts[i*4+2].x = right;
+ quadpts[i*4+2].y = top;
+ quadpts[i*4+3].x = left;
+ quadpts[i*4+3].y = top;
+ }
+
+ annot = pdf_create_annot(idoc, (pdf_page *)page, type);
+ pdf_set_markup_annot_quadpoints(idoc, annot, quadpts, rects.count*4);
+ pdf_set_markup_appearance(idoc, annot, color, alpha, line_thickness, line_height);
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, quadpts);
+ }
+ fz_catch(ctx)
+ {
+ printf("Annotation creation failed\n");
+ }
+}
+
static int setFocussedWidgetText(fz_document *doc, fz_page *page, const char *text)
{
int accepted;
@@ -329,7 +512,6 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
}
}
-#import "MuPageViewNormal.h"
@implementation MuPageViewNormal
@@ -426,6 +608,7 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
[widgetRects release];
[linkView release];
[hitView release];
+ [textSelectView release];
[tileView release];
[loadingView release];
[imageView release];
@@ -490,6 +673,47 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
}
}
+- (void) textSelectModeOn
+{
+ dispatch_async(queue, ^{
+ [self ensurePageLoaded];
+ NSArray *words = enumerateWords(doc, page);
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ textSelectView = [[MuTextSelectView alloc] initWithWords:words pageSize:pageSize];
+ [words release];
+ if (imageView)
+ [textSelectView setFrame:[imageView frame]];
+ [self addSubview:textSelectView];
+ });
+ });
+}
+
+- (void) textSelectModeOff
+{
+ [textSelectView removeFromSuperview];
+ [textSelectView release];
+ textSelectView = nil;
+}
+
+-(void) saveMarkup:(int)type
+{
+ CGRect tframe = tileFrame;
+ float tscale = tileScale;
+ CGRect vframe = tframe;
+ vframe.origin.x -= imageView.frame.origin.x;
+ vframe.origin.y -= imageView.frame.origin.y;
+
+ NSArray *rects = [textSelectView selectionRects];
+ if (rects.count == 0)
+ return;
+
+ dispatch_async(queue, ^{
+ addMarkupAnnot(doc, page, type, rects);
+ [self updatePageAndTileWithTileFrame:tframe tileScale:tscale viewFrame:vframe];
+ });
+ [self textSelectModeOff];
+}
+
- (void) resetZoomAnimated: (BOOL)animated
{
// discard tile and any pending tile jobs
@@ -554,6 +778,8 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
[self addSubview: imageView];
if (hitView)
[self bringSubviewToFront: hitView];
+ if (textSelectView)
+ [self bringSubviewToFront:textSelectView];
} else {
[imageView setImage: image];
}
@@ -632,6 +858,9 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
if (linkView)
[linkView setFrame:[imageView frame]];
+
+ if (textSelectView)
+ [textSelectView setFrame:[imageView frame]];
}
}
@@ -694,6 +923,8 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
[self bringSubviewToFront: hitView];
if (linkView)
[self bringSubviewToFront:linkView];
+ if (textSelectView)
+ [self bringSubviewToFront:textSelectView];
} else {
printf("discard tile\n");
}
@@ -730,8 +961,14 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa
- (void) scrollViewDidZoom: (UIScrollView*)scrollView
{
- if (hitView && imageView)
- [hitView setFrame: [imageView frame]];
+ if (imageView)
+ {
+ if (hitView)
+ [hitView setFrame: [imageView frame]];
+
+ if (textSelectView)
+ [textSelectView setFrame:[imageView frame]];
+ }
}
- (void) setScale:(float)scale {}