Category Archives: Posts

SkyEpub for Android 3.6.0 Released with the the Advanced Demo.

SkyEpub for Android 3.6.0 Released.

  1. Functions and Events are added in new version.
  2. Bugs Fixed, Engine more stabilized.
  3. Performance Enhanced
  4. The Advanced Demo Provided,  which is highly comprehensive and easy to apply.
  5. The Advanced Demo Tested Under Galaxy S2, S3, S4 Galaxy Tab 10.1, Galaxy Note 10.1.

SkyEpub 3.6 for iOS released with the Advanced Sample Project

SkyEpub 3.6 for iOS release

1. A lot of functions and events added.
2. bugs fixed, it became more reliable and robust
3. performance improvement
4. Highly Advanced Sample Project provided
(You can learn easily how to implement iBooks level ebook reader with SkyEpub for iOS now.)

% NEW Functions & Events
// 3.6
/** called when certain highlight should be updated in the case like changing color */
-(void)reflowableViewController:(ReflowableViewController*)rvc updateHighlight:(Highlight*)highlight;
/** Javascript source for chapterIndex can be passed to the engine if you like to implement some custom behaviors. */
-(NSString*)reflowableViewController:(ReflowableViewController*)rvc scriptForChapter:(NSInteger)chapterIndex;
/** should tell the engine whether a given pagePositionInBook value is bookmarked or not */
-(BOOL)reflowableViewController:(ReflowableViewController*)rvc isBookmarked:(PageInformation*)pageInformation;
/** should return the bookmarked image for rendering */
-(UIImage*)bookmarkImage:(ReflowableViewController*)rvc isBookmarked:(BOOL)isBookmarked;
/** should return the CGRect of the bookmarked image for rendering */
-(CGRect)bookmarkRect:(ReflowableViewController*)rvc isBookmarked:(BOOL)isBookmarked;

// 3.6
/** called when highlight is hit by tap gesture. @param highlight Highlight object hit by tap gesture. @param position CGPoint at tap position */
-(void)reflowableViewController:(ReflowableViewController*)rvc didHitHighlight:(Highlight*)highlight atPosition:(CGPoint)position startRect:(CGRect)startRect endRect:(CGRect)endRect;
-(void)pageTransitionStarted:(ReflowableViewController*)rvc;
-(void)pageTransitionEnded:(ReflowableViewController*)rvc;
/** called when text selection is cancelled */
-(void)reflowableViewController:(ReflowableViewController*)rvc didSelectionCanceled:(NSString*)lastSelectedText;
/** called when seletected text is changed */
-(void)reflowableViewController:(ReflowableViewController*)rvc didSelectionChanged:(NSString*)selectedText;
-(void)reflowableViewController:(ReflowableViewController*)rvc didHitBookmark:(PageInformation*)pageInformation isBookmarked:(BOOL)isBookmarked;

// 3.6
/** change the color of the highlight */
-(void)changeHighlight:(Highlight*)highlight color:(UIColor*)color;
/** change the text for note */
-(void)changeHighlight:(Highlight *)highlight note:(NSString *)note;
/** change the color and note of text. */
-(void)changeHighlight:(Highlight *)highlight color:(UIColor*)color note:(NSString *)note;
/** check where book is double paged or not. */
-(BOOL)isDoublePaged;
/** tells the engine to rebuild internal cache images for curl transition */
-(void)refresh;
/** tells the engine to repaint viewer */
-(void)repaint;
/** gets the start rectangle from a highlight */
-(CGRect)getStartRectFromHighlight:(Highlight*)highlight;
/** gets the end rectangle from a highlight */
-(CGRect)getEndRectFromHighlight:(Highlight*)highlight;
/** return pagePositionInBook value for given page of current chapter */
-(double)getPagePositionInBook:(int)pageIndex;

/** backup current position */
-(void)backupPosition;
/** goto the position backuped */
-(void)restorePosition;

/** Hide the contents of book */
-(void)hidePages;
/** show the contents of book */
-(void)showPages;
/** tell the pages of viewer is shown or hidden */
-(BOOL)isPagesShown;

SkyEpub for iOS 3.5.4 Released

SkyEpub for iOS 3.5.4

ReflowableView customView Property Added
; custom controls can be inserted into this view.

ReflowableView useDOMForHighlight:(BOOL) method Added
; if YES, SkyEpub engine will use DOM to highlight text.
; if NO, Built-In redering engine will be used for highlighting.

The Bugs about Pagination are Fixed.
The Bugs about Highlighting by Built-in Render are Fixed.

