/// <summary> /// Add text at the X Y position; multiple lines handled /// </summary> private void addText(float x, float y, float width, float height, string[] textLines, StyleInfo styleInfo, float[] textWidths, bool wrap, string url, bool noClip, string tooltip) { RenderFont renderFont = RenderUtility.GetRenderFont(styleInfo); BaseFont baseFont = null; //convert the render font type to iTextSharp type int fontType = 0; switch (renderFont.Style) { case RenderFont.FontStyle.Bold: fontType = iTextSharp.text.Font.BOLD; break; case RenderFont.FontStyle.Italic: fontType = iTextSharp.text.Font.ITALIC; break; case RenderFont.FontStyle.BoldItalic: fontType = iTextSharp.text.Font.BOLDITALIC; break; default: fontType = iTextSharp.text.Font.NORMAL; break; } //get the index of the font name in the list font name int indexBaseFont = BaseFontNames.FindIndex(delegate(string _fontname) { return(_fontname == renderFont.FaceName + "_" + fontType); }); //if not found then add the new BaseFont if (indexBaseFont == -1) { //create a new font or a with a new type baseFont = FontFactory.GetFont(renderFont.FaceName, BaseFont.IDENTITY_H, 0, fontType).BaseFont; //add the font face name and font to the lists BaseFontNames.Add(renderFont.FaceName + "_" + fontType); BaseFonts.Add(baseFont); } else { baseFont = BaseFonts[indexBaseFont]; } //text alignment int align = 0; //first position x and y and the leading (usefull for all kind of justified text) float firstStartX = -1; float firstStartY = -1; float leading = -1; //chunks of text List <Chunk> chunks = new List <Chunk>(); //loop thru the lines of text for (int i = 0; i < textLines.Length; i++) { string text = textLines[i]; float textwidth = textWidths[i]; float startX = x + styleInfo.PaddingLeft; // TODO: handle tb_rl float startY = y + styleInfo.PaddingTop + (i * styleInfo.FontSize); // TODO: handle tb_rl if (styleInfo.WritingMode == WritingModeEnum.lr_tb) { //calculate the x position switch (styleInfo.TextAlign) { case TextAlignEnum.Center: if (width > 0) { startX = x + styleInfo.PaddingLeft + (width - styleInfo.PaddingLeft - styleInfo.PaddingRight) / 2 - textwidth / 2; align = Element.ALIGN_CENTER; } break; case TextAlignEnum.Right: if (width > 0) { startX = x + width - textwidth - styleInfo.PaddingRight - 2; align = Element.ALIGN_RIGHT; } break; case TextAlignEnum.Justified: case TextAlignEnum.JustifiedLine: case TextAlignEnum.JustifiedDottedLine: if (width > 0) { startX += 2; align = Element.ALIGN_JUSTIFIED; } break; case TextAlignEnum.Left: default: if (width > 0) { startX += 2; } align = Element.ALIGN_LEFT; break; } //calculate the y position switch (styleInfo.VerticalAlign) { case VerticalAlignEnum.Middle: if (height <= 0) { break; } //calculate the middle of the region startY = y + styleInfo.PaddingTop + (height - styleInfo.PaddingTop - styleInfo.PaddingBottom) / 2 - styleInfo.FontSize / 2; //now go up or down depending on which line if (textLines.Length == 1) { break; } //even number if (textLines.Length % 2 == 0) { startY = startY - ((textLines.Length / 2 - i) * styleInfo.FontSize) + styleInfo.FontSize / 2; } else { startY = startY - ((textLines.Length / 2 - i) * styleInfo.FontSize); } break; case VerticalAlignEnum.Bottom: if (height <= 0) { break; } startY = y + height - styleInfo.PaddingBottom - (styleInfo.FontSize * (textLines.Length - i)); break; case VerticalAlignEnum.Top: default: break; } } else { //move x in a little - it draws to close to the edge of the rectangle (25% of the font size seems to work!) and Center or right align vertical text startX += styleInfo.FontSize / 4; switch (styleInfo.TextAlign) { case TextAlignEnum.Center: if (height > 0) { startY = y + styleInfo.PaddingLeft + (height - styleInfo.PaddingLeft - styleInfo.PaddingRight) / 2 - textwidth / 2; } break; case TextAlignEnum.Right: if (width > 0) { startY = y + height - textwidth - styleInfo.PaddingRight; } break; case TextAlignEnum.Left: default: break; } } //mark the first x position for justify text if (firstStartX == -1) { firstStartX = startX; } //mark the first y position for justify text if (firstStartY == -1) { firstStartY = startY; } //mark the first leading height for justify text else if (leading == -1) { leading = startY - firstStartY; } //draw background rectangle if needed (only put out on the first line, since we do whole rectangle) if (!styleInfo.BackgroundColor.IsEmpty && height > 0 && width > 0 && i == 0) { addFillRectangle(x, y, width, height, styleInfo.BackgroundColor); } //set the clipping path, (Itext have no clip) if (height > 0 && width > 0) { pdfContent.SetRGBColorFill(styleInfo.Color.R, styleInfo.Color.G, styleInfo.Color.B); if (align == Element.ALIGN_JUSTIFIED) { chunks.Add(new Chunk(text)); } else { if (styleInfo.WritingMode == WritingModeEnum.lr_tb) { //if textline after measure with word break can fit just simple show Text if (width >= textwidth) { pdfContent.SaveState(); pdfContent.BeginText(); pdfContent.SetFontAndSize(baseFont, styleInfo.FontSize); //same fonts dont have nativelly bold so we could simulate that if (renderFont.SimulateBold) { pdfContent.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE); pdfContent.SetLineWidth(0.2f); } pdfContent.SetTextMatrix(startX, pageHeight - startY - styleInfo.FontSize); pdfContent.ShowText(text); pdfContent.EndText(); pdfContent.RestoreState(); } else { //else use Column text to wrap or clip (wrap: for example a text like an URL so word break is not working here //itextsharp ColumnText do the work for us) ColumnText columnText = new ColumnText(pdfContent); columnText.SetSimpleColumn(new Phrase(text, new iTextSharp.text.Font(baseFont, styleInfo.FontSize)), x + styleInfo.PaddingLeft, pageHeight - startY, x + width - styleInfo.PaddingRight, pageHeight - y - styleInfo.PaddingBottom - height, 10f, align); columnText.Go(); } } else { //not checked double rads = -283.0 / 180.0; double radsCos = Math.Cos(rads); double radsSin = Math.Sin(rads); pdfContent.BeginText(); pdfContent.SetFontAndSize(baseFont, styleInfo.FontSize); pdfContent.SetTextMatrix((float)radsCos, (float)radsSin, (float)-radsSin, (float)radsCos, startX, pageHeight - startY); pdfContent.ShowText(text); pdfContent.EndText(); } } //add URL if (url != null) { document.Add(new Annotation(x, pageHeight - y, height, width, url)); } //add tooltip if (tooltip != null) { document.Add(new Annotation(x, pageHeight - y, height, width, tooltip)); } } //handle underlining etc ... float maxX; switch (styleInfo.TextDecoration) { case TextDecorationEnum.Underline: maxX = width > 0 ? Math.Min(x + width, startX + textwidth) : startX + textwidth; addLine(startX, startY + styleInfo.FontSize + 1, maxX, startY + styleInfo.FontSize + 1, 1, styleInfo.Color, BorderStyleEnum.Solid); break; case TextDecorationEnum.LineThrough: maxX = width > 0 ? Math.Min(x + width, startX + textwidth) : startX + textwidth; addLine(startX, startY + (styleInfo.FontSize / 2) + 1, maxX, startY + (styleInfo.FontSize / 2) + 1, 1, styleInfo.Color, BorderStyleEnum.Solid); break; case TextDecorationEnum.Overline: maxX = width > 0 ? Math.Min(x + width, startX + textwidth) : startX + textwidth; addLine(startX, startY + 1, maxX, startY + 1, 1, styleInfo.Color, BorderStyleEnum.Solid); break; case TextDecorationEnum.None: default: break; } } //add text to justify if (chunks.Count > 0) { Paragraph paragraph = new Paragraph(); paragraph.Alignment = align; paragraph.Leading = leading; paragraph.Font = new iTextSharp.text.Font(baseFont, styleInfo.FontSize); //join all text (is necessary to justify alignment) foreach (Chunk chunk in chunks) { paragraph.Add(chunk); } //add separator for kind of justified alignments if (styleInfo.TextAlign == TextAlignEnum.JustifiedLine) { iTextSharp.text.pdf.draw.LineSeparator lineSeparator = new iTextSharp.text.pdf.draw.LineSeparator(); lineSeparator.Offset = 3f; lineSeparator.LineColor = new BaseColor(styleInfo.Color); paragraph.Add(new Chunk(lineSeparator)); } else if (styleInfo.TextAlign == TextAlignEnum.JustifiedDottedLine) { iTextSharp.text.pdf.draw.DottedLineSeparator dottedLineSeparator = new iTextSharp.text.pdf.draw.DottedLineSeparator(); dottedLineSeparator.Offset = 3f; dottedLineSeparator.LineColor = new BaseColor(styleInfo.Color); paragraph.Add(new Chunk(dottedLineSeparator)); } ColumnText columnText = new ColumnText(pdfContent); //start from the top of the column columnText.UseAscender = true; //width, y position from the bottom page (compensate 2 units), x position, 0 columnText.SetSimpleColumn(firstStartX, pageHeight - firstStartY - 2, firstStartX + width - styleInfo.PaddingRight, 0); columnText.AddElement(paragraph); columnText.Go(); } //add any required border addBorder(styleInfo, x, y, width, height); }
/// <summary> /// Render all the objects in a page /// </summary> private void processPage(Pages pages, IEnumerable page) { //loop thru the items in the page foreach (PageItem pageItem in page) { if (pageItem.SI.BackgroundImage != null) { //put out any background image PageImage backgroundImage = pageItem.SI.BackgroundImage; float imageWidth = RSize.PointsFromPixels(pages.G, backgroundImage.SamplesW); float imageHeight = RSize.PointsFromPixels(pages.G, backgroundImage.SamplesH); int repeatX = 0; int repeatY = 0; float itemWidth = pageItem.W - (pageItem.SI.PaddingLeft + pageItem.SI.PaddingRight); float itemHeight = pageItem.H - (pageItem.SI.PaddingTop + pageItem.SI.PaddingBottom); switch (backgroundImage.Repeat) { case ImageRepeat.Repeat: repeatX = (int)Math.Floor(itemWidth / imageWidth); repeatY = (int)Math.Floor(itemHeight / imageHeight); break; case ImageRepeat.RepeatX: repeatX = (int)Math.Floor(itemWidth / imageWidth); repeatY = 1; break; case ImageRepeat.RepeatY: repeatY = (int)Math.Floor(itemHeight / imageHeight); repeatX = 1; break; case ImageRepeat.NoRepeat: default: repeatX = repeatY = 1; break; } //make sure the image is drawn at least 1 times repeatX = Math.Max(repeatX, 1); repeatY = Math.Max(repeatY, 1); float currX = pageItem.X + pageItem.SI.PaddingLeft; float currY = pageItem.Y + pageItem.SI.PaddingTop; float startX = currX; float startY = currY; for (int i = 0; i < repeatX; i++) { for (int j = 0; j < repeatY; j++) { currX = startX + i * imageWidth; currY = startY + j * imageHeight; addImage(backgroundImage.SI, currX, currY, imageWidth, imageHeight, RectangleF.Empty, backgroundImage.ImageData, null, pageItem.Tooltip); } } } else if (pageItem is PageTextHtml) { PageTextHtml pageTextHtml = pageItem as PageTextHtml; pageTextHtml.Build(pages.G); processPage(pages, pageTextHtml); continue; } else if (pageItem is PageText) { PageText pageText = pageItem as PageText; float[] textwidth; string[] measureStrings = RenderUtility.MeasureString(pageText, pages.G, out textwidth); addText(pageText.X, pageText.Y, pageText.W, pageText.H, measureStrings, pageText.SI, textwidth, pageText.CanGrow, pageText.HyperLink, pageText.NoClip, pageText.Tooltip); continue; } else if (pageItem is PageLine) { PageLine pageLine = pageItem as PageLine; addLine(pageLine.X, pageLine.Y, pageLine.X2, pageLine.Y2, pageLine.SI); continue; } else if (pageItem is PageEllipse) { PageEllipse pageEllipse = pageItem as PageEllipse; addEllipse(pageEllipse.X, pageEllipse.Y, pageEllipse.W, pageEllipse.H, pageEllipse.SI, pageEllipse.HyperLink); continue; } else if (pageItem is PageImage) { PageImage pageImage = pageItem as PageImage; //Duc Phan added 20 Dec, 2007 to support sized image RectangleF r2 = new RectangleF(pageImage.X + pageImage.SI.PaddingLeft, pageImage.Y + pageImage.SI.PaddingTop, pageImage.W - pageImage.SI.PaddingLeft - pageImage.SI.PaddingRight, pageImage.H - pageImage.SI.PaddingTop - pageImage.SI.PaddingBottom); //work rectangle RectangleF adjustedRect; RectangleF clipRect = RectangleF.Empty; switch (pageImage.Sizing) { case ImageSizingEnum.AutoSize: adjustedRect = new RectangleF(r2.Left, r2.Top, r2.Width, r2.Height); break; case ImageSizingEnum.Clip: adjustedRect = new RectangleF(r2.Left, r2.Top, RSize.PointsFromPixels(pages.G, pageImage.SamplesW), RSize.PointsFromPixels(pages.G, pageImage.SamplesH)); clipRect = new RectangleF(r2.Left, r2.Top, r2.Width, r2.Height); break; case ImageSizingEnum.FitProportional: float height; float width; float ratioIm = (float)pageImage.SamplesH / pageImage.SamplesW; float ratioR = r2.Height / r2.Width; height = r2.Height; width = r2.Width; if (ratioIm > ratioR) { //this means the rectangle width must be corrected width = height * (1 / ratioIm); } else if (ratioIm < ratioR) { //this means the rectangle height must be corrected height = width * ratioIm; } adjustedRect = new RectangleF(r2.X, r2.Y, width, height); break; case ImageSizingEnum.Fit: default: adjustedRect = r2; break; } if (pageImage.ImgFormat != System.Drawing.Imaging.ImageFormat.Wmf && pageImage.ImgFormat != System.Drawing.Imaging.ImageFormat.Emf) { addImage(pageImage.SI, adjustedRect.X, adjustedRect.Y, adjustedRect.Width, adjustedRect.Height, clipRect, pageImage.ImageData, pageImage.HyperLink, pageImage.Tooltip); } continue; } else if (pageItem is PageRectangle) { PageRectangle pageRectangle = pageItem as PageRectangle; addRectangle(pageRectangle.X, pageRectangle.Y, pageRectangle.W, pageRectangle.H, pageItem.SI, pageItem.HyperLink, pageItem.Tooltip); continue; } else if (pageItem is PagePie) { PagePie pagePie = pageItem as PagePie; addPie(pagePie.X, pagePie.Y, pagePie.W, pagePie.H, pageItem.SI, pageItem.HyperLink, pageItem.Tooltip); continue; } else if (pageItem is PagePolygon) { PagePolygon pagePolygon = pageItem as PagePolygon; addPolygon(pagePolygon.Points, pageItem.SI, pageItem.HyperLink); continue; } else if (pageItem is PageCurve) { PageCurve pageCurve = pageItem as PageCurve; addCurve(pageCurve.Points, pageItem.SI); continue; } } }