Skip to content

Commit

Permalink
Add layout methods that write to memory instead of a file (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
chtenb authored Aug 11, 2023
1 parent f41e135 commit 1015038
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 12 deletions.
47 changes: 45 additions & 2 deletions Rubjerg.Graphviz.Test/TestDotLayout.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using NUnit.Framework;
Expand Down Expand Up @@ -299,4 +297,49 @@ public void TestLabelEscaping(bool escape)
}
}
}

[Test()]
public void TestOutputFormatsConsistency()
{
RootGraph root = CreateUniqueTestGraph();
Node node1 = root.GetOrAddNode("1");
_ = root.GetOrAddEdge(node1, node1);

var testFile = GetTestFilePath("out.txt");

{
root.ToXDotFile(testFile);
var fileContent = File.ReadAllText(testFile).Replace("\r\n", "\n");;
var stringContent = root.CreateLayout().ToDotString();
Assert.AreEqual(fileContent, stringContent);
}

{
root.ToSvgFile(testFile);
var fileContent = File.ReadAllText(testFile).Replace("\r\n", "\n");;
var stringContent = root.ToSvgString();
Assert.AreEqual(fileContent, stringContent);
}

{
root.ToPngFile(testFile);
var fileContent = File.ReadAllBytes(testFile);
var stringContent = root.ToPngBytes();
Assert.AreEqual(fileContent, stringContent);
}

{
root.ToPdfFile(testFile);
var fileContent = File.ReadAllBytes(testFile);
var stringContent = root.ToPdfBytes();
Assert.AreEqual(fileContent, stringContent);
}

{
root.ToPsFile(testFile);
var fileContent = File.ReadAllBytes(testFile);
var stringContent = root.ToPsBytes();
Assert.AreEqual(fileContent, stringContent);
}
}
}
15 changes: 15 additions & 0 deletions Rubjerg.Graphviz/Graph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ public override string ToString()
/// Attributes with the empty string as default are not correctly exported.
/// https://gitlab.com/graphviz/graphviz/-/issues/1887
/// </summary>
/// <returns>string with unix line endings</returns>
public string ToDotString()
{
return Rjagmemwrite(_ptr);
Expand Down Expand Up @@ -600,10 +601,24 @@ private void ToFile(string filepath, string format, string engine)
_ = GraphvizCommand.Exec(this, format: format, filepath, engine: engine);
}

private byte[] ToBytes(string format, string engine)
{
var (stdout, _) = GraphvizCommand.Exec(this, format: format, engine: engine);
return stdout;
}

public void ToXDotFile(string filepath, string engine = LayoutEngines.Dot) => ToFile(filepath, "xdot", engine);
public void ToSvgFile(string filepath, string engine = LayoutEngines.Dot) => ToFile(filepath, "svg", engine);
public void ToPngFile(string filepath, string engine = LayoutEngines.Dot) => ToFile(filepath, "png", engine);
public void ToPdfFile(string filepath, string engine = LayoutEngines.Dot) => ToFile(filepath, "pdf", engine);
public void ToPsFile(string filepath, string engine = LayoutEngines.Dot) => ToFile(filepath, "ps", engine);

/// <returns>string with unix line endings</returns>
public string ToSvgString(string engine = LayoutEngines.Dot) => GraphvizCommand.ConvertBytesToString(ToBytes("svg", engine));
public byte[] ToPngBytes(string engine = LayoutEngines.Dot) => ToBytes("png", engine);
public byte[] ToPdfBytes(string engine = LayoutEngines.Dot) => ToBytes("pdf", engine);
public byte[] ToPsBytes(string engine = LayoutEngines.Dot) => ToBytes("ps", engine);

#endregion


Expand Down
34 changes: 24 additions & 10 deletions Rubjerg.Graphviz/GraphvizCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,29 @@ public class GraphvizCommand
public static RootGraph CreateLayout(Graph input, string engine = LayoutEngines.Dot, CoordinateSystem coordinateSystem = CoordinateSystem.BottomLeft)
{
var (stdout, stderr) = Exec(input, engine: engine);
var resultGraph = RootGraph.FromDotString(stdout, coordinateSystem);
var stdoutStr = ConvertBytesToString(stdout);
var resultGraph = RootGraph.FromDotString(stdoutStr, coordinateSystem);
resultGraph.Warnings = stderr;
return resultGraph;
}

public static string ConvertBytesToString(byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
using (StreamReader reader = new StreamReader(ms, true))
{
// Just to be safe, make sure the input has unix line endings. Graphviz does not properly support
// windows line endings passed to stdin when it comes to attribute line continuations.
return reader.ReadToEnd().Replace("\r\n", "\n");
}
}

/// <summary>
/// Start dot.exe to compute a layout.
/// </summary>
/// <exception cref="ApplicationException">When the Graphviz process did not return successfully</exception>
/// <returns>stderr may contain warnings</returns>
public static (string stdout, string stderr) Exec(Graph input, string format = "xdot", string outputPath = null, string engine = LayoutEngines.Dot)
public static (byte[] stdout, string stderr) Exec(Graph input, string format = "xdot", string outputPath = null, string engine = LayoutEngines.Dot)
{
string exeName = "dot.exe";
string arguments = $"-T{format} -K{engine}";
Expand Down Expand Up @@ -56,19 +68,21 @@ public static (string stdout, string stderr) Exec(Graph input, string format = "

// Write to stdin
using (StreamWriter sw = process.StandardInput)
sw.WriteLine(inputToStdin);
sw.Write(inputToStdin);

// Read from stdout
string stdout;
using (StreamReader sr = process.StandardOutput)
stdout = sr.ReadToEnd()
.Replace("\r\n", "\n"); // File operations do this automatically, but stream operations do not
// Read from stdout, can be binary output such as pdf
byte[] stdout;
using (MemoryStream memoryStream = new MemoryStream())
{
process.StandardOutput.BaseStream.CopyTo(memoryStream);
stdout = memoryStream.ToArray();
}

// Read from stderr
string stderr;
using (StreamReader sr = process.StandardError)
stderr = sr.ReadToEnd()
.Replace("\r\n", "\n"); // File operations do this automatically, but stream operations do not
// Let's use unix line endings for consistency with stdout
stderr = sr.ReadToEnd().Replace("\r\n", "\n");

process.WaitForExit();

Expand Down

0 comments on commit 1015038

Please sign in to comment.