Drawing Unicode characters on iPhone - iphone

Why is it so hard to figure out how to draw Unicode characters on the iPhone, deriving simple font metrics along the way, such as how wide each imaged glyph is going to be in the font of choice?
It looks like it'd be easy with NSLayoutManager, but that API apparently isn't available on the phone. It appears the way people are doing this is to use a private API, CGFontGetGlyphsForUnichars, which won't get you past the Apple gatekeepers into the App store.
Can anybody point me to documentation that shows how to do this? I'm losing hair rapidly.
Howard

I assumed that the exclusion of CGFontGetGlyphsForUnichars
was an oversight rather than a deliberate move, however I'm not
betting the farm on it. So instead I use
[NSString drawAtPoint:withFont:]; (in UIStringDrawing.h)
and
[NSString sizeWithFont];
This also has the advantage of performing decent substitution
on characters missing from your font, something that
CGContextShowGlyphs does not do.

CoreText is the answer if you want to draw unicode rather than CGContextShowGlyphsAtPositions. Also it's better than [NSString drawAtPoint:withFont:] if you need custom drawing.
Here is a complete example:
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedString);
CFArrayRef runArray = CTLineGetGlyphRuns(line);
//in more complicated cases make loop on runArray
//here I assumed this array has only 1 CTRunRef within
const CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, 0);
//do not use CTFontCreateWithName, otherwise you won't see e.g. chinese characters
const CTFontRef font = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
CFIndex glyphCount = CTRunGetGlyphCount(run);
CGGlyph glyphs[glyphCount];
CGPoint glyphPositions[glyphCount];
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
//you can modify positions further
CTRunGetPositions(run, CFRangeMake(0, 0), glyphPositions);
CTFontDrawGlyphs(font, glyphs, glyphPositions, glyphCount, context);
CFRelease(line);

I've made a pretty suitable replacement for the private function. Read about it here:
http://thoughts.codemelody.com/2009/07/a-replacement-for-cgfontgetglyphsforunichars/

Related

Is there a way to determine Unicode character browser compatibility?

