PDFsharp & MigraDoc Foundation

PDFsharp - A .NET library for processing PDF & MigraDoc Foundation - Creating documents on the fly
It is currently Thu Mar 28, 2024 8:22 am

All times are UTC


Forum rules


Please read this before posting on this forum: Forum Rules



Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sun Mar 26, 2017 3:38 pm 
Offline

Joined: Sun Mar 26, 2017 1:35 pm
Posts: 5
Hi,

I am trying to create a multiple-pages document that contains images and text.
I use MigraDoc to format the document using sections and paragraphs, thus I don't know the exact coordinates at which the images will be placed.
Unfortunately, I'm, required to mark each image with circles whose center is given relative to the image top-left.
Is there a simple was for doing this?

Thanks


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 26, 2017 5:10 pm 
Offline
PDFsharp Expert
User avatar

Joined: Sat Mar 14, 2015 10:15 am
Posts: 909
Location: CCAA
Hi!
is2 wrote:
Unfortunately, I'm, required to mark each image with circles whose center is given relative to the image top-left.
Is there a simple was for doing this?
Depends on the definition of simple. I assume you want to generate PDF documents.

You can use "pdfRenderer.PrepareRenderPages()" to let MigraDoc do the layout.

Then you can use PDFsharp to draw page by page by calling "pdfRenderer.DocumentRenderer.RenderPage(gfx, i)".
For each image you can use PDFsharp methods to draw the circles.

Class "DocumentRenderer" has a method "public RenderInfo[] GetRenderInfoFromPage(int page)" that can be used to find all objects for a page.

You can use the Tag property of any MigraDoc element (including the images) to identify the images you find on a page. Finding images in table cells is a bit tricky.

See also:
viewtopic.php?f=8&t=3172
http://stackoverflow.com/a/38685582/1015447

I haven't published a working sample for those methods (yet).
If you get it running, feel free to share a sample on this forum.
If you encounter specific problems, feel free to ask for help.

_________________
Best regards
Thomas
(Freelance Software Developer with several years of MigraDoc/PDFsharp experience)


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 28, 2017 11:11 am 
Offline

Joined: Sun Mar 26, 2017 1:35 pm
Posts: 5
Hi Thomas

I upgraded from version 1.32 to 1.50-Beta3 and followed you instructions.
I was able to locate the image objects inside the paragraphs, but I wasn't able to retrive their absolute coordinates on the page.
I need those coordinates in order to draw circles on specific locations on images.

This is what I did so far:
I call the following function after calling pdfRenderer.DocumentRenderer.RenderPage() :

Code:
using MigraDoc.Rendering;
void PostRenderPage(DocumentRenderer documentRenderer, XGraphics xGraphics, int pageNumber)
{
  RenderInfo[] pageObjects = documentRenderer.GetRenderInfoFromPage(pageNumber);
  for ( int i = 0; i < pageObjects.Length; ++i  )
  {
    ParagraphRenderInfo paragraphRenderInfo = null;
    if ( pageObjects[i].GetType() != typeof(ParagraphRenderInfo) )
      continue;

    paragraphRenderInfo = (ParagraphRenderInfo)System.Convert.ChangeType(pageObjects[i], typeof(ParagraphRenderInfo));
    FormatInfo formatInfo = paragraphRenderInfo.FormatInfo;

    // The following doesn't work since 'ParagraphFormatInfo' is an internal class.
    // MigraDoc.Rendering.ParagraphFormatInfo paragraphFormatInfo =
    //                                              (ParagraphFormatInfo)paragraphRenderInfo.FormatInfo;

    Paragraph    paragraph = (Paragraph)System.Convert.ChangeType(documentObject, typeof(Paragraph));

    ParagraphElements paragraphElements = paragraph.Elements;
    for ( int j = 0; j < paragraph.Elements.Count; ++j )
    {
      DocumentObject paragraphObject = paragraphElements[j];
      Image image = null;
      if ( paragraphObject.GetType() != typeof(Image) )
        continue;

      image = (Image)System.Convert.ChangeType(paragraphObject, typeof(Image));

      object objectTag = image.Tag;
    }
  }
}


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 28, 2017 1:05 pm 
Offline
PDFsharp Guru
User avatar

Joined: Mon Oct 16, 2006 8:16 am
Posts: 3095
Location: Cologne, Germany
Hi!

What you need is ImageRenderInfo for your image, not ParagraphRenderImage for the paragraph that contains the image.
The LayoutInfo member of ImageRenderInfo should have the coordinates you need.

_________________
Regards
Thomas Hoevel
PDFsharp Team


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 28, 2017 2:55 pm 
Offline

Joined: Sun Mar 26, 2017 1:35 pm
Posts: 5
Thanks again,

