PDF-Scrollview - show PDF - document in landscape format - iphone

I'm using Apple's example «PDFScrollView» to display PDFs on an iPad. This works fine, as long as the PDF-document is in Portrait-Mode.
When the document is in Landscape-mode, though, the document is always shown rotated by 90 degrees.
I found this How to detect the orientation of a PDF document in iPhone SDK - but when I try to get the dimensions of the PDF, the height is always bigger than the width, no matter what orientation the PDF has...
Any ideas?

As mentionend in, the CGPDFPageGetBoxRect(page, kCGPDFMediaBox) always returns the same size for a PDF, no matter what orientation the PDF has.
But the rotation of the page is returned correctly.
So I get the rotation using this code:
rotate = CGPDFPageGetRotationAngle(page);
And then use the code below which I found here: http://ipdfdev.com/2011/03/23/display-a-pdf-page-on-the-iphone-and-ipad/
switch (rotate) {
case 0:
// Translate the origin of the coordinate system at the
// bottom left corner of the page rectangle.
CGContextTranslateCTM(context, 0, cropBox.size.height);
// Reverse the Y axis to grow from bottom to top.
CGContextScaleCTM(context, 1, -1);
break;
case 90:
// Reverse the Y axis to grow from bottom to top.
CGContextScaleCTM(context, 1, -1);
// Rotate the coordinate system.
CGContextRotateCTM(context, -M_PI / 2);
break;
case 180:
case -180:
// Reverse the Y axis to grow from bottom to top.
CGContextScaleCTM(context, 1, -1);
// Translate the origin of the coordinate system at the
// top right corner of the page rectangle.
CGContextTranslateCTM(context, cropBox.size.width, 0);
// Rotate the coordinate system with 180 degrees.
CGContextRotateCTM(context, M_PI);
break;
case 270:
case -90:
// Translate the origin of the coordinate system at the
// bottom right corner of the page rectangle.
CGContextTranslateCTM(context, cropBox.size.height, cropBox.size.width);
// Rotate the coordinate system.
CGContextRotateCTM(context, M_PI / 2);
// Reverse the X axis.
CGContextScaleCTM(context, -1, 1);
break;
}
Et voilà - the PDF is displayed in the right orientation

I am writing this with assumption that your problem is about rotating document when user rotates device....
For that you have to redraw document in view. TO achieve that do following....
change frame of the view in which document is drawn, and CALayer(OR CATiledLayer) being used in that view in following method.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
Call setNeedsDisplay method of CATiledLayer after changing frame.
Then return YES in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation.
Above steps will redraw the document in new frame of you View accordingly so it will appear properly.
->IF your view is in full screen or then only step 2 ans 3 will be enough.
Post here if any further assistance is required....

Is there a particular reason you are drawing PDFs yourself? You could use QLPreviewController on iOS 4.0 or later, and UIDocumentInteractionController for previous versions.

Related

Translating a view and the rotating it problem

I have a custom UIImageView, I can drag it around screen by making a translation with (xDif and yDif is the amount fingers moved):
CGAffineTransform translate = CGAffineTransformMakeTranslation(xDif, yDif);
[self setTransform: CGAffineTransformConcat([self transform], translate)];
Let's say I moved the ImageView for 50px in both x and y directions. I then try to rotate the ImageView (via gesture recognizer) with:
CGAffineTransform transform = CGAffineTransformMakeRotation([recognizer rotation]);
myImageView.transform = transform;
What happens is the ImageView suddenly moves to where the ImageView was originally located (before the translation - not from the moved position + 50px in both directions).
(It seems that no matter how I translate the view, the self.center of the ImageView subclass stays the same - where it was originally laid in IB).
Another problem is, if I rotate the ImageView by 30 deg, and then try to rotate it a bit more, it will again start from the original position (angle = 0) and go from there, why wouldn't it start from the angle 30 deg and not 0.
You are overwriting the earlier transform. To add to the current transform, you should do this –
myImageView.transform = CGAffineTransformRotate(myImageView.transform, recognizer.rotation);
Since you're changing the transform property in a serial order, you should use CGAffineTransformRotate, CGAffineTransformTranslate and CGAffineTransformScale instead so that you add to the original transform and not create a new one.