SkyEpub for iOS 3.5.3 released.

Background Image and color looks more natural in SkyEpub for iOS 3.5.3

1. Background Image with transparent color can be used now. 

2. Alpha value is supported in changeBackground:(UIColor*) color;

3. More bugs related to background are fixed. 

SkyEpub 3.5.1 is available now !!!

SkyEpub 3.5.1 is now available. 

There are great changes and improvements in this version. 

1. MediaOverlay supported. 

2. Footnote popup based on HTML5 aside tag is supported. 

3. Background images can be easily changed with user defined client area. 

4. PageTransition Effects are available in Android version .

5. BookInformation class to tell you more detailed information about epub file. 

6. SkyEpub for iOS version supports new rendering features for Highlights. 

7. A lot of functions to move pages conveniently are added to SDK. 

8. Some serious bugs are fixed. 

 

PDF Reader Source Code for iOS is now Available !!!

Hi customers and visitors !

This is PDF Reader source code for iOS.
Though pdf reader is not a part of our product(SkyEpub), SkyEpub has the function to read pdf files in iOS.

LGPL license
Here is the source code under LGPL license, so this source is copy left, license free and ok to use commercial purpose.
But in case of using this, please link this site and provide the original writer.

Thank you always.

PdfViewController.h
//
// PdfViewController.h
// CoreTest
//
// Created by SkyTree on 12. 2. 9..
// Copyright (c) 2012 Skytree Corporation. All rights reserved.
//

#import <UIKit/UIKit.h>

@class SearchResult;
@class PDFViewController;

@interface PDFPageInformation :NSObject{
NSInteger pageIndex;
NSInteger numberOfPages;
double pagePosition;
}
@property NSInteger pageIndex;
@property NSInteger numberOfPages;
@property double pagePosition;
@end

@protocol PDFViewControllerDelegate <NSObject>
@optional
-(void)pdfViewController:(PDFViewController*)pvc didDetectTapAtPositionInView:(CGPoint)positionInView positionInPage:(CGPoint)positionInPage;
-(void)pdfViewController:(PDFViewController*)pvc pageMoved:(PDFPageInformation*)pdfPageInformation;
-(void)pdfViewController:(PDFViewController*)pvc didSearchKey:(SearchResult*)searchResult;
-(void)pdfViewController:(PDFViewController*)pvc didFinishSearchAll:(SearchResult*)searchResult;
@end
@interface PDFViewController :UIViewController {
NSString *filePath; // full path for pdf file to be opened
NSString* version;
id <PDFViewControllerDelegate> delegate;
int transitionType;
}
@property (nonatomic,retain) NSString* version;
@property (nonatomic,retain) NSString* filePath;
@property (nonatomic,retain) id <PDFViewControllerDelegate> delegate;
@property int transitionType;

-(id)initWithStartPageIndex:(int)pageIndex;
-(void)gotoPageByPageIndex:(int)pageIndex;
-(void)gotoPrevPage;
-(void)gotoNextPage;
-(UIImage*)getPageImage:(int)pageIndex;
-(UIImage*)getThumbImage:(int)pageIndex;
-(void)searchKey:(NSString*)key;
-(int)getNumberOfPages;
-(void)debug0;
-(void)debug1;
-(void)debug2;
@end

PDFViewController.m


//
// PDFViewController.m
// CoreTest
//
// Created by SkyTree on 12. 2. 9..
// Copyright (c) 2012 Skytree Corporation. All rights reserved.
//

#import "PDFViewController.h"
#import <QuartzCore/QuartzCore.h>
#import "PDFSearcher.h"
#import "ReflowableViewController.h"

#define UP 0
#define DOWN 1
#define PageTransitionNone 0
#define PageTransitionSlide 1
#define PageTransitionCurl 2

#define offsetTop 0
#define offsetCenter 1
#define offsetBottom 2

#define DEBUGMODE 0

void XLog(NSString * formatString, ...);

@implementation PDFPageInformation
@synthesize pageIndex,numberOfPages,pagePosition;
@end

@interface PDFViewController() <UIWebViewDelegate,UIGestureRecognizerDelegate,PDFViewControllerDelegate> {
UIWebView *webView;
UIView *contentView;
int currentPageIndex;
int oldPageIndex;
int pastIndex;
int numberOfPages;
double pageHeight;
double documentHeight;
CGPDFDocumentRef pdfDocument;
UIScrollView *innerScrollView;
int lastOffset;
int direction;
BOOL isLocked;
BOOL btFlag;
double defaultHeight;
int currentPageOffsetMode;
int startPageIndex;
}

