CGContextDrawPDFPage is drawing the page on the wrong origin point - iphone

Edit: It seems that the origin point's components are been multiplied by 2 when drawing the PDF page. Is something I'm doing causing this?
I have a UIViewController that displays a PDF page on a UIScrollView. the PDF page itself is drawn on a CATiledLayer, however, when my view controller draws the layer there is a considerable offset between the layer's bounds and the drawn PDF. As you can see in the picture, the page should have been drawn on the yellow view:
Here is the relevant code that draws the page:
- (void)refreshPage
{
if(contentView) {
for(UIView *v in self.view.subviews) {
[v removeFromSuperview];
[v release];
}
}
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(self._document.page, kCGPDFCropBox));
pageRect.origin.x = ((self.view.frame.size.width / 2) - (pageRect.size.width / 2));
CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self;
tiledLayer.tileSize = CGSizeMake(1024.0, 1024.0);
tiledLayer.levelsOfDetail = 1000;
tiledLayer.levelsOfDetailBias = 1000;
tiledLayer.frame = pageRect;
contentView = [[UIView alloc] initWithFrame:pageRect];
[contentView.layer addSublayer:tiledLayer];
CGRect viewFrame = self.view.frame;
viewFrame.origin = CGPointZero;
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
//[scrollView setBackgroundColor:[UIColor cyanColor]];
//[contentView setBackgroundColor:[UIColor yellowColor]];
scrollView.delegate = self;
scrollView.contentSize = pageRect.size;
scrollView.maximumZoomScale = 1000;
[scrollView addSubview:contentView];
[self.view addSubview:scrollView];
pagingViewController = [[PDFPagingViewController alloc] initWithDocument:self._document AndObserver:self];
[self.view addSubview:pagingViewController.view];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return contentView;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
if(self._document) {
[layer setBackgroundColor:(CGColorRef)[UIColor redColor]];
CGRect drawingRect = CGContextGetClipBoundingBox(ctx);
CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, drawingRect);
CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(self._document.page, kCGPDFCropBox, layer.bounds, 0, true));
CGContextDrawPDFPage(ctx, self._document.page);
}
}

You need to change when you set the pageRect's origin (which I assume you do to center in the view). You are setting both the layer's frame and the contentView's frame to the offset pageRect when you really intend to offset only one.
-(void)refreshPage {
//...
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(self._document.page, kCGPDFCropBox));
CATiledLayer *tiledLayer = [CATiledLayer layer];
//...
tiledLayer.frame = pageRect;
// set the pageRect origin now to center the contentView, not the layer
pageRect.origin.x = ((self.view.frame.size.width / 2) - (pageRect.size.width / 2));
contentView = [[UIView alloc] initWithFrame:pageRect];
[contentView.layer addSublayer:tiledLayer];
//...
}

Related

UIScrollview isn't displayed

Hi I'm testing out drawing and created a simple scrollview and embedded a subview without using interface builder. It displays correctly when I position everything at the origin but if I move everything down past y = 40 it disappears. Alternatively, the scrollview and subview independently display fine at whatever position I place them ie. without setting the view as a subview. Can anyone explain why this would happen?
thanks
the view to be embedded:
#implementation BLRView
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
if(self)
{
[self setBackgroundColor:[UIColor blackColor]];
}
return self;
}
- (void) drawRect:(CGRect)dirtyRect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
CGContextSetLineWidth(ctx, 30);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
float dashphase = 1.0;
float dashlengths[] = {1.0, 20.0};
CGContextSetLineDash(ctx, dashphase , dashlengths, 2);
CGContextMoveToPoint(ctx, bounds.origin.x, bounds.origin.y);
CGContextAddLineToPoint(ctx, bounds.size.width , bounds.origin.y);
CGContextStrokePath(ctx);
}
#end
and in the appdelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect screenRect = [[self window] bounds];
//this displays
CGRect viewFrame = CGRectMake(0, 0, screenRect.size.width * 3, 50);
CGRect scrollFrame = CGRectMake(0, 0, screenRect.size.width, 50);
//this is slightly cut off at the bottom
//CGRect viewFrame = CGRectMake(0, 30, screenRect.size.width * 3, 50);
//CGRect scrollFrame = CGRectMake(0, 30, screenRect.size.width, 50);
//this isnt shown
//CGRect viewFrame = CGRectMake(0, 100, screenRect.size.width * 3, 50);
//CGRect scrollFrame = CGRectMake(0, 100, screenRect.size.width, 50);
UIScrollView *scrollview = [[UIScrollView alloc] initWithFrame:scrollFrame];
BLRView *view = [[BLRView alloc]initWithFrame:viewFrame];
[[self window] addSubview:scrollview];
[scrollview addSubview:view];
[scrollview setContentSize:viewFrame.size];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Sorry, i'm an idiot. The embedded view frame is being pushed down from the origin of the scroll frame
these should be
CGRect viewFrame = CGRectMake(0, 0, screenRect.size.width * 3, 50);
CGRect scrollFrame = CGRectMake(0, 30, screenRect.size.width, 50);