How do get the ImageRenderInfo objects?
The RenderInfo[] returns from GetRenderInfoFromPage contains only ParagraphRenderInfo and TableRenderInfo objects.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 29, 2017 8:25 am 
Offline
PDFsharp Guru
User avatar

Joined: Mon Oct 16, 2006 8:16 am
Posts: 3095
Location: Cologne, Germany
is2 wrote:
The RenderInfo[] returns from GetRenderInfoFromPage contains only ParagraphRenderInfo and TableRenderInfo objects.
Where are your images?
Are they part of the paragraphs?
Are they part of table cells?

You can use the AddImage() of the section. Is that a suitable workaround?
If not: MigraDoc has all the information internally. I don't know if it is public yet and I don't know where it is - but it is there.

_________________
Regards
Thomas Hoevel
PDFsharp Team


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 29, 2017 2:25 pm 
Offline

Joined: Sun Mar 26, 2017 1:35 pm
Posts: 5
My images are placed in paragraphs since I want to place 2 images side by side below a description text and all should be on the same page.


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 01, 2017 7:53 pm 
Offline

Joined: Sun Mar 26, 2017 1:35 pm
Posts: 5
Input:
Pairs of images along with a title and description and coordinates of a shape that should be drawn over each image.
The size of the first image is fixed, and a rectangle should be drawn over it.
The size of the second image is variable, and an elipse should be drawn over it.

Example:
The first image in each pair is a scaled down high resolution image of a tree, with a rectangle roi (region-of-interest) marked over it.
The second image is the cliped roi in high resolution, with an ellipse marking a bird or insect that is on the tree.

The problem
I would like to use MigraDoc in order to format the document so that for each pair of images, their title and description will be in the same pdf page as the images.
In case multiple pairs re displayed in the same page, I would like to control the gap between them.

On the other hand I would like to use PdfSharp for drawing the marks over the images, and since the drawing requires abolute coordinates, I need to convert the relative coordinates of the marks (relative to the image) to absolute page coordinatesm, by retrieving and adding the absolute coordinates of each image.

The solution
1) Displaying the images in a 1-row x 2-columns table. This way the top-left of the first image will be the same as the top-left of the table, and the top-left of the second image will be the top-left of the table shifted by the column width to the right.
Note: The using of a table is a workaround I used since I didn't find a way to retrived the rendering coordinates of the images. This workaround woudn't have worked if the size of the first images wasn't fixed.

2) In order to ensure that the title, description and images are displayed on the same page they are added to paragraphs with a KeepWithNext style.
The table of images is followed by a paragraph with a KeepWithNext = false , and SpaceAfter = 4 style, thus ensuring the gap between different data displayed on the same page.
Note:Since there are no KeepWithPrev styles, I don't know of a way to ensure that text followng the images will be displaed in the same page as the images.

The code
Note: The code below is a simplification of my runtime code. I compiled it with no errors, but I didn't run or debug it.

Code:
using System;
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using MigraDoc.DocumentObjectModel.Shapes;
using MigraDoc.DocumentObjectModel.Tables;
using PdfSharp.Pdf;
using PdfSharp.Drawing;


namespace ReporterNs
{
    class ReportCreatorDemo
    {
      public class Ellipse
      {
         public double X;       // center X
         public double Y;      // center Y
         public double L;       // long radius
         public double S;      // short radius
         public double Phi;      // angle in radians between the X axis and the long radius.
      }

      public class Data
      {
         public string  title;
         public string  description;
         public string  image1Path;
         public XRect   image1Mark;
         public string  image2Path;
         public Ellipse image2Mark;
      }

        Document m_document = null;
      PdfDocument m_pdfDocument = null;

      // The following variables should be initialized before calling CreateReport()      
      public Unit m_pageWidth        = 0;
      public Unit m_pageHeight       = 0;
      public Unit m_Image1Width      = 0;
      public Unit m_GapBetweenImages = 0;
      public Unit m_MaxImage2Width   = 0;

      protected void CreateReport(Data[] data, string pdfPath)
        {
         m_document = new Document();
         DefineStyles();
         AddData(data);
         Render(m_pageWidth, m_pageHeight);
            m_pdfDocument.Save(pdfPath);
        }