@property (strong, nonatomic) UIWebView *webView;
@property (retain, nonatomic) UIView *contentView;
@property (strong, nonatomic) UIScrollView *innerScrollView;
@property CGPDFDocumentRef pdfDocument;
@property double documentHeight;
@property int numberOfPages,currentPageIndex,oldPageIndex;
@property double pageHeight;
@property int startPageIndex;

-(int)getNumberOfPages;
-(void)gotoPage:(int)index;
-(void)makeXIB;
-(void)recalcFrames;
-(void)recalcLayout;
-(void)customizeWebView;
-(void)scrollToOffsetY:(float)offsetY;
-(void)recalcPageInformation;
-(BOOL)hasString:(NSString*)key inPage:(int)pageIndex;
-(void)writeImage:(UIImage *)image withFilename:(NSString* )fileName;
-(void)stickToTopOfNextPage;
-(void)stickToTopOfPrevPage;
-(void)stickToTopOfThisPage;
-(void)stickToBottomOfThisPage;
-(void)stickToBottomOfPrevPage;
-(void)gotoPageWithoutRecalc:(int)index;
-(BOOL)isLineAbove;
-(BOOL)isLineBelow;
-(BOOL)isUpperSide;
-(void)toLeftSwipeDetected:(UIGestureRecognizer *)sender;
-(void)toRightSwipeDetected:(UIGestureRecognizer *)sender;
-(void)animatePage:(bool)toLeft;
-(CGRect)getPageRect:(int)index;
-(void)displayAdjacentPages;
-(CGPoint)getOffsetByPageIndex:(int)pageIndex;
-(void)gotoStartPage;

@end
@implementation PDFViewController
@synthesize webView,contentView;
@synthesize documentHeight;
@synthesize pdfDocument,innerScrollView;
@synthesize pageHeight,numberOfPages,currentPageIndex,oldPageIndex;
@synthesize version,filePath;
@synthesize delegate;
@synthesize startPageIndex;
@synthesize transitionType;

-(id)init {
self = [super init];
if (self) {
// Custom initialization
self.startPageIndex = -100;
}
return self;
}

-(id)initWithStartPageIndex:(int)pageIndex {
self = [super init];
if (self) {
// Custom initialization
self.startPageIndex = pageIndex;
}
return self;
}

-(BOOL)isAbove5 {
@autoreleasepool {
// A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
// class is used as fallback when it isn't available.
NSString *reqSysVer = @"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
return YES;
}else {
return NO;
}
}
}

-(void)debug0 {
// [self gotoPrevPage];
// for (int i=0; i<self.numberOfPages; i++) {
// CGRect ri = [self getPageRect:i];
// XLog(@"pageIndex:i width:%f height:%f",ri.size.width*innerScrollView.zoomScale,ri.size.height*innerScrollView.zoomScale);
// }
[self gotoPage:10];
}

-(void)debug1 {
[self gotoNextPage];

// XLog(@"%f",[self getOuterHeightFromWebView:self.webView]);
}

-(void)debug2 {
[self displayAdjacentPages];
}

-(BOOL)isOriginalZoomScale {
if (innerScrollView.contentSize.width == self.contentView.bounds.size.width) return YES;
else return NO;
}

-(BOOL)isPortrait {
if (self.view.frame.size.height >self.view.frame.size.width) return YES;
else return NO;
}

-(CGRect)getPageRect:(int)index {
CGRect result = CGRectZero;

CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument,index+1); // assuming all the pages are the same size!

CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(page);

CGPDFArrayRef pageBoxArray;
if(!CGPDFDictionaryGetArray(pageDictionary, "MediaBox", &pageBoxArray)) {
return result; // we've got something wrong here!!!
}

int pageBoxArrayCount = CGPDFArrayGetCount( pageBoxArray );
CGPDFReal pageCoords[4];
for( int k = 0; k < pageBoxArrayCount; ++k )
{
CGPDFObjectRef pageRectObj;
if(!CGPDFArrayGetObject(pageBoxArray, k, &pageRectObj))
{
return result;
}

CGPDFReal pageCoord;
if(!CGPDFObjectGetValue(pageRectObj, kCGPDFObjectTypeReal, &pageCoord)) {
return result;
}

pageCoords[k] = pageCoord;
}

