Skip to content

Commit 8342f18

Browse files
committed
Added example how to combine 2 SVG into 1
1 parent 7c3802f commit 8342f18

1 file changed

Lines changed: 152 additions & 0 deletions

File tree

snippets/generate/svg/Combine.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using Aspose.BarCode.Cloud.Sdk.Api;
2+
using Aspose.BarCode.Cloud.Sdk.Model;
3+
4+
using System;
5+
using System.Globalization;
6+
using System.IO;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using System.Xml.Linq;
10+
11+
namespace GenerateSnippets;
12+
13+
/// <summary>
14+
/// Demonstrates generating two SVG barcodes via Aspose.BarCode Cloud and combining
15+
/// them into a single SVG containing both codes side-by-side.
16+
/// </summary>
17+
internal static class Program
18+
{
19+
private static readonly Encoding Utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
20+
private const double BarcodeSpacing = 20d;
21+
22+
private static Configuration MakeConfiguration()
23+
{
24+
var config = new Configuration();
25+
26+
string? envToken = Environment.GetEnvironmentVariable("TEST_CONFIGURATION_ACCESS_TOKEN");
27+
if (string.IsNullOrEmpty(envToken))
28+
{
29+
config.ClientId = "Client Id from https://dashboard.aspose.cloud/applications";
30+
config.ClientSecret = "Client Secret from https://dashboard.aspose.cloud/applications";
31+
}
32+
else
33+
{
34+
config.JwtToken = envToken;
35+
}
36+
37+
return config;
38+
}
39+
40+
public static async Task Main(string[] args)
41+
{
42+
string fileName = Path.GetFullPath(Path.Join("Tests", "test_data", "combined.svg"));
43+
44+
GenerateApi generateApi = new GenerateApi(MakeConfiguration());
45+
46+
Task<string> eanTask = GenerateSvgAsync(generateApi,
47+
barcodeType: EncodeBarcodeType.EAN13,
48+
data: "5901234123457");
49+
50+
Task<string> qrTask = GenerateSvgAsync(generateApi,
51+
barcodeType: EncodeBarcodeType.QR,
52+
data: "https://products.aspose.cloud/barcode/");
53+
54+
await Task.WhenAll(eanTask, qrTask);
55+
56+
string combinedSvg = CombineSvg(eanTask.Result, qrTask.Result);
57+
58+
await File.WriteAllTextAsync(fileName, combinedSvg, Utf8NoBom);
59+
60+
Console.WriteLine($"File '{fileName}' generated.");
61+
}
62+
63+
private static async Task<string> GenerateSvgAsync(GenerateApi api, EncodeBarcodeType barcodeType, string data)
64+
{
65+
await using Stream generated = await api.GenerateAsync(
66+
barcodeType: barcodeType,
67+
data: data,
68+
imageFormat: BarcodeImageFormat.Svg);
69+
70+
using var reader = new StreamReader(generated, Utf8NoBom, detectEncodingFromByteOrderMarks: true);
71+
return await reader.ReadToEndAsync();
72+
}
73+
74+
private static string CombineSvg(string eanSvg, string qrSvg)
75+
{
76+
XDocument eanDoc = XDocument.Parse(eanSvg);
77+
XDocument qrDoc = XDocument.Parse(qrSvg);
78+
79+
double eanWidth = ParseLength(eanDoc.Root?.Attribute("width"));
80+
double eanHeight = ParseLength(eanDoc.Root?.Attribute("height"));
81+
double qrWidth = ParseLength(qrDoc.Root?.Attribute("width"));
82+
double qrHeight = ParseLength(qrDoc.Root?.Attribute("height"));
83+
84+
double combinedWidth = eanWidth + BarcodeSpacing + qrWidth;
85+
double combinedHeight = Math.Max(eanHeight, qrHeight);
86+
87+
XNamespace svgNamespace = eanDoc.Root?.Name.Namespace ?? "http://www.w3.org/2000/svg";
88+
var combinedRoot = new XElement(svgNamespace + "svg",
89+
new XAttribute("xmlns", svgNamespace.NamespaceName),
90+
new XAttribute(XNamespace.Xmlns + "xlink", "http://www.w3.org/1999/xlink"),
91+
new XAttribute("width", ToInvariantLength(combinedWidth)),
92+
new XAttribute("height", ToInvariantLength(combinedHeight)),
93+
new XAttribute("viewBox", $"0 0 {ToInvariantLength(combinedWidth)} {ToInvariantLength(combinedHeight)}"));
94+
95+
double eanOffsetY = Math.Max(0, (combinedHeight - eanHeight) / 2);
96+
double qrOffsetY = Math.Max(0, (combinedHeight - qrHeight) / 2);
97+
98+
combinedRoot.Add(CreateNestedSvg(eanDoc, 0, eanOffsetY, "EAN13"));
99+
combinedRoot.Add(CreateNestedSvg(qrDoc, eanWidth + BarcodeSpacing, qrOffsetY, "QR"));
100+
101+
return combinedRoot.ToString(SaveOptions.OmitDuplicateNamespaces);
102+
}
103+
104+
private static XElement CreateNestedSvg(XDocument source, double offsetX, double offsetY, string label)
105+
{
106+
if (source.Root == null)
107+
{
108+
throw new InvalidOperationException("SVG document does not have a root element.");
109+
}
110+
111+
var nested = new XElement(source.Root);
112+
nested.SetAttributeValue("x", ToInvariantLength(offsetX));
113+
nested.SetAttributeValue("y", ToInvariantLength(offsetY));
114+
nested.SetAttributeValue("data-barcode", label);
115+
return nested;
116+
}
117+
118+
private static double ParseLength(XAttribute? attribute, double fallback = 100d)
119+
{
120+
return ParseLength(attribute?.Value, fallback);
121+
}
122+
123+
private static double ParseLength(string? rawValue, double fallback = 100d)
124+
{
125+
if (string.IsNullOrWhiteSpace(rawValue))
126+
{
127+
return fallback;
128+
}
129+
130+
var buffer = new StringBuilder();
131+
foreach (char c in rawValue)
132+
{
133+
if (char.IsDigit(c) || c == '.' || c == '-')
134+
{
135+
buffer.Append(c);
136+
}
137+
else if (buffer.Length > 0)
138+
{
139+
break;
140+
}
141+
}
142+
143+
return double.TryParse(buffer.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double parsed)
144+
? parsed
145+
: fallback;
146+
}
147+
148+
private static string ToInvariantLength(double value)
149+
{
150+
return value.ToString("0.##", CultureInfo.InvariantCulture);
151+
}
152+
}

0 commit comments

Comments
 (0)