UIImageView pinch zooming in UIScrollView

I am comfortable with pinch zooming functionality using UIScrollView. But the problem is the aspect fit of image in scrollview.
Currently, I am having this, below image:
But I want image to be fit in screen like below image:
And same behavior for landscape. How can I achieve this?
Below is the code:
- (void)viewDidLoad
{
UIImage *image = [UIImage imageWithData:appDelegate.selectedOriginalImage];
imgView.image = image;
CGSize imageSize = image.size;
CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);
imgView.frame = rect;
scrollView.contentSize = CGSizeMake(imgView.frame.size.width, imgView.frame.size.height);
scrollView.maximumZoomScale = 4.0;
scrollView.minimumZoomScale = 1.0;
scrollView.delegate = self;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
UIImage *image = [UIImage imageWithData:appDelegate.selectedOriginalImage];
CGSize imageSize = image.size;
CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);
imgView.frame = rect;
[scrollView setContentOffset:CGPointMake(0, 0)];
return YES;
}
You are setting the UIImageView to the original size of the image instead of the size of the UIScrollView that contains it.
- (void)viewDidLoad
{
UIImage *image = [UIImage imageWithData:appDelegate.selectedOriginalImage];
imgView.image = image;
imgView.frame = scrollView.bounds;
[imgView setContentMode:UIViewContentModeScaleAspectFit];
scrollView.contentSize = CGSizeMake(imgView.frame.size.width, imgView.frame.size.height);
scrollView.maximumZoomScale = 4.0;
scrollView.minimumZoomScale = 1.0;
scrollView.delegate = self;
}
remember to return the imgView on the viewToZoom delegate method

Position UILabel in circle

I want to position a UILabel in the center of my Circle but I can't seem to affect the position of the label. I can only seem to affect the position of the label by changing the height of CGRect frame. changing the other values doesn't affect the position at all.
here's my Circle.m code
- (id)initWithFrame:(CGRect)frame radius:(CGFloat)aRadius color:(UIColor*) aColor {
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
[self setRadius:aRadius];
[self setColor:aColor];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSString *string = #"1";
UIFont* font = [UIFont systemFontOfSize:80];
UILabel *label = [[UILabel alloc] init];
label.text = string;
label.textColor = [UIColor whiteColor];
label.font = font;
CGRect frame = label.frame;
frame = CGRectMake(10, 10, 0, 85);
label.frame = frame;
CGContextRef contextRef = UIGraphicsGetCurrentContext();
[color setFill];
circle = CGRectMake(0, 0, radius, radius);
CGContextAddEllipseInRect(contextRef, circle);
CGContextDrawPath (contextRef, kCGPathFill);
[label drawRect:circle];
}
and my viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat radius = 70;
CGRect position = CGRectMake(0, 0, radius, radius);
Circle *myCircle = [[Circle alloc] initWithFrame:position radius:radius color:[UIColor redColor]];
[self.view addSubview:myCircle];
}
You should not be allocating new UIViews in drawRect: (and UILabel is a subclass of UIView). There are a few good ways of doing what you want, but none of them involve allocating a new UILabel in drawRect:.
One way is to make your Circle give itself a UILabel subview in its initializer, and center the label in layoutSubviews. Then in drawRect:, you just draw the circle and don't worry about drawing the label's text:
#implementation Circle {
UILabel *_label;
}
#synthesize radius = _radius;
#synthesize color = _color;
- (id)initWithFrame:(CGRect)frame radius:(CGFloat)aRadius color:(UIColor*) aColor {
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
[self setRadius:aRadius];
[self setColor:aColor];
_label = [[UILabel alloc] init];
_label.font = [UIFont systemFontOfSize:80];
_label.textColor = [UIColor whiteColor];
_label.text = #"1";
[_label sizeToFit];
[self addSubview:_label];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGSize mySize = self.bounds.size;
_label.center = CGPointMake(mySize.width * 0.5f, mySize.height * 0.5f);
}
- (void)drawRect:(CGRect)rect {
[self.color setFill];
CGSize mySize = self.bounds.size;
CGFloat radius = self.radius;
[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(mySize.width * 0.5f, mySize.height * 0.5f, self.radius, self.radius)] fill];
}