// XLog(@"PDF coordinates -- bottom left x %f ",pageCoords[0]); // should be 0
// XLog(@"PDF coordinates -- bottom left y %f ",pageCoords[1]); // should be 0
// XLog(@"PDF coordinates -- top right x %f ",pageCoords[2]);
// XLog(@"PDF coordinates -- top right y %f ",pageCoords[3]);
// XLog(@"-- i.e. PDF page is %f wide and %f high",pageCoords[2],pageCoords[3]);

// **** now to convert a point on the page from PDF coordinates to iOS coordinates.

double PDFHeight, PDFWidth;
PDFWidth = pageCoords[2];
PDFHeight = pageCoords[3];

// the size of your iOS view or image into which you have rendered your PDF page
// in this example full screen iPad in portrait orientation
double iOSWidth = 768.0;
double iOSHeight = 1024.0;

// the PDF co-ordinate values you want to convert
double PDFxval = 89; // or whatever
double PDFyval = 520; // or whatever

// the iOS coordinate values
int iOSxval, iOSyval;

iOSxval = (int) PDFxval * (iOSWidth/PDFWidth);
iOSyval = (int) (PDFHeight - PDFyval) * (iOSHeight/PDFHeight);

// XLog(@"PDF: %f %f",PDFxval,PDFyval);
// XLog(@"iOS: %i %i",iOSxval,iOSyval);

result = CGRectMake(0,0,pageCoords[2],pageCoords[3]);
return result;
}

-(double)getDefaultHeight {
float ah=0;
for (int i=0; i<self.numberOfPages; i++) {
CGRect ri = [self getPageRect:i];
ah += ri.size.height;
XLog(@"pageIndex:%d width:%f height:%f",i,ri.size.width*innerScrollView.zoomScale,ri.size.height*innerScrollView.zoomScale);
}
return ah;
}

-(double)getScaleFactor {
double factor = documentHeight/defaultHeight;
return factor;
}

-(void)recalcDefault {
defaultHeight = [self getDefaultHeight];
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}

-(int)getTransitionType {
return self.transitionType;
}

-(IBAction)tapPressed:(UIGestureRecognizer *)sender {
CGPoint point = [sender locationInView:self.webView];
CGPoint pointInView = [sender locationInView:self.view];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(pdfViewController:didDetectTapAtPositionInView:positionInPage:)]) {
[self.delegate pdfViewController:self didDetectTapAtPositionInView:pointInView positionInPage:point];
}
if (pointInView.x <= (self.view.bounds.size.width)/5) {
[self toLeftSwipeDetected:sender];
}
if (pointInView.x >= (self.view.bounds.size.width)*.8) {
[self toRightSwipeDetected:sender]; }
}

-(IBAction)doubleTapPressed:(id)sender {
// innerScrollView.zoomScale = 1.0f;
}

-(IBAction)toLeftSwipeDetected:(UIGestureRecognizer *)sender {
if (currentPageIndex==0) return;
[self animatePage:YES];
[self gotoPrevPage];
}

-(IBAction)toRightSwipeDetected:(UIGestureRecognizer *)sender {
if (currentPageIndex>=(numberOfPages-1)) return;
[self animatePage:NO];
[self gotoNextPage];
}
-(void)makeGestures {
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapPressed:)];
tapRecognizer.delegate = self;
[webView addGestureRecognizer:tapRecognizer];

UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapPressed:)];
doubleTapRecognizer.delegate = self;
doubleTapRecognizer.numberOfTapsRequired = 2;
[webView addGestureRecognizer:doubleTapRecognizer];

UISwipeGestureRecognizer *toLeftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(toLeftSwipeDetected:)];
toLeftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
toLeftSwipeRecognizer.delaysTouchesBegan = YES;
[self.webView addGestureRecognizer:toLeftSwipeRecognizer];

UISwipeGestureRecognizer *toRightSwipeRecognizer =[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(toRightSwipeDetected:)];
toRightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
toRightSwipeRecognizer.delaysTouchesBegan = YES;
[self.webView addGestureRecognizer:toRightSwipeRecognizer];
}

-(void)makeXIB {
self.contentView = [[UIView alloc]initWithFrame:self.view.bounds];
self.contentView.contentMode = UIViewContentModeScaleToFill;
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.contentView.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.contentView];

self.webView = [[UIWebView alloc]initWithFrame:self.view.bounds];
self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.webView.alpha = 1;
[self.webView setScalesPageToFit:YES];
// self.webView.contentMode = UIViewContentModeCenter;
self.webView.contentMode = UIViewContentModeScaleToFill;
self.webView.opaque = NO;
self.webView.delegate = self;
self.webView.userInteractionEnabled = YES;
self.webView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.webView];
[self customizeWebView];

