> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/android/get-started/samples/unicodewritetest.md).

# UnicodeWrite

Sample Java code for using Apryse SDK to create Unicode text and embed composite fonts in PDF files.

Sample Java code for using Apryse SDK to create Unicode text and embed composite fonts in PDF files. Learn more about our [Android SDK](/core/get-started/languages/java.md).

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

package com.pdftron.android.pdfnetsdksamples.samples;

import com.pdftron.android.pdfnetsdksamples.OutputListener;
import com.pdftron.android.pdfnetsdksamples.PDFNetSample;
import com.pdftron.android.pdfnetsdksamples.R;
import com.pdftron.android.pdfnetsdksamples.util.Utils;
import com.pdftron.pdf.Element;
import com.pdftron.pdf.ElementBuilder;
import com.pdftron.pdf.ElementWriter;
import com.pdftron.pdf.Font;
import com.pdftron.pdf.PDFDoc;
import com.pdftron.pdf.Page;
import com.pdftron.pdf.Rect;
import com.pdftron.pdf.ShapedText;
import com.pdftron.sdf.SDFDoc;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * This example illustrates how to create Unicode text and how to embed
 * composite fonts.
 * <p>
 * Note: This sample assumes that your device contains some of the regular
 * fonts distributed with the Android SDK. Since not all fonts are shipped
 * depending on the manufacturer, you may need to change the sample code
 * or add a font that covers the text you want to use.
 * <p>
 * In case some of the text used in this sample does not work properly
 * (squared or dot characters appear instead of the real characters) you can
 * search for the correct fonts in the Android SDK or download and use the
 * Cyberbit font, available here:
 * http://ftp.netscape.com/pub/communicator/extras/fonts/windows/
 * <p>
 * Add the font file to the assets\TestFiles folder and change the code
 * accordingly.
 */
public class UnicodeWriteTest extends PDFNetSample {

	private static OutputListener mOutputListener;

	private static ArrayList<String> mFileList = new ArrayList<>();

    public UnicodeWriteTest() {
        setTitle(R.string.sample_unicodewrite_title);
        setDescription(R.string.sample_unicodewrite_description);
    }

	@Override
	public void run(OutputListener outputListener) {
		super.run(outputListener);
		mOutputListener = outputListener;
		mFileList.clear();
		printHeader(outputListener);

        try (PDFDoc doc = new PDFDoc()) {
            ElementBuilder eb = new ElementBuilder();
            ElementWriter writer = new ElementWriter();

            // Start a new page ------------------------------------
            Page page = doc.pageCreate(new Rect(0, 0, 612, 794));

            writer.begin(page);    // begin writing to this page

            String fontLocation = Utils.getAssetTempFile(INPUT_PATH + "ARIALUNI.TTF").getAbsolutePath();

            Font fnt = null;
            try {
                // Embed and subset the font
                fnt = Font.createCIDTrueTypeFont(doc, fontLocation, true, true);
            } catch (Exception e) {
                fontLocation = "C:/Windows/Fonts/ARIALUNI.TTF";
                try {
                     fnt = Font.createCIDTrueTypeFont(doc, fontLocation, true, true);
                }
                catch (Exception e2) {
                    fontLocation = null;
                }
            }

            if(fnt != null) {
                mOutputListener.println("Note: using " + fontLocation + " for unshaped unicode text");
            }
            else {
                mOutputListener.println("Note: using system font substitution for unshaped unicode text");
                fnt = Font.create(doc, "Helvetica", "");
            }

            Element element = eb.createTextBegin(fnt, 1);
            element.setTextMatrix(10, 0, 0, 10, 50, 600);
            element.getGState().setLeading(2);         // Set the spacing between lines
            writer.writeElement(element);

            // Hello World!
            char hello[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
            writer.writeElement(eb.createUnicodeTextRun(new String(hello)));
            writer.writeElement(eb.createTextNewLine());

            // Latin
            char latin[] = {
                    'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 0x45, 0x0046, 0x00C0,
                    0x00C1, 0x00C2, 0x0143, 0x0144, 0x0145, 0x0152, '1', '2' // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(latin)));
            writer.writeElement(eb.createTextNewLine());

            // Greek
            char greek[] = {
                    0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A6, 0x03A8, 0x03A9  // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(greek)));
            writer.writeElement(eb.createTextNewLine());

            // Cyrillic
            char cyrilic[] = {
                    0x0409, 0x040A, 0x040B, 0x040C, 0x040E, 0x040F, 0x0410, 0x0411,
                    0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(cyrilic)));
            writer.writeElement(eb.createTextNewLine());

            // Hebrew
            char hebrew[] = {
                    0x05D0, 0x05D1, 0x05D3, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
                    0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(hebrew)));
            writer.writeElement(eb.createTextNewLine());

            // Arabic
            char arabic[] = {
                    0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C,
                    0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(arabic)));
            writer.writeElement(eb.createTextNewLine());

            // Thai
            char thai[] = {
                    0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09,
                    0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, 0x0E10, 0x0E11, 0x0E12 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(thai)));
            writer.writeElement(eb.createTextNewLine());

            // Hiragana - Japanese
            char hiragana[] = {
                    0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049,
                    0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3051, 0x3051, 0x3052 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(hiragana)));
            writer.writeElement(eb.createTextNewLine());

