Hi Alex,
Thank you for the example. It gets me pretty close.
However when using text files with long text string with no spaces, the text is truncated at the right border of the page.
I think this is happening because the DrawString method will word wrap but not wrap on character.
I was able to get around this by using a System.Drawing font and using the DrawString method that takes a System.Drawing font and the StringFormat enum.
This worked well, except the text does not get added to the page TextRegion. I assume that the reason for this is that I am using a System.Drawing font.
Here is the code I used:
Code: Select all
/// <summary>
/// Converts a text file to a PDF document.
/// </summary>
/// <remarks>This CAN throw.</remarks>
/// <param name="filePath">The full-path to the file to convert.</param>
/// <returns>The full-path to the converted PDF.</returns>
public static string ConvertTextFileToPDF(string filePath)
{
// Path to the created PDF file.
string outputPath = string.Concat(filePath, ".pdf");
//Get text from text file
string text = File.ReadAllText(filePath, System.Text.Encoding.UTF8);
// Set new line to '\n' character
text = text.Replace("\r\n", "\n");
text = text.Replace("\n\r", "\n");
text = text.Replace("\r", "\n");
// Create PDF document
using (PdfDocument pdfDocument = new PdfDocument())
{
do
{
float textMargin = 25f;
PdfPage pdfPage = new PdfPage(pdfDocument, Vintasoft.Imaging.ImageSize.FromPaperKind(Vintasoft.Imaging.PaperSizeKind.Letter));
// Add page to the PDF document
pdfDocument.Pages.Add(pdfPage);
// The DrawString method will not wrap on character when a PDF font is used. Using a System mono space font
// so the DrawString method will wrap on character. The 15.25 em-size is the closest size that emulates the font size we want.
Font font = new Font(FontFamily.GenericMonospace, 15.25f, GraphicsUnit.Pixel);
// Create a brush that should be used for drawing a text
PdfBrush brush = new PdfBrush(Color.Black);
// Create area on document to write the text to.
Vintasoft.Imaging.PaddingF textPadding = new Vintasoft.Imaging.PaddingF(textMargin);
RectangleF rect = pdfPage.MediaBox;
rect = textPadding.ApplyTo(rect);
RectangleF regionRect = pdfPage.TextRegion.Rectangle;
regionRect = textPadding.ApplyTo(regionRect);
// Convert unit size to Pixel size because measuring the text size is done in pixels.
float pageWidthPixels = PdfPage.ConvertFromUserUnitsToUnitOfMeasure(rect.Width, Vintasoft.Imaging.UnitOfMeasure.Pixels);
float pageHeightPixels = PdfPage.ConvertFromUserUnitsToUnitOfMeasure(rect.Height, Vintasoft.Imaging.UnitOfMeasure.Pixels);
// Get PdfGraphics that is associated with PDF page
using (PdfGraphics graphics = PdfGraphics.FromPage(pdfPage))
{
// Get text that must be drawn on current page
string drawnText = GetDrawnText(font, pageWidthPixels, pageHeightPixels, ref text);
// Draw text on the PDF page
graphics.DrawString(drawnText, font, brush, rect, StringFormat.GenericDefault);
}
} while (string.IsNullOrEmpty(text) == false);
pdfDocument.FontManager.PackAllFonts();
//Pack the document. This will also save it to the outputPath.
pdfDocument.Pack(outputPath);
}
return outputPath;
}
/// <summary>
/// Returns the text portion that must be drawn in PDF graphics on the rectangle with specified size.
/// </summary>
/// <param name="font">The text font.</param>
/// <param name="pageWidth">The width of text rectangle.</param>
/// <param name="pageHeight">The height of text rectangle.</param>
/// <param name="text">The text.</param>
/// <returns>The text portion that must be drawn.</returns>
private static string GetDrawnText(Font font, float pageWidth, float pageHeight, ref string text)
{
if (string.IsNullOrEmpty(text))
{
text = "";
return text;
}
float step = text.Length;
float position = text.Length;
int drawnTextLength = text.Length;
string drawnText = text;
int prevTextLength = 0;
// Use System.Drawing.Graphics because it uses GDI+. This will more accurately measure the text length.
using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
graphics.PageUnit = GraphicsUnit.Pixel;
SizeF textSize = graphics.MeasureString(text.Substring(0, drawnTextLength), font, new SizeF(pageWidth, 1500f), StringFormat.GenericDefault);
// If text height is greater than maximum height
if (textSize.Height > pageHeight)
{
// Find drawn text using bisection algorithm
while (drawnTextLength != prevTextLength)
{
step /= 2;
if (textSize.Height > pageHeight)
{
position -= step;
}
else
{
position += step;
}
// Get the adjusted text length and text to compare with the page height.
prevTextLength = drawnTextLength;
drawnTextLength = (int)Math.Ceiling(position);
drawnText = text.Substring(0, drawnTextLength).Trim();
textSize = graphics.MeasureString(drawnText, font, new SizeF(pageWidth, 1500f), StringFormat.GenericDefault);
}
// Fine tune text length to fit in to the page height.
while (textSize.Height > pageHeight)
{
drawnTextLength--;
drawnText = text.Substring(0, drawnTextLength).Trim();
textSize = graphics.MeasureString(drawnText, font, new SizeF(pageWidth, 1500f), StringFormat.GenericDefault);
}
// Add last '\n' character to the drawn text
if (drawnTextLength < text.Length && text[drawnTextLength] == '\n')
{
drawnTextLength++;
}
if (drawnTextLength == 0)
{
drawnTextLength = 1;
drawnText = text.Substring(0, 1);
}
}
}
// Update the remaining text to determine if another page is created by caller.
text = text.Substring(drawnTextLength);
return drawnText;
}
I cannot parse the string and add new line characters to it because the our requirements are that no new line characters are to be added to the text.
Is there a way to use the Drawing method with a PDFFont that will wrap on character?
or
Is there a way to use the Draw method with a System.Drawing font that will add the text to the page TextRegion?
Here is a sample of test text I have been using. You can just copy and paste into a txt file. :
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10ab255
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10ab510
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10ab765
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10a1020
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10a1275
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10a1530
abcdefghijklmnopqrstuvwx1abcdefghijklmnopqrstuvwx2abcdefghijklmnopqrstuvwx3abcdefghijklmnopqrstuvwx4abcdefghijklmnopqrstuvwx5abcdefghijklmnopqrstuvwx6abcdefghijklmnopqrstuvwx7abcdefghijklmnopqrstuvwx8abcdefghijklmnopqrstuvwx9abcdefghijklmnopqrstuvw10a1785