Showing text with CGContextShowTextAtPoint draws strange text - ios

I'm just trying to overlay a text in a UIImage (using CGContext) but it doesn't show the text I specified. In this code I'm giving as the text argument "Hello" but it shows "eÉääc". I don't know what's happening I think the characters are displaced but I don't know how to solve it.
This is my code:
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0);
CGContextRef c = UIGraphicsGetCurrentContext();
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
CGContextSetTextMatrix(c, CGAffineTransformMake(1.0, 0, 0, -1.0, 0, 0));
CGContextSelectFont(c, "ArialMT", 50, kCGEncodingFontSpecific);
CGContextSetRGBStrokeColor(c, 255, 0, 0, 1);
CGContextSetRGBFillColor(c, 255, 0, 0, 1);
CGContextSetCharacterSpacing(c, 2);
CGContextShowTextAtPoint(c,100,100, "Hello", 5);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I'm using the Spanish Keyboard (I don't know if this matters) and the iPad (where I'm testing the application) is in Catalan.

CGContextShowTextAtPoint() interprets the given text according to the specified encoding parameter of CGContextSelectFont. You have chosen kCGEncodingFontSpecific, which is the font built-in encoding (whatever that might be).
The only other choice is kCGEncodingMacRoman:
CGContextSelectFont(c, "ArialMT", 50, kCGEncodingMacRoman);
Then your text should display correctly, as long as you use only characters from the ASCII character set.
For non-ASCII characters, you have to convert the string to the MacRoman encoding, see e.g. https://stackoverflow.com/a/13743834/1187415 for an example.
Note that CGContextShowTextAtPoint cannot display general Unicode strings, and even has problems with the Euro (€) character. The drawAtPoint:withFont: method of NSString does not have these limitations.

Related

Losing NSTextEffectLetterpressStyle when drawing into CGBitmapContext

I am drawing text on top of a solid background color, and while it is appearing, the NSTextEffectLetterpressStyle effect applied to the attributed string isn't showing up - you can only see the text color not the additional white outline that provides the desired look. It looks essentially the exact same as if I didn't apply the letterpress effect. Why is this, how can I draw the letterpress text effect correctly?
let bitmapContext = CGBitmapContextCreate(nil, UInt(imageRect.width), UInt(imageRect.height), UInt(8), UInt(imageRect.width * 16), CGColorSpaceCreateDeviceRGB(), CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue))
CGContextSetFillColorWithColor(bitmapContext, UIColor.blackColor().CGColor)
let fullBox = CGRectMake(0, 0, imageRect.width, imageRect.height)
CGContextAddRect(bitmapContext, fullBox)
CGContextFillPath(bitmapContext)
CGContextSetTextDrawingMode(bitmapContext, kCGTextFill)
CGContextSetTextPosition(bitmapContext, drawPoint.x, drawPoint.y)
let coloredAttributedString = NSAttributedString(string: "20", attributes:[NSFontAttributeName: myFont, NSForegroundColorAttributeName: textColor, NSTextEffectAttributeName: NSTextEffectLetterpressStyle])
let displayLineTextColored = CTLineCreateWithAttributedString(coloredAttributedString)
CTLineDraw(displayLineTextColored, bitmapContext)
let cgImage = CGBitmapContextCreateImage(bitmapContext)
var myImage = CIImage(CGImage: dateStampCGImage)
This is the result:
This is what I expected it to be (notice the white-ish outline):
Both CFAttributedString and NSAttributedString can apply arbitrary attributes to ranges. The attributed string types don't inherently interpret the attributes.
Rather, the string drawing technologies interpret the attributes. Core Text understands a different set of attributes than UIKit or AppKit. The set of attributes supported by Core Text is documented here. It does not list (an equivalent of) NSTextEffectAttributeName.
If you set up a current graphics context using UIGraphicsBeginImageContextWithOptions() and draw into that using the NSAttributedString drawing methods, that should work, since it's using UIKit to do the drawing.

Drawing text with an MKOverlayRenderer