iPhone correct landscape window coordinates

I am trying to get the window coordinates of a table view using the following code:
[self.tableView.superview convertRect:self.tableView.frame toView:nil]
It reports the correct coordinates while in portrait mode, but when I rotate to landscape it no longer reports correct coordinates. First off, it flips the x, y coordinates and the width and height. That's not really the problem though. The real problem is that the coordinates are incorrect. In portrait the window coordinates for the table view's frame are {{0, 114}, {320, 322}}, while in landscape the window coordinates are {{32, 0}, {204, 480}}. Obviously the x-value here is incorrect, right? Shouldn't it be 84? I'm looking for a fix to this problem, and if anybody knows how to get the correct window coordinates of a view in landscape mode, I would greatly appreciate it if you would share that knowledge with me.
Here are some screenshots so you can see the view layout.
Portrait: http://i.stack.imgur.com/IaKJc.png
Landscape: http://i.stack.imgur.com/JHUV6.png
I've found what I believe to be the beginnings of the solution. It seems the coordinates you and I are seeing are being based on the bottom left or top right, depending on whether the orientation is UIInterfaceOrientationLandscapeRight or UIInterfaceOrientationLandscapeLeft.
I don't know why yet, but hopefully that helps. :)
[UPDATE]
So I guess the origin of the window is 0,0 in normal portrait mode, and rotates with the ipad/iphone.
So here's how I solved this.
First I grab my orientation, window bounds and the rect of my view within the window (with the wonky coordinates)
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect windowRect = appDelegate.window.bounds;
CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:nil];
Then if the orientation is landscape, I reverse the x and y coordinates and the width and height
if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
windowRect = XYWidthHeightRectSwap(windowRect);
viewRectAbsolute = XYWidthHeightRectSwap(viewRectAbsolute);
}
Then I call my function for fixing the origin to be based on the top left no matter the rotation of the ipad/iphone.
It fixes the origin depending on where 0,0 currently lives (depending on the orientation)
viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);
Here are the two functions I use
CGRect XYWidthHeightRectSwap(CGRect rect) {
CGRect newRect;
newRect.origin.x = rect.origin.y;
newRect.origin.y = rect.origin.x;
newRect.size.width = rect.size.height;
newRect.size.height = rect.size.width;
return newRect;
}
CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
CGRect newRect;
switch(orientation)
{
case UIInterfaceOrientationLandscapeLeft:
newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), rect.origin.y, rect.size.width, rect.size.height);
break;
case UIInterfaceOrientationLandscapeRight:
newRect = CGRectMake(rect.origin.x, parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
break;
case UIInterfaceOrientationPortrait:
newRect = rect;
break;
case UIInterfaceOrientationPortraitUpsideDown:
newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
break;
}
return newRect;
}
This is a hack, but it works for me:
UIView *toView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
[self.tableView convertRect:self.tableView.bounds toView:toView];
I am not sure this is the best solution. It may not work reliably if your root view controller doesn't support the same orientations as the current view controller.
You should be able to get the current table view coordinates from self.tableView.bounds
Your code should be:
[tableView convertRect:tableView.bounds toView:[UIApplication sharedApplication].keyWindow];
That will give you the view's rectangle in the window's coordinate system. Be sure to use "bounds" and not "frame". frame is the rectangle of the view in its parent view coordinate system already. "bounds" is the view rectangle in its own system. So the above code asks the table view to convert its own rectangle from its own system to the window's system. Your previous code was asking the table's parent view to convert the table's rectangle from the parent coordinate system to nothing.
Try bounds instead of frame
self.parentViewController.view.bounds
for it gives me adjusted coords according to the current orientation

CGPDFPageDrawingTransform not Rotating the Page