[self.view addSubview:self.contentView];
[self makeGestures];
}

-(void)animatePage:(bool)toLeft {
@autoreleasepool {
[UIView beginAnimations:@"page transition" context:nil];
[UIView setAnimationDuration:0.5];
transitionType = [self getTransitionType];

if (transitionType==PageTransitionSlide) {
NSString *transition = kCATransitionPush; //[transitions objectAtIndex:transitionsIndex];
NSString *moveDirection;
if (!toLeft) {
moveDirection = kCATransitionFromRight;
}else {
moveDirection = kCATransitionFromLeft;
}
//----------------------------------------------------------------------------
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setDuration:0.3f];
[animation setType:transition];
[animation setSubtype:moveDirection];
//----------------------------------------------------------------------------
[[self.contentView layer] addAnimation:animation forKey:@"transitionViewAnimation"]; }
else {
[UIView setAnimationTransition:toLeft ? UIViewAnimationTransitionNone : UIViewAnimationTransitionNone forView:self.contentView cache:NO];
}
[UIView commitAnimations];
}
}
-(void)loadPDF:(NSString*)pdfPath {
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
NSURL *targetURL = [[NSURL alloc]initFileURLWithPath:pdfPath];
NSURLRequest *request = [NSURLRequest requestWithURL:targetURL];
pdfDocument = CGPDFDocumentCreateWithURL((__bridge_retained CFURLRef)targetURL);
numberOfPages = CGPDFDocumentGetNumberOfPages(pdfDocument);
[self.webView loadRequest:request];
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
}

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self recalcPageInformation];
XLog(@"zoomScale %f",innerScrollView.zoomScale);
}

#pragma mark - View lifecycle

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/

-(double)getOuterHeightFromWebView:(UIWebView *)view {
[view stringByEvaluatingJavaScriptFromString:@"function getOuterHeightl() { alert('outerHeight:'+window.outerHeight); return window.outerHeight;}"];
NSString*ret = [view stringByEvaluatingJavaScriptFromString:@"window.outerHeight"];
return [ret doubleValue];
}
-(void)searchKey:(NSString*)key {
int numberOfSearched=0;
for (int i=0; i<self.numberOfPages; i++) {
BOOL res = [self hasString:key inPage:i];
if (res) {
numberOfSearched++;
SearchResult* sr = [[SearchResult alloc]init];
sr.pageIndex = i;
sr.numberOfSearched = numberOfSearched;
if (self.delegate!=nil && [self.delegate respondsToSelector:@selector(pdfViewController:didSearchKey:)]) {
[delegate pdfViewController:self didSearchKey:sr];
}
}
}
SearchResult* sr = [[SearchResult alloc]init];
sr.numberOfSearched = numberOfSearched;
if (self.delegate!=nil && [self.delegate respondsToSelector:@selector(pdfViewController:didFinishSearchAll:)]) {
[delegate pdfViewController:self didFinishSearchAll:sr];
}
}

-(void)scrollToOffsetY:(float)offsetY {
// [self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.scrollTo(0.0, %f)", offsetY]];
// self.innerScrollView.contentOffset = CGPointMake(0, offsetY); // 이건 동작한다.
// if (offsetY<0) offsetY = 0;
[self.innerScrollView setContentOffset:CGPointMake(0, offsetY) animated:NO];

}

-(void)scrollToOffset:(CGPoint)offset {
if (offset.y<0) offset.y = 0;
[self.innerScrollView setContentOffset:offset animated:NO];
}

-(void)displayAdjacentPages {
XLog(@"======================================================");
XLog(@"pageInformation for index :%d",currentPageIndex);

for (int i=0; i<[innerScrollView.subviews count]; i++) {
UIView *view = [innerScrollView.subviews objectAtIndex:i];
XLog(@"%d tag:%d %f %f %f %f",i,view.tag,view.frame.origin.x,view.frame.origin.y,view.frame.size.width,view.frame.size.height);
}

UIView *firstView = [innerScrollView.subviews objectAtIndex:0];

for (int i=0; i<[firstView.subviews count]; i++) {
UIView *view = [firstView.subviews objectAtIndex:i];
XLog(@"%d tag:%d %f %f %f %f",i,view.tag,view.frame.origin.x,view.frame.origin.y,view.frame.size.width,view.frame.size.height);
}
}