            // CJK Unified Ideographs
            char cjk_uni[] = {
                    0x5841, 0x5842, 0x5843, 0x5844, 0x5845, 0x5846, 0x5847, 0x5848, 0x5849,
                    0x584A, 0x584B, 0x584C, 0x584D, 0x584E, 0x584F, 0x5850, 0x5851, 0x5852 // etc.
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(cjk_uni)));
            writer.writeElement(eb.createTextNewLine());

            // Simplified Chinese
            char chinese_simplified[] = {
              0x4e16, 0x754c, 0x60a8, 0x597d
            };
            writer.writeElement(eb.createUnicodeTextRun(new String(chinese_simplified)));
            writer.writeElement(eb.createTextNewLine());

            // Finish the block of text
            writer.writeElement(eb.createTextEnd());

            mOutputListener.println("Now using text shaping logic to place text");

            // Create a font in indexed encoding mode 
            // normally this would mean that we are required to provide glyph indices
            // directly to CreateUnicodeTextRun, but instead, we will use the GetShapedText
            // method to take care of this detail for us.
            Font indexedFont = Font.createCIDTrueTypeFont(doc, Utils.getAssetTempFile(INPUT_PATH + "NotoSans_with_hindi.ttf").getAbsolutePath(), true, true, Font.e_Indices);
            element = eb.createTextBegin(indexedFont, 10.0);
            writer.writeElement(element);

            double linePos = 350.0;
            double lineSpace = 20.0;

            // Transform unicode text into an abstract collection of glyph indices and positioning info 
            ShapedText shapedText = indexedFont.getShapedText("Shaped Hindi Text:");

            // transform the shaped text info into a PDF element and write it to the page
            element = eb.createShapedTextRun(shapedText);
            element.setTextMatrix(1.5, 0, 0, 1.5, 50, linePos);
            linePos -= lineSpace;
            writer.writeElement(element);

            // read in unicode text lines from a file 
            List<String> hindiTextLines = Files.readAllLines(Paths.get(Utils.getAssetTempFile(INPUT_PATH + "hindi_sample_utf16le.txt").getAbsolutePath()), StandardCharsets.UTF_16LE);

            mOutputListener.println("Read in " + hindiTextLines.size() + " lines of Unicode text from file");
            for (String textLine : hindiTextLines)  
            {
                shapedText = indexedFont.getShapedText(textLine);
                element = eb.createShapedTextRun(shapedText);
                element.setTextMatrix(1.5, 0, 0, 1.5, 50, linePos);
                linePos -= lineSpace;
                writer.writeElement(element);
                mOutputListener.println("Wrote shaped line to page");
            }
        
            // Finish the shaped block of text
            writer.writeElement(eb.createTextEnd());

            writer.end();  // save changes to the current page
            doc.pagePushBack(page);

            doc.save(Utils.createExternalFile("unicodewrite.pdf", mFileList).getAbsolutePath(), new SDFDoc.SaveMode[]{SDFDoc.SaveMode.REMOVE_UNUSED, SDFDoc.SaveMode.HEX_STRINGS}, null);
            mOutputListener.println("Done. Result saved in unicodewrite.pdf...");
        } catch (Exception e) {
            mOutputListener.printError(e.getStackTrace());
        }

		for (String file : mFileList) {
			addToFileList(file);
		}
		printFooter(outputListener);
	}

}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
package com.pdftron.android.pdfnetsdksamples.samples

