diff --git a/Examples/ApiExamples/ApiExamples/ApiExamples.csproj b/Examples/ApiExamples/ApiExamples/ApiExamples.csproj
index 6fa5fd323..1ccca3b6e 100644
--- a/Examples/ApiExamples/ApiExamples/ApiExamples.csproj
+++ b/Examples/ApiExamples/ApiExamples/ApiExamples.csproj
@@ -125,9 +125,9 @@
-
-
-
+
+
+
diff --git a/Examples/ApiExamples/ApiExamples/ExXpsSaveOptions.cs b/Examples/ApiExamples/ApiExamples/ExXpsSaveOptions.cs
index f96cf2fd9..17cd32dcd 100644
--- a/Examples/ApiExamples/ApiExamples/ExXpsSaveOptions.cs
+++ b/Examples/ApiExamples/ApiExamples/ExXpsSaveOptions.cs
@@ -170,9 +170,11 @@ public void XpsDigitalSignature()
Document doc = new Document(MyDir + "Document.docx");
CertificateHolder certificateHolder = CertificateHolder.Create(MyDir + "morzal.pfx", "aw");
- DigitalSignatureDetails digitalSignatureDetails = new DigitalSignatureDetails(
- certificateHolder,
- new SignOptions() { Comments = "Some comments", SignTime = DateTime.Now });
+ SignOptions options = new SignOptions();
+ options.SignTime = DateTime.Now;
+ options.Comments = "Some comments";
+
+ DigitalSignatureDetails digitalSignatureDetails = new DigitalSignatureDetails(certificateHolder, options);
XpsSaveOptions saveOptions = new XpsSaveOptions();
saveOptions.DigitalSignatureDetails = digitalSignatureDetails;
diff --git a/Examples/ApiExamples/Runner.MAUI/Runner.MAUI.csproj b/Examples/ApiExamples/Runner.MAUI/Runner.MAUI.csproj
index 7b30d22a7..f5e48b519 100644
--- a/Examples/ApiExamples/Runner.MAUI/Runner.MAUI.csproj
+++ b/Examples/ApiExamples/Runner.MAUI/Runner.MAUI.csproj
@@ -49,20 +49,20 @@
-
-
-
-
+
+
+
+
-
+
-
+
-
+
diff --git a/Examples/DocsExamples/Docker/Docker.csproj b/Examples/DocsExamples/Docker/Docker.csproj
index 3bcedcee0..8a13643d7 100644
--- a/Examples/DocsExamples/Docker/Docker.csproj
+++ b/Examples/DocsExamples/Docker/Docker.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/Examples/DocsExamples/DocsExamples/DocsExamples.csproj b/Examples/DocsExamples/DocsExamples/DocsExamples.csproj
index 2caba3a8f..243afc8b2 100644
--- a/Examples/DocsExamples/DocsExamples/DocsExamples.csproj
+++ b/Examples/DocsExamples/DocsExamples/DocsExamples.csproj
@@ -116,11 +116,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/Examples/DocsExamples/DocsExamples/Mail Merge and Reporting/Base operations.cs b/Examples/DocsExamples/DocsExamples/Mail Merge and Reporting/Base operations.cs
index 50d5ffe32..36dab756d 100644
--- a/Examples/DocsExamples/DocsExamples/Mail Merge and Reporting/Base operations.cs
+++ b/Examples/DocsExamples/DocsExamples/Mail Merge and Reporting/Base operations.cs
@@ -41,8 +41,6 @@ public void UseIfElseMustache()
//ExStart:UseIfElseMustache
//GistId:544788f602e697802e313a641cedb9b8
Document doc = new Document(MyDir + "Mail merge destinations - Mustache syntax.docx");
- doc.Sections.Clear();
- doc.Save(ArtifactsDir + "output.docx");
doc.MailMerge.UseNonMergeFields = true;
doc.MailMerge.Execute(new[] { "GENDER" }, new object[] { "MALE" });
diff --git a/Examples/DocsExamples/DocsExamples/Programming with Documents/Working with Graphic Elements/CustomBarcodeGenerator.cs b/Examples/DocsExamples/DocsExamples/Programming with Documents/Working with Graphic Elements/CustomBarcodeGenerator.cs
index eac134d7d..0afe2cb6f 100644
--- a/Examples/DocsExamples/DocsExamples/Programming with Documents/Working with Graphic Elements/CustomBarcodeGenerator.cs
+++ b/Examples/DocsExamples/DocsExamples/Programming with Documents/Working with Graphic Elements/CustomBarcodeGenerator.cs
@@ -1,240 +1,315 @@
+// Copyright (c) 2001-2024 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
using System;
-using System.Drawing;
-using System.Globalization;
-using Aspose.BarCode.Generation;
+using System.IO;
using Aspose.Words.Fields;
-using BarcodeParameters = Aspose.Words.Fields.BarcodeParameters;
-#if NET6_0 || __MOBILE__
-using Image = SkiaSharp.SKBitmap;
-using Color = Aspose.Drawing.Color;
+using Aspose.BarCode.Generation;
+#if NET5_0_OR_GREATER
+using SkiaSharp;
+using Aspose.Drawing;
+using Aspose.Drawing.Imaging;
+#else
+using System.Drawing;
+using System.Drawing.Imaging;
#endif
-namespace DocsExamples.Programming_with_Documents.Working_with_Graphic_Elements
+namespace DocsExamples
{
- //ExStart:CustomBarcodeGenerator
- //GistId:00d34dba66626dbc0175b60bb3b71c8a
- public class CustomBarcodeGenerator : DocsExamplesBase, IBarcodeGenerator
+ internal class CustomBarcodeGeneratorUtils
{
///
- /// Converts barcode image height from Word units to Aspose.BarCode units.
+ /// Converts a height value in twips to pixels using a default DPI of 96.
///
- ///
- ///
- private static float ConvertSymbolHeight(string heightInTwipsString)
+ /// The height value in twips.
+ /// The default value to return if the conversion fails.
+ /// The height value in pixels.
+ public static double TwipsToPixels(string heightInTwips, double defVal)
{
- // Input value is in 1/1440 inches (twips).
- int heightInTwips = TryParseInt(heightInTwipsString);
-
- if (heightInTwips == int.MinValue)
- throw new Exception("Error! Incorrect height - " + heightInTwipsString + ".");
-
- // Convert to mm.
- return (float) (heightInTwips * 25.4 / 1440);
+ return TwipsToPixels(heightInTwips, 96, defVal);
}
///
- /// Converts barcode image color from Word to Aspose.BarCode.
+ /// Converts a height value in twips to pixels based on the given resolution.
///
- ///
- ///
- private static Color ConvertColor(string inputColor)
+ /// The height value in twips to be converted.
+ /// The resolution in pixels per inch.
+ /// The default value to be returned if the conversion fails.
+ /// The converted height value in pixels.
+ public static double TwipsToPixels(string heightInTwips, double resolution, double defVal)
{
- // Input should be from "0x000000" to "0xFFFFFF".
- int color = TryParseHex(inputColor.Replace("0x", ""));
-
- if (color == int.MinValue)
- throw new Exception("Error! Incorrect color - " + inputColor + ".");
-
- return Color.FromArgb(color >> 16, (color & 0xFF00) >> 8, color & 0xFF);
-
- // Backward conversion -
- // return string.Format("0x{0,6:X6}", mControl.ForeColor.ToArgb() & 0xFFFFFF);
+ try
+ {
+ int lVal = int.Parse(heightInTwips);
+ return (lVal / 1440.0) * resolution;
+ }
+ catch
+ {
+ return defVal;
+ }
}
///
- /// Converts bar code scaling factor from percent to float.
+ /// Gets the rotation angle in degrees based on the given rotation angle string.
///
- ///
- ///
- private static float ConvertScalingFactor(string scalingFactor)
+ /// The rotation angle string.
+ /// The default value to return if the rotation angle is not recognized.
+ /// The rotation angle in degrees.
+ public static float GetRotationAngle(string rotationAngle, float defVal)
{
- bool isParsed = false;
- int percent = TryParseInt(scalingFactor);
-
- if (percent != int.MinValue && percent >= 10 && percent <= 10000)
- isParsed = true;
-
- if (!isParsed)
- throw new Exception("Error! Incorrect scaling factor - " + scalingFactor + ".");
-
- return percent / 100.0f;
+ switch (rotationAngle)
+ {
+ case "0":
+ return 0;
+ case "1":
+ return 270;
+ case "2":
+ return 180;
+ case "3":
+ return 90;
+ default:
+ return defVal;
+ }
}
///
- /// Implementation of the GetBarCodeImage() method for IBarCodeGenerator interface.
+ /// Converts a string representation of an error correction level to a QRErrorLevel enum value.
///
- ///
- ///
- public Image GetBarcodeImage(BarcodeParameters parameters)
+ /// The string representation of the error correction level.
+ /// The default error correction level to return if the input is invalid.
+ /// The corresponding QRErrorLevel enum value.
+ public static QRErrorLevel GetQRCorrectionLevel(string errorCorrectionLevel, QRErrorLevel def)
{
- if (parameters.BarcodeType == null || parameters.BarcodeValue == null)
- return null;
-
- BarcodeGenerator generator = new BarcodeGenerator(EncodeTypes.QR);
-
- string type = parameters.BarcodeType.ToUpper();
+ switch (errorCorrectionLevel)
+ {
+ case "0":
+ return QRErrorLevel.LevelL;
+ case "1":
+ return QRErrorLevel.LevelM;
+ case "2":
+ return QRErrorLevel.LevelQ;
+ case "3":
+ return QRErrorLevel.LevelH;
+ default:
+ return def;
+ }
+ }
- switch (type)
+ ///
+ /// Gets the barcode encode type based on the given encode type from Word.
+ ///
+ /// The encode type from Word.
+ /// The barcode encode type.
+ public static SymbologyEncodeType GetBarcodeEncodeType(string encodeTypeFromWord)
+ {
+ // https://support.microsoft.com/en-au/office/field-codes-displaybarcode-6d81eade-762d-4b44-ae81-f9d3d9e07be3
+ switch (encodeTypeFromWord)
{
case "QR":
- generator = new BarcodeGenerator(EncodeTypes.QR);
- break;
+ return EncodeTypes.QR;
case "CODE128":
- generator = new BarcodeGenerator(EncodeTypes.Code128);
- break;
+ return EncodeTypes.Code128;
case "CODE39":
- generator = new BarcodeGenerator(EncodeTypes.Code39Standard);
- break;
+ return EncodeTypes.Code39;
+ case "JPPOST":
+ return EncodeTypes.RM4SCC;
case "EAN8":
- generator = new BarcodeGenerator(EncodeTypes.EAN8);
- break;
+ case "JAN8":
+ return EncodeTypes.EAN8;
case "EAN13":
- generator = new BarcodeGenerator(EncodeTypes.EAN13);
- break;
+ case "JAN13":
+ return EncodeTypes.EAN13;
case "UPCA":
- generator = new BarcodeGenerator(EncodeTypes.UPCA);
- break;
+ return EncodeTypes.UPCA;
case "UPCE":
- generator = new BarcodeGenerator(EncodeTypes.UPCE);
- break;
- case "ITF14":
- generator = new BarcodeGenerator(EncodeTypes.ITF14);
- break;
+ return EncodeTypes.UPCE;
case "CASE":
- generator = new BarcodeGenerator(EncodeTypes.None);
- break;
+ case "ITF14":
+ return EncodeTypes.ITF14;
+ case "NW7":
+ return EncodeTypes.Codabar;
+ default:
+ return EncodeTypes.None;
}
+ }
- if (generator.BarcodeType.Equals(EncodeTypes.None))
- return null;
-
- generator.CodeText = parameters.BarcodeValue;
-
- if (generator.BarcodeType.Equals(EncodeTypes.QR))
- generator.Parameters.Barcode.CodeTextParameters.TwoDDisplayText = parameters.BarcodeValue;
-
- if (parameters.ForegroundColor != null)
- generator.Parameters.Barcode.BarColor = ConvertColor(parameters.ForegroundColor);
-
- if (parameters.BackgroundColor != null)
- generator.Parameters.BackColor = ConvertColor(parameters.BackgroundColor);
-
- if (parameters.SymbolHeight != null)
+ ///
+ /// Converts a hexadecimal color string to a Color object.
+ ///
+ /// The hexadecimal color string to convert.
+ /// The default Color value to return if the conversion fails.
+ /// The Color object representing the converted color, or the default value if the conversion fails.
+ public static Color ConvertColor(string inputColor, Color defVal)
+ {
+ if (string.IsNullOrEmpty(inputColor)) return defVal;
+ try
{
- generator.Parameters.ImageHeight.Pixels = ConvertSymbolHeight(parameters.SymbolHeight);
- generator.Parameters.AutoSizeMode = AutoSizeMode.None;
+ int color = Convert.ToInt32(inputColor, 16);
+ // Return Color.FromArgb((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
+ return Color.FromArgb(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);
}
-
- generator.Parameters.Barcode.CodeTextParameters.Location = CodeLocation.None;
-
- if (parameters.DisplayText)
- generator.Parameters.Barcode.CodeTextParameters.Location = CodeLocation.Below;
-
- generator.Parameters.CaptionAbove.Text = "";
-
- // Empiric scaling factor for converting Word barcode to Aspose.BarCode.
- const float scale = 2.4f;
- float xdim = 1.0f;
-
- if (generator.BarcodeType.Equals(EncodeTypes.QR))
+ catch
{
- generator.Parameters.AutoSizeMode = AutoSizeMode.Nearest;
- generator.Parameters.ImageWidth.Inches *= scale;
- generator.Parameters.ImageHeight.Inches = generator.Parameters.ImageWidth.Inches;
- xdim = generator.Parameters.ImageHeight.Inches / 25;
- generator.Parameters.Barcode.XDimension.Inches =
- generator.Parameters.Barcode.BarHeight.Inches = xdim;
+ return defVal;
}
+ }
- if (parameters.ScalingFactor != null)
+ ///
+ /// Calculates the scale factor based on the provided string representation.
+ ///
+ /// The string representation of the scale factor.
+ /// The default value to return if the scale factor cannot be parsed.
+ ///
+ /// The scale factor as a decimal value between 0 and 1, or the default value if the scale factor cannot be parsed.
+ ///
+ public static double ScaleFactor(string scaleFactor, double defVal)
+ {
+ try
{
- float scalingFactor = ConvertScalingFactor(parameters.ScalingFactor);
- generator.Parameters.ImageHeight.Inches *= scalingFactor;
-
- if (generator.BarcodeType.Equals(EncodeTypes.QR))
- {
- generator.Parameters.ImageWidth.Inches = generator.Parameters.ImageHeight.Inches;
- generator.Parameters.Barcode.XDimension.Inches =
- generator.Parameters.Barcode.BarHeight.Inches = xdim * scalingFactor;
- }
-
- generator.Parameters.AutoSizeMode = AutoSizeMode.None;
+ int scale = int.Parse(scaleFactor);
+ return scale / 100.0;
+ }
+ catch
+ {
+ return defVal;
}
-
-#if NET48 || JAVA
- return generator.GenerateBarCodeImage();
-
-#elif NET6_0 || __MOBILE__
- generator.GenerateBarCodeImage().Save(ArtifactsDir + "GetBarcodeImage.png");
- return Image.Decode(ArtifactsDir + "GetBarcodeImage.png");
-#endif
}
///
- /// Implementation of the GetOldBarcodeImage() method for IBarCodeGenerator interface.
+ /// Sets the position code style for a barcode generator.
///
- ///
- ///
- public Image GetOldBarcodeImage(BarcodeParameters parameters)
+ /// The barcode generator.
+ /// The position code style to set.
+ /// The barcode value.
+ public static void SetPosCodeStyle(BarcodeGenerator gen, string posCodeStyle, string barcodeValue)
{
- if (parameters.PostalAddress == null)
- return null;
-
- BarcodeGenerator generator = new BarcodeGenerator(EncodeTypes.Postnet)
+ switch (posCodeStyle)
{
- CodeText = parameters.PostalAddress
- };
-
-#if NET48 || JAVA
- return generator.GenerateBarCodeImage();
-#elif NET6_0 || __MOBILE__
- generator.GenerateBarCodeImage().Save(ArtifactsDir + "OldBarcodeImage.png");
- return Image.Decode(ArtifactsDir + "OldBarcodeImage.png");
-#endif
+ // STD default and without changes.
+ case "SUP2":
+ gen.CodeText = barcodeValue.Substring(0, barcodeValue.Length - 2);
+ gen.Parameters.Barcode.Supplement.SupplementData = barcodeValue.Substring(barcodeValue.Length - 2, 2);
+ break;
+ case "SUP5":
+ gen.CodeText = barcodeValue.Substring(0, barcodeValue.Length - 5);
+ gen.Parameters.Barcode.Supplement.SupplementData = barcodeValue.Substring(barcodeValue.Length - 5, 5);
+ break;
+ case "CASE":
+ gen.Parameters.Border.Visible = true;
+ gen.Parameters.Border.Color = gen.Parameters.Barcode.BarColor;
+ gen.Parameters.Border.DashStyle = BorderDashStyle.Solid;
+ gen.Parameters.Border.Width.Pixels = gen.Parameters.Barcode.XDimension.Pixels * 5;
+ break;
+ }
}
+ public const double DefaultQRXDimensionInPixels = 4.0;
+ public const double Default1DXDimensionInPixels = 1.0;
+
///
- /// Parses an integer using the invariant culture. Returns Int.MinValue if cannot parse.
- ///
- /// Allows leading sign.
- /// Allows leading and trailing spaces.
+ /// Draws an error image with the specified exception message.
///
- public static int TryParseInt(string s)
+ /// The exception containing the error message.
+ /// A Bitmap object representing the error image.
+ public static Bitmap DrawErrorImage(Exception error)
{
- return double.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out double temp)
- ? CastDoubleToInt(temp)
- : int.MinValue;
+ Bitmap bmp = new Bitmap(100, 100);
+
+ using (Graphics grf = Graphics.FromImage(bmp))
+#if NET5_0_OR_GREATER
+ grf.DrawString(error.Message, new Aspose.Drawing.Font("Microsoft Sans Serif", 8f, FontStyle.Regular), Brushes.Red, new Rectangle(0, 0, bmp.Width, bmp.Height));
+#else
+ grf.DrawString(error.Message, new System.Drawing.Font("Microsoft Sans Serif", 8f, FontStyle.Regular), Brushes.Red, new Rectangle(0, 0, bmp.Width, bmp.Height));
+#endif
+ return bmp;
}
- ///
- /// Casts a double to int32 in a way that uint32 are "correctly" casted too (they become negative numbers).
- ///
- public static int CastDoubleToInt(double value)
+#if NET5_0_OR_GREATER
+ public static SKBitmap ConvertImageToWord(Bitmap bmp)
{
- long temp = (long) value;
- return (int) temp;
+ MemoryStream ms = new MemoryStream();
+ bmp.Save(ms, ImageFormat.Png);
+ ms.Position = 0;
+
+ return SKBitmap.Decode(ms);
+ }
+#else
+ public static Image ConvertImageToWord(Bitmap bmp)
+ {
+ return bmp;
}
+#endif
+ }
- ///
- /// Try parses a hex String into an integer value.
- /// on error return int.MinValue
- ///
- public static int TryParseHex(string s)
+ internal class CustomBarcodeGenerator : IBarcodeGenerator
+ {
+#if NET5_0_OR_GREATER
+ public SKBitmap GetBarcodeImage(Aspose.Words.Fields.BarcodeParameters parameters)
+#else
+ public Image GetBarcodeImage(Aspose.Words.Fields.BarcodeParameters parameters)
+#endif
+ {
+ try
+ {
+ BarcodeGenerator gen = new BarcodeGenerator(CustomBarcodeGeneratorUtils.GetBarcodeEncodeType(parameters.BarcodeType), parameters.BarcodeValue);
+
+ // Set color.
+ gen.Parameters.Barcode.BarColor = CustomBarcodeGeneratorUtils.ConvertColor(parameters.ForegroundColor, gen.Parameters.Barcode.BarColor);
+ gen.Parameters.BackColor = CustomBarcodeGeneratorUtils.ConvertColor(parameters.BackgroundColor, gen.Parameters.BackColor);
+
+ // Set display or hide text.
+ if (!parameters.DisplayText)
+ gen.Parameters.Barcode.CodeTextParameters.Location = CodeLocation.None;
+ else
+ gen.Parameters.Barcode.CodeTextParameters.Location = CodeLocation.Below;
+
+ // Set QR Code error correction level.s
+ gen.Parameters.Barcode.QR.QrErrorLevel = QRErrorLevel.LevelH;
+ if (!string.IsNullOrEmpty(parameters.ErrorCorrectionLevel))
+ gen.Parameters.Barcode.QR.QrErrorLevel = CustomBarcodeGeneratorUtils.GetQRCorrectionLevel(parameters.ErrorCorrectionLevel, gen.Parameters.Barcode.QR.QrErrorLevel);
+
+ // Set rotation angle.
+ if (!string.IsNullOrEmpty(parameters.SymbolRotation))
+ gen.Parameters.RotationAngle = CustomBarcodeGeneratorUtils.GetRotationAngle(parameters.SymbolRotation, gen.Parameters.RotationAngle);
+
+ // Set scaling factor.
+ double scalingFactor = 1;
+ if (!string.IsNullOrEmpty(parameters.ScalingFactor))
+ scalingFactor = CustomBarcodeGeneratorUtils.ScaleFactor(parameters.ScalingFactor, scalingFactor);
+
+ // Set size.
+ if (gen.BarcodeType == EncodeTypes.QR)
+ gen.Parameters.Barcode.XDimension.Pixels = (float)Math.Max(1.0, Math.Round(CustomBarcodeGeneratorUtils.DefaultQRXDimensionInPixels * scalingFactor));
+ else
+ gen.Parameters.Barcode.XDimension.Pixels = (float)Math.Max(1.0, Math.Round(CustomBarcodeGeneratorUtils.Default1DXDimensionInPixels * scalingFactor));
+
+ //Set height.
+ if (!string.IsNullOrEmpty(parameters.SymbolHeight))
+ gen.Parameters.Barcode.BarHeight.Pixels = (float)Math.Max(5.0, Math.Round(CustomBarcodeGeneratorUtils.TwipsToPixels(parameters.SymbolHeight, gen.Parameters.Barcode.BarHeight.Pixels) * scalingFactor));
+
+ // Set style of a Point-of-Sale barcode.
+ if (!string.IsNullOrEmpty(parameters.PosCodeStyle))
+ CustomBarcodeGeneratorUtils.SetPosCodeStyle(gen, parameters.PosCodeStyle, parameters.BarcodeValue);
+
+ return CustomBarcodeGeneratorUtils.ConvertImageToWord(gen.GenerateBarCodeImage());
+ }
+ catch (Exception e)
+ {
+ return CustomBarcodeGeneratorUtils.ConvertImageToWord(CustomBarcodeGeneratorUtils.DrawErrorImage(e));
+ }
+ }
+
+#if NET5_0_OR_GREATER
+ public SKBitmap GetOldBarcodeImage(Aspose.Words.Fields.BarcodeParameters parameters)
+#else
+ public Image GetOldBarcodeImage(Aspose.Words.Fields.BarcodeParameters parameters)
+#endif
{
- return int.TryParse(s, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int result)
- ? result
- : int.MinValue;
+ throw new NotImplementedException();
}
}
- //ExEnd:CustomBarcodeGenerator
}
diff --git a/Examples/DocsExamples/DocsExamples/Rendering and Printing/Rendering shapes.cs b/Examples/DocsExamples/DocsExamples/Rendering and Printing/Rendering shapes.cs
index c4ca7480e..8199c5b9f 100644
--- a/Examples/DocsExamples/DocsExamples/Rendering and Printing/Rendering shapes.cs
+++ b/Examples/DocsExamples/DocsExamples/Rendering and Printing/Rendering shapes.cs
@@ -1,6 +1,4 @@
-#if NET48 || JAVA
-using System.Drawing;
-using System.Drawing.Imaging;
+using System.Drawing;
using Aspose.Words;
using Aspose.Words.Drawing;
using Aspose.Words.Rendering;
@@ -8,6 +6,8 @@
using Aspose.Words.Tables;
using NUnit.Framework;
using System.IO;
+using Aspose.Words.Layout;
+using System.Drawing.Imaging;
namespace DocsExamples.Rendering_and_Printing
{
@@ -17,7 +17,6 @@ internal class RenderingShapes : DocsExamplesBase
public void RenderShapeAsEmf()
{
Document doc = new Document(MyDir + "Rendering.docx");
-
// Retrieve the target shape from the document.
Shape shape = (Shape) doc.GetChild(NodeType.Shape, 0, true);
@@ -43,12 +42,10 @@ public void RenderShapeAsJpeg()
//ExStart:RenderShapeAsJpeg
//GistId:7fc867ac8ef1b729b6f70580fbc5b3f9
ShapeRenderer render = new ShapeRenderer(shape);
-
ImageSaveOptions imageOptions = new ImageSaveOptions(SaveFormat.Jpeg)
{
// Output the image in gray scale
ImageColorMode = ImageColorMode.Grayscale,
-
// Reduce the brightness a bit (default is 0.5f)
ImageBrightness = 0.45f
};
@@ -58,8 +55,8 @@ public void RenderShapeAsJpeg()
render.Save(stream, imageOptions);
}
//ExEnd:RenderShapeAsJpeg
- }
-
+ }
+#if NET48 || JAVA
[Test]
//ExStart:RenderShapeToGraphics
//GistId:7fc867ac8ef1b729b6f70580fbc5b3f9
@@ -68,12 +65,10 @@ public void RenderShapeToGraphics()
Document doc = new Document(MyDir + "Rendering.docx");
Shape shape = (Shape) doc.GetChild(NodeType.Shape, 0, true);
-
ShapeRenderer render = shape.GetShapeRenderer();
// Find the size that the shape will be rendered to at the specified scale and resolution.
Size shapeSizeInPixels = render.GetSizeInPixels(1.0f, 96.0f);
-
// Rotating the shape may result in clipping as the image canvas is too small. Find the longest side
// and make sure that the graphics canvas is large enough to compensate for this.
int maxSide = System.Math.Max(shapeSizeInPixels.Width, shapeSizeInPixels.Height);
@@ -102,6 +97,29 @@ public void RenderShapeToGraphics()
}
//ExEnd:RenderShapeToGraphics
+ [Test]
+ public void FindShapeSizes()
+ {
+ Document doc = new Document(MyDir + "Rendering.docx");
+
+ Shape shape = (Shape)doc.GetChild(NodeType.Shape, 0, true);
+
+ //ExStart:FindShapeSizes
+ //GistId:7fc867ac8ef1b729b6f70580fbc5b3f9
+ Size shapeRenderedSize = shape.GetShapeRenderer().GetSizeInPixels(1.0f, 96.0f);
+
+ using (Bitmap image = new Bitmap(shapeRenderedSize.Width, shapeRenderedSize.Height))
+ {
+ using (Graphics graphics = Graphics.FromImage(image))
+ {
+ // Render shape onto the graphics object using the RenderToScale
+ // or RenderToSize methods of ShapeRenderer class.
+ }
+ }
+ //ExEnd:FindShapeSizes
+ }
+#endif
+
[Test]
public void RenderCellToImage()
{
@@ -109,7 +127,8 @@ public void RenderCellToImage()
//ExStart:RenderCellToImage
Cell cell = (Cell)doc.GetChild(NodeType.Cell, 2, true);
- RenderNode(cell, ArtifactsDir + "RenderShape.RenderCellToImage.png", null);
+ Document tmp = ConvertToImage(doc, cell);
+ tmp.Save(ArtifactsDir + "RenderShape.RenderCellToImage.png");
//ExEnd:RenderCellToImage
}
@@ -120,7 +139,8 @@ public void RenderRowToImage()
//ExStart:RenderRowToImage
Row row = (Row) doc.GetChild(NodeType.Row, 0, true);
- RenderNode(row, ArtifactsDir + "RenderShape.RenderRowToImage.png", null);
+ Document tmp = ConvertToImage(doc, row);
+ tmp.Save(ArtifactsDir + "RenderShape.RenderRowToImage.png");
//ExEnd:RenderRowToImage
}
@@ -141,32 +161,11 @@ public void RenderParagraphToImage()
PaperColor = Color.LightPink
};
- RenderNode(textBoxShape.LastParagraph, ArtifactsDir + "RenderShape.RenderParagraphToImage.png", options);
+ Document tmp = ConvertToImage(doc, textBoxShape.LastParagraph);
+ tmp.Save(ArtifactsDir + "RenderShape.RenderParagraphToImage.png");
//ExEnd:RenderParagraphToImage
}
- [Test]
- public void FindShapeSizes()
- {
- Document doc = new Document(MyDir + "Rendering.docx");
-
- Shape shape = (Shape) doc.GetChild(NodeType.Shape, 0, true);
-
- //ExStart:FindShapeSizes
- //GistId:7fc867ac8ef1b729b6f70580fbc5b3f9
- Size shapeRenderedSize = shape.GetShapeRenderer().GetSizeInPixels(1.0f, 96.0f);
-
- using (Bitmap image = new Bitmap(shapeRenderedSize.Width, shapeRenderedSize.Height))
- {
- using (Graphics graphics = Graphics.FromImage(image))
- {
- // Render shape onto the graphics object using the RenderToScale
- // or RenderToSize methods of ShapeRenderer class.
- }
- }
- //ExEnd:FindShapeSizes
- }
-
[Test]
public void RenderShapeImage()
{
@@ -180,114 +179,90 @@ public void RenderShapeImage()
}
///
- /// Renders any node in a document to the path specified using the image save options.
+ /// Renders any node in a document into an image.
///
+ /// The current document.
/// The node to render.
- /// The path to save the rendered image to.
- /// The image options to use during rendering. This can be null.
- public void RenderNode(Node node, string filePath, ImageSaveOptions imageOptions)
+ private static Document ConvertToImage(Document doc, CompositeNode node)
{
- if (imageOptions == null)
- imageOptions = new ImageSaveOptions(FileFormatUtil.ExtensionToSaveFormat(Path.GetExtension(filePath)));
-
- // Store the paper color to be used on the final image and change to transparent.
- // This will cause any content around the rendered node to be removed later on.
- Color savePaperColor = imageOptions.PaperColor;
- imageOptions.PaperColor = Color.Transparent;
-
- // There a bug which affects the cache of a cloned node.
- // To avoid this, we clone the entire document, including all nodes,
- // finding the matching node in the cloned document and rendering that instead.
- Document doc = (Document) node.Document.Clone(true);
- node = doc.GetChild(NodeType.Any, node.Document.GetChildNodes(NodeType.Any, true).IndexOf(node), true);
-
- // Create a temporary shape to store the target node in. This shape will be rendered to retrieve
- // the rendered content of the node.
- Shape shape = new Shape(doc, ShapeType.TextBox);
- Section parentSection = (Section) node.GetAncestor(NodeType.Section);
-
- // Assume that the node cannot be larger than the page in size.
- shape.Width = parentSection.PageSetup.PageWidth;
- shape.Height = parentSection.PageSetup.PageHeight;
- shape.FillColor = Color.Transparent;
-
- // Don't draw a surronding line on the shape.
- shape.Stroked = false;
-
- // Move up through the DOM until we find a suitable node to insert into a Shape
- // (a node with a parent can contain paragraphs, tables the same as a shape). Each parent node is cloned
- // on the way up so even a descendant node passed to this method can be rendered. Since we are working
- // with the actual nodes of the document we need to clone the target node into the temporary shape.
- Node currentNode = node;
- while (!(currentNode.ParentNode is InlineStory || currentNode.ParentNode is Story ||
- currentNode.ParentNode is ShapeBase))
- {
- CompositeNode parent = (CompositeNode) currentNode.ParentNode.Clone(false);
- currentNode = currentNode.ParentNode;
- parent.AppendChild(node.Clone(true));
- node = parent; // Store this new node to be inserted into the shape.
- }
+ Document tmp = CreateTemporaryDocument(doc, node);
+ AppendNodeContent(tmp, node);
+ AdjustDocumentLayout(tmp);
+ return tmp;
+ }
- // We must add the shape to the document tree to have it rendered.
- shape.AppendChild(node.Clone(true));
- parentSection.Body.FirstParagraph.AppendChild(shape);
+ ///
+ /// Creates a temporary document for further rendering.
+ ///
+ private static Document CreateTemporaryDocument(Document doc, CompositeNode node)
+ {
+ Document tmp = (Document)doc.Clone(false);
+ tmp.Sections.Add(tmp.ImportNode(node.GetAncestor(NodeType.Section), false, ImportFormatMode.UseDestinationStyles));
+ tmp.FirstSection.AppendChild(new Body(tmp));
+ tmp.FirstSection.PageSetup.TopMargin = 0;
+ tmp.FirstSection.PageSetup.BottomMargin = 0;
- // Render the shape to stream so we can take advantage of the effects of the ImageSaveOptions class.
- // Retrieve the rendered image and remove the shape from the document.
- MemoryStream stream = new MemoryStream();
- ShapeRenderer renderer = shape.GetShapeRenderer();
- renderer.Save(stream, imageOptions);
- shape.Remove();
+ return tmp;
+ }
- Rectangle crop = renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution,
- imageOptions.VerticalResolution);
+ ///
+ /// Adds a node to a temporary document.
+ ///
+ private static void AppendNodeContent(Document tmp, CompositeNode node)
+ {
+ if (node is HeaderFooter headerFooter)
+ foreach (Node hfNode in headerFooter.GetChildNodes(NodeType.Any, false))
+ tmp.FirstSection.Body.AppendChild(tmp.ImportNode(hfNode, true, ImportFormatMode.UseDestinationStyles));
+ else
+ AppendNonHeaderFooterContent(tmp, node);
+ }
- using (Bitmap renderedImage = new Bitmap(stream))
+ private static void AppendNonHeaderFooterContent(Document tmp, CompositeNode node)
+ {
+ Node parentNode = node.ParentNode;
+ while (!(parentNode is InlineStory || parentNode is Story || parentNode is ShapeBase))
{
- Bitmap croppedImage = new Bitmap(crop.Width, crop.Height);
- croppedImage.SetResolution(imageOptions.HorizontalResolution, imageOptions.VerticalResolution);
-
- // Create the final image with the proper background color.
- using (Graphics g = Graphics.FromImage(croppedImage))
- {
- g.Clear(savePaperColor);
- g.DrawImage(renderedImage, new Rectangle(0, 0, croppedImage.Width, croppedImage.Height), crop.X,
- crop.Y, crop.Width, crop.Height, GraphicsUnit.Pixel);
+ CompositeNode parent = (CompositeNode)parentNode.Clone(false);
+ parent.AppendChild(node.Clone(true));
+ node = parent;
- croppedImage.Save(filePath);
- }
+ parentNode = parentNode.ParentNode;
}
+
+ tmp.FirstSection.Body.AppendChild(tmp.ImportNode(node, true, ImportFormatMode.UseDestinationStyles));
}
///
- /// Finds the minimum bounding box around non-transparent pixels in a Bitmap.
+ /// Adjusts the layout of the document to fit the content area.
///
- public Rectangle FindBoundingBoxAroundNode(Bitmap originalBitmap)
+ private static void AdjustDocumentLayout(Document tmp)
{
- Point min = new Point(int.MaxValue, int.MaxValue);
- Point max = new Point(int.MinValue, int.MinValue);
+ LayoutEnumerator enumerator = new LayoutEnumerator(tmp);
+ RectangleF rect = RectangleF.Empty;
+ rect = CalculateVisibleRect(enumerator, rect);
+
+ tmp.FirstSection.PageSetup.PageHeight = rect.Height;
+ tmp.UpdatePageLayout();
+ }
- for (int x = 0; x < originalBitmap.Width; ++x)
+ ///
+ /// Calculates the visible area of the content.
+ ///
+ private static RectangleF CalculateVisibleRect(LayoutEnumerator enumerator, RectangleF rect)
+ {
+ RectangleF result = rect;
+ do
{
- for (int y = 0; y < originalBitmap.Height; ++y)
+ if (enumerator.MoveFirstChild())
{
- // Note that you can speed up this part of the algorithm using LockBits and unsafe code instead of GetPixel.
- Color pixelColor = originalBitmap.GetPixel(x, y);
-
- // For each pixel that is not transparent, calculate the bounding box around it.
- if (pixelColor.ToArgb() != Color.Empty.ToArgb())
- {
- min.X = System.Math.Min(x, min.X);
- min.Y = System.Math.Min(y, min.Y);
- max.X = System.Math.Max(x, max.X);
- max.Y = System.Math.Max(y, max.Y);
- }
+ if (enumerator.Type == LayoutEntityType.Line || enumerator.Type == LayoutEntityType.Span)
+ result = result.IsEmpty ? enumerator.Rectangle : RectangleF.Union(result, enumerator.Rectangle);
+ result = CalculateVisibleRect(enumerator, result);
+ enumerator.MoveParent();
}
- }
+ } while (enumerator.MoveNext());
- // Add one pixel to the width and height to avoid clipping.
- return new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1);
+ return result;
}
}
-}
-#endif
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/Examples/DocsExamples/DocumentExplorer/DocumentExplorer.csproj b/Examples/DocsExamples/DocumentExplorer/DocumentExplorer.csproj
index 531a4346f..b9b2290af 100644
--- a/Examples/DocsExamples/DocumentExplorer/DocumentExplorer.csproj
+++ b/Examples/DocsExamples/DocumentExplorer/DocumentExplorer.csproj
@@ -141,7 +141,7 @@
- 24.4.0
+ 24.8.0