-(CGPoint)getOffsetByPageIndex:(int)pageIndex offsetMode:(int)offsetMode {
int index;
double offsetX,offsetY;
CGPoint result = CGPointZero;
double zoomScale = innerScrollView.zoomScale;
double pageSpace;

if ([self isAbove5]) {
[self scrollToOffsetY:self.pageHeight*pageIndex]; // 근접위치로 이동
UIView *firstView = [innerScrollView.subviews objectAtIndex:0];

if ([firstView.subviews count]<2) return CGPointMake(-1,-1);

UIView *nextView = [firstView.subviews objectAtIndex:0];
UIView *preView =[firstView.subviews objectAtIndex:1];

pageSpace = fabs(nextView.frame.origin.y-(preView.frame.origin.y+preView.frame.size.height));
pageSpace = pageSpace-1;
if (pageSpace>50) pageSpace = 8;

for (int i=0; i<[firstView.subviews count]; i++) {
UIView *pageView = [firstView.subviews objectAtIndex:i];
pageView.hidden = NO;
index = (pageView.tag-1000000);
if (index==pageIndex) {
double deltaX,deltaY;
if (offsetMode==offsetTop) {
deltaX = (self.contentView.bounds.size.width-(pageView.frame.size.width)*zoomScale)/2;
deltaY = pageSpace*zoomScale;
}else if (offsetMode==offsetCenter) {
deltaX = (self.contentView.bounds.size.width-(pageView.frame.size.width)*zoomScale)/2;
deltaY = (self.contentView.bounds.size.height-(pageView.frame.size.height)*zoomScale)/2;
}else if (offsetMode==offsetBottom) {
deltaX = (self.contentView.bounds.size.width-(pageView.frame.size.width)*zoomScale)/2;
deltaY = (self.contentView.bounds.size.height-(pageView.frame.size.height)*zoomScale)-pageSpace*zoomScale;
}

offsetX = (pageView.frame.origin.x)*zoomScale-deltaX;
offsetY = (pageView.frame.origin.y)*zoomScale-deltaY;

// XLog(@"ch %f cw %f deltaX %f deltaY %f offsetX %f offsetY %f",self.contentView.bounds.size.width,self.contentView.bounds.size.height,deltaX,deltaY,offsetX,offsetY);

result.x = offsetX;
result.y = offsetY;

return result;
}
}
}else {
double deltaX,deltaY;
double pageSpace = 8.0;
if (offsetMode==offsetTop) {
deltaX = (self.contentView.bounds.size.width-(self.contentView.bounds.size.width)*zoomScale)/2;
deltaY = 0;
}else if (offsetMode==offsetCenter) {
deltaX = (self.contentView.bounds.size.width-(self.contentView.bounds.size.width)*zoomScale)/2;
deltaY = (self.contentView.bounds.size.height-pageHeight)/2;
}else {
deltaX = (self.contentView.bounds.size.width-(self.contentView.bounds.size.width)*zoomScale)/2;
deltaY = (self.contentView.bounds.size.height-pageHeight)-pageSpace*zoomScale;
}
result.x = -deltaX;
result.y = pageHeight*pageIndex -deltaY;
}
return result;
}
-(int)getPageIndexByOffset:(double)offset {
UIView *firstView = [innerScrollView.subviews objectAtIndex:0];

double zoomScale = innerScrollView.zoomScale;
double minDelta = 100000000000;
double signDelta;
double pageCenter;
int minIndex = -1;
int targetIndex;

if ([self isAbove5]) {
for (int i=0; i<[firstView.subviews count]; i++) {
UIView *pageView = [firstView.subviews objectAtIndex:i];
pageCenter = (pageView.frame.origin.y+(pageView.frame.size.height)/2)*zoomScale;
double delta = pageCenter-(offset+contentView.bounds.size.height/2);
if (fabs(delta)<=minDelta) {
minDelta = fabs(delta);
signDelta = delta;
minIndex = i;
}
}
UIView *targetView;
if (minIndex!=-1) {
targetView = [firstView.subviews objectAtIndex:minIndex];
targetIndex = targetView.tag - 1000000;
}else targetIndex = 0;
currentPageOffsetMode = offsetCenter;
if (signDelta<0) {
double lineDelta = fabs(minDelta-((targetView.frame.size.height/2)*zoomScale));
if (lineDelta<contentView.bounds.size.height/2) {
currentPageOffsetMode = offsetBottom;
}
}else if (signDelta>0) {
double lineDelta = fabs(minDelta-((targetView.frame.size.height/2)*zoomScale));
if (lineDelta<(contentView.bounds.size.height/2)) {
currentPageOffsetMode = offsetTop;
}
}
}else {
int ti = (offset/documentHeight)*numberOfPages;
for (int pi = ti-1;pi<=ti+1; pi++) {
double py,pageCenter;
py = (pageHeight)*pi;
pageCenter = py+(pageHeight/2);
double delta = pageCenter-(offset+contentView.bounds.size.height/2);
if (fabs(delta)<=minDelta) {
minDelta = fabs(delta);
signDelta = delta;
minIndex = pi;
}
}
targetIndex = minIndex;
currentPageOffsetMode = offsetCenter;
if (signDelta<0) {
double lineDelta = fabs(minDelta-((pageHeight/2)*zoomScale));
if (lineDelta<contentView.bounds.size.height/2) {
currentPageOffsetMode = offsetBottom;
}
}else if (signDelta>0) {
double lineDelta = fabs(minDelta-((pageHeight/2)*zoomScale));
if (lineDelta<(contentView.bounds.size.height/2)) {
currentPageOffsetMode = offsetTop;
}
}
}
return targetIndex;
}