import com.pdftron.android.pdfnetsdksamples.OutputListener
import com.pdftron.android.pdfnetsdksamples.PDFNetSample
import com.pdftron.android.pdfnetsdksamples.R
import com.pdftron.android.pdfnetsdksamples.util.Utils
import com.pdftron.pdf.ElementBuilder
import com.pdftron.pdf.ElementWriter
import com.pdftron.pdf.PDFDoc
import com.pdftron.pdf.ShapedText
import com.pdftron.sdf.SDFDoc
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths

/**
 * This example illustrates how to create Unicode text and how to embed
 * composite fonts.
 *
 *
 * Note: This sample assumes that your device contains some of the regular
 * fonts distributed with the Android SDK. Since not all fonts are shipped
 * depending on the manufacturer, you may need to change the sample code
 * or add a font that covers the text you want to use.
 *
 *
 * In case some of the text used in this sample does not work properly
 * (squared or dot characters appear instead of the real characters) you can
 * search for the correct fonts in the Android SDK or download and use the
 * Cyberbit font, available here:
 * http://ftp.netscape.com/pub/communicator/extras/fonts/windows/
 *
 *
 * Add the font file to the assets\TestFiles folder and change the code
 * accordingly.
 */
class UnicodeWriteTest : PDFNetSample() {
    override fun run(outputListener: OutputListener?) {
        super.run(outputListener)
        mOutputListener = outputListener
        mFileList.clear()
        printHeader(outputListener!!)
        try {
            PDFDoc().use { doc ->
                val eb = ElementBuilder()
                val writer = ElementWriter()

                // Start a new page ------------------------------------
                val page: com.pdftron.pdf.Page = doc.pageCreate(com.pdftron.pdf.Rect(0.0, 0.0, 612.0, 794.0))
                writer.begin(page) // begin writing to this page
                var fontLocation: String? = Utils.getAssetTempFile(INPUT_PATH.toString() + "ARIALUNI.TTF")!!.getAbsolutePath()
                var fnt: com.pdftron.pdf.Font? = null
                try {
                    // Embed and subset the font
                    fnt = com.pdftron.pdf.Font.createCIDTrueTypeFont(doc, fontLocation, true, true)
                } catch (e: java.lang.Exception) {
                    fontLocation = "C:/Windows/Fonts/ARIALUNI.TTF"
                    try {
                        fnt = com.pdftron.pdf.Font.createCIDTrueTypeFont(doc, fontLocation, true, true)
                    } catch (e2: java.lang.Exception) {
                        fontLocation = null
                    }
                }
                if (fnt != null) {
                    mOutputListener!!.println("Note: using $fontLocation for unshaped unicode text")
                } else {
                    mOutputListener!!.println("Note: using system font substitution for unshaped unicode text")
                    fnt = com.pdftron.pdf.Font.create(doc, "Helvetica", "")
                }
                var element: com.pdftron.pdf.Element = eb.createTextBegin(fnt, 1.0)
                element.setTextMatrix(10.0, 0.0, 0.0, 10.0, 50.0, 600.0)
                element.getGState().setLeading(2.0) // Set the spacing between lines
                writer.writeElement(element)

                // Hello World!
                val hello = charArrayOf('H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!')
                writer.writeElement(eb.createUnicodeTextRun(String(hello)))
                writer.writeElement(eb.createTextNewLine())

                // Latin
                val latin = charArrayOf(
                    'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 0x45.toChar(), 0x0046.toChar(), 0x00C0.toChar(),
                    0x00C1.toChar(), 0x00C2.toChar(), 0x0143.toChar(), 0x0144.toChar(), 0x0145.toChar(), 0x0152.toChar(), '1', '2' // etc.
                )
                writer.writeElement(eb.createUnicodeTextRun(String(latin)))
                writer.writeElement(eb.createTextNewLine())

                // Greek
                val greek = charArrayOf(
                    0x039E.toChar(), 0x039F.toChar(), 0x03A0.toChar(), 0x03A1.toChar(), 0x03A3.toChar(), 0x03A6.toChar(), 0x03A8.toChar(), 0x03A9 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(greek)))
                writer.writeElement(eb.createTextNewLine())

                // Cyrillic
                val cyrilic = charArrayOf(
                    0x0409.toChar(), 0x040A.toChar(), 0x040B.toChar(), 0x040C.toChar(), 0x040E.toChar(), 0x040F.toChar(), 0x0410.toChar(), 0x0411.toChar(),
                    0x0412.toChar(), 0x0413.toChar(), 0x0414.toChar(), 0x0415.toChar(), 0x0416.toChar(), 0x0417.toChar(), 0x0418.toChar(), 0x0419 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(cyrilic)))
                writer.writeElement(eb.createTextNewLine())

                // Hebrew
                val hebrew = charArrayOf(
                    0x05D0.toChar(), 0x05D1.toChar(), 0x05D3.toChar(), 0x05D3.toChar(), 0x05D4.toChar(), 0x05D5.toChar(), 0x05D6.toChar(), 0x05D7.toChar(), 0x05D8.toChar(),
                    0x05D9.toChar(), 0x05DA.toChar(), 0x05DB.toChar(), 0x05DC.toChar(), 0x05DD.toChar(), 0x05DE.toChar(), 0x05DF.toChar(), 0x05E0.toChar(), 0x05E1 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(hebrew)))
                writer.writeElement(eb.createTextNewLine())

