What is the best practice for Unit conversion from point to MM for pdf dimensions

Hello,

i am using Syncfusion WinForms PDF on winform Net 8 application. 

1) My first question is which nuget package should be used for winform application on .Net 8:

Syncfusion.Pdf.NET or Syncfusion.Pdf.WinForms. What is the difference between these two as both of them can be used on .net winform project?

2) My main question is what is the best way to define  page size, page width as well objects(Drawstirng,drawImage) as mm instead of default point? And then how to manage dpi value
I am creating the page dimension with :

document.PageSettings.Size = new SizeF(_pagewidth, _pageHeight);

As it's default unit is point , my requirement is create page dimension with mm.
So is there a build-in procedure for this like:

document.PageSettings.Size = new SyncfusionSizeF(_pagewidth, _pageHeight,Unit.MM); 


or i need to convert each dimension unit to mm manually as i see syncfusion has PdfUnitConvertor helper class for this:

PdfUnitConvertor converter =newPdfUnitConvertor();
var _pagewidthMM =converter.ConvertUnits(_pagewidth,PdfGraphicsUnit.Inch,PdfGraphicsUnit.Point);
.....


So if i need to convert each dimension value to mm manually how to deal with dpi valuefor images and other objects like string on pdf.My current code to draw Image andstring:


Image :


 graphics.DrawRectangle(backColorBrush, rect);
  //Draw the image on top of the background
 if(imageObject.Data!=null)
 {
     graphics.SetTransparency(0.7f);
     using(var ms =newMemoryStream(imageObject.Dataasbyte[]))
     {
         using(var image =newBitmap(ms))
         {
             // Draw the image
             PdfBitmap pdfImage =newPdfBitmap(image);
             graphics.DrawImage(pdfImage, x, y, width, height);
         }
     }
 }


 // Draw the border last
 if(hasBorder)
 {
     graphics.SetTransparency(1.0f);
     graphics.DrawRectangle(borderPen, rect);
 } 


  String:

 RectangleF rect = new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value);


 if (backColorBrush != null)
     graphics.DrawRectangle(backColorBrush, rect); // Draw background


 graphics.DrawString(text, font, foreColorBrush, rect, format); // Draw text
 if (hasBorder)
     graphics.DrawRectangle(borderPen, rect);


3- Instead of adding drawrectangles for backcolor and border is there a way to apply borderpen and 

backColorBrush to graphics.DrawString or graphics.DrawImage => Also how to add bacground color for Image after set it is transparency like graphics.SetTransparency(0.5f);

 


12 Replies 1 reply marked as answer

JT Jeyalakshmi Thangamarippandian Syncfusion Team July 25, 2024 01:01 PM UTC

Hi ERTEM,

1. We recommend installing our Syncfusion.Pdf.WinForms package for .NET 8 WinForms applications. Additionally, the Syncfusion.Pdf.NET package is also compatible with .NET 8 WinForms applications.

The difference between the two packages is:

  • Syncfusion.Pdf.WinForms - This package depends on System.Drawing APIs and is only supported on Windows-based applications.
  • Syncfusion.Pdf.NET - This package does not depend on any Windows-specific packages, so we can use this package for all the supported platforms like windows, Mac, and Linux.

2. PDF dimensions are typically in points by default. We can utilize the PdfUnitConvertor helper class to convert millimeters (mm) to points.

3. It does not directly support the background color while drawing text and images. However, we can achieve this by drawing the rectangle. Kindly refer to the code snippet for your reference.

Code snippet:

//Draw the image background

graphics.DrawRectangle(PdfBrushes.Pink, new RectangleF(0,0, image.PhysicalDimension.Width, image.PhysicalDimension.Height));

graphics.Save();

graphics.SetTransparency(0.5f);

//Draw the image

graphics.DrawImage(image, 0, 0, image.PhysicalDimension.Width,image.PhysicalDimension.Height);

graphics.Restore();

 

string text = "Hello World!!!";

SizeF fontSize=font.MeasureString(text);

//Draw the text background

graphics.DrawRectangle(PdfBrushes.Pink, new RectangleF(0, 100,fontSize.Width,fontSize.Height));

//Draw the text.

graphics.DrawString(text, font, PdfBrushes.Black, new PointF(0, 100));

 

Sample:

https://www.syncfusion.com/downloads/support/directtrac/general/ze/189450F_190109F_sample-931667142