I'm trying to render text on a map using an MKOverlayRenderer. I have an existing, functional MKOverlayRenderer rendering a set of points, so my only problem is rendering a piece of text for each point within the '-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context' function.
All solutions I have found through SO and Google use annotations or UILabels. But I want to have the text drawing code in the same location as the code rendering the points. Also there are about 10,000 points, though I'm ensuring it's not rendering them all at the same time through zoom and bounds checking. I am reasonably sure I don't want to create 10,000 objects with the other solutions.
This is the current test code I have to try to render one of the 'Text Text' items. It is a combination of some of the methods I have found on the net to try to render something.
CGPoint* point = self.pointList.pointArray + pointIndex;
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSelectFont(context, "Helvetica", 20.f, kCGEncodingFontSpecific);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, xform);
CGContextShowTextAtPoint(context, point->x, point->y, "Test Text 1", 11);
CGContextShowTextAtPoint(context, 10, 10, "Test Text 2", 11);
CGContextShowText(context, "Test Text 4", 11);
UIFont* font = [UIFont fontWithName:#"Helvetica" size:12.0];
[#"Test Text 3" drawAtPoint:*point withFont:font];
This is my first SO questions, so sorry if it isn't that correct.
Edit: I just saw the text when zoomed in as far as I can go, so realise I haven't been accounting for the zoom scale. Assuming I need to do a scale transform before rendering to account for it. Haven't solved it currently, but I think I am on my way.
I have solved it. Sorry for posting this, but I was at my wit's end and thought I needed help.
The line that rendered was:
CGContextShowTextAtPoint(context, point->x, point->y, "Test Text 1", 11);
Which is a deprecated function, but I don't know any other way to render to a specific context.
To fix it, the affine transform became:
CGAffineTransform xform = CGAffineTransformMake(1.0 / zoomScale, 0.0, 0.0, -1.0 / zoomScale, 0.0, 0.0);
The other error was that the 'select font' call needed to become:
CGContextSelectFont(context, "Helvetica", 12.f, kCGEncodingMacRoman);
I had copied the other encoding from some example code I had seen on the net, but it causes the text to have wrong characters.
If there is still a way I can do it without using the deprecated CGContextShowTextAtPoint function I would still love to know.

How to display dashed lines in objective-c?

I have this code to display a grid with dashed line. In runtime on an iphone 5 below it shows fine, but if I run the app on iphone 5s there's no grid. I tested in iPhone Simulator and on real devices and happens the same.
Here's the code:
if (self.dashLongitude) {
CGFloat lengths[] = {3.0, 3.0};
CGContextSetLineDash(context, 0.0, lengths, 2);
}
//other stuff here
CGContextSetLineDash(context, 0, nil, 0);
So anyone could help??
EDIT: Hey guys I solved the issue using the same code I posted here, but in a different method. So I have now two methods: one just for the drawing the grid and another on to draw the line with data and finally got everything working.
The code looks fine.
As I look into the code I saw you are setting the nil in the context. nil is used to remove the dashed line.
Try to use
CGFloat dash[] = {2.0, 2.0};
CGContextSetLineDash(context, 0.0, dash, 2);
where you are creating or provide stroke your line(underneath).
CGContextSetLineDash(context, 0, NULL, 0);
is used to remove that dash pattern.
Instead of setting nil in CGContextSetLineDash, just wrap your code into CGContextSaveGState/CGContextRestoreGState to preserve context state before applying line dash:
CGContextSaveGState(context);
CGFloat dash[] = {2.0, 2.0};
CGContextSetLineDash(context, 0.0, dash, 2);
// Draw some lines here
CGContextRestoreGState(context);

CGImageCreateWithMaskingColors No Matching Functions

I'm using the QR Code creation project at https://github.com/kuapay/iOS-QR-Code-Generator within my project. I've added it in exactly as the instructions say.
I can compile and run the project on my test devices with no problem what-so-ever, but when I try to archive it, I get the following error:
Path/to/project/Barcode.mm:67:33: No matching function for call to 'CGImageCreateWithMaskingColors'
I am pulling my hair out on this one. Here's the code snippet where it's called along with the variable declarations that it's using.
CGImageRef rawImageRef = image.CGImage;
const float colorMasking[6] = {222, 255, 222, 255, 222, 255};
UIGraphicsBeginImageContext(image.size);
CGImageRef maskedImageRef = CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
I know the asker found his answer, but my problem was with release build where it is supposed to be NO. Because we want non-active architectures too!
Problem lies in XCode being much more type-strict with 64-bit builds in new XCode 5.1(5B130a). CGImageCreateWithMaskingColors second parameter is CGFloat, so changing the type from float to CGFloat fixed it.
//const float colorMasking[6] = {222, 255, 222, 255, 222, 255};//before
const CGFloat colorMasking[6] = {222, 255, 222, 255, 222, 255};//after
UIGraphicsBeginImageContext(image.size);
CGImageRef maskedImageRef = CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
Since the answer is in the comments of the question, I'm answering it myself just to have a marked answer. In the build settings for "Build for active architectures only" for Debug I had YES, and release I had NO. I switched the release version to YES, and it worked with no problem.
Thanks to Wain for pointing me in the right direction.

no german umlaute with function "ShowTextAtPoint" in CGBitmapContext

we have a problem displaying text with german umlaute with the function ShowTextAtPoint in CGBitmapContext. The umlaute characters are not displayed.
We tried to convert Code from XCode:
CGContextSelectFont(MyBitmapContext, FontName, 24, kCGEncodingMacRoman);
CGContextShowTextAtPoint(MyBitmapContext, x, y, [caption cStringUsingEncoding:
NSMacOSRomanStringEncoding], [caption length]);
to MonoTouch:
MyBitmapContext.SelectFont(FontName, 24, CGTextEncoding.MacRoman);
MyBitmapContext.ShowTextAtPoint(x, x, caption , caption.Length);
Thanks a lot for any help.
Frank
The problem is that CoreGraphics APIs for CGContext do not support rendering UTF8 code, it is limited to the text encoding in MacRoman (as you showed in your sample).
The fix is to use the UIKit functions instead, to do this, you can change your code to be like this:
UIGraphics.PushContext (mBmpContext);
mBmpContext.SetRGBFillColor(1f,1f,1f,1f);
var font = UIFont.FromName ("Arial", 30);
using (var nsstr = new NSString ("äöü ÜÖÄ")){
nsstr.DrawString (new PointF (10, 400), font);
}
UIGraphics.PopContext ()

Resources