Skip to content

Commit

Permalink
Merge branch 'feature/color-support'
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Oct 20, 2019
2 parents 351e010 + 4c1d9e5 commit b52a11b
Show file tree
Hide file tree
Showing 55 changed files with 1,908 additions and 69 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ You may also pass your own `IElementRenderer` implementation to `TexFormula.Rend
Documentation
-------------

- [Color support in WPF-Math][docs-colors]
- [Matrices and Matrix-Like Constructs][docs-matrices]
- [How to improve blurred formulas][docs-blurred-text-issue]

Expand Down Expand Up @@ -131,6 +132,7 @@ We're very grateful to JMathTeX authors for their work and allowing to redistrib
- Nico Van Cleemput
- Kurt Vermeulen

[docs-colors]: docs/colors.md
[docs-prepare-font]: docs/prepare-font.md
[docs-blurred-text-issue]: docs/blurred-text-issue.md
[docs-licensing-history]: docs/licensing-history.md
Expand Down
2 changes: 2 additions & 0 deletions WpfMath.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{39669369-C4F6-4AC6-9D35-B4B6086FF172}"
ProjectSection(SolutionItems) = preProject
docs\example-screenshot.png = docs\example-screenshot.png
docs\JMathTeX-license.txt = docs\JMathTeX-license.txt
docs\colors.md = docs\colors.md
docs\licensing-history.md = docs\licensing-history.md
docs\blurred-text-issue.md = docs\blurred-text-issue.md
docs\cleartype.png = docs\cleartype.png
Expand Down
88 changes: 88 additions & 0 deletions docs/colors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
Color support in WPF-Math
=========================

WPF-Math supports standard LaTeX commands: `\color` for foreground color, and
`\colorbox` for background color.

The commands also support additional syntax for color definitions. Standard
LaTeX only allows to use predefined colors or colors defined in the same
document. WPF-Math allows immediate color definition in the command arguments
instead.

The full color command syntax is:

```
\command [mode] {color} {text}
```

Where:
- `command` is either `color` or `colorbox`
- `mode` is an optional argument that could be one of
- `gray`
- `RGB`, `rgb`, `ARGB`, `argb`, `RGBA`, `rgba`
- `cmyk`
- `HTML`
- `color` is either a predefined color name if the `mode` argument wasn't
provided, or a color definition according to the `mode` argument

Some of the modes accepts multiple numbers separated by comma `,`; whitespace is
allowed around the comma, before first and after the last element in the list.

## Default mode (when no `mode` was provided)

In the default mode, `color` should be a predefined color name. Predefined
colors are stored in the `PredefinedColors.xml` file from the WPF-Math
resources. Additionally, this mode accepts an opacity index in range from 0.0 to
1.0. Examples:

```
\color{red}{without opacity}
\color{red, 0.5}{with opacity}
```

## `gray` mode

`gray` mode accepts a grayscale tone in range from 0.0 to 1.0. Additionally,
this mode accepts an opacity index in range from 0.0 to 1.0. Examples:

```
\color[gray]{0.5}{without opacity}
\color[gray]{0.5,0.5}{with opacity}
```

## RGB-based modes

There're six RGB-based modes: capital ones (`RGB`, `RGBA`, `ARGB`) accept three
(or four with opacity) comma-separated values in range from 0 to 255, lowercase
ones (`rgb`, `rgba`, `argb`) accept three (or four) comma-separated values in
range from 0.0 to 1.0. `ARGB` accepts opacity index first, `RGBA` accepts it
last. Examples:

```
\colorbox[rgb]{0,0,0}{text}
\colorbox[rgba]{0,0,0, 0.5}{opacity = 0.5}
\colorbox[argb]{0.5, 0,0,0}{opacity = 0.5}
\colorbox[RGB]{255,255,255}{text}
\colorbox[RGBA]{255,255,255,128}{opacity = 128}
\colorbox[ARGB]{128, 255,255,255}{opacity = 128}
```

## CMYK mode

`cmyk` mode accepts four (or five with opacity) parameters in the range from 0
to 1 for the CMYK color model. Examples:

```
\colorbox[cmyk]{0,0,0,0}{text}
\colorbox[cmyk]{0,0,0,0, 0.5}{opacity = 0.5}
```

## HTML mode

`HTML` mode accepts six or eight hexadecimal digits, in the latter case last two
should be opacity. Examples:

```
\color[HTML]{FF0000}{red text}
\color[HTML]{FF000000}{fully transparent red text}
```
6 changes: 3 additions & 3 deletions docs/prepare-font.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ How to prepare `DefaultTexFont.xml` from the font file
======================================================

This document describes the correspondence between the font files we use and
data in `DefaultTexFont.xml`. The conrete approach (i.e. script files to
data in `DefaultTexFont.xml`. The concrete approach (i.e. script files to
regenerate XML data) hasn't been reproduced yet, although we were able to get
nearly all the required information.

Data in our XML files is often inaccurate and/or seemlingly generated from other
Data in our XML files is often inaccurate and/or seemingly generated from other
TTF files than the files in the repository. Be prepared for that. When in doubt,
refer to [the original TFM files][tfm] (they seem to correspond to our data
better than the TFM files generated from our TTF files).
Expand Down Expand Up @@ -67,7 +67,7 @@ To get these values from the `cmmi10.tpl` file, search for the following:

Here, `CHARWD` corresponds to `width`, `CHARHT` corresponds to `height`,
`CHARDP` corresponds to `depth`, and `CHARIC` corresponds to `italic`. Any of
them could be ommited.
them could be omitted.

The kerning section can also be reconstructed from the `*.tpl` file.

Expand Down
2 changes: 1 addition & 1 deletion scripts/approve-all.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ $ErrorActionPreference = 'Stop'
Get-ChildItem $TestResultDirectory -Filter "*.received.txt" | ForEach-Object {
$receivedTestResult = $_.FullName
$approvedTestResult = $receivedTestResult.Replace('.received.txt', '.approved.txt')
Move-Item -Force $receivedTestResult $approvedTestResult
Move-Item -Force -LiteralPath $receivedTestResult $approvedTestResult
}
32 changes: 31 additions & 1 deletion src/WpfMath.Tests/ParserExceptionTests.fs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
module WpfMath.Tests.ParserExceptionTests

open System
open System.Collections.Generic

open Xunit

open WpfMath
open WpfMath.Atoms
open WpfMath.Colors
open WpfMath.Exceptions
open WpfMath.Parsers
open WpfMath.Tests.Utils
Expand Down Expand Up @@ -35,6 +37,34 @@ let ``Incorrect command parser behavior should be detected``(): unit =
member __.ProcessCommand _ =
CommandProcessingResult(SpaceAtom(null), 0) }
let parserRegistry = Map([| "dummy", incorrectParser |])
let parser = TexFormulaParser(parserRegistry)
let parser = TexFormulaParser(parserRegistry, Dictionary(), PredefinedColorParser.Instance)
let ex = Assert.Throws<TexParseException>(Action(fun () -> ignore <| parser.Parse("\dummy")))
Assert.Contains("NextPosition = 0", ex.Message)

[<Theory>]
[<InlineData(@"\color [nonexistent123] {red} x");
InlineData(@"\colorbox [nonexistent123] {red} x")>]
let ``Nonexistent color model throws a TexParseException``(text: string): unit =
let ex = assertParseThrows<TexParseException> text
Assert.Contains("nonexistent123", ex.Message)

[<Theory>]
[<InlineData(@"\color {reddit} x");
InlineData(@"\colorbox {reddit} x")>]
let ``Nonexistent color throws a TexParseException``(text: string): unit =
let ex = assertParseThrows<TexParseException> text
Assert.Contains("reddit", ex.Message)

[<Theory>]
[<InlineData(@"\color [gray] {x} x", "gray");
InlineData(@"\color [gray] {1.01} x", "gray");
InlineData(@"\color [argb] {2, 0.5, 0.5, 0.5} x", "argb");
InlineData(@"\color [argb] {x, 0.5, 0.5, 0.5} x", "argb");
InlineData(@"\color [ARGB] {256, 128, 128, 128} x", "ARGB");
InlineData(@"\color [ARGB] {x, 128, 128, 128} x", "ARGB");
InlineData(@"\color [cmyk] {2, 0.5, 0.5, 0.5, 0.1} x", "cmyk");
InlineData(@"\color [cmyk] {x, 0.5, 0.5, 0.5, 0.1} x", "cmyk");
InlineData(@"\color [HTML] {wwwwwwww} x", "HTML")>]
let ``Invalid color numbers throw exceptions``(formula: string, colorModel: string): unit =
let ex = assertParseThrows<TexParseException> formula
Assert.Contains(colorModel, ex.Message)
44 changes: 44 additions & 0 deletions src/WpfMath.Tests/ParserTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,47 @@ let matrixExpression() =
[<Fact>]
let bigMatrixExpression() =
verifyParseResult @"\Gamma_{\mu \rho} ^{\sigma}= \pmatrix{\pmatrix{0 & 0 & 0 \\ 0 & -r & 0 \\ 0 & 0 & -r sin^2(\theta)} \\ \pmatrix{0 & \frac{1}{r} & 0 \\ \frac{1}{r} & 0 & 0 \\ 0 & 0 & -\sin(\theta) \cos(\theta)} \\ \pmatrix{0 & 0 & \frac{1}{r} \\ 0 & 0 & \frac{1}{\tan(\theta)} \\ \frac{1}{r} & \frac{1}{\tan(\theta)} & 0 }}"

[<Theory>]
[<InlineData(@"\color {red} x");
InlineData(@"\color [] {red} x");
InlineData(@"\color [gray] {0.5} x");
InlineData(@"\color [rgb] {0.5, 0.5, 0.5} x");
InlineData(@"\color [RGB] {128, 128, 128} x");
InlineData(@"\color [cmyk] {0.5, 0.5, 0.5, 0.5} x");
InlineData(@"\color [HTML] {abcdef} x");
InlineData(@"\colorbox {red} x");
InlineData(@"\colorbox [] {red} x");
InlineData(@"\colorbox [gray] {0.5} x");
InlineData(@"\colorbox [rgb] {0.5, 0.5, 0.5} x");
InlineData(@"\colorbox [RGB] {128, 128, 128} x");
InlineData(@"\colorbox [cmyk] {0.5, 0.5, 0.5, 0.5} x");
InlineData(@"\colorbox [HTML] {abcdef} x")>]
let colorModels(text: string): unit =
verifyParseResultScenario
<| processSpecialChars text
<| text

[<Theory>]
[<InlineData(@"\color {red, 0.1} x");
InlineData(@"\color [] {red, 0.1} x");
InlineData(@"\color [gray] {0.5, 0.1} x");
InlineData(@"\color [argb] {0.1, 0.5, 0.5, 0.5} x");
InlineData(@"\color [rgba] {0.5, 0.5, 0.5, 0.1} x");
InlineData(@"\color [ARGB] {25, 128, 128, 128} x");
InlineData(@"\color [RGBA] {128, 128, 128, 25} x");
InlineData(@"\color [cmyk] {0.5, 0.5, 0.5, 0.5, 0.1} x");
InlineData(@"\color [HTML] {abcdef19} x");
InlineData(@"\colorbox {red, 0.1} x");
InlineData(@"\colorbox [] {red, 0.1} x");
InlineData(@"\colorbox [gray] {0.5, 0.1} x");
InlineData(@"\colorbox [argb] {0.1, 0.5, 0.5, 0.5} x");
InlineData(@"\colorbox [rgba] {0.5, 0.5, 0.5, 0.1} x");
InlineData(@"\colorbox [ARGB] {25, 128, 128, 128} x");
InlineData(@"\colorbox [RGBA] {128, 128, 128, 25} x");
InlineData(@"\colorbox [cmyk] {0.5, 0.5, 0.5, 0.5, 0.1} x");
InlineData(@"\colorbox [HTML] {abcdef19} x")>]
let colorModelsWithOpacity(text: string): unit =
verifyParseResultScenario
<| processSpecialChars text
<| text
25 changes: 25 additions & 0 deletions src/WpfMath.Tests/PredefinedColorParserTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module WpfMath.Tests.PredefinedColorParserTests

open System.Windows.Media

open Xunit

open WpfMath.Colors

let parser = PredefinedColorParser.Instance

[<Fact>]
let ``PredefinedColorParser parses a correctly defined color``(): unit =
Assert.Equal(Color.FromRgb(237uy, 27uy, 35uy), parser.Parse([| "red" |]).Value)

[<Fact>]
let ``PredefinedColorParser returns null for wrong input``(): unit =
Assert.Null(parser.Parse([| "nonexistent-color" |]))

[<Fact>]
let ``PredefinedColorParser returns null for empty input``(): unit =
Assert.Null(parser.Parse(Array.empty))

[<Fact>]
let ``PredefinedColorParser returns null for too long input``(): unit =
Assert.Null(parser.Parse([| "red"; "green" |]))
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"TextStyle": null,
"RootAtom": {
"RowAtom": {
"PreviousAtom": null,
"Elements": [
{
"Character": "x",
"TextStyle": null,
"IsDefaultTextStyle": true,
"IsTextSymbol": false,
"Type": "Ordinary",
"Source": {
"Start": 13,
"End": 14,
"Length": 1,
"Source": "\\color {red} x"
}
}
],
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 14,
"Length": 13,
"Source": "\\color {red} x"
}
},
"Background": null,
"Foreground": "#FFED1B23",
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 14,
"Length": 13,
"Source": "\\color {red} x"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"TextStyle": null,
"RootAtom": {
"RowAtom": {
"PreviousAtom": null,
"Elements": [
{
"Character": "x",
"TextStyle": null,
"IsDefaultTextStyle": true,
"IsTextSymbol": false,
"Type": "Ordinary",
"Source": {
"Start": 23,
"End": 24,
"Length": 1,
"Source": "\\color [HTML] {abcdef} x"
}
}
],
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 24,
"Length": 23,
"Source": "\\color [HTML] {abcdef} x"
}
},
"Background": null,
"Foreground": "#FFABCDEF",
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 24,
"Length": 23,
"Source": "\\color [HTML] {abcdef} x"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"TextStyle": null,
"RootAtom": {
"RowAtom": {
"PreviousAtom": null,
"Elements": [
{
"Character": "x",
"TextStyle": null,
"IsDefaultTextStyle": true,
"IsTextSymbol": false,
"Type": "Ordinary",
"Source": {
"Start": 29,
"End": 30,
"Length": 1,
"Source": "\\color [RGB] {128, 128, 128} x"
}
}
],
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 30,
"Length": 29,
"Source": "\\color [RGB] {128, 128, 128} x"
}
},
"Background": null,
"Foreground": "#FF808080",
"Type": "Ordinary",
"Source": {
"Start": 1,
"End": 30,
"Length": 29,
"Source": "\\color [RGB] {128, 128, 128} x"
}
}
}
Loading

0 comments on commit b52a11b

Please sign in to comment.