Convert string to Font - c#

I've been having a hard time trying to get the right answers for my problem. And have spent numerous days searching online and in documentation and have found nothing.
I have a Text File that contains a bunch of text. And on one of those lines inside the file will contain some Font info like this:
Tahoma,12.5,Regular
Note that the font info will not always have the same font name, size or style so I can't just set it manually.
When this file is opened into my app, it will parse the contents (which I have mostly covered), I just need some help converting the above font string into an actual font object and then assigning that font to a control, i.e. a label etc...
Can somebody please help me with this?

You will want to use the Font class. Assuming you use String.Split() to parse the text into an array you will want to take each part of the array and use it to create a Font object like:
string s = "Tahoma,12.5,Regular";
string[] fi = s.Split(',');
Font font = new Font(fi[0], fi[1],fi[2]);
I don't have a C# compiler on this Mac so it may not be exactly correct.
Example constructor:
public Font(
string familyName,
float emSize,
FontStyle style
)
Here you need to specify the second argument as a float, so cast the string to a float with:
(float)fi[1]
Next you need to lookup a FontStyle based on what fi2 is:
if (fi[2] == "Regular") {
// set font style
}

Related

How to format a RichTextBox with existing contents

I'm getting data from a web API that returns text, and formatting information. The formatting data only includes the type of formatting (bold, italic, etc.) and the range of that formatting. The main problem with this is, that two ranges can "collide" (for example the first 3 characters of a word are bold and italic but the last 3 characters are only italic). Example response
{
"text" : "This is an example text",
"inlineStyles" : [
{
"offsetFromStart" : 5,
"length" : 10,
"type" : "bold"
}
{
"offsetFromStart" : 10,
"length" : 10,
"type" : "italic"
}
]
}
I already tried doing this with a simple TextBlock and failed. And I also tried this with a RichTextBox but when I added a Span I couldn't insert it into its original position. I also tought about formatting each character with its own span or run but that would be very ugly and in general just a bad solution. (My main concern is speed..)
var tb = new RichTextBox();
var para = new Paragraph();
para.Inlines.Add("This is an example text") // Text parsed from the response
var startingPointer1 = para.ContentStart.GetPositionAtOffset(5);
var sp1 = new Span(startingPointer1, startingPointer1.GetPositionAtOffset(10));
sp1.FontWeight = FontWeights.Bold;
var startingPointer2 = para.ContentStart.GetPositionAtOffset(10);
var sp2 = new Span(startingPointer2 , startingPointer2 .GetPositionAtOffset(10));
sp2.FontStyle= FontStyles.Italic;
para.Inlines.Add(sp1);
para.Inlines.Add(sp2);
tb.Document.Blocks.Add(para);
This code appends it to the end and when combining multiple inline elements like in my example it doesn't work at all (because of the first problem.)
Example result:
I don't think you can overlap Runs/Spans like this, you'll have to find all the breaking points in your text and format each text range separately. It's similar to HTML, where
<bold>some<italic> bold italic</bold> and other </italic> text.
is not valid. In your case, you'll have a bold from (5,10), bolditalic from (11, 15) etc.
It's probably useful to find some kind of Range class with methods to combine ranges, split, find overlaps, etc. A while ago I started with this.
EDIT: I don't exactly have an idea how to implement all this (last time I did something similar was almost 10 years ago), but you can try something like this:
Create a List<Range<int>>. Initially it contains a single Range(0, length of text).
Load the first style, create a new Range with start/end offset. Overlap (or whatever method is appropriate) this range with the range in the list. This should give you 3 ranges, something like (0, start of style), (start of style, end of style), (end of style, end of text). Remove old range from the list and add new ones.
Load the next, find overlaps, with the ranges in the list, delete the ones that are overlapped and add new ranges.
This should give you a list of nonoverlapping ranges.
Now, for the styles. You can create a kind of stylesheet class. This class can use the FontWeights, FontStyles and other enums, defined in System.Windows. Modify a list, so that it contains, for example, List<Tuple<int, Stylesheet>>. To calculate overlaps just use the first param in the Tuple.
Before you remove old ranges from the list, combine the styles.
This should give you a list of nonoverlapped regions, with the appropriate styles. Create TextRanges, apply styles
Other idea that might work:
Again, create a stylesheet. Initially it should be normal weighy, normal style, default font size etc.
Find the next offset from the input (the first one that is larger than the current), create a TextRange and apply a style.
Find the next offset from the input, modify current (and only) style and apply.
If I remember correctly, inserting style definition in the text also counts as characters, so you might need to adjust offsets when you insert style tags in the final text. Also, I believe it is doable just using TextBlock.
As I said, I don't know if this works like described, but this might give you and idea.
My current solution is that I go through every character one by one and scan through the ranges detecting if the current character is in any of them and then assigning a span to the character. This is not ideal at all, but it gets the job done. I'll try to implement an actual algorithm for this later. Until then, if you have any information that could help, please comment.
If anyone needs sample code of my current implementation I'd happily share it with you. (Even though it's not really efficient at all)