-(CGPoint)getTopOffsetByPageIndex:(int)pageIndex {
return [self getOffsetByPageIndex:pageIndex offsetMode:offsetTop];
}

-(CGPoint)getCenterOffsetByPageIndex:(int)pageIndex {
return [self getOffsetByPageIndex:pageIndex offsetMode:offsetCenter];
}

-(CGPoint)getBottomOffsetByPageIndex:(int)pageIndex {
return [self getOffsetByPageIndex:pageIndex offsetMode:offsetBottom];
}

-(void)gotoPage:(int)index {
if (index<0) return;
currentPageIndex = index;
CGPoint res = [self getCenterOffsetByPageIndex:index];
[self scrollToOffset:res];
[self performSelector:@selector(recalcPageInformation) withObject:nil afterDelay:.3];
}

-(void)gotoNextPage {
currentPageIndex++;
if (currentPageIndex>=numberOfPages) {
currentPageIndex=numberOfPages-1;
return;
}
[self gotoPage:currentPageIndex];
}
-(void)gotoPrevPage {
currentPageIndex--;
if (currentPageIndex<0) {
currentPageIndex = 0;
return;
}
[self gotoPage:currentPageIndex];
}
-(void)gotoPageByPageIndex:(int)pageIndex {
[self gotoPage:pageIndex];
}
-(int)getNumberOfPages {
return numberOfPages;
}

-(void)monitor {
if (direction==UP) {
XLog(@"UP");
}else {
XLog(@"Down");
}

if (currentPageOffsetMode==offsetTop) {
XLog(@"offsetTop");
}else if (currentPageOffsetMode==offsetCenter) {
XLog(@"offsetCenter");
}else {
XLog(@"offsetBottom");
}
}

-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
UIView *viewForZoom=nil;
if ([self isAbove5]) {
viewForZoom = [innerScrollView.subviews objectAtIndex:0];
}else {
viewForZoom = [innerScrollView.subviews objectAtIndex:10];
}
return viewForZoom;
}

-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
[self recalcPageInformation];
}

-(void)scrollViewDidZoom:(UIScrollView *)scrollView{
[self recalcPageInformation];
XLog(@"zoomScale %f",scrollView.zoomScale);
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (isLocked) return;
[self recalcPageInformation];
if (lastOffset > scrollView.contentOffset.y) {
direction = UP;
}else if (lastOffset < scrollView.contentOffset.y) {
direction = DOWN;
}
lastOffset = scrollView.contentOffset.y;
}

-(void) scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)willDecelerate {
if (currentPageOffsetMode==offsetTop) {
[self scrollToOffset:[self getTopOffsetByPageIndex:currentPageIndex]];
}else if (currentPageOffsetMode == offsetBottom) {
[self scrollToOffset:[self getBottomOffsetByPageIndex:currentPageIndex]];
}
}

-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
[self monitor];
if (direction==UP) { 
if (currentPageOffsetMode==offsetBottom) {
[self scrollToOffset:[self getTopOffsetByPageIndex:currentPageIndex+1]];
}else if (currentPageOffsetMode==offsetTop) {
[self scrollToOffset:[self getBottomOffsetByPageIndex:currentPageIndex]];
}else if (currentPageOffsetMode==offsetCenter) {
[self scrollToOffset:[self getTopOffsetByPageIndex:currentPageIndex]];
}
return;
}
if (direction==DOWN) { 
if (currentPageOffsetMode==offsetTop) {
[self scrollToOffset:[self getBottomOffsetByPageIndex:currentPageIndex-1]];
}else if (currentPageOffsetMode==offsetCenter) {
[self scrollToOffset:[self getBottomOffsetByPageIndex:currentPageIndex]];
}else if (currentPageOffsetMode==offsetBottom) {
[self scrollToOffset:[self getTopOffsetByPageIndex:currentPageIndex+1]];
}
return;
}
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
}

