using System; using System.Collections.Generic; using System.Linq; using System.Text; using MigraDom = MigraDoc.DocumentObjectModel; using System.Windows.Documents; using System.Windows; using System.Windows.Media; namespace Demos.Warden.TagTextEditing { // REMARKS: // - FlowDocument consists of Blocks, which, according to MSDN, can be of following types: // >> Paragraph (SUPPORTED), Table (SUPPORTED), BlockUIContainer (PARTIALLY SUPPORTED (IMAGE)) // >> List (NOT SUPPORTED, BUT SHOULD BE), Section (NOT SUPPORTED, NOT PLANED) // - actual content is part of Inline which can be of various types, but mostly Run // >> special Inline type is Span, which somehow encompasses styling for whole group of Runs => THE FORMATTING IS NOT YET FIGURED OUT!! // - Not all elements and case scenarios are supported // >> unsupported parts are currently JUMPED OVER // => These jumps SHOULD probably be gathered into an object (property) that the caller could read... // >> these cases are commented in the code below as viable subjects to logging... internal class PdfConverter { private MigraDom.Document _document = null; private const double A4Width = 210; private const double SideMarginPDF = 22; public MigraDom.Document convertToMigraDoc(FlowDocument document) { this._document = new MigraDom.Document(); MigraDom.Section sec = this._document.AddSection(); MigraDom.PageSetup ps = new MigraDom.PageSetup(); ps.PageFormat = MigraDom.PageFormat.A4; ps.LeftMargin = MigraDom.Unit.FromMillimeter(SideMarginPDF); ps.RightMargin = MigraDom.Unit.FromMillimeter(SideMarginPDF); sec.PageSetup = ps; foreach (Block block in document.Blocks.ToArray()) { if (block is Paragraph) { this.ProcessParagraph((Paragraph)block, sec.AddParagraph()); } else if (block is ThreeColumnLayoutTable) { this.ProcessThreeColumnLayout((ThreeColumnLayoutTable)block, sec); } else if (block is Table) { this.ProcessTable((Table)block, sec); } else if (block is BlockUIContainer) { this.ProcessBlockUIContainer((BlockUIContainer)block, sec); } } return this._document; } private void ProcessParagraph(Paragraph para, MigraDom.Paragraph mpara) { foreach(Inline inline in para.Inlines.ToArray()) { this.ProcessInline(inline, mpara); } } private void ProcessInline(Inline inline, MigraDom.Paragraph para) { if (inline is Run) { this.ProcessRun((Run)inline, para); } else if (inline is Span) { Span curSpan = (Span)inline; foreach (Inline subInline in curSpan.Inlines.ToArray()) { this.ProcessInline(subInline, para); } } //Unable to figure out formatting for content of span; the formatting is somehow part of the span itself else if (inline is InlineUIContainer && ((InlineUIContainer)inline).Child is System.Windows.Controls.Image) { System.Windows.Controls.Image img = (System.Windows.Controls.Image)((InlineUIContainer)inline).Child; this.ProcessImageInline(img, para); } else { // log the situation (see class remarks above) } } private void ProcessRun(Run run, MigraDom.Paragraph para) { TextRange tr = new TextRange(run.ContentStart, run.ContentEnd); string plainText = tr.Text; MigraDom.FormattedText ft = para.AddFormattedText(plainText); MigraDom.Font mfont = new MigraDom.Font(); if (new[] { FontWeights.Black, FontWeights.ExtraBlack, FontWeights.UltraBlack, FontWeights.SemiBold, FontWeights.Bold, FontWeights.ExtraBold, FontWeights.UltraBold }.Contains(run.FontWeight)) { ft.Bold = true; } if (run.FontStyle == FontStyles.Italic) { ft.Italic = true; } if (run.TextDecorations == TextDecorations.Underline) { ft.Underline = MigraDom.Underline.Single; } if (run.Parent is Paragraph) { Paragraph containingPara = (Paragraph)run.Parent; if (containingPara.TextAlignment == TextAlignment.Left) { para.Format.Alignment = MigraDom.ParagraphAlignment.Left; } else if (containingPara.TextAlignment == TextAlignment.Center) { para.Format.Alignment = MigraDom.ParagraphAlignment.Center; } else if (containingPara.TextAlignment == TextAlignment.Right) { para.Format.Alignment = MigraDom.ParagraphAlignment.Right; } else if (containingPara.TextAlignment == TextAlignment.Justify) { para.Format.Alignment = MigraDom.ParagraphAlignment.Justify; } } ft.Font.Size = MigraDom.Unit.FromPoint(run.FontSize); SolidColorBrush color = run.Foreground as SolidColorBrush; if (color != null) { string colorRgb = color.ToString(); string parsable = colorRgb.Replace("#", "0x"); try { ft.Font.Color = MigraDom.Color.Parse(parsable); } catch (Exception ex) { } // log the situation (see class remarks above) } try { ft.FontName = run.FontFamily.Source; } catch (Exception ex) { } // log the situation (see class remarks above) } private void ProcessTagElement(TagBaseElement element, MigraDom.Paragraph para) { MigraDom.FormattedText ft = para.AddFormattedText(); ft.AddText(element.getActualValue()); } private void ProcessThreeColumnLayout(ThreeColumnLayoutTable threeColumnLayout, MigraDom.Section section) { MigraDom.Tables.Table table = section.AddTable(); table.Rows.Alignment = MigraDom.Tables.RowAlignment.Center; table.Borders.Width = 0; table.LeftPadding = 0; table.RightPadding = 0; double colWidth = (A4Width -(2 * SideMarginPDF)) / 3; MigraDom.Tables.Column col1 = table.AddColumn(); col1.Width = MigraDom.Unit.FromMillimeter(colWidth); MigraDom.Tables.Column col2 = table.AddColumn(); col2.Width = MigraDom.Unit.FromMillimeter(colWidth); MigraDom.Tables.Column col3 = table.AddColumn(); col3.Width = MigraDom.Unit.FromMillimeter(colWidth); foreach (TableRowGroup curRowGroup in threeColumnLayout.RowGroups) { foreach(TableRow curRow in curRowGroup.Rows) { MigraDom.Tables.Row row = table.AddRow(); int cellNo = 0; foreach(TableCell tc in curRow.Cells) { foreach (Block curBlock in tc.Blocks) { if (curBlock is Paragraph) { MigraDom.Paragraph para = row.Cells[cellNo].AddParagraph(); this.ProcessParagraph((Paragraph)curBlock, para); } else { } // log the situation (see class remarks above) ? } cellNo++; } } } } private void ProcessTable(Table table, MigraDom.Section section) { // currently no formatting MigraDom.Tables.Table mtable = section.AddTable(); int clmnCount = table.Columns.Count; for (int i = 0; i < clmnCount; i++) { mtable.AddColumn(); } int rowGroupCount = table.RowGroups.Count; for (int rgi = 0; rgi < rowGroupCount; rgi++) { TableRowGroup rg = table.RowGroups[rgi]; int rowsCount = rg.Rows.Count; for (int ri = 0; ri < rowsCount; ri++) { TableRow row = rg.Rows[ri]; MigraDom.Tables.Row mrow = mtable.AddRow(); for (int clmi = 0; clmi < clmnCount; clmi++) { MigraDom.Paragraph mpara = mrow.Cells[clmi].AddParagraph(); BlockCollection curTableCellBlocks = row.Cells[clmi].Blocks; foreach (Block curBlock in curTableCellBlocks) { if (curBlock is Paragraph) { this.ProcessParagraph((Paragraph)curBlock, mpara); } else { } // log the situation (see class remarks above) ? } } } } } private void ProcessBlockUIContainer(BlockUIContainer block, MigraDom.Section section) { if ((block.Child is System.Windows.Controls.Image)) { System.Windows.Controls.Image img = (System.Windows.Controls.Image)block.Child; this.ProcessImageBlock(img, section); } else { } // log the situation (see class remarks above) ? } private string PreprocessImage(System.Windows.Controls.Image img) { try { System.Windows.Media.Imaging.BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage(); bitmapImage = ((System.Windows.Media.Imaging.BitmapImage)img.Source); System.Windows.Media.Imaging.PngBitmapEncoder pngBitmapEncoder = new System.Windows.Media.Imaging.PngBitmapEncoder(); string tempImgPath = FlowDocumentTagManager.GeneratedDocumentsDir + "\\" + "tempImg"; using (System.IO.FileStream stream = new System.IO.FileStream(tempImgPath, System.IO.FileMode.Create)) { pngBitmapEncoder.Interlace = System.Windows.Media.Imaging.PngInterlaceOption.On; pngBitmapEncoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bitmapImage)); pngBitmapEncoder.Save(stream); stream.Flush(); stream.Close(); } return tempImgPath; } catch (Exception) { return null; } } private void ProcessImageBlock(System.Windows.Controls.Image img, MigraDom.Section sec) { string imagePath = this.PreprocessImage(img); if (imagePath != null) { sec.AddImage(imagePath); } else { } // log the situation (see class remarks above) } private void ProcessImageInline(System.Windows.Controls.Image img, MigraDom.Paragraph para) { string imagePath = this.PreprocessImage(img); if (imagePath != null) { para.AddImage(imagePath); } else { } // log the situation (see class remarks above) } } }