Is there a way to determine unicode compatibility, particularly with newer sets? I want to use the Unicode 6.0 character ❌ (❌), but was not sure which browsers it was compatible with. Searched on caniuse.com, but could not find compatability tables.
This is not a browser issue. Any browser can handle the character ❌, but the user would need to have a font installed that has a shape for it otherwise they'll see some kind of placeholder.
A glyph for U+274C Cross Mark ❌ is supplied as part of fonts bundled with Windows 7, and at least the Android and Ubuntu versions I have here, so that's not bad. If you need to be sure, you can use an embedded font that has such a glyph.
Alternatively there's the very old and well-supported U+00D7 Multiplication Sign ×, or other alternatives.
(There are cases when a browser—or, more specifically, the text layout engine used by the browser—does need to understand what a character is to render it correctly, in addition to having font support. But that's for when characters are added as part of complex scripts like Arabic where characters change their shape in response to context. Not a concern for simple standalone characters like ❌.)
You can check if an emoji is supported by:
Rendering it into a Canvas.
Resizing it to a 1 × 1 to get a single pixel average of it.
Comparing that average value to the one you get when rendering the square character that shows up when an emoji is missing.
Something like this (just a starting point, it just works on Chrome):
function emojiExists(emoji) {
try {
const canvas = document.createElement('CANVAS');
const context = canvas.getContext('2d');
// Set font baseline, size and family:
context.textBaseline = 'top';
context.font = '100px sans-serif';
// Scale so that we get a 1 x 1 representation of the emoji
// (just an average of all the pixels):
context.scale(0.01, 0.01);
// Write the emoji:
context.fillText(emoji, 0, 0);
// Just for testing. Uncoment this line and comment context.scale(...);
// document.body.appendChild(canvas);
// [0, 0, 0, 42] is the value returned for the rectangle character that shows
// up for missing emojis:
return context.getImageData(0, 0, 1, 1).data.join(',') !== '0,0,0,42';
} catch (err) {
// Canvas might not be suported...
}
}
console.log(emojiExists('😃')); // https://emojipedia.org/smiling-face-with-open-mouth/
console.log(emojiExists('💭')); // https://emojipedia.org/right-anger-bubble/
console.log(emojiExists('🛹')); // https://emojipedia.org/skateboard/
console.log(emojiExists('🇨🇳')); // https://emojipedia.org/flag-for-china/
For me, with Chrome Version 63.0.3239.132 (Official Build) (64-bit), I get true, true, false, false, but it doesn't work right in Firefox. It seems to be a known bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1209480
You might need to adapt the code (and change or dynamically calculate the '0,0,0,42' value) when using custom fonts or different browsers.

How to display superscript for third power/cube characters as a string in UILabel?

I'm trying to find solution for it and confused how do I display third power/ cube in a UILabel. I tried to find answer in previously asked question but none of them were useful.
Questions i tried to get answers :
how-to-show-superscript-for-registered-symbol
UILabel and superscript
If I have to use unichars how do I use them for Superscripts??
Thanks..
You need to include the unicode symbol for a superscripted three:
NSInteger number = 10;
NSString *cubedSymbol = #"\u00B3";
NSString *tenCubed = [NSString stringWithFormat:#"%d%#",number,cubedSymbol];
Plenty more fun is to be had here
Another solution would be to use the Core Text framework to draw an NSAttributedString with the kCTSuperscriptAttributeName attribute on the section of the string you want to make superscript. This ends up being more work including custom drawing and things, but is more flexible than relying on unicode characters.
Here’s a blog post I found with some more information: http://iphonedevelopment.blogspot.com/2011/03/attributed-strings-in-ios.html
NSAttributedString on Mac OS X has lots of nice uses built into AppKit, but Apple hasn’t made it easy with UIKit for iOS.

How to Display International Accents with Quartz/Core Graphics on iPhone

I've localized an app for the iPhone. No surprise, the localization includes some accents:
"Touch cards to select. Then touch
'Bid'." = "Touchez les cartes pour les
sélectionner, puis touchez 'Miser'.";
These work fine in high-level stuff, like when I put the text into a table, but when I try to write them to a UIView by hand, the accents get mangled:
I'm using kCGEncodingMacRoman and UTF8, both of which should support accents, I think, but I'm clearly missing something:
CGContextSelectFont(ctx,fontName,thisWriting.fontSize,kCGEncodingMacRoman);
CGContextShowTextAtPoint(ctx,
thisWriting.center.x - floor(thisTextSize.width/2),
yThusFar,
[thisText UTF8String],
[thisText length]);
The font is some variant of ArialMT. thisText is just an NSString.
Quartz provides a limited, low-level interface for drawing text. For information on text-drawing functions, see CGContext Reference. For full Unicode and text-layout support, use the services provided by Core Text or ATSUI).
To expand on what sorin said: Quartz/Core Graphics do not support Unicode text, which includes the accents you need for foreign languages. There have traditionally been a number of alternative ways to resolve this, but currently the best answer is to use Core Text, which can write directly to a graphical context, as I was doing here.
The main element in Core Text is the NSAttributedString or NSMutableAttributed String class.
Here's similar code to what I had for Core Text:
CTLineRef thisLine = CTLineCreateWithAttributedString((CFAttributedStringRef)thisAText);
CGContextSetTextPosition(ctx, self.center.x - floor(thisTextSize.width/2), yThusFar);
CTLineDraw(thisLine, ctx);
The font is already taken care of, because it's part of that NSAttributedString (or CFAttributedStringRef, which is a toll-free bridged equivalent).
Here's the result:

iPhone: Reading Text From File and UISegmentedControl

First off, I'm a complete beginner.
That said, I thought an ambitious longer-term project/learning experience would be to create an app that displayed daily quotes, like those cheesy day-by-day calendars our grandmothers have in their bathrooms. I want it to have two per day, each one represented by a tab in a UISegmentedControl. That's the long term. Right now I'd be happy with getting a single day's worth of quotes functioning.
Onto the questions:
How can I get text saved in a .txt or .rtf file to be displayed in a UITextView? Preferably without using 'stringWithContentsOfFile,' since Xcode is telling me that's deprecated.
How can I get content from a different file (or maybe a different portion of the same file...?) to be displayed when the user taps the second segment?
If I can get it running so that those two conditions are met and I understand what's going on, I'll consider the day a success. Thanks!
1.
NSError *error = nil;
NSStringEncoding stringEncoding;
NSString *fileText = [NSString stringWithContentsOfFile:#"/path" usedEncoding:&stringEncoding error:&error];
myTextView.text = fileText;
The error and encoding are optional, and you can pass in nil for both. But if you care about the error, or what encoding the file was in they will have useful info in them after the string is created.
2.
Set the valueChanged outlet in Interface Builder to an IBAction on your controller, such as setSegmentValue:. Then, assuming you have an array of quote strings:
- (IBAction)setSegmentValue:(id)sender {
UISegmentedControl *control = (UISegmentedControl*)sender;
NSString *quote = [quotes objectAtIndex:control.selectedSegmentIndex];
myTextView.text = quote;
}
Even though stringWithContentsOfFile: is deprecated, stringWithContentsOfFile:usedEncoding:error: is not. That is the standard method to use for reading from files.
As for the second question, you simply test the state of the segmented control and perform as action based on it. Admittedly this is a high level answer but should get you going.

Using .png files instead of using .ico files in windows programs

hi I have a collection of nice .png files....
meanwhile, I'm developing a win-based software and need some .ico files as icons for toolbar buttons and ....
Is there any way to use .png file as an icon ? or what?
Thank you
As a workaround you can use IrfanView to convert your *.png file to *.ico file (or any other image to ico) & use it.
http://www.irfanview.com/main_download_engl.htm
You can simply convert the images to ico files online Ico Convert.
If you are using .NET this is not a real problem for you, because afaik PNG support is already build in. You are probably talking about native C/C++ development with GDI/win32?
To my knowledge you will not accomplish this by simply using GDI. There are a couple of options where you can set ONE color as transparent then load a simple BMP/JPEG and do some BITMAP tricks however using ICO/GIF will be far easier for this.
What you are probably looking for is a working GDI+ example which will use a PNG with alpha channel? This is just an excerpt and I left out the whole mess loading external functions from a DLL part, but maybe this will help you:
static GpImage *background = NULL;
GDIPLOADIMAGEFROMSTREAM GdipLoadImageFromStream;
GDIPLUSSTARTUP GdiplusStartup;
GDIPPLUSSHUTDOWN GdiplusShutdown;
GDIPCREATEFROMHDC GdipCreateFromHDC;
GDIPDELETEGRAPHICS GdipDeleteGraphics;
GDIPDRAWIMAGEI GdipDrawImageI;
GDIPDRAWIMAGERECTI GdipDrawImageRectI;
GDIPLUS_STARTUP_INPUT GdiplusStartupInput;
void LoadPNG(GpImage **image, int resource, HMODULE hInstance)
{
HRSRC resrc;
LPSTREAM lpstr;
HGLOBAL hPng;
LPVOID fByte;
GpImage *img = NULL;
resrc = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(resource), TEXT("PNG"));
hPng = LoadResource(GetModuleHandle(NULL), resrc);
fByte = LockResource(hPng);
lpstr = SHCreateMemStream(fByte, 200000);
GdipLoadImageFromStream(lpstr, &img);
*image = img;
}
void CreateBack(HWND hWnd)
{
HDC memDC = NULL;
HDC hdc = NULL;
RECT rect;
DeleteObject(curBack);
GetClientRect(hWnd, &rect);
hdc = GetDC(hWnd);
memDC = CreateCompatibleDC(hdc);
curBack = CreateCompatibleBitmap(hdc, rect.right, 44);
SelectObject(memDC, curBack);
/* gdiplus - background*/ {
int e = 0;
GpGraphics *g;
GdipCreateFromHDC(memDC, &g);
GdipDrawImageRectI(g, background, e, 0, 971, 44);
GdipDeleteGraphics(g);
}
DeleteObject(memDC);
ReleaseDC(hWnd, hdc);
}
Just a quick note: This GDI+ stuff is really CPU/memory intensive for a couple of reasons. Although fun I did abandoned this approach in favor of gdi and simple BMPs.
If you're loading the images from a resource file, then no, you can't use PNGs, you have to use ICOs. Fortunately, there are a number of tools that can convert PNGs into ICOs, including ImageMagick (great for automation), and MSPaint as a lowest common denominator.
If you're loading image files at runtime, then you can load any type of image format you want (e.g. use libpng for loading PNGs), but you still have to convert them to icons internally before you can do interesting things with them, such as setting them as a window's icon. Once you've decoded the image data, it's not terribly difficult to convert it to the proper format, but it's not trivial, it just involves a lot of data mangling and strange structs and function calls from the Win32 API.