Why is my text flip over when using CGContextShowAtPoint? - iphone

I am writing a simple practice. However, my text is flip upside down when I trying to use CGContext to put some string on the UIView, I am wondering why and how to change it into correct format.
Here is my code in the drawRect
char *string = "TEST";
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
CGContextSelectFont (context,"Helvetica-Bold",12, kCGEncodingMacRoman);
CGContextShowTextAtPoint(context, 5, 5, string, strlen(string));
CGContextClosePath(context);
Thanx for your help.

CoreGraphics uses cartesian coordinates, so you need to translate your context before doing any drawing
CGContextRef context = UIGraphicsGetCurrentContext();
// transforming context
CGContextTranslateCTM(context, 0.0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// your drawing code

Quartz2D has an inverted y axis - handy eh? If you are inside a drawRect method, you can use the following to flip the text over.
CGContextTranslateCTM(context, 0.0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
Another way is;
transform = CGAffineTransformMake(1.0,0.0,0.0,-1.0,0.0,0.0);
CGContextSetTextMatrix(context, transform);
Or on one line;
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));

Use the UIKit additions in NSString:
NSString *string = #"TEST";
[string drawAtPoint:CGPointMake(5, 5)
withFont:[UIFont boldSystemFontOfSize:12]];

Related

Swift - drawing lines from one point to another

What is the best way to draw lines from one point to another? I want to draw a line that is the most efficient way to the next point. Should I be using NSBezierPath?
How would I start this or start learning about this?
Sebastian is totally correct on this; don't make it harder than it needs to be. To add a few more details, the following code draws a box around a window:
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
NSRect nsBounds = [self bounds]; // Get the bounds
CGRect cgBounds = NSRectToCGRect(nsBounds); // Sets the graphics bounds
// ******************************************** Box the Window in Gray ********************************************
CGContextMoveToPoint(context, 0.0,1.0);
CGContextAddLineToPoint(context,0.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, 1.0);
CGContextAddLineToPoint(context,0.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.7, 1.0);
CGContextStrokePath(context);

iPhone - Image drawn upside down into a CGGraphic context (custom UIView)

I have a custom view with that code :
- (void)drawRect:(CGRect)rect
{
UIImage* theImage = [UIImage imageNamed:#"blue_arrow"];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 1.0);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGPoint posOnScreen = self.center;
CGContextDrawImage(context, CGRectMake(posOnScreen.x - theImage.size.width/2,
posOnScreen.y - theImage.size.height/2,
theImage.size.width,
theImage.size.height),
theImage .CGImage);
}
The image is an arrow, pointiing to the top.
But when drawn, it is draw upside down, pointing to bottom.
What causes that problem ?
How may I correct that, naturally without side effect ?
This is because Core Graphics is using a flipped coordinate system.
You could try flipping the object you're drawing to using the isFlipped property.
Or you could try using this code in your drawing method (Source):
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

iPhone - Draw some text with CGContext : ok but... mirrored

When I draw some text using CGContext, it is drawn mirrored.
I tried to apply some transformations, then it is draw well, but then the rest of the drawing and all coordinates seems to be draw bad.
I tried to save and restore the context, before and ater drawing the text (and aplying transformation), but that does not help.
How some text must be drawn onto a View using CGContext without affecting the rest of the drawing, nor the onscreen CGPoint coords for that text ?
Can you clarify what you mean as 'mirrored'? Here is some code for drawing some black text. It should not be 'mirrored'.
CGRect viewBounds = self.bounds;
CGContextTranslateCTM(ctx, 0, viewBounds.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextSetRGBFillColor(ctx, 0.0, 1.0, 0.0, 1.0);
CGContextSetLineWidth(ctx, 2.0);
CGContextSelectFont(ctx, "Helvetica", 10.0, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(ctx, 1.7);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGContextShowTextAtPoint(ctx, 100.0, 100.0, "SOME TEXT", 9);
I think you have to reverse the text matrix :
CGAffineTransform transform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, transform);

Drawing a PDF Right-Side-Up in CGContext

I'm overriding the drawRect: method in a custom UIView, and I'm doing some custom drawing. All was going well, until I needed to draw a PDF resource (a vector glyph, to be precise) into the context. First I retrieve the PDF from a file:
NSURL *pdfURL = [NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"CardKit.bundle/A.pdf"]];
CGPDFDocumentRef pdfDoc = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDoc, 1);
Then I create a box with the same dimensions as the loaded PDF:
CGRect box = CGPDFPageGetBoxRect(pdfPage, kCGPDFArtBox);
Then I save my graphics state, so that I don't screw anything up:
CGContextSaveGState(context);
And then I perform a scale+translate of the CTM, theoretically flipping the whole context:
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, rect.size.height);
I then scale the PDF so that it fits into the view properly:
CGContextScaleCTM(context, rect.size.width/box.size.width, rect.size.height/box.size.height);
And finally, I draw the PDF and restore the graphics state:
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
The issue is that there is nothing visible drawn. All this code should theoretically draw the PDF glyph into the view, right?
If I remove the scale+translate used to flip the context, it draws perfectly: it just draws upside-down.
Any ideas?
Try doing the translate before the scale:
CGContextTranslateCTM(context, 0.0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGPDFPageRef page = CGPDFDocumentGetPage(pdf, currentPage);
CGContextSaveGState(context);
CGRect box = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGContextScaleCTM(context, self.bounds.size.width/box.size.width, self.bounds.size.height/box.size.height);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
This is the right answer to your question
To scale before translate, I think we can put minus when translate.
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -rect.size.height);
This flips everything right side up for me:
pdfDisplayView.layer.geometryFlipped = YES; //(NO)

