/** * Replaces the current text array with this <CODE>Phrase</CODE>. * Anything added previously with AddElement() is lost. * @param phrase the text */ public void SetText(Phrase phrase) { bidiLine = null; composite = false; compositeColumn = null; compositeElements = null; listIdx = 0; splittedRow = false; waitPhrase = phrase; }
/** Shows a line of text. Only the first line is written. * @param canvas where the text is to be written to * @param alignment the alignment. It is not influenced by the run direction * @param phrase the <CODE>Phrase</CODE> with the text * @param x the x reference position * @param y the y reference position * @param rotation the rotation to be applied in degrees counterclockwise * @param runDirection the run direction * @param arabicOptions the options for the arabic shaping */ public static void ShowTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation, int runDirection, int arabicOptions) { if (alignment != Element.ALIGN_LEFT && alignment != Element.ALIGN_CENTER && alignment != Element.ALIGN_RIGHT) alignment = Element.ALIGN_LEFT; canvas.SaveState(); ColumnText ct = new ColumnText(canvas); float lly = -1; float ury = 2; float llx; float urx; switch (alignment) { case Element.ALIGN_LEFT: llx = 0; urx = 20000; break; case Element.ALIGN_RIGHT: llx = -20000; urx = 0; break; default: llx = -20000; urx = 20000; break; } if (rotation == 0) { llx += x; lly += y; urx += x; ury += y; } else { double alpha = rotation * Math.PI / 180.0; float cos = (float)Math.Cos(alpha); float sin = (float)Math.Sin(alpha); canvas.ConcatCTM(cos, sin, -sin, cos, x, y); } ct.SetSimpleColumn(phrase, llx, lly, urx, ury, 2, alignment); if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { if (alignment == Element.ALIGN_LEFT) alignment = Element.ALIGN_RIGHT; else if (alignment == Element.ALIGN_RIGHT) alignment = Element.ALIGN_LEFT; } ct.Alignment = alignment; ct.ArabicOptions = arabicOptions; ct.RunDirection = runDirection; ct.Go(); canvas.RestoreState(); }
/** Makes this instance an independent copy of <CODE>org</CODE>. * @param org the original <CODE>ColumnText</CODE> * @return itself */ public ColumnText SetACopy(ColumnText org) { SetSimpleVars(org); if (org.bidiLine != null) bidiLine = new BidiLine(org.bidiLine); return this; }
/** Creates an independent duplicated of the instance <CODE>org</CODE>. * @param org the original <CODE>ColumnText</CODE> * @return the duplicated */ public static ColumnText Duplicate(ColumnText org) { ColumnText ct = new ColumnText(null); ct.SetACopy(org); return ct; }
/** Gets the width that the line will occupy after writing. * Only the width of the first line is returned. * @param phrase the <CODE>Phrase</CODE> containing the line * @param runDirection the run direction * @param arabicOptions the options for the arabic shaping * @return the width of the line */ public static float GetWidth(Phrase phrase, int runDirection, int arabicOptions) { ColumnText ct = new ColumnText(null); ct.AddText(phrase); ct.AddWaitingPhrase(); PdfLine line = ct.bidiLine.ProcessLine(0, 20000, Element.ALIGN_LEFT, runDirection, arabicOptions); if (line == null) return 0; else return 20000 - line.WidthLeft; }
protected internal void SetSimpleVars(ColumnText org) { maxY = org.maxY; minY = org.minY; alignment = org.alignment; leftWall = null; if (org.leftWall != null) leftWall = new ArrayList(org.leftWall); rightWall = null; if (org.rightWall != null) rightWall = new ArrayList(org.rightWall); yLine = org.yLine; currentLeading = org.currentLeading; fixedLeading = org.fixedLeading; multipliedLeading = org.multipliedLeading; canvas = org.canvas; canvases = org.canvases; lineStatus = org.lineStatus; indent = org.indent; followingIndent = org.followingIndent; rightIndent = org.rightIndent; extraParagraphSpace = org.extraParagraphSpace; rectangularWidth = org.rectangularWidth; rectangularMode = org.rectangularMode; spaceCharRatio = org.spaceCharRatio; lastWasNewline = org.lastWasNewline; linesWritten = org.linesWritten; arabicOptions = org.arabicOptions; runDirection = org.runDirection; descender = org.descender; composite = org.composite; splittedRow = org.splittedRow; if (org.composite) { compositeElements = new ArrayList(org.compositeElements); if (splittedRow) { PdfPTable table = (PdfPTable)compositeElements[0]; compositeElements[0] = new PdfPTable(table); } if (org.compositeColumn != null) compositeColumn = Duplicate(org.compositeColumn); } listIdx = org.listIdx; firstLineY = org.firstLineY; leftX = org.leftX; rightX = org.rightX; firstLineYDone = org.firstLineYDone; waitPhrase = org.waitPhrase; useAscender = org.useAscender; filledWidth = org.filledWidth; adjustFirstLine = org.adjustFirstLine; }
protected int GoComposite(bool simulate) { if (!rectangularMode) throw new DocumentException("Irregular columns are not supported in composite mode."); linesWritten = 0; descender = 0; bool firstPass = adjustFirstLine; main_loop: while (true) { if (compositeElements.Count == 0) return NO_MORE_TEXT; IElement element = (IElement)compositeElements[0]; if (element.Type == Element.PARAGRAPH) { Paragraph para = (Paragraph)element; int status = 0; for (int keep = 0; keep < 2; ++keep) { float lastY = yLine; bool createHere = false; if (compositeColumn == null) { compositeColumn = new ColumnText(canvas); compositeColumn.UseAscender = (firstPass ? useAscender : false); compositeColumn.Alignment = para.Alignment; compositeColumn.Indent = para.IndentationLeft + para.FirstLineIndent; compositeColumn.ExtraParagraphSpace = para.ExtraParagraphSpace; compositeColumn.FollowingIndent = para.IndentationLeft; compositeColumn.RightIndent = para.IndentationRight; compositeColumn.SetLeading(para.Leading, para.MultipliedLeading); compositeColumn.RunDirection = runDirection; compositeColumn.ArabicOptions = arabicOptions; compositeColumn.SpaceCharRatio = spaceCharRatio; compositeColumn.AddText(para); if (!firstPass) { yLine -= para.SpacingBefore; } createHere = true; } compositeColumn.leftX = leftX; compositeColumn.rightX = rightX; compositeColumn.yLine = yLine; compositeColumn.rectangularWidth = rectangularWidth; compositeColumn.rectangularMode = rectangularMode; compositeColumn.minY = minY; compositeColumn.maxY = maxY; bool keepCandidate = (para.KeepTogether && createHere && !firstPass); status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); UpdateFilledWidth(compositeColumn.filledWidth); if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { compositeColumn = null; yLine = lastY; return NO_MORE_COLUMN; } if (simulate || !keepCandidate) break; if (keep == 0) { compositeColumn = null; yLine = lastY; } } firstPass = false; yLine = compositeColumn.yLine; linesWritten += compositeColumn.linesWritten; descender = compositeColumn.descender; if ((status & NO_MORE_TEXT) != 0) { compositeColumn = null; compositeElements.RemoveAt(0); yLine -= para.SpacingAfter; } if ((status & NO_MORE_COLUMN) != 0) { return NO_MORE_COLUMN; } } else if (element.Type == Element.LIST) { List list = (List)element; ArrayList items = list.Items; ListItem item = null; float listIndentation = list.IndentationLeft; int count = 0; Stack stack = new Stack(); for (int k = 0; k < items.Count; ++k) { Object obj = items[k]; if (obj is ListItem) { if (count == listIdx) { item = (ListItem)obj; break; } else ++count; } else if (obj is List) { stack.Push(new Object[]{list, k, listIndentation}); list = (List)obj; items = list.Items; listIndentation += list.IndentationLeft; k = -1; continue; } if (k == items.Count - 1) { if (stack.Count > 0) { Object[] objs = (Object[])stack.Pop(); list = (List)objs[0]; items = list.Items; k = (int)objs[1]; listIndentation = (float)objs[2]; } } } int status = 0; for (int keep = 0; keep < 2; ++keep) { float lastY = yLine; bool createHere = false; if (compositeColumn == null) { if (item == null) { listIdx = 0; compositeElements.RemoveAt(0); goto main_loop; } compositeColumn = new ColumnText(canvas); compositeColumn.UseAscender = (firstPass ? useAscender : false); compositeColumn.Alignment = item.Alignment; compositeColumn.Indent = item.IndentationLeft + listIndentation + item.FirstLineIndent; compositeColumn.ExtraParagraphSpace = item.ExtraParagraphSpace; compositeColumn.FollowingIndent = compositeColumn.Indent; compositeColumn.RightIndent = item.IndentationRight + list.IndentationRight; compositeColumn.SetLeading(item.Leading, item.MultipliedLeading); compositeColumn.RunDirection = runDirection; compositeColumn.ArabicOptions = arabicOptions; compositeColumn.SpaceCharRatio = spaceCharRatio; compositeColumn.AddText(item); if (!firstPass) { yLine -= item.SpacingBefore; } createHere = true; } compositeColumn.leftX = leftX; compositeColumn.rightX = rightX; compositeColumn.yLine = yLine; compositeColumn.rectangularWidth = rectangularWidth; compositeColumn.rectangularMode = rectangularMode; compositeColumn.minY = minY; compositeColumn.maxY = maxY; bool keepCandidate = (item.KeepTogether && createHere && !firstPass); status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); UpdateFilledWidth(compositeColumn.filledWidth); if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { compositeColumn = null; yLine = lastY; return NO_MORE_COLUMN; } if (simulate || !keepCandidate) break; if (keep == 0) { compositeColumn = null; yLine = lastY; } } firstPass = false; yLine = compositeColumn.yLine; linesWritten += compositeColumn.linesWritten; descender = compositeColumn.descender; if (!float.IsNaN(compositeColumn.firstLineY) && !compositeColumn.firstLineYDone) { if (!simulate) ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(item.ListSymbol), compositeColumn.leftX + listIndentation, compositeColumn.firstLineY, 0); compositeColumn.firstLineYDone = true; } if ((status & NO_MORE_TEXT) != 0) { compositeColumn = null; ++listIdx; yLine -= item.SpacingAfter; } if ((status & NO_MORE_COLUMN) != 0) { return NO_MORE_COLUMN; } } else if (element.Type == Element.PTABLE) { // don't write anything in the current column if there's no more space available if (yLine < minY || yLine > maxY) return NO_MORE_COLUMN; // get the PdfPTable element PdfPTable table = (PdfPTable)element; // we ignore tables without a body if (table.Size <= table.HeaderRows) { compositeElements.RemoveAt(0); continue; } // offsets float yTemp = yLine; if (!firstPass && listIdx == 0) { yTemp -= table.SpacingBefore; } float yLineWrite = yTemp; // don't write anything in the current column if there's no more space available if (yTemp < minY || yTemp > maxY) { return NO_MORE_COLUMN; } // coordinates currentLeading = 0; float x1 = leftX; float tableWidth; if (table.LockedWidth) { tableWidth = table.TotalWidth; UpdateFilledWidth(tableWidth); } else { tableWidth = rectangularWidth * table.WidthPercentage / 100f; table.TotalWidth = tableWidth; } // how many header rows are real header rows; how many are footer rows? int headerRows = table.HeaderRows; int footerRows = table.FooterRows; if (footerRows > headerRows) footerRows = headerRows; int realHeaderRows = headerRows - footerRows; float headerHeight = table.HeaderHeight; float footerHeight = table.FooterHeight; // make sure the header and footer fit on the page bool skipHeader = (!firstPass && table.SkipFirstHeader && listIdx <= headerRows); if (!skipHeader) { yTemp -= headerHeight; if (yTemp < minY || yTemp > maxY) { if (firstPass) { compositeElements.RemoveAt(0); continue; } return NO_MORE_COLUMN; } } // how many real rows (not header or footer rows) fit on a page? int k; if (listIdx < headerRows) { listIdx = headerRows; } if (!table.ElementComplete) { yTemp -= footerHeight; } for (k = listIdx; k < table.Size; ++k) { float rowHeight = table.GetRowHeight(k); if (yTemp - rowHeight < minY) break; yTemp -= rowHeight; } if (!table.ElementComplete) { yTemp += footerHeight; } // either k is the first row that doesn't fit on the page (break); if (k < table.Size) { if (table.SplitRows && (!table.SplitLate || (k == listIdx && firstPass))) { if (!splittedRow) { splittedRow = true; table = new PdfPTable(table); compositeElements[0] = table; ArrayList rows = table.Rows; for (int i = headerRows; i < listIdx; ++i) rows[i] = null; } float h = yTemp - minY; PdfPRow newRow = table.GetRow(k).SplitRow(table, k, h); if (newRow == null) { if (k == listIdx) { return NO_MORE_COLUMN; } } else { yTemp = minY; table.Rows.Insert(++k, newRow); } } else if (!table.SplitRows && k == listIdx && firstPass) { compositeElements.RemoveAt(0); splittedRow = false; continue; } else if (k == listIdx && !firstPass && (!table.SplitRows || table.SplitLate) && (table.FooterRows == 0 || table.ElementComplete)) { return NO_MORE_COLUMN; } } // or k is the number of rows in the table (for loop was done). firstPass = false; // we draw the table (for real now) if (!simulate) { // set the alignment switch (table.HorizontalAlignment) { case Element.ALIGN_LEFT: break; case Element.ALIGN_RIGHT: x1 += rectangularWidth - tableWidth; break; default: x1 += (rectangularWidth - tableWidth) / 2f; break; } // copy the rows that fit on the page in a new table nt PdfPTable nt = PdfPTable.ShallowCopy(table); ArrayList sub = nt.Rows; // first we add the real header rows (if necessary) if (!skipHeader) { for (int j = 0; j < realHeaderRows; ++j) { PdfPRow headerRow = table.GetRow(j); sub.Add(headerRow); } } else { nt.HeaderRows = footerRows; } // then we add the real content sub.AddRange(table.GetRows(listIdx, k)); // if k < table.size(), we must indicate that the new table is complete; // otherwise no footers will be added (because iText thinks the table continues on the same page) bool showFooter = !table.SkipLastFooter; if (k < table.Size) { nt.ElementComplete = true; showFooter = true; } // we add the footer rows if necessary (not for incomplete tables) for (int j = 0; j < footerRows && nt.ElementComplete && showFooter; ++j) { sub.Add(table.GetRow(j + realHeaderRows)); } // we need a correction if the last row needs to be extended float rowHeight = 0; PdfPRow last = (PdfPRow)sub[sub.Count - 1 - footerRows]; if (table.ExtendLastRow) { rowHeight = last.MaxHeights; last.MaxHeights = yTemp - minY + rowHeight; yTemp = minY; } // now we render the rows of the new table if (canvases != null) nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvases); else nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvas); if (table.ExtendLastRow) { last.MaxHeights = rowHeight; } } else if (table.ExtendLastRow && minY > PdfPRow.BOTTOM_LIMIT) { yTemp = minY; } yLine = yTemp; if (!(skipHeader || table.ElementComplete)) { yLine += footerHeight; } if (k >= table.Size) { yLine -= table.SpacingAfter; compositeElements.RemoveAt(0); splittedRow = false; listIdx = 0; } else { if (splittedRow) { ArrayList rows = table.Rows; for (int i = listIdx; i < k; ++i) rows[i] = null; } listIdx = k; return NO_MORE_COLUMN; } } else if (element.Type == Element.YMARK) { if (!simulate) { IDrawInterface zh = (IDrawInterface)element; zh.Draw(canvas, leftX, minY, rightX, maxY, yLine); } compositeElements.RemoveAt(0); } else compositeElements.RemoveAt(0); } }
/** * Get the <code>PdfAppearance</code> of a text or combo field * @throws IOException on error * @throws DocumentException on error * @return A <code>PdfAppearance</code> */ public PdfAppearance GetAppearance() { PdfAppearance app = GetBorderAppearance(); app.BeginVariableText(); if (text == null || text.Length == 0) { app.EndVariableText(); return app; } bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; float h = box.Height - borderWidth * 2 - extraMarginTop; float bw2 = borderWidth; if (borderExtra) { h -= borderWidth * 2; bw2 *= 2; } float offsetX = Math.Max(bw2, 1); float offX = Math.Min(bw2, offsetX); app.SaveState(); app.Rectangle(offX, offX, box.Width - 2 * offX, box.Height - 2 * offX); app.Clip(); app.NewPath(); String ptext; if ((options & PASSWORD) != 0) ptext = ObfuscatePassword(text); else if ((options & MULTILINE) == 0) ptext = RemoveCRLF(text); else ptext = text; //fixed by Kazuya Ujihara (ujihara.jp) BaseFont ufont = RealFont; Color fcolor = (textColor == null) ? GrayColor.GRAYBLACK : textColor; int rtl = CheckRTL(ptext) ? PdfWriter.RUN_DIRECTION_LTR : PdfWriter.RUN_DIRECTION_NO_BIDI; float usize = fontSize; Phrase phrase = ComposePhrase(ptext, ufont, fcolor, usize); if ((options & MULTILINE) != 0) { float width = box.Width - 4 * offsetX - extraMarginLeft; float factor = ufont.GetFontDescriptor(BaseFont.BBOXURY, 1) - ufont.GetFontDescriptor(BaseFont.BBOXLLY, 1); ColumnText ct = new ColumnText(null); if (usize == 0) { usize = h / factor; if (usize > 4) { if (usize > 12) usize = 12; float step = Math.Max((usize - 4) / 10, 0.2f); ct.SetSimpleColumn(0, -h, width, 0); ct.Alignment = alignment; ct.RunDirection = rtl; for (; usize > 4; usize -= step) { ct.YLine = 0; ChangeFontSize(phrase, usize); ct.SetText(phrase); ct.Leading = factor * usize; int status = ct.Go(true); if ((status & ColumnText.NO_MORE_COLUMN) == 0) break; } } if (usize < 4) { usize = 4; } } ChangeFontSize(phrase, usize); ct.Canvas = app; float leading = usize * factor; float offsetY = offsetX + h - ufont.GetFontDescriptor(BaseFont.BBOXURY, usize); ct.SetSimpleColumn(extraMarginLeft + 2 * offsetX, -20000, box.Width - 2 * offsetX, offsetY + leading); ct.Leading = leading; ct.Alignment = alignment; ct.RunDirection = rtl; ct.SetText(phrase); ct.Go(); } else { if (usize == 0) { float maxCalculatedSize = h / (ufont.GetFontDescriptor(BaseFont.BBOXURX, 1) - ufont.GetFontDescriptor(BaseFont.BBOXLLY, 1)); ChangeFontSize(phrase, 1); float wd = ColumnText.GetWidth(phrase, rtl, 0); if (wd == 0) usize = maxCalculatedSize; else usize = Math.Min(maxCalculatedSize, (box.Width - extraMarginLeft - 4 * offsetX) / wd); if (usize < 4) usize = 4; } ChangeFontSize(phrase, usize); float offsetY = offX + ((box.Height - 2*offX) - ufont.GetFontDescriptor(BaseFont.ASCENT, usize)) / 2; if (offsetY < offX) offsetY = offX; if (offsetY - offX < -ufont.GetFontDescriptor(BaseFont.DESCENT, usize)) { float ny = -ufont.GetFontDescriptor(BaseFont.DESCENT, usize) + offX; float dy = box.Height - offX - ufont.GetFontDescriptor(BaseFont.ASCENT, usize); offsetY = Math.Min(ny, Math.Max(offsetY, dy)); } if ((options & COMB) != 0 && maxCharacterLength > 0) { int textLen = Math.Min(maxCharacterLength, ptext.Length); int position = 0; if (alignment == Element.ALIGN_RIGHT) { position = maxCharacterLength - textLen; } else if (alignment == Element.ALIGN_CENTER) { position = (maxCharacterLength - textLen) / 2; } float step = (box.Width - extraMarginLeft) / maxCharacterLength; float start = step / 2 + position * step; if (textColor == null) app.SetGrayFill(0); else app.SetColorFill(textColor); app.BeginText(); foreach (Chunk ck in phrase) { BaseFont bf = ck.Font.BaseFont; app.SetFontAndSize(bf, usize); StringBuilder sb = ck.Append(""); for (int j = 0; j < sb.Length; ++j) { String c = sb.ToString(j, 1); float wd = bf.GetWidthPoint(c, usize); app.SetTextMatrix(extraMarginLeft + start - wd / 2, offsetY - extraMarginTop); app.ShowText(c); start += step; } } app.EndText(); } else { float x; switch (alignment) { case Element.ALIGN_RIGHT: x = extraMarginLeft + box.Width - (2 * offsetX); break; case Element.ALIGN_CENTER: x = extraMarginLeft + (box.Width / 2); break; default: x = extraMarginLeft + (2 * offsetX); break; } ColumnText.ShowTextAligned(app, alignment, phrase, x, offsetY - extraMarginTop, 0, rtl, 0); } } app.RestoreState(); app.EndVariableText(); return app; }
/** Constructs a deep copy of a <CODE>PdfPCell</CODE>. * @param cell the <CODE>PdfPCell</CODE> to duplicate */ public PdfPCell(PdfPCell cell) : base(cell.llx, cell.lly, cell.urx, cell.ury) { CloneNonPositionParameters(cell); verticalAlignment = cell.verticalAlignment; paddingLeft = cell.paddingLeft; paddingRight = cell.paddingRight; paddingTop = cell.paddingTop; paddingBottom = cell.paddingBottom; phrase = cell.phrase; fixedHeight = cell.fixedHeight; minimumHeight = cell.minimumHeight; noWrap = cell.noWrap; colspan = cell.colspan; rowspan = cell.rowspan; if (cell.table != null) table = new PdfPTable(cell.table); image = Image.GetInstance(cell.image); cellEvent = cell.cellEvent; useDescender = cell.useDescender; column = ColumnText.Duplicate(cell.column); useBorderPadding = cell.useBorderPadding; rotation = cell.rotation; }
/** * Fits the text to some rectangle adjusting the font size as needed. * @param font the font to use * @param text the text * @param rect the rectangle where the text must fit * @param maxFontSize the maximum font size * @param runDirection the run direction * @return the calculated font size that makes the text fit */ public static float FitText(Font font, String text, Rectangle rect, float maxFontSize, int runDirection) { ColumnText ct = null; int status = 0; if (maxFontSize <= 0) { int cr = 0; int lf = 0; char[] t = text.ToCharArray(); for (int k = 0; k < t.Length; ++k) { if (t[k] == '\n') ++lf; else if (t[k] == '\r') ++cr; } int minLines = Math.Max(cr, lf) + 1; maxFontSize = Math.Abs(rect.Height) / minLines - 0.001f; } font.Size = maxFontSize; Phrase ph = new Phrase(text, font); ct = new ColumnText(null); ct.SetSimpleColumn(ph, rect.Left, rect.Bottom, rect.Right, rect.Top, maxFontSize, Element.ALIGN_LEFT); ct.RunDirection = runDirection; status = ct.Go(true); if ((status & ColumnText.NO_MORE_TEXT) != 0) return maxFontSize; float precision = 0.1f; float min = 0; float max = maxFontSize; float size = maxFontSize; for (int k = 0; k < 50; ++k) { //just in case it doesn't converge size = (min + max) / 2; ct = new ColumnText(null); font.Size = size; ct.SetSimpleColumn(new Phrase(text, font), rect.Left, rect.Bottom, rect.Right, rect.Top, size, Element.ALIGN_LEFT); ct.RunDirection = runDirection; status = ct.Go(true); if ((status & ColumnText.NO_MORE_TEXT) != 0) { if (max - min < size * precision) return size; min = size; } else max = size; } return size; }
/** * Gets the main appearance layer. * <p> * Consult <A HREF="http://partners.adobe.com/asn/developer/pdfs/tn/PPKAppearances.pdf">PPKAppearances.pdf</A> * for further details. * @return the main appearance layer * @throws DocumentException on error * @throws IOException on error */ public PdfTemplate GetAppearance() { if (IsInvisible()) { PdfTemplate t = new PdfTemplate(writer); t.BoundingBox = new Rectangle(0, 0); writer.AddDirectTemplateSimple(t, null); return t; } if (app[0] == null) { PdfTemplate t = app[0] = new PdfTemplate(writer); t.BoundingBox = new Rectangle(100, 100); writer.AddDirectTemplateSimple(t, new PdfName("n0")); t.SetLiteral("% DSBlank\n"); } if (app[1] == null && !acro6Layers) { PdfTemplate t = app[1] = new PdfTemplate(writer); t.BoundingBox = new Rectangle(100, 100); writer.AddDirectTemplateSimple(t, new PdfName("n1")); t.SetLiteral(questionMark); } if (app[2] == null) { String text; if (layer2Text == null) { StringBuilder buf = new StringBuilder(); buf.Append("Digitally signed by ").Append(PdfPKCS7.GetSubjectFields((X509Certificate)certChain[0]).GetField("CN")).Append('\n'); buf.Append("Date: ").Append(signDate.ToString("yyyy.MM.dd HH:mm:ss zzz")); if (reason != null) buf.Append('\n').Append("Reason: ").Append(reason); if (location != null) buf.Append('\n').Append("Location: ").Append(location); text = buf.ToString(); } else text = layer2Text; PdfTemplate t = app[2] = new PdfTemplate(writer); t.BoundingBox = rect; writer.AddDirectTemplateSimple(t, new PdfName("n2")); if (image != null) { if (imageScale == 0) { t.AddImage(image, rect.Width, 0, 0, rect.Height, 0, 0); } else { float usableScale = imageScale; if (imageScale < 0) usableScale = Math.Min(rect.Width / image.Width, rect.Height / image.Height); float w = image.Width * usableScale; float h = image.Height * usableScale; float x = (rect.Width - w) / 2; float y = (rect.Height - h) / 2; t.AddImage(image, w, 0, 0, h, x, y); } } Font font; if (layer2Font == null) font = new Font(); else font = new Font(layer2Font); float size = font.Size; Rectangle dataRect = null; Rectangle signatureRect = null; if (Render == SignatureRender.NameAndDescription || (Render == SignatureRender.GraphicAndDescription && this.SignatureGraphic != null)) { // origin is the bottom-left signatureRect = new Rectangle( MARGIN, MARGIN, rect.Width / 2 - MARGIN, rect.Height - MARGIN); dataRect = new Rectangle( rect.Width / 2 + MARGIN / 2, MARGIN, rect.Width - MARGIN / 2, rect.Height - MARGIN); if (rect.Height > rect.Width) { signatureRect = new Rectangle( MARGIN, rect.Height / 2, rect.Width - MARGIN, rect.Height); dataRect = new Rectangle( MARGIN, MARGIN, rect.Width - MARGIN, rect.Height / 2 - MARGIN); } } else { dataRect = new Rectangle( MARGIN, MARGIN, rect.Width - MARGIN, rect.Height * (1 - TOP_SECTION) - MARGIN); } if (Render == SignatureRender.NameAndDescription) { string signedBy = Legacy.Text.Pdf.PdfPKCS7.GetSubjectFields(this.certChain[0]).GetField("CN"); Rectangle sr2 = new Rectangle(signatureRect.Width - MARGIN, signatureRect.Height - MARGIN ); float signedSize = FitText(font, signedBy, sr2, -1, runDirection); ColumnText ct2 = new ColumnText(t); ct2.RunDirection = runDirection; ct2.SetSimpleColumn(new Phrase(signedBy, font), signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, signedSize, Element.ALIGN_LEFT); ct2.Go(); } else if (Render == SignatureRender.GraphicAndDescription) { ColumnText ct2 = new ColumnText(t); ct2.RunDirection = runDirection; ct2.SetSimpleColumn(signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, 0, Element.ALIGN_RIGHT); Image im = Image.GetInstance(SignatureGraphic); im.ScaleToFit(signatureRect.Width, signatureRect.Height); Paragraph p = new Paragraph(); // must calculate the point to draw from to make image appear in middle of column float x = 0; // experimentation found this magic number to counteract Adobe's signature graphic, which // offsets the y co-ordinate by 15 units float y = -im.ScaledHeight + 15; x = x + (signatureRect.Width - im.ScaledWidth) / 2; y = y - (signatureRect.Height - im.ScaledHeight) / 2; p.Add(new Chunk(im, x + (signatureRect.Width - im.ScaledWidth) / 2, y, false)); ct2.AddElement(p); ct2.Go(); } if (size <= 0) { Rectangle sr = new Rectangle(dataRect.Width, dataRect.Height); size = FitText(font, text, sr, 12, runDirection); } ColumnText ct = new ColumnText(t); ct.RunDirection = runDirection; ct.SetSimpleColumn(new Phrase(text, font), dataRect.Left, dataRect.Bottom, dataRect.Right, dataRect.Top, size, Element.ALIGN_LEFT); ct.Go(); } if (app[3] == null && !acro6Layers) { PdfTemplate t = app[3] = new PdfTemplate(writer); t.BoundingBox = new Rectangle(100, 100); writer.AddDirectTemplateSimple(t, new PdfName("n3")); t.SetLiteral("% DSBlank\n"); } if (app[4] == null && !acro6Layers) { PdfTemplate t = app[4] = new PdfTemplate(writer); t.BoundingBox = new Rectangle(0, rect.Height * (1 - TOP_SECTION), rect.Right, rect.Top); writer.AddDirectTemplateSimple(t, new PdfName("n4")); Font font; if (layer2Font == null) font = new Font(); else font = new Font(layer2Font); float size = font.Size; String text = "Signature Not Verified"; if (layer4Text != null) text = layer4Text; Rectangle sr = new Rectangle(rect.Width - 2 * MARGIN, rect.Height * TOP_SECTION - 2 * MARGIN); size = FitText(font, text, sr, 15, runDirection); ColumnText ct = new ColumnText(t); ct.RunDirection = runDirection; ct.SetSimpleColumn(new Phrase(text, font), MARGIN, 0, rect.Width - MARGIN, rect.Height - MARGIN, size, Element.ALIGN_LEFT); ct.Go(); } int rotation = writer.reader.GetPageRotation(page); Rectangle rotated = new Rectangle(rect); int n = rotation; while (n > 0) { rotated = rotated.Rotate(); n -= 90; } if (frm == null) { frm = new PdfTemplate(writer); frm.BoundingBox = rotated; writer.AddDirectTemplateSimple(frm, new PdfName("FRM")); float scale = Math.Min(rect.Width, rect.Height) * 0.9f; float x = (rect.Width - scale) / 2; float y = (rect.Height - scale) / 2; scale /= 100; if (rotation == 90) frm.ConcatCTM(0, 1, -1, 0, rect.Height, 0); else if (rotation == 180) frm.ConcatCTM(-1, 0, 0, -1, rect.Width, rect.Height); else if (rotation == 270) frm.ConcatCTM(0, -1, 1, 0, 0, rect.Width); frm.AddTemplate(app[0], 0, 0); if (!acro6Layers) frm.AddTemplate(app[1], scale, 0, 0, scale, x, y); frm.AddTemplate(app[2], 0, 0); if (!acro6Layers) { frm.AddTemplate(app[3], scale, 0, 0, scale, x, y); frm.AddTemplate(app[4], 0, 0); } } PdfTemplate napp = new PdfTemplate(writer); napp.BoundingBox = rotated; writer.AddDirectTemplateSimple(napp, null); napp.AddTemplate(frm, 0, 0); return napp; }
/** * Copy the parameters from the specified ColumnText to use * when rendering. Parameters like <CODE>setArabicOptions</CODE> * must be set in this way. * * @param sourceColumn */ public void UseColumnParams(ColumnText sourceColumn) { // note that canvas will be overwritten later columnText.SetSimpleVars(sourceColumn); }
/** * Construct a MultiColumnText container of the specified height * starting at the specified Y position. * * @param height * @param top */ public MultiColumnText(float top, float height) { columnDefs = new ArrayList(); desiredHeight = height; this.top = top; nextY = top; // canvas will be set later columnText = new ColumnText(null); totalHeight = 0f; }
/** * Construct a MultiColumnText container of the specified height. * If height is <CODE>AUTOMATIC</CODE>, fill complete pages until done. * If a specific height is used, it may span one or more pages. * * @param height */ public MultiColumnText(float height) { columnDefs = new ArrayList(); desiredHeight = height; top = AUTOMATIC; // canvas will be set later columnText = new ColumnText(null); totalHeight = 0f; }
/** * @since 3.0.0 protected is now public static */ public static float SetColumn(ColumnText ct, float left, float bottom, float right, float top) { if (left > right) right = left; if (bottom > top) top = bottom; ct.SetSimpleColumn(left, bottom, right, top); return top; }
// [M4] Adding a PdfPTable /** Adds a <CODE>PdfPTable</CODE> to the document. * @param ptable the <CODE>PdfPTable</CODE> to be added to the document. * @throws DocumentException on error */ internal void AddPTable(PdfPTable ptable) { ColumnText ct = new ColumnText(writer.DirectContent); // if the table prefers to be on a single page, and it wouldn't //fit on the current page, start a new page. if (ptable.KeepTogether && !FitsPage(ptable, 0f) && currentHeight > 0) { NewPage(); } // add dummy paragraph if we aren't at the top of a page, so that // spacingBefore will be taken into account by ColumnText if (currentHeight > 0) { Paragraph p = new Paragraph(); p.Leading = 0; ct.AddElement(p); } ct.AddElement(ptable); bool he = ptable.HeadersInEvent; ptable.HeadersInEvent = true; int loop = 0; while (true) { ct.SetSimpleColumn(IndentLeft, IndentBottom, IndentRight, IndentTop - currentHeight); int status = ct.Go(); if ((status & ColumnText.NO_MORE_TEXT) != 0) { text.MoveText(0, ct.YLine - IndentTop + currentHeight); currentHeight = IndentTop - ct.YLine; break; } if (IndentTop - currentHeight == ct.YLine) ++loop; else loop = 0; if (loop == 3) { Add(new Paragraph("ERROR: Infinite table loop")); break; } NewPage(); } ptable.HeadersInEvent = he; }