Please try it on your end and let us know if you require any further assistance.


Regards,

Jeyalakshmi T



ER ERTEM July 27, 2024 07:26 PM UTC

Thanks for answer, So again how to deal with image objects DPI value. Syncfusion  PdfUnitConvertor 's default dpi value is 96 but what is printer's dpi value is different? The image is autoresized by dpi value?



JT Jeyalakshmi Thangamarippandian Syncfusion Team July 29, 2024 12:39 PM UTC

Hi ERTEM,

We have an option in the PdfUnitConverter to obtain the resolution from the system graphics. Please refer to the following code example for more details.

 

Image systemImage = Image.FromFile("../../../Image.jpg");

//Create PDF bitmap instance.

PdfBitmap image = new PdfBitmap(systemImage);

//Create system graphics.

Graphics graphics = Graphics.FromImage(systemImage);

//Create a PDF unit converter instance.

PdfUnitConvertor converter = new PdfUnitConvertor(graphics);

//Convert to point.

float width = converter.ConvertFromPixels(image.Width, PdfGraphicsUnit.Point);

float height = converter.ConvertFromPixels(image.Height, PdfGraphicsUnit.Point);

//Draw image to PDF page.

page.Graphics.DrawImage(image, new RectangleF(0, 0, width, height));

              

 

Please refer to the API documentation for further details:

PdfUnitConvertor Class - C# PDF Library API Reference | Syncfusion


Regards,

Jeyalakshmi T



ER ERTEM July 29, 2024 03:30 PM UTC

Thanks for the reply, the problem is i need to encapsulate/trim image based on fixed width height value of object:

var width = 256; //as point

var height = 256; //as point


 PdfBitmap pdfImage = new PdfBitmap(image);

Graphics graphics = Graphics.FromImage(systemImage);

PdfUnitConvertor converter = new PdfUnitConvertor(graphics);

float imgWidth = converter.ConvertFromPixels(image.Width, PdfGraphicsUnit.Point); //810 as point

float imgHeight = converter.ConvertFromPixels(image.Height, PdfGraphicsUnit.Point);//1,440 as point


page.Graphics.DrawImage(image, new RectangleF(0, 0, width, height));

So how is it working when i use image inside DrawImage with fixed height and width, is it automaticllay convert ed pixel to pt and trimmed based on x,y location?

- I am also confused about  
PdfTextElement and graphics.DrawString methods? What is the difference of them? When drawing string on pdf , sometimes , i need also to add border and backgroundcolor? Which one of them fit for this scenario?




JT Jeyalakshmi Thangamarippandian Syncfusion Team July 30, 2024 03:11 PM UTC

Our PdfGraphics.DrawImage API draws images within the specified bounds. If the image dimensions exceed these bounds, the image will be encapsulated and drawn within the limits. If the image dimensions are smaller than the bounds, the image will be stretched to fit. This method does not trim or clip the image.

 

However, to meet your requirements, we can set the image clip bounds in PdfGraphics and draw them on the PDF page. Please refer to the following code example and the Knowledge Base article for more details.

Image systemImage = Image.FromFile("../../../Image.jpg");

//Create PDF bitmap instance.

PdfBitmap image = new PdfBitmap(systemImage);

 

float width = 100;

float height = 100;

page.Graphics.Save();

GraphicsPath path = new GraphicsPath();

path.AddRectangle(new RectangleF(0, 0, width, height));

PdfPath pdfpath = new PdfPath(path.PathPoints, path.PathTypes);

page.Graphics.SetClip(pdfpath);

//Draw image to PDF page.

page.Graphics.DrawImage(image, new RectangleF(0, 0, image.Width, image.Height));

page.Graphics.Restore();

 

KB article: https://support.syncfusion.com/kb/article/8672/how-to-draw-the-circular-shape-image-in-a-pdf-using-c-and-vb-net 

 

The PdfTextElement is used to draw text to the PDF page and returns a layout result, allowing us to track the bounds of the drawn text. However, the PdfGraphics.DrawString method does not return any layout results, so the positioning of graphic elements must be done manually. As mentioned in the previous update, neither of these APIs supports borders or background colors directly. Therefore, you can draw the border or background color using the layout result of the PdfTextElement.




ER ERTEM July 31, 2024 08:55 PM UTC

Thank you, but i cannot use PdfTextLayoutResult as cannot send page parameter instead i can send