Flipped NSString drawing in CGContext

I try to draw a string in this texture:
http://picasaweb.google.it/lh/photo/LkYWBv_S_9v2d6BAfbrhag?feat=directlink
but the green numbers seem vertical flipped.
I've created my context in this way:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
and i've draw the strings:
UIGraphicsPushContext(context);
for(int i=0;i<packs.size();++i)
{
CGPoint points[4] =
{
gltextures[i].texCoords[0] * size.width, //0
gltextures[i].texCoords[1] * size.height, //1
gltextures[i].texCoords[2] * size.width, //2
gltextures[i].texCoords[3] * size.height, //3
gltextures[i].texCoords[4] * size.width, //4
gltextures[i].texCoords[5] * size.height, //5
gltextures[i].texCoords[6] * size.width, //6
gltextures[i].texCoords[7] * size.height //7
};
CGRect debugRect = CGRectMake
(
gltextures[i].texCoords[0] * size.width,
gltextures[i].texCoords[1] * size.height,
gltextures[i].width,
gltextures[i].height
);
CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextAddLines(context, points, 4);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathStroke);
NSString* s = [NSString stringWithFormat:#"%d",gltextures[i].texID];
UIFont* font = [UIFont fontWithName:#"Arial" size:12];
CGContextSetRGBFillColor(context, 0, 1, 0, 1);
[s drawAtPoint:points[0] withFont:font];
}
UIGraphicsPopContext();
The transformation matrix seems the Identity matrix... no CGAffineTransform is applied to THIS context.
If the string is flipped, maybe, all my images are flipped!
Any suggestion?
PS: sorry for my english ;)
As describe here, the coordinate system for a context within a UIView or its layer is inverted when compared to the normal Quartz drawing space. However, when using Quartz to draw to an image, this is no longer the case. The UIStringDrawing Cocoa Touch category on NSString that gives you the -drawAtPoint:withFont: method assumes an inverted layout, and that's why you're seeing the flipped text in your image.
One way to work around this would be to save the graphics state, apply an invert transform to the image, draw the text, and restore the old graphics state. This would look something like the following:
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
[text drawAtPoint:CGPointMake(0.0f, 0.0f) withFont:font];
CGContextRestoreGState(context);
This is a fairly crude example, in that I believe it just draws the text at the bottom of the image, but you should be able to adjust the translation or the coordinate of the text to place it where it's needed.
Better save the text 's matrix before draw, otherwise it will affect other text draw by CoreGraphic:
CGContextSaveGState(ctx);
CGAffineTransform save = CGContextGetTextMatrix(ctx);
CGContextTranslateCTM(ctx, 0.0f, self.bounds.size.height);
CGContextScaleCTM(ctx, 1.0f, -1.0f);
[str drawAtPoint:point withFont:font];
CGContextSetTextMatrix(ctx, save);
CGContextRestoreGState(ctx);