        void AddData(Data[] data)
        {
         Section section = m_document.LastSection;
            for (int i = 0; i < data.Length; ++i )
            {
            Data cur = data[i];

            Paragraph paragraph = section.AddParagraph(cur.title, "DataTitle");
            paragraph = section.AddParagraph(cur.description, "DataDescription");
            section.AddParagraph("", "BeforeImages");

            Table table = section.AddTable();
            table.AddColumn(m_Image1Width + m_GapBetweenImages);
            table.AddColumn(m_MaxImage2Width);
            table.Columns[0].LeftPadding = table.Columns[0].RightPadding = table.Columns[1].LeftPadding = table.Columns[1].RightPadding = 0;

            Row row = table.AddRow();

            Image image1 = new Image(cur.image1Path);
            image1.Tag = cur.image1Mark;
            image1.LockAspectRatio = true;
            row.Cells[0].Add(image1);

            Image image2 = new Image(cur.image2Path);
            image2.Tag = cur.image2Mark;
            image2.LockAspectRatio = true;
            row.Cells[1].Add(image2);

            section.AddParagraph("", "AfterImages"); // Setting KeepWithNext to false
            }
      }


        protected void Render(double pageWidth_mm, double pageHeight_mm)
        {
         DocumentRenderer documentRenderer = new DocumentRenderer(m_document);
         PdfDocument m_pdfDocument = new PdfDocument();

         documentRenderer.PrepareDocument();
         int pageCount = documentRenderer.FormattedDocument.PageCount;
         XRect pageRect = new XRect(0, 0, m_pageWidth, m_pageHeight);
      
         for (int pageNumber = 1; pageNumber <= pageCount; pageNumber++) // Note that page numbers start with 1.
         {
            PdfPage pdfPage = m_pdfDocument.AddPage();
            XGraphics xGraphics = XGraphics.FromPdfPage(pdfPage);

            XGraphicsContainer container = xGraphics.BeginContainer(pageRect, pageRect, XGraphicsUnit.Point);
            documentRenderer.RenderPage(xGraphics, pageNumber);
            PostRenderPage(documentRenderer, xGraphics, pageNumber);
            xGraphics.EndContainer(container); // Pop the previous graphical state
         }
      }


      protected void PostRenderPage(DocumentRenderer documentRenderer, XGraphics xGraphics, int pageNumber)
      {
         RenderInfo[] renderInfo = documentRenderer.GetRenderInfoFromPage(pageNumber);
         for ( int i = 0; i < renderInfo.Length; ++i  )
         {
            if ( renderInfo[i].GetType() != typeof(TableRenderInfo) )
               continue;
            TableRenderInfo tableRenderInfo = (TableRenderInfo)renderInfo[i];
            Table table = (Table)tableRenderInfo.DocumentObject;
            if ( table.IsNull() || table.Columns.IsNull() || table.Rows.IsNull() || table.Columns.Count < 2 )
                  continue;
            if ( table.Rows[0].Cells[0].Elements[0].GetType() != typeof(Image) || table.Rows[0].Cells[1].Elements[0].GetType() != typeof(Image) )
               continue;

            Area a = tableRenderInfo.LayoutInfo.ContentArea;

            Image image1 = (Image)System.Convert.ChangeType(table.Rows[0].Cells[0].Elements[0], typeof(Image));
            Image image2 = (Image)System.Convert.ChangeType(table.Rows[0].Cells[1].Elements[0], typeof(Image));
            XRect rect = (XRect)image1.Tag;
            rect.X += a.X;
            rect.Y += a.Y;
            xGraphics.DrawRectangle(new XPen(XColor.FromArgb(0,0,255), 2), rect);

            Ellipse ellipse = (Ellipse)image2.Tag;
            double centerX = a.X + table.Columns[0].Width + ellipse.X;
            double centerY = a.Y + ellipse.Y;

            float phiDegrees = -1 * (float)(180 * ellipse.Phi / Math.PI);
            XGraphicsState gfxState = xGraphics.Save();
            xGraphics.RotateAtTransform(phiDegrees, new XPoint(centerX , centerY));
            xGraphics.DrawEllipse(new XPen(XColor.FromArgb(255,0,0), 2), centerX - ellipse.L , centerY - ellipse.S, 2*ellipse.L, 2*ellipse.S);
            xGraphics.Restore(gfxState);
         }
      }

      public void DefineStyles()
      {
         Style style = m_document.Styles["Normal"];  // Get the predefined style Normal.

         style = m_document.Styles.AddStyle("DataTitle", "Normal");
         style.Font.Bold = true;
         style.ParagraphFormat.KeepWithNext = true;

         style = m_document.Styles.AddStyle("DataDescription", "Normal");
         style.ParagraphFormat.KeepWithNext = true;

         style = m_document.Styles.AddStyle("AfterImages", "Normal");
         style.ParagraphFormat.SpaceAfter = Unit.FromMillimeter(3.0);
         style.ParagraphFormat.KeepWithNext = false;
      }

    } // class ReportCreatorDemo


} // namespace ReporterNs



Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 108 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Privacy Policy, Data Protection Declaration, Impressum
Powered by phpBB® Forum Software © phpBB Group