Aligning string with spaces

Is there a way to perfectly align two strings in C#?
I am trying to align the string "CBI" with "Central Bureau of Investigation" and I want both strings to occupy 35 characters. I use the function
string.Format("{0,-35}", str);
to format both strings. But they do not appear to be aligned properly. Does it have something to do with the font settings?
I have to use these strings in a chart in excel and they have to occupy the same width on the screen
Yes there is PadLeft and PadRight
str.PadLeft(35);
str.PadRight(35);
str = "BBQ and Slaw";
Console.WriteLine(str.PadLeft(15)); // Displays " BBQ and Slaw".
Console.Write(str.PadRight(15)); // Displays "BBQ and Slaw ".
Side Note from documentation:
However, if totalWidth is less than the length of this instance, the method returns a reference to the existing instance
Basically if your length is less than the length of the string then an reference of the existing string is returned
If EvenMcDonnal wishes to include this in an answer I'll gladly remove it from my answer.
You can find a list of MonoSpaced fonts you can use here
I find that I am never satisfied by monospaced fonts, so I use character padding with a micro-space character (about 1 pixel wide) (char)0x200A to line things up. This is especially useful when simulating column alignment with a list of strings. The most flexible method is to use a while loop comparing string pixel widths and adding the space character until the match. I use System.Windows.Forms.TextRenderer.MeasureText() with a NoPadding flag and just to be save, an initial size of int.MaxValue, then check the Width parameter of System.Drawing.Size. If you feed in any Font in the MeasureText constructor, it works with any font.

showing some thing like र on the android dropdown