PdfGraphics parameter as i am using PdfPageTemplateElement for header and footer:

    
 
    private MemoryStream GeneratePdf()
    {
        List<BaseReportObject> reportObjects = _pdfUIObject.PdfObject.OfType<BaseReportObject>().ToList();
        if (!reportObjects.Any())
        {
            return null;
        }




        //PdfUnitConvertor converter = new PdfUnitConvertor();
        //converter.ConvertUnits(1, PdfGraphicsUnit.Inch, PdfGraphicsUnit.Point);


        PdfDocument document = new PdfDocument();
        document.PageSettings.Size = new SizeF(_pagewidth, _pageHeight);
        document.PageSettings.Margins.All = 0;


        var headerObjects = reportObjects.Where(o => LocationTypeEnumHelper.GetLocationType(o.Location?.Trim()) == LocationTypeEnumHelper.LocationTypeEnum.H).ToList();
        var footerObjects = reportObjects.Where(o => LocationTypeEnumHelper.GetLocationType(o.Location?.Trim()) == LocationTypeEnumHelper.LocationTypeEnum.F).ToList();
        var bodyObjects = reportObjects.Where(o => LocationTypeEnumHelper.GetLocationType(o.Location?.Trim()) == LocationTypeEnumHelper.LocationTypeEnum.B).ToList();
        var newPageObjects = reportObjects.Where(o => ObjectTypeEnumHelper.GetObjectType(o.ObjectType?.Trim()) == ObjectTypeEnumHelper.ObjectTypeEnum.NewPage).ToList();
        PdfPage currentPage = document.Pages.Add();


        // Define header template
        PdfPageTemplateElement headerTemplate = new PdfPageTemplateElement(new RectangleF(0, 0, _pagewidth, _headerHeight));
        PdfGraphics headerGraphics = headerTemplate.Graphics;
        document.Template.Top = headerTemplate;
        foreach (var headerObject in headerObjects)
        {
            switch (headerObject)
            {
                case TextObject textObject:
                    CreateTextObjectOnTemplate(textObject, headerGraphics);
                    break;
                case TableObject tableObject:
                    CreateTableObjectOnTemplate(tableObject, headerGraphics);
                    break;


                case ImageObject imageObject:
                    CreateImageObjectOnTemplate(imageObject, headerGraphics);
                    break;
            }
        }




        // Define footer template
        PdfPageTemplateElement footerTemplate = new PdfPageTemplateElement(new RectangleF(0, 0, _pagewidth, _footerHeight));
        PdfGraphics footerGraphics = footerTemplate.Graphics;
        document.Template.Bottom = footerTemplate;




        foreach (var footerObject in footerObjects)
        {
            switch (footerObject)
            {


                case TextObject textObject:
                    CreateTextObjectOnTemplate(textObject, footerGraphics);
                    break;
                case TableObject tableObject:
                    CreateTableObjectOnTemplate(tableObject, footerGraphics);
                    break;
                case ImageObject imageObject:
                    CreateImageObjectOnTemplate(imageObject, footerGraphics);
                    break;


            }
        }




        // Add body objects to the document pages


        int firstElementCount = 0;
        foreach (var bodyObject in bodyObjects)
        {
            // Process the object
            switch (bodyObject)
            {
                case NewPageObject newPageObject:
                    currentPage = document.Pages.Add();
                    break;


                case ImageObject imageObject:
                    CreateImageObjectOnBody(imageObject, currentPage);
                    break;
                case TextObject textObject:
                    CreateTextObjectOnBody(textObject, currentPage, document);
                    break;
                case TableObject tableObject:
                    currentPageNumberForTable = 1;
                    CreateTableObjectOnBody(tableObject, currentPage, document);
                    break;


            }
        }


        MemoryStream stream = new MemoryStream();
        document.Save(stream);
        document.Close(true);


        stream.Position = 0;
        return stream;
    }

 private void CreateTextObjectOnTemplate(TextObject textObject, PdfGraphics graphics)
 {
     CreateTextObject(textObject, graphics);
 }


 private void CreateTextObject(TextObject textObject, PdfGraphics graphics)
 {


     ConvertObjectDimensions(textObject, PdfGraphicsUnit.Millimeter);
     PdfTrueTypeFont font = GetFont(textObject); // Font related props => FontType , FontSize, FontBold, FontItalic, FontUnderline
     (float? bordersize, PdfPen? borderPen) = GetBorderInfo(textObject); //Border,BorderSize
     bool hasBorder = textObject.Border ?? false;
     (PdfTextAlignment horizontalAlignment, PdfVerticalAlignment verticalAlignment) = GetAligmentInfo(textObject); //HorizontalAlign, VerticalAlign assign
     (PdfBrush foreColorBrush, PdfBrush backColorBrush) = GetColors(textObject); //ForeColor,Backcolor
     PdfStringFormat format = GetFormat(textObject, horizontalAlignment, verticalAlignment); //text vertical , horizantal aligment set , Multine/wordwrap


     string text = textObject.Data as string ?? "";
     if (!string.IsNullOrWhiteSpace(text) && textObject.MaxChar != null)
     {
         if (textObject.MaxChar < text.Count())
             text = text.Substring(0, textObject.MaxChar.Value);
     }
     RectangleF rect = new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value);








     if (backColorBrush != null)
         graphics.DrawRectangle(backColorBrush, rect);


    graphics.DrawString(text, font, foreColorBrush, rect, format);




     if (hasBorder)
     {
         RectangleF borderRect = new RectangleF(rect.X - bordersize.Value / 2, rect.Y - bordersize.Value / 2, rect.Width + bordersize.Value, rect.Height + bordersize.Value);
         graphics.DrawRectangle(borderPen, borderRect);
     }


 }

      

 I cannot find a way to get page from graphics if possible. My ultimate goal was converting DrawString to


