Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color support #142

Merged
merged 40 commits into from
Oct 20, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
87b4f15
Update TexFormulaParser.cs
B3zaleel Jun 29, 2018
5cc7392
Create UserDefinedColorParser.cs
B3zaleel Jun 29, 2018
7a9b481
Update TexFormulaParser.cs
B3zaleel Jun 29, 2018
9f8de7c
Update UserDefinedColorParser.cs
B3zaleel Jun 30, 2018
2a3f581
Update UserDefinedColorParser.cs
B3zaleel Jul 17, 2018
c31c6f8
Update UserDefinedColorParser.cs
B3zaleel Jul 17, 2018
4af3a26
Fix compilation (#142)
ForNeVeR Jul 23, 2018
d3d0b85
Add a unit test for UserDefinedColorParser (#142)
ForNeVeR Jul 24, 2018
a7627eb
Merge branch 'master' into 'feature/color-support'
ForNeVeR Sep 20, 2018
21f4d45
Drop fgcolor and bgcolor in favor of color and colorbox (#142)
ForNeVeR Sep 20, 2018
f1f7729
Fix the unit tests (#142)
ForNeVeR Sep 30, 2018
3cabd6c
Fix small typos in prepare-font.md
ForNeVeR Oct 3, 2018
56e6ea0
Add color documentation (#165)
ForNeVeR Oct 3, 2018
d387a8b
Color models unit tests and fixes (#165)
ForNeVeR Oct 5, 2018
29bf5fe
Merge branch 'master' into feature/color-support
ForNeVeR Sep 15, 2019
3bd5e81
Generalize PredefinedColorParser as an IColorParser instance (#165)
ForNeVeR Sep 16, 2019
be368d1
Improve the color model tests: add \colorbox checks (#165)
ForNeVeR Sep 16, 2019
c2fbca4
Color mode parsers support, extract the common command code (#165)
ForNeVeR Sep 16, 2019
a69d808
Fix the approval script for paths with square brackets
ForNeVeR Sep 16, 2019
39ab960
Add the test results for the simplest cases (#165)
ForNeVeR Sep 16, 2019
f42092e
Add a HTML color parser (#165)
ForNeVeR Oct 19, 2019
67543ec
Update the IColorParser documentation (#165)
ForNeVeR Oct 19, 2019
98312b2
Use invariant culture for number parsing (#165)
ForNeVeR Oct 20, 2019
e057623
Add a grayscale color parser (#165)
ForNeVeR Oct 20, 2019
1e12d2c
Add an RGB color parser (#165)
ForNeVeR Oct 20, 2019
99e392a
Add an CMYK color parser, refactor some bits (#165)
ForNeVeR Oct 20, 2019
ef3d3e5
Add a float RGB color parser (#165)
ForNeVeR Oct 20, 2019
0f68105
Add the ARGB-style parsers (#165)
ForNeVeR Oct 20, 2019
12f5d10
Support the alpha channel in the HTML color parser (#165)
ForNeVeR Oct 20, 2019
91aedc1
Show the color model name in the error message (#165)
ForNeVeR Oct 20, 2019
814fd6d
Support RGBA as well as ARGB (#165)
ForNeVeR Oct 20, 2019
1a69b9d
Support alpha channel for the predefined colors (#165)
ForNeVeR Oct 20, 2019
8eee404
Support alpha channel in the CMYK color parser (#165)
ForNeVeR Oct 20, 2019
1e1deb3
Support alpha channel in the grayscale color parser (#165)
ForNeVeR Oct 20, 2019
14011f3
Delete #regions (#165)
ForNeVeR Oct 20, 2019
55a583c
Remove a redundant comment (#165)
ForNeVeR Oct 20, 2019
f227315
Delete the unused now UserDefinedColorParser (#165)
ForNeVeR Oct 20, 2019
b565ce5
Add tests for exceptions; fix parsers (#165)
ForNeVeR Oct 20, 2019
b91a09f
Allow the users to redefine the parser's color models (#165)
ForNeVeR Oct 20, 2019
4c1d9e5
Fix the code indentation (#165)
ForNeVeR Oct 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 64 additions & 13 deletions src/WpfMath/TexFormulaParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace WpfMath
// TODO: Use TextReader for lexing.
public class TexFormulaParser
{
// Special characters for parsing
#region Special characters for parsing
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
private const char escapeChar = '\\';

private const char leftGroupChar = '{';
Expand All @@ -25,8 +25,8 @@ public class TexFormulaParser
private const char subScriptChar = '_';
private const char superScriptChar = '^';
private const char primeChar = '\'';

// Information used for parsing
#endregion
#region Information used for parsing
private static HashSet<string> commands;
private static IList<string> symbols;
private static IList<string> delimeters;
Expand All @@ -49,7 +49,7 @@ public class TexFormulaParser
new[] { "vert", "vert" },
new[] { "Vert", "Vert" }
};

#endregion
static TexFormulaParser()
{
predefinedColors = new Dictionary<string, Color>();
Expand Down Expand Up @@ -80,7 +80,8 @@ private static void Initialize()
"left",
"right",
"sqrt",
"color",
"fgcolor",
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
"bgcolor",
"colorbox"
};

Expand Down Expand Up @@ -365,6 +366,7 @@ private Atom ProcessCommand(
}

case "sqrt":
{
// Command is radical.

SkipWhiteSpace(value, ref position);
Expand Down Expand Up @@ -393,20 +395,58 @@ private Atom ProcessCommand(

source = value.Segment(start, sqrtEnd - start);
return new Radical(source, sqrtFormula.RootAtom, degreeFormula?.RootAtom);

case "color":
}
case "fgcolor":
{
//Command to change the foreground color
var colorName = ReadGroup(formula, value, ref position, leftGroupChar, rightGroupChar);
var remainingString = value.Segment(position);

string remainingString = value.Substring(position);
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
var remaining = Parse(remainingString, formula.TextStyle);
position = value.Length;
if (predefinedColors.TryGetValue(colorName.ToString(), out var color))

if (predefinedColors.TryGetValue(colorName, out Color color))
{
source = value.Segment(start, position - start);
return new StyledAtom(source, remaining.RootAtom, null, new SolidColorBrush(color));
return new StyledAtom(remaining.RootAtom, null, new SolidColorBrush(color));
}
else
{
try
{
Color color1 = UserDefinedColorParser.ParseUserColor(colorName);
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
return new StyledAtom(remaining.RootAtom, null, new SolidColorBrush(color1));
}
catch
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
throw new TexParseException(String.Format("Color {0} could either not be found or converted.", colorName));
}

}
}
case "bgcolor":
{
//Command to change the background color
var colorName = ReadGroup(formula, value, ref position, leftGroupChar, rightGroupChar);
string remainingString = value.Substring(position);
var remaining = Parse(remainingString, formula.TextStyle);
position = value.Length;

throw new TexParseException($"Color {colorName} not found");
if (predefinedColors.TryGetValue(colorName, out Color color))
{
return new StyledAtom(remaining.RootAtom, new SolidColorBrush(color), null);
}
else
{
try
{
Color color1 = UserDefinedColorParser.ParseUserColor(colorName);
return new StyledAtom(remaining.RootAtom, new SolidColorBrush(color1), null);
}
catch (Exception ex)
{
throw new TexParseException(String.Format("Color {0} could either not be found or converted.", colorName));
}
}
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
}
case "colorbox":
{
Expand All @@ -418,8 +458,19 @@ private Atom ProcessCommand(
source = value.Segment(start, position - start);
return new StyledAtom(source, remaining.RootAtom, new SolidColorBrush(color), null);
}
else
{
try
{
Color color1 = UserDefinedColorParser.ParseUserColor(colorName);
return new StyledAtom(remaining.RootAtom, new SolidColorBrush(color1), null);
}
catch (Exception ex)
{
throw new TexParseException(String.Format("Color {0} could either not be found or converted.", colorName));
}
}

throw new TexParseException($"Color {colorName} not found");
}
}

Expand Down
264 changes: 264 additions & 0 deletions src/WpfMath/UserDefinedColorParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;
using WpfMath.Exceptions;

namespace WpfMath
{
/// <summary>
/// Parses definitions of colors from a <see cref="string"/>.
/// </summary>
public class UserDefinedColorParser
{
/// <summary>
/// Parses the <paramref name="input"/> to its <see cref="Color"/> equivalent.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static Color ParseUserColor(string input)
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
Color resultColor = new Color();
ColorStringTypes CST = GetColorString(input.Trim());
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
switch (CST)
{
case ColorStringTypes.Byte_longString:
{
byte[] channelbytes = ByteStringValues(input.Trim(), 4);
resultColor.A = channelbytes[0];
resultColor.R = channelbytes[1];
resultColor.G = channelbytes[2];
resultColor.B = channelbytes[3];
break;
}

case ColorStringTypes.Byte_shortString:
{
byte[] channelbytes = ByteStringValues(input.Trim(), 3);
resultColor.A = 255;
resultColor.R = channelbytes[0];
resultColor.G = channelbytes[1];
resultColor.B = channelbytes[2];
break;
}
case ColorStringTypes.Hex_longString:
{
byte[] channelbytes = ByteHexStringValues(input.Trim(), 8);
resultColor.A = channelbytes[0];
resultColor.R = channelbytes[1];
resultColor.G = channelbytes[2];
resultColor.B = channelbytes[3];
break;
}
case ColorStringTypes.Hex_shortString:
{
byte[] channelbytes = ByteHexStringValues(input.Trim(), 6);
resultColor.A = 255;
resultColor.R = channelbytes[0];
resultColor.G = channelbytes[1];
resultColor.B = channelbytes[2];
break;
}
case ColorStringTypes.None:
throw new TexParseException($"The text: {input} could not be parsed.");
default:
break;
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
}
return resultColor;
}

#region Color Parsing Helpers
/// <summary>
/// Specifies the type of <see cref="Color"/> the string might represent.
/// </summary>
private enum ColorStringTypes
{
/// <summary>
/// Type is a <see cref="string"/> consisting of byte values of the color.
/// </summary>
Byte_longString,
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Type is a <see cref="string"/> consisting of byte values of the color.<para/>
/// Alpha channel is strictly = 255.
/// </summary>
Byte_shortString,
//FloatString,----->Will include this later.
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Type is a Hexadecimal <see cref="string"/> consisting of Hexadecimal values of the color.
/// </summary>
Hex_longString,
/// <summary>
/// Type is a Hexadecimal <see cref="string"/> consisting of Hexadecimal values of the color.<para/>
/// Alpha channel is strictly = FF.
/// </summary>
Hex_shortString,


/// <summary>
/// An unrecognized ColorStringType.
/// </summary>
None
}

/// <summary>
/// Gets the type of <see cref="ColorStringTypes"/> from the <paramref name="input"/>.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static ColorStringTypes GetColorString(string input)
{
if (IsByteHexTrain(input,6)==true)
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
return ColorStringTypes.Hex_shortString;
}
else if (IsByteHexTrain(input,8))
{
return ColorStringTypes.Hex_longString;
}
else if (IsByteTrain(input, 3) == true)
{
return ColorStringTypes.Byte_shortString;
}
else if (IsByteTrain(input, 4) == true)
{
return ColorStringTypes.Byte_longString;
}
else
{
return ColorStringTypes.None;
}
}

/// <summary>
/// Returns a value that tells if the <paramref name="input"/> contains byte values, separated by a ",".
/// </summary>
/// <example>
/// 23,78,56=>true
/// 789,fp=>false
/// </example>
/// <param name="input"></param>
/// <param name="num"></param>
/// <returns></returns>
private static bool IsByteTrain(string input, int num)
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
bool StrCheck = false;
string[] arrStr = input.Trim().Split(',');
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
if (num == arrStr.Length)
{
int i = 0;
foreach (var item in arrStr)
{
if (Byte.TryParse(item, out byte result) == true)
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
i += 1;
}
else { continue; }
}
StrCheck = i == num ? true : false;
}
else
{
StrCheck = false;
}
return StrCheck;
}

/// <summary>
/// Returns a value that tells if the <paramref name="input"/> contains byte hex values,
/// </summary>
/// <param name="input"></param>
/// <param name="num"></param>
/// <returns></returns>
/// <remarks><paramref name="input"/> should be left in the raw state(e.g.;#56e245, not 56e245).</remarks>
private static bool IsByteHexTrain(string input, int num)
{
bool StrCheck = false;
string subStr = input.Substring(1);
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
if (num == subStr.Length)
{
int c = 0;
for (int i = 1; i < num; i+=2)
{
string item = subStr[i - 1].ToString() + subStr[1].ToString();
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
if (Byte.TryParse(item, System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out byte result) == true)
{
c+=2;
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
}
else { continue; }
}

StrCheck = (c == num )? true : false;
}
else
{
StrCheck = false;
}
return StrCheck;
}

/// <summary>
/// Gets the <see cref="byte"/> values from the <paramref name="input"/> if the number of items are ==<paramref name="num"/>.
/// </summary>
/// <param name="input"></param>
/// <param name="num"></param>
/// <returns></returns>
private static byte[] ByteStringValues(string input,int num)
ForNeVeR marked this conversation as resolved.
Show resolved Hide resolved
{
List<byte> resultByteArr = new List<byte>();
string[] arrStr = input.Split(',');
if (num == arrStr.Length)
{
foreach (var item in arrStr)
{
if (Byte.TryParse(item, out byte result) == true)
{
resultByteArr.Add(result);
}
else { continue; }
}

}
return resultByteArr.ToArray();
}

/// <summary>
/// Gets the <see cref="byte"/> values from the Hex <paramref name="input"/> if the number of items are ==<paramref name="num"/>.
/// </summary>
/// <param name="input"></param>
/// <param name="num"></param>
/// <returns></returns>
private static byte[] ByteHexStringValues(string input, int num)
{
List<string> hexTwos = new List<string>();
List<byte> resultByteLst = new List<byte>();
for (int i = 0; i <input.Length; i++)
{
if (i%2==0&&i>0)
{
//add the current and previous strings as one to the "hexTwos" list
string str = input[i].ToString() + input[i - 1].ToString();
hexTwos.Add(str);
}
}

if ((num/2)==hexTwos.Count)
{
foreach (string item in hexTwos)
{
if (Byte.TryParse(item, NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture, out byte hexbyteres) )
{
resultByteLst.Add(hexbyteres);
}
}
}
return resultByteLst.ToArray();
}

#endregion

}
}