|
| 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