PdfTextElement textElement = new PdfTextElement(text, font, borderPen , foreColorBrush, format);

PdfTextLayoutResult result = textElement.Draw(page, new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value), layoutFormat);


as you see PdfTextElement is getting pen element as border defining, so i thought i can get rid of graphics.DrawRectangle(borderPen, rect); line to draw border. But it looks i must continue with my current codes

- Another issue is after i define rectange width,height value , if text font is too big to not fit inside Rectange, it goes invisible instead i want to see visible part Like this:

Image_2306_1722458767143

but instead text is going invisible:

Image_2813_1722458823299

 graphics.DrawString(text, font, foreColorBrush, rect, format);
......

 PdfStringFormat format = new PdfStringFormat

 {

     Alignment = horizontalAlign,

     LineAlignment = verticalAlignment,

     LineLimit = true,

     WordWrap = PdfWordWrapType.Word


 };





JT Jeyalakshmi Thangamarippandian Syncfusion Team August 1, 2024 04:02 PM UTC

Currently we are working on this, we will update further details by 2nd August 2024.



JT Jeyalakshmi Thangamarippandian Syncfusion Team August 2, 2024 01:57 PM UTC

Thank you for your patience,

 

I cannot find a way to get page from graphics if possible. My ultimate goal was converting DrawString to

 

PdfTextElement textElement = new PdfTextElement(text, font, borderPen , foreColorBrush, format);

PdfTextLayoutResult result = textElement.Draw(page, new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value), layoutFormat);

 

as you see PdfTextElement is getting pen element as border defining, so i thought i can get rid of graphics.DrawRectangle(borderPen, rect); line to draw border. But it looks i must continue with my current codes

 

As we mentioned before, the PdfGraphics.DrawString method does not return any layout results. The PdfTextElement is used to draw text to the PDF page and returns a layout result, allowing us to track the bounds of the drawn text.

However, you can use our PdfStringLayouter to obtain the PdfStringLayoutResult API. We have also modified the sample and attached for your reference.

Sample:

https://www.syncfusion.com/downloads/support/directtrac/general/ze/618313_sample360922143

Please try it on your end and let us know if you require any further assistance. 

 

Another issue is after i define rectange width,height value , if text font is too big to not fit inside Rectange, it goes invisible instead i want to see visible part Like this:

 

As per the behavior, if the text doesn't fit within the given rectangle bounds, it will not render. To ensure the text fits within the given bounds, we suggest disable the NoClip and LineLimit API. Kindly refer to the code snippet for your reference.

 

string text = @"PdfStringFormat 1

 

PdfStringFormat 2

 

PdfStringFormat 3

 

";

PdfStringFormat format = new PdfStringFormat();

format.Alignment = PdfTextAlignment.Left;

format.NoClip = false;

format.LineLimit = false;