The code below is intended to display the pages of a PDF while properly handling any non-zero rotation angles that might be specified for each page. My test PDF file has multiple pages and one them has a 180 degree rotation angle, which the code properly detects, but the call to CGPDFPageGetDrawingTransform (followed by CGContextContactCTM) has no effect. The page is being displayed unrotated. What am I doing wrong?
CGContextSaveGState(context);
CGRect drawRect=self.bounds;
CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
int rotationAngle=CGPDFPageGetRotationAngle(pdfPage);
if (kDebug>1) {
NSLog(#"***** page rotation angle is %d",rotationAngle);
}
CGContextTranslateCTM(context, drawRect.origin.x, drawRect.origin.y);
CGAffineTransform transform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, cropBox, rotationAngle, true);
CGContextConcatCTM (context, transform);
float xScaleFactor=drawRect.size.width / cropBox.size.width;
float yScaleFactor=drawRect.size.height / cropBox.size.height;
CGContextTranslateCTM(context, -CGRectGetMinX(cropBox), CGRectGetMaxY(cropBox)*yScaleFactor);
CGContextScaleCTM(context, xScaleFactor, -yScaleFactor);
CGContextClipToRect(context, cropBox);
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
Thanks,
//Scott
So after a careful re-reading of the API for CGPDFPageGetDrawingTransform, I discover that the value of page's /ROTATE attribute is ADDED to the rotation angle you specify in the method call. In my situation above, the page's /ROTATE happend to be 180. was grabbing that in the rotationAngle var and passing that in to get the transform. So, 180+180 = 360 = no visibile rotation.
I now call GPDFPageGetDrawingTransform with a rotation angle of 0.0. Anything in the /ROTATE is added, and voila, I get the correct results.

Drawing in UIView stops working if view width becomes greater than about 16600

I am using following code to plot graph in a view (in the drawRect method):
CGContextBeginPath(context);
CGContextMoveToPoint(context, devicePoint.x, devicePoint.y);
for (index = 1; index < dataCount; index++) {
devicePoint = [[deviceDataArray objectAtIndex:index] CGPointValue];
CGContextAddLineToPoint(context, devicePoint.x, devicePoint.y);
}
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextStrokePath(context);
It works if the view.bounds.size.width is less than about 16600. But above that size the plot stops appearing.
I resize the view depending on the range of the data to be plotted.
This is very bad idea to make such huge width for view, you must draw only what user can see in one time (or a little more) and use view of normal (screen) size for this. For controlling where user currently is use UIScrollView.
You are probably better off using CAShapeLayers to do the drawing, as they have no actual pixels, just a path that the hardware draws. Then you could have a UIScrollView which just exposed parts of the CAShapeLayers for drawing, otherwise you are making a huge image with the view as large as you have it currently.

How to handle a translation Matrix in an inverted Y axis point of view

My usercase is an iphone application where I do an animation on the scale, rotation and translation of an image.
So, I concat everything and feed it to the transform property, but there is one problem:
Since my images vary in size, it is a problem to position them correctly. I'm used to an inverted y axis coordinate system, so I want my image to positioned exactly at 60 pixels in the y axis.
So, how do I change from the original cartesian y axis to an inverted y axis point of view?
As smacl points out, the easiest way to do this is to shift your origin to the bottom-left of the screen by using (screenheight - viewheight - y) instead of y in the origins of your views.
However, you can flip the coordinate system of your main view's layers using a CATransform3D. I do this so that I can share the same Core Animation CALayer layout code between my iPhone application and a Mac client (the iPhone inverts the normal Quartz coordinate system for CALayers to match that of the UIViews). All you need to do to enable this is to place the line
self.layer.sublayerTransform = CATransform3DMakeScale(1.0f, -1.0f, 1.0f);
in your initialization code for your layer-hosting UIView. Remember that this will flip your CALayers, so any UIKit text rendering in those layers may also need to be flipped using code similar to the following:
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.frame.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
UIFont *theFont = [UIFont fontWithName:#"Helvetica" size:fontSize];
[text drawAtPoint:CGPointZero withFont:theFont];
CGContextRestoreGState(context);
You can do a similar sort of inversion using a CGAffineTransform, but you will also need to apply a translation to make that work:
CGAffineTransform flipTransform = CGAffineTransformMakeTranslation(0.0f, self.frame.size.height);
flipTransform = CGAffineTransformScale(flipTransform, 1.0f, -1.0f);
You may be able to use the affine transform to convert your origin coordinates using CGPointApplyAffineTransform().
For every y ordinate, y = top-y, where top is the y ordinate of the top of the bounding box you are drawing in.