Subclassing UIScrollview

I have been trying desperately to draw some images into a view. The view should be inside a scrollview. For that I subclassed UIScrollview and override the drawRect method in it. And added this as my UIView's subview.
#interface DrawAnotherViewClass : UIScrollView<UIScrollViewDelegate> {
}
#end
#implementation DrawAnotherViewClass
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
self.frame = fullScreenRect;
self.contentSize = CGSizeMake(600, 600);
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = NO;
self.pagingEnabled = YES;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 10.0f, 50.0f);
CGContextAddLineToPoint(context, 10.0f, 200.0f);
CGContextStrokePath(context);
CGContextMoveToPoint(context, 8.0f, 77.0f);
CGContextAddLineToPoint(context, 300.0f, 77.0f);
CGContextStrokePath(context);
CGContextSetRGBFillColor(context, 0, 0, 255, 0.1);
CGContextSetRGBStrokeColor(context, 0, 0, 255, 1);
CGContextStrokeEllipseInRect(context, CGRectMake(65.0, 33.5, 25, 25));
UIImage *image1 = [UIImage imageNamed:#"PinDown1.png"];
UIImage *image2 = [UIImage imageNamed:#"pinGreen_v1.png"];
CGPoint drawPoint = CGPointMake(0.0f, 10.0f);
[image2 drawAtPoint:drawPoint];
for(int i =1; i<20; i++){
CGPoint drawPointOne = CGPointMake(40.0f * i, 40.0f);
[image1 drawAtPoint:drawPointOne];
}
}
Am I missing something here. Is this the right way to go.
If the view that should perform the drawing resides in that UIScrollView, you have to put the - (void)drawRect:(CGRect)rect method into that view's class method and not into the UIScrollView subclass.

UIView's drawRect is not getting called

I am trying to display horizontal and/or vertical lines in a grid. So I created a UIView subclass GridLines that draws lines in drawRect:. I then create two of these (one vertical, one not), and add them as subviews to my primary view (Canvas) also UIView derived. The other custom subviews I add to Canvas are displayed, removed, etc. properly, but the GridLines objects are not, and their drawRect:s never get called. When I had this line-drawing code in [Canvas drawRect:] (which is now disabled), it displayed the grid properly.
Looking through similar questions, it seems most people with this issue are calling drawRect in a non-UIView derived class, but mine is a UIView.
Am I missing something here?
GridLines.h:
#import <UIKit/UIKit.h>
#interface GridLines : UIView
{
BOOL mVertical;
}
- (id) initWithFrame: (CGRect) _frame vertical: (BOOL) _vertical;
#end
GridLines.m:
#import "GridLines.h"
#implementation GridLines
- (id) initWithFrame: (CGRect) _frame vertical: (BOOL) _vertical
{
if ((self = [super initWithFrame: _frame]))
{
mVertical = _vertical;
}
return self;
}
- (void) drawRect: (CGRect) _rect
{
NSLog(#"[GridLines drawRect]");
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor clearColor] set];
UIRectFill([self bounds]);
if (mVertical)
{
for (int i = 50; i < self.frame.size.width; i += 50)
{
CGContextBeginPath(context);
CGContextMoveToPoint(context, (CGFloat)i, 0.0);
CGContextAddLineToPoint(context, (CGFloat)i, self.frame.size.height);
[[UIColor grayColor] setStroke];
CGContextSetLineWidth(context, 1.0);
CGContextDrawPath(context, kCGPathFillStroke);
}
}
else
{
for (int j = 50; j < self.frame.size.height; j += 50)
{
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, (CGFloat)j);
CGContextAddLineToPoint(context, self.frame.size.width, (CGFloat)j);
[[UIColor grayColor] setStroke];
CGContextSetLineWidth(context, 1.0);
CGContextDrawPath(context, kCGPathFillStroke);
}
}
}
#end
In another UIView derived class:
- (void) createGrids
{
mHorizontalLines = [[GridLines alloc] initWithFrame: self.frame vertical: NO];
mVerticalLines = [[GridLines alloc] initWithFrame: self.frame vertical: YES];
[self addSubview: mHorizontalLines];
[self addSubview: mVerticalLines];
}
You may have a frame v bounds problem.
mHorizontalLines = [[GridLines alloc] initWithFrame: self.frame vertical: NO];
mVerticalLines = [[GridLines alloc] initWithFrame: self.frame vertical: YES];
frame is kept in superview's co-ordinate space, if self.frame is offset more that it is wide, when you set these new views to that frame, they'll be clipped to rect of self.
try changing this to self.bounds, which should have origin = {0,0}