format.WordWrap = PdfWordWrapType.Word;

PdfFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 50);

 

PdfDocument document = new PdfDocument();

 

document.PageSettings.Margins.All = 0;

 

PdfPage page = document.Pages.Add();

 

PdfGraphics graphics = page.Graphics;

 

 

graphics.DrawRectangle(PdfPens.Red, new RectangleF(100, 100, 100, 40));

 

graphics.DrawString(text, font, PdfBrushes.Black, new RectangleF(100, 100, 100, 40), format);

 

 

 

PdfStringFormat.LineLimit: The default value of the LineLimit property is true. If we set the LineLimit, the provided string will be laid out within the specified bounds. If we disable the LineLimit property, the layout will continue with the remaining spaces.

 

PdfStringFormat.NoClip: If we enable the NoClip option, it will show the text without cutting any words. If we disable the NoClip option, any text outside the fitting area will be hidden.

 

 

LineLimit

NoClip

Result

true

true

undefined

false

true

undefined

true

false

undefined

false

false

undefined

 

 





ER ERTEM August 2, 2024 04:09 PM UTC

Thanks for answer, noClip and LineLimit together solved my issue.

Now i have one last thing to do. On my app , as default the format for texts on pdf :

PdfStringFormat format = new PdfStringFormat


 {


     Alignment = horizontalAlign,


     LineAlignment = verticalAlignment,


     LineLimit = true,


     WordWrap = PdfWordWrapType.Word,


 };



 


Given your example, i need to identify if rectangle Height is exceed by text's font size so i can change format. How can i do that?

 PdfTrueTypeFont font = new PdfTrueTypeFont(new System.Drawing.Font(FontFamily.GenericSerif, fontSize, fontStyleIsBold | fontStyleIsItalic | fontStyleIsUnderline), fontSize);


RectangleF rect = new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value);


//Need to compare rectange's height against fontsize like this

//Should i need to convert font.fontsize(it' unit em i though) to point or something?

If(font.Size > rect.Height )


{


format. LineLimit = false

format.NoClip = false


}








JT Jeyalakshmi Thangamarippandian Syncfusion Team August 5, 2024 01:54 PM UTC

Now i have one last thing to do. On my app , as default the format for texts on pdf :

By default, the format for texts on PDF can be set using the PdfStringFormat class.

 

Property

Default value

Alignment

PdfTextAlignment.Left

Line alignment

PdfVerticalAlignment.Top

LineLimit

false

WordWrap

PdfWordWrapType.Word

ClipPath

false

CharacterSpacing

zero

LineSpacing

zero

NoClip

false

WordSpacing

zero

 

Please refer to the API documentation for further details:

https://help.syncfusion.com/cr/file-formats/Syncfusion.Pdf.Graphics.PdfStringFormat.html#Syncfusion_Pdf_Graphics_PdfStringFormat_Alignment

 

Given your example, i need to identify if rectangle Height is exceed by text's font size so i can change format. How can i do that?

Upon further analysis, we found that we can achieve your requirement by calculating the font height. You can use the measureString method to determine the width and height of the text to be drawn, which should return a point value. If the font height exceeds the rectangle height, you can include your condition within the if block.

Code snippet:

 

PdfTrueTypeFont font = new PdfTrueTypeFont(new System.Drawing.Font(FontFamily.GenericSerif, fontSize, fontStyleIsBold | fontStyleIsItalic | fontStyleIsUnderline), fontSize);

//Measure the text

SizeF size = font.MeasureString(text);

float textHeight=size.Height;//return a point value

RectangleF rect = new RectangleF(textObject.X.Value, textObject.Y.Value, textObject.Width.Value, textObject.Height.Value);

 

//Need to compare rectange's height against fontsize like this

//Should i need to convert font.fontsize(it' unit em i though) to point or something?

If(font.Size > rect.Height )

 

{

//Include your code here

format. LineLimit = false

format.NoClip = false

}

 

Please refer to the UG and API documentation for further details:

PdfFont Class - C# PDF Library API Reference | Syncfusion

Working with Text | Syncfusion 

 

 



Marked as answer

ER ERTEM August 5, 2024 02:26 PM UTC

Thanks for awesome support



SS Swetha Srikumar Syncfusion Team August 8, 2024 10:46 AM UTC

Most welcome.

Please get back to us for any further assistance.


Loader.
Up arrow icon