I'm trying to show currency symbols on the dropdown in my monodroid application.
As you know currency units contain some thing like "र". but when I run application, the drop down just show a rectangle instead of "र".
How I can make it human-readable?
EDIT
Actually I parse this json for accessing to the unit ( saving the name attribute to a string variable):
{"id":"167","name":"\u0930","type":"4","enabled":"1","tosi":"0.0182","index":"1","extra":"INR","extra2":"Indian Rupee","extra3":"India","extra4":"Paisa","seperator":",","d_seperator":"","after_before":"0"},
When I parse it, in run-time the string variable includes "र" but when I show it on the dropdown the device show a box.
So according to 'Sam' comment I use this code. I pass the string varible to method and show the return string to the dropdow. but yet I see a box :(
public static string ConvertUnitsEncoding(Activity act,string Encoded){
try {
if( Encoded =="र")
return act. Resources .GetString(Resource .String .IndianUnit );
else
return Encoded ;
} catch (Exception ex) {
RltLog .HandleException (ex);
return Encoded ;
}
}
You've got two options:
Either load a custom font that includes that special character:
TextView tv = (TextView)findViewById(R.id.tv);
// Put the font in the asset folder
Typeface tf = Typeface.createFromAsset(Context.Assets, "Symbol.ttf");
tv.setTypeface(tf);
Most of the installed fonts on Windows have a currency subset which includes currency symbols but not Rupee. I read somewhere that Microsoft Update will add the Rupee to the fonts but I don't have it on my system. I have found Amty Currency Font with Rupee support but I'm not sure how useful it would be for your case. Try it.
Or simply use a small image for that purpose. I would prefer this approach because it's platform independent and you can find lots of symbol icons out there. Something like this:

Match.Value and international characters

UPDATE May this post be helpful for coders using RichTextBoxes. The Match is correct for a normal string, I did not see this AND I did not see that "ä" transforms to "\e4r" in the richTextBox.Rtf! So the Match.Value is correct - human error.
A RegEx finds the correct text but Match.Value is wrong because it replaces the german "ä" with "\'e4"!
Let example_text = "Primär-ABC" and lets use the following code
String example_text = "<em>Primär-ABC</em>";
Regex em = new Regex(#"<em>[^<]*</em>" );
Match emMatch = em.Match(example_text); //Works!
Match emMatch = em.Match(richtextBox.RTF); //Fails!
while (emMatch.Success)
{
string matchValue = emMatch.Value;
Foo(matchValue) ...
}
then the emMatch.Value returns "Prim\'e4r-ABC" instead of "Primär-ABC".
The German ä transforms to \'e4!
Because I want to work with the exact string, i would need
emMatch.Value to be Primär-ABC - how do I achieve that?
In what context are you doing this?
string example_text = "<em>Ich bin ein Bärliner</em>";
Regex em = new Regex(#"<em>[^<]*</em>" );
Match emMatch = em.Match(example_text);
while (emMatch.Success)
{
Console.WriteLine(emMatch.Value);
emMatch = emMatch.NextMatch();
}
This outputs <em>Ich bin ein Bärliner</em> in my console
The problem probably isn't that you're getting the wrong value back, it's that you're getting a representation of the value that isn't displayed correctly. This can depend on a lot of things. Try writing the value to a text file using UTF8 encoding and see if it still is incorrect.
Edit: Right. The thing is that you are getting the text from a WinForms RichTextBox using the Rtf property. This will not return the text as is, but will return the RTF representation of the text. RTF is not plain text, it's a markup format to display rich text. If you open an RTF document in e.g. Notepad you will see that it has a lot of weird codes in it - including \'e4 for every 'ä' in your RTF document. If you would've used some markup (like bold text, color etc) in the RTF box, the .Rtf property would return that code as well, looking something like {\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf6\insrsid15946317\charrsid15946317 test}
So use the .Text property instead. It will return the actual plain text.

How to determine the O/S filename of an installed font?

We use a third-party PDF Generator library which requires that you specify the TrueType or Type1 file name when using a font other than the 14 or so that are part of the default PDF standard.
So if I want to use Bitstream Arrus Bold I have to know to reference arrusb.ttf.
Short of enumerating all of the files in the font folder and creating a disposable PrivateFontCollection to extract the relationships, is there a way to obtain the underlying font name from font information, i.e. given Courier New, Bold, Italic derive CourBI.ttf?
I've already looked at the InstalledFontCollection and there's nothing.
If you don't mind poking around in the registry, take a look at
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Fonts
It has pairs like
Name = "Arial (TrueType)"
Data = "arial.ttf"
You can do this the necessary queries like this:
static RegistryKey fontsKey =
Registry.LocalMachine.OpenSubKey(
#"Software\Microsoft\Windows NT\CurrentVersion\Fonts");
static public string GetFontFile(string fontName)
{
return fontsKey.GetValue(fontName, string.Empty) as string;
}
A call to GetFontFile("Arial (TrueType)") returns "arial.ttf"
You could of course modify the code to append the (TrueType) portion to the fontName, or to look through everything returned by fontsKey.GetValueNames() to find the best match.

Categories