                // Arabic
                val arabic = charArrayOf(
                    0x0624.toChar(), 0x0625.toChar(), 0x0626.toChar(), 0x0627.toChar(), 0x0628.toChar(), 0x0629.toChar(), 0x062A.toChar(), 0x062B.toChar(), 0x062C.toChar(),
                    0x062D.toChar(), 0x062E.toChar(), 0x062F.toChar(), 0x0630.toChar(), 0x0631.toChar(), 0x0632.toChar(), 0x0633.toChar(), 0x0634.toChar(), 0x0635 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(arabic)))
                writer.writeElement(eb.createTextNewLine())

                // Thai
                val thai = charArrayOf(
                    0x0E01.toChar(), 0x0E02.toChar(), 0x0E03.toChar(), 0x0E04.toChar(), 0x0E05.toChar(), 0x0E06.toChar(), 0x0E07.toChar(), 0x0E08.toChar(), 0x0E09.toChar(),
                    0x0E0A.toChar(), 0x0E0B.toChar(), 0x0E0C.toChar(), 0x0E0D.toChar(), 0x0E0E.toChar(), 0x0E0F.toChar(), 0x0E10.toChar(), 0x0E11.toChar(), 0x0E12 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(thai)))
                writer.writeElement(eb.createTextNewLine())

                // Hiragana - Japanese
                val hiragana = charArrayOf(
                    0x3041.toChar(), 0x3042.toChar(), 0x3043.toChar(), 0x3044.toChar(), 0x3045.toChar(), 0x3046.toChar(), 0x3047.toChar(), 0x3048.toChar(), 0x3049.toChar(),
                    0x304A.toChar(), 0x304B.toChar(), 0x304C.toChar(), 0x304D.toChar(), 0x304E.toChar(), 0x304F.toChar(), 0x3051.toChar(), 0x3051.toChar(), 0x3052 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(hiragana)))
                writer.writeElement(eb.createTextNewLine())

                // CJK Unified Ideographs
                val cjk_uni = charArrayOf(
                    0x5841.toChar(), 0x5842.toChar(), 0x5843.toChar(), 0x5844.toChar(), 0x5845.toChar(), 0x5846.toChar(), 0x5847.toChar(), 0x5848.toChar(), 0x5849.toChar(),
                    0x584A.toChar(), 0x584B.toChar(), 0x584C.toChar(), 0x584D.toChar(), 0x584E.toChar(), 0x584F.toChar(), 0x5850.toChar(), 0x5851.toChar(), 0x5852 // etc.
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(cjk_uni)))
                writer.writeElement(eb.createTextNewLine())

                // Simplified Chinese
                val chinese_simplified = charArrayOf(
                    0x4e16.toChar(), 0x754c.toChar(), 0x60a8.toChar(), 0x597d
                        .toChar())
                writer.writeElement(eb.createUnicodeTextRun(String(chinese_simplified)))
                writer.writeElement(eb.createTextNewLine())

                // Finish the block of text
                writer.writeElement(eb.createTextEnd())
                mOutputListener!!.println("Now using text shaping logic to place text")

                // Create a font in indexed encoding mode
                // normally this would mean that we are required to provide glyph indices
                // directly to CreateUnicodeTextRun, but instead, we will use the GetShapedText
                // method to take care of this detail for us.
                val indexedFont: com.pdftron.pdf.Font = com.pdftron.pdf.Font.createCIDTrueTypeFont(doc, Utils.getAssetTempFile(INPUT_PATH.toString() + "NotoSans_with_hindi.ttf")!!.getAbsolutePath(), true, true, com.pdftron.pdf.Font.e_Indices)
                element = eb.createTextBegin(indexedFont, 10.0)
                writer.writeElement(element)
                var linePos = 350.0
                val lineSpace = 20.0

                // Transform unicode text into an abstract collection of glyph indices and positioning info
                var shapedText: ShapedText = indexedFont.getShapedText("Shaped Hindi Text:")

                // transform the shaped text info into a PDF element and write it to the page
                element = eb.createShapedTextRun(shapedText)
                element.setTextMatrix(1.5, 0.0, 0.0, 1.5, 50.0, linePos)
                linePos -= lineSpace
                writer.writeElement(element)

                // read in unicode text lines from a file
                val hindiTextLines: List<String> = Files.readAllLines(Paths.get(Utils.getAssetTempFile(INPUT_PATH + "hindi_sample_utf16le.txt")!!.absolutePath), StandardCharsets.UTF_16LE)
                mOutputListener!!.println("Read in " + hindiTextLines.size + " lines of Unicode text from file")
                for (textLine in hindiTextLines) {
                    shapedText = indexedFont.getShapedText(textLine)
                    element = eb.createShapedTextRun(shapedText)
                    element.setTextMatrix(1.5, 0.0, 0.0, 1.5, 50.0, linePos)
                    linePos -= lineSpace
                    writer.writeElement(element)
                    mOutputListener!!.println("Wrote shaped line to page")
                }

                // Finish the shaped block of text
                writer.writeElement(eb.createTextEnd())
                writer.end() // save changes to the current page
                doc.pagePushBack(page)
                doc.save(Utils.createExternalFile("unicodewrite.pdf", mFileList).getAbsolutePath(), arrayOf<SDFDoc.SaveMode>(SDFDoc.SaveMode.REMOVE_UNUSED, SDFDoc.SaveMode.HEX_STRINGS), null)
                mOutputListener!!.println("Done. Result saved in unicodewrite.pdf...")
            }
        } catch (e: java.lang.Exception) {
            mOutputListener!!.printError(e.getStackTrace())
        }
        for (file in mFileList) {
            addToFileList(file)
        }
        printFooter(outputListener)
    }

    companion object {
        private var mOutputListener: OutputListener? = null
        private val mFileList: java.util.ArrayList<String> = java.util.ArrayList<String>()
    }

    init {
        setTitle(R.string.sample_unicodewrite_title)
        setDescription(R.string.sample_unicodewrite_description)
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/android/get-started/samples/unicodewritetest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