-(void)customizeWebView {
for (id subview in webView.subviews) {
if ([[subview class] isSubclassOfClass: [UIScrollView class]]) {
innerScrollView = ((UIScrollView *)subview);
}
}
self.innerScrollView.delegate = self;
}

-(BOOL)hasString:(NSString*)key inPage:(int)pageIndex{
@autoreleasepool {
CGPDFPageRef pageRef = CGPDFDocumentGetPage(pdfDocument, pageIndex+1);
PDFSearcher *searcher = [[PDFSearcher alloc]init];
return [searcher page:pageRef containsString:key];
}
}

-(void)processPageChanged {
@autoreleasepool {
PDFPageInformation* pageInformation = [[PDFPageInformation alloc]init];
pageInformation.pageIndex = self.currentPageIndex;
pageInformation.numberOfPages = self.numberOfPages;
pageInformation.pagePosition = ((double)currentPageIndex/(double)numberOfPages);
[self.delegate pdfViewController:self pageMoved:pageInformation];
}
}

-(void)recalcPageInformation {
if (numberOfPages==0) return;
self.documentHeight = self.innerScrollView.contentSize.height;
self.pageHeight = ((double)self.documentHeight/(double)(self.numberOfPages));
CGPoint offset = [self.innerScrollView.layer.presentationLayer bounds].origin;
float contentOffsetY = offset.y;
self.currentPageIndex = [self getPageIndexByOffset:contentOffsetY];
if (self.currentPageIndex!=self.oldPageIndex) {
if (currentPageIndex==0 && (oldPageIndex!=1 )) return;
[self processPageChanged];
}
oldPageIndex = currentPageIndex;
}

-(void)writeImage:(UIImage *)image withFilename:(NSString* )filename {
@autoreleasepool{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
NSString *imagePath = [paths objectAtIndex:0] ;
NSString *filepath = [NSString stringWithFormat:@"%@/%@", imagePath, filename] ;
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
[imageData writeToFile:filepath atomically:YES];
}
}

-(UIImage *)getPageImage:(int)pageIndex isThumb:(BOOL)isThumb {
CGFloat width = 60.0;
CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, pageIndex+1);
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
float pdfScale;
if (isThumb) pdfScale = width/pageRect.size.width;
else pdfScale = 1.0;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;

UIGraphicsBeginImageContext(pageRect.size);

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);

CGContextSaveGState(context);

// ***********
// Next 3 lines makes the rotations so that the page look in the right direction
// ***********
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, pageRect, 0, true));

CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);

UIImage *thm = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();
return thm;
}

-(UIImage*)getPageImage:(int)pageIndex {
return [self getPageImage:pageIndex isThumb:NO];
}

-(UIImage*)getThumbImage:(int)pageIndex {
return [self getPageImage:pageIndex isThumb:YES];
}

-(BOOL)isReadyFor5 {
UIView *firstView = [innerScrollView.subviews objectAtIndex:0];
if ([firstView.subviews count]>0) return YES;
else return NO;
}

-(void)gotoStartPage {
if ([self isAbove5]) {
while (![self isReadyFor5]) {
[NSThread sleepForTimeInterval:.1];
}
}

[self recalcPageInformation];

if (startPageIndex!=-100) {
[self gotoPage:startPageIndex];
self.currentPageIndex = startPageIndex;
oldPageIndex = startPageIndex;
[self processPageChanged];
}
}

-(void)webViewDidFinishLoad:(UIWebView *)webView {
if ([self isAbove5]) [self performSelectorInBackground:@selector(gotoStartPage) withObject:nil];
else [self performSelector:@selector(gotoStartPage) withObject:nil afterDelay:0];
}

-(void)unload {
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
return;
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
[self makeXIB];
// [self performSelector:@selector(loadPDF:) withObject:self.filePath afterDelay:.2];
[self loadPDF:self.filePath];
self.transitionType = PageTransitionSlide;
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.webView = nil;
self.contentView = nil;
}

-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:(BOOL)animated]; // Call the super class implementation.
self.webView = nil;
self.contentView = nil;
}

-(void)viewWillAppear:(BOOL)animated {

}

@end