You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@pdfbox.apache.org by "Tilman Hausherr (JIRA)" <ji...@apache.org> on 2017/11/08 20:48:00 UTC

[jira] [Resolved] (PDFBOX-3992) Implement show text with positioning operator (TJ)

     [ https://issues.apache.org/jira/browse/PDFBOX-3992?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Tilman Hausherr resolved PDFBOX-3992.
-------------------------------------
       Resolution: Fixed
    Fix Version/s: 3.0.0
                   2.0.9

> Implement show text with positioning operator (TJ)
> --------------------------------------------------
>
>                 Key: PDFBOX-3992
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-3992
>             Project: PDFBox
>          Issue Type: Improvement
>          Components: PDModel
>            Reporter: Dan Fickling
>            Assignee: Tilman Hausherr
>             Fix For: 2.0.9, 3.0.0
>
>         Attachments: justify-example.pdf, showtextwithpositioning.patch
>
>
> Why: The TJ operator is required to properly implement text justification in unicode fonts. The word spacing operator (Tw) is not sufficient because of note[1] from the PDF specification.
> Github user backslash47 has provided a basic implementation if that is of any help:
> https://github.com/backslash47/pdfbox/commit/3c528295b16445e58dc9fe895f78384221452be2
> Thanks,
> Daniel.
> [1] Note: Word spacing is applied to every occurrence of the single-byte character code 32 in a string when using a simple font or a composite font that defines code 32 as a single-byte code. It does not apply to occurrences of the byte value 32 in multiple-byte codes. 
> Example code:
> {code:java}
> import java.io.InputStream;
> import java.util.ArrayList;
> import java.util.List;
> import org.apache.pdfbox.pdmodel.PDDocument;
> import org.apache.pdfbox.pdmodel.PDPage;
> import org.apache.pdfbox.pdmodel.PDPageContentStream;
> import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
> import org.apache.pdfbox.pdmodel.common.PDRectangle;
> import org.apache.pdfbox.pdmodel.font.PDFont;
> import org.apache.pdfbox.pdmodel.font.PDType0Font;
> import org.apache.pdfbox.util.Matrix;
> public class TextWithPositioningExample {
> 	public static void main(String[] args) throws Exception {
> 		doIt("Hello World, this is a test!", "justify-example.pdf");
> 	}
> 	/**
> 	 * This example shows how to justify a string using the showTextWithPositioning method.
> 	 * First only spaces are adjusted, and then every letter.
> 	 */
> 	public static void doIt(String message, String outfile) throws Exception {
> 		// the document
> 		try (PDDocument doc = new PDDocument();
> 			 InputStream is = PDDocument.class.getResourceAsStream("/org/apache/pdfbox/resources/ttf/LiberationSans-Regular.ttf")) {
> 			final float FONT_SIZE = 20.0f;
> 			// Page 1
> 			PDFont font = PDType0Font.load(doc, is, true);
> 			//PDFont font = PDType1Font.COURIER;
> 			PDPage page = new PDPage(PDRectangle.A4);
> 			doc.addPage(page);
> 			
> 			// Get the non-justified string width in text space units.
> 			float stringWidth = font.getStringWidth(message) * FONT_SIZE;
> 			
> 			// Get the string height in text space units.
> 			float stringHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE;
> 			
> 			// Get the width we have to justify in.
> 			PDRectangle pageSize = page.getMediaBox();
> 			
> 			PDPageContentStream contentStream = new PDPageContentStream(doc,
> 					page, AppendMode.OVERWRITE, false);
> 		
> 			contentStream.beginText();
> 			contentStream.setFont(font, FONT_SIZE);
> 			
> 			// Start at top of page.
> 			contentStream.setTextMatrix(Matrix.getTranslateInstance(0, pageSize.getHeight() - stringHeight / 1000f));
> 			
> 			// First show non-justified.
> 			contentStream.showText(message);
> 			
> 			// Move to next line.
> 			contentStream.setTextMatrix(Matrix.getTranslateInstance(0, pageSize.getHeight() - ((stringHeight / 1000f) * 2)));
> 			
> 			// Now show word justified.
> 			// The space we have to make up, in text space units.
> 			float justifyWidth = ((pageSize.getWidth() * 1000f) - (stringWidth));
> 			
> 			List<Object> text = new ArrayList<>();
> 			String[] parts = message.split("\\s");
> 			
> 			float spaceWidth = (justifyWidth / (parts.length - 1)) / FONT_SIZE;
> 			for (int i = 0; i < parts.length; i++) {
> 				if (i != 0) {
> 					text.add(" ");
> 					// Positive values move to the left, negative to the right.
> 					text.add(Float.valueOf(-spaceWidth));
> 				}
> 				text.add(parts[i]);
> 			}
> 			contentStream.showTextWithPositioning(text.toArray());
> 			contentStream.setTextMatrix(Matrix.getTranslateInstance(0, pageSize.getHeight() - ((stringHeight / 1000f) * 3)));
> 			
> 			// Now show letter justified.
> 			text = new ArrayList<>();
> 			justifyWidth = ((pageSize.getWidth() * 1000f) - stringWidth);
> 			float extraLetterWidth = (justifyWidth / (message.codePointCount(0, message.length()) - 1)) / FONT_SIZE;
> 			
> 			for (int i = 0; i < message.length();) {
> 				if (i != 0) {
> 					text.add(Float.valueOf(-extraLetterWidth));
> 				}
> 				
> 				text.add(String.valueOf(Character.toChars(message.codePointAt(i))));
> 				
> 				i += Character.charCount(message.codePointAt(i));
> 			}
> 			contentStream.showTextWithPositioning(text.toArray());;
> 			
> 			// Finish up.
> 			contentStream.endText();
> 			contentStream.close();
> 			doc.save(outfile);
> 		}
> 	}
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: dev-help